ruby-debug 0.9.3 → 0.10.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 (64) hide show
  1. data/AUTHORS +1 -0
  2. data/CHANGES +41 -0
  3. data/ChangeLog +0 -0
  4. data/README +27 -13
  5. data/Rakefile +220 -0
  6. data/bin/rdebug +116 -42
  7. data/cli/ruby-debug.rb +33 -3
  8. data/cli/ruby-debug/command.rb +49 -12
  9. data/cli/ruby-debug/commands/breakpoints.rb +47 -64
  10. data/cli/ruby-debug/commands/control.rb +41 -13
  11. data/cli/ruby-debug/commands/display.rb +35 -18
  12. data/cli/ruby-debug/commands/enable.rb +159 -0
  13. data/cli/ruby-debug/commands/eval.rb +78 -4
  14. data/cli/ruby-debug/commands/frame.rb +67 -42
  15. data/cli/ruby-debug/commands/help.rb +21 -17
  16. data/cli/ruby-debug/commands/info.rb +210 -0
  17. data/cli/ruby-debug/commands/irb.rb +9 -1
  18. data/cli/ruby-debug/commands/list.rb +11 -8
  19. data/cli/ruby-debug/commands/method.rb +12 -23
  20. data/cli/ruby-debug/commands/script.rb +14 -9
  21. data/cli/ruby-debug/commands/settings.rb +174 -39
  22. data/cli/ruby-debug/commands/show.rb +193 -0
  23. data/cli/ruby-debug/commands/stepping.rb +15 -10
  24. data/cli/ruby-debug/commands/threads.rb +55 -56
  25. data/cli/ruby-debug/commands/variables.rb +27 -27
  26. data/cli/ruby-debug/helper.rb +134 -0
  27. data/cli/ruby-debug/interface.rb +46 -15
  28. data/cli/ruby-debug/processor.rb +156 -25
  29. data/doc/rdebug.1 +236 -0
  30. data/runner.sh +7 -0
  31. data/test/breakpoints.cmd +43 -0
  32. data/test/breakpoints.right +94 -0
  33. data/test/display.cmd +18 -0
  34. data/test/display.right +37 -0
  35. data/test/frame.cmd +21 -0
  36. data/test/frame.right +45 -0
  37. data/test/gcd.rb +18 -0
  38. data/test/help.cmd +12 -0
  39. data/test/help.right +4 -0
  40. data/test/helper.rb +87 -0
  41. data/test/info-var-bug.rb +45 -0
  42. data/test/info-var.cmd +23 -0
  43. data/test/info-var.right +47 -0
  44. data/test/info.cmd +12 -0
  45. data/test/info.right +35 -0
  46. data/test/quit.cmd +9 -0
  47. data/test/quit.right +22 -0
  48. data/test/setshow.cmd +44 -0
  49. data/test/setshow.right +73 -0
  50. data/test/stepping.cmd +17 -0
  51. data/test/stepping.right +40 -0
  52. data/test/tdebug.rb +196 -0
  53. data/test/test-breakpoints.rb +28 -0
  54. data/test/test-columnize.rb +46 -0
  55. data/test/test-display.rb +26 -0
  56. data/test/test-frame.rb +27 -0
  57. data/test/test-help.rb +44 -0
  58. data/test/test-info-var.rb +33 -0
  59. data/test/test-info.rb +28 -0
  60. data/test/test-quit.rb +28 -0
  61. data/test/test-ruby-debug-base.rb +76 -0
  62. data/test/test-setshow.rb +24 -0
  63. data/test/test-stepping.rb +26 -0
  64. metadata +63 -22
