byebug 0.0.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 (133) hide show
  1. data/.gitignore +10 -0
  2. data/.travis.yml +8 -0
  3. data/AUTHORS +10 -0
  4. data/CHANGELOG.md +2 -0
  5. data/CONTRIBUTING.md +1 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +20 -0
  8. data/README.md +5 -0
  9. data/Rakefile +28 -0
  10. data/bin/byebug +395 -0
  11. data/byebug.gemspec +29 -0
  12. data/doc/hanoi.rb +35 -0
  13. data/doc/primes.rb +28 -0
  14. data/doc/rdebug-emacs.texi +1030 -0
  15. data/doc/test-tri2.rb +18 -0
  16. data/doc/tri3.rb +8 -0
  17. data/doc/triangle.rb +12 -0
  18. data/ext/byebug/breakpoint.c +476 -0
  19. data/ext/byebug/byebug.c +512 -0
  20. data/ext/byebug/byebug.h +131 -0
  21. data/ext/byebug/context.c +424 -0
  22. data/ext/byebug/extconf.rb +21 -0
  23. data/ext/byebug/locker.c +53 -0
  24. data/lib/byebug.rb +404 -0
  25. data/lib/byebug/command.rb +232 -0
  26. data/lib/byebug/commands/breakpoints.rb +153 -0
  27. data/lib/byebug/commands/catchpoint.rb +56 -0
  28. data/lib/byebug/commands/condition.rb +49 -0
  29. data/lib/byebug/commands/continue.rb +38 -0
  30. data/lib/byebug/commands/control.rb +110 -0
  31. data/lib/byebug/commands/display.rb +122 -0
  32. data/lib/byebug/commands/edit.rb +48 -0
  33. data/lib/byebug/commands/enable.rb +202 -0
  34. data/lib/byebug/commands/eval.rb +176 -0
  35. data/lib/byebug/commands/finish.rb +43 -0
  36. data/lib/byebug/commands/frame.rb +303 -0
  37. data/lib/byebug/commands/help.rb +56 -0
  38. data/lib/byebug/commands/info.rb +462 -0
  39. data/lib/byebug/commands/irb.rb +123 -0
  40. data/lib/byebug/commands/jump.rb +66 -0
  41. data/lib/byebug/commands/kill.rb +51 -0
  42. data/lib/byebug/commands/list.rb +94 -0
  43. data/lib/byebug/commands/method.rb +84 -0
  44. data/lib/byebug/commands/quit.rb +39 -0
  45. data/lib/byebug/commands/reload.rb +40 -0
  46. data/lib/byebug/commands/save.rb +90 -0
  47. data/lib/byebug/commands/set.rb +210 -0
  48. data/lib/byebug/commands/show.rb +246 -0
  49. data/lib/byebug/commands/skip.rb +35 -0
  50. data/lib/byebug/commands/source.rb +36 -0
  51. data/lib/byebug/commands/stepping.rb +83 -0
  52. data/lib/byebug/commands/threads.rb +189 -0
  53. data/lib/byebug/commands/tmate.rb +36 -0
  54. data/lib/byebug/commands/trace.rb +56 -0
  55. data/lib/byebug/commands/variables.rb +199 -0
  56. data/lib/byebug/context.rb +58 -0
  57. data/lib/byebug/helper.rb +69 -0
  58. data/lib/byebug/interface.rb +223 -0
  59. data/lib/byebug/processor.rb +468 -0
  60. data/lib/byebug/version.rb +3 -0
  61. data/man/rdebug.1 +241 -0
  62. data/test/breakpoints_test.rb +357 -0
  63. data/test/conditions_test.rb +77 -0
  64. data/test/continue_test.rb +44 -0
  65. data/test/display_test.rb +141 -0
  66. data/test/edit_test.rb +56 -0
  67. data/test/eval_test.rb +92 -0
  68. data/test/examples/breakpoint1.rb +15 -0
  69. data/test/examples/breakpoint2.rb +7 -0
  70. data/test/examples/conditions.rb +4 -0
  71. data/test/examples/continue.rb +4 -0
  72. data/test/examples/display.rb +5 -0
  73. data/test/examples/edit.rb +3 -0
  74. data/test/examples/edit2.rb +3 -0
  75. data/test/examples/eval.rb +4 -0
  76. data/test/examples/finish.rb +20 -0
  77. data/test/examples/frame.rb +20 -0
  78. data/test/examples/frame_threads.rb +31 -0
  79. data/test/examples/help.rb +2 -0
  80. data/test/examples/info.rb +38 -0
  81. data/test/examples/info2.rb +3 -0
  82. data/test/examples/info_threads.rb +48 -0
  83. data/test/examples/irb.rb +6 -0
  84. data/test/examples/jump.rb +14 -0
  85. data/test/examples/kill.rb +2 -0
  86. data/test/examples/list.rb +12 -0
  87. data/test/examples/method.rb +15 -0
  88. data/test/examples/post_mortem.rb +19 -0
  89. data/test/examples/quit.rb +2 -0
  90. data/test/examples/reload.rb +6 -0
  91. data/test/examples/restart.rb +6 -0
  92. data/test/examples/save.rb +3 -0
  93. data/test/examples/set.rb +3 -0
  94. data/test/examples/set_annotate.rb +12 -0
  95. data/test/examples/settings.rb +1 -0
  96. data/test/examples/show.rb +2 -0
  97. data/test/examples/source.rb +3 -0
  98. data/test/examples/stepping.rb +21 -0
  99. data/test/examples/thread.rb +32 -0
  100. data/test/examples/tmate.rb +10 -0
  101. data/test/examples/trace.rb +7 -0
  102. data/test/examples/trace_threads.rb +20 -0
  103. data/test/examples/variables.rb +26 -0
  104. data/test/finish_test.rb +48 -0
  105. data/test/frame_test.rb +143 -0
  106. data/test/help_test.rb +50 -0
  107. data/test/info_test.rb +313 -0
  108. data/test/irb_test.rb +81 -0
  109. data/test/jump_test.rb +70 -0
  110. data/test/kill_test.rb +48 -0
  111. data/test/list_test.rb +145 -0
  112. data/test/method_test.rb +70 -0
  113. data/test/post_mortem_test.rb +27 -0
  114. data/test/quit_test.rb +56 -0
  115. data/test/reload_test.rb +44 -0
  116. data/test/restart_test.rb +164 -0
  117. data/test/save_test.rb +92 -0
  118. data/test/set_test.rb +177 -0
  119. data/test/show_test.rb +293 -0
  120. data/test/source_test.rb +45 -0
  121. data/test/stepping_test.rb +130 -0
  122. data/test/support/breakpoint.rb +13 -0
  123. data/test/support/context.rb +14 -0
  124. data/test/support/matchers.rb +67 -0
  125. data/test/support/mocha_extensions.rb +72 -0
  126. data/test/support/processor.rb +7 -0
  127. data/test/support/test_dsl.rb +206 -0
  128. data/test/support/test_interface.rb +68 -0
  129. data/test/test_helper.rb +10 -0
  130. data/test/tmate_test.rb +44 -0
  131. data/test/trace_test.rb +159 -0
  132. data/test/variables_test.rb +119 -0
  133. metadata +265 -0
