debugger 1.4.0 → 1.5.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 (75) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/README.md +9 -3
  3. data/debugger.gemspec +1 -1
  4. data/ext/ruby_debug/192/ruby_debug.c +21 -9
  5. data/ext/ruby_debug/193/ruby_debug.c +15 -5
  6. data/lib/debugger/test.rb +6 -0
  7. data/{test/support → lib/debugger/test}/breakpoint.rb +0 -0
  8. data/{test/support → lib/debugger/test}/context.rb +0 -0
  9. data/{test/support → lib/debugger/test}/matchers.rb +0 -0
  10. data/{test/support → lib/debugger/test}/mocha_extensions.rb +1 -1
  11. data/lib/debugger/test/printer_helpers.rb +8 -0
  12. data/{test/support → lib/debugger/test}/processor.rb +0 -0
  13. data/{test/support → lib/debugger/test}/test_dsl.rb +22 -2
  14. data/{test/support → lib/debugger/test}/test_interface.rb +4 -0
  15. data/lib/debugger/version.rb +1 -1
  16. data/lib/ruby-debug.rb +4 -1
  17. data/lib/ruby-debug/command.rb +18 -6
  18. data/lib/ruby-debug/commands/breakpoints.rb +27 -29
  19. data/lib/ruby-debug/commands/condition.rb +7 -2
  20. data/lib/ruby-debug/commands/continue.rb +1 -2
  21. data/lib/ruby-debug/commands/control.rb +8 -9
  22. data/lib/ruby-debug/commands/display.rb +7 -15
  23. data/lib/ruby-debug/commands/edit.rb +6 -6
  24. data/lib/ruby-debug/commands/enable.rb +6 -7
  25. data/lib/ruby-debug/commands/eval.rb +1 -3
  26. data/lib/ruby-debug/commands/frame.rb +72 -101
  27. data/lib/ruby-debug/commands/info.rb +8 -14
  28. data/lib/ruby-debug/commands/irb.rb +1 -1
  29. data/lib/ruby-debug/commands/jump.rb +6 -6
  30. data/lib/ruby-debug/commands/kill.rb +0 -1
  31. data/lib/ruby-debug/commands/list.rb +4 -4
  32. data/lib/ruby-debug/commands/method.rb +8 -11
  33. data/lib/ruby-debug/commands/quit.rb +1 -1
  34. data/lib/ruby-debug/commands/reload.rb +1 -1
  35. data/lib/ruby-debug/commands/save.rb +1 -1
  36. data/lib/ruby-debug/commands/set.rb +10 -15
  37. data/lib/ruby-debug/commands/show.rb +28 -42
  38. data/lib/ruby-debug/commands/skip.rb +1 -1
  39. data/lib/ruby-debug/commands/source.rb +1 -1
  40. data/lib/ruby-debug/commands/start.rb +26 -0
  41. data/lib/ruby-debug/commands/threads.rb +29 -18
  42. data/lib/ruby-debug/commands/tmate.rb +1 -1
  43. data/lib/ruby-debug/commands/trace.rb +6 -7
  44. data/lib/ruby-debug/commands/variables.rb +36 -19
  45. data/lib/ruby-debug/helper.rb +5 -5
  46. data/lib/ruby-debug/interface.rb +15 -3
  47. data/lib/ruby-debug/printers/base.rb +58 -0
  48. data/lib/ruby-debug/printers/plain.rb +41 -0
  49. data/lib/ruby-debug/printers/texts/base.yml +146 -0
  50. data/lib/ruby-debug/printers/texts/plain.yml +60 -0
  51. data/lib/ruby-debug/processor.rb +56 -47
  52. data/test/breakpoints_test.rb +43 -54
  53. data/test/conditions_test.rb +18 -6
  54. data/test/continue_test.rb +1 -1
  55. data/test/display_test.rb +11 -11
  56. data/test/edit_test.rb +1 -2
  57. data/test/eval_test.rb +5 -6
  58. data/test/finish_test.rb +1 -1
  59. data/test/frame_test.rb +29 -27
  60. data/test/help_test.rb +0 -1
  61. data/test/info_test.rb +10 -14
  62. data/test/irb_test.rb +0 -1
  63. data/test/jump_test.rb +21 -2
  64. data/test/method_test.rb +3 -3
  65. data/test/new/printers/plain_test.rb +84 -0
  66. data/test/reload_test.rb +2 -2
  67. data/test/restart_test.rb +1 -2
  68. data/test/set_test.rb +8 -7
  69. data/test/show_test.rb +22 -22
  70. data/test/source_test.rb +1 -1
  71. data/test/test_helper.rb +2 -1
  72. data/test/thread_test.rb +11 -13
  73. data/test/trace_test.rb +7 -7
  74. data/test/variables_test.rb +33 -15
  75. metadata +20 -12
