From 505e2d99da9f0e199dd0bf248fc1db77145730ba Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 24 Jan 2005 13:41:57 +0000 Subject: Added Florian Gross' latest version of Breakpointer and friends that fixes a variaty of bugs #441 [Florian Gross] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@492 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- railties/lib/binding_of_caller.rb | 168 +++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 85 deletions(-) (limited to 'railties/lib/binding_of_caller.rb') diff --git a/railties/lib/binding_of_caller.rb b/railties/lib/binding_of_caller.rb index 759e760016..d18fbdef3d 100644 --- a/railties/lib/binding_of_caller.rb +++ b/railties/lib/binding_of_caller.rb @@ -1,85 +1,83 @@ -begin - require 'simplecc' -rescue LoadError - class Continuation #:nodoc: - def self.create(*args, &block) - cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?} - result ||= args - return *[cc, *result] - end - end -end - -class Binding #:nodoc: - # This method returns the binding of the method that called your - # method. It will raise an Exception when you're not inside a method. - # - # It's used like this: - # def inc_counter(amount = 1) - # Binding.of_caller do |binding| - # # Create a lambda that will increase the variable 'counter' - # # in the caller of this method when called. - # inc = eval("lambda { |arg| counter += arg }", binding) - # # We can refer to amount from inside this block safely. - # inc.call(amount) - # end - # # No other statements can go here. Put them inside the block. - # end - # counter = 0 - # 2.times { inc_counter } - # counter # => 2 - # - # Binding.of_caller must be the last statement in the method. - # This means that you will have to put everything you want to - # do after the call to Binding.of_caller into the block of it. - # This should be no problem however, because Ruby has closures. - # If you don't do this an Exception will be raised. Because of - # the way that Binding.of_caller is implemented it has to be - # done this way. - def self.of_caller(&block) - old_critical = Thread.critical - Thread.critical = true - count = 0 - cc, result, error, extra_data = Continuation.create(nil, nil) - error.call if error - - tracer = lambda do |*args| - type, context, extra_data = args[0], args[4], args - if type == "return" - count += 1 - # First this method and then calling one will return -- - # the trace event of the second event gets the context - # of the method which called the method that called this - # method. - if count == 2 - # It would be nice if we could restore the trace_func - # that was set before we swapped in our own one, but - # this is impossible without overloading set_trace_func - # in current Ruby. - set_trace_func(nil) - cc.call(eval("binding", context), nil, extra_data) - end - elsif type == "line" then - nil - elsif type == "c-return" and extra_data[3] == :set_trace_func then - nil - else - set_trace_func(nil) - error_msg = "Binding.of_caller used in non-method context or " + - "trailing statements of method using it aren't in the block." - cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil) - end - end - - unless result - set_trace_func(tracer) - return nil - else - Thread.critical = old_critical - case block.arity - when 1 then yield(result) - else yield(result, extra_data) - end - end - end -end \ No newline at end of file +begin + require 'simplecc' +rescue LoadError + class Continuation; end # :nodoc: # for RDoc + def Continuation.create(*args, &block) # :nodoc: + cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?} + result ||= args + return *[cc, *result] + end +end + +class Binding; end # for RDoc +# This method returns the binding of the method that called your +# method. It will raise an Exception when you're not inside a method. +# +# It's used like this: +# def inc_counter(amount = 1) +# Binding.of_caller do |binding| +# # Create a lambda that will increase the variable 'counter' +# # in the caller of this method when called. +# inc = eval("lambda { |arg| counter += arg }", binding) +# # We can refer to amount from inside this block safely. +# inc.call(amount) +# end +# # No other statements can go here. Put them inside the block. +# end +# counter = 0 +# 2.times { inc_counter } +# counter # => 2 +# +# Binding.of_caller must be the last statement in the method. +# This means that you will have to put everything you want to +# do after the call to Binding.of_caller into the block of it. +# This should be no problem however, because Ruby has closures. +# If you don't do this an Exception will be raised. Because of +# the way that Binding.of_caller is implemented it has to be +# done this way. +def Binding.of_caller(&block) + old_critical = Thread.critical + Thread.critical = true + count = 0 + cc, result, error, extra_data = Continuation.create(nil, nil) + error.call if error + + tracer = lambda do |*args| + type, context, extra_data = args[0], args[4], args + if type == "return" + count += 1 + # First this method and then calling one will return -- + # the trace event of the second event gets the context + # of the method which called the method that called this + # method. + if count == 2 + # It would be nice if we could restore the trace_func + # that was set before we swapped in our own one, but + # this is impossible without overloading set_trace_func + # in current Ruby. + set_trace_func(nil) + cc.call(eval("binding", context), nil, extra_data) + end + elsif type == "line" then + nil + elsif type == "c-return" and extra_data[3] == :set_trace_func then + nil + else + set_trace_func(nil) + error_msg = "Binding.of_caller used in non-method context or " + + "trailing statements of method using it aren't in the block." + cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil) + end + end + + unless result + set_trace_func(tracer) + return nil + else + Thread.critical = old_critical + case block.arity + when 1 then yield(result) + else yield(result, extra_data) + end + end +end -- cgit v1.2.3