byebug 2.1.1 → 2.2.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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +9 -0
  4. data/CONTRIBUTING.md +13 -1
  5. data/GUIDE.md +181 -1
  6. data/README.md +67 -211
  7. data/Rakefile +1 -0
  8. data/bin/byebug +1 -8
  9. data/ext/byebug/byebug.c +66 -25
  10. data/ext/byebug/context.c +16 -20
  11. data/ext/byebug/extconf.rb +2 -1
  12. data/lib/byebug.rb +16 -9
  13. data/lib/byebug/command.rb +3 -3
  14. data/lib/byebug/commands/condition.rb +2 -2
  15. data/lib/byebug/commands/edit.rb +12 -9
  16. data/lib/byebug/commands/eval.rb +0 -16
  17. data/lib/byebug/commands/frame.rb +7 -17
  18. data/lib/byebug/commands/info.rb +2 -9
  19. data/lib/byebug/commands/list.rb +1 -1
  20. data/lib/byebug/commands/reload.rb +11 -0
  21. data/lib/byebug/commands/repl.rb +3 -6
  22. data/lib/byebug/commands/set.rb +5 -5
  23. data/lib/byebug/commands/show.rb +5 -0
  24. data/lib/byebug/commands/threads.rb +4 -4
  25. data/lib/byebug/commands/trace.rb +2 -1
  26. data/lib/byebug/context.rb +14 -5
  27. data/lib/byebug/interface.rb +1 -1
  28. data/lib/byebug/processor.rb +1 -1
  29. data/lib/byebug/remote.rb +1 -24
  30. data/lib/byebug/version.rb +1 -1
  31. data/old_doc/byebug.1 +0 -3
  32. data/old_doc/byebug.texi +2 -3
  33. data/test/breakpoints_test.rb +75 -52
  34. data/test/conditions_test.rb +2 -3
  35. data/test/continue_test.rb +6 -0
  36. data/test/edit_test.rb +3 -3
  37. data/test/eval_test.rb +14 -5
  38. data/test/examples/breakpoint.rb +4 -13
  39. data/test/examples/breakpoint_deep.rb +1 -21
  40. data/test/examples/conditions.rb +1 -1
  41. data/test/examples/continue.rb +2 -1
  42. data/test/examples/edit.rb +1 -0
  43. data/test/examples/eval.rb +1 -11
  44. data/test/examples/finish.rb +0 -17
  45. data/test/examples/frame.rb +2 -26
  46. data/test/examples/frame_deep.rb +0 -19
  47. data/test/examples/help.rb +0 -1
  48. data/test/examples/info.rb +4 -36
  49. data/test/examples/kill.rb +1 -1
  50. data/test/examples/list.rb +1 -1
  51. data/test/examples/method.rb +2 -13
  52. data/test/examples/post_mortem.rb +1 -16
  53. data/test/examples/quit.rb +1 -1
  54. data/test/examples/reload.rb +1 -1
  55. data/test/examples/restart.rb +1 -1
  56. data/test/examples/show.rb +0 -1
  57. data/test/examples/stepping.rb +2 -19
  58. data/test/examples/thread.rb +0 -27
  59. data/test/examples/variables.rb +0 -22
  60. data/test/finish_test.rb +22 -6
  61. data/test/frame_test.rb +89 -56
  62. data/test/info_test.rb +71 -46
  63. data/test/kill_test.rb +6 -1
  64. data/test/list_test.rb +1 -2
  65. data/test/method_test.rb +32 -13
  66. data/test/post_mortem_test.rb +34 -21
  67. data/test/quit_test.rb +0 -1
  68. data/test/restart_test.rb +6 -0
  69. data/test/set_test.rb +1 -1
  70. data/test/show_test.rb +17 -17
  71. data/test/source_test.rb +2 -3
  72. data/test/stepping_test.rb +31 -7
  73. data/test/support/test_dsl.rb +11 -1
  74. data/test/test_helper.rb +9 -0
  75. data/test/thread_test.rb +57 -23
  76. data/test/trace_test.rb +0 -1
  77. data/test/variables_test.rb +36 -17
  78. metadata +3 -9
  79. data/test/examples/breakpoint2.rb +0 -7
  80. data/test/examples/jump.rb +0 -14
  81. data/test/examples/set_annotate.rb +0 -12