@@ -0,0 +1,60 @@
1
+ breakpoints:
2
+ set_breakpoint_to_line: "Breakpoint {id} file {file}, line {line}"
3
+ set_breakpoint_to_method: "Breakpoint {id} at {class}::{method}"
4
+ stop_at_breakpoint: "Breakpoint {id} at {file}:{line}"
5
+ delete: "Breakpoint {id} has been deleted"
6
+
7
+ conditions:
8
+ set_condition: "Condition '{expr}' is set for the breakpoint {id}"
9
+ unset_condition: "Condition is cleared for the breakpoint {id}"
10
+
11
+ display:
12
+ result: "{n}: {exp} = {result}"
13
+
14
+ eval:
15
+ exception: "{text_message}"
16
+ result: "{result}"
17
+
18
+ frame:
19
+ line: "{mark}#{pos} {call_str}at line {file}:{line}"
20
+
21
+ method:
22
+ methods: "{name}|c"
23
+
24
+ stop:
25
+ suspend: "{file}:{line_number}\n{line}"
26
+
27
+ toggle:
28
+ breakpoint_enabled: "Breakpoint {id} is enabled"
29
+ breakpoint_disabled: "Breakpoint {id} is disabled"
30
+
31
+ restart:
32
+ success: "Re exec'ing:\n\t{cmd}"
33
+
34
+ set:
35
+ errors:
36
+ no_subcommand: "\"set\" must be followed by the name of an set command:\nList of set subcommands:\n\n{subcommands}"
37
+
38
+ show:
39
+ errors:
40
+ no_subcommand: "\"show\" must be followed by the name of an show command:\nList of show subcommands:\n\n{subcommands}"
41
+
42
+ thread:
43
+ context: "{status_flag}{debug_flag}{id} {thread}\t{file_line}"
44
+
45
+ tmate:
46
+ errors:
47
+ wrong_frame: "Wrong frame number"
48
+
49
+ trace:
50
+ messages:
51
+ all_threads: "Tracing {status} all threads"
52
+ current_thread: "Tracing {status} on current thread"
53
+ errors:
54
+ wrong_var_subcommand: "expecting 'stop' or 'nostop'; got {subcmd}"
55
+ var_is_not_global: "{name} is not a global variable"
56
+ wrong_subcommand: "expecting 'on', 'off', 'var' or 'variable'; got: {subcmd}"
57
+ trace: "traced variable {name} has value {value}"
58
+
59
+ variable:
60
+ variable: "{key} = {value}"
@@ -6,6 +6,27 @@ module Debugger
6
6
  # Should this be a mixin?
7
7
  class Processor # :nodoc
8
8
  attr_accessor :interface
9
+ extend Forwardable
10
+ def_delegator :"Debugger.printer", :print, :pr
11
+
12
+ def self.protect(mname)
13
+ alias_method "__#{mname}", mname
14
+ module_eval %{
15
+ def #{mname}(*args)
16
+ @mutex.synchronize do
17
+ return unless @interface
18
+ __#{mname}(*args)
19
+ end
20
+ rescue IOError, Errno::EPIPE
21
+ self.interface = nil
22
+ rescue SignalException
23
+ raise
24
+ rescue Exception
25
+ print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
26
+ print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
27
+ end
28
+ }
29
+ end
9
30
 
