debugger-xml 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 (73) hide show
  1. data/.gitignore +20 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +24 -0
  5. data/Rakefile +10 -0
  6. data/bin/rdebug-ide +90 -0
  7. data/debugger-xml.gemspec +25 -0
  8. data/lib/debugger/printers/texts/xml.yml +121 -0
  9. data/lib/debugger/printers/xml.rb +195 -0
  10. data/lib/debugger/xml.rb +3 -0
  11. data/lib/debugger/xml/extensions/commands/edit.rb +13 -0
  12. data/lib/debugger/xml/extensions/commands/frame.rb +14 -0
  13. data/lib/debugger/xml/extensions/commands/help.rb +13 -0
  14. data/lib/debugger/xml/extensions/commands/info.rb +13 -0
  15. data/lib/debugger/xml/extensions/commands/irb.rb +13 -0
  16. data/lib/debugger/xml/extensions/commands/kill.rb +13 -0
  17. data/lib/debugger/xml/extensions/commands/tmate.rb +13 -0
  18. data/lib/debugger/xml/extensions/commands/trace.rb +13 -0
  19. data/lib/debugger/xml/extensions/commands/variables.rb +16 -0
  20. data/lib/debugger/xml/extensions/debugger.rb +28 -0
  21. data/lib/debugger/xml/extensions/processor.rb +9 -0
  22. data/lib/debugger/xml/ide_processor.rb +149 -0
  23. data/lib/debugger/xml/interface.rb +65 -0
  24. data/lib/debugger/xml/version.rb +5 -0
  25. data/test/breakpoints_test.rb +190 -0
  26. data/test/conditions_test.rb +32 -0
  27. data/test/continue_test.rb +12 -0
  28. data/test/display_test.rb +25 -0
  29. data/test/edit_test.rb +12 -0
  30. data/test/eval_test.rb +20 -0
  31. data/test/examples/breakpoint1.rb +15 -0
  32. data/test/examples/breakpoint2.rb +7 -0
  33. data/test/examples/conditions.rb +4 -0
  34. data/test/examples/continue.rb +4 -0
  35. data/test/examples/display.rb +5 -0
  36. data/test/examples/edit.rb +3 -0
  37. data/test/examples/eval.rb +4 -0
  38. data/test/examples/frame.rb +31 -0
  39. data/test/examples/help.rb +2 -0
  40. data/test/examples/info.rb +48 -0
  41. data/test/examples/irb.rb +6 -0
  42. data/test/examples/jump.rb +14 -0
  43. data/test/examples/kill.rb +2 -0
  44. data/test/examples/method.rb +15 -0
  45. data/test/examples/reload.rb +6 -0
  46. data/test/examples/restart.rb +6 -0
  47. data/test/examples/set.rb +3 -0
  48. data/test/examples/stepping.rb +21 -0
  49. data/test/examples/thread.rb +32 -0
  50. data/test/examples/tmate.rb +10 -0
  51. data/test/examples/trace.rb +7 -0
  52. data/test/examples/variables.rb +26 -0
  53. data/test/examples/variables_xml.rb +31 -0
  54. data/test/frame_test.rb +29 -0
  55. data/test/help_test.rb +13 -0
  56. data/test/ide_control_command_processor_test.rb +62 -0
  57. data/test/ide_processor_test.rb +118 -0
  58. data/test/info_test.rb +12 -0
  59. data/test/irb_test.rb +12 -0
  60. data/test/jump_test.rb +22 -0
  61. data/test/kill_test.rb +13 -0
  62. data/test/method_test.rb +36 -0
  63. data/test/printers/xml_test.rb +193 -0
  64. data/test/reload_test.rb +14 -0
  65. data/test/restart_test.rb +50 -0
  66. data/test/set_test.rb +12 -0
  67. data/test/stepping_test.rb +15 -0
  68. data/test/test_helper.rb +6 -0
  69. data/test/thread_test.rb +20 -0
  70. data/test/tmate_test.rb +15 -0
  71. data/test/trace_test.rb +12 -0
  72. data/test/variables_test.rb +84 -0
  73. metadata +253 -0
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ .rvmrc
20
+ vendor/bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in debugger-xml.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Anton Astashov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ ## Description
2
+
3
+ This is a gem, which adds the XML printer to the 'debugger' gem, using the same API as
4
+ the ruby-debug-ide gem, which allows it to be used with Ruby IDEs (for example, in my
5
+ vim-ruby-debugger :))
6
+
7
+ ## Installation
8
+
9
+ As usual, add it to your Gemfile, and you are all set
10
+
11
+ gem 'debugger-xml'
12
+
13
+ ## Usage
14
+
15
+ There is the the bin/rdebug-ide file, check it out. For description of XML API,
16
+ check http://debug-commons.rubyforge.org/protocol-spec.html, I tried to be
17
+ compatible with it
18
+
19
+ ## Tests
20
+
21
+ It uses debugger/test helpers. To run all tests, just do
22
+
23
+ rake test
24
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ desc "Run tests."
5
+ task :test do
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.test_files = FileList["test/*_test.rb"]
8
+ t.verbose = true
9
+ end
10
+ end
data/bin/rdebug-ide ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
4
+ require 'optparse'
5
+ require 'ostruct'
6
+ require 'debugger'
7
+ require 'ruby-debug/ide_processor'
8
+
9
+ $stdout.sync = true
10
+
11
+ class RdebugIde
12
+
13
+ def initialize
14
+ check_argv!
15
+ Debugger.const_set("ARGV", ARGV.clone)
16
+ Debugger.const_set("RDEBUG_SCRIPT", rdebug_path)
17
+ install_interruption_hander
18
+ Debugger.tracing = options.tracing
19
+ Debugger.wait_for_start = options.wait_for_start
20
+ Debugger.wait_connection = true
21
+ Debugger.printer = Printers::Xml.new
22
+ Debugger.const_set("PROG_SCRIPT", ARGV.shift)
23
+ end
24
+
25
+ def run
26
+ Debugger.start_remote_ide(options.host, options.port)
27
+ bt = Debugger.debug_load(Debugger::PROG_SCRIPT, false, false)
28
+ if bt
29
+ print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n"
30
+ print "Uncaught exception: #{bt}\n"
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def check_argv!
37
+ if ARGV.empty?
38
+ puts opts
39
+ puts
40
+ puts "Must specify a script to run"
41
+ exit(1)
42
+ end
43
+ end
44
+
45
+ def install_interruption_hander
46
+ trap('INT') { Debugger.interrupt_last }
47
+ end
48
+
49
+ def rdebug_path
50
+ File.expand_path($0).tap do |path|
51
+ if RUBY_PLATFORM =~ /mswin/
52
+ rdebug_path << ".cmd" unless rdebug_path =~ /\.cmd$/i
53
+ end
54
+ end
55
+ end
56
+
57
+ def options
58
+ opts
59
+ @options
60
+ end
61
+
62
+ def opts
63
+ @opts ||= begin
64
+ @options = OpenStruct.new(host: "127.0.0.1", port: 12345, stop: false, tracing: false, wait_for_start: true)
65
+ opts = OptionParser.new do |opts|
66
+ opts.banner = %{
67
+ Using rdebug-ide
68
+ Usage: rdebug-ide is supposed to be called from RDT, NetBeans, RubyMine or
69
+ vim-ruby-debugger. The command line interface to 'debugger' is rdebug.
70
+ }.gsub(/^\s*/, '')
71
+ opts.separator ""
72
+ opts.separator "Options:"
73
+ opts.on("-h", "--host HOST", "Host name used for remote debugging") { |host| @options.host = host }
74
+ opts.on("--cport PORT", Integer, "Port used for control commands") { |cport| @options.cport = cport }
75
+ opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") { |port| @options.port = port }
76
+ opts.on("--wait", String, "Wait for 'start' command") do |bool|
77
+ @options.wait_for_start = (bool == "false" ? false : true)
78
+ end
79
+ opts.on('--stop', 'stop when the script is loaded') { @options.stop = true }
80
+ opts.on("-x", "--trace", "turn on line tracing") { @options.tracing = true }
81
+ opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") { |path| $LOAD_PATH.unshift(path) }
82
+ end
83
+ opts.parse!
84
+ opts
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ RdebugIde.new.run
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'debugger/xml/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "debugger-xml"
8
+ gem.version = Debugger::Xml::VERSION
9
+ gem.authors = ["Anton Astashov"]
10
+ gem.email = ["anton.astashov@gmail.com"]
11
+ gem.description = %q{XML interface for debugger}
12
+ gem.summary = %q{Implements XML interface for the 'debugger' gem, compatible with ruby-debug-ide gem}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "debugger", '>= 1.5.0'
21
+ gem.add_dependency 'builder', '>= 2.0.0'
22
+ gem.add_development_dependency 'rake', '~> 0.9.2.2'
23
+ gem.add_development_dependency 'minitest', '~> 2.12.1'
24
+ gem.add_development_dependency 'mocha', '~> 0.13.0'
25
+ end
@@ -0,0 +1,121 @@
1
+ general:
2
+ errors:
3
+ unsupported: "Unsupported command '{cmd}'"
4
+
5
+ breakpoints:
6
+ set_breakpoint_to_line:
7
+ tag: breakpointAdded
8
+ attributes:
9
+ "no": "{id}"
10
+ location: "{file}:{line}"
11
+ set_breakpoint_to_method:
12
+ tag: breakpointAdded
13
+ attributes:
14
+ "no": "{id}"
15
+ method: "{class}::{method}"
16
+ stop_at_breakpoint:
17
+ tag: breakpoint
18
+ attributes:
19
+ file: "{file}"
20
+ line: "{line}"
21
+ threadId: "{thread_id}"
22
+ delete:
23
+ tag: breakpointDeleted
24
+ attributes:
25
+ "no": "{id}"
26
+
27
+ conditions:
28
+ set_condition:
29
+ tag: conditionSet
30
+ attributes:
31
+ bp_id: "{id}"
32
+ unset_condition:
33
+ tag: conditionSet # Would ideally be conditionUnset, but we keep compatibility with old ruby-debug-ide
34
+ attributes:
35
+ bp_id: "{id}"
36
+
37
+ display:
38
+ result:
39
+ tag: display
40
+ attributes:
41
+ key: "{exp}"
42
+ value: "{result}"
43
+
44
+ eval:
45
+ exception:
46
+ tag: processingException
47
+ attributes:
48
+ type: "{class}"
49
+ message: "{value}"
50
+ result:
51
+ tag: eval
52
+ attributes:
53
+ expression: "{expr}"
54
+ value: "{result}"
55
+
56
+ frame:
57
+ line:
58
+ tag: frame
59
+ attributes:
60
+ "no": "{pos}"
61
+ file: "{file}"
62
+ line: "{line}"
63
+ current: "{mark}"
64
+
65
+ method:
66
+ methods:
67
+ tag: method
68
+ attributes:
69
+ name: "{name}"
70
+
71
+ stop:
72
+ suspend:
73
+ tag: suspended
74
+ attributes:
75
+ file: "{file}"
76
+ line: "{line_number}"
77
+ threadId: "{thnum}"
78
+ frames: "{frames}"
79
+
80
+ toggle:
81
+ breakpoint_enabled:
82
+ tag: breakpointEnabled
83
+ attributes:
84
+ bp_id: "{id}"
85
+ breakpoint_disabled:
86
+ tag: breakpointDisabled
87
+ attributes:
88
+ bp_id: "{id}"
89
+
90
+ restart:
91
+ success:
92
+ tag: restart
93
+ attributes:
94
+ command: "{cmd}"
95
+
96
+ set:
97
+ errors:
98
+ no_subcommand: "'set' must be followed by the name of a subcommand"
99
+
100
+ show:
101
+ errors:
102
+ no_subcommand: "'show' must be followed by the name of a subcommand"
103
+
104
+ thread:
105
+ context:
106
+ tag: thread
107
+ attributes:
108
+ id: "{id}"
109
+ status: "{status}"
110
+ current: "{current}"
111
+
112
+ variable:
113
+ variable:
114
+ tag: variable
115
+ attributes:
116
+ name: "{name}"
117
+ kind: "{kind}"
118
+ value: "{value}"
119
+ type: "{type}"
120
+ hasChildren: "{has_children}"
121
+ objectId: "{id}"
@@ -0,0 +1,195 @@
1
+ require 'ruby-debug/printers/base'
2
+ require 'builder'
3
+
4
+ module Printers
5
+ class Xml < Base
6
+
7
+ def print(path, args = {})
8
+ case parts(path)[1]
9
+ when "errors"
10
+ print_error(path, args)
11
+ when "confirmations"
12
+ print_confirmation(path, args)
13
+ when "debug"
14
+ print_debug(path, args)
15
+ when "messages"
16
+ print_message(path, args)
17
+ else
18
+ print_general(path, args)
19
+ end
20
+ end
21
+
22
+ def print_collection(path, collection, &block)
23
+ settings = locate(path)
24
+ xml = ::Builder::XmlMarkup.new
25
+ tag = translate(settings["tag"])
26
+ xml.tag!("#{tag}s") do |xml|
27
+ array_of_args(collection, &block).each do |args|
28
+ xml.tag!(tag, translated_attributes(settings["attributes"], args))
29
+ end
30
+ end
31
+ end
32
+
33
+ def print_variables(variables, global_kind)
34
+ print_collection("variable.variable", variables) do |(key, value, kind), index|
35
+ Variable.new(key, value, kind || global_kind).to_hash
36
+ end
37
+ end
38
+
39
+ def print_instance_variables(object)
40
+ variables = if object.is_a?(Array)
41
+ object.each.with_index.map { |item, index| ["[#{index}]", item, 'instance'] }
42
+ elsif object.is_a?(Hash)
43
+ object.map { |key, value| [key.is_a?(String) ? "'#{key}'" : key.to_s, value, 'instance'] }
44
+ else
45
+ AllVariables.new(object).variables
46
+ end
47
+ print_variables(variables, nil)
48
+ end
49
+
50
+ private
51
+
52
+ def print_general(path, args)
53
+ settings = locate(path)
54
+ xml = ::Builder::XmlMarkup.new
55
+ tag = translate(settings["tag"], args)
56
+ attributes = translated_attributes(settings["attributes"], args)
57
+ xml.tag!(tag, attributes)
58
+ end
59
+
60
+ def print_debug(path, args)
61
+ translate(locate(path), args)
62
+ end
63
+
64
+ def print_error(path, args)
65
+ xml = ::Builder::XmlMarkup.new
66
+ xml.error { print_content(xml, path, args) }
67
+ end
68
+
69
+ def print_confirmation(path, args)
70
+ xml = ::Builder::XmlMarkup.new
71
+ xml.confirmation { print_content(xml, path, args) }
72
+ end
73
+
74
+ def print_message(path, args)
75
+ xml = ::Builder::XmlMarkup.new
76
+ xml.message { print_content(xml, path, args) }
77
+ end
78
+
79
+ def print_content(xml, path, args)
80
+ xml.text!(translate(locate(path), args))
81
+ end
82
+
83
+ def translated_attributes(attributes, args)
84
+ attributes.inject({}) do |hash, (key, value)|
85
+ hash[key] = translate(value, args)
86
+ hash
87
+ end
88
+ end
89
+
90
+ def contents_files
91
+ [File.expand_path(File.join("..", "texts", "xml.yml"), __FILE__)] + super
92
+ end
93
+
94
+ class Variable
95
+ attr_reader :name, :kind
96
+ def initialize(name, value, kind = nil)
97
+ @name = name.to_s
98
+ @value = value
99
+ @kind = kind
100
+ end
101
+
102
+ def has_children?
103
+ if @value.is_a?(Array) || @value.is_a?(Hash)
104
+ !@value.empty?
105
+ else
106
+ !@value.instance_variables.empty? || !@value.class.class_variables.empty?
107
+ end
108
+ rescue
109
+ false
110
+ end
111
+
112
+ def value
113
+ if @value.is_a?(Array) || @value.is_a?(Hash)
114
+ if has_children?
115
+ "#{@value.class} (#{@value.size} element(s))"
116
+ else
117
+ "Empty #{@value.class}"
118
+ end
119
+ else
120
+ value_str = @value.nil? ? 'nil' : @value.to_s
121
+ if !value_str.is_a?(String)
122
+ "ERROR: #{@value.class}.to_s method returns #{value_str.class}. Should return String."
123
+ elsif binary_data?(value_str)
124
+ "[Binary Data]"
125
+ else
126
+ value_str.gsub(/^(")(.*)(")$/, '\2')
127
+ end
128
+ end
129
+ rescue => e
130
+ "<raised exception: #{e}>"
131
+ end
132
+
133
+ def id
134
+ @value.respond_to?(:object_id) ? "%#+x" % @value.object_id : nil
135
+ rescue
136
+ nil
137
+ end
138
+
139
+ def type
140
+ @value.class
141
+ rescue
142
+ "Undefined"
143
+ end
144
+
145
+ def to_hash
146
+ {name: @name, kind: @kind, value: value, type: type, has_children: has_children?, id: id}
147
+ end
148
+
149
+ private
150
+
151
+ def binary_data?(string)
152
+ string.count("\x00-\x7F", "^ -~\t\r\n").fdiv(string.size) > 0.3 || string.index("\x00") unless string.empty?
153
+ end
154
+ end
155
+
156
+ class AllVariables
157
+ def initialize(object)
158
+ @object = object
159
+ @instance_binding = object.instance_eval{binding()}
160
+ @class_binding = object.class.class_eval('binding()')
161
+
162
+ @instance_variable_names = object.instance_variables
163
+ @self_variable_name = @instance_variable_names.delete('self')
164
+ @class_variable_names = object.class.class_variables
165
+ end
166
+
167
+ def variables
168
+ self_variables + instance_variables + class_variables
169
+ end
170
+
171
+ private
172
+
173
+ def instance_variables
174
+ @instance_variable_names.map do |var|
175
+ [var.to_s, (eval(var.to_s, @instance_binding) rescue "<raised exception>"), 'instance']
176
+ end
177
+ end
178
+
179
+ def self_variables
180
+ if @self_variable_name
181
+ [@self_variable_name, (eval(@self_variable_name, @instance_binding)), 'instance']
182
+ else
183
+ []
184
+ end
185
+ end
186
+
187
+ def class_variables
188
+ @class_variable_names.map do |var|
189
+ [var.to_s, (eval(var.to_s, @class_binding) rescue "<raised exception>"), 'class']
190
+ end
191
+ end
192
+ end
193
+
194
+ end
195
+ end