# class Byebug::Context

Mantains context information for the debugger and it's the main communication point between the library and the C-extension through the #at_breakpoint, #at_catchpoint, #at_tracing, #at_line and #at_return callbacks

### Public Class Methods

bin_file() click to toggle source

    # File lib/byebug/context.rb, line 15
    def self.bin_file
      @bin_file ||= Gem.bin_path('byebug', 'byebug')
    end

ignored_files() click to toggle source

List of files byebug will ignore while debugging

    # File lib/byebug/context.rb, line 11
    def self.ignored_files
      Byebug.mode == :standalone ? lib_files + [bin_file] : lib_files
    end

lib_files() click to toggle source

    # File lib/byebug/context.rb, line 19
    def self.lib_files
      @lib_files ||= Dir.glob(File.expand_path('../../**/*.rb', __FILE__))
    end

### Public Instance Methods

at_breakpoint(brkpnt) click to toggle source

    # File lib/byebug/context.rb, line 77
    def at_breakpoint(brkpnt)
      handler.at_breakpoint(self, brkpnt)
    end

at_catchpoint(excpt) click to toggle source

    # File lib/byebug/context.rb, line 81
    def at_catchpoint(excpt)
      handler.at_catchpoint(self, excpt)
    end

at_line(file, line) click to toggle source

    # File lib/byebug/context.rb, line 89
    def at_line(file, line)
      handler.at_line(self, file, line) unless ignored_file?(file)
    end

at_return(file, line) click to toggle source

    # File lib/byebug/context.rb, line 93
    def at_return(file, line)
      handler.at_return(self, file, line) unless ignored_file?(file)
    end

at_tracing(file, line) click to toggle source

    # File lib/byebug/context.rb, line 85
    def at_tracing(file, line)
      handler.at_tracing(self, file, line) unless ignored_file?(file)
    end

backtrace() click to toggle source

    inline VALUE
    Context_backtrace(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);

      return dc_backtrace(context);
    }

dead?() click to toggle source

    inline VALUE
    Context_dead(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);
      return CTX_FL_TEST(context, CTX_FL_DEAD) ? Qtrue : Qfalse;
    }

frame_args(frame_no = 0) click to toggle source

Gets current method arguments for a frame.

@param frame_no Frame index in the backtrace. Defaults to 0.

    # File lib/byebug/context.rb, line 66
    def frame_args(frame_no = 0)
      bind = frame_binding(frame_no)
      return c_frame_args(frame_no) unless bind

      ruby_frame_args(bind)
    end

frame_binding(frame_position = 0) → binding click to toggle source

Returns frame's binding.

    static VALUE
    Context_frame_binding(int argc, VALUE * argv, VALUE self)
    {
      FRAME_SETUP;

      return dc_frame_binding(context, frame_n);
    }

frame_class(frame_position = 0) → binding click to toggle source

Returns frame's defined class.

    static VALUE
    Context_frame_class(int argc, VALUE * argv, VALUE self)
    {
      FRAME_SETUP;

      return dc_frame_class(context, frame_n);
    }

frame_file(frame_position = 0) → string click to toggle source

Returns the name of the file in the frame.

    static VALUE
    Context_frame_file(int argc, VALUE * argv, VALUE self)
    {
      VALUE loc, absolute_path;

      FRAME_SETUP;

      loc = dc_frame_location(context, frame_n);

      absolute_path = rb_funcall(loc, rb_intern("absolute_path"), 0);

      if (!NIL_P(absolute_path))
        return absolute_path;

      return rb_funcall(loc, rb_intern("path"), 0);
    }

frame_line(frame_position = 0) → int click to toggle source

Returns the line number in the file.

    static VALUE
    Context_frame_line(int argc, VALUE * argv, VALUE self)
    {
      VALUE loc;

      FRAME_SETUP;

      loc = dc_frame_location(context, frame_n);

      return rb_funcall(loc, rb_intern("lineno"), 0);
    }

frame_locals(frame_no = 0) click to toggle source

Gets local variables for a frame.

@param frame_no Frame index in the backtrace. Defaults to 0.

TODO: Use brand new local_variable_{get,set,defined?} for rubies >= 2.1

    # File lib/byebug/context.rb, line 54
    def frame_locals(frame_no = 0)
      bind = frame_binding(frame_no)
      return [] unless bind

      bind.eval('local_variables.inject({}){|h, v| h[v] = eval(v.to_s); h}')
    end

