byebug 2.7.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -6
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +23 -0
  5. data/Gemfile +9 -0
  6. data/README.md +35 -32
  7. data/Rakefile +1 -3
  8. data/byebug.gemspec +0 -6
  9. data/ext/byebug/byebug.c +64 -51
  10. data/ext/byebug/byebug.h +12 -13
  11. data/ext/byebug/context.c +28 -43
  12. data/ext/byebug/extconf.rb +6 -6
  13. data/lib/byebug.rb +34 -38
  14. data/lib/byebug/command.rb +4 -2
  15. data/lib/byebug/commands/continue.rb +0 -1
  16. data/lib/byebug/commands/control.rb +0 -1
  17. data/lib/byebug/commands/edit.rb +1 -1
  18. data/lib/byebug/commands/finish.rb +10 -16
  19. data/lib/byebug/commands/help.rb +1 -1
  20. data/lib/byebug/commands/kill.rb +1 -1
  21. data/lib/byebug/commands/quit.rb +1 -1
  22. data/lib/byebug/commands/repl.rb +3 -3
  23. data/lib/byebug/commands/set.rb +24 -39
  24. data/lib/byebug/commands/show.rb +39 -112
  25. data/lib/byebug/commands/stepping.rb +0 -2
  26. data/lib/byebug/commands/threads.rb +0 -5
  27. data/lib/byebug/commands/trace.rb +1 -1
  28. data/lib/byebug/commands/variables.rb +1 -1
  29. data/lib/byebug/context.rb +8 -12
  30. data/lib/byebug/helper.rb +1 -1
  31. data/lib/byebug/history.rb +46 -0
  32. data/lib/byebug/interface.rb +5 -5
  33. data/lib/byebug/interfaces/local_interface.rb +11 -62
  34. data/lib/byebug/interfaces/remote_interface.rb +6 -22
  35. data/lib/byebug/interfaces/script_interface.rb +2 -17
  36. data/lib/byebug/processor.rb +4 -4
  37. data/lib/byebug/{command_processor.rb → processors/command_processor.rb} +7 -14
  38. data/lib/byebug/{control_command_processor.rb → processors/control_command_processor.rb} +3 -7
  39. data/lib/byebug/version.rb +1 -1
  40. data/test/edit_test.rb +6 -6
  41. data/test/examples/breakpoint_deep.rb +1 -1
  42. data/test/finish_test.rb +6 -6
  43. data/test/help_test.rb +1 -1
  44. data/test/info_test.rb +0 -1
  45. data/test/kill_test.rb +2 -2
  46. data/test/post_mortem_test.rb +35 -219
  47. data/test/quit_test.rb +2 -2
  48. data/test/restart_test.rb +12 -33
  49. data/test/set_test.rb +80 -107
  50. data/test/show_test.rb +42 -77
  51. data/test/stepping_test.rb +1 -1
  52. data/test/support/test_dsl.rb +4 -25
  53. data/test/support/test_interface.rb +40 -48
  54. data/test/test_helper.rb +1 -3
  55. data/test/timeout_test.rb +9 -0
  56. metadata +8 -75
@@ -12,8 +12,7 @@ reset_stepping_stop_points(debug_context_t *context)
12
12
  context->dest_frame = -1;
13
13
  context->lines = -1;
14
14
  context->steps = -1;
15
- context->after_frame = -1;
16
- context->before_frame = -1;
15
+ context->steps_out = -1;
17
16
  }
18
17
 
19
18
  /*
@@ -38,16 +37,10 @@ context_mark(void *data)
38
37
  rb_gc_mark(context->backtrace);
39
38
  }
40
39
 
41
- static void
42
- context_free(void *data)
43
- {
44
-
45
- }
46
-
47
40
  static int
48
41
  real_stack_size()
49
42
  {
50
- return FIX2INT(rb_funcall(cContext, rb_intern("real_stack_size"), 0));
43
+ return FIX2INT(rb_funcall(cContext, rb_intern("stack_size"), 1, Qtrue));
51
44
  }
52
45
 
53
46
  extern VALUE
@@ -67,7 +60,7 @@ context_create(VALUE thread)
67
60
 
68
61
  if (rb_obj_class(thread) == cDebugThread) CTX_FL_SET(context, CTX_FL_IGNORE);
69
62
 
70
- return Data_Wrap_Struct(cContext, context_mark, context_free, context);
63
+ return Data_Wrap_Struct(cContext, context_mark, 0, context);
71
64
  }
72
65
 
73
66
  extern VALUE
@@ -80,7 +73,7 @@ context_dup(debug_context_t *context)
80
73
  new_context->backtrace = context->backtrace;
81
74
  CTX_FL_SET(new_context, CTX_FL_DEAD);
82
75
 
83
- return Data_Wrap_Struct(cContext, context_mark, context_free, new_context);
76
+ return Data_Wrap_Struct(cContext, context_mark, 0, new_context);
84
77
  }
85
78
 
86
79
  static VALUE
@@ -225,7 +218,7 @@ Context_frame_binding(int argc, VALUE *argv, VALUE self)
225
218
  *
226
219
  * Returns frame's defined class.
227
220
  */
