ruby-debug 0.9.3 → 0.10.0

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