byebug 3.2.0 → 3.3.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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +125 -99
  4. data/CONTRIBUTING.md +4 -6
  5. data/GUIDE.md +42 -20
  6. data/Gemfile +5 -3
  7. data/README.md +2 -3
  8. data/Rakefile +11 -7
  9. data/bin/byebug +2 -252
  10. data/byebug.gemspec +7 -4
  11. data/ext/byebug/byebug.c +17 -18
  12. data/ext/byebug/byebug.h +4 -5
  13. data/ext/byebug/context.c +37 -39
  14. data/ext/byebug/threads.c +39 -18
  15. data/lib/byebug.rb +2 -110
  16. data/lib/byebug/attacher.rb +23 -0
  17. data/lib/byebug/breakpoint.rb +60 -0
  18. data/lib/byebug/command.rb +62 -70
  19. data/lib/byebug/commands/break.rb +24 -24
  20. data/lib/byebug/commands/catchpoint.rb +18 -10
  21. data/lib/byebug/commands/condition.rb +18 -17
  22. data/lib/byebug/commands/continue.rb +17 -9
  23. data/lib/byebug/commands/delete.rb +19 -13
  24. data/lib/byebug/commands/display.rb +19 -53
  25. data/lib/byebug/commands/edit.rb +7 -4
  26. data/lib/byebug/commands/enable_disable.rb +130 -0
  27. data/lib/byebug/commands/eval.rb +40 -22
  28. data/lib/byebug/commands/finish.rb +13 -4
  29. data/lib/byebug/commands/frame.rb +65 -45
  30. data/lib/byebug/commands/help.rb +17 -18
  31. data/lib/byebug/commands/history.rb +14 -8
  32. data/lib/byebug/commands/info.rb +160 -182
  33. data/lib/byebug/commands/interrupt.rb +4 -1
  34. data/lib/byebug/commands/irb.rb +30 -0
  35. data/lib/byebug/commands/kill.rb +7 -8
  36. data/lib/byebug/commands/list.rb +71 -66
  37. data/lib/byebug/commands/method.rb +14 -6
  38. data/lib/byebug/commands/pry.rb +35 -0
  39. data/lib/byebug/commands/quit.rb +9 -6
  40. data/lib/byebug/commands/reload.rb +5 -2
  41. data/lib/byebug/commands/restart.rb +13 -9
  42. data/lib/byebug/commands/save.rb +17 -17
  43. data/lib/byebug/commands/set.rb +16 -15
  44. data/lib/byebug/commands/show.rb +10 -11
  45. data/lib/byebug/commands/source.rb +11 -5
  46. data/lib/byebug/commands/stepping.rb +38 -24
  47. data/lib/byebug/commands/threads.rb +45 -31
  48. data/lib/byebug/commands/trace.rb +22 -9
  49. data/lib/byebug/commands/undisplay.rb +45 -0
  50. data/lib/byebug/commands/variables.rb +83 -27
  51. data/lib/byebug/context.rb +25 -22
  52. data/lib/byebug/core.rb +82 -0
  53. data/lib/byebug/helper.rb +37 -28
  54. data/lib/byebug/history.rb +8 -4
  55. data/lib/byebug/interface.rb +12 -17
  56. data/lib/byebug/interfaces/local_interface.rb +11 -8
  57. data/lib/byebug/interfaces/remote_interface.rb +11 -8
  58. data/lib/byebug/interfaces/script_interface.rb +9 -6
  59. data/lib/byebug/options.rb +46 -0
  60. data/lib/byebug/processor.rb +7 -1
  61. data/lib/byebug/processors/command_processor.rb +135 -125
  62. data/lib/byebug/processors/control_command_processor.rb +23 -23
  63. data/lib/byebug/remote.rb +17 -26
  64. data/lib/byebug/runner.rb +100 -0
  65. data/lib/byebug/setting.rb +33 -8
  66. data/lib/byebug/settings/autoeval.rb +5 -15
  67. data/lib/byebug/settings/autoirb.rb +4 -1
  68. data/lib/byebug/settings/autolist.rb +5 -2
  69. data/lib/byebug/settings/autoreload.rb +5 -2
  70. data/lib/byebug/settings/autosave.rb +6 -2
  71. data/lib/byebug/settings/basename.rb +7 -2
  72. data/lib/byebug/settings/callstyle.rb +4 -1
  73. data/lib/byebug/settings/forcestep.rb +6 -3
  74. data/lib/byebug/settings/fullpath.rb +5 -2
  75. data/lib/byebug/settings/histfile.rb +5 -3
  76. data/lib/byebug/settings/histsize.rb +5 -3
  77. data/lib/byebug/settings/linetrace.rb +4 -1
  78. data/lib/byebug/settings/listsize.rb +5 -1
  79. data/lib/byebug/settings/post_mortem.rb +21 -13
  80. data/lib/byebug/settings/stack_on_error.rb +6 -2
  81. data/lib/byebug/settings/testing.rb +6 -1
  82. data/lib/byebug/settings/tracing_plus.rb +5 -1
  83. data/lib/byebug/settings/verbose.rb +13 -2
  84. data/lib/byebug/settings/width.rb +4 -1
  85. data/lib/byebug/version.rb +1 -1
  86. data/test/{break_test.rb → commands/break_test.rb} +41 -53
  87. data/test/{condition_test.rb → commands/condition_test.rb} +14 -14
  88. data/test/{continue_test.rb → commands/continue_test.rb} +0 -0
  89. data/test/{delete_test.rb → commands/delete_test.rb} +2 -2
  90. data/test/commands/display_test.rb +37 -0
  91. data/test/{edit_test.rb → commands/edit_test.rb} +0 -0
  92. data/test/{eval_test.rb → commands/eval_test.rb} +1 -0
  93. data/test/{finish_test.rb → commands/finish_test.rb} +11 -1
  94. data/test/{frame_test.rb → commands/frame_test.rb} +12 -16
  95. data/test/{help_test.rb → commands/help_test.rb} +21 -4
  96. data/test/{history_test.rb → commands/history_test.rb} +0 -0
  97. data/test/{info_test.rb → commands/info_test.rb} +5 -55
  98. data/test/{interrupt_test.rb → commands/interrupt_test.rb} +0 -0
  99. data/test/commands/irb_test.rb +28 -0
  100. data/test/{kill_test.rb → commands/kill_test.rb} +1 -1
  101. data/test/{list_test.rb → commands/list_test.rb} +1 -1
  102. data/test/{method_test.rb → commands/method_test.rb} +0 -0
  103. data/test/{post_mortem_test.rb → commands/post_mortem_test.rb} +6 -10
  104. data/test/{pry_test.rb → commands/pry_test.rb} +4 -13
  105. data/test/{quit_test.rb → commands/quit_test.rb} +4 -4
  106. data/test/{reload_test.rb → commands/reload_test.rb} +0 -0
  107. data/test/{restart_test.rb → commands/restart_test.rb} +6 -0
  108. data/test/{save_test.rb → commands/save_test.rb} +2 -2
  109. data/test/{set_test.rb → commands/set_test.rb} +9 -2
  110. data/test/{show_test.rb → commands/show_test.rb} +1 -1
  111. data/test/{source_test.rb → commands/source_test.rb} +3 -3
  112. data/test/{stepping_test.rb → commands/stepping_test.rb} +44 -35
  113. data/test/{thread_test.rb → commands/thread_test.rb} +0 -0
  114. data/test/{trace_test.rb → commands/trace_test.rb} +0 -0
  115. data/test/{display_test.rb → commands/undisplay_test.rb} +7 -45
  116. data/test/{variables_test.rb → commands/variables_test.rb} +10 -1
  117. data/test/debugger_alias_test.rb +2 -2
  118. data/test/runner_test.rb +127 -0
  119. data/test/support/matchers.rb +27 -25
  120. data/test/support/test_interface.rb +9 -5
  121. data/test/support/utils.rb +96 -101
  122. data/test/test_helper.rb +32 -20
  123. metadata +93 -68
  124. data/lib/byebug/commands/enable.rb +0 -154
  125. data/lib/byebug/commands/repl.rb +0 -126
  126. data/test/irb_test.rb +0 -47
  127. data/test/support/breakpoint.rb +0 -13