10
31
  # Format msg with gdb-style annotation header
11
32
  def afmt(msg, newline="\n")
@@ -31,6 +52,11 @@ module Debugger
31
52
  @interface.print(*args)
32
53
  end
33
54
 
55
+ # Split commands like this:
56
+ # split_commands("abc;def\\;ghi;jkl") => ["abc", "def;ghi", "jkl"]
57
+ def split_commands(input)
58
+ input.split(/(?<!\\);/).map { |e| e.gsub("\\;", ";") }
59
+ end
34
60
  end
35
61
 
36
62
  class CommandProcessor < Processor # :nodoc:
@@ -94,35 +120,23 @@ module Debugger
94
120
  end
95
121
  end
96
122
 
97
- def self.print_location_and_text(file, line)
98
- file_line = "%s:%s\n%s" % [canonic_file(file), line,
99
- Debugger.line_at(file, line)]
123
+ def self.print_location_and_text(file, line, context)
124
+ result = Debugger.printer.print("stop.suspend",
125
+ file: canonic_file(file), line_number: line, line: Debugger.line_at(file, line),
126
+ thnum: context && context.thnum, frames: context && context.stack_size
127
+ )
128
+ Debugger.handler.interface.print(annotate_location_and_text(result))
129
+ end
130
+
131
+ def self.annotate_location_and_text(output)
100
132
  # FIXME: use annotations routines
101
133
  if Debugger.annotate.to_i > 2
102
- file_line = "\032\032source #{file_line}"
134
+ "\032\032source #{output}"
103
135
  elsif ENV['EMACS']
104
- file_line = "\032\032#{file_line}"
136
+ "\032\032#{output}"
137
+ else
138
+ output
105
139
  end
106
- print file_line
107
- end
108
-
109
- def self.protect(mname)
110
- alias_method "__#{mname}", mname
111
- module_eval %{
112
- def #{mname}(*args)
113
- @mutex.synchronize do
114
- return unless @interface
115
- __#{mname}(*args)
116
- end
117
- rescue IOError, Errno::EPIPE
118
- self.interface = nil
119
- rescue SignalException
120
- raise
121
- rescue Exception
122
- print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
123
- print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
124
- end
125
- }
126
140
  end
127
141
 
128
142
  def at_breakpoint(context, breakpoint)
@@ -133,7 +147,10 @@ module Debugger
133
147
  if Debugger.annotate.to_i > 2
134
148
  print afmt("source #{file}:#{line}")
135
149
  end
136
- print "Breakpoint %d at %s:%s\n", n, file, line
150
+ print pr(
151
+ "breakpoints.stop_at_breakpoint", id: n, file: file, line: line, thread_id: Debugger.current_context.thnum
152
+ )
153
+ @last_breakpoint = breakpoint
137
154
  end
138
155
  protect :at_breakpoint
139
156
 
@@ -170,12 +187,16 @@ module Debugger
170
187
  protect :at_tracing
171
188
 
172
189
  def at_line(context, file, line)
190
+ CommandProcessor.print_location_and_text(file, line, context) unless @last_breakpoint
173
191
  process_commands(context, file, line)
192
+ ensure
193
+ @last_breakpoint = nil
174
194
  end
175
195
  protect :at_line
176
196
 
177
197
  def at_return(context, file, line)
178
198
  context.stop_frame = -1
199
+ CommandProcessor.print_location_and_text(file, line, context)
179
200
  process_commands(context, file, line)
180
201
  end
181
202
 
@@ -225,30 +246,14 @@ module Debugger
225
246
  def process_commands(context, file, line)
226
247
  state, commands = always_run(context, file, line, 1)
227
248
  $rdebug_state = state if Command.settings[:debuggertesting]