data/Rakefile CHANGED
@@ -10,6 +10,7 @@ desc "Run MiniTest suite"
10
10
  task :test do
11
11
  Rake::TestTask.new(:test) do |t|
12
12
  t.test_files = FileList["test/*_test.rb"]
13
+ t.warning = true
13
14
  t.verbose = true
14
15
  end
15
16
  end
data/bin/byebug CHANGED
@@ -62,9 +62,8 @@ require File.dirname(__FILE__) + "/../lib/byebug"
62
62
 
63
63
  def debug_program(options)
64
64
  # Make sure Ruby script syntax checks okay.
65
- # Otherwise we get a load message that looks like byebug has a problem.
66
65
  output = `ruby -c "#{Byebug::PROG_SCRIPT}" 2>&1`
67
- if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/
66
+ if $?.exitstatus != 0
68
67
  puts output
69
68
  exit $?.exitstatus
70
69
  end
@@ -96,7 +95,6 @@ options = OpenStruct.new(
96
95
  'script' => nil,
97
96
  'stop' => true,
98
97
  'tracing' => false,
99
- 'verbose_long' => false
100
98
  )
101
99
 
102
100
  def process_options(options)
@@ -158,10 +156,6 @@ EOB
158
156
  puts "byebug #{Byebug::VERSION}"
159
157
  exit
160
158
  end
161
- opts.on('--verbose', 'Turn on verbose mode') do
162
- $VERBOSE = true
163
- options.verbose_long = true
164
- end
165
159
  opts.on_tail('-v', 'Print version number, then turn on verbose mode') do
166
160
  puts "byebug #{Byebug::VERSION}"
167
161
  $VERBOSE = true
@@ -198,7 +192,6 @@ rescue StandardError => e
198
192
  end
199
193
 
200
194
  if ARGV.empty?
201
- exit if $VERBOSE and not options.verbose_long
202
195
  puts opts
203
196
  puts
204
197
  puts 'Must specify a script to run'
@@ -4,7 +4,7 @@ static VALUE mByebug; /* Ruby Byebug Module object */
4
4
 
5
5
  static VALUE tracing = Qfalse;
6
6
  static VALUE post_mortem = Qfalse;
7
- static VALUE debug = Qfalse;
7
+ static VALUE verbose = Qfalse;
8
8
 
9
9
  static VALUE catchpoints = Qnil;
10
10
  static VALUE breakpoints = Qnil;
@@ -69,7 +69,7 @@ cleanup(debug_context_t *dc)
69
69
  VALUE context; \
70
70
  thread_context_lookup(rb_thread_current(), &context); \
71
71
  Data_Get_Struct(context, debug_context_t, dc); \
72
- if (debug == Qtrue) trace_print(trace_arg, dc); \
72
+ if (verbose == Qtrue) trace_print(trace_arg, dc); \
73
73
 
74
74
  #define EVENT_COMMON if (!trace_common(trace_arg, dc)) { return; }
75
75
 
@@ -182,13 +182,15 @@ call_at_line_check(VALUE context_obj, debug_context_t *dc,
182
182
  static void
183
183
  line_event(VALUE trace_point, void *data)
184
184
  {
185
+ VALUE breakpoint, file, line, binding;
186
+ int moved = 0;
187
+
185
188
  EVENT_SETUP
186
189
 
187
- VALUE breakpoint = Qnil;
188
- VALUE file = rb_tracearg_path(trace_arg);
189
- VALUE line = rb_tracearg_lineno(trace_arg);
190
- VALUE binding = rb_tracearg_binding(trace_arg);
191
- int moved = 0;
190
+ breakpoint = Qnil;
191
+ file = rb_tracearg_path(trace_arg);
192
+ line = rb_tracearg_lineno(trace_arg);
193
+ binding = rb_tracearg_binding(trace_arg);
192
194
 
193
195
  EVENT_COMMON
194
196
 
@@ -209,7 +211,12 @@ line_event(VALUE trace_point, void *data)
209
211
  if (dc->stack_size <= dc->dest_frame)
210
212
  {
211
213
  dc->lines = dc->lines <= 0 ? -1 : dc->lines - 1;
212
- dc->dest_frame = dc->stack_size;
214
+ if (dc->stack_size < dc->dest_frame)
215
+ {
216
+ dc->dest_frame = dc->stack_size;
217
+ rb_funcall(mByebug, rb_intern("print"), 1,
218
+ rb_str_new2("Next went up a frame because previous frame finished\n"));
219
+ }
213
220
  }
214
221
  }
215
222
 
@@ -227,19 +234,21 @@ line_event(VALUE trace_point, void *data)
227
234
  static void
228
235
  call_event(VALUE trace_point, void *data)
229
236
  {
237
+ VALUE breakpoint, klass, mid, binding, self, file, line;
238
+
230
239
  EVENT_SETUP
231
240
 
232
241
  dc->stack_size++;
233
242
 
234
243
  EVENT_COMMON
235
244
 
236
- VALUE breakpoint = Qnil;
237
- VALUE klass = rb_tracearg_defined_class(trace_arg);
238
- VALUE mid = SYM2ID(rb_tracearg_method_id(trace_arg));
239
- VALUE binding = rb_tracearg_binding(trace_arg);
240
- VALUE self = rb_tracearg_self(trace_arg);
241
- VALUE file = rb_tracearg_path(trace_arg);
242
- VALUE line = rb_tracearg_lineno(trace_arg);
245
+ breakpoint = Qnil;
246
+ klass = rb_tracearg_defined_class(trace_arg);
247
+ mid = SYM2ID(rb_tracearg_method_id(trace_arg));
248
+ binding = rb_tracearg_binding(trace_arg);
249
+ self = rb_tracearg_self(trace_arg);
250
+ file = rb_tracearg_path(trace_arg);
251
+ line = rb_tracearg_lineno(trace_arg);
243
252
 
244
253
  breakpoint = find_breakpoint_by_method(breakpoints, klass, mid, binding, self);
245
254
  if (breakpoint != Qnil)
@@ -262,9 +271,11 @@ return_event(VALUE trace_point, void *data)
262
271
 
263
272
  if (dc->stack_size + 1 == dc->before_frame)
264
273
  {
274
+ VALUE file, line;
275
+
265
276
  reset_stepping_stop_points(dc);
266
- VALUE file = rb_tracearg_path(trace_arg);
267
- VALUE line = rb_tracearg_lineno(trace_arg);
277
+ file = rb_tracearg_path(trace_arg);
278
+ line = rb_tracearg_lineno(trace_arg);
268
279
  call_at_return(context, dc, file, line);
269
280
  }
270
281
 
@@ -304,19 +315,22 @@ c_return_event(VALUE trace_point, void *data)
304
315
  static void
305
316
  raise_event(VALUE trace_point, void *data)
306
317
  {
307
- EVENT_SETUP
308
-
309
318
  VALUE expn_class, aclass;
310
- VALUE err = rb_errinfo();
319
+ VALUE err;
311
320
  VALUE ancestors;
312
321
  int i;
313
322
  debug_context_t *new_dc;
323
+ VALUE binding, path, lineno;
324
+
325
+ EVENT_SETUP
326
+
327
+ err = rb_errinfo();
314
328
 
315
329
  EVENT_COMMON
316
330
 
317
- VALUE binding = rb_tracearg_binding(trace_arg);
318
- VALUE path = rb_tracearg_path(trace_arg);
319
- VALUE lineno = rb_tracearg_lineno(trace_arg);
331
+ binding = rb_tracearg_binding(trace_arg);
332
+ path = rb_tracearg_path(trace_arg);
333
+ lineno = rb_tracearg_lineno(trace_arg);
320
334
 
321
335
  if (post_mortem == Qtrue)
322
336
  {
@@ -374,8 +388,6 @@ register_tracepoints(VALUE self)
374
388
 
375
389
  if (NIL_P(traces))
376
390
  {
377
- traces = rb_ary_new();
378
-
379
391
  int line_msk = RUBY_EVENT_LINE;
380
392
  int call_msk = RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS;
381
393
  int return_msk = RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END;
@@ -390,6 +402,7 @@ register_tracepoints(VALUE self)
390
402
  VALUE tpCReturn = rb_tracepoint_new(Qnil, c_return_msk, c_return_event, 0);
391
403
  VALUE tpRaise = rb_tracepoint_new(Qnil, raise_msk , raise_event , 0);
392
404
 
405
+ traces = rb_ary_new();
393
406
  rb_ary_push(traces, tpLine);
394
407
  rb_ary_push(traces, tpCall);
395
408
  rb_ary_push(traces, tpReturn);
@@ -613,6 +626,32 @@ bb_load(int argc, VALUE *argv, VALUE self)
613
626
  return status;
614
627
  }
615
628
 
629
+ /*
630
+ * call-seq:
631
+ * Byebug.verbose -> bool
632
+ *
633
+ * Returns +true+ if verbose output of TracePoint API events is enabled.
634
+ */
635
+ static VALUE
636
+ bb_verbose(VALUE self)
637
+ {
638
+ return verbose;
639
+ }
640
+
641
+ /*
642
+ * call-seq:
643
+ * Byebug.verbose = bool
644
+ *
645
+ * Enable verbose output of every TracePoint API events, useful for debugging
646
+ * byebug.
647
+ */
648
+ static VALUE
649
+ bb_set_verbose(VALUE self, VALUE value)
650
+ {
651
+ verbose = RTEST(value) ? Qtrue : Qfalse;
652
+ return value;
653
+ }
654
+
616
655
  static VALUE
617
656
  set_current_skipped_status(VALUE status)
618
657
  {
@@ -784,6 +823,8 @@ Init_byebug()
784
823
  rb_define_module_function(mByebug, "thread_context" , bb_thread_context , 1);
785
824
  rb_define_module_function(mByebug, "tracing?" , bb_tracing , 0);
786
825
  rb_define_module_function(mByebug, "tracing=" , bb_set_tracing , 1);
826
+ rb_define_module_function(mByebug, "verbose" , bb_verbose , 0);
827
+ rb_define_module_function(mByebug, "verbose=" , bb_set_verbose , 1);
787
828
 
788
829
  cThreadsTable = rb_define_class_under(mByebug, "ThreadsTable", rb_cObject);
789
830
 
@@ -45,13 +45,9 @@ context_free(void *data)
45
45
  }
46
46
 
47
47
  static int
48
- real_stack_size(VALUE thread)
48
+ real_stack_size()
49
49
  {
50
- VALUE locs = rb_funcall(thread, rb_intern("backtrace_locations"), 1, INT2FIX(1));
51
- if (locs == Qnil)
52
- return 0;
53
-
54
- return (int)RARRAY_LEN(locs);
50
+ return FIX2INT(rb_funcall(cContext, rb_intern("real_stack_size"), 0));
55
51
  }
56
52
 
57
53
  extern VALUE
@@ -62,7 +58,7 @@ context_create(VALUE thread)
62
58
  context->last_file = Qnil;
63
59
  context->last_line = Qnil;
64
60
  context->flags = 0;
65
- context->stack_size = real_stack_size(thread);
61
+ context->stack_size = real_stack_size();
66
62
  context->thnum = ++thnum_max;
67
63
  context->thread = thread;
68
64
  reset_stepping_stop_points(context);
@@ -97,13 +93,15 @@ static VALUE
97
93
  dc_frame_get(const debug_context_t *context, int frame_index,
98
94
  enum frame_component type)
99
95
  {
96
+ VALUE frame;
97
+
100
98
  if (NIL_P(dc_backtrace(context)))
101
99
  rb_raise(rb_eRuntimeError, "Backtrace information is not available");
102
100
 
103
101
  if (frame_index >= RARRAY_LEN(dc_backtrace(context)))
104
102
  rb_raise(rb_eRuntimeError, "That frame doesn't exist!");
105
103
 
106
- VALUE frame = rb_ary_entry(dc_backtrace(context), frame_index);
104
+ frame = rb_ary_entry(dc_backtrace(context), frame_index);
107
105
  return rb_ary_entry(frame, type);
108
106
  }
109
107
 
@@ -243,9 +241,11 @@ Context_frame_class(int argc, VALUE *argv, VALUE self)
243
241
  static VALUE
244
242
  Context_frame_file(int argc, VALUE *argv, VALUE self)
245
243
  {
244
+ VALUE loc;
245
+
246
246
  FRAME_SETUP
247
247
 
248
- VALUE loc = dc_frame_location(context, frame_n);
248
+ loc = dc_frame_location(context, frame_n);
249
249
 
250
250
  return rb_funcall(loc, rb_intern("path"), 0);
251
251
  }
@@ -259,9 +259,11 @@ Context_frame_file(int argc, VALUE *argv, VALUE self)
259
259
  static VALUE
260
260
  Context_frame_line(int argc, VALUE *argv, VALUE self)
261
261
  {
262
+ VALUE loc;
263
+
262
264
  FRAME_SETUP
263
265
 
264
- VALUE loc = dc_frame_location(context, frame_n);
266
+ loc = dc_frame_location(context, frame_n);
265
267
 
266
268
  return rb_funcall(loc, rb_intern("lineno"), 0);
267
269
  }
@@ -275,9 +277,11 @@ Context_frame_line(int argc, VALUE *argv, VALUE self)
275
277
  static VALUE
276
278
  Context_frame_method(int argc, VALUE *argv, VALUE self)
277
279
  {
280
+ VALUE loc;
281
+
278
282
  FRAME_SETUP
279
283
 
280
- VALUE loc = dc_frame_location(context, frame_n);
284
+ loc = dc_frame_location(context, frame_n);
281
285
 
282
286
  return rb_str_intern(rb_funcall(loc, rb_intern("label"), 0));
283
287
  }
@@ -354,16 +358,8 @@ Context_stack_size(VALUE self)
354
358
  {
355
359
  debug_context_t *context;
356
360
  Data_Get_Struct(self, debug_context_t, context);
357
- VALUE backtrace = dc_backtrace(context);
358
-
359
- if (NIL_P(backtrace))
360
- return INT2FIX(context->stack_size);
361
-
362
- if (context->stack_size != RARRAY_LEN(backtrace))
363
- rb_warn("Calculated stack size is %d but there are actually %ld frames",
364
- context->stack_size, RARRAY_LEN(backtrace));
365
361
 
366
- return INT2FIX(RARRAY_LEN(backtrace));
362
+ return INT2FIX(context->stack_size);
367
363
  }
368
364
 
369
365
  static VALUE
@@ -8,7 +8,8 @@ if RUBY_VERSION < "2.0"
8
8
  end
9
9
 
10
10
  if RbConfig::MAKEFILE_CONFIG['CC'] =~ /gcc/
11
- $CFLAGS = '-Wall -Werror'
11
+ $CFLAGS ||= ''
12
+ $CFLAGS += ' -Wall -Werror'
12
13
  $CFLAGS += ' -gdwarf-2 -g3' if ENV['debug']
13
14
  end
14
15
 
@@ -4,12 +4,11 @@ require_relative 'byebug/context'
4
4
  require_relative 'byebug/processor'
5
5
  require_relative 'byebug/remote'
6
6
  require 'stringio'
7
+ require 'tracer'
7
8
  require 'linecache19'
8
9
 
9
10
  module Byebug
10
11
 
11
- self.handler = CommandProcessor.new
12
-
13
12
  # List of files byebug will ignore while debugging
14
13
  IGNORED_FILES = Dir[Pathname.new(__FILE__) + "../**/*.rb"].map {
15
14
  |f| File.expand_path(f) }
@@ -26,14 +25,17 @@ module Byebug
26
25
 
27
26
  class << self
28
27
 
28
+ # processor modules provide +handler+ object
29
+ attr_accessor :handler
30
+ Byebug.handler = CommandProcessor.new
31
+
29
32
  attr_accessor :last_exception
30
33
  Byebug.last_exception = nil
31
34
 
32
35
  def source_reload
33
- Object.send(:remove_const, "SCRIPT_LINES__") if
34
- Object.const_defined?("SCRIPT_LINES__")
35
- Object.const_set("SCRIPT_LINES__", {})
36
- LineCache::clear_file_cache
36
+ Object.send(:remove_const, 'SCRIPT_LINES__') if
37
+ Object.const_defined?('SCRIPT_LINES__')
38
+ Object.const_set('SCRIPT_LINES__', {})
37
39
  end
38
40
 
39
41
  #
@@ -42,9 +44,11 @@ module Byebug
42
44
  # @return "\n" if there was a problem. Leaking blanks are stripped off.
43
45
  #
44
46
  def line_at(filename, line_number)
45
- @@autoreload = nil unless defined?(@@autoreload)
46
- line = LineCache::getline filename, line_number, @@autoreload
47
- return "\n" unless line
47
+ source_reload
48
+
49
+ return "\n" unless File.exist?(filename)
50
+ line = Tracer::Single.get_line(filename, line_number)
51
+
48
52
  return "#{line.gsub(/^\s+/, '').chomp}"
49
53
  end
50
54
 
@@ -69,6 +73,9 @@ module Byebug
69
73
  handler.interface = value
70
74
  end
71
75
 
76
+ extend Forwardable
77
+ def_delegators :"handler.interface", :print
78
+
72
79
  #
73
80
  # Byebug.start(options) -> bool
74
81
  # Byebug.start(options) { ... } -> obj
@@ -31,7 +31,7 @@ module Byebug
31
31
  need_context: false } unless defined?(DEF_OPTIONS)
32
32
 
33
33
  def help(args)
34
- output = description.gsub(/^ +/, '')
34
+ output = description.gsub(/^ +/, '') + "\n"
35
35
 
36
36
  if defined? self::Subcommands
37
37
  return output += format_subcmds unless args and args[1]
@@ -176,7 +176,7 @@ module Byebug
176
176
  register_setting_var(:argv, Byebug::ARGV)
177
177
 
178
178
  def initialize(state)
179
- @state = state
179
+ @match, @state = nil, state
180
180
  end
181
181
 
182
182
  def match(input)
@@ -197,7 +197,7 @@ module Byebug
197
197
  eval(str, b)
198
198
  rescue StandardError, ScriptError => e
199
199
  if Command.settings[:stack_trace_on_error]
200
- at = eval("Thread.current.backtrace_locations(1)", b)
200
+ at = eval("Thread.current.backtrace_locations", b)
201
201
  print "#{at.shift}: #{e.class} Exception(#{e.message})\n"
202
202
  for i in at
203
203
  print "\tfrom #{i}\n"
@@ -17,8 +17,8 @@ module Byebug
17
17
  return print "No breakpoints have been set.\n" if 0 == largest
18
18
  return unless pos = get_int(@match[1], "Condition", 1, largest)
19
19
 
20
- b = breakpoints.select{ |b| b.id == pos }.first
21
- b.expr = @match[2] if b
20
+ breakpoint = breakpoints.select{ |b| b.id == pos }.first
21
+ breakpoint.expr = @match[2] if breakpoint
22
22
  end
23
23
 
24
24
  class << self
@@ -9,21 +9,24 @@ module Byebug
9
9
 
10
10
  def execute
11
11
  if not @match[1]
12
- unless @state.context
13
- errmsg "We are not in a state that has an associated file.\n"
14
- return
12
+ unless @state.file
13
+ return errmsg "We are not in a state that has an associated file.\n"
15
14
  end
16
15
  file = @state.file
17
- line_number = @state.line
16
+ line = @state.line if @state.line
18
17
  elsif @pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1])
19
- file, line_number = @pos_match.captures
18
+ file, line = @pos_match.captures
19
+ elsif File.exist?(@match[1])
20
+ file = @match[1]
20
21
  else
21
- errmsg "Invalid file/line number specification: #{@match[1]}\n"
22
- return
22
+ return errmsg "Invalid file[:line] number specification: #{@match[1]}\n"
23
23
  end
24
- editor = ENV['EDITOR'] || 'ex'
24
+
25
+ editor = ENV['EDITOR'] || 'vim'
26
+
25
27
  if File.readable?(file)
26
- system("#{editor} +#{line_number} #{file}")
28
+ system("#{editor} +#{line} #{file}") if line
29
+ system("#{editor} #{file}") unless line
27
30
  else
28
31
  errmsg "File \"#{file}\" is not readable.\n"
29
32
  end