ruby-debug-ide19 0.4.10

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 (39) hide show
  1. data/CHANGES +75 -0
  2. data/ChangeLog +465 -0
  3. data/ChangeLog.archive +1073 -0
  4. data/MIT-LICENSE +24 -0
  5. data/Rakefile +110 -0
  6. data/bin/rdebug-ide +88 -0
  7. data/ext/mkrf_conf.rb +28 -0
  8. data/lib/ruby-debug-ide.rb +172 -0
  9. data/lib/ruby-debug/command.rb +169 -0
  10. data/lib/ruby-debug/commands/breakpoints.rb +129 -0
  11. data/lib/ruby-debug/commands/catchpoint.rb +52 -0
  12. data/lib/ruby-debug/commands/condition.rb +51 -0
  13. data/lib/ruby-debug/commands/control.rb +129 -0
  14. data/lib/ruby-debug/commands/enable.rb +203 -0
  15. data/lib/ruby-debug/commands/eval.rb +64 -0
  16. data/lib/ruby-debug/commands/frame.rb +155 -0
  17. data/lib/ruby-debug/commands/inspect.rb +24 -0
  18. data/lib/ruby-debug/commands/jump.rb +73 -0
  19. data/lib/ruby-debug/commands/load.rb +18 -0
  20. data/lib/ruby-debug/commands/stepping.rb +108 -0
  21. data/lib/ruby-debug/commands/threads.rb +153 -0
  22. data/lib/ruby-debug/commands/variables.rb +136 -0
  23. data/lib/ruby-debug/event_processor.rb +74 -0
  24. data/lib/ruby-debug/helper.rb +33 -0
  25. data/lib/ruby-debug/interface.rb +39 -0
  26. data/lib/ruby-debug/printers.rb +2 -0
  27. data/lib/ruby-debug/processor.rb +152 -0
  28. data/lib/ruby-debug/xml_printer.rb +268 -0
  29. data/test/rd_basic_test.rb +10 -0
  30. data/test/rd_catchpoint_test.rb +20 -0
  31. data/test/rd_condition_test.rb +11 -0
  32. data/test/rd_enable_disable_test.rb +43 -0
  33. data/test/rd_inspect_test.rb +11 -0
  34. data/test/rd_stepping_breakpoints_test.rb +36 -0
  35. data/test/rd_test_base.rb +44 -0
  36. data/test/rd_threads_and_frames_test.rb +11 -0
  37. data/test/rd_variables_test.rb +11 -0
  38. data/test/ruby-debug/xml_printer_test.rb +105 -0
  39. metadata +103 -0