228
- splitter = lambda do |str|
229
- str.split(/;/).inject([]) do |m, v|
230
- if m.empty?
231
- m << v
232
- else
233
- if m.last[-1] == ?\\
234
- m.last[-1,1] = ''
235
- m.last << ';' << v
236
- else
237
- m << v
238
- end
239
- end
240
- m
241
- end
242
- end
243
249
 
244
250
  preloop(commands, context)
245
- CommandProcessor.print_location_and_text(file, line)
246
251
  while !state.proceed?
247
252
  input = if @interface.command_queue.empty?
248
- @interface.read_command(prompt(context))
249
- else
250
- @interface.command_queue.shift
251
- end
253
+ @interface.read_command(prompt(context))
254
+ else
255
+ @interface.command_queue.shift
256
+ end
252
257
  break unless input
253
258
  catch(:debug_error) do
254
259
  if input == ""
@@ -257,7 +262,7 @@ module Debugger
257
262
  else
258
263
  @last_cmd = input
259
264
  end
260
- splitter[input].each do |cmd|
265
+ split_commands(input).each do |cmd|
261
266
  one_cmd(commands, context, cmd)
262
267
  postcmd(commands, context, cmd)
263
268
  end
@@ -375,6 +380,10 @@ module Debugger
375
380
  @interface.print(*args)
376
381
  end
377
382
 
383
+ def print_debug(*args)
384
+ @interface.print_debug(*args)
385
+ end
386
+
378
387
  def confirm(*args)
379
388
  @interface.confirm(*args)
380
389
  end
@@ -40,23 +40,9 @@ describe "Breakpoints" do
40
40
  debug_file("breakpoint1") { Debugger.breakpoints.must_be_empty }
41
41
  end
42
42
 
43
- it "must show an error" do
44
- debug_file("breakpoint1")
45
- check_output_includes "There are only #{LineCache.size(fullpath('breakpoint1'))} lines in file \"breakpoint1.rb\".", interface.error_queue
46
- end
47
- end
48
-
49
-
50
- describe "setting breakpoint to incorrect line" do
51
- before { enter 'break 8' }
52
-
53
- it "must not create a breakpoint" do
54
- debug_file("breakpoint1") { Debugger.breakpoints.must_be_empty }
55
- end
56
-
57
- it "must show an error" do
43
+ it "shows an error" do
58
44
  debug_file("breakpoint1")
59
- check_output_includes 'Line 8 is not a stopping point in file "breakpoint1.rb".', interface.error_queue
45
+ check_output_includes "There are only #{LineCache.size(fullpath('breakpoint1'))} lines in file 'breakpoint1.rb'", interface.error_queue
60
46
  end
61
47
  end
62
48
 
@@ -72,7 +58,7 @@ describe "Breakpoints" do
72
58
  debug_file("breakpoint1") { state.file.must_equal fullpath("breakpoint1") }
73
59
  end
74
60
 
75
- describe "show a message" do
61
+ describe "shows a message" do
76
62
  temporary_change_hash_value(Debugger::Command.settings, :basename, false)
77
63
 
78
64
  it "must show a message with full filename" do
@@ -90,32 +76,6 @@ describe "Breakpoints" do
90
76
  end
91
77
 
92
78
 
93
- describe "reloading source on change" do
94
- temporary_change_hash_value(Debugger::Command.settings, :reload_source_on_change, false)
95
-
96
- it "must not reload source if autoreload is not set" do
97
- enter(
98
- 'set noautoreload',
99
- ->{change_line_in_file(fullpath('breakpoint1'), 14, ''); 'break 14'},
100
- ->{change_line_in_file(fullpath('breakpoint1'), 14, 'c = a + b'); 'cont'}
101
- )
102
- debug_file "breakpoint1"
103
- check_output_includes "Breakpoint 1 at #{fullpath('breakpoint1')}:14"
104
- end
105
-
106
- it "must reload source if autoreload is set" do
107
- enter(
108
- 'set autoreload',
109
- ->{change_line_in_file(fullpath('breakpoint1'), 14, ''); 'break 14'},
110
- # Setting second breakpoint just to reload the source code after rolling the file changes back
111
- ->{change_line_in_file(fullpath('breakpoint1'), 14, 'c = a + b'); 'break 15'}, 'cont'
112
- )
113
- debug_file "breakpoint1"
114
- check_output_includes "Line 14 is not a stopping point in file \"breakpoint1.rb\".", interface.error_queue
115
- end
116
- end
117
-
118
-
119
79
  describe "set breakpoint in a file" do
