Module: BindingOfCaller

Included in:
Binding
Defined in:
lib/binding_of_caller.rb,
lib/binding_of_caller/version.rb,
ext/binding_of_caller/binding_of_caller.c

Defined Under Namespace

Modules: BindingExtensions

Constant Summary collapse

VERSION =
"0.6.8"

Instance Method Summary collapse

Instance Method Details

#callersObject



201
202
203
204
205
206
207
208
209
210
# File 'ext/binding_of_caller/binding_of_caller.c', line 201

static VALUE
callers(VALUE self)
{
  VALUE ary = rb_ary_new();

  for (int i = 0; i < FIX2INT(frame_count(self)); i++)
    rb_ary_push(ary, binding_of_caller(self, INT2FIX(i)));

  return ary;
}

#frame_countObject



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'ext/binding_of_caller/binding_of_caller.c', line 173

static VALUE frame_count(VALUE self)
{
  rb_thread_t *th;
  GetThreadPtr(rb_thread_current(), th);

  rb_control_frame_t *cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
  rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);

  int i = 1;
  while (cfp < limit_cfp) {
    cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);

    if (cfp >= limit_cfp)
      return INT2FIX(i);

    // skip invalid frames
    if (!valid_frame_p(cfp, limit_cfp))
      cfp = find_valid_frame(cfp, limit_cfp);

    if (!cfp)
      break;

    i++;
  }

  return INT2FIX(i);
}

#frame_descriptionObject



167
168
169
170
171
# File 'ext/binding_of_caller/binding_of_caller.c', line 167

static VALUE
frame_description(VALUE self)
{
  return rb_iv_get(self, "@frame_description");
}

#frame_typeObject



161
162
163
164
165
# File 'ext/binding_of_caller/binding_of_caller.c', line 161

static VALUE
frame_type(VALUE self)
{
  return rb_iv_get(self, "@frame_type");
}

#of_caller(rb_level) ⇒ Object



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/binding_of_caller/binding_of_caller.c', line 123

static VALUE binding_of_caller(VALUE self, VALUE rb_level)
{
  rb_thread_t *th;
  GetThreadPtr(rb_thread_current(), th);

  rb_control_frame_t *cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
  rb_control_frame_t *limit_cfp = (void *)(th->stack + th->stack_size);
  int level = FIX2INT(rb_level);

  // attempt to locate the nth parent control frame
  for (int i = 0; i < level; i++) {
    cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);

    if (cfp >= limit_cfp)
      rb_raise(rb_eRuntimeError, "Invalid frame, gone beyond end of stack!");

    // skip invalid frames
    if (!valid_frame_p(cfp, limit_cfp))
      cfp = find_valid_frame(cfp, limit_cfp);
  }

  VALUE bindval = binding_alloc(rb_cBinding);
  rb_binding_t *bind;

  if (cfp == 0)
    rb_raise(rb_eRuntimeError, "Can't create Binding Object on top of Fiber.");

  GetBindingPtr(bindval, bind);
  bind->env = rb_vm_make_env_object(th, cfp);
  bind->filename = cfp->iseq->filename;
  bind->line_no = rb_vm_get_sourceline(cfp);

  rb_iv_set(bindval, "@frame_type", frametype_name(cfp->flag));
  rb_iv_set(bindval, "@frame_description", cfp->iseq->name);

  return bindval;
}