228
- static VALUE
221
+ static VALUE
229
222
  Context_frame_class(int argc, VALUE *argv, VALUE self)
230
223
  {
231
224
  FRAME_SETUP
@@ -405,8 +398,7 @@ Context_stop_reason(VALUE self)
405
398
  static VALUE
406
399
  Context_step_into(int argc, VALUE *argv, VALUE self)
407
400
  {
408
- VALUE steps;
409
- VALUE force;
401
+ VALUE steps, force;
410
402
  debug_context_t *context;
411
403
 
412
404
  rb_scan_args(argc, argv, "11", &steps, &force);
@@ -428,22 +420,35 @@ Context_step_into(int argc, VALUE *argv, VALUE self)
428
420
  * call-seq:
429
421
  * context.step_out(frame)
430
422
  *
431
- * Stops after frame number +frame+ is activated. Implements +finish+ and
432
- * +next+ commands.
423
+ * Stops after +n_frames+ frames are finished. Implements +finish+ and
424
+ * +next+ commands. +force+ parameter (if true) ensures that the cursor will
425
+ * stop in the specified frame even when there's no more instructions to run.
426
+ * In that case, it will stop when the return event for that frame is
427
+ * triggered.
433
428
  */
434
429
  static VALUE
435
- Context_step_out(VALUE self, VALUE frame)
430
+ Context_step_out(int argc, VALUE *argv, VALUE self)
436
431
  {
432
+ int n_args, n_frames;
433
+ VALUE v_frames, v_force;
437
434
  debug_context_t *context;
438
435
 
436
+ n_args = rb_scan_args(argc, argv, "02", &v_frames, &v_force);
437
+ n_frames = n_args == 0 ? 1 : FIX2INT(v_frames);
438
+ v_force = (n_args < 2) ? Qfalse : v_force;
439
+
439
440
  Data_Get_Struct(self, debug_context_t, context);
440
441
 
441
- if (FIX2INT(frame) < 0 || FIX2INT(frame) >= context->calced_stack_size)
442
+ if (n_frames < 0 || n_frames >= context->calced_stack_size)
442
443
  rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
443
444
 
444
- context->after_frame = context->calced_stack_size - FIX2INT(frame);
445
+ context->steps_out = n_frames;
446
+ if (RTEST(v_force))
447
+ CTX_FL_SET(context, CTX_FL_STOP_ON_RET);
448
+ else
449
+ CTX_FL_UNSET(context, CTX_FL_STOP_ON_RET);
445
450
 
446
- return frame;
451
+ return Qnil;
447
452
  }
448
453
 
449
454
  /*
@@ -481,27 +486,6 @@ Context_step_over(int argc, VALUE *argv, VALUE self)
481
486
  return Qnil;
482
487
  }
483
488
 
484
- /*
485
- * call-seq:
486
- * context.stop_return(frame)
487
- *
488
- * Stops before frame number +frame+ is activated. Useful when you enter the
489
- * debugger after the last statement in a method.
490
- */
491
- static VALUE
492
- Context_stop_return(VALUE self, VALUE frame)
493
- {
494
- debug_context_t *context;
495
-
496
- Data_Get_Struct(self, debug_context_t, context);
497
- if (FIX2INT(frame) < 0 || FIX2INT(frame) >= context->calced_stack_size)
498
- rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
499
-
500
- context->before_frame = context->calced_stack_size - FIX2INT(frame);
501
-
502
- return frame;
503
- }
504
-
505
489
  static void
506
490
  context_suspend_0(debug_context_t *context)
507
491
  {
@@ -619,6 +603,8 @@ static VALUE
619
603
  DebugThread_inherited(VALUE klass)
620
604
  {
621
605
  rb_raise(rb_eRuntimeError, "Can't inherit Byebug::DebugThread class");
606
+
607
+ return Qnil;
622
608
  }
623
609
 
624
610
  /*
@@ -644,9 +630,8 @@ Init_context(VALUE mByebug)
644
630
  rb_define_method(cContext, "resume" , Context_resume , 0);
645
631
  rb_define_method(cContext, "calced_stack_size", Context_calced_stack_size, 0);
646
632
  rb_define_method(cContext, "step_into" , Context_step_into , -1);
647
- rb_define_method(cContext, "step_out" , Context_step_out , 1);
633
+ rb_define_method(cContext, "step_out" , Context_step_out , -1);
648
634
  rb_define_method(cContext, "step_over" , Context_step_over , -1);
649
- rb_define_method(cContext, "stop_return" , Context_stop_return , 1);
650
635
  rb_define_method(cContext, "stop_reason" , Context_stop_reason , 0);
651
636
  rb_define_method(cContext, "suspend" , Context_suspend , 0);
652
637
  rb_define_method(cContext, "suspended?" , Context_is_suspended , 0);
@@ -1,17 +1,17 @@
1
- require 'mkmf'
2
-
3
- RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
4
-
5
- if RUBY_VERSION < "2.0"
1
+ if RUBY_VERSION < '2.0'
6
2
  STDERR.print("Ruby version is too old\n")
7
3
  exit(1)
8
4
  end
9
5
 
6
+ require 'mkmf'
7
+
8
+ RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
9
+
10
10
  if RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/
11
11
  $CFLAGS ||= ''
12
12
  $CFLAGS += ' -Wall -Werror -Wno-unused-parameter'
13
13
  $CFLAGS += ' -gdwarf-2 -g3 -O0' if ENV['debug']
14
14
  end
15
15
 
16
- dir_config("ruby")
16
+ dir_config('ruby')
17
17
  create_makefile('byebug/byebug')
@@ -1,9 +1,8 @@
1
1
  require 'byebug/byebug'
2
2
  require 'byebug/version'
3
3
  require 'byebug/context'
4
+ require 'byebug/interface'
4
5
  require 'byebug/processor'
5
- require 'byebug/command_processor'
6
- require 'byebug/control_command_processor'
7
6
  require 'byebug/remote'
8
7
  require 'stringio'
9
8
  require 'tracer'
@@ -15,24 +14,26 @@ module Byebug
15
14
  IGNORED_FILES = Dir.glob(File.expand_path('../**/*.rb', __FILE__))
16
15
 
17
16
  # Default options to Byebug.start
18
- DEFAULT_START_SETTINGS = {
19
- init: true, # Set $0 and save ARGV?
20
- post_mortem: false, # post-mortem debugging on uncaught exception?
21
- tracing: nil # Byebug.tracing? value. true/false resets
22
- } unless defined?(DEFAULT_START_SETTINGS)
17
+ unless defined?(DEFAULT_START_SETTINGS)
18
+ DEFAULT_START_SETTINGS = { post_mortem: false,
19
+ tracing: false,
20
+ save_history: true }
21
+ end
23
22
 
24
23
  # Configuration file used for startup commands. Default value is .byebugrc
25
24
  INITFILE = '.byebugrc' unless defined?(INITFILE)
26
25
 
26
+ # Original ARGV, command line and initial directory to make restarts possible
27
+ ARGV = ARGV.clone unless defined?(ARGV)
28
+ PROG_SCRIPT = $0 unless defined?(PROG_SCRIPT)
29
+ INITIAL_DIR = Dir.pwd unless defined?(INITIAL_DIR)
30
+
27
31
  class << self
28
32
 
29
33
  # processor modules provide +handler+ object
30
34
  attr_accessor :handler
31
35
  Byebug.handler = CommandProcessor.new
32
36
 
33
- attr_accessor :last_exception
34
- Byebug.last_exception = nil
35
-
36
37
  def source_reload
37
38
  Object.send(:remove_const, 'SCRIPT_LINES__') if
38
39
  Object.const_defined?('SCRIPT_LINES__')
@@ -102,25 +103,23 @@ module Byebug
102
103
  # many times as you called Byebug.start method.</i>
103
104
  #
104
105
  # +options+ is a hash used to set various debugging options.
105
- # :init - true if you want to save ARGV and some other variables to
106
- # make a byebug restart possible. Only the first time :init
107
- # is set to true the values will get set. Since ARGV is
108
- # saved, you should make sure it hasn't been changed before
109
- # the (first) call.
110
- # :post_mortem - true if you want to enter post-mortem debugging on an
111
- # uncaught exception. Once post-mortem debugging is set, it
112
- # can't be unset.
106
+ # :post_mortem - true if you want to enter post-mortem debugging on an
107
+ # uncaught exception, false otherwise. Default: false.
108
+ # :tracing - true if line tracing should be enabled, false otherwise.
109
+ # Default: false.
110
+ # :save_history - true if byebug's command history should be saved to a
111
+ # file on program termination so that it can be reloaded
112
+ # later.
113
113
  #
114
114
  def start(options={}, &block)
115
115
  options = Byebug::DEFAULT_START_SETTINGS.merge(options)
116
- if options[:init]
117
- Byebug.const_set('ARGV', ARGV.clone) unless defined? Byebug::ARGV
118
- Byebug.const_set('PROG_SCRIPT', $0) unless defined? Byebug::PROG_SCRIPT
119
- Byebug.const_set('INITIAL_DIR', Dir.pwd) unless defined? Byebug::INITIAL_DIR
120
- end
121
- Byebug.tracing = options[:tracing] unless options[:tracing].nil?
116
+ Byebug.tracing = options[:tracing]
117
+
122
118
  retval = Byebug._start(&block)
119
+
123
120
  post_mortem if options[:post_mortem]
121
+ at_exit { Byebug::History.save } if options[:save_history]
122
+
124
123
  return retval
125
124
  end
126
125
 
@@ -139,7 +138,7 @@ module Byebug
139
138
 
140
139
  home_script = File.expand_path(File.join(ENV['HOME'].to_s, INITFILE))
141
140
  if File.exist?(home_script) and cwd_script != home_script
142
- run_script(home_script, out)
141
+ run_script(home_script, out)
143
142
  end
144
143
  end
145
144
 
@@ -161,17 +160,17 @@ module Byebug
161
160
  #
162
161
  def post_mortem
163
162
  return if self.post_mortem?
164
- at_exit { handle_post_mortem($!) if post_mortem? }
165
163
  self.post_mortem = true
164
+ at_exit { handle_post_mortem if post_mortem? }
166
165
  end
167
166
 
168
- def handle_post_mortem(exp)
169
- return if !exp
170
- Byebug.last_exception = exp
171
- return if !exp.__bb_context || !exp.__bb_context.calced_stack_size
167
+ def handle_post_mortem
168
+ context = raised_exception.__bb_context
169
+ file = raised_exception.__bb_file
170
+ line = raised_exception.__bb_line
172
171
  orig_tracing = Byebug.tracing?
173
172
  Byebug.tracing = false
174
- handler.at_line(exp.__bb_context, exp.__bb_file, exp.__bb_line)
173
+ handler.at_line(context, file, line)
175
174
  ensure
176
175
  Byebug.tracing = orig_tracing
177
176
  end
@@ -185,16 +184,13 @@ end
185
184
 
186
185
  module Kernel
187
186
  #
188
- # Enters byebug after _steps_into_ line events and _steps_out_ return events
189
- # occur. Before entering byebug startup, the init script is read.
187
+ # Enters byebug right before (or right after if _before_ is false) return
188
+ # events occur. Before entering byebug the init script is read.
190
189
  #
191
- def byebug(steps_into = 1, steps_out = 2)
190
+ def byebug(steps_out = 1, before = true)
192
191
  Byebug.start
193
192
  Byebug.run_init_script(StringIO.new)
194
- if Byebug.current_context.calced_stack_size > 2
195
- Byebug.current_context.stop_return steps_out if steps_out >= 1
196
- end
197
- Byebug.current_context.step_into steps_into if steps_into >= 0
193
+ Byebug.current_context.step_out(steps_out, before)
198
194
  end
199
195
 
200
196
  alias_method :debugger, :byebug
@@ -1,6 +1,6 @@
1
1
  require 'columnize'
2
2
  require 'forwardable'
3
- require_relative 'helper'
3
+ require 'byebug/helper'
4
4
 
5
5
  module Byebug
6
6
 
@@ -23,7 +23,7 @@ module Byebug
23
23
  @commands ||= []
24
24
  end
25
25
 
26
- attr_accessor :allow_in_control, :unknown, :need_context
26
+ attr_accessor :allow_in_control, :unknown
27
27
  attr_writer :allow_in_post_mortem, :always_run
28
28
 
29
29
  def allow_in_post_mortem
@@ -143,6 +143,7 @@ module Byebug
143
143
  end
144
144
 
145
145
  # Register default settings
146
+ register_setting_var(:autosave, true)
146
147
  register_setting_var(:basename, false)
147
148
  register_setting_var(:callstyle, :long)
148
149
  register_setting_var(:testing, false)
@@ -217,6 +218,7 @@ module Byebug
217
218
  # :autolist - automatically calls 'list' command on breakpoint
218
219
  # :autoreload - makes 'list' command always display up-to-date source
219
220
  # code
221
+ # :autosave - automatic saving of command history on exit
220
222
  # :frame_class_names - displays method's class name when showing frame stack
221
223
  # :forcestep - stepping command always move to the new line
222
224
  # :fullpath - displays full paths when showing frame stack
@@ -3,7 +3,6 @@ module Byebug
3
3
  # Implements byebug "continue" command.
4
4
  class ContinueCommand < Command
5
5
  self.allow_in_post_mortem = true
6
- self.need_context = false
7
6
 
8
7
  def regexp
9
8
  /^\s* c(?:ont(?:inue)?)? (?:\s+(\S+))? \s*$/x
@@ -66,7 +66,6 @@ module Byebug
66
66
  class InterruptCommand < Command
67
67
  self.allow_in_control = true
68
68
  self.allow_in_post_mortem = false
69
- self.need_context = true
70
69
 
71
70
  def regexp
72
71
  /^\s*i(?:nterrupt)?\s*$/
@@ -1,6 +1,6 @@
1
1
  module Byebug
2
2
 
3
- class Edit < Command
3
+ class EditCommand < Command
4
4
  self.allow_in_control = true
5
5
 
6
6
  def regexp
@@ -3,21 +3,18 @@ module Byebug
3
3
  # Implements byebug's 'finish' command.
4
4
  class FinishCommand < Command
5
5
  self.allow_in_post_mortem = false
6
- self.need_context = true
7
6
 
8
7
  def regexp
9
8
  /^\s* fin(?:ish)? (?:\s+(\S+))? \s*$/x
10
9
  end
11
10
 
12
11
  def execute
13
- if not @match[1]
14
- frame_pos = @state.frame_pos
15
- else
16
- max_frame = Context.stack_size - @state.frame_pos
17
- frame_pos = get_int(@match[1], "finish", 0, max_frame-1, 0)
18
- return nil unless frame_pos
19
- end
20
- @state.context.step_out frame_pos
12
+ max_frames = Context.stack_size - @state.frame_pos
13
+ n_frames = get_int(@match[1], "finish", 0, max_frames - 1, 1)
14
+ return nil unless n_frames
15
+
16
+ force = n_frames == 0 ? true : false
17
+ @state.context.step_out(@state.frame_pos + n_frames, force)
21
18
  @state.frame_pos = 0
22
19
  @state.proceed
23
20
  end
@@ -28,14 +25,11 @@ module Byebug
28
25
  end
29
26
 
30
27
  def description
31
- %{fin[ish][ frame-number]\tExecute until selected stack frame returns.
32
-
33
- If no frame number is given, we run until the currently selected frame
34
- returns. The currently selected frame starts out the most-recent frame
35
- or 0 if no frame positioning (e.g "up", "down" or "frame") has been
36
- performed.
28
+ %{fin[ish][ n_frames]\tExecute until frame returns.
37
29
 
38
- If a frame number is given we run until that frame returns.}
30
+ If no number is given, we run until the current frame returns. If a
31
+ number of frames `n_frames` is given, then we run until `n_frames`
32
+ return from the current position.}
39
33
  end
40
34
  end
41
35
  end
@@ -21,7 +21,7 @@ module Byebug
21
21
  help.pop if help.last && help.last.empty?
22
22
  return print help.join("\n") + "\n"
23
23
  else
24
- return errmsg "Undefined command: \"#{args[0]}\". Try \"help\".\n" if
24
+ return errmsg "Undefined command: \"#{args[0]}\". Try \"help\".\n" if
25
25
  args[0]
26
26
  end
27
27
  end
@@ -16,7 +16,7 @@ module Byebug
16
16
  return false
17
17
  end
18
18
  if 'KILL' == signame
19
- @state.interface.finalize
19
+ @state.interface.close
20
20
  end
21
21
  else
22
22
  if not confirm("Really kill? (y/n) ")
@@ -10,7 +10,7 @@ module Byebug
10
10
 
11
11
  def execute
12
12
  if @match[1] or confirm("Really quit? (y/n) ")
13
- @state.interface.finalize
13
+ @state.interface.close
14
14
  exit! # exit -> exit!: No graceful way to stop...
15
15
  end
16
16
  end
@@ -50,12 +50,12 @@ end
50
50
  module Byebug
51
51
 
52
52
  # Implements byebug's "irb" command.
53
- class IRBCommand < Command
53
+ class IrbCommand < Command
54
54
  register_setting_get(:autoirb) do
55
- IRBCommand.always_run
55
+ IrbCommand.always_run
56
56
  end
57
57
  register_setting_set(:autoirb) do |value|
58
- IRBCommand.always_run = value
58
+ IrbCommand.always_run = value
59
59
  end
60
60
 
61
61
  def regexp