Skip to content
This repository
Browse code

Fixed some breakpoint issues and made breakpoint_client depend on act…

…iverecord/support instead of duplicating the files in railties #441 [Florian Gross]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@424 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit c46e390920950f273bdfc1c664f5e672f59e3a21 1 parent fb13b7a
David Heinemeier Hansson authored January 15, 2005
59  activesupport/lib/breakpoint.rb
@@ -21,6 +21,9 @@
21 21
 require 'drb/acl'
22 22
 
23 23
 module Breakpoint
  24
+  id = %q$Id$
  25
+  Version = id.split(" ")[2].to_i
  26
+  
24 27
   extend self
25 28
 
26 29
   # This will pop up an interactive ruby session at a
@@ -133,15 +136,24 @@ def eval(code)
133 136
       end
134 137
 
135 138
       # Will execute the specified statement at the client.
136  
-      def method_missing(method, *args)
137  
-        if args.empty?
138  
-          result = eval("#{method}")
  139
+      def method_missing(method, *args, &block)
  140
+        if args.empty? and not block
  141
+          result = eval "#{method}"
139 142
         else
140 143
           result = eval("#{method}(*Marshal.load(#{Marshal.dump(args).inspect}))")
141  
-        end
142  
-
143  
-        unless [true, false, nil].include?(result)
144  
-          result.extend(DRbUndumped) if result
  144
+          # This is a bit ugly. The alternative would be using an
  145
+          # eval context instead of an eval handler for executing
  146
+          # the code at the client. The problem with that approach
  147
+          # is that we would have to handle special expressions
  148
+          # like "self", "nil" or constants ourself which is hard.
  149