120
80
  describe "successfully" do
121
81
  before do
@@ -132,10 +92,12 @@ describe "Breakpoints" do
132
92
  end
133
93
 
134
94
  describe "when setting breakpoint to unexisted file" do
95
+
135
96
  before do
136
97
  enter "break asf:324"
137
98
  debug_file("breakpoint1")
138
99
  end
100
+
139
101
  it "must show an error" do
140
102
  check_output_includes "No source file named asf", interface.error_queue
141
103
  end
@@ -160,6 +122,12 @@ describe "Breakpoints" do
160
122
  it "must stop at the correct file" do
161
123
  debug_file("breakpoint1") { state.file.must_equal fullpath("breakpoint1") }
162
124
  end
125
+
126
+ it "must show output in plain text" do
127
+ id = nil
128
+ debug_file("breakpoint1") { id = breakpoint.id }
129
+ check_output_includes "Breakpoint #{id} at A::b"
130
+ end
163
131
  end
164
132
 
165
133
  describe "set breakpoint to a class method" do
@@ -180,7 +148,7 @@ describe "Breakpoints" do
180
148
  it "must show an error" do
181
149
  enter "break B.a"
182
150
  debug_file("breakpoint1")
183
- check_output_includes "Unknown class B.", interface.error_queue
151
+ check_output_includes "Unknown class B", interface.error_queue
184
152
  end
185
153
  end
186
154
  end
@@ -195,7 +163,7 @@ describe "Breakpoints" do
195
163
 
196
164
  it "must show an error" do
197
165
  debug_file("breakpoint1")
198
- check_output_includes 'Invalid breakpoint location: foo.', interface.error_queue
166
+ check_output_includes 'Invalid breakpoint location: foo', interface.error_queue
199
167
  end
200
168
  end
201
169
 
@@ -214,6 +182,12 @@ describe "Breakpoints" do
214
182
  enter "cont"
215
183
  debug_file("breakpoint1") { state.line.must_equal 15 }
216
184
  end
185
+
186
+ it "must show success message" do
187
+ id = nil
188
+ debug_file("breakpoint1") { id = breakpoint.id }
189
+ check_output_includes "Breakpoint #{id} is disabled"
190
+ end
217
191
  end
218
192
 
219
193
  describe "full syntax" do
@@ -229,7 +203,7 @@ describe "Breakpoints" do
229
203
  enter "disable"
230
204
  debug_file("breakpoint1")
231
205
  check_output_includes(
232
- '"disable" must be followed "display", "breakpoints" or breakpoint numbers.',
206
+ "'disable' must be followed 'display', 'breakpoints' or breakpoint numbers",
233
207
  interface.error_queue
234
208
  )
235
209
  end
@@ -237,14 +211,15 @@ describe "Breakpoints" do
237
211
  it "must show an error if no breakpoints is set" do
238
212
  enter "disable 1"
239
213
  debug_file("breakpoint1")
240
- check_output_includes 'No breakpoints have been set.', interface.error_queue
214
+ check_output_includes 'No breakpoints have been set', interface.error_queue
241
215
  end
242
216
 
243
217
  it "must show an error if not a number is provided as an argument to 'disable' command" do
244
218
  enter "break 14", "disable foo"
245
219
  debug_file("breakpoint1")
246
- check_output_includes "Disable breakpoints argument 'foo' needs to be a number."
220
+ check_output_includes "Disable breakpoints argument 'foo' needs to be a number"
247
221
  end
222
+
248
223
  end
249
224
  end
250
225
 
