Class: Object

Inherits:
BasicObject
Defined in:
lib/gen_eval.rb

Instance Method Summary collapse

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