byebug 1.3.0 → 1.3.1

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/GUIDE.md +209 -0
  4. data/README.md +11 -2
  5. data/Rakefile +12 -0
  6. data/ext/byebug/byebug.c +50 -53
  7. data/ext/byebug/context.c +0 -24
  8. data/lib/byebug.rb +23 -7
  9. data/lib/byebug/command.rb +35 -24
  10. data/lib/byebug/commands/breakpoints.rb +24 -35
  11. data/lib/byebug/commands/catchpoint.rb +13 -17
  12. data/lib/byebug/commands/condition.rb +14 -19
  13. data/lib/byebug/commands/continue.rb +5 -7
  14. data/lib/byebug/commands/display.rb +3 -3
  15. data/lib/byebug/commands/edit.rb +1 -1
  16. data/lib/byebug/commands/enable.rb +18 -45
  17. data/lib/byebug/commands/eval.rb +1 -1
  18. data/lib/byebug/commands/finish.rb +1 -1
  19. data/lib/byebug/commands/frame.rb +24 -22
  20. data/lib/byebug/commands/info.rb +91 -122
  21. data/lib/byebug/commands/jump.rb +3 -8
  22. data/lib/byebug/commands/list.rb +2 -2
  23. data/lib/byebug/commands/method.rb +6 -8
  24. data/lib/byebug/commands/save.rb +1 -1
  25. data/lib/byebug/commands/set.rb +0 -12
  26. data/lib/byebug/commands/show.rb +9 -21
  27. data/lib/byebug/commands/variables.rb +3 -3
  28. data/lib/byebug/context.rb +13 -2
  29. data/lib/byebug/interface.rb +13 -7
  30. data/lib/byebug/processor.rb +23 -25
  31. data/lib/byebug/version.rb +1 -1
  32. data/old_doc/primes.rb +1 -4
  33. data/test/continue_test.rb +2 -9
  34. data/test/examples/list.rb +1 -1
  35. data/test/examples/trace.rb +1 -0
  36. data/test/help_test.rb +1 -1
  37. data/test/info_test.rb +3 -3
  38. data/test/list_test.rb +7 -1
  39. data/test/method_test.rb +0 -1
  40. data/test/show_test.rb +8 -0
  41. data/test/support/matchers.rb +4 -2
  42. data/test/trace_test.rb +18 -1
  43. metadata +2 -2
@@ -2,7 +2,7 @@ module Byebug
2
2
 
3
3
  module EvalFunctions
4
4
  def run_with_binding
5
- binding = @state.context ? get_binding : TOPLEVEL_BINDING
5
+ binding = get_binding
6
6
  $__dbg_interface = @state.interface
7
7
  eval(<<-EOC, binding)
8
8
  __dbg_verbose_save=$VERBOSE; $VERBOSE=false
@@ -11,7 +11,7 @@ module Byebug
11
11
 
12
12
  def execute
13
13
  max_frame = @state.context.stack_size - @state.frame_pos
14
- if !@match[1] or @match[1].empty?
14
+ if not @match[1]
15
15
  frame_pos = @state.frame_pos
16
16
  else
17
17
  frame_pos = get_int(@match[1], "Finish", 0, max_frame-1, 0)
@@ -16,10 +16,11 @@ module Byebug
16
16
  end
17
17
 
18
18
  if abs_frame_pos >= context.stack_size then
19
- errmsg "Adjusting would put us beyond the oldest (initial) frame.\n"
20
- return
19
+ return \
20
+ errmsg "Adjusting would put us beyond the oldest (initial) frame.\n"
21
21
  elsif abs_frame_pos < 0 then
22
- errmsg "Adjusting would put us beyond the newest (innermost) frame.\n"
22
+ return \
23
+ errmsg "Adjusting would put us beyond the newest (innermost) frame.\n"
23
24
  return
24
25
  end
25
26
 
@@ -28,25 +29,26 @@ module Byebug
28
29
  @state.frame_pos = abs_frame_pos
29
30
  end
30
31
 
31
- @state.file = context.frame_file(@state.frame_pos)
32
- @state.line = context.frame_line(@state.frame_pos)
32
+ @state.file = @state.context.frame_file @state.frame_pos
33
+ @state.line = @state.context.frame_line @state.frame_pos
33
34
 