@@ -9,17 +9,13 @@ module Byebug
9
9
  end
10
10
 
11
11
  def switch_to_frame(frame_no)
12
- if frame_no < 0
13
- abs_frame_no = Context.stack_size + frame_no
14
- else
15
- abs_frame_no = frame_no
16
- end
12
+ frame_no >= 0 ? frame_no : Context.stack_size + frame_no
17
13
  end
18
14
 
19
15
  def navigate_to_frame(jump_no)
20
16
  return if jump_no == 0
21
17
  total_jumps, current_jumps, new_pos = jump_no.abs, 0, @state.frame_pos
22
- step = jump_no/total_jumps
18
+ step = jump_no / total_jumps
23
19
  loop do
24
20
  new_pos += step
25
21
  return new_pos if new_pos < 0 || new_pos >= Context.stack_size
@@ -29,21 +25,22 @@ module Byebug
29
25
  current_jumps += 1
30
26
  break if current_jumps == total_jumps
31
27
  end
32
- return new_pos
28
+ new_pos
33
29
  end
34
30
 
35
31
  def adjust_frame(frame_pos, absolute)
36
32
  if absolute
37
33
  abs_frame_pos = switch_to_frame(frame_pos)
38
- return errmsg "Can't navigate to c-frame\n" if c_frame?(abs_frame_pos)
34
+ return errmsg("Can't navigate to c-frame") if c_frame?(abs_frame_pos)
39
35
  else
40
36
  abs_frame_pos = navigate_to_frame(frame_pos)
41
37
  end
42
38
 
43
- return errmsg "Can't navigate beyond the oldest frame\n" if
44
- abs_frame_pos >= Context.stack_size
45
- return errmsg "Can't navigate beyond the newest frame\n" if
46
- abs_frame_pos < 0
39
+ if abs_frame_pos >= Context.stack_size
40
+ return errmsg("Can't navigate beyond the oldest frame")
41
+ elsif abs_frame_pos < 0
42
+ return errmsg("Can't navigate beyond the newest frame")
43
+ end
47
44
 
48
45
  @state.frame_pos = abs_frame_pos
