byebug 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,13 @@
1
+ module Byebug
2
+
3
+ class Breakpoint
4
+
5
+ def inspect
6
+ values = %w{id pos source expr hit_condition hit_count hit_value enabled?}.map do |field|
7
+ "#{field}: #{send(field)}"
8
+ end.join(", ")
9
+ "#<Byebug::Breakpoint #{values}>"
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Byebug
2
+ class Context
3
+
4
+ def inspect
5
+ values = %w{
6
+ thread thnum stop_reason tracing ignored? stack_size dead? frame_line frame_file frame_self
7
+ }.map do |field|
8
+ "#{field}: #{send(field)}"
9
+ end.join(", ")
10
+ "#<Byebug::Context #{values}>"
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,67 @@
1
+ module MiniTest::Assertions
2
+
3
+ # This matcher checks that given collection is included into the original collection,
4
+ # and in correct order. It accepts both strings and regexps.
5
+ #
6
+ # Examples:
7
+ #
8
+ # assert_includes_in_order(%w{1 2 3 4 5}, %w{1 3 5}) # => pass
9
+ # assert_includes_in_order(%w{1 2 3 4 5}, %w{1 5 3}) # => fail
10
+ # assert_includes_in_order(w{1 2 3 4 5}, ["1", /\d+/, "5"]) # => pass
11
+ # assert_includes_in_order(w{1 2 3 4 5}, ["1", /\[a-z]+/, "5"]) # => fail
12
+ #
13
+ def assert_includes_in_order(given_collection, original_collection, msg = nil)
14
+ msg = message(msg) do
15
+ "Expected #{mu_pp(original_collection)} to include #{mu_pp(given_collection)} in order"
16
+ end
17
+ assert includes_in_order_result(original_collection, given_collection), msg
18
+ end
19
+
20
+ def refute_includes_in_order(given_collection, original_collection, msg = nil)
21
+ msg = message(msg) do
22
+ "Expected #{mu_pp(original_collection)} to not include #{mu_pp(given_collection)} in order"
23
+ end
24
+ refute includes_in_order_result(original_collection, given_collection), msg
25
+ end
26
+
27
+
28
+ private
29
+
30
+ def includes_in_order_result(original_collection, given_collection)
31
+ result = true
32
+ given_collection.each do |given_item|
33
+ result &&= case given_item
34
+ when String
35
+ index = original_collection.index(given_item)
36
+ if index
37
+ original_collection = original_collection[(index + 1)..-1]
38
+ true
39
+ else
40
+ false
41
+ end
42
+ when Regexp
43
+ index = nil
44
+ original_collection.each_with_index do |original_item, i|
45
+ if original_item =~ given_item
46
+ index = i
47
+ break
48
+ end
49
+ end
50
+ if index
51
+ original_collection = original_collection[(index + 1)..-1]
52
+ true
53
+ else
54
+ false
55
+ end
56
+ else
57
+ false
58
+ end
59
+ end
60
+ result
61
+ end
62
+ end
63
+
64
+ module MiniTest::Expectations
65
+ infect_an_assertion :assert_includes_in_order, :must_include_in_order
66
+ infect_an_assertion :refute_includes_in_order, :wont_include_in_order
67
+ end
@@ -0,0 +1,72 @@
1
+ module Mocha
2
+
3
+ class Expectation
4
+
5
+ # Allows to specify a block to execute when expectation will be matched.
6
+ # This way, we can specify dynamic values to return or just make some side effects
7
+ #
8
+ # Example:
9
+ #
10
+ # foo.expects(:bar).with('bla').calls { 2 + 3 }
11
+ # foo.bar('bla') # => 5
12
+ #
13
+ def calls(&block)
14
+ @calls ||= Call.new
15
+ @calls += Call.new(block)
16
+ self
17
+ end
18
+
19
+ def invoke_with_calls(arguments, &block)
20
+ invoke_without_calls(&block) || (@calls.next(arguments, &block) if @calls)
21
+ end
22
+ alias_method :invoke_without_calls, :invoke
23
+ alias_method :invoke, :invoke_with_calls
24
+
25
+ end
26
+
27
+ class Mock
28
+
29
+ # We monkey-patch that method to be able to pass arguments to Expectation#invoke method
30
+ def method_missing(symbol, *arguments, &block)
31
+ if @responder and not @responder.respond_to?(symbol)
32
+ raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
33
+ end
34
+ if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments)
35
+ # We change this line - added arguments
36
+ matching_expectation_allowing_invocation.invoke(arguments, &block)
37
+ else
38
+ if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
39
+ # We change this line - added arguments
40
+ matching_expectation.invoke(arguments, &block) if matching_expectation
41
+ message = UnexpectedInvocation.new(self, symbol, *arguments).to_s
42
+ require 'mocha/mockery'
43
+ message << Mockery.instance.mocha_inspect
44
+ raise ExpectationError.new(message, caller)
45
+ end
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ class Call
52
+
53
+ attr_reader :blocks
54
+
55
+ def initialize(*blocks)
56
+ @blocks = [ *blocks ]
57
+ end
58
+
59
+ def next(arguments, &block)
60
+ case @blocks.length
61
+ when 0 then nil
62
+ when 1 then @blocks.first.call(*arguments, &block)
63
+ else @blocks.shift.call(*arguments, &block)
64
+ end
65
+ end
66
+
67
+ def +(other)
68
+ self.class.new(*(@blocks + other.blocks))
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,7 @@
1
+ class Byebug::Processor
2
+ class << self
3
+ def print(message)
4
+ Byebug.handler.interface.print_queue << message
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,206 @@
1
+ module TestDsl
2
+
3
+ module Shared
4
+ def fullpath(filename)
5
+ (Pathname.new(__FILE__) + "../../examples/#{filename}.rb").cleanpath.to_s
6
+ end
7
+ end
8
+
9
+ include Shared
10
+
11
+ def self.included(base)
12
+ base.class_eval do
13
+ extend ClassMethods
14
+ before do
15
+ Byebug.interface = TestInterface.new
16
+ Byebug.handler.display.clear
17
+ end
18
+ after do
19
+ Byebug.handler.display.clear
20
+ end
21
+ end
22
+ end
23
+
24
+ # Adds commands to the input queue, so they will be later retrieved by
25
+ # Processor, i.e. it emulates user's input.
26
+ #
27
+ # If a command is a Proc object, it will be executed before retrieving by
28
+ # Processor. May be handy when you need build a command depending on the
29
+ # current context/state.
30
+ #
31
+ # Usage:
32
+ # enter 'b 12'
33
+ # enter 'b 12', 'cont'
34
+ # enter ['b 12', 'cont']
35
+ # enter 'b 12', ->{"disable #{breakpoint.id}"}, 'cont'
36
+ #
37
+ def enter(*messages)
38
+ messages = messages.first.is_a?(Array) ? messages.first : messages
39
+ interface.input_queue.concat(messages)
40
+ end
41
+
42
+ # Runs a byebug with the provided basename for a file. The file should be
43
+ # placed in the test/examples dir.
44
+ #
45
+ # You also can specify a block, which will be executed when Processor extracts
46
+ # all the commands from the input queue. You can use it e.g. for making
47
+ # asserts for the current test. If you specified the block, and it never was
48
+ # executed, the test will fail.
49
+ #
50
+ # Usage:
51
+ # debug "ex1" # ex1 should be placed in test/examples/ex1.rb
52
+ #
53
+ # enter 'b 4', 'cont'
54
+ # debug("ex1") { state.line.must_equal 4 }
55
+ #
56
+ def debug_file(filename, &block)
57
+ is_test_block_called = false
58
+ debug_completed = false
59
+ exception = nil
60
+ Byebug.stubs(:run_init_script)
61
+ if block
62
+ interface.test_block= lambda do
63
+ is_test_block_called = true
64
+ # We need to store exception and reraise it after completing debugging,
65
+ # because Byebug will swallow any exceptions, so e.g. our failed
66
+ # assertions will be ignored
67
+ begin
68
+ block.call
69
+ rescue Exception => e
70
+ exception = e
71
+ raise e
72
+ end
73
+ end
74
+ end
75
+ Byebug.start do
76
+ load fullpath(filename)
77
+ debug_completed = true
78
+ end
79
+ flunk "Debug block was not completed" unless debug_completed
80
+ flunk "Test block was provided, but not called" if block && !is_test_block_called
81
+ raise exception if exception
82
+ end
83
+
84
+ #
85
+ # Checks the output of byebug. By default it checks output queue of the current
86
+ # interface, but you can check again any queue by providing it as a second
87
+ # argument.
88
+ #
89
+ # Usage:
90
+ # enter 'break 4', 'cont'
91
+ # debug("ex1")
92
+ # check_output "Breakpoint 1 at #{fullpath('ex1')}:4"
93
+ #
94
+ def check_output(check_method, *args)
95
+ queue = args.last.is_a?(String) || args.last.is_a?(Regexp) ? interface.output_queue : args.pop
96
+ queue_messages = queue.map(&:strip)
97
+ messages = Array(args).map { |msg| msg.is_a?(String) ? msg.strip : msg }
98
+ queue_messages.send(check_method, messages)
99
+ end
100
+
101
+ def check_output_includes(*args)
102
+ check_output :must_include_in_order, *args
103
+ end
104
+
105
+ def check_output_doesnt_include(*args)
106
+ check_output :wont_include_in_order, *args
107
+ end
108
+
109
+ def interface
110
+ Byebug.handler.interface
111
+ end
112
+
113
+ def state
114
+ $rdebug_state
115
+ end
116
+
117
+ def context
118
+ state.context
119
+ end
120
+
121
+ def breakpoint
122
+ Byebug.breakpoints.first
123
+ end
124
+
125
+ def force_set_const(klass, const, value)
126
+ klass.send(:remove_const, const) if klass.const_defined?(const)
127
+ klass.const_set(const, value)
128
+ end
129
+
130
+ def change_line_in_file(file, line, new_line_content)
131
+ old_content = File.read(file)
132
+ new_content = old_content.split("\n").tap { |c| c[line - 1] = new_line_content }.join("\n")
133
+ File.open(file, 'w') { |f| f.write(new_content) }
134
+ end
135
+
136
+ def temporary_change_method_value(item, method, value)
137
+ old = item.send(method)
138
+ item.send("#{method}=", value)
139
+ yield
140
+ ensure
141
+ item.send("#{method}=", old)
142
+ end
143
+
144
+ def temporary_change_hash_value(item, key, value)
145
+ old_value = item[key]
146
+ item[key] = value
147
+ yield
148
+ ensure
149
+ item[key] = old_value
150
+ end
151
+
152
+ def temporary_set_const(klass, const, value)
153
+ old_value = klass.const_defined?(const) ? klass.const_get(const) : :__undefined__
154
+ force_set_const(klass, const, value)
155
+ yield
156
+ ensure
157
+ if old_value == :__undefined__
158
+ klass.send(:remove_const, const)
159
+ else
160
+ force_set_const(klass, const, old_value)
161
+ end
162
+ end
163
+
164
+ module ClassMethods
165
+
166
+ include Shared
167
+
168
+ def temporary_change_method_value(item, method, value)
169
+ old_value = nil
170
+ before do
171
+ old_value = item.send(method)
172
+ item.send("#{method}=", value)
173
+ end
174
+ after do
175
+ item.send("#{method}=", old_value)
176
+ end
177
+ end
178
+
179
+ def temporary_change_hash_value(item, key, value)
180
+ old_value = nil
181
+ before do
182
+ old_value = item[key]
183
+ item[key] = value
184
+ end
185
+ after do
186
+ item[key] = old_value
187
+ end
188
+ end
189
+
190
+ def temporary_set_const(klass, const, value)
191
+ old_value = nil
192
+ before do
193
+ old_value = klass.const_defined?(const) ? klass.const_get(const) : :__undefined__
194
+ force_set_const(klass, const, value)
195
+ end
196
+ after do
197
+ if old_value == :__undefined__
198
+ klass.send(:remove_const, const)
199
+ else
200
+ force_set_const(klass, const, old_value)
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ end
@@ -0,0 +1,68 @@
1
+ class TestInterface < Byebug::Interface
2
+ attr_reader :input_queue, :output_queue, :error_queue, :confirm_queue
3
+
4
+ attr_accessor :command_queue, :histfile, :history_length, :history_save
5
+ attr_accessor :print_queue, :readline_support, :restart_file, :test_block
6
+
7
+ def initialize
8
+ @input_queue = []
9
+ @output_queue = []
10
+ @error_queue = []
11
+ @confirm_queue = []
12
+ @command_queue = []
13
+ @print_queue = []
14
+ @readline_support = false
15
+ end
16
+
17
+ def errmsg(*args)
18
+ @error_queue << format(args)
19
+ end
20
+
21
+ def read_command(*args)
22
+ if @input_queue.empty? && test_block
23
+ test_block.call
24
+ self.test_block = nil
25
+ end
26
+ result = @input_queue.shift
27
+ result.is_a?(Proc) ? result.call : result
28
+ end
29
+
30
+ def print(*args)
31
+ @output_queue << format(args)
32
+ end
33
+
34
+ def confirm(message)
35
+ @confirm_queue << message
36
+ read_command message
37
+ end
38
+
39
+ def readline_support?
40
+ @readline_support
41
+ end
42
+
43
+ def finalize
44
+ end
45
+
46
+ def close
47
+ end
48
+
49
+ def inspect
50
+ [
51
+ "input_queue: #{input_queue.inspect}",
52
+ "output_queue: #{output_queue.inspect}",
53
+ "error_queue: #{error_queue.inspect}",
54
+ "confirm_queue: #{confirm_queue.inspect}",
55
+ "print_queue: #{print_queue.inspect}"
56
+ ].join("\n")
57
+ end
58
+
59
+ private
60
+
61
+ def format(args)
62
+ if args.size > 1
63
+ args.first % args[1..-1]
64
+ else
65
+ args.first
66
+ end
67
+ end
68
+ end