34
- print_frame(@state.frame_pos, false)
35
+ print_frame @state.frame_pos, false
35
36
  end
36
37
 
37
- def get_frame_call(prefix, pos, context)
38
- id = context.frame_method(pos)
38
+ def get_frame_call(prefix, pos)
39
+ id = @state.context.frame_method(pos)
39
40
  return "<main>" unless id
40
41
 
41
- klass = context.frame_class(pos)
42
+ klass = @state.context.frame_class(pos)
43
+
42
44
  if Command.settings[:callstyle] != :short && klass
43
45
  call_str = "#{klass}.#{id.id2name}"
44
46
  else
45
47
  call_str = "#{id.id2name}"
46
48
  end
47
49
 
48
- args = context.frame_args(pos)
49
- locals = context.frame_locals(pos)
50
+ args = @state.context.frame_args pos
51
+ locals = @state.context.frame_locals pos
50
52
  if args.any?
51
53
  call_str += "("
52
54
  args.each_with_index do |name, i|
@@ -60,7 +62,7 @@ module Byebug
60
62
  end
61
63
  call_str += "#{name}##{klass}, "
62
64
  when :tracked
63
- arg_info = context.frame_args_info(pos)
65
+ arg_info = context.frame_args_info pos
64
66
  if arg_info && arg_info.size > i
65
67
  call_str += "#{name}: #{arg_info[i].inspect}, "
66
68
  else
@@ -84,10 +86,9 @@ module Byebug
84
86
  end
85
87
  end
86
88
 
87
- def print_frame(pos, mark_current = true, context = @state.context)
88
- file = context.frame_file(pos)
89
- line = context.frame_line(pos)
90
- klass = context.frame_class(pos)
89
+ def print_frame(pos, mark_current = true)
90
+ file = @state.context.frame_file pos
91
+ line = @state.context.frame_line pos
91
92
 
92
93
  unless Command.settings[:frame_fullpath]
93
94
  path_components = file.split(/[\\\/]/)
@@ -104,7 +105,7 @@ module Byebug
104
105
  end
105
106
 
106
107
  frame_str += sprintf "#%-2d ", pos
107
- frame_str += get_frame_call(frame_str, pos, context)
108
+ frame_str += get_frame_call frame_str, pos
108
109
  file_line = "at #{CommandProcessor.canonic_file(file)}:#{line}"
109
110
  if frame_str.size + file_line.size + 1 > Command.settings[:width]
110
111
  frame_str += "\n #{file_line}\n"
@@ -129,9 +130,10 @@ module Byebug
129
130
  # ignoring additional caller entries. sentinal is set by byebug, but if it's
130
131
  # nil then additional entries are presumably ones that we haven't recorded
131
132
  # in context
132
- def truncated_callstack?(context, sentinal=nil, cs=caller)
133
- recorded_size = context.stack_size
134
- to_find_fl = "#{context.frame_file(0)}:#{context.frame_line(0)}"
133
+ def truncated_callstack?(sentinal=nil, cs=caller)
134
+ recorded_size = @state.context.stack_size
135
+ to_find_fl =
136
+ "#{@state.context.frame_file(0)}:#{@state.context.frame_line(0)}"
135
137
  top_discard = false
136
138
  cs.each_with_index do |fl, i|