49
46
  @state.file = @state.context.frame_file @state.frame_pos
@@ -54,14 +51,14 @@ module Byebug
54
51
 
55
52
  def get_frame_class(style, pos)
56
53
  frame_class = style == 'short' ? '' : "#{@state.context.frame_class pos}"
57
- return frame_class == '' ? '' : "#{frame_class}."
54
+ frame_class == '' ? '' : "#{frame_class}."
58
55
  end
59
56
 
60
57
  def get_frame_block_and_method(pos)
61
58
  frame_deco_regexp = /((?:block(?: \(\d+ levels\))?|rescue) in )?(.+)/
62
59
  frame_deco_method = "#{@state.context.frame_method pos}"
63
60
  frame_block_and_method = frame_deco_regexp.match(frame_deco_method)[1..2]
64
- return frame_block_and_method.map{ |x| x.nil? ? '' : x }
61
+ frame_block_and_method.map { |x| x.nil? ? '' : x }
65
62
  end
66
63
 
67
64
  def get_frame_args(style, pos)
@@ -71,18 +68,19 @@ module Byebug
71
68
  locals = @state.context.frame_locals pos if style == 'long'
72
69
  my_args = args.map do |arg|
73
70
  case arg[0]
74
- when :block
75
- prefix, default = '&', 'block'
76
- when :rest
77
- prefix, default = '*', 'args'
78
- else
79
- prefix, default = '', nil
71
+ when :block
72
+ prefix, default = '&', 'block'
73
+ when :rest
74
+ prefix, default = '*', 'args'
75
+ else
76
+ prefix, default = '', nil
80
77
  end
78
+
81
79
  klass = style == 'long' && arg[1] ? "##{locals[arg[1]].class}" : ''
82
80
  "#{prefix}#{arg[1] || default}#{klass}"
83
81
  end
84
82
 
85
- return "(#{my_args.join(', ')})"
83
+ "(#{my_args.join(', ')})"
86
84
  end
87
85
 
88
86
  def get_frame_call(prefix, pos)
@@ -94,10 +92,10 @@ module Byebug
94
92
 
95
93
  max_call_str_size = Setting[:width] - prefix.size
96
94
  if call_str.size > max_call_str_size
97
- call_str = call_str[0..max_call_str_size - 5] + "...)"
95
+ call_str = call_str[0..max_call_str_size - 5] + '...)'
98
96
  end
99
97
 
100
- return call_str
98
+ call_str
101
99
  end
102
100
 
103
101
  def print_backtrace
@@ -119,36 +117,43 @@ module Byebug
119
117
  end
120
118
  end
121
119
 
120
+ require 'pathname'
121
+
122
122
  def shortpath(fullpath)
123
- separator = File::ALT_SEPARATOR || File::SEPARATOR
124
- "...#{separator}" + fullpath.split(separator)[-3..-1].join(separator)
123
+ components = Pathname(fullpath).each_filename.to_a
124
+ return File.join(components) if components.size <= 2
125
+
126
+ File.join('...', components[-3..-1])
125
127
  end
126
128
 
127
129
  def print_frame(pos, mark_current = true)
128
- fullpath = @state.context.frame_file pos
130
+ fullpath = @state.context.frame_file(pos)
129
131
  file = Setting[:fullpath] ? fullpath : shortpath(fullpath)
130
- line = @state.context.frame_line pos
132
+ line = @state.context.frame_line(pos)
131
133
 
132
134
  if mark_current
133
135
  frame_str = (pos == @state.frame_pos) ? '--> ' : ' '
134
136
  else
135
- frame_str = ""
137
+ frame_str = ''
136
138
  end
137
139
  frame_str += c_frame?(pos) ? ' ͱ-- ' : ''
138
140
 
139
- frame_str += sprintf "#%-2d ", pos
141
+ frame_str += format('#%-2d ', pos)
140
142
  frame_str += get_frame_call frame_str, pos
141
143
  file_line = "at #{CommandProcessor.canonic_file(file)}:#{line}"
142
144
  if frame_str.size + file_line.size + 1 > Setting[:width]
143
- frame_str += "\n #{file_line}\n"
145
+ frame_str += "\n #{file_line}"
144
146
  else
145
- frame_str += " #{file_line}\n"
147
+ frame_str += " #{file_line}"
146
148
  end
147
149
 
148
- print frame_str
150
+ puts frame_str
149
151
  end
150
152
  end
151
153
 
154
+ #
155
+ # Show current backtrace.
156
+ #
152
157
  class WhereCommand < Command
153
158
  def regexp
154
159
  /^\s* (?:w(?:here)?|bt|backtrace) \s*$/x
@@ -164,26 +169,30 @@ module Byebug
164
169
  end
165
170
 
166
171
  def description
167
- %{w[here]|bt|backtrace\tdisplay stack frames
172
+ %(w[here]|bt|backtrace Display stack frames.
168
173
 
169
174
  Print the entire stack frame. Each frame is numbered; the most recent
170
175
  frame is 0. A frame number can be referred to in the "frame" command;
171
176
  "up" and "down" add or subtract respectively to frame numbers shown.
172
177
  The position of the current frame is marked with -->. C-frames hang
173
178
  from their most immediate Ruby frame to indicate that they are not
174
- navigable}
179
+ navigable.)
175
180
  end