@@ -0,0 +1,268 @@
1
+ require 'cgi'
2
+ require 'yaml'
3
+
4
+ module Debugger
5
+
6
+ class XmlPrinter # :nodoc:
7
+ attr_accessor :interface
8
+
9
+ def initialize(interface)
10
+ @interface = interface
11
+ end
12
+
13
+ def print_msg(*args)
14
+ msg, *args = args
15
+ xml_message = CGI.escapeHTML(msg % args)
16
+ print "<message>#{xml_message}</message>"
17
+ end
18
+
19
+ # Sends debug message to the frontend if XML debug logging flag (--xml-debug) is on.
20
+ def print_debug(*args)
21
+ Debugger.print_debug(*args)
22
+ if Debugger.xml_debug
23
+ msg, *args = args
24
+ xml_message = CGI.escapeHTML(msg % args)
25
+ @interface.print("<message debug='true'>#{xml_message}</message>")
26
+ end
27
+ end
28
+
29
+ def print_error(*args)
30
+ print_element("error") do
31
+ msg, *args = args
32
+ print CGI.escapeHTML(msg % args)
33
+ end
34
+ end
35
+
36
+ def print_frames(context, current_frame_id)
37
+ print_element("frames") do
38
+ (0...context.stack_size).each do |id|
39
+ print_frame(context, id, current_frame_id)
40
+ end
41
+ end
42
+ end
43
+
44
+ def print_current_frame(frame_pos)
45
+ print_debug "Selected frame no #{frame_pos}"
46
+ end
47
+
48
+ def print_frame(context, frame_id, current_frame_id)
49
+ # idx + 1: one-based numbering as classic-debugger
50
+ file = context.frame_file(frame_id)
51
+ print "<frame no=\'%s\' file=\'%s\' line=\'%s\' #{"current='true' " if frame_id == current_frame_id}/>",
52
+ frame_id + 1, File.expand_path(file), context.frame_line(frame_id)
53
+ end
54
+
55
+ def print_contexts(contexts)
56
+ print_element("threads") do
57
+ contexts.each do |c|
58
+ print_context(c) unless c.ignored?
59
+ end
60
+ end
61
+ end
62
+
63
+ def print_context(context)
64
+ current = 'current="yes"' if context.thread == Thread.current
65
+ print "<thread id=\"%s\" status=\"%s\" #{current}/>", context.thnum, context.thread.status
66
+ end
67
+
68
+ def print_variables(vars, kind)
69
+ print_element("variables") do
70
+ # print self at top position
71
+ print_variable('self', yield('self'), kind) if vars.include?('self')
72
+ vars.sort.each do |v|
73
+ print_variable(v, yield(v), kind) unless v == 'self'
74
+ end
75
+ end
76
+ end
77
+
78
+ def print_array(array)
79
+ print_element("variables") do
80
+ index = 0
81
+ array.each { |e|
82
+ print_variable('[' + index.to_s + ']', e, 'instance')
83
+ index += 1
84
+ }
85
+ end
86
+ end
87
+
88
+ def print_hash(hash)
89
+ print_element("variables") do
90
+ hash.keys.each { | k |
91
+ if k.class.name == "String"
92
+ name = '\'' + k + '\''
93
+ else
94
+ name = k.to_s
95
+ end
96
+ print_variable(name, hash[k], 'instance')
97
+ }
98
+ end
99
+ end
100
+
101
+ def print_variable(name, value, kind)
102
+ name = name.to_s
103
+ unless value
104
+ print("<variable name=\"%s\" kind=\"%s\"/>", CGI.escapeHTML(name), kind)
105
+ return
106
+ end
107
+ if value.is_a?(Array) || value.is_a?(Hash)
108
+ has_children = !value.empty?
109
+ unless has_children
110
+ value_str = "Empty #{value.class}"
111
+ else
112
+ value_str = "#{value.class} (#{value.size} element(s))"
113
+ end
114
+ else
115
+ has_children = !value.instance_variables.empty? || !value.class.class_variables.empty?
116
+ value_str = value.to_s || 'nil' rescue "<#to_s method raised exception: #$!>"
117
+ unless value_str.is_a?(String)
118
+ value_str = "ERROR: #{value.class}.to_s method returns #{value_str.class}. Should return String."
119
+ end
120
+ if value_str =~ /^\"(.*)"$/
121
+ value_str = $1
122
+ end
123
+ end
124
+ value_str = "[Binary Data]" if value_str.is_binary_data?
125
+ print("<variable name=\"%s\" kind=\"%s\" value=\"%s\" type=\"%s\" hasChildren=\"%s\" objectId=\"%#+x\"/>",
126
+ CGI.escapeHTML(name), kind, CGI.escapeHTML(value_str), value.class,
127
+ has_children, value.respond_to?(:object_id) ? value.object_id : value.id)
128
+ end
129
+
130
+ def print_breakpoints(breakpoints)
131
+ print_element 'breakpoints' do
132
+ breakpoints.sort_by{|b| b.id }.each do |b|
133
+ print "<breakpoint n=\"%d\" file=\"%s\" line=\"%s\" />", b.id, b.source, b.pos.to_s
134
+ end
135
+ end
136
+ end
137
+
138
+ def print_breakpoint_added(b)
139
+ print "<breakpointAdded no=\"%s\" location=\"%s:%s\"/>", b.id, b.source, b.pos
140
+ end
141
+
142
+ def print_breakpoint_deleted(b)
143
+ print "<breakpointDeleted no=\"%s\"/>", b.id
144
+ end
145
+
146
+ def print_breakpoint_enabled(b)
147
+ print "<breakpointEnabled bp_id=\"%s\"/>", b.id
148
+ end
149
+
150
+ def print_breakpoint_disabled(b)
151
+ print "<breakpointDisabled bp_id=\"%s\"/>", b.id
152
+ end
153
+
154
+ def print_contdition_set(bp_id)
155
+ print "<conditionSet bp_id=\"%d\"/>", bp_id
156
+ end
157
+
158
+ def print_catchpoint_set(exception_class_name)
159
+ print "<catchpointSet exception=\"%s\"/>", exception_class_name
160
+ end
161
+
162
+ def print_expressions(exps)
163
+ print_element "expressions" do
164
+ exps.each_with_index do |(exp, value), idx|
165
+ print_expression(exp, value, idx+1)
166
+ end
167
+ end unless exps.empty?
168
+ end
169
+
170
+ def print_expression(exp, value, idx)
171
+ print "<dispay name=\"%s\" value=\"%s\" no=\"%d\" />", exp, value, idx
172
+ end
173
+
174
+ def print_eval(exp, value)
175
+ print "<eval expression=\"%s\" value=\"%s\" />", CGI.escapeHTML(exp), value
176
+ end
177
+
178
+ def print_pp(value)
179
+ print value
180
+ end
181
+
182
+ def print_list(b, e, file, line)
183
+ print "[%d, %d] in %s\n", b, e, file
184
+ if lines = Debugger.source_for(file)
185
+ b.upto(e) do |n|
186
+ if n > 0 && lines[n-1]
187
+ if n == line
188
+ print "=> %d %s\n", n, lines[n-1].chomp
189
+ else
190
+ print " %d %s\n", n, lines[n-1].chomp
191
+ end
192
+ end
193
+ end
194
+ else
195
+ print "No sourcefile available for %s\n", file
196
+ end
197
+ end
198
+
199
+ def print_methods(methods)
200
+ print_element "methods" do
201
+ methods.each do |method|
202
+ print "<method name=\"%s\" />", method
203
+ end
204
+ end
205
+ end
206
+
207
+ # Events
208
+
209
+ def print_breakpoint(n, breakpoint)
210
+ print("<breakpoint file=\"%s\" line=\"%s\" threadId=\"%d\"/>",
211
+ breakpoint.source, breakpoint.pos, Debugger.current_context.thnum)
212
+ end
213
+
214
+ def print_catchpoint(exception)
215
+ context = Debugger.current_context
216
+ print("<exception file=\"%s\" line=\"%s\" type=\"%s\" message=\"%s\" threadId=\"%d\"/>",
217
+ context.frame_file(0), context.frame_line(0), exception.class, CGI.escapeHTML(exception.to_s), context.thnum)
218
+ end
219
+
220
+ def print_trace(context, file, line)
221
+ Debugger::print_debug "trace: location=\"%s:%s\", threadId=%d", file, line, context.thnum
222
+ # TBD: do we want to clog fronend with the <trace> elements? There are tons of them.
223
+ # print "<trace file=\"%s\" line=\"%s\" threadId=\"%d\" />", file, line, context.thnum
224
+ end
225
+
226
+ def print_at_line(context, file, line)
227
+ print "<suspended file=\'%s\' line=\'%s\' threadId=\'%d\' frames=\'%d\'/>",
228
+ File.expand_path(file), line, context.thnum, context.stack_size
229
+ end
230
+
231
+ def print_exception(exception, binding)
232
+ print "<processingException type=\"%s\" message=\"%s\"/>",
233
+ exception.class, CGI.escapeHTML(exception.to_s)
234
+ end
235
+
236
+ def print_inspect(eval_result)
237
+ print_element("variables") do
238
+ print_variable("eval_result", eval_result, 'local')
239
+ end
240
+ end
241
+
242
+ def print_load_result(file, exception=nil)
243
+ if exception then
244
+ print("<loadResult file=\"%s\" exceptionType=\"%s\" exceptionMessage=\"%s\"/>", file, exception.class, CGI.escapeHTML(exception.to_s))
245
+ else
246
+ print("<loadResult file=\"%s\" status=\"OK\"/>", file)
247
+ end
248
+ end
249
+
250
+ def print_element(name)
251
+ print("<#{name}>")
252
+ begin
253
+ yield
254
+ ensure
255
+ print("</#{name}>")
256
+ end
257
+ end
258
+
259
+ private
260
+
261
+ def print(*params)
262
+ Debugger::print_debug(*params)
263
+ @interface.print(*params)
264
+ end
265
+
266
+ end
267
+
268
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'basic_test'
4
+ require 'rd_test_base'
5
+
6
+ class RDSteppingAndBreakpointsTest < RDTestBase
7
+
8
+ include BasicTest
9
+
10
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rd_test_base'
4
+
5
+ class RDCatchpointTest < RDTestBase
6
+
7
+ def test_catchpoint_basics
8
+ create_socket ['sleep 0.01', '5/0', 'sleep 0.01']
9
+ run_to_line(1)
10
+ send_next
11
+ assert_suspension(@test_path, 2, 1)
12
+ send_ruby('catch ZeroDivisionError')
13
+ assert_catchpoint_set('ZeroDivisionError')
14
+ send_next
15
+ assert_exception(@test_path, 2, 'ZeroDivisionError')
16
+ send_next
17
+ end
18
+
19
+ end
20
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rd_test_base'
4
+ require 'condition_test'
5
+
6
+ class RDConditionTest < RDTestBase
7
+
8
+ include ConditionTest
9
+
10
+ end
11
+
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rd_test_base'
4
+
5
+ class RDEnableDisableTest < RDTestBase
6
+
7
+ def test_enable_disable_basics
8
+ create_socket ['1.upto(10) do', 'sleep 0.01', 'sleep 0.01', 'end']
9
+
10
+ send_test_breakpoint(2)
11
+ assert_breakpoint_added_no(1)
12
+ send_test_breakpoint(3)
13
+ assert_breakpoint_added_no(2)
14
+
15
+ start_debugger
16
+ assert_test_breakpoint(2)
17
+ send_cont
18
+ assert_test_breakpoint(3)
19
+ send_cont
20
+ assert_test_breakpoint(2)
21
+ send_ruby('disable 2')
22
+ assert_breakpoint_disabled(2)
23
+ send_cont
24
+ assert_test_breakpoint(2)
25
+ send_cont
26
+ assert_test_breakpoint(2)
27
+ send_ruby('enable 2')
28
+ assert_breakpoint_enabled(2)
29
+ send_cont
30
+ assert_test_breakpoint(3)
31
+ send_cont
32
+ assert_test_breakpoint(2)
33
+ send_cont
34
+ assert_test_breakpoint(3)
35
+ send_ruby('disable 1')
36
+ assert_breakpoint_disabled(1)
37
+ send_ruby('disable 2')
38
+ assert_breakpoint_disabled(2)
39
+ send_cont
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rd_test_base'
4
+ require 'inspect_test'
5
+
6
+ class RDInspectTest < RDTestBase
7
+
8
+ include InspectTest
9
+
10
+ end
11
+
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rd_test_base'
4
+ require 'stepping_breakpoints_test'
5
+
6
+ class RDSteppingAndBreakpointsTest < RDTestBase
7
+
8
+ include SteppingAndBreakpointsTest
9
+
10
+ def test_hit_breakpoint_while_stepping_over
11
+ create_test2 ["class Test2", "def print", "puts 'XX'", "puts 'XX'", "end", "end"]
12
+ create_socket ["require 'test2.rb'", "Test2.new.print", "puts 'a'"]
13
+ send_ruby("b #{@test2_name}:4")
14
+ assert_breakpoint_added_no(1)
15
+ run_to_line(2)
16
+ send_next
17
+ assert_breakpoint(@test2_name, 4)
18
+ send_cont
19
+ end
20
+
21
+ def test_breakpoint_and_continue_from_other_file
22
+ create_test2 ["class Test2", "def print12", "puts 'one'","puts 'two'", "end", "end"]
23
+ create_socket ["require 'test2.rb'", "Test2.new.print12", "puts 'three'"]
24
+ send_test_breakpoint(2)
25
+ assert_breakpoint_added_no(1)
26
+ send_ruby("b #{@test2_name}:4")
27
+ assert_breakpoint_added_no(2)
28
+ start_debugger
29
+ assert_test_breakpoint(2)
30
+ send_next # test:1 -> test2:4
31
+ assert_breakpoint(@test2_name, 4)
32
+ send_cont # test2:4 -> test:3
33
+ end
34
+
35
+ end
36
+
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), "..", "test-base")
4
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
5
+
6
+ require 'test_base'
7
+
8
+ class RDTestBase < TestBase
9
+
10
+ def setup
11
+ super
12
+ @rdebug_ide = config_load('rdebug_ide', true) || find_rdebug_ide
13
+ unless @rdebug_ide and File.exist?(@rdebug_ide)
14
+ @fast_fail = true
15
+ assert_not_nil(@rdebug_ide, "Cannot find rdebug-ide executable. " +
16
+ "Neither set in the config(.private).yaml nor found on the PATH")
17
+ assert(false, "#{@rdebug_ide} exist")
18
+ end
19
+ end
20
+
21
+ def debug_command(script, port)
22
+ cmd = "#{interpreter}"
23
+ cmd << " --debug" if jruby?
24
+ cmd << " -J-Xdebug -J-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y" if jruby? and debug_jruby?
25
+ cmd << " -I '#{File.dirname(script)}' #{@rdebug_ide} _0.4.9_" +
26
+ (@verbose_server ? " -d" : "") +
27
+ " -p #{port} -- '#{script}'"
28
+ end
29
+
30
+ def start_debugger
31
+ send_ruby("start")
32
+ end
33
+
34
+ private
35
+
36
+ def find_rdebug_ide
37
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
38
+ rdebug_ide = File.join(dir, 'rdebug-ide')
39
+ return rdebug_ide if File.exists?(rdebug_ide)
40
+ end
41
+ nil
42
+ end
43
+
44
+ end