frame_method(frame_position = 0) → sym click to toggle source

Returns the sym of the called method.

    static VALUE
    Context_frame_method(int argc, VALUE * argv, VALUE self)
    {
      VALUE loc;

      FRAME_SETUP;

      loc = dc_frame_location(context, frame_n);

      return rb_str_intern(rb_funcall(loc, rb_intern("label"), 0));
    }

frame_self(frame_postion = 0) → obj click to toggle source

Returns self object of the frame.

    static VALUE
    Context_frame_self(int argc, VALUE * argv, VALUE self)
    {
      FRAME_SETUP;

      return dc_frame_self(context, frame_n);
    }

handler() click to toggle source

    # File lib/byebug/context.rb, line 73
    def handler
      Byebug.handler || fail('No interface loaded')
    end

ignored?() click to toggle source

    inline VALUE
    Context_ignored(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);
      return CTX_FL_TEST(context, CTX_FL_IGNORE) ? Qtrue : Qfalse;
    }

ignored_file?(path) click to toggle source

Tells whether a file is ignored by the debugger.

@param path [String] filename to be checked.

    # File lib/byebug/context.rb, line 28
    def ignored_file?(path)
      self.class.ignored_files.include?(path)
    end

interrupt() click to toggle source

    # File lib/byebug/context.rb, line 43
    def interrupt
      step_into 1
    end

resume → nil click to toggle source

Resumes thread from the suspended mode.

    static VALUE
    Context_resume(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);

      if (!CTX_FL_TEST(context, CTX_FL_SUSPEND))
        return Qnil;

      CTX_FL_UNSET(context, CTX_FL_SUSPEND);

      if (CTX_FL_TEST(context, CTX_FL_WAS_RUNNING))
        rb_thread_wakeup(context->thread);

      return Qnil;
    }

stack_size() click to toggle source

Context's stack size

    # File lib/byebug/context.rb, line 35
    def stack_size
      return 0 unless backtrace

      backtrace.drop_while { |l| ignored_file?(l.first.path) }
        .take_while { |l| !ignored_file?(l.first.path) }
        .size
    end

step_into(steps, frame = 0) click to toggle source

Stops the current context after a number of `steps` are made from frame `frame` (by default the newest one).

    static VALUE
    Context_step_into(int argc, VALUE * argv, VALUE self)
    {
      VALUE steps, v_frame;
      int n_args, from_frame;
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);

      if (context->calced_stack_size == 0)
        rb_raise(rb_eRuntimeError, "No frames collected.");

      n_args = rb_scan_args(argc, argv, "11", &steps, &v_frame);

      if (FIX2INT(steps) <= 0)
        rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");

      from_frame = n_args == 1 ? 0 : FIX2INT(v_frame);

      if (from_frame < 0 || from_frame >= context->calced_stack_size)
        rb_raise(rb_eRuntimeError, "Destination frame (%d) is out of range (%d)",
                 from_frame, context->calced_stack_size);
      else if (from_frame > 0)
        CTX_FL_SET(context, CTX_FL_IGNORE_STEPS);

      context->steps = FIX2INT(steps);
      context->dest_frame = context->calced_stack_size - from_frame;

      return steps;
    }

step_out(n_frames = 1, force = false) click to toggle source

Stops after `n_frames` frames are finished. `force` parameter (if true) ensures that the execution will stop in the specified frame even when there are no more instructions to run. In that case, it will stop when the return event for that frame is triggered.

    static VALUE
    Context_step_out(int argc, VALUE * argv, VALUE self)
    {
      int n_args, n_frames;
      VALUE v_frames, force;
      debug_context_t *context;

      n_args = rb_scan_args(argc, argv, "02", &v_frames, &force);
      n_frames = n_args == 0 ? 1 : FIX2INT(v_frames);

      Data_Get_Struct(self, debug_context_t, context);

      if (n_frames < 0 || n_frames > context->calced_stack_size)
        rb_raise(rb_eRuntimeError,
                 "You want to finish %d frames, but stack size is only %d",
                 n_frames, context->calced_stack_size);

      context->steps_out = n_frames;
      if (n_args == 2 && RTEST(force))
        CTX_FL_SET(context, CTX_FL_STOP_ON_RET);
      else
        CTX_FL_UNSET(context, CTX_FL_STOP_ON_RET);

      return Qnil;
    }

step_over(lines, frame = 0) click to toggle source

