У меня возникли проблемы с тем, как переопределить функцию rb_ (например, rb_ivar_get) в c. У меня есть следующий код:Как перезаписать функцию rb_ в расширении ruby c?
#include "ruby.h"
void Init_metaobject();
VALUE meta_cObject = Qnil;
VALUE meta_ivar_get(VALUE obj, VALUE mId, VALUE mWarn);
VALUE meta_ivar_set(VALUE obj, VALUE mId, VALUE val);
void Init_metaobject() {
meta_cObject = rb_define_class("MetaObject", rb_cObject);
rb_define_method(meta_cObject, "meta_ivar_get", meta_ivar_get, 2);
rb_define_method(meta_cObject, "meta_ivar_set", meta_ivar_set, 2);
}
VALUE
rb_ivar_get(obj, id)
VALUE obj;
ID id;
{
return meta_ivar_get(obj, ID2SYM(id), Qtrue);
}
VALUE
rb_attr_get(obj, id)
VALUE obj;
ID id;
{
return meta_ivar_get(obj, ID2SYM(id), Qfalse);
}
VALUE
rb_ivar_set(obj, id, val)
VALUE obj;
ID id;
VALUE val;
{
return meta_ivar_set(obj, ID2SYM(id), val);
}
VALUE
meta_ivar_get(obj, mId, mWarn)
VALUE obj;
VALUE mId;
VALUE mWarn;
{
VALUE val;
ID id = rb_to_id(id);
int warn = RTEST(warn);
switch (TYPE(obj)) {
case T_OBJECT:
case T_CLASS:
case T_MODULE:
if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, &val))
return val;
break;
default:
if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
return generic_ivar_get(obj, id, warn);
break;
}
if (warn) {
rb_warning("instance variable %s not initialized", rb_id2name(id));
}
return Qnil;
}
VALUE
meta_ivar_set(obj, mId, val)
VALUE obj;
VALUE mId;
VALUE val;
{
ID id = rb_to_id(mId);
if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
if (OBJ_FROZEN(obj)) rb_error_frozen("object");
switch (TYPE(obj)) {
case T_OBJECT:
case T_CLASS:
case T_MODULE:
if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable();
st_insert(ROBJECT(obj)->iv_tbl, id, val);
break;
default:
generic_ivar_set(obj, id, val);
break;
}
return val;
}
И следующий тест:
require 'metaobject'
class Tracker < MetaObject
attr_accessor :ivar
def initialize
@ivar = nil
end
def meta_ivar_get(symbol, warn)
puts "Instance variable, #{symbol}, retrieved"
super(symbol, warn)
end
def meta_ivar_set(symbol, obj)
puts "Instance variable, #{symbol}, changed to #{obj.inspect}"
super(symbol, obj)
end
end
obj = Tracker.new
obj.ivar = "Modified"
puts obj.ivar
Выход из которых только:
Modified
Мои мысли о том, что рубин линкер вуалируя My определение rb_ivar_get, rb_attr_get и rb_ivar_set с его определением, найденным в переменных.c. Я прав? Если да, то как я могу изменить его, что мои методы скрывают рубины, а не наоборот.
Я не могу перезаписать 'attr_accessor', потому что для меня основным моментом добавления этого расширения было уметь отслеживать изменения непосредственно в' @ivar = "некоторых значениях' 'вызовы. Итак, вы говорите, чтобы сделать это, мне нужно будет отредактировать и перекомпилировать источник, нет другого пути? – tophat
Насколько я знаю, нет. –
См. Издание. –