@@ -0,0 +1,159 @@
1
+ module Debugger
2
+ # Mix-in module to assist in command parsing.
3
+ module EnableDisableFunctions # :nodoc:
4
+ def enable_disable_breakpoints(is_enable, args)
5
+ breakpoints = Debugger.breakpoints.sort_by{|b| b.id }
6
+ largest = breakpoints.inject(0){|largest, b| largest = b.id if b.id > largest}
7
+ if 0 == largest
8
+ print "No breakpoints have been set.\n"
9
+ return
10
+ end
11
+ args.each do |pos|
12
+ pos = get_int(pos, "#{is_enable} breakpoints", 1, largest)
13
+ return nil unless pos
14
+ breakpoints.each do |b|
15
+ if b.id == pos
16
+ b.enabled = ("Enable" == is_enable)
17
+ return
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ def enable_disable_display(is_enable, args)
24
+ args.each do |pos|
25
+ pos = get_int(pos, "#{is_enable} display", 1, @state.display.size)
26
+ return nil unless pos
27
+ @state.display[pos-1][0] = ("Enable" == is_enable)
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ class EnableCommand < Command # :nodoc:
34
+ SubcmdStruct=Struct.new(:name, :min, :short_help) unless
35
+ defined?(SubcmdStruct)
36
+ Subcommands =
37
+ [
38
+ ['breakpoints', 2, "Enable specified breakpoints"],
39
+ ['display', 2, "Enable some expressions to be displayed when program stops"],
40
+ ].map do |name, min, short_help|
41
+ SubcmdStruct.new(name, min, short_help)
42
+ end unless defined?(Subcommands)
43
+
44
+ def regexp
45
+ /^\s* en(?:able)? (?:\s+(.*))?$/ix
46
+ end
47
+
48
+ def execute
49
+ if not @match[1]
50
+ print "\"enable\" must be followed \"display\", \"breakpoints\"" +
51
+ " or breakpoint numbers.\n"
52
+ else
53
+ args = @match[1].split(/[ \t]+/)
54
+ subcmd = args.shift.downcase
55
+ for try_subcmd in Subcommands do
56
+ if (subcmd.size >= try_subcmd.min) and
57
+ (try_subcmd.name[0..subcmd.size-1] == subcmd)
58
+ send("enable_#{try_subcmd.name}", args)
59
+ return
60
+ end
61
+ end
62
+ send("enable_breakpoints", args.unshift(subcmd))
63
+ end
64
+ end
65
+
66
+ def enable_breakpoints(args)
67
+ enable_disable_breakpoints("Enable", args)
68
+ end
69
+
70
+ def enable_display(args)
71
+ enable_disable_display("Enable", args)
72
+ end
73
+
74
+ class << self
75
+ def help_command
76
+ 'enable'
77
+ end
78
+
79
+ def help(cmd)
80
+ s = %{
81
+ Enable some things.
82
+ This is used to cancel the effect of the "disable" command.
83
+ --
84
+ List of enable subcommands:
85
+ --
86
+ }
87
+ for subcmd in Subcommands do
88
+ s += "enable #{subcmd.name} -- #{subcmd.short_help}\n"
89
+ end
90
+ return s
91
+ end
92
+ end
93
+ end
94
+
95
+ class DisableCommand < Command # :nodoc:
96
+ SubcmdStruct=Struct.new(:name, :min, :short_help) unless
97
+ defined?(SubcmdStruct)
98
+ Subcommands =
99
+ [
100
+ ['breakpoints', 2, "Disable specified breakpoints"],
101
+ ['display', 2, "Disable some display expressions when program stops"],
102
+ ].map do |name, min, short_help|
103
+ SubcmdStruct.new(name, min, short_help)
104
+ end unless defined?(Subcommands)
105
+
106
+ def regexp
107
+ /^\s* dis(?:able)? (?:\s+(.*))?$/ix
108
+ end
109
+
110
+ def execute
111
+ if not @match[1]
112
+ print "\"disable\" must be followed \"display\", \"breakpoints\"" +
113
+ " or breakpoint numbers.\n"
114
+ else
115
+ args = @match[1].split(/[ \t]+/)
116
+ subcmd = args.shift.downcase
117
+ for try_subcmd in Subcommands do
118
+ if (subcmd.size >= try_subcmd.min) and
119
+ (try_subcmd.name[0..subcmd.size-1] == subcmd)
120
+ send("disable_#{try_subcmd.name}", args)
121
+ return
122
+ end
123
+ end
124
+ send("disable_breakpoints", args.unshift(subcmd))
125
+ end
126
+ end
127
+
128
+ def disable_breakpoints(args)
129
+ enable_disable_breakpoints("Disable", args)
130
+ end
131
+
132
+ def disable_display(args)
133
+ enable_disable_display("Disable", args)
134
+ end
135
+
136
+ class << self
137
+ def help_command
138
+ 'disable'
139
+ end
140
+
141
+ def help(cmd)
142
+ s = %{
143
+ Disable some things.
144
+
145
+ A disabled item is not forgotten, but has no effect until reenabled.
146
+ Use the "enable" command to have it take effect again.
147
+ --
148
+ List of disable subcommands:
149
+ --
150
+ }
151
+ for subcmd in Subcommands do
152
+ s += "disable #{subcmd.name} -- #{subcmd.short_help}\n"
153
+ end
154
+ return s
155
+ end
156
+ end
157
+ end
158
+
159
+ end # module Debugger
@@ -4,13 +4,16 @@ module Debugger
4
4
  binding = @state.context ? get_binding : TOPLEVEL_BINDING