@@ -263,6 +238,12 @@ describe "Breakpoints" do
263
238
  enter "cont"
264
239
  debug_file("breakpoint1") { state.line.must_equal 14 }
265
240
  end
241
+
242
+ it "must show success message" do
243
+ id = nil
244
+ debug_file("breakpoint1") { id = breakpoint.id }
245
+ check_output_includes "Breakpoint #{id} is enabled"
246
+ end
266
247
  end
267
248
 
268
249
  describe "full syntax" do
@@ -279,7 +260,7 @@ describe "Breakpoints" do
279
260
  enter "enable"
280
261
  debug_file("breakpoint1")
281
262
  check_output_includes(
282
- '"enable" must be followed "display", "breakpoints" or breakpoint numbers.',
263
+ "'enable' must be followed 'display', 'breakpoints' or breakpoint numbers",
283
264
  interface.error_queue
284
265
  )
285
266
  end
@@ -288,7 +269,10 @@ describe "Breakpoints" do
288
269
 
289
270
 
290
271
  describe "deleting a breakpoint" do
291
- before { enter "break 14", ->{"delete #{breakpoint.id}"}, "break 15" }
272
+ before do
273
+ @breakpoint_id = nil
274
+ enter "break 14", ->{@breakpoint_id = breakpoint.id; "delete #{@breakpoint_id}"}, "break 15"
275
+ end
292
276
 
293
277
  it "must have only one breakpoint" do
294
278
  debug_file("breakpoint1") { Debugger.breakpoints.size.must_equal 1 }
@@ -298,6 +282,11 @@ describe "Breakpoints" do
298
282
  enter "cont"
299
283
  debug_file("breakpoint1") { state.line.must_equal 15 }
300
284
  end
285
+
286
+ it "must show a success message" do
287
+ debug_file("breakpoint1")
288
+ check_output_includes "Breakpoint #{@breakpoint_id} has been deleted"
289
+ end
301
290
  end
302
291
 
303
292
 
@@ -315,7 +304,7 @@ describe "Breakpoints" do
315
304
  it "must show an error when conditional syntax is wrong" do
316
305
  enter "break 14 ifa b == 3", "break 15", "cont"
317
306
  debug_file("breakpoint1") { state.line.must_equal 15 }
318
- check_output_includes "Expecting 'if' in breakpoint condition; got: ifa b == 3.", interface.error_queue
307
+ check_output_includes "Expecting 'if' in breakpoint condition; got: ifa b == 3", interface.error_queue
319
308
  end
320
309
 
321
310
  describe "enabling with wrong conditional syntax" do
@@ -335,7 +324,7 @@ describe "Breakpoints" do
335
324
  it "must show an error" do
336
325
  debug_file("breakpoint1")
337
326
  check_output_includes(
338
- 'Expression "b -=( 3" syntactically incorrect; breakpoint remains disabled.',
327
+ "Expression 'b -=( 3' syntactically incorrect; breakpoint remains disabled",
339
328
  interface.error_queue
340
329
  )
341
330
  end
@@ -344,13 +333,13 @@ describe "Breakpoints" do
344
333
  it "must show an error if no file or line is specified" do
345
334
  enter "break ifa b == 3", "break 15", "cont"
346
335
  debug_file("breakpoint1") { state.line.must_equal 15 }
347
- check_output_includes "Invalid breakpoint location: ifa b == 3.", interface.error_queue
336
+ check_output_includes "Invalid breakpoint location: ifa b == 3", interface.error_queue
348
337
  end
349
338
 
350
339
  it "must show an error if expression syntax is invalid" do
351
340
  enter "break if b -=) 3", "break 15", "cont"
352
341
  debug_file("breakpoint1") { state.line.must_equal 15 }
353
- check_output_includes 'Expression "b -=) 3" syntactically incorrect; breakpoint disabled.', interface.error_queue
342
+ check_output_includes "Expression 'b -=) 3' syntactically incorrect; breakpoint disabled", interface.error_queue
354
343
  end
355
344
  end
356
345