137
139
  fl.gsub!(/in `.*'$/, '')
@@ -166,7 +168,7 @@ module Byebug
166
168
 
167
169
  def execute
168
170
  print_backtrace
169
- if truncated_callstack?(@state.context, Byebug.start_sentinal)
171
+ if truncated_callstack?(Byebug.start_sentinal)
170
172
  print \
171
173
  "Warning: saved frames may be incomplete; compare with caller(0)\n"
172
174
  end
@@ -261,7 +263,7 @@ module Byebug
261
263
  %w(frame)
262
264
  end
263
265
 
264
- def help(cmd)
266
+ def description
265
267
  %{
266
268
  f[rame][ frame-number]
267
269
 
@@ -2,10 +2,8 @@ module Byebug
2
2
 
3
3
  module InfoFunctions
4
4
  def info_catch(*args)
5
- unless @state.context
6
- print "No frame selected.\n"
7
- return
8
- end
5
+ return print "No frame selected.\n" unless @state.context
6
+
9
7
  if Byebug.catchpoints and not Byebug.catchpoints.empty?
10
8
  Byebug.catchpoints.each do |exception, hits|
11
9
  print "#{exception}: #{exception.is_a?(Class)}\n"
@@ -69,7 +67,7 @@ module Byebug
69
67
  end
70
68
 
71
69
  def execute
72
- return help(@match) unless @match[1]
70
+ return print InfoCommand.help(nil) unless @match[1]
73
71
 
74
72
  args = @match[1].split(/[ \t]+/)
75
73
  param = args.shift
@@ -82,12 +80,11 @@ module Byebug
82
80
  end
83
81
 
84
82
  def info_args(*args)
85
- unless @state.context
86
- print "No frame selected.\n"
87
- return
88
- end
89
- locals = @state.context.frame_locals(@state.frame_pos)
90
- args = @state.context.frame_args(@state.frame_pos)
83
+ return errmsg "No frame selected.\n" unless @state.context
84
+
85
+ locals = @state.context.frame_locals
86
+ args = @state.context.frame_args
87
+
91
88
  args.each do |name|
92
89
  s = "#{name} = #{locals[name].inspect}"
93
90
  pad_with_dots(s)
@@ -95,8 +92,20 @@ module Byebug
95
92
  end
96
93
  end
97
94
 
95
+ def info_breakpoint(brkpt)
96
+ expr = brkpt.expr.nil? ? '' : " if #{brkpt.expr}"
97
+ print "%-3d %-3s at %s:%s%s\n" %
98
+ [brkpt.id, brkpt.enabled? ? 'y' : 'n', brkpt.source, brkpt.pos, expr]
99
+ hits = brkpt.hit_count
100
+ if hits > 0
101
+ s = (hits > 1) ? 's' : ''
102
+ print "\tbreakpoint already hit #{hits} time#{s}\n"
103
+ end
104
+ end
105
+ private :info_breakpoint
106
+
98
107
  def info_breakpoints(*args)
99
- return print "\"info breakpoints\" not available here.\n" unless
108
+ return errmsg "\"info breakpoints\" not available here.\n" unless
100
109
  @state.context
101
110
 
102
111
  return print "No breakpoints.\n" if Byebug.breakpoints.empty?
@@ -109,50 +118,34 @@ module Byebug
109
118
  brkpts.empty?
110
119
  end
111
120
  print "Num Enb What\n"
112
- brkpts.each do |b|
113
- print "%-3d %-3s at %s:%s%s\n", b.id,
114
- b.enabled? ? 'y' : 'n',
115
- b.source,
116
- b.pos,
117
- b.expr.nil? ? '' : " if #{b.expr}"
118
- hits = b.hit_count
119
- if hits > 0
120
- s = (hits > 1) ? 's' : ''
121
- print "\tbreakpoint already hit #{hits} time#{s}\n"
122
- end
123
- end
121
+ brkpts.each { |b| info_breakpoint(b) }
124
122
  end
125
123
 
126
124
  def info_display(*args)
127
- unless @state.context
128
- print "info display not available here.\n"
129
- return
130
- end
131
- if @state.display.find{|d| d[0]}
132
- print "Auto-display expressions now in effect:\n"
133
- print "Num Enb Expression\n"
134
- n = 1
135
- for d in @state.display
136
- print "%3d: %s %s\n", n, (d[0] ? 'y' : 'n'), d[1] if
137
- d[0] != nil
138
- n += 1
139
- end
140
- else
141
- print "There are no auto-display expressions now.\n"
125
+ return errmsg "\"info display\" not available here.\n" unless
126
+ @state.context
127
+
128
+ return print "There are no auto-display expressions now.\n" unless
129
+ @state.display.find{|d| d[0]}
130
+
131
+ print "Auto-display expressions now in effect:\n" \
132
+ "Num Enb Expression\n"
133
+ n = 1
134
+ for d in @state.display
135
+ print "%3d: %s %s\n" % [n, (d[0] ? 'y' : 'n'), d[1]]
136
+ n += 1
142
137
  end
143
138
  end
144
139
 
145
140
  def info_file_path(file)
146
141
  path = LineCache.path(file)
147
- if path != file
148
- print " - #{path}"
149
- end
142
+ print " - #{path}" if path and path != file
150
143
  end
151
144
  private :info_file_path
152
145
 
153
146
  def info_file_lines(file)
154
147
  lines = LineCache.size(file)
155
- print "\t %d lines\n", lines if lines
148
+ print "\t #{lines} lines\n" if lines
156
149
  end
157
150
  private :info_file_lines
158
151
 
@@ -167,80 +160,69 @@ module Byebug
167
160
 
168
161
  def info_file_mtime(file)
169
162
  stat = LineCache.stat(file)
170
- print "\t%s\n", stat.mtime if stat
163
+ print "\t#{stat.mtime}\n" if stat
171
164
  end
172
165
  private :info_file_mtime
173
166
 
174
167
  def info_file_sha1(file)
175
- print "\t%s\n", LineCache.sha1(file)
168
+ print "\t#{LineCache.sha1(file)}\n"
176
169
  end
177
170
  private :info_file_sha1
178
171
 
179
172
  def info_file(*args)
180
173
  return info_files unless args[0]
181
- file = args[0]
182
174
 
183
- param = args[1] ? args[1] : 'basic'
175
+ param = args[1] || 'basic'
184
176
 
185
177
  subcmd = find(InfoFileSubcommands, param)
186
178
  return errmsg "Invalid parameter #{param}\n" unless subcmd
187
179
 
188
- unless LineCache::cached?(file)
189
- unless LineCache::cached_script?(file)
190
- return print "File #{file} is not cached\n"
180
+ unless LineCache::cached?(args[0])
181
+ unless LineCache::cached_script?(args[0])
182
+ return print "File #{args[0]} is not cached\n"
191
183
  end
192
- LineCache::cache(file, Command.settings[:autoreload])
184
+ LineCache::cache(args[0], Command.settings[:autoreload])
193
185
  end
194
186
 
195
- print "File #{file}"
196
- info_file_path(file) if %w(all basic path).member?(subcmd.name)
187
+ print "File #{args[0]}"
188
+ info_file_path(args[0]) if %w(all basic path).member?(subcmd.name)
197
189
  print "\n"
198
190
 
199
- info_file_lines(file) if %w(all basic lines).member?(subcmd.name)
200
- info_file_breakpoints(file) if %w(all breakpoints).member?(subcmd.name)
201
- info_file_mtime(file) if %w(all mtime).member?(subcmd.name)
202
- info_file_sha1(file) if %w(all sha1).member?(subcmd.name)
191
+ info_file_lines(args[0]) if %w(all basic lines).member?(subcmd.name)
192
+ info_file_breakpoints(args[0]) if %w(all breakpoints).member?(subcmd.name)
193
+ info_file_mtime(args[0]) if %w(all mtime).member?(subcmd.name)
194
+ info_file_sha1(args[0]) if %w(all sha1).member?(subcmd.name)
203
195
  end
204
196
 
205
197
  def info_files(*args)
206
198
  files = LineCache::cached_files
207
199
  files += SCRIPT_LINES__.keys unless 'stat' == args[0]
208
200
  files.uniq.sort.each do |file|
209
- stat = LineCache::stat(file)
210
- path = LineCache::path(file)
211
- print "File %s", file
212
- if path and path != file
213
- print " - %s\n", path
214
- else
215
- print "\n"
216
- end
217
- print "\t%s\n", stat.mtime if stat
201
+ print "File #{file}"
202
+ info_file_path(file)
203
+ print "\n"
204
+ info_file_mtime(file)
218
205
  end
219
206
  end
220
207
 
221
208
  def info_instance_variables(*args)
222
- unless @state.context
223
- print "info instance_variables not available here.\n"
224
- return
225
- end
209
+ return errmsg "\"info instance_variables\" not available here.\n" unless
210
+ @state.context
211
+
226
212
  obj = debug_eval('self')
227
213
  var_list(obj.instance_variables)
228
214
  end
229
215
 
230
216
  def info_line(*args)
231
- unless @state.context
232
- errmsg "info line not available here.\n"
233
- return
234
- end
235
- print "Line %d of \"%s\"\n", @state.line, @state.file
217
+ return errmsg "\"info line\" not available here.\n" unless @state.context
218
+ print "Line #{@state.line} of \"#{@state.file}\"\n"
236
219
  end
237
220
 
238
221
  def info_locals(*args)
239
- unless @state.context
240
- errmsg "info line not available here.\n"
241
- return
242
- end
243
- locals = @state.context.frame_locals(@state.frame_pos)
222
+ return errmsg "\"info locals\" not available here.\n" unless
223
+ @state.context
224
+
225
+ locals = @state.context.frame_locals
244
226
  locals.keys.sort.each do |name|
245
227
  ### FIXME: make a common routine
246
228
  begin
@@ -272,8 +254,8 @@ module Byebug
272
254
  private :info_stop_reason
273
255
 
274
256
  def info_program(*args)
275
- return print "The program being debugged is not being run.\n" if
276
- not @state.context
257
+ return errmsg "The program being debugged is not being run.\n" unless
258
+ @state.context
277
259
 
278
260
  return print "The program crashed.\n" + Byebug.last_exception ?
279
261
  "Exception: #{Byebug.last_exception.inspect}" : "" + "\n" if
@@ -284,31 +266,26 @@ module Byebug
284
266
  end
285
267
 
286
268
  def info_stack(*args)
287
- if not @state.context
288
- errmsg "info stack not available here.\n"
289
- return
290
- end
269
+ return errmsg "\"info stack\" not available here.\n" unless @state.context
270
+
291
271
  print_backtrace
292
272
  end
293
273
 
294
274
  def info_global_variables(*args)
295
- unless @state.context
296
- errmsg "info global_variables not available here.\n"
297
- return
298
- end
275
+ return errmsg "\"info global_variables\" not available here.\n" unless
276
+ @state.context
277
+
299
278
  var_global
300
279
  end
301
280
 
302
281
  def info_variables(*args)
303
- if not @state.context
304
- errmsg "info variables not available here.\n"
305
- return
306
- end
282
+ return errmsg "\"info variables\" not available here.\n" unless
283
+ @state.context
284
+
307
285
  obj = debug_eval('self')
308
- locals = @state.context.frame_locals(@state.frame_pos)
286
+ locals = @state.context.frame_locals
309
287
  locals[:self] = @state.context.frame_self(@state.frame_pos)
310
288
  locals.keys.sort.each do |name|
311
- next if name =~ /^__dbg_/ # skip byebug pollution
312
289
  ### FIXME: make a common routine
313
290
  begin
314
291
  s = "#{name} = #{locals[name].inspect}"
@@ -320,37 +297,12 @@ module Byebug
320
297
  end
321
298
  end
322
299
  pad_with_dots(s)
323
- s.gsub!('%', '%%') # protect against printf format strings
324
300
  print "#{s}\n"
325
301
  end
326
302
  var_list(obj.instance_variables, obj.instance_eval{binding()})
327
303
  var_class_self
328
304
  end
329
305
 
330
- def help(args)
331
- if args[1]
332
- subcmd = find(Subcommands, args[1])
333
- if subcmd
334
- str = subcmd.short_help + '.'
335
- if 'file' == subcmd.name and args[2]
336
- subsubcmd = find(InfoFileSubcommands, args[2])
337
- if subsubcmd
338
- str += "\nInvalid \"file\" attribute \"#{args[2]}\"."
339
- else
340
- str += "\n" + subsubcmd.short_help + '.'
341
- end
342
- else
343
- str += "\n" + subcmd.long_help if subcmd.long_help
344
- end
345
- else
346
- str = "Invalid \"info\" subcommand \"#{args[1]}\"."
347
- end
348
- else
349
- str = InfoCommand.description + format_subcmds(Subcommands)
350
- end
351
- print str
352
- end
353
-
354
306
  class << self
355
307
  def names
356
308
  %w(info)
@@ -360,10 +312,27 @@ module Byebug
360
312
  %{
361
313
  info[ subcommand]
362
314
 
363
- Generic command for showing things about the program being
315
+ Generic command for showing things about the program being debugged.
364
316
  }
365
317
  end
318
+
319
+ def help(args)
320
+ return description + format_subcmds unless args and args[1]
321
+
322
+ return format_subcmd(args[1]) unless 'file' == args[1] and args[2]
323
+
324
+ str = subcmd.short_help + '.'
325
+ subsubcmd = find(InfoFileSubcommands, args[2])
326
+ if subsubcmd
327
+ str += "\nInvalid \"file\" attribute \"#{args[2]}\"."
328
+ else
329
+ str += "\n" + subsubcmd.short_help + '.'
330
+ end
331
+
332
+ return str
333
+ end
366
334
  end
335
+
367
336
  end
368
337
 
369
338
  end