5
5
  $__dbg_interface = @state.interface
6
6
  eval(<<-EOC, binding)
7
+ __dbg_verbose_save=$VERBOSE; $VERBOSE=false
7
8
  def dbg_print(*args)
8
9
  $__dbg_interface.print(*args)
9
10
  end
11
+ remove_method :puts if self.respond_to?(:puts)
10
12
  def dbg_puts(*args)
11
13
  $__dbg_interface.print(*args)
12
14
  $__dbg_interface.print("\n")
13
15
  end
16
+ $VERBOSE=__dbg_verbose_save
14
17
  EOC
15
18
  yield binding
16
19
  ensure
@@ -21,8 +24,6 @@ module Debugger
21
24
  class EvalCommand < Command # :nodoc:
22
25
  self.control = true
23
26
 
24
- include EvalFunctions
25
-
26
27
  register_setting_get(:autoeval) do
27
28
  EvalCommand.unknown
28
29
  end
@@ -70,8 +71,6 @@ module Debugger
70
71
  class PPCommand < Command # :nodoc:
71
72
  self.control = true
72
73
 
73
- include EvalFunctions
74
-
75
74
  def regexp
76
75
  /^\s*pp\s+/
77
76
  end
@@ -98,4 +97,79 @@ module Debugger
98
97
  end
99
98
  end
100
99
  end
100
+
101
+ class PutLCommand < Command # :nodoc:
102
+ self.control = true
103
+
104
+ def regexp
105
+ /^\s*putl\s+/
106
+ end
107
+
108
+ def execute
109
+ out = StringIO.new
110
+ run_with_binding do |b|
111
+ vals = debug_eval(@match.post_match, b)
112
+ if vals.is_a?(Array)
113
+ vals = vals.map{|item| item.to_s}
114
+ print "%s\n", columnize(vals, self.class.settings[:width])
115
+ else
116
+ PP.pp(vals, out)
117
+ print out.string
118
+ end
119
+ end
120
+ rescue
121
+ out.puts $!.message
122
+ end
123
+
124
+ class << self
125
+ def help_command
126
+ 'putl'
127
+ end
128
+
129
+ def help(cmd)
130
+ %{
131
+ putl expression\t\tevaluate expression, an array, and columnize its value
132
+ }
133
+ end
134
+ end
135
+ end
136
+
137
+ class PSCommand < Command # :nodoc:
138
+ self.control = true
139
+
140
+ include EvalFunctions
141
+
142
+ def regexp
143
+ /^\s*ps\s+/
144
+ end
145
+
146
+ def execute
147
+ out = StringIO.new
148
+ run_with_binding do |b|
149
+ vals = debug_eval(@match.post_match, b)
150
+ if vals.is_a?(Array)
151
+ vals = vals.map{|item| item.to_s}
152
+ print "%s\n", columnize(vals.sort!, self.class.settings[:width])
153
+ else
154
+ PP.pp(vals, out)
155
+ print out.string
156
+ end
157
+ end
158
+ rescue
159
+ out.puts $!.message
160
+ end
161
+
162
+ class << self
163
+ def help_command
164
+ 'ps'
165
+ end
166
+
167
+ def help(cmd)
168
+ %{
169
+ ps expression\tevaluate expression, an array, sort, and columnize its value
170
+ }
171
+ end
172
+ end
173
+ end
174
+
101
175
  end
@@ -1,4 +1,5 @@
1
1
  module Debugger
2
+ # Mix-in module to assist in command parsing.
2
3
  module FrameFunctions # :nodoc:
3
4
  def adjust_frame(frame_pos, absolute)
4
5
  if absolute