@@ -0,0 +1,38 @@
1
+ module Byebug
2
+
3
+ # Implements byebug "continue" command.
4
+ class ContinueCommand < Command
5
+ self.allow_in_post_mortem = true
6
+ self.need_context = false
7
+ def regexp
8
+ /^\s* c(?:ont(?:inue)?)? (?:\s+(.*))? $/x
9
+ end
10
+
11
+ def execute
12
+ if @match[1] && !@state.context.dead?
13
+ filename = File.expand_path(@state.file)
14
+ line_number = get_int(@match[1], "Continue", 0, nil, 0)
15
+ return unless line_number
16
+ unless LineCache.trace_line_numbers(filename).member?(line_number)
17
+ errmsg("Line %d is not a stopping point in file \"%s\".\n",
18
+ line_number, filename)
19
+ return
20
+ end
21
+ Byebug.add_breakpoint filename, line_number
22
+ end
23
+ @state.proceed
24
+ end
25
+
26
+ class << self
27
+ def help_command
28
+ 'continue'
29
+ end
30
+
31
+ def help(cmd)
32
+ %{
33
+ c[ont[inue]][ nnn]\trun until program ends, hits a breakpoint or reaches line nnn
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,110 @@
1
+ module Byebug
2
+
3
+ class RestartCommand < Command # :nodoc:
4
+ self.allow_in_control = true
5
+
6
+ def regexp
7
+ / ^\s*
8
+ (?:restart|R)
9
+ (?:\s+ (\S?.*\S))? \s*
10
+ $
11
+ /ix
12
+ end
13
+
14
+ def execute
15
+ if not defined? Byebug::PROG_SCRIPT
16
+ errmsg "Don't know name of debugged program\n"
17
+ return
18
+ end
19
+
20
+ if not File.exist?(File.expand_path(Byebug::PROG_SCRIPT))
21
+ errmsg "Ruby program #{Byebug::PROG_SCRIPT} doesn't exist\n"
22
+ return
23
+ end
24
+
25
+ if not defined? Byebug::RDEBUG_SCRIPT
26
+ print "Byebug was not called from the outset...\n"
27
+ if not File.executable?(Byebug::PROG_SCRIPT)
28
+ print "Ruby program #{Byebug::PROG_SCRIPT} not executable... " \
29
+ "We'll add a call to Ruby.\n"
30
+ ruby = begin defined?(Gem) ? Gem.ruby : "ruby" rescue "ruby" end
31
+ rdebug_script = "#{ruby} -I#{$:.join(' -I')} #{prog_script}"
32
+ else
33
+ rdebug_script = Byebug::PROG_SCRIPT
34
+ end
35
+ else
36
+ rdebug_script = Byebug::RDEBUG_SCRIPT
37
+ end
38
+
39
+ begin
40
+ Dir.chdir(Byebug::INITIAL_DIR)
41
+ rescue
42
+ print "Failed to change initial directory #{Byebug::INITIAL_DIR}"
43
+ end
44
+
45
+ if @match[1]
46
+ argv = [Byebug::PROG_SCRIPT] + @match[1].split(/[ \t]+/)
47
+ else
48
+ if not defined? Command.settings[:argv]
49
+ errmsg "Arguments have not been set. Use 'set args' to set them.\n"
50
+ return
51
+ else
52
+ argv = Command.settings[:argv]
53
+ end
54
+ end
55
+ args = argv.join(' ')
56
+
57
+ # An execv would be preferable to the "exec" below.
58
+ cmd = "#{rdebug_script} #{args}"
59
+ p "cmd: #{cmd}"
60
+ print "Re exec'ing:\n\t#{cmd}\n"
61
+ exec cmd
62
+ rescue Errno::EOPNOTSUPP
63
+ print "Restart command is not available at this time.\n"
64
+ end
65
+
66
+ class << self
67
+ def help_command
68
+ 'restart'
69
+ end
70
+
71
+ def help(cmd)
72
+ %{
73
+ restart|R [args]
74
+ Restart the program. This is a re-exec - all byebug state
75
+ is lost. If command arguments are passed those are used.
76
+ }
77
+ end
78
+ end
79
+ end
80
+
81
+ class InterruptCommand < Command # :nodoc:
82
+ self.allow_in_control = true
83
+ self.allow_in_post_mortem = false
84
+ self.event = false
85
+ self.need_context = true
86
+
87
+ def regexp
88
+ /^\s*i(?:nterrupt)?\s*$/
89
+ end
90
+
91
+ def execute
92
+ unless Byebug.interrupt_last
93
+ context = Byebug.thread_context(Thread.main)
94
+ context.interrupt
95
+ end
96
+ end
97
+
98
+ class << self
99
+ def help_command
100
+ 'interrupt'
101
+ end
102
+
103
+ def help(cmd)
104
+ %{
105
+ i[nterrupt]\tinterrupt the program
106
+ }
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,122 @@
1
+ module Byebug
2
+
3
+ module DisplayFunctions # :nodoc:
4
+
5
+ def display_expression(exp)
6
+ print "%s = %s\n", exp, debug_silent_eval(exp).to_s
7
+ end
8
+
9
+ def active_display_expressions?
10
+ @state.display.select{|d| d[0]}.size > 0
11
+ end
12
+
13
+ def print_display_expressions
14
+ n = 1
15
+ for d in @state.display
16
+ if d[0]
17
+ print "%d: ", n
18
+ display_expression(d[1])
19
+ end
20
+ n += 1
21
+ end
22
+ end
23
+ end
24
+
25
+ class AddDisplayCommand < Command # :nodoc:
26
+ def regexp
27
+ /^\s*disp(?:lay)?\s+(.+)$/
28
+ end
29
+
30
+ def execute
31
+ exp = @match[1]
32
+ @state.display.push [true, exp]
33
+ print "%d: ", @state.display.size
34
+ display_expression(exp)
35
+ end
36
+
37
+ class << self
38
+ def help_command
39
+ 'display'
40
+ end
41
+
42
+ def help(cmd)
43
+ %{
44
+ disp[lay] <expression>\tadd expression into display expression list
45
+ }
46
+ end
47
+ end
48
+ end
49
+
50
+ class DisplayCommand < Command # :nodoc:
51
+ def self.always_run
52
+ Byebug.annotate = 0 unless Byebug.annotate
53
+ if Byebug.annotate > 1
54
+ 0
55
+ else
56
+ 2
57
+ end
58
+ end
59
+
60
+ def regexp
61
+ /^\s*disp(?:lay)?$/
62
+ end
63
+
64
+ def execute
65
+ print_display_expressions
66
+ end
67
+
68
+ class << self
69
+ def help_command
70
+ 'display'
71
+ end
72
+
73
+ def help(cmd)
74
+ %{
75
+ disp[lay]\t\tdisplay expression list
76
+ }
77
+ end
78
+ end
79
+ end
80
+
81
+ class DeleteDisplayCommand < Command # :nodoc:
82
+
83
+ def regexp
84
+ /^\s* undisp(?:lay)? \s* (?:(\S+))?$/x
85
+ end
86
+
87
+ def execute
88
+ unless pos = @match[1]
89
+ if confirm("Clear all expressions? (y/n) ")
90
+ for d in @state.display
91
+ d[0] = false
92
+ end
93
+ end
94
+ else
95
+ pos = get_int(pos, "Undisplay")
96
+ return unless pos
97
+ if @state.display[pos-1]
98
+ @state.display[pos-1][0] = nil
99
+ else
100
+ errmsg "Display expression %d is not defined.\n", pos
101
+ end
102
+ end
103
+ end
104
+
105
+ class << self
106
+ def help_command
107
+ 'undisplay'
108
+ end
109
+
110
+ def help(cmd)
111
+ %{
112
+ undisp[lay][ nnn]
113
+ Cancel some expressions to be displayed when program stops.
114
+ Arguments are the code numbers of the expressions to stop displaying.
115
+ No argument means cancel all automatic-display expressions.
116
+ "delete display" has the same effect as this command.
117
+ Do "info display" to see current list of code numbers.
118
+ }
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,48 @@
1
+ module Byebug
2
+ class Edit < Command # :nodoc:
3
+ self.allow_in_control = true
4
+ def regexp
5
+ /^\s* ed(?:it)? (?:\s+(.*))?$/ix
6
+ end
7
+
8
+ def execute
9
+ if not @match[1] or @match[1].strip.empty?
10
+ unless @state.context
11
+ errmsg "We are not in a state that has an associated file.\n"
12
+ return
13
+ end
14
+ file = @state.file
15
+ line_number = @state.line
16
+ elsif @pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1])
17
+ file, line_number = @pos_match.captures
18
+ else
19
+ errmsg "Invalid file/line number specification: #{@match[1]}\n"
20
+ return
21
+ end
22
+ editor = ENV['EDITOR'] || 'ex'
23
+ if File.readable?(file)
24
+ system("#{editor} +#{line_number} #{file}")
25
+ else
26
+ errmsg "File \"#{file}\" is not readable.\n"
27
+ end
28
+ end
29
+
30
+ class << self
31
+ def help_command
32
+ 'edit'
33
+ end
34
+
35
+ def help(cmd)
36
+ %{
37
+ Edit specified file.
38
+
39
+ With no argument, edits file containing most recent line listed.
40
+ Editing targets can also be specified in this:
41
+ FILE:LINENUM, to edit at that line in that file,
42
+ }
43
+ end
44
+ end
45
+ end
46
+
47
+
48
+ end # module Byebug
@@ -0,0 +1,202 @@
1
+ module Byebug
2
+ # Mix-in module to assist in command parsing.
3
+ module EnableDisableFunctions # :nodoc:
4
+ def enable_disable_breakpoints(is_enable, args)
5
+ breakpoints = Byebug.breakpoints.sort_by{|b| b.id }
6
+ largest = breakpoints.inject(0) do |tally, b|
7
+ tally = b.id if b.id > tally
8
+ end
9
+ if 0 == largest
10
+ errmsg "No breakpoints have been set.\n"
11
+ return
12
+ end
13
+ args.each do |pos|
14
+ pos = get_int(pos, "#{is_enable} breakpoints", 1, largest)
15
+ return nil unless pos
16
+ breakpoints.each do |b|
17
+ if b.id == pos
18
+ enabled = ("Enable" == is_enable)
19
+ if enabled
20
+ unless syntax_valid?(b.expr)
21
+ errmsg("Expression \"#{b.expr}\" syntactically incorrect; breakpoint remains disabled.\n")
22
+ break
23
+ end
24
+ end
25
+ b.enabled = ("Enable" == is_enable)
26
+ break
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def enable_disable_display(is_enable, args)
33
+ if 0 == @state.display.size
34
+ errmsg "No display expressions have been set.\n"
35
+ return
36
+ end
37
+ args.each do |pos|
38
+ pos = get_int(pos, "#{is_enable} display", 1, @state.display.size)
39
+ return nil unless pos
40
+ @state.display[pos-1][0] = ("Enable" == is_enable)
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ class EnableCommand < Command # :nodoc:
47
+ Subcommands =
48
+ [
49
+ ['breakpoints', 2, "Enable specified breakpoints",
50
+ "Give breakpoint numbers (separated by spaces) as arguments.
51
+ This is used to cancel the effect of the \"disable\" command."
52
+ ],
53
+ ['display', 2,
54
+ "Enable some expressions to be displayed when program stops",
55
+ "Arguments are the code numbers of the expressions to resume displaying.
56
+ Do \"info display\" to see current list of code numbers."],
57
+ ].map do |name, min, short_help, long_help|
58
+ SubcmdStruct.new(name, min, short_help, long_help)
59
+ end unless defined?(Subcommands)
60
+
61
+ def regexp
62
+ /^\s* en(?:able)? (?:\s+(.*))?$/ix
63
+ end
64
+
65
+ def execute
66
+ if not @match[1]
67
+ errmsg "\"enable\" must be followed \"display\", \"breakpoints\"" +
68
+ " or breakpoint numbers.\n"
69
+ else
70
+ args = @match[1].split(/[ \t]+/)
71
+ param = args.shift
72
+ subcmd = find(Subcommands, param)
73
+ if subcmd
74
+ send("enable_#{subcmd.name}", args)
75
+ else
76
+ send("enable_breakpoints", args.unshift(param))
77
+ end
78
+ end
79
+ end
80
+
81
+ def enable_breakpoints(args)
82
+ enable_disable_breakpoints("Enable", args)
83
+ end
84
+
85
+ def enable_display(args)
86
+ enable_disable_display("Enable", args)
87
+ end
88
+
89
+ class << self
90
+ def help_command
91
+ 'enable'
92
+ end
93
+
94
+ def help(args)
95
+ if args[1]
96
+ s = args[1]
97
+ subcmd = Subcommands.find do |try_subcmd|
98
+ (s.size >= try_subcmd.min) and
99
+ (try_subcmd.name[0..s.size-1] == s)
100
+ end
101
+ if subcmd
102
+ str = subcmd.short_help + '.'
103
+ str += "\n" + subcmd.long_help if subcmd.long_help
104
+ return str
105
+ else
106
+ return "Invalid 'enable' subcommand '#{args[1]}'."
107
+ end
108
+ end
109
+ s = %{
110
+ Enable some things.
111
+ This is used to cancel the effect of the "disable" command.
112
+ --
113
+ List of enable subcommands:
114
+ --
115
+ }
116
+ for subcmd in Subcommands do
117
+ s += "enable #{subcmd.name} -- #{subcmd.short_help}\n"
118
+ end
119
+ return s
120
+ end
121
+ end
122
+ end
123
+
124
+ class DisableCommand < Command # :nodoc:
125
+ Subcommands =
126
+ [
127
+ ['breakpoints', 1, "Disable some breakpoints",
128
+ "Arguments are breakpoint numbers with spaces in between.
129
+ A disabled breakpoint is not forgotten, but has no effect until reenabled."],
130
+ ['display', 1, "Disable some display expressions when program stops",
131
+ "Arguments are the code numbers of the expressions to stop displaying.
132
+ Do \"info display\" to see current list of code numbers."],
133
+ ].map do |name, min, short_help, long_help|
134
+ SubcmdStruct.new(name, min, short_help, long_help)
135
+ end unless defined?(Subcommands)
136
+
137
+ def regexp
138
+ /^\s* dis(?:able)? (?:\s+(.*))?$/ix
139
+ end
140
+
141
+ def execute
142
+ if not @match[1]
143
+ errmsg "\"disable\" must be followed \"display\", \"breakpoints\"" +
144
+ " or breakpoint numbers.\n"
145
+ else
146
+ args = @match[1].split(/[ \t]+/)
147
+ param = args.shift
148
+ subcmd = find(Subcommands, param)
149
+ if subcmd
150
+ send("disable_#{subcmd.name}", args)
151
+ else
152
+ send("disable_breakpoints", args.unshift(param))
153
+ end
154
+ end
155
+ end
156
+
157
+ def disable_breakpoints(args)
158
+ enable_disable_breakpoints("Disable", args)
159
+ end
160
+
161
+ def disable_display(args)
162
+ enable_disable_display("Disable", args)
163
+ end
164
+
165
+ class << self
166
+ def help_command
167
+ 'disable'
168
+ end
169
+
170
+ def help(args)
171
+ if args[1]
172
+ s = args[1]
173
+ subcmd = Subcommands.find do |try_subcmd|
174
+ (s.size >= try_subcmd.min) and
175
+ (try_subcmd.name[0..s.size-1] == s)
176
+ end
177
+ if subcmd
178
+ str = subcmd.short_help + '.'
179
+ str += "\n" + subcmd.long_help if subcmd.long_help
180
+ return str
181
+ else
182
+ return "Invalid 'disable' subcommand '#{args[1]}'."
183
+ end
184
+ end
185
+ s = %{
186
+ Disable some things.
187
+
188
+ A disabled item is not forgotten, but has no effect until reenabled.
189
+ Use the "enable" command to have it take effect again.
190
+ --
191
+ List of disable subcommands:
192
+ --
193
+ }
194
+ for subcmd in Subcommands do
195
+ s += "disable #{subcmd.name} -- #{subcmd.short_help}\n"
196
+ end
197
+ return s
198
+ end
199
+ end
200
+ end
201
+
202
+ end # module Byebug