Class: Object
- Inherits:
- BasicObject
- Defined in:
- lib/gen_eval.rb
Instance Method Summary collapse
-
#__mirror__ ⇒ Object
end of Ruby 1.9 funcs *.
- #__remove_hidden_self__ ⇒ Object
- #__retrieve_hidden_self__ ⇒ Object
- #__set_hidden_self__(hidden_self) ⇒ Object
- #__unmirror__ ⇒ Object
-
#capture(&block) ⇒ Object
call-seq: capture {| | block } => result Used in conjunction with
gen_eval
. -
#gen_eval(*objs, &block) ⇒ Object
(also: #gen_eval_with)
call-seq: obj.gen_eval {| | block } => obj Works similarly to instance_eval except instance variables are not looked up in obj.
Instance Method Details
#__mirror__ ⇒ Object
end of Ruby 1.9 funcs *
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'ext/gen_eval/gen_eval.c', line 111
VALUE
rb_mirror_object(VALUE context)
{
VALUE duped_context;
#ifdef RUBY_19
if(TYPE(context) == T_OBJECT)
duped_context = rb_funcall(rb_cObject, rb_intern("new"), 0);
else
duped_context = rb_funcall(rb_cClass, rb_intern("new"), 0);
#else
duped_context = rb_funcall(rb_cClass, rb_intern("new"), 0);
#endif
/* the duped_context shares the context's iv_tbl.
2 cases: (1) external iv_tbl, (2) local iv_tbl
NOTE: we do not need to save original iv_tbl before replacing it, a brand new Class
instance does not yet have an iv_tbl (the pointer is set to 0)
*/
if(FL_TEST(context, FL_EXIVAR))
RCLASS_IV_TBL(duped_context) = (struct st_table *) rb_generic_ivar_table(context);
else {
#ifdef RUBY_19
if(TYPE(context) == T_OBJECT)
redirect_iv_for_object(context, duped_context);
else {
save_m_tbl(duped_context);
RCLASS_M_TBL(duped_context) = (struct st_table *) RCLASS_M_TBL(context);
RCLASS_IV_TBL(duped_context) = (struct st_table *) RCLASS_IV_TBL(context);
}
#else
save_m_tbl(duped_context);
RCLASS_M_TBL(duped_context) = (struct st_table *) RCLASS_M_TBL(context);
RCLASS_IV_TBL(duped_context) = (struct st_table *) RCLASS_IV_TBL(context);
#endif
}
/* ensure singleton exists */
rb_singleton_class(context);
/* set up the class hierarchy for our dup_context */
KLASS_OF(duped_context) = rb_singleton_class_clone(context);
return duped_context;
}
|
#__remove_hidden_self__ ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'ext/gen_eval/gen_eval.c', line 9
VALUE
retrieve_hidden_self(VALUE duped_context)
{
VALUE thread_id, unique_name, hidden_self;
/* retrieve hidden self (if it exists) */
thread_id = rb_funcall(rb_obj_id(rb_thread_current()), rb_intern("to_s"), 0);
unique_name = rb_str_plus(rb_str_new2("__hidden_self__"), thread_id);
hidden_self = rb_ivar_get(duped_context, rb_to_id(unique_name));
return hidden_self;
}
|
#__retrieve_hidden_self__ ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'ext/gen_eval/gen_eval.c', line 9
VALUE
retrieve_hidden_self(VALUE duped_context)
{
VALUE thread_id, unique_name, hidden_self;
/* retrieve hidden self (if it exists) */
thread_id = rb_funcall(rb_obj_id(rb_thread_current()), rb_intern("to_s"), 0);
unique_name = rb_str_plus(rb_str_new2("__hidden_self__"), thread_id);
hidden_self = rb_ivar_get(duped_context, rb_to_id(unique_name));
return hidden_self;
}
|
#__set_hidden_self__(hidden_self) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'ext/gen_eval/gen_eval.c', line 36
VALUE
set_hidden_self(VALUE duped_context, VALUE hidden_self)
{
VALUE thread_id, unique_name;
/* generate a unique (thread safe) name for the hidden self */
thread_id = rb_funcall(rb_obj_id(rb_thread_current()), rb_intern("to_s"), 0);
unique_name = rb_str_plus(rb_str_new2("__hidden_self__"), thread_id);
/* store self in hidden var in duped context */
rb_ivar_set(duped_context, rb_to_id(unique_name), hidden_self);
return Qnil;
}
|
#__unmirror__ ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'ext/gen_eval/gen_eval.c', line 161
VALUE
rb_unmirror_object(VALUE duped_context)
{
#ifdef RUBY_19
if(TYPE(duped_context) == T_OBJECT)
release_iv_for_object(duped_context);
else {
RCLASS_IV_TBL(duped_context) = (struct st_table *) 0;
restore_m_tbl(duped_context);
}
#else
RCLASS_IV_TBL(duped_context) = (struct st_table *) 0;
restore_m_tbl(duped_context);
#endif
return Qnil;
}
|
#capture(&block) ⇒ Object
call-seq:
capture {| | block } => result
Used in conjunction with +gen_eval+. Causes code in block
to be +instance_eval+'d with respect to the receiver of
the +gen_eval+.
85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/gen_eval.rb', line 85 def capture(&block) raise "block needed" if !block hidden_self = self.__retrieve_hidden_self__ if hidden_self result = hidden_self.instance_eval(&block) else result = yield end result end |
#gen_eval(*objs, &block) ⇒ Object Also known as: gen_eval_with
call-seq:
obj.gen_eval {| | block } => obj
Works similarly to instance_eval except instance variables are
not looked up in _obj_. All instance methods of +Klass+ are
available but mutators must be wrapped in a +capture+ block.
class Klass
attr_reader :age
def hello(name)
"hello #{name}"
end
def set_age(age)
capture {
@age = age
}
end
end
k = Klass.new
@name = "John"
k.gen_eval { hello(@name) } #=> "hello John"
k.gen_eval { set_age(21) }
k.age #=> 21
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/gen_eval.rb', line 55 def gen_eval(*objs, &block) raise "block needed" if !block objs = [self] if objs.empty? raise "cannot gen_eval on Object" if objs.include?(Object) mirror_context = block.__context__.__mirror__ mirror_context.gen_extend(*objs) mirror_context.__set_hidden_self__(self) begin m = mirror_context.is_a?(Module) ? :module_eval : :instance_eval result = mirror_context.send(m, &block) ensure mirror_context.__remove_hidden_self__ mirror_context.__unmirror__ end result end |