@@ -12,10 +13,10 @@ module Debugger
12
13
  end
13
14
 
14
15
  if abs_frame_pos >= @state.context.stack_size then
15
- print "Adjusting would put us beyond the oldest (initial) frame.\n"
16
+ print "Adjusting would put us beyond the oldest (initial) frame."
16
17
  return
17
18
  elsif abs_frame_pos < 0 then
18
- print "Adjusting would put us beyond the newest (innermost) frame.\n"
19
+ print "Adjusting would put us beyond the newest (innermost) frame."
19
20
  return
20
21
  end
21
22
  if @state.frame_pos != abs_frame_pos then
@@ -28,46 +29,83 @@ module Debugger
28
29
 
29
30
  print_frame(@state.frame_pos, true)
30
31
  end
31
-
32
- def get_int(str, cmd)
33
- begin
34
- return Integer(@match[1])
35
- rescue
36
- print "%s argument needs to be a number.\n" % cmd
37
- return nil
32
+
33
+ def get_frame_call(prefix, pos)
34
+ id = @state.context.frame_method(pos)
35
+ klass = @state.context.frame_class(pos)
36
+ call_str = ""
37
+ if id
38
+ args = @state.context.frame_args(pos)
39
+ locals = @state.context.frame_locals(pos)
40
+ if Command.settings[:callstyle] != :short && klass
41
+ if Command.settings[:callstyle] == :tracked
42
+ arg_info = @state.context.frame_args_info(pos)
43
+ end
44
+ call_str << "#{klass}."
45
+ end
46
+ call_str << id.id2name
47
+ if args.any?
48
+ call_str << "("
49
+ args.each_with_index do |name, i|
50
+ case Command.settings[:callstyle]
51
+ when :short
52
+ call_str += "%s, " % [name]
53
+ when :last
54
+ klass = locals[name].class
55
+ if klass.inspect.size > 20+3
56
+ klass = klass.inspect[0..20]+"..."
57
+ end
58
+ call_str += "%s#%s, " % [name, klass]
59
+ when :tracked
60
+ if arg_info && arg_info.size > i
61
+ call_str += "#{name}: #{arg_info[i].inspect}, "
62
+ else
63
+ call_str += "%s, " % name
64
+ end
65
+ end
66
+ if call_str.size > self.class.settings[:width] - prefix.size
67
+ # Strip off trailing ', ' if any but add stuff for later trunc
68
+ call_str[-2..-1] = ",...XX"
69
+ break
70
+ end
71
+ end
72
+ call_str[-2..-1] = ")" # Strip off trailing ', ' if any
73
+ end
38
74
  end
75
+ return call_str
39
76
  end
40
77
 
41
78
  def print_frame(pos, adjust = false)
42
79
  file = @state.context.frame_file(pos)
43
80
  line = @state.context.frame_line(pos)
44
- id = @state.context.frame_method(pos)
45
81
  klass = @state.context.frame_class(pos)
46
82
 
47
- method = ""
48
- if id
49
- method << " in '"
50
- method << "#{klass}." if Command.settings[:frame_class_names] && klass
51
- method << id.id2name
52
- method << "'"
53
- end
54
-
55
- unless Command.settings[:frame_full_path]
83
+ unless Command.settings[:full_path]
56
84
  path_components = file.split(/[\\\/]/)
57
85
  if path_components.size > 3
58
86
  path_components[0...-3] = '...'
59
87
  file = path_components.join(File::ALT_SEPARATOR || File::SEPARATOR)
60
88
  end
61
89
  end
62
-
63
- print "#%d %s:%d%s\n", pos, file, line, method
64
- print "\032\032%s:%d\n", file, line if ENV['EMACS'] && adjust
90
+
91
+ frame_num = "#%d " % pos
92
+ call_str = get_frame_call(frame_num, pos)
93
+ file_line = "at line %s:%d\n" % [CommandProcessor.canonic_file(file), line]
94
+ print frame_num
95
+ unless call_str.empty?
96
+ print call_str
97
+ print ' '
98
+ if call_str.size + frame_num.size + file_line.size > self.class.settings[:width]
99
+ print "\n "
100
+ end
101
+ end
102
+ print file_line
103
+ print "\032\032%s:%d\n" % [CommandProcessor.canonic_file(file),
104
+ line] if ENV['EMACS'] && adjust
65
105
  end