+          remote = eval %{
  150
+            result = lambda { |block, *args| #{method}(*args, &block) }
  151
+            def result.call_with_block(*args, &block)
  152
+              call(block, *args)
  153
+            end
  154
+            result
  155
+          }
  156
+          remote.call_with_block(*args, &block)
145 157
         end
146 158
 
147 159
         return result
@@ -175,6 +187,7 @@ def source_lines(context = 5, return_line_numbers = false)
175 187
     #   client.File.open("temp.txt", "w") { |f| f.puts "Hello" } 
176 188
     def client()
177 189
       if Breakpoint.use_drb? then
  190
+        sleep(0.5) until Breakpoint.drb_service.eval_handler
178 191
         Client.new(Breakpoint.drb_service.eval_handler)
179 192
       else
180 193
         Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
@@ -279,7 +292,7 @@ def collision
279 292
       @collision_handler.call
280 293
     end
281 294
 
282  
-    def ping; end
  295
+    def ping() end
283 296
 
284 297
     def add_breakpoint(context, message)
285 298
       workspace = IRB::WorkSpace.new(context)
@@ -290,31 +303,7 @@ def add_breakpoint(context, message)
290 303
       @handler.call(workspace, message)
291 304
     end
292 305
 
293  
-    def register_handler(&block)
294  
-      @handler = block
295  
-    end
296  
-
297  
-    def unregister_handler
298  
-      @handler = nil
299  
-    end
300  
-
301  
-    attr_reader :eval_handler
302  
-
303  
-    def register_eval_handler(&block)
304  
-      @eval_handler = block
305  
-    end
306  
-
307  
-    def unregister_eval_handler
308  
-      @eval_handler = lambda { }
309  
-    end
310  
-
311  
-    def register_collision_handler(&block)
312  
-      @collision_handler = block
313  
-    end
314  
-
315  
-    def unregister_collision_handler
316  
-      @collision_handler = lambda { }
317  
-    end
  306
+    attr_accessor :handler, :eval_handler, :collision_handler
318 307
   end
319 308
 
320 309
   # Will run Breakpoint in DRb mode. This will spawn a server
@@ -507,8 +496,8 @@ def self.eval(code, context, *more)
507 496
 
508 497
 module DRb # :nodoc:
509 498
   class DRbObject#:nodoc:
510  
-    undef :inspect
511  
-    undef :clone
  499
+    undef :inspect if method_defined?(:inspect)
  500
+    undef :clone if method_defined?(:clone)
512 501
   end
513 502
 end
514 503
 
1  railties/bin/breakpointer
... ...
@@ -1,3 +1,4 @@
1 1
 #!/usr/local/bin/ruby
2 2
 $LOAD_PATH << File.dirname(__FILE__) + '/../vendor/railties/lib'
  3
+$LOAD_PATH << File.dirname(__FILE__) + '/../vendor/activerecord/lib/support'
3 4
 require 'breakpoint_client'
81  railties/lib/binding_of_caller.rb
... ...
@@ -1,81 +0,0 @@
1  
-begin
2  
-  require 'simplecc'
3  
-rescue LoadError
4  
-  def Continuation.create(*args, &block)
5  
-    cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
6  
-    result ||= args
7  
-    return *[cc, *result]
8  
-  end
9  
-end
10  
-
11  
-# This method returns the binding of the method that called your
12  
-# method. It will raise an Exception when you're not inside a method.
13  
-#
14  
-# It's used like this:
15  
-#   def inc_counter(amount = 1)
16  
-#     Binding.of_caller do |binding|
17  
-#       # Create a lambda that will increase the variable 'counter'
18  
-#       # in the caller of this method when called.
19  
-#       inc = eval("lambda { |arg| counter += arg }", binding)
20  
-#       # We can refer to amount from inside this block safely.
21  
-#       inc.call(amount)
22  
-#     end
23  
-#     # No other statements can go here. Put them inside the block.
24  
-#   end
25  
-#   counter = 0
26  
-#   2.times { inc_counter }
27  
-#   counter # => 2
28  
-#
29  
-# Binding.of_caller must be the last statement in the method.
30  
-# This means that you will have to put everything you want to
31  
-# do after the call to Binding.of_caller into the block of it.
32  
-# This should be no problem however, because Ruby has closures.
33  
-# If you don't do this an Exception will be raised. Because of
34  
-# the way that Binding.of_caller is implemented it has to be
35  
-# done this way.
36  
-def Binding.of_caller(&block)
37  
-  old_critical = Thread.critical
38  
-  Thread.critical = true
39  
-  count = 0
40  
-  cc, result, error, extra_data = Continuation.create(nil, nil)
41  
-  error.call if error
42  
-
43  
-  tracer = lambda do |*args|
44  
-    type, context, extra_data = args[0], args[4], args
45  
-    if type == "return"
46  
-      count += 1
47  
-      # First this method and then calling one will return --
48  
-      # the trace event of the second event gets the context
49  
-      # of the method which called the method that called this
50  
-      # method.
51  
-      if count == 2
52  
-        # It would be nice if we could restore the trace_func
53  
-        # that was set before we swapped in our own one, but
54  
-        # this is impossible without overloading set_trace_func
55  
-        # in current Ruby.
56  
-        set_trace_func(nil)
57  
-        cc.call(eval("binding", context), nil, extra_data)
58  
-      end
59  
-    elsif type == "line" then
60  
-      nil
61  
-    elsif type == "c-return" and extra_data[3] == :set_trace_func then
62  
-      nil
63  
-    else
64  
-      set_trace_func(nil)
65  
-      error_msg = "Binding.of_caller used in non-method context or " +
66  
-        "trailing statements of method using it aren't in the block."
67  
-      cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
68  
-    end
69  
-  end
70  
-
71  
-  unless result
72  
-    set_trace_func(tracer)
73  
-    return nil
74  
-  else
75  
-    Thread.critical = old_critical
76  
-    case block.arity
77  
-      when 1 then yield(result)
78  
-      else yield(result, extra_data)        
79  
-    end
80  
-  end
81  
-end
525  railties/lib/breakpoint.rb
... ...
@@ -1,525 +0,0 @@
1  
-# The Breakpoint library provides the convenience of
2  
-# being able to inspect and modify state, diagnose
3  
-# bugs all via IRB by simply setting breakpoints in
4  
-# your applications by the call of a method.
5  
-#
6  
-# This library was written and is supported by me,
7  
-# Florian Gross. I can be reached at flgr@ccan.de
8  
-# and enjoy getting feedback about my libraries.
9  
-#
10  
-# The whole library (including breakpoint_client.rb
11  
-# and binding_of_caller.rb) is licensed under the
12  
-# same license that Ruby uses. (Which is currently
13  
-# either the GNU General Public License or a custom
14  
-# one that allows for commercial usage.) If you for
15  
-# some good reason need to use this under another
16  
-# license please contact me.
17  
-
18  
-require 'irb'
19  
-require 'binding_of_caller'
20  
-require 'drb'
21  
-require 'drb/acl'
22  
-
23  
-module Breakpoint
24  
-  extend self
25  
-
26  
-  # This will pop up an interactive ruby session at a
27  
-  # pre-defined break point in a Ruby application. In
28  
-  # this session you can examine the environment of
29  
-  # the break point.
30  
-  #
31  
-  # You can get a list of variables in the context using
32  
-  # local_variables via +local_variables+. You can then
33  
-  # examine their values by typing their names.
34  
-  #
35  
-  # You can have a look at the call stack via +caller+.
36  
-  #
37  
-  # The source code around the location where the breakpoint
38  
-  # was executed can be examined via +source_lines+. Its
39  
-  # argument specifies how much lines of context to display.
40  
-  # The default amount of context is 5 lines. Note that
41  
-  # the call to +source_lines+ can raise an exception when
42  
-  # it isn't able to read in the source code.
43  
-  #
44  
-  # breakpoints can also return a value. They will execute
45  
-  # a supplied block for getting a default return value.
46  
-  # A custom value can be returned from the session by doing
47  
-  # +throw(:debug_return, value)+.
48  
-  #
49  
-  # You can also give names to break points which will be
50  
-  # used in the message that is displayed upon execution 
51  
-  # of them.
52  
-  #
53  
-  # Here's a sample of how breakpoints should be placed:
54  
-  #
55  
-  #   class Person
56  
-  #     def initialize(name, age)
57  
-  #       @name, @age = name, age
58  
-  #       breakpoint("Person#initialize")
59  
-  #     end
60  
-  #
61  
-  #     attr_reader :age
62  
-  #     def name
63  
-  #       breakpoint("Person#name") { @name }
64  
-  #     end
65  
-  #   end
66  
-  #
67  
-  #   person = Person.new("Random Person", 23)
68  
-  #   puts "Name: #{person.name}"
69  
-  #
70  
-  # And here is a sample debug session:
71  
-  #
72  
-  #   Executing break point "Person#initialize" at file.rb:4 in `initialize'
73  
-  #   irb(#<Person:0x292fbe8>):001:0> local_variables
74  
-  #   => ["name", "age", "_", "__"]
75  
-  #   irb(#<Person:0x292fbe8>):002:0> [name, age]
76  
-  #   => ["Random Person", 23]
77  
-  #   irb(#<Person:0x292fbe8>):003:0> [@name, @age]
78  
-  #   => ["Random Person", 23]
79  
-  #   irb(#<Person:0x292fbe8>):004:0> self
80  
-  #   => #<Person:0x292fbe8 @age=23, @name="Random Person">
81  
-  #   irb(#<Person:0x292fbe8>):005:0> @age += 1; self
82  
-  #   => #<Person:0x292fbe8 @age=24, @name="Random Person">
83  
-  #   irb(#<Person:0x292fbe8>):006:0> exit
84  
-  #   Executing break point "Person#name" at file.rb:9 in `name'
85  
-  #   irb(#<Person:0x292fbe8>):001:0> throw(:debug_return, "Overriden name")
86  
-  #   Name: Overriden name
87  
-  #
88  
-  # Breakpoint sessions will automatically have a few
89  
-  # convenience methods available. See Breakpoint::CommandBundle
90  
-  # for a list of them.
91  
-  #
92  
-  # Breakpoints can also be used remotely over sockets.
93  
-  # This is implemented by running part of the IRB session
94  
-  # in the application and part of it in a special client.
95  
-  # You have to call Breakpoint.activate_drb to enable
96  
-  # support for remote breakpoints and then run
97  
-  # breakpoint_client.rb which is distributed with this
98  
-  # library. See the documentation of Breakpoint.activate_drb
99  
-  # for details.
100  
-  def breakpoint(id = nil, context = nil, &block)
101  
-    callstack = caller
102  
-    callstack.slice!(0, 3) if callstack.first["breakpoint"]
103  
-    file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
104  
-
105  
-    message = "Executing break point " + (id ? "#{id.inspect} " : "") +
106  
-              "at #{file}:#{line}" + (method ? " in `#{method}'" : "")
107  
-
108  
-    if context then
109  
-      return handle_breakpoint(context, message, file, line, &block)
110  
-    end
111  
-
112  
-    Binding.of_caller do |binding_context|
113  
-      handle_breakpoint(binding_context, message, file, line, &block)
114  
-    end
115  
-  end
116  
-
117  
-  module CommandBundle #:nodoc:
118  
-    # Proxy to a Breakpoint client. Lets you directly execute code
119  
-    # in the context of the client.
120  
-    class Client#:nodoc:
121  
-      def initialize(eval_handler) # :nodoc:
122  
-        @eval_handler = eval_handler
123  
-      end
124  
-
125  
-      instance_methods.each do |method|
126  
-        next if method[/^__.+__$/]
127  
-        undef_method method
128  
-      end
129  
-
130  
-      # Executes the specified code at the client.
131  
-      def eval(code)
132  
-        @eval_handler.call(code)
133  
-      end
134  
-
135  
-      # Will execute the specified statement at the client.
136  
-      def method_missing(method, *args)
137  
-        if args.empty?
138  
-          result = eval("#{method}")
139  
-        else
140  
-          result = eval("#{method}(*Marshal.load(#{Marshal.dump(args).inspect}))")
141  
-        end
142  
-
143  
-        unless [true, false, nil].include?(result)
144  
-          result.extend(DRbUndumped) if result
145  
-        end
146  
-
147  
-        return result
148  
-      end
149  
-    end
150  
-
151  
-    # Returns the source code surrounding the location where the
152  
-    # breakpoint was issued.
153  
-    def source_lines(context = 5, return_line_numbers = false)
154  
-      lines = File.readlines(@__bp_file).map { |line| line.chomp }
155  
-
156  
-      break_line = @__bp_line
157  
-      start_line = [break_line - context, 1].max
158  
-      end_line = break_line + context
159  
-
160  
-      result = lines[(start_line - 1) .. (end_line - 1)]
161  
-
162  
-      if return_line_numbers then
163  
-        return [start_line, break_line, result]
164  
-      else
165  
-        return result
166  
-      end
167  
-    end
168  
-
169  
-    # Lets an object that will forward method calls to the breakpoint
170  
-    # client. This is useful for outputting longer things at the client
171  
-    # and so on. You can for example do these things:
172  
-    #
173  
-    #   client.puts "Hello" # outputs "Hello" at client console
174  
-    #   # outputs "Hello" into the file temp.txt at the client
175  
-    #   client.File.open("temp.txt", "w") { |f| f.puts "Hello" } 
176  
-    def client()
177  
-      if Breakpoint.use_drb? then
178  
-        Client.new(Breakpoint.drb_service.eval_handler)
179  
-      else
180  
-        Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
181  
-      end
182  
-    end
183  
-  end
184  
-
185  
-  def handle_breakpoint(context, message, file = "", line = "", &block) # :nodoc:
186  
-    catch(:debug_return) do |value|
187  
-      eval(%{
188  
-        @__bp_file = #{file.inspect}
189  
-        @__bp_line = #{line}
190  
-        extend Breakpoint::CommandBundle
191  
-        extend DRbUndumped if self
192  
-      }, context) rescue nil
193  
-
194  
-      if not use_drb? then
195  
-        puts message
196  
-        IRB.start(nil, IRB::WorkSpace.new(context))
197  
-      else
198  
-        @drb_service.add_breakpoint(context, message)
199  
-      end
200  
-
201  
-      block.call if block
202  
-    end
203  
-  end
204  
-
205  
-  # These exceptions will be raised on failed asserts
206  
-  # if Breakpoint.asserts_cause_exceptions is set to
207  
-  # true.
208  
-  class FailedAssertError < RuntimeError#:nodoc:
209  
-  end
210  
-
211  
-  # This asserts that the block evaluates to true.
212  
-  # If it doesn't evaluate to true a breakpoint will
213  
-  # automatically be created at that execution point.
214  
-  #
215  
-  # You can disable assert checking in production
216  
-  # code by setting Breakpoint.optimize_asserts to
217  
-  # true. (It will still be enabled when Ruby is run
218  
-  # via the -d argument.)
219  
-  #
220  
-  # Example:
221  
-  #   person_name = "Foobar"
222  
-  #   assert { not person_name.nil? }
223  
-  #
224  
-  # Note: If you want to use this method from an
225  
-  # unit test, you will have to call it by its full
226  
-  # name, Breakpoint.assert.
227  
-  def assert(context = nil, &condition)
228  
-    return if Breakpoint.optimize_asserts and not $DEBUG
229  
-    return if yield
230  
-
231  
-    callstack = caller
232  
-    callstack.slice!(0, 3) if callstack.first["assert"]
233  
-    file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
234  
-
235  
-    message = "Assert failed at #{file}:#{line}#{" in `#{method}'" if method}."
236  
-
237  
-    if Breakpoint.asserts_cause_exceptions and not $DEBUG then
238  
-      raise(Breakpoint::FailedAssertError, message)
239  
-    end
240  
-
241  
-    message += " Executing implicit breakpoint."
242  
-
243  
-    if context then
244  
-      return handle_breakpoint(context, message, file, line)
245  
-    end
246  
-
247  
-    Binding.of_caller do |context|
248  
-      handle_breakpoint(context, message, file, line)
249  
-    end
250  
-  end
251  
-
252  
-  # Whether asserts should be ignored if not in debug mode.
253  
-  # Debug mode can be enabled by running ruby with the -d
254  
-  # switch or by setting $DEBUG to true.
255  
-  attr_accessor :optimize_asserts
256  
-  self.optimize_asserts = false
257  
-
258  
-  # Whether an Exception should be raised on failed asserts
259  
-  # in non-$DEBUG code or not. By default this is disabled.
260  
-  attr_accessor :asserts_cause_exceptions
261  
-  self.asserts_cause_exceptions = false
262  
-  @use_drb = false
263  
-
264  
-  attr_reader :drb_service # :nodoc:
265  
-
266  
-  class DRbService # :nodoc:
267  
-    include DRbUndumped
268  
-
269  
-    def initialize
270  
-      @handler = @eval_handler = @collision_handler = nil
271  
-
272  
-      IRB.instance_eval { @CONF[:RC] = true }
273  
-      IRB.run_config
274  
-    end
275  
-
276  
-    def collision
277  
-      sleep(0.5) until @collision_handler
278  
-
279  
-      @collision_handler.call
280  
-    end
281  
-
282  
-    def ping; end
283  
-
284  
-    def add_breakpoint(context, message)
285  
-      workspace = IRB::WorkSpace.new(context)
286  
-      workspace.extend(DRbUndumped)
287  
-
288  
-      sleep(0.5) until @handler
289  
-
290  
-      @handler.call(workspace, message)
291  
-    end
292  
-
293  
-    def register_handler(&block)
294  
-      @handler = block
295  
-    end
296  
-
297  
-    def unregister_handler
298  
-      @handler = nil
299  
-    end
300  
-
301  
-    attr_reader :eval_handler
302  
-
303  
-    def register_eval_handler(&block)
304  
-      @eval_handler = block
305  
-    end
306  
-
307  
-    def unregister_eval_handler
308  
-      @eval_handler = lambda { }
309  
-    end
310  
-
311  
-    def register_collision_handler(&block)
312  
-      @collision_handler = block
313  
-    end
314  
-
315  
-    def unregister_collision_handler
316  
-      @collision_handler = lambda { }
317  
-    end
318  
-  end
319  
-
320  
-  # Will run Breakpoint in DRb mode. This will spawn a server
321  
-  # that can be attached to via the breakpoint-client command
322  
-  # whenever a breakpoint is executed. This is useful when you
323  
-  # are debugging CGI applications or other applications where
324  
-  # you can't access debug sessions via the standard input and
325  
-  # output of your application.
326  
-  #
327  
-  # You can specify an URI where the DRb server will run at.
328  
-  # This way you can specify the port the server runs on. The
329  
-  # default URI is druby://localhost:42531.
330  
-  #
331  
-  # Please note that breakpoints will be skipped silently in
332  
-  # case the DRb server can not spawned. (This can happen if
333  
-  # the port is already used by another instance of your
334  
-  # application on CGI or another application.)
335  
-  #
336  
-  # Also note that by default this will only allow access
337  
-  # from localhost. You can however specify a list of
338  
-  # allowed hosts or nil (to allow access from everywhere).
339  
-  # But that will still not protect you from somebody
340  
-  # reading the data as it goes through the net.
341  
-  #
342  
-  # A good approach for getting security and remote access
343  
-  # is setting up an SSH tunnel between the DRb service
344  
-  # and the client. This is usually done like this:
345  
-  #
346  
-  # $ ssh -L20000:127.0.0.1:20000 -R10000:127.0.0.1:10000 example.com
347  
-  # (This will connect port 20000 at the client side to port
348  
-  # 20000 at the server side, and port 10000 at the server
349  
-  # side to port 10000 at the client side.)
350  
-  #
351  
-  # After that do this on the server side: (the code being debugged)
352  
-  # Breakpoint.activate_drb("druby://127.0.0.1:20000", "localhost")
353  
-  #
354  
-  # And at the client side:
355  
-  # ruby breakpoint_client.rb -c druby://127.0.0.1:10000 -s druby://127.0.0.1:20000
356  
-  #
357  
-  # Running through such a SSH proxy will also let you use 
358  
-  # breakpoint.rb in case you are behind a firewall.
359  
-  #
360  
-  # Detailed information about running DRb through firewalls is
361  
-  # available at http://www.rubygarden.org/ruby?DrbTutorial
362  
-  def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'], ignore_collisions = false) #:nodoc:
363  
-
364  
-    return false if @use_drb
365  
-
366  
-    uri ||= 'druby://localhost:42531'
367  
-
368  
-    if allowed_hosts then
369  
-      acl = ["deny", "all"]
370  
-
371  
-      Array(allowed_hosts).each do |host|
372  
-        acl += ["allow", host]
373  
-      end
374  
-
375  
-      DRb.install_acl(ACL.new(acl))
376  
-    end
377  
-
378  
-    @use_drb = true
379  
-    @drb_service = DRbService.new
380  
-    did_collision = false
381  
-    begin
382  
-      @service = DRb.start_service(uri, @drb_service)
383  
-    rescue Errno::EADDRINUSE
384  
-      if ignore_collisions then
385  
-        nil
386  
-      else
387  
-        # The port is already occupied by another
388  
-        # Breakpoint service. We will try to tell
389  
-        # the old service that we want its port.
390  
-        # It will then forward that request to the
391  
-        # user and retry.
392  
-        unless did_collision then
393  
-          DRbObject.new(nil, uri).collision
394  
-          did_collision = true
395  
-        end
396  
-        sleep(10)
397  
-        retry
398  
-      end
399  
-    end
400  
-
401  
-    return true
402  
-  end
403  
-
404  
-  # Deactivates a running Breakpoint service.
405  
-  def deactivate_drb #:nodoc:
406  
-    @service.stop_service unless @service.nil?
407  
-    @service = nil
408  
-    @use_drb = false
409  
-    @drb_service = nil
410  
-  end
411  
-
412  
-  # Returns true when Breakpoints are used over DRb.
413  
-  # Breakpoint.activate_drb causes this to be true.
414  
-  def use_drb? #:nodoc:
415  
-    @use_drb == true
416  
-  end
417  
-end
418  
-
419  
-module IRB # :nodoc:
420  
-  class << self; remove_method :start; end
421  
-  def self.start(ap_path = nil, main_context = nil, workspace = nil)
422  
-    $0 = File::basename(ap_path, ".rb") if ap_path
423  
-
424  
-    # suppress some warnings about redefined constants
425  
-    old_verbose, $VERBOSE = $VERBOSE, nil
426  
-    IRB.setup(ap_path)
427  
-    $VERBOSE = old_verbose
428  
-
429  
-    if @CONF[:SCRIPT] then
430  
-      irb = Irb.new(main_context, @CONF[:SCRIPT])
431  
-    else
432  
-      irb = Irb.new(main_context)
433  
-    end
434  
-
435  
-    if workspace then
436  
-      irb.context.workspace = workspace
437  
-    end
438  
-
439  
-    @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
440  
-    @CONF[:MAIN_CONTEXT] = irb.context
441  
-
442  
-    old_sigint = trap("SIGINT") do
443  
-      irb.signal_handle
444  
-    end
445  
-    
446  
-    catch(:IRB_EXIT) do
447  
-      irb.eval_input
448  
-    end
449  
-  ensure
450  
-    trap("SIGINT", old_sigint)
451  
-  end
452  
-
453  
-  class << self
454  
-    alias :old_CurrentContext :CurrentContext
455  
-    remove_method :CurrentContext
456  
-  end
457  
-  def IRB.CurrentContext
458  
-    if old_CurrentContext.nil? and Breakpoint.use_drb? then
459  
-      result = Object.new
460  
-      def result.last_value; end
461  
-      return result
462  
-    else
463  
-      old_CurrentContext
464  
-    end
465  
-  end
466  
-
467  
-  class Context#:nodoc:
468  
-    alias :old_evaluate :evaluate
469  
-    def evaluate(line, line_no)
470  
-      if line.chomp == "exit" then
471  
-        exit
472  
-      else
473  
-        old_evaluate(line, line_no)
474  
-      end
475  
-    end
476  
-  end
477  
-
478  
-  class WorkSpace#:nodoc:
479  
-    alias :old_evaluate :evaluate
480  
-
481  
-    def evaluate(*args)
482  
-      if Breakpoint.use_drb? then
483  
-        result = old_evaluate(*args)
484  
-        if args[0] != :no_proxy and
485  
-          not [true, false, nil].include?(result)
486  
-        then
487  
-          result.extend(DRbUndumped) rescue nil
488  
-        end
489  
-        return result
490  
-      else
491  
-        old_evaluate(*args)
492  
-      end
493  
-    end
494  
-  end
495  
-
496  
-  module InputCompletor#:nodoc:
497  
-    def self.eval(code, context, *more)
498  
-      # Big hack, this assumes that InputCompletor
499  
-      # will only call eval() when it wants code
500  
-      # to be executed in the IRB context.
501  
-      IRB.conf[:MAIN_CONTEXT].workspace.evaluate(:no_proxy, code, *more)
502  
-    end
503  
-  end
504  
-end
505  
-
506  
-module DRb # :nodoc:
507  
-  class DRbObject#:nodoc:
508  
-    undef :inspect
509  
-    undef :clone
510  
-  end
511  
-end
512  
-
513  
-# See Breakpoint.breakpoint
514  
-def breakpoint(id = nil, &block)
515  
-  Binding.of_caller do |context|
516  
-    Breakpoint.breakpoint(id, context, &block)
517  
-  end
518  
-end
519  
-
520  
-# See Breakpoint.assert
521  
-def assert(&block)
522  
-  Binding.of_caller do |context|
523  
-    Breakpoint.assert(context, &block)
524  
-  end
525  
-end
119  railties/lib/breakpoint_client.rb
@@ -57,6 +57,15 @@
57 57
     "Show this help message."
58 58
   ) { puts opts; exit }
59 59
 
  60
+  opts.on("-v", "--version",
  61
+    "Display the version information."
  62
+  ) do
  63
+    id = %q$Id$
  64
+    puts id.sub("Id: ", "")
  65
+    puts "(Breakpoint::Version = #{Breakpoint::Version})"
  66
+    exit
  67
+  end
  68
+  
60 69
   opts.parse!
61 70
 end
62 71
 
@@ -68,6 +77,60 @@
68 77
 
69 78
 puts "Waiting for initial breakpoint..."
70 79
 
  80
+module Handlers
  81
+  extend self
  82
+
  83
+  def breakpoint_handler(workspace, message)
  84
+    puts message
  85
+    IRB.start(nil, nil, workspace)
  86
+    puts "", "Resumed execution. Waiting for next breakpoint...", ""
  87
+  end
  88
+
  89
+  def eval_handler(code)
  90
+    result = eval(code, TOPLEVEL_BINDING)
  91
+    if result then
  92
+      DRbObject.new(result)
  93
+    else
  94
+      result
  95
+    end
  96
+  end
  97
+
  98
+  def collision_handler()
  99
+    msg = [
  100
+      "  *** Breakpoint service collision ***",
  101
+      "  Another Breakpoint service tried to use the",
  102
+      "  port already occupied by this one. It will",
  103
+      "  keep waiting until this Breakpoint service",
  104
+      "  is shut down.",
  105
+      "  ",
  106
+      "  If you are using the Breakpoint library for",
  107
+      "  debugging a Rails or other CGI application",
  108
+      "  this likely means that this Breakpoint",
  109
+      "  session belongs to an earlier, outdated",
  110
+      "  request and should be shut down via 'exit'."
  111
+    ].join("\n")
  112
+
  113
+    if RUBY_PLATFORM["win"] then
  114
+      # This sucks. Sorry, I'm not doing this because
  115
+      # I like funky message boxes -- I need to do this
  116
+      # because on Windows I have no way of displaying
  117
+      # my notification via puts() when gets() is still
  118
+      # being performed on STDIN. I have not found a
  119
+      # better solution.
  120
+      begin
  121
+        require 'tk'
  122
+        root = TkRoot.new { withdraw }
  123
+        Tk.messageBox('message' => msg, 'type' => 'ok')
  124
+        root.destroy
  125
+      rescue Exception
  126
+        puts "", msg, ""
  127
+      end
  128
+    else
  129
+      puts "", msg, ""
  130
+    end
  131
+  end
  132
+end
  133
+
71 134
 loop do
72 135
   DRb.start_service(options[:ClientURI])
73 136
 
@@ -90,55 +153,9 @@
90 153
     end
91 154
 
92 155
     begin
93  
-      service.register_eval_handler do |code|
94  
-        result = eval(code, TOPLEVEL_BINDING)
95  
-        if result
96  
-          DRbObject.new(result)
97  
-        else
98  
-          result
99  
-        end
100  
-      end 
101  
-
102  
-      service.register_collision_handler do
103  
-        msg = [
104  
-          "  *** Breakpoint service collision ***",
105  
-          "  Another Breakpoint service tried to use the",
106  
-          "  port already occupied by this one. It will",
107  
-          "  keep waiting until this Breakpoint service",
108  
-          "  is shut down.",
109  
-          "  ",
110  
-          "  If you are using the Breakpoint library for",
111  
-          "  debugging a Rails or other CGI application",
112  
-          "  this likely means that this Breakpoint",
113  
-          "  session belongs to an earlier, outdated",
114  
-          "  request and should be shut down via 'exit'."
115  
-        ].join("\n")
116  
-
117  
-        if RUBY_PLATFORM["win"] then
118  
-          # This sucks. Sorry, I'm not doing this because
119  
-          # I like funky message boxes -- I need to do this
120  
-          # because on Windows I have no way of displaying
121  
-          # my notification via puts() when gets() is still
122  
-          # being performed on STDIN. I have not found a
123  
-          # better solution.
124  
-          begin
125  
-            require 'tk'
126  
-            root = TkRoot.new { withdraw }
127  
-            Tk.messageBox('message' => msg, 'type' => 'ok')
128  
-            root.destroy
129  
-          rescue Exception
130  
-            puts "", msg, ""
131  
-          end
132  
-        else
133  
-          puts "", msg, ""
134  
-        end
135  
-      end
136  
-
137  
-      service.register_handler do |workspace, message|
138  
-        puts message
139  
-        IRB.start(nil, nil, workspace)
140  
-        puts "", "Resumed execution. Waiting for next breakpoint...", ""
141  
-      end
  156
+      service.eval_handler = Handlers.method(:eval_handler)
  157
+      service.collision_handler = Handlers.method(:collision_handler)
  158
+      service.handler = Handlers.method(:breakpoint_handler)
142 159
 
143 160
       puts "Connection established. Waiting for breakpoint...", "" if options[:Verbose]
144 161
 
@@ -153,7 +170,9 @@
153 170
         sleep(0.5)
154 171
       end
155 172
     ensure
156  
-      service.unregister_handler
  173
+      service.eval_handler = nil
  174
+      service.collision_handler = nil
  175
+      service.handler = nil
157 176
     end
158 177
   rescue Exception => error
159 178
     break unless $running

0 notes on commit c46e390

Please sign in to comment.
Something went wrong with that request. Please try again.