Steps over `lines` lines in frame `frame` (by default the newest one) or higher (if frame `frame` finishes).

    static VALUE
    Context_step_over(int argc, VALUE * argv, VALUE self)
    {
      int n_args, frame;
      VALUE lines, v_frame;
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);

      if (context->calced_stack_size == 0)
        rb_raise(rb_eRuntimeError, "No frames collected.");

      n_args = rb_scan_args(argc, argv, "11", &lines, &v_frame);
      frame = n_args == 1 ? 0 : FIX2INT(v_frame);

      if (frame < 0 || frame >= context->calced_stack_size)
        rb_raise(rb_eRuntimeError, "Destination frame (%d) is out of range (%d)",
                 frame, context->calced_stack_size);

      context->lines = FIX2INT(lines);
      context->dest_frame = context->calced_stack_size - frame;

      return Qnil;
    }

stop_reason() click to toggle source

    static VALUE
    Context_stop_reason(VALUE self)
    {
      debug_context_t *context;
      const char *symbol;

      Data_Get_Struct(self, debug_context_t, context);

      if (CTX_FL_TEST(context, CTX_FL_DEAD))
        symbol = "post-mortem";
      else
        switch (context->stop_reason)
        {
          case CTX_STOP_STEP:
            symbol = "step";
            break;
          case CTX_STOP_BREAKPOINT:
            symbol = "breakpoint";
            break;
          case CTX_STOP_CATCHPOINT:
            symbol = "catchpoint";
            break;
          case CTX_STOP_NONE:
          default:
            symbol = "none";
        }
      return ID2SYM(rb_intern(symbol));
    }

suspend → nil click to toggle source

Suspends the thread when it is running.

    static VALUE
    Context_suspend(VALUE self)
    {
      VALUE status;
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);

      status = rb_funcall(context->thread, rb_intern("status"), 0);

      if (rb_str_cmp(status, rb_str_new2("run")) == 0)
        CTX_FL_SET(context, CTX_FL_WAS_RUNNING);
      else if (rb_str_cmp(status, rb_str_new2("sleep")) == 0)
        CTX_FL_UNSET(context, CTX_FL_WAS_RUNNING);
      else
        return Qnil;

      CTX_FL_SET(context, CTX_FL_SUSPEND);

      return Qnil;
    }

suspended? → bool click to toggle source

Returns `true` if the thread is suspended by debugger.

    static VALUE
    Context_is_suspended(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);

      return CTX_FL_TEST(context, CTX_FL_SUSPEND) ? Qtrue : Qfalse;
    }

switch → nil click to toggle source

Switches execution to this context.

    static VALUE
    Context_switch(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);

      next_thread = context->thread;

      context->steps = 1;
      context->steps_out = 0;
      CTX_FL_SET(context, CTX_FL_STOP_ON_RET);

      return Qnil;
    }

thnum() click to toggle source

    inline VALUE
    Context_thnum(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);
      return INT2FIX(context->thnum);
    }

thread() click to toggle source

    inline VALUE
    Context_thread(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);
      return context->thread;
    }

tracing → bool click to toggle source

Returns the tracing flag for the current context.

    static VALUE
    Context_tracing(VALUE self)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);
      return CTX_FL_TEST(context, CTX_FL_TRACING) ? Qtrue : Qfalse;
    }

tracing = bool click to toggle source

Controls the tracing for this context.

    static VALUE
    Context_set_tracing(VALUE self, VALUE value)
    {
      debug_context_t *context;

      Data_Get_Struct(self, debug_context_t, context);

      if (RTEST(value))
        CTX_FL_SET(context, CTX_FL_TRACING);
      else
        CTX_FL_UNSET(context, CTX_FL_TRACING);
      return value;
    }

### Private Instance Methods

c_frame_args(frame_no) click to toggle source

Gets method arguments for a c-frame.

@param frame_no Frame index in the backtrace.

    # File lib/byebug/context.rb, line 104
    def c_frame_args(frame_no)
      myself = frame_self(frame_no)
      return [] unless myself.to_s != 'main'

      myself.method(frame_method(frame_no)).parameters
    end

ruby_frame_args(bind) click to toggle source

Gets method arguments for a ruby-frame.

@param bind Binding for the ruby-frame.

    # File lib/byebug/context.rb, line 116
    def ruby_frame_args(bind)
      return [] unless bind.eval('__method__')

      bind.eval('method(__method__).parameters')
    rescue NameError => e
      Byebug.errmsg          "Exception #{e.class} (#{e.message}) while retreving frame params"
      []
    end