66
106
  end
67
107
 
68
108
  class WhereCommand < Command # :nodoc:
69
- include FrameFunctions
70
-
71
109
  def regexp
72
110
  /^\s*(?:w(?:here)?|bt|backtrace)$/
73
111
  end
@@ -103,19 +141,13 @@ module Debugger
103
141
  end
104
142
 
105
143
  class UpCommand < Command # :nodoc:
106
- include FrameFunctions
107
-
108
144
  def regexp
109
- /^\s* u(?:p)? (?:\s+(.*))? .*$/x
145
+ /^\s* u(?:p)? (?:\s+(.*))?$/x
110
146
  end
111
147
 
112
148
  def execute
113
- unless @match[1]
114
- pos = 1
115
- else
116
- pos = get_int(@match[1], "Up")
117
- return unless pos
118
- end
149
+ pos = get_int(@match[1], "Up")
150
+ return unless pos
119
151
  adjust_frame(pos, false)
120
152
  end
121
153
 
@@ -133,19 +165,13 @@ module Debugger
133
165
  end
134
166
 
135
167
  class DownCommand < Command # :nodoc:
136
- include FrameFunctions
137
-
138
168
  def regexp
139
169
  /^\s* down (?:\s+(.*))? .*$/x
140
170
  end
141
171
 
142
172
  def execute
143
- if not @match[1]
144
- pos = 1
145
- else
146
- pos = get_int(@match[1], "Down")
147
- return unless pos
148
- end
173
+ pos = get_int(@match[1], "Down")
174
+ return unless pos
149
175
  adjust_frame(-pos, false)
150
176
  end
151
177
 
@@ -163,7 +189,6 @@ module Debugger
163
189
  end
164
190
 
165
191
  class FrameCommand < Command # :nodoc:
166
- include FrameFunctions
167
192
  def regexp
168
193
  /^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x
169
194
  end
@@ -1,3 +1,9 @@
1
+ # Display a list of strings as a compact set of columns.
2
+ #
3
+ # Each column is only as wide as necessary.
4
+ # Columns are separated by two spaces (one was not legible enough).
5
+ # Adapted from the routine of the same name in cmd.py
6
+
1
7
  module Debugger
2
8
  class HelpCommand < Command # :nodoc:
3
9
  self.control = true
@@ -7,27 +13,25 @@ module Debugger
7
13
  end
8
14
 
9
15
  def execute
10
- print "ruby-debug help v#{Debugger::VERSION}\n"
16
+ print "ruby-debug help v#{Debugger::VERSION}\n" unless
17
+ self.class.settings[:debuggertesting]
11
18
  cmds = @state.commands.select{ |cmd| [cmd.help_command].flatten.include?(@match[1]) }
12
19
  unless cmds.empty?
13
20
  help = cmds.map{ |cmd| cmd.help(@match[1]) }.join
14
- print help.split("\n").reject{|l| l =~ /^\s*$/ }.map{|l| l.gsub(/^ +/, '')}.join("\n")
21
+ help = help.split("\n").map{|l| l.gsub(/^ +/, '')}
22
+ help.shift if help.first && help.first.empty?
23
+ help.pop if help.last && help.last.empty?
24
+ print help.join("\n")
15
25
  else
16
- print "Type 'help <command-name>' for help on a specific command\n\n"
17
- print "Available commands:\n"
18
- cmds = @state.commands.map{ |cmd| cmd.help_command }
19
- cmds = cmds.flatten.uniq.sort
20
-
21
- buf = ""
22
- cmds.each do |cmd|
23
- if buf.length + cmd.length > 70
24
- print "%s\n", buf
25
- buf = "#{cmd} "
26
- else
27
- buf << cmd << ' '
28
- end
26
+ if @match[1]
27
+ print "Undefined command: \"#{@match[1]}\". Try \"help\"."
28
+ else
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.help_command }
32
+ cmds = cmds.flatten.uniq.sort
33
+ print columnize(cmds, self.class.settings[:width])
29
34
  end
30
- print "%s\n", buf if buf.length > 0
31
35
  end
32
36
  print "\n"
33
37
  end
@@ -45,4 +49,4 @@ module Debugger
45
49
  end
46
50
  end
47
51
  end
48
- end
52
+ end