176
181
  end
177
182
  end
178
183
 
184
+ #
185
+ # Move the current frame up in the backtrace.
186
+ #
179
187
  class UpCommand < Command
180
188
  def regexp
181
189
  /^\s* u(?:p)? (?:\s+(\S+))? \s*$/x
182
190
  end
183
191
 
184
192
  def execute
185
- pos = get_int(@match[1], 'Up')
186
- return unless pos
193
+ pos, err = parse_steps(@match[1], 'Up')
194
+ return errmsg(err) unless pos
195
+
187
196
  adjust_frame(pos, false)
188
197
  end
189
198
 
@@ -193,19 +202,23 @@ module Byebug
193
202
  end
194
203
 
195
204
  def description
196
- %{up[ count]\tmove to higher frame}
205
+ %(up[ count] Move to higher frame.)
197
206
  end
198
207
  end
199
208
  end
200
209
 
210
+ #
211
+ # Move the current frame down in the backtrace.
212
+ #
201
213
  class DownCommand < Command
202
214
  def regexp
203
215
  /^\s* down (?:\s+(\S+))? \s*$/x
204
216
  end
205
217
 
206
218
  def execute
207
- pos = get_int(@match[1], 'Down')
208
- return unless pos
219
+ pos, err = parse_steps(@match[1], 'Down')
220
+ return errmsg(err) unless pos
221
+
209
222
  adjust_frame(-pos, false)
210
223
  end
211
224
 
@@ -215,11 +228,14 @@ module Byebug
215
228
  end
216
229
 
217
230
  def description
218
- %{down[ count]\tmove to lower frame}
231
+ %(down[ count] Move to lower frame.)
219
232
  end
220
233
  end
221
234
  end
222
235
 
236
+ #
237
+ # Move to specific frames in the backtrace.
238
+ #
223
239
  class FrameCommand < Command
224
240
  def regexp
225
241
  /^\s* f(?:rame)? (?:\s+(\S+))? \s*$/x
@@ -227,7 +243,10 @@ module Byebug
227
243
 
228
244
  def execute
229
245
  return print_frame @state.frame_pos unless @match[1]
230
- return unless pos = get_int(@match[1], 'Frame')
246
+
247
+ pos, err = get_int(@match[1], 'Frame')
248
+ return errmsg(err) unless pos
249
+
231
250
  adjust_frame(pos, true)
232
251
  end
233
252
 
@@ -237,17 +256,18 @@ module Byebug
237
256
  end
238
257
 
239
258
  def description
240
- %{f[rame][ frame-number]
259
+ %(f[rame][ frame-number]
241
260
 
242
261
  Move the current frame to the specified frame number, or the 0 if no
243
262
  frame-number has been given.
244
263
 
245
- A negative number indicates position from the other end, so "frame -1"
246
- moves to the oldest frame, and "frame 0" moves to the newest frame.
264
+ A negative number indicates position from the other end, so
265
+ "frame -1" moves to the oldest frame, and "frame 0" moves to the
266
+ newest frame.
247
267
 
248
268
  Without an argument, the command prints the current stack frame. Since
249
269
  the current position is redisplayed, it may trigger a resyncronization
250
- if there is a front end also watching over things.}
270
+ if there is a front end also watching over things.)
251
271
  end
252
272
  end
253
273
  end
@@ -1,4 +1,7 @@
1
1
  module Byebug
2
+ #
3
+ # Ask for help from byebug's prompt.
4
+ #
2
5
  class HelpCommand < Command
3
6
  include Columnize
4
7
 
@@ -12,24 +15,18 @@ module Byebug
12
15
  if @match[1]
13
16
  args = @match[1].split
14
17
  cmds = @state.commands.select { |cmd| cmd.names.include?(args[0]) }
15
- unless cmds.empty?
16
- help = cmds.map{ |cmd| cmd.help(args) }.join("\n")
17
- help = help.split("\n").map{|l| l.gsub(/^ +/, '')}
18
- help.shift if help.first && help.first.empty?
19
- help.pop if help.last && help.last.empty?
20
- return print help.join("\n") + "\n"
21
- else
22
- return errmsg "Undefined command: \"#{args[0]}\". Try \"help\".\n" if
23
- args[0]
18
+ if cmds.empty?
19
+ return errmsg("Undefined command: \"#{args[0]}\". Try \"help\"")
24
20
  end
25
- end
26
21
 
27
- print "byebug help v#{VERSION}\n" unless Setting[:testing]
22
+ return puts(cmds.map { |cmd| cmd.help(args[1..-1]) }.join("\n"))
23
+ end
28
24
 
29
- print "Type \"help <command-name>\" for help on a specific command\n\n"
30
- print "Available commands:\n"
31
- cmds = @state.commands.map{ |cmd| cmd.names }.flatten.uniq.sort
32
- print columnize(cmds, Setting[:width])
25
+ puts "byebug help v#{VERSION}" unless Setting[:testing]
26
+ puts "Type \"help <command-name>\" for help on a specific command\n"
27
+ puts 'Available commands:'
28
+ cmds = @state.commands.map { |cmd| cmd.names }.flatten.uniq.sort
29
+ puts columnize(cmds, Setting[:width])
33
30
  end
34
31
 
35
32
  class << self
@@ -38,9 +35,11 @@ module Byebug
38
35
  end
39
36
 
40
37
  def description
41
- %{h[elp]\t\tprint this help
42
- h[elp] command\tprint help on command
43
- h[elp] command subcommand\tprint help on subcommand}
38
+ %(h[elp][ <command>[ <subcommand>]]
39
+
40
+ "help" alone prints this help.
41
+ "help <command>" prints help on <command>.
42
+ "help <command> <subcommand> prints help on <subcommand>.)
44
43
  end
45
44
  end
46
45
  end
@@ -1,18 +1,24 @@
1
1
  module Byebug
2
+ #
3
+ # Show history of byebug commands.
4
+ #
2
5
  class HistoryCommand < Command
3
6
  def regexp
4
7
  /^\s* hist(?:ory)? (?:\s+(?<num_cmds>.+))? \s*$/x
5
8
  end
6
9
 
7
10
  def execute
8
- if Setting[:autosave]
9
- if arg = @match[:num_cmds]
10
- size = get_int(arg, 'history', 1, Setting[:histsize])
11
- end
12
- print History.to_s(size || Setting[:histsize])
13
- else
14
- errmsg "Not currently saving history. Enable it with \"set autosave\"\n"
11
+ unless Setting[:autosave]
12
+ return errmsg('Not currently saving history. ' \
13
+ "Enable it with \"set autosave\"")
15
14
  end
15
+
16
+ if @match[:num_cmds]
17
+ size, err = get_int(@match[:num_cmds], 'history', 1, Setting[:histsize])
18
+ return errmsg(err) unless size
19
+ end
20
+
21
+ puts History.to_s(size || Setting[:histsize])
16
22
  end
17
23
 
18
24
  class << self
@@ -21,7 +27,7 @@ module Byebug
21
27
  end
22
28
 
23
29
  def description
24
- %{hist[ory] [num_cmds]\t\tShow byebug's command history}
30
+ %(hist[ory] [num_cmds] Show byebug's command history.)
25
31
  end
26
32
  end
27
33
  end
@@ -1,81 +1,17 @@
1
1
  module Byebug
2
+ #
3
+ # Utility methods to assist the info command
4
+ #
2
5
  module InfoFunctions
3
- def info_catch(*args)
4
- return print "No frame selected.\n" unless @state.context
6
+ def info_catch(*_args)
7
+ return puts('No frame selected.') unless @state.context
5
8
 
6
- if Byebug.catchpoints and not Byebug.catchpoints.empty?
7
- Byebug.catchpoints.each do |exception, hits|
8
- print "#{exception}: #{exception.is_a?(Class)}\n"
9
+ if Byebug.catchpoints && !Byebug.catchpoints.empty?
10
+ Byebug.catchpoints.each do |exception, _hits|
11
+ puts("#{exception}: #{exception.is_a?(Class)}")
9
12
  end
10
13
  else
11
- print "No exceptions set to be caught.\n"
12
- end
13
- end
14
- end
15
-
16
- class InfoCommand < Command
17
- include Columnize
18
- self.allow_in_control = true
19
-
20
- Subcommands = [
21
- ['args' , 1, 'Argument variables of current stack frame' ],
22
- ['breakpoints' , 1, 'Status of user-settable breakpoints',
23
- 'Without argument, list info about all ' \
24
- 'breakpoints. With an integer argument, ' \
25
- 'list info on that breakpoint.' ],
26
- ['catch' , 3, 'Exceptions that can be caught in the ' \
27
- 'current stack frame' ],
28
- ['display' , 2, 'Expressions to display when program stops' ],
29
- ['file' , 4, 'Info about a particular file read in',
30
- 'After the file name is supplied, you can' \
31
- 'list file attributes that you wish to ' \
32
- 'see. Attributes include: "all", "basic",' \
33
- ' "breakpoint", "lines", "mtime", "path" ' \
34
- 'and "sha1".' ],
35
- ['files' , 5, 'File names and timestamps of files read in' ],
36
- ['global_variables' , 2, 'Global variables' ],
37
- ['instance_variables', 2, 'Instance variables in current stack frame' ],
38
- ['line' , 2, 'Line number and file name of current ' \
39
- 'position in source file' ],
40
- ['locals' , 2, 'Local variables of the current stack frame' ],
41
- ['program' , 2, 'Execution status of the program' ],
42
- ['variables' , 1, 'Local and instance variables of the ' \
43
- 'current stack frame' ]
44
- ].map do |name, min, help|
45
- Subcmd.new(name, min, help)
46
- end unless defined?(Subcommands)
47
-
48
- InfoFileSubcommands = [
49
- ['all' , 1, 'All file information available - breakpoints, ' \
50
- 'lines, mtime, path and sha1' ],
51
- ['basic' , 2, 'basic information - path, number of lines' ],
52
- ['breakpoints', 2, 'Show trace line numbers',
53
- 'These are the line number where a breakpoint ' \
54
- 'can be set.' ],
55
- ['lines' , 1, 'Show number of lines in the file' ],
56
- ['mtime' , 1, 'Show modification time of file' ],
57
- ['path' , 4, 'Show full file path name for file' ],
58
- ['sha1' , 1, 'Show SHA1 hash of contents of the file' ]
59
- ].map do |name, min, help|
60
- Subcmd.new(name, min, help)
61
- end unless defined?(InfoFileSubcommands)
62
-
63
- def regexp
64
- /^\s* i(?:nfo)? (?:\s+(.+))? \s*$/x
65
- end
66
-
67
- def execute
68
- return print InfoCommand.help(nil) unless @match[1]
69
-
70
- args = @match[1].split(/[ \t]+/)
71
- param = args.shift
72
- subcmd = Command.find(Subcommands, param)
73
- return errmsg "Unknown info command #{param}\n" unless subcmd
74
-
75
- if @state.context
76
- send("info_#{subcmd.name}", *args)
77
- else
78
- errmsg "info_#{subcmd.name} not available without a context.\n"
14
+ puts 'No exceptions set to be caught.'
79
15
  end
80
16
  end
81
17
 
@@ -86,104 +22,81 @@ module Byebug
86
22
 
87
23
  args.map do |_, name|
88
24
  s = "#{name} = #{locals[name].inspect}"
89
- s[Setting[:width]-3..-1] = "..." if s.size > Setting[:width]
90
- print "#{s}\n"
25
+ s[Setting[:width] - 3..-1] = '...' if s.size > Setting[:width]
26
+ puts s
91
27
  end
92
28
  end
93
29
 
94
30
  def info_breakpoint(brkpt)
95
31
  expr = brkpt.expr.nil? ? '' : " if #{brkpt.expr}"
96
- print "%-3d %-3s at %s:%s%s\n" %
97
- [brkpt.id, brkpt.enabled? ? 'y' : 'n', brkpt.source, brkpt.pos, expr]
32
+ y_n = brkpt.enabled? ? 'y' : 'n'
33
+ interp = format('%-3d %-3s at %s:%s%s',
34
+ brkpt.id, y_n, brkpt.source, brkpt.pos, expr)
35
+ puts interp
98
36
  hits = brkpt.hit_count
99
- if hits > 0
100
- s = (hits > 1) ? 's' : ''
101
- print "\tbreakpoint already hit #{hits} time#{s}\n"
102
- end
37
+ return unless hits > 0
38
+
39
+ s = (hits > 1) ? 's' : ''
40
+ puts "\tbreakpoint already hit #{hits} time#{s}"
103
41
  end
104
- private :info_breakpoint
105
42
 
106
43
  def info_breakpoints(*args)
107
- return print "No breakpoints.\n" if Byebug.breakpoints.empty?
44
+ return puts('No breakpoints.') if Byebug.breakpoints.empty?
108
45
 
109
- brkpts = Byebug.breakpoints.sort_by{|b| b.id}
46
+ brkpts = Byebug.breakpoints.sort_by { |b| b.id }
110
47
  unless args.empty?
111
- indices = args.map{|a| a.to_i}
112
- brkpts = brkpts.select{|b| indices.member?(b.id)}
113
- return errmsg "No breakpoints found among list given.\n" if
114
- brkpts.empty?
48
+ indices = args.map { |a| a.to_i }
49
+ brkpts = brkpts.select { |b| indices.member?(b.id) }
50
+ return errmsg('No breakpoints found among list given') if brkpts.empty?
115
51
  end
116
- print "Num Enb What\n"
52
+
53
+ puts 'Num Enb What'
117
54
  brkpts.each { |b| info_breakpoint(b) }
118
55
  end
119
56
 
120
- def info_display(*args)
121
- return print "There are no auto-display expressions now.\n" unless
122
- @state.display.find{|d| d[0]}
57
+ def info_display(*_args)
58
+ return puts('There are no auto-display expressions now.') unless
59
+ @state.display.find { |d| d[0] }
123
60
 
124
- print "Auto-display expressions now in effect:\n" \
125
- "Num Enb Expression\n"
61
+ puts 'Auto-display expressions now in effect:'
62
+ puts 'Num Enb Expression'
126
63
  n = 1
127
- for d in @state.display
128
- print "%3d: %s %s\n" % [n, (d[0] ? 'y' : 'n'), d[1]]
64
+ @state.display.each do |d|
65
+ puts(format('%3d: %s %s', n, d[0] ? 'y' : 'n', d[1]))
129
66
  n += 1
130
67
  end
131
68
  end
132
69
 
133
70
  def info_file_path(file)
134
- print "File #{file}"
71
+ s = "File #{file}"
135
72
  path = File.expand_path(file)
136
- print " - #{path}\n" if path and path != file
73
+ s = "#{s} - #{path}" if path && path != file
74
+ puts s
137
75
  end
138
- private :info_file_path
139
76
 
140
77
  def info_file_lines(file)
141
78
  lines = File.foreach(file)
142
- print "\t#{lines.count} lines\n" if lines
79
+ puts "\t#{lines.count} lines" if lines
143
80
  end
144
- private :info_file_lines
145
81
 
146
82
  def info_file_breakpoints(file)
147
83
  breakpoints = LineCache.trace_line_numbers(file)
148
- if breakpoints
149
- print "\tbreakpoint line numbers:\n"
150
- print columnize(breakpoints.to_a.sort, Setting[:width])
151
- end
84
+ return unless breakpoints
85
+
86
+ puts "\tbreakpoint line numbers:"
87
+ puts columnize(breakpoints.to_a.sort, Setting[:width])
152
88
  end
153
- private :info_file_breakpoints
154
89
 
155
90
  def info_file_mtime(file)
156
91
  stat = File.stat(file)
157
- print "\t#{stat.mtime}\n" if stat
92
+ puts "\t#{stat.mtime}" if stat
158
93
  end
159
- private :info_file_mtime
160
94
 
161
95
  def info_file_sha1(file)
162
- print "\t#{Digest::SHA1.hexdigest(file)}\n"
163
- end
164
- private :info_file_sha1
165
-
166
- def info_file(*args)
167
- return info_files unless args[0]
168
-
169
- subcmd = Command.find(InfoFileSubcommands, args[1] || 'basic')
170
- return errmsg "Invalid parameter #{args[1]}\n" unless subcmd
171
-
172
- if %w(all basic).member?(subcmd.name)
173
- info_file_path(args[0])
174
- info_file_lines(args[0])
175
- if subcmd.name == 'all'
176
- info_file_breakpoints(args[0])
177
- info_file_mtime(args[0])
178
- info_file_sha1(args[0])
179
- end
180
- else
181
- print "File #{args[0]}\n" if subcmd.name != 'path'
182
- send("info_file_#{subcmd.name}", args[0])
183
- end
96
+ puts "\t#{Digest::SHA1.hexdigest(file)}"
184
97
  end
185
98
 
186
- def info_files(*args)
99
+ def info_files(*_args)
187
100
  files = SCRIPT_LINES__.keys
188
101
  files.uniq.sort.each do |file|
189
102
  info_file_path(file)
@@ -191,18 +104,8 @@ module Byebug
191
104
  end
192
105
  end
193
106
 
194
- def info_instance_variables(*args)
195
- obj = bb_eval('self')
196
- var_list(obj.instance_variables)
197
- end
198
-
199
- def info_line(*args)
200
- print "Line #{@state.line} of \"#{@state.file}\"\n"
201
- end
202
-
203
- def info_locals(*args)
204
- locals = @state.context.frame_locals
205
- print_hash(locals)
107
+ def info_line(*_args)
108
+ puts "Line #{@state.line} of \"#{@state.file}\""
206
109
  end
207
110
 
208
111
  def print_hash(vars)
@@ -211,55 +114,130 @@ module Byebug
211
114
  s = "#{name} = #{vars[name].inspect}"
212
115
  rescue
213
116
  begin
214
- s = "#{name} = #{vars[name].to_s}"
215
- rescue
216
- s = "#{name} = *Error in evaluation*"
117
+ s = "#{name} = #{vars[name]}"
118
+ rescue
119
+ s = "#{name} = *Error in evaluation*"
217
120
  end
218
121
  end
219
- s[Setting[:width]-3..-1] = "..." if s.size > Setting[:width]
220
- print "#{s}\n"
122
+ s[Setting[:width] - 3..-1] = '...' if s.size > Setting[:width]
123
+ puts s
221
124
  end
222
125
  end
223
- private :print_hash
224
126
 
225
127
  def info_stop_reason(stop_reason)
226
128
  case stop_reason
227
- when :step
228
- print "It stopped after stepping, next'ing or initial start.\n"
229
- when :breakpoint
230
- print("It stopped at a breakpoint.\n")
231
- when :catchpoint
232
- print("It stopped at a catchpoint.\n")
233
- else
234
- print "unknown reason: %s\n" % @state.context.stop_reason.to_s
129
+ when :step
130
+ puts "It stopped after stepping, next'ing or initial start."
131
+ when :breakpoint
132
+ puts 'It stopped at a breakpoint.'
133
+ when :catchpoint
134
+ puts 'It stopped at a catchpoint.'
135
+ else
136
+ puts "Unknown reason: #{@state.context.stop_reason}"
235
137
  end
236
138
  end
237
- private :info_stop_reason
238
139
 
239
- def info_program(*args)
140
+ def info_program(*_args)
240
141
  if @state.context.dead?
241
- print "The program crashed.\n"
242
- print "Exception: #{Byebug.last_exception.inspect}\n" if Byebug.last_exception
243
- return
142
+ puts 'The program crashed.'
143
+ excpt = Byebug.last_exception
144
+ return puts("Exception: #{excpt.inspect}") if excpt
244
145
  end
245
146
 
246
- print "Program stopped. "
147
+ puts 'Program stopped. '
247
148
  info_stop_reason @state.context.stop_reason
248
149
  end
249
150
 
250
- def info_global_variables(*args)
251
- var_global
252
- end
253
-
254
- def info_variables(*args)
151
+ def info_variables(*_args)
255
152
  locals = @state.context.frame_locals
256
153
  locals[:self] = @state.context.frame_self(@state.frame_pos)
257
154
  print_hash(locals)
258
155
 
259
156
  obj = bb_eval('self')
260
- var_list(obj.instance_variables, obj.instance_eval{binding()})
157
+ var_list(obj.instance_variables, obj.instance_eval { binding })
261
158
  var_class_self
262
159
  end
160
+ end
161
+
162
+ #
163
+ # Show info about different aspects of the debugger.
164
+ #
165
+ class InfoCommand < Command
166
+ include Columnize
167
+ self.allow_in_control = true
168
+
169
+ Subcommands = [
170
+ ['args', 1, 'Argument variables of current stack frame'],
171
+ ['breakpoints', 1, 'Status of user-settable breakpoints',
172
+ 'Without argument, list info about all breakpoints. With an integer ' \
173
+ 'argument, list info on that breakpoint.'],
174
+ ['catch', 3, 'Exceptions that can be caught in the current stack frame'],
175
+ ['display', 2, 'Expressions to display when program stops'],
176
+ ['file', 4, 'Info about a particular file read in',
177
+ 'After the file name is supplied, you can list file attributes that ' \
178
+ 'you wish to see. Attributes include: "all", "basic", "breakpoint", ' \
179
+ '"lines", "mtime", "path" and "sha1".'],
180
+ ['files', 5, 'File names and timestamps of files read in'],
181
+ ['line', 2, 'Line number and file name of current position in source ' \
182
+ 'file.'],
183
+ ['program', 2, 'Execution status of the program']
184
+ ].map do |name, min, help|
185
+ Subcmd.new(name, min, help)
186
+ end unless defined?(Subcommands)
187
+
188
+ InfoFileSubcommands = [
189
+ ['all', 1, 'All file information available - breakpoints, lines, ' \
190
+ 'mtime, path and sha1'],
191
+ ['basic', 2, 'basic information - path, number of lines'],
192
+ ['breakpoints', 2, 'Show trace line numbers',
193
+ 'These are the line number where a breakpoint can be set.'],
194
+ ['lines', 1, 'Show number of lines in the file'],
195
+ ['mtime', 1, 'Show modification time of file'],
196
+ ['path', 4, 'Show full file path name for file'],
197
+ ['sha1', 1, 'Show SHA1 hash of contents of the file']
198
+ ].map do |name, min, help|
199
+ Subcmd.new(name, min, help)
200
+ end unless defined?(InfoFileSubcommands)
201
+
202
+ def info_file(*args)
203
+ return info_files unless args[0]
204
+
205
+ mode = args[1] || 'basic'
206
+ subcmd = Command.find(InfoFileSubcommands, mode)
207
+ return errmsg "Invalid parameter #{args[1]}\n" unless subcmd
208
+
209
+ if %w(all basic).member?(subcmd.name)
210
+ info_file_path(args[0])
211
+ info_file_lines(args[0])
212
+ if subcmd.name == 'all'
213
+ info_file_breakpoints(args[0])
214
+ info_file_mtime(args[0])
215
+ info_file_sha1(args[0])
216
+ end
217
+ else
218
+ puts("File #{args[0]}") if subcmd.name != 'path'
219
+ send("info_file_#{subcmd.name}", args[0])
220
+ end
221
+ end
222
+
223
+ def regexp
224
+ /^\s* i(?:nfo)? (?:\s+(.+))? \s*$/x
225
+ end
226
+
227
+ def execute
228
+ return puts(InfoCommand.help) unless @match[1]
229
+
230
+ args = @match[1].split(/[ \t]+/)
231
+ param = args.shift
232
+ subcmd = Command.find(Subcommands, param)
233
+ return errmsg "Unknown info command #{param}\n" unless subcmd
234
+
235
+ if @state.context
236
+ send("info_#{subcmd.name}", *args)
237
+ else
238
+ errmsg "info_#{subcmd.name} not available without a context.\n"
239
+ end
240
+ end
263
241
 
264
242
  class << self
265
243
  def names
@@ -267,25 +245,25 @@ module Byebug
267
245
  end
268
246
 
269
247
  def description
270
- %{info[ subcommand]
248
+ <<-EOD.gsub(/^ {8}/, '')
271
249
 
272
- Generic command for showing things about the program being debugged.}
250
+ info[ subcommand]
251
+
252
+ Generic command for showing things about the program being debugged.
253
+
254
+ EOD
273
255
  end
274
256
 
275
- def help(args)
276
- return description + format_subcmds unless args and args[1]
257
+ def help(subcmds = [])
258
+ return description + format_subcmds if subcmds.empty?
277
259
 
278
- return format_subcmd(args[1]) unless 'file' == args[1] and args[2]
260
+ subcmd = subcmds.first
261
+ return format_subcmd(subcmd) unless 'file' == subcmd && subcmds[2]
279
262
 
280
- str = subcmd.short_help + '.'
281
- subsubcmd = Command.find(InfoFileSubcommands, args[2])
282
- if subsubcmd
283
- str += "\nInvalid \"file\" attribute \"#{args[2]}\"."
284
- else
285
- str += "\n" + subsubcmd.short_help + '.'
286
- end
263
+ subsubcmd = Command.find(InfoFileSubcommands, subcmds[2])
264
+ return "\nInvalid \"file\" attribute \"#{args[2]}\"." unless subsubcmd
287
265
 
288
- return str
266
+ subsubcmd.short_help
289
267
  end
290
268
  end
291
269
  end