byebug 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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