Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug...

Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back [DHH]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6611 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 1d5c34c2
......@@ -124,30 +124,6 @@ def rescue_action_locally(exception)
def perform_action_with_rescue #:nodoc:
perform_action_without_rescue
rescue Exception => exception # errors from action performed
if defined?(Breakpoint) && params["BP-RETRY"]
msg = exception.backtrace.first
if md = /^(.+?):(\d+)(?::in `(.+)')?$/.match(msg) then
origin_file, origin_line = md[1], md[2].to_i
set_trace_func(lambda do |type, file, line, method, context, klass|
if file == origin_file and line == origin_line then
set_trace_func(nil)
params["BP-RETRY"] = false
callstack = caller
callstack.slice!(0) if callstack.first["rescue.rb"]
file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
message = "Exception at #{file}:#{line}#{" in `#{method}'" if method}." # `´ ( for ruby-mode)
Breakpoint.handle_breakpoint(context, message, file, line)
end
end)
retry
end
end
rescue_action(exception)
end
......
......@@ -5,26 +5,6 @@
<pre id="blame_trace" <%='style="display:none"' if hide %>><code><%=h @exception.describe_blame %></code></pre>
<% end %>
<% if false %>
<br /><br />
<% begin %>
<%= form_tag(request.request_uri, "method" => request.method) %>
<input type="hidden" name="BP-RETRY" value="1" />
<% for key, values in params %>
<% next if key == "BP-RETRY" %>
<% for value in Array(values) %>
<input type="hidden" name="<%= key %>" value="<%= value %>" />
<% end %>
<% end %>
<input type="submit" value="Retry with Breakpoint" />
</form>
<% rescue Exception => e %>
<%=h "Couldn't render breakpoint link due to #{e.class} #{e.message}" %>
<% end %>
<% end %>
<%
clean_params = request.parameters.clone
clean_params.delete("action")
......
......@@ -5,7 +5,6 @@
require 'yaml'
require 'test/unit'
require 'action_controller'
require 'breakpoint'
require 'action_controller/test_process'
# Show backtraces for deprecated behavior for quicker cleanup.
......
......@@ -198,7 +198,6 @@ def columns(table_name, name = nil) #:nodoc:
sql_type_name(row["typename"],row["length"]),
row["notnull"]
)
# breakpoint() if row["fieldname"] == "content"
end
columns
end
......
......@@ -4,8 +4,6 @@
require 'test/unit'
require 'active_record'
require 'active_record/fixtures'
require 'active_support/binding_of_caller'
require 'active_support/breakpoint'
require 'connection'
# Show backtraces for deprecated behavior for quicker cleanup.
......
......@@ -3,7 +3,6 @@
$:.unshift "#{File.dirname(__FILE__)}/../lib"
require 'active_resource'
require 'active_resource/http_mock'
require 'active_support/breakpoint'
$:.unshift "#{File.dirname(__FILE__)}/../test"
require 'setter_trap'
......
*SVN*
* Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back [DHH]
* Added parsing of file type in Hash.xml_in so you can easily do file uploads with base64 from an API [DHH]
<person>
......
begin
require 'simplecc'
rescue LoadError
class Continuation # :nodoc: # for RDoc
end
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
# The Breakpoint library provides the convenience of
# being able to inspect and modify state, diagnose
# bugs all via IRB by simply setting breakpoints in
# your applications by the call of a method.
#
# This library was written and is supported by me,
# Florian Gross. I can be reached at flgr@ccan.de
# and enjoy getting feedback about my libraries.
#
# The whole library (including breakpoint_client.rb
# and binding_of_caller.rb) is licensed under the
# same license that Ruby uses. (Which is currently
# either the GNU General Public License or a custom
# one that allows for commercial usage.) If you for
# some good reason need to use this under another
# license please contact me.
require 'irb'
require File.dirname(__FILE__) + '/binding_of_caller' unless defined? Binding.of_caller
require 'drb'
require 'drb/acl'
module Breakpoint
id = %q$Id: breakpoint.rb 92 2005-02-04 22:35:53Z flgr $
Version = id.split(" ")[2].to_i
extend self
# This will pop up an interactive ruby session at a
# pre-defined break point in a Ruby application. In
# this session you can examine the environment of
# the break point.
#
# You can get a list of variables in the context using
# local_variables via +local_variables+. You can then
# examine their values by typing their names.
#
# You can have a look at the call stack via +caller+.
#
# The source code around the location where the breakpoint
# was executed can be examined via +source_lines+. Its
# argument specifies how much lines of context to display.
# The default amount of context is 5 lines. Note that
# the call to +source_lines+ can raise an exception when
# it isn't able to read in the source code.
#
# breakpoints can also return a value. They will execute
# a supplied block for getting a default return value.
# A custom value can be returned from the session by doing
# +throw(:debug_return, value)+.
#
# You can also give names to break points which will be
# used in the message that is displayed upon execution
# of them.
#
# Here's a sample of how breakpoints should be placed:
#
# class Person
# def initialize(name, age)
# @name, @age = name, age
# breakpoint("Person#initialize")
# end
#
# attr_reader :age
# def name
# breakpoint("Person#name") { @name }
# end
# end
#
# person = Person.new("Random Person", 23)
# puts "Name: #{person.name}"
#
# And here is a sample debug session:
#
# Executing break point "Person#initialize" at file.rb:4 in `initialize'
# irb(#<Person:0x292fbe8>):001:0> local_variables
# => ["name", "age", "_", "__"]
# irb(#<Person:0x292fbe8>):002:0> [name, age]
# => ["Random Person", 23]
# irb(#<Person:0x292fbe8>):003:0> [@name, @age]
# => ["Random Person", 23]
# irb(#<Person:0x292fbe8>):004:0> self
# => #<Person:0x292fbe8 @age=23, @name="Random Person">
# irb(#<Person:0x292fbe8>):005:0> @age += 1; self
# => #<Person:0x292fbe8 @age=24, @name="Random Person">
# irb(#<Person:0x292fbe8>):006:0> exit
# Executing break point "Person#name" at file.rb:9 in `name'
# irb(#<Person:0x292fbe8>):001:0> throw(:debug_return, "Overriden name")
# Name: Overriden name
#
# Breakpoint sessions will automatically have a few
# convenience methods available. See Breakpoint::CommandBundle
# for a list of them.
#
# Breakpoints can also be used remotely over sockets.
# This is implemented by running part of the IRB session
# in the application and part of it in a special client.
# You have to call Breakpoint.activate_drb to enable
# support for remote breakpoints and then run
# breakpoint_client.rb which is distributed with this
# library. See the documentation of Breakpoint.activate_drb
# for details.
def breakpoint(id = nil, context = nil, &block)
callstack = caller
callstack.slice!(0, 3) if callstack.first["breakpoint"]
file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
message = "Executing break point " + (id ? "#{id.inspect} " : "") +
"at #{file}:#{line}" + (method ? " in `#{method}'" : "")
if context then
return handle_breakpoint(context, message, file, line, &block)
end
Binding.of_caller do |binding_context|
handle_breakpoint(binding_context, message, file, line, &block)
end
end
module CommandBundle #:nodoc:
# Proxy to a Breakpoint client. Lets you directly execute code
# in the context of the client.
class Client #:nodoc:
def initialize(eval_handler) # :nodoc:
eval_handler.untaint
@eval_handler = eval_handler
end
instance_methods.each do |method|
next if method[/^__.+__$/]
undef_method method
end
# Executes the specified code at the client.
def eval(code)
@eval_handler.call(code)
end
# Will execute the specified statement at the client.
def method_missing(method, *args, &block)
if args.empty? and not block
result = eval "#{method}"
else
# This is a bit ugly. The alternative would be using an
# eval context instead of an eval handler for executing
# the code at the client. The problem with that approach
# is that we would have to handle special expressions
# like "self", "nil" or constants ourself which is hard.
remote = eval %{
result = lambda { |block, *args| #{method}(*args, &block) }
def result.call_with_block(*args, &block)
call(block, *args)
end
result
}
remote.call_with_block(*args, &block)
end
return result
end
end
# Returns the source code surrounding the location where the
# breakpoint was issued.
def source_lines(context = 5, return_line_numbers = false)
lines = File.readlines(@__bp_file).map { |line| line.chomp }
break_line = @__bp_line
start_line = [break_line - context, 1].max
end_line = break_line + context
result = lines[(start_line - 1) .. (end_line - 1)]
if return_line_numbers then
return [start_line, break_line, result]
else
return result
end
end
# Lets an object that will forward method calls to the breakpoint
# client. This is useful for outputting longer things at the client
# and so on. You can for example do these things:
#
# client.puts "Hello" # outputs "Hello" at client console
# # outputs "Hello" into the file temp.txt at the client
# client.File.open("temp.txt", "w") { |f| f.puts "Hello" }
def client()
if Breakpoint.use_drb? then
sleep(0.5) until Breakpoint.drb_service.eval_handler
Client.new(Breakpoint.drb_service.eval_handler)
else
Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
end
end
end
def handle_breakpoint(context, message, file = "", line = "", &block) # :nodoc:
catch(:debug_return) do |value|
eval(%{
@__bp_file = #{file.inspect}
@__bp_line = #{line}
extend Breakpoint::CommandBundle
extend DRbUndumped if self
}, context) rescue nil
if not use_drb? then
puts message
IRB.start(nil, IRB::WorkSpace.new(context))
else
@drb_service.add_breakpoint(context, message)
end
block.call if block
end
end
# These exceptions will be raised on failed asserts
# if Breakpoint.asserts_cause_exceptions is set to
# true.
class FailedAssertError < RuntimeError #:nodoc:
end
# This asserts that the block evaluates to true.
# If it doesn't evaluate to true a breakpoint will
# automatically be created at that execution point.
#
# You can disable assert checking in production
# code by setting Breakpoint.optimize_asserts to
# true. (It will still be enabled when Ruby is run
# via the -d argument.)
#
# Example:
# person_name = "Foobar"
# assert { not person_name.nil? }
#
# Note: If you want to use this method from an
# unit test, you will have to call it by its full
# name, Breakpoint.assert.
def assert(context = nil, &condition)
return if Breakpoint.optimize_asserts and not $DEBUG
return if yield
callstack = caller
callstack.slice!(0, 3) if callstack.first["assert"]
file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
message = "Assert failed at #{file}:#{line}#{" in `#{method}'" if method}."
if Breakpoint.asserts_cause_exceptions and not $DEBUG then
raise(Breakpoint::FailedAssertError, message)
end
message += " Executing implicit breakpoint."
if context then
return handle_breakpoint(context, message, file, line)
end
Binding.of_caller do |context|
handle_breakpoint(context, message, file, line)
end
end
# Whether asserts should be ignored if not in debug mode.
# Debug mode can be enabled by running ruby with the -d
# switch or by setting $DEBUG to true.
attr_accessor :optimize_asserts
self.optimize_asserts = false
# Whether an Exception should be raised on failed asserts
# in non-$DEBUG code or not. By default this is disabled.
attr_accessor :asserts_cause_exceptions
self.asserts_cause_exceptions = false
@use_drb = false
attr_reader :drb_service # :nodoc:
class DRbService # :nodoc:
include DRbUndumped
def initialize
@handler = @eval_handler = @collision_handler = nil
IRB.instance_eval { @CONF[:RC] = true }
IRB.run_config
end
def collision
sleep(0.5) until @collision_handler
@collision_handler.untaint
@collision_handler.call
end
def ping() end
def add_breakpoint(context, message)
workspace = IRB::WorkSpace.new(context)
workspace.extend(DRbUndumped)
sleep(0.5) until @handler
@handler.untaint
@handler.call(workspace, message)
end
attr_accessor :handler, :eval_handler, :collision_handler
end
# Will run Breakpoint in DRb mode. This will spawn a server
# that can be attached to via the breakpoint-client command
# whenever a breakpoint is executed. This is useful when you
# are debugging CGI applications or other applications where
# you can't access debug sessions via the standard input and
# output of your application.
#
# You can specify an URI where the DRb server will run at.
# This way you can specify the port the server runs on. The
# default URI is druby://localhost:42531.
#
# Please note that breakpoints will be skipped silently in
# case the DRb server can not spawned. (This can happen if
# the port is already used by another instance of your
# application on CGI or another application.)
#
# Also note that by default this will only allow access
# from localhost. You can however specify a list of
# allowed hosts or nil (to allow access from everywhere).
# But that will still not protect you from somebody
# reading the data as it goes through the net.
#
# A good approach for getting security and remote access
# is setting up an SSH tunnel between the DRb service
# and the client. This is usually done like this:
#
# $ ssh -L20000:127.0.0.1:20000 -R10000:127.0.0.1:10000 example.com
# (This will connect port 20000 at the client side to port
# 20000 at the server side, and port 10000 at the server
# side to port 10000 at the client side.)
#
# After that do this on the server side: (the code being debugged)
# Breakpoint.activate_drb("druby://127.0.0.1:20000", "localhost")
#
# And at the client side:
# ruby breakpoint_client.rb -c druby://127.0.0.1:10000 -s druby://127.0.0.1:20000
#
# Running through such a SSH proxy will also let you use
# breakpoint.rb in case you are behind a firewall.
#
# Detailed information about running DRb through firewalls is
# available at http://www.rubygarden.org/ruby?DrbTutorial
def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'],
ignore_collisions = false)
return false if @use_drb
uri ||= 'druby://localhost:42531'
if allowed_hosts then
acl = ["deny", "all"]
Array(allowed_hosts).each do |host|
acl += ["allow", host]
end
DRb.install_acl(ACL.new(acl))
end
@use_drb = true
@drb_service = DRbService.new
did_collision = false
begin
@service = DRb.start_service(uri, @drb_service)
rescue Errno::EADDRINUSE
if ignore_collisions then
nil
else
# The port is already occupied by another
# Breakpoint service. We will try to tell
# the old service that we want its port.
# It will then forward that request to the
# user and retry.
unless did_collision then
DRbObject.new(nil, uri).collision
did_collision = true
end
sleep(10)
retry
end
end
return true
end
# Deactivates a running Breakpoint service.
def deactivate_drb
@service.stop_service unless @service.nil?
@service = nil
@use_drb = false
@drb_service = nil
end
# Returns true when Breakpoints are used over DRb.
# Breakpoint.activate_drb causes this to be true.
def use_drb?
@use_drb == true
end
end
module IRB #:nodoc:
class << self; remove_method :start; end
def self.start(ap_path = nil, main_context = nil, workspace = nil)
$0 = File::basename(ap_path, ".rb") if ap_path
# suppress some warnings about redefined constants
old_verbose, $VERBOSE = $VERBOSE, nil
IRB.setup(ap_path)
$VERBOSE = old_verbose
if @CONF[:SCRIPT] then
irb = Irb.new(main_context, @CONF[:SCRIPT])
else
irb = Irb.new(main_context)
end
if workspace then
irb.context.workspace = workspace
end
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
@CONF[:MAIN_CONTEXT] = irb.context
old_sigint = trap("SIGINT") do
begin
irb.signal_handle
rescue RubyLex::TerminateLineInput
# ignored
end
end
catch(:IRB_EXIT) do
irb.eval_input
end
ensure
trap("SIGINT", old_sigint)
end
class << self
alias :old_CurrentContext :CurrentContext
remove_method :CurrentContext
end
def IRB.CurrentContext
if old_CurrentContext.nil? and Breakpoint.use_drb? then
result = Object.new
def result.last_value; end
return result
else
old_CurrentContext
end
end
class << self
alias :old_parse_opts :parse_opts
remove_method :parse_opts
end
def IRB.parse_opts() end
class Context #:nodoc:
alias :old_evaluate :evaluate
def evaluate(line, line_no)
if line.chomp == "exit" then
exit
else
old_evaluate(line, line_no)
end
end
end
class WorkSpace #:nodoc:
alias :old_evaluate :evaluate
def evaluate(*args)
if Breakpoint.use_drb? then
result = old_evaluate(*args)
if args[0] != :no_proxy and
not [true, false, nil].include?(result)
then
result.extend(DRbUndumped) rescue nil
end
return result
else
old_evaluate(*args)
end
end
end
module InputCompletor #:nodoc:
def self.eval(code, context, *more)
# Big hack, this assumes that InputCompletor
# will only call eval() when it wants code
# to be executed in the IRB context.
IRB.conf[:MAIN_CONTEXT].workspace.evaluate(:no_proxy, code, *more)
end
end
end
module DRb # :nodoc:
class DRbObject #:nodoc:
undef :inspect if method_defined?(:inspect)
undef :clone if method_defined?(:clone)
end
end
# See Breakpoint.breakpoint
def breakpoint(id = nil, &block)
Binding.of_caller do |context|
Breakpoint.breakpoint(id, context, &block)
end
end
# See Breakpoint.assert
def assert(&block)
Binding.of_caller do |context|
Breakpoint.assert(context, &block)
end
end
......@@ -2,3 +2,4 @@
require File.dirname(__FILE__) + '/kernel/reporting'
require File.dirname(__FILE__) + '/kernel/agnostics'
require File.dirname(__FILE__) + '/kernel/requires'
require File.dirname(__FILE__) + '/kernel/debugger'
module Kernel
unless respond_to?(:debugger)
# Starts a debugging session if ruby-debug has been loaded (call script/server --debugger to do load it).
def debugger
RAILS_DEFAULT_LOGGER.info "\n***** Debugger requested, but was not available: Start server with --debugger to enable *****\n"
end
end
def breakpoint
RAILS_DEFAULT_LOGGER.info "\n***** The 'breakpoint' command has been renamed 'debugger' -- please change *****\n"
debugger
end
end
\ No newline at end of file
*SVN*
* Removed breakpointer and Binding.of_caller in favor of relying on ruby-debug by Kent Sibilev since the breakpointer has been broken since Ruby 1.8.4 and will not be coming back [DHH]
To use the new debugger, start your server with script/server --debugger and insert a call to 'debugger'
(instead of 'breakpoint') where you want to jump into the debugger.
BACKWARDS INCOMPATIBILITY NOTE: You must remove the default line 12 from config/environments/development.rb:
config.breakpoint_server = true
This configuration option is no longer available. Rails will fail to start in development mode as long as
that's still present.
* Resource scaffolding returns the created entity.to_xml. [Jeremy Kemper]
* Resource scaffolding responds to new.xml. #8185 [Eric Mill]
......
......@@ -69,29 +69,27 @@ automatically display debugging and runtime information to these files. Debuggin
info will also be shown in the browser on requests from 127.0.0.1.
== Breakpoints
== Debugger
Breakpoint support is available through the script/breakpointer client. This
means that you can break out of execution at any point in the code, investigate
Debugger support is available through the debugger command when you start your Mongrel or
Webrick server with --debugger. This means that you can break out of execution at any point in the code, investigate
and change the model, AND then resume execution! Example:
class WeblogController < ActionController::Base
def index
@posts = Post.find(:all)
breakpoint "Breaking out from the list"
debugger
end
end
So the controller will accept the action, run the first line, then present you
with a IRB prompt in the breakpointer window. Here you can do things like:
Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
with a IRB prompt in the server window. Here you can do things like:
>> @posts.inspect
=> "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
#<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
>> @posts.first.title = "hello from a breakpoint"
=> "hello from a breakpoint"
>> @posts.first.title = "hello from a debugger"
=> "hello from a debugger"
...and even better is that you can examine how your runtime objects actually work:
......@@ -100,7 +98,7 @@ Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in
>> f.
Display all 152 possibilities? (y or n)
Finally, when you're ready to resume execution, you press CTRL-D
Finally, when you're ready to resume execution, you enter "cont"
== Console
......
......@@ -69,7 +69,7 @@ LOG_FILES = %w( server.log development.log test.log production.log )
HTML_FILES = %w( 404.html 500.html index.html robots.txt favicon.ico images/rails.png
javascripts/prototype.js javascripts/application.js
javascripts/effects.js javascripts/dragdrop.js javascripts/controls.js )
BIN_FILES = %w( about breakpointer console destroy generate performance/benchmarker performance/profiler process/reaper process/spawner process/inspector runner server plugin )
BIN_FILES = %w( about console destroy generate performance/benchmarker performance/profiler process/reaper process/spawner process/inspector runner server plugin )
VENDOR_LIBS = %w( actionpack activerecord actionmailer activesupport actionwebservice railties )
......
#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/breakpointer'
\ No newline at end of file
......@@ -8,9 +8,6 @@
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Enable the breakpoint server that script/breakpointer connects to
config.breakpoint_server = true
# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true
config.action_controller.perform_caching = false
......
begin
require 'simplecc'
rescue LoadError
# to satisfy rdoc
class Continuation #:nodoc:
end
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
# The Breakpoint library provides the convenience of
# being able to inspect and modify state, diagnose
# bugs all via IRB by simply setting breakpoints in
# your applications by the call of a method.
#
# This library was written and is supported by me,
# Florian Gross. I can be reached at flgr@ccan.de
# and enjoy getting feedback about my libraries.
#
# The whole library (including breakpoint_client.rb
# and binding_of_caller.rb) is licensed under the
# same license that Ruby uses. (Which is currently
# either the GNU General Public License or a custom
# one that allows for commercial usage.) If you for
# some good reason need to use this under another
# license please contact me.
require 'irb'
if RUBY_VERSION == '1.8.5'
def Binding.of_caller(&block)
raise "Breakpoints are not currently working with Ruby 1.8.5"
end
else
require 'binding_of_caller'
end
require 'drb'
require 'drb/acl'
module Breakpoint
id = %q$Id: breakpoint.rb 92 2005-02-04 22:35:53Z flgr $
Version = id.split(" ")[2].to_i
extend self
# This will pop up an interactive ruby session at a
# pre-defined break point in a Ruby application. In
# this session you can examine the environment of
# the break point.
#
# You can get a list of variables in the context using
# local_variables via +local_variables+. You can then
# examine their values by typing their names.
#
# You can have a look at the call stack via +caller+.
#
# The source code around the location where the breakpoint
# was executed can be examined via +source_lines+. Its
# argument specifies how much lines of context to display.
# The default amount of context is 5 lines. Note that
# the call to +source_lines+ can raise an exception when
# it isn't able to read in the source code.
#
# breakpoints can also return a value. They will execute
# a supplied block for getting a default return value.
# A custom value can be returned from the session by doing
# +throw(:debug_return, value)+.
#
# You can also give names to break points which will be
# used in the message that is displayed upon execution
# of them.
#
# Here's a sample of how breakpoints should be placed:
#
# class Person
# def initialize(name, age)
# @name, @age = name, age
# breakpoint("Person#initialize")
# end
#
# attr_reader :age
# def name
# breakpoint("Person#name") { @name }
# end
# end
#
# person = Person.new("Random Person", 23)
# puts "Name: #{person.name}"
#
# And here is a sample debug session:
#
# Executing break point "Person#initialize" at file.rb:4 in `initialize'
# irb(#<Person:0x292fbe8>):001:0> local_variables
# => ["name", "age", "_", "__"]
# irb(#<Person:0x292fbe8>):002:0> [name, age]
# => ["Random Person", 23]
# irb(#<Person:0x292fbe8>):003:0> [@name, @age]
# => ["Random Person", 23]
# irb(#<Person:0x292fbe8>):004:0> self
# => #<Person:0x292fbe8 @age=23, @name="Random Person">
# irb(#<Person:0x292fbe8>):005:0> @age += 1; self
# => #<Person:0x292fbe8 @age=24, @name="Random Person">
# irb(#<Person:0x292fbe8>):006:0> exit
# Executing break point "Person#name" at file.rb:9 in `name'
# irb(#<Person:0x292fbe8>):001:0> throw(:debug_return, "Overriden name")
# Name: Overriden name
#
# Breakpoint sessions will automatically have a few
# convenience methods available. See Breakpoint::CommandBundle
# for a list of them.
#
# Breakpoints can also be used remotely over sockets.
# This is implemented by running part of the IRB session
# in the application and part of it in a special client.
# You have to call Breakpoint.activate_drb to enable
# support for remote breakpoints and then run
# breakpoint_client.rb which is distributed with this
# library. See the documentation of Breakpoint.activate_drb
# for details.
def breakpoint(id = nil, context = nil, &block)
callstack = caller
callstack.slice!(0, 3) if callstack.first["breakpoint"]
file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
message = "Executing break point " + (id ? "#{id.inspect} " : "") +
"at #{file}:#{line}" + (method ? " in `#{method}'" : "")
if context then
return handle_breakpoint(context, message, file, line, &block)
end
Binding.of_caller do |binding_context|
handle_breakpoint(binding_context, message, file, line, &block)
end
end
module CommandBundle
# Proxy to a Breakpoint client. Lets you directly execute code
# in the context of the client.
class Client
def initialize(eval_handler) # :nodoc:
eval_handler.untaint
@eval_handler = eval_handler
end
instance_methods.each do |method|
next if method[/^__.+__$/]
undef_method method
end
# Executes the specified code at the client.
def eval(code)
@eval_handler.call(code)
end
# Will execute the specified statement at the client.
def method_missing(method, *args, &block)
if args.empty? and not block
result = eval "#{method}"
else
# This is a bit ugly. The alternative would be using an
# eval context instead of an eval handler for executing
# the code at the client. The problem with that approach
# is that we would have to handle special expressions
# like "self", "nil" or constants ourself which is hard.
remote = eval %{
result = lambda { |block, *args| #{method}(*args, &block) }
def result.call_with_block(*args, &block)
call(block, *args)
end
result
}
remote.call_with_block(*args, &block)
end
return result
end
end
# Returns the source code surrounding the location where the
# breakpoint was issued.
def source_lines(context = 5, return_line_numbers = false)
lines = File.readlines(@__bp_file).map { |line| line.chomp }
break_line = @__bp_line
start_line = [break_line - context, 1].max
end_line = break_line + context
result = lines[(start_line - 1) .. (end_line - 1)]
if return_line_numbers then
return [start_line, break_line, result]
else
return result
end
end
# Prints the source code surrounding the location where the
# breakpoint was issued.
def show_source_list(context = 5)
start_line, break_line, result = source_lines(context, true)
offset = [(break_line + context).to_s.length, 4].max
result.each_with_index do |line, i|
mark = (start_line + i == break_line ? '->' : ' ')
client.puts("%0#{offset}d%s#{line}" % [start_line + i, mark])
end
Pathname.new(@__bp_file).cleanpath.to_s
end
# Prints the call stack.
def show_call_stack(depth = 10)
base = Pathname.new(RAILS_ROOT).cleanpath.to_s
caller[1..depth].each do |line|
line.sub!(/^[^:]*/) do |path|
Pathname.new(path).cleanpath.to_s
end
client.puts(line.index(base) == 0 ? line[(base.length + 1)..-1] : line)
end
"#{Pathname.new(@__bp_file).cleanpath.to_s}:#{@__bp_line}"
end
# Lets an object that will forward method calls to the breakpoint
# client. This is useful for outputting longer things at the client
# and so on. You can for example do these things:
#
# client.puts "Hello" # outputs "Hello" at client console
# # outputs "Hello" into the file temp.txt at the client
# client.File.open("temp.txt", "w") { |f| f.puts "Hello" }
def client()
if Breakpoint.use_drb? then
sleep(0.5) until Breakpoint.drb_service.eval_handler
Client.new(Breakpoint.drb_service.eval_handler)
else
Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
end
end
end
def handle_breakpoint(context, message, file = "", line = "", &block) # :nodoc:
catch(:debug_return) do |value|
eval(%{
@__bp_file = #{file.inspect}
@__bp_line = #{line}
extend Breakpoint::CommandBundle
extend DRbUndumped if self
}, context) rescue nil
if not use_drb? then
puts message
IRB.start(nil, IRB::WorkSpace.new(context))
else
@drb_service.add_breakpoint(context, message)
end
block.call if block
end
end
# These exceptions will be raised on failed asserts
# if Breakpoint.asserts_cause_exceptions is set to
# true.
class FailedAssertError < RuntimeError
end
# This asserts that the block evaluates to true.
# If it doesn't evaluate to true a breakpoint will
# automatically be created at that execution point.
#
# You can disable assert checking in production
# code by setting Breakpoint.optimize_asserts to
# true. (It will still be enabled when Ruby is run
# via the -d argument.)
#
# Example:
# person_name = "Foobar"
# assert { not person_name.nil? }
#
# Note: If you want to use this method from an
# unit test, you will have to call it by its full
# name, Breakpoint.assert.
def assert(context = nil, &condition)
return if Breakpoint.optimize_asserts and not $DEBUG
return if yield
callstack = caller
callstack.slice!(0, 3) if callstack.first["assert"]
file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
message = "Assert failed at #{file}:#{line}#{" in `#{method}'" if method}."
if Breakpoint.asserts_cause_exceptions and not $DEBUG then
raise(Breakpoint::FailedAssertError, message)
end
message += " Executing implicit breakpoint."
if context then
return handle_breakpoint(context, message, file, line)
end
Binding.of_caller do |context|
handle_breakpoint(context, message, file, line)
end
end
# Whether asserts should be ignored if not in debug mode.
# Debug mode can be enabled by running ruby with the -d
# switch or by setting $DEBUG to true.
attr_accessor :optimize_asserts
self.optimize_asserts = false
# Whether an Exception should be raised on failed asserts
# in non-$DEBUG code or not. By default this is disabled.
attr_accessor :asserts_cause_exceptions
self.asserts_cause_exceptions = false
@use_drb = false
attr_reader :drb_service # :nodoc:
class DRbService # :nodoc:
include DRbUndumped
def initialize
@handler = @eval_handler = @collision_handler = nil
IRB.instance_eval { @CONF[:RC] = true }
IRB.run_config
end
def collision
sleep(0.5) until @collision_handler
@collision_handler.untaint
@collision_handler.call
end
def ping() end
def add_breakpoint(context, message)
workspace = IRB::WorkSpace.new(context)
workspace.extend(DRbUndumped)
sleep(0.5) until @handler
@handler.untaint
@handler.call(workspace, message)
end
attr_accessor :handler, :eval_handler, :collision_handler
end
# Will run Breakpoint in DRb mode. This will spawn a server
# that can be attached to via the breakpoint-client command
# whenever a breakpoint is executed. This is useful when you
# are debugging CGI applications or other applications where
# you can't access debug sessions via the standard input and
# output of your application.
#
# You can specify an URI where the DRb server will run at.
# This way you can specify the port the server runs on. The
# default URI is druby://localhost:42531.
#
# Please note that breakpoints will be skipped silently in
# case the DRb server can not spawned. (This can happen if
# the port is already used by another instance of your
# application on CGI or another application.)
#
# Also note that by default this will only allow access
# from localhost. You can however specify a list of
# allowed hosts or nil (to allow access from everywhere).
# But that will still not protect you from somebody
# reading the data as it goes through the net.
#
# A good approach for getting security and remote access
# is setting up an SSH tunnel between the DRb service
# and the client. This is usually done like this:
#
# $ ssh -L20000:127.0.0.1:20000 -R10000:127.0.0.1:10000 example.com
# (This will connect port 20000 at the client side to port
# 20000 at the server side, and port 10000 at the server
# side to port 10000 at the client side.)
#
# After that do this on the server side: (the code being debugged)
# Breakpoint.activate_drb("druby://127.0.0.1:20000", "localhost")
#
# And at the client side:
# ruby breakpoint_client.rb -c druby://127.0.0.1:10000 -s druby://127.0.0.1:20000
#
# Running through such a SSH proxy will also let you use
# breakpoint.rb in case you are behind a firewall.
#
# Detailed information about running DRb through firewalls is
# available at http://www.rubygarden.org/ruby?DrbTutorial
def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'],
ignore_collisions = false)
return false if @use_drb
uri ||= 'druby://localhost:42531'
if allowed_hosts then
acl = ["deny", "all"]
Array(allowed_hosts).each do |host|
acl += ["allow", host]
end
DRb.install_acl(ACL.new(acl))
end
@use_drb = true
@drb_service = DRbService.new
did_collision = false
begin
@service = DRb.start_service(uri, @drb_service)
rescue Errno::EADDRINUSE
if ignore_collisions then
nil
else
# The port is already occupied by another
# Breakpoint service. We will try to tell
# the old service that we want its port.
# It will then forward that request to the
# user and retry.
unless did_collision then
DRbObject.new(nil, uri).collision
did_collision = true
end
sleep(10)
retry
end
end
return true
end
# Deactivates a running Breakpoint service.
def deactivate_drb
@service.stop_service unless @service.nil?
@service = nil
@use_drb = false
@drb_service = nil
end
# Returns true when Breakpoints are used over DRb.
# Breakpoint.activate_drb causes this to be true.
def use_drb?
@use_drb == true
end
end
module IRB # :nodoc:
class << self; remove_method :start; end
def self.start(ap_path = nil, main_context = nil, workspace = nil)
$0 = File::basename(ap_path, ".rb") if ap_path
# suppress some warnings about redefined constants
old_verbose, $VERBOSE = $VERBOSE, nil
IRB.setup(ap_path)
$VERBOSE = old_verbose
if @CONF[:SCRIPT] then
irb = Irb.new(main_context, @CONF[:SCRIPT])
else
irb = Irb.new(main_context)
end
if workspace then
irb.context.workspace = workspace
end
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
@CONF[:MAIN_CONTEXT] = irb.context
old_sigint = trap("SIGINT") do
begin
irb.signal_handle
rescue RubyLex::TerminateLineInput
# ignored
end
end
catch(:IRB_EXIT) do
irb.eval_input
end
ensure
trap("SIGINT", old_sigint)
end
class << self
alias :old_CurrentContext :CurrentContext
remove_method :CurrentContext
end
def IRB.CurrentContext
if old_CurrentContext.nil? and Breakpoint.use_drb? then
result = Object.new
def result.last_value; end
return result
else
old_CurrentContext
end
end
def IRB.parse_opts() end
class Context #:nodoc:
alias :old_evaluate :evaluate
def evaluate(line, line_no)
if line.chomp == "exit" then
exit
else
old_evaluate(line, line_no)
end
end
end
class WorkSpace #:nodoc:
alias :old_evaluate :evaluate
def evaluate(*args)
if Breakpoint.use_drb? then
result = old_evaluate(*args)
if args[0] != :no_proxy and
not [true, false, nil].include?(result)
then
result.extend(DRbUndumped) rescue nil
end
return result
else
old_evaluate(*args)
end
end
end
module InputCompletor #:nodoc:
def self.eval(code, context, *more)
# Big hack, this assumes that InputCompletor
# will only call eval() when it wants code
# to be executed in the IRB context.
IRB.conf[:MAIN_CONTEXT].workspace.evaluate(:no_proxy, code, *more)
end
end
end
module DRb #:nodoc:
class DRbObject #:nodoc:
undef :inspect if method_defined?(:inspect)
undef :clone if method_defined?(:clone)
end
end
# See Breakpoint.breakpoint
def breakpoint(id = nil, &block)
Binding.of_caller do |context|
Breakpoint.breakpoint(id, context, &block)
end
end
# See Breakpoint.assert
def assert(&block)
Binding.of_caller do |context|
Breakpoint.assert(context, &block)
end
end
require 'breakpoint'
require 'optparse'
require 'timeout'
Options = {
:ClientURI => nil,
:ServerURI => "druby://localhost:42531",
:RetryDelay => 2,
:Permanent => true,
:Verbose => false
}
ARGV.options do |opts|
script_name = File.basename($0)
opts.banner = [
"Usage: ruby #{script_name} [Options] [server uri]",
"",
"This tool lets you connect to a breakpoint service ",
"which was started via Breakpoint.activate_drb.",
"",
"The server uri defaults to druby://localhost:42531"
].join("\n")
opts.separator ""
opts.on("-c", "--client-uri=uri",
"Run the client on the specified uri.",
"This can be used to specify the port",
"that the client uses to allow for back",
"connections from the server.",
"Default: Find a good URI automatically.",
"Example: -c druby://localhost:12345"
) { |v| Options[:ClientURI] = v }
opts.on("-s", "--server-uri=uri",
"Connect to the server specified at the",
"specified uri.",
"Default: druby://localhost:42531"
) { |v| Options[:ServerURI] = v }
opts.on("-R", "--retry-delay=delay", Integer,
"Automatically try to reconnect to the",
"server after delay seconds when the",
"connection failed or timed out.",
"A value of 0 disables automatical",
"reconnecting completely.",
"Default: 10"
) { |v| Options[:RetryDelay] = v }
opts.on("-P", "--[no-]permanent",
"Run the breakpoint client in permanent mode.",
"This means that the client will keep continue",
"running even after the server has closed the",
"connection. Useful for example in Rails."
) { |v| Options[:Permanent] = v }
opts.on("-V", "--[no-]verbose",
"Run the breakpoint client in verbose mode.",
"Will produce more messages, for example between",
"individual breakpoints. This might help in seeing",
"that the breakpoint client is still alive, but adds",
"quite a bit of clutter."
) { |v| Options[:Verbose] = v }
opts.separator ""
opts.on("-h", "--help",
"Show this help message."
) { puts opts; exit }
opts.on("-v", "--version",
"Display the version information."
) do
id = %q$Id: breakpoint_client.rb 91 2005-02-04 22:34:08Z flgr $
puts id.sub("Id: ", "")
puts "(Breakpoint::Version = #{Breakpoint::Version})"
exit
end
opts.parse!
end
Options[:ServerURI] = ARGV[0] if ARGV[0]
module Handlers #:nodoc:
extend self
def breakpoint_handler(workspace, message)
puts message
IRB.start(nil, nil, workspace)
puts ""
if Options[:Verbose] then
puts "Resumed execution. Waiting for next breakpoint...", ""
end
end
def eval_handler(code)
result = eval(code, TOPLEVEL_BINDING)
if result then
DRbObject.new(result)
else
result
end
end
def collision_handler()
msg = [
" *** Breakpoint service collision ***",
" Another Breakpoint service tried to use the",
" port already occupied by this one. It will",
" keep waiting until this Breakpoint service",
" is shut down.",
" ",
" If you are using the Breakpoint library for",
" debugging a Rails or other CGI application",
" this likely means that this Breakpoint",
" session belongs to an earlier, outdated",
" request and should be shut down via 'exit'."
].join("\n")
if RUBY_PLATFORM["win"] then
# This sucks. Sorry, I'm not doing this because
# I like funky message boxes -- I need to do this
# because on Windows I have no way of displaying
# my notification via puts() when gets() is still
# being performed on STDIN. I have not found a
# better solution.
begin
require 'tk'
root = TkRoot.new { withdraw }
Tk.messageBox('message' => msg, 'type' => 'ok')
root.destroy
rescue Exception
puts "", msg, ""
end
else
puts "", msg, ""
end
end
end
# Used for checking whether we are currently in the reconnecting loop.
reconnecting = false
loop do
DRb.start_service(Options[:ClientURI])
begin
service = DRbObject.new(nil, Options[:ServerURI])
begin
ehandler = Handlers.method(:eval_handler)
chandler = Handlers.method(:collision_handler)
handler = Handlers.method(:breakpoint_handler)
service.eval_handler = ehandler
service.collision_handler = chandler
service.handler = handler
reconnecting = false
if Options[:Verbose] then
puts "Connection established. Waiting for breakpoint...", ""
end
loop do
begin
service.ping
rescue DRb::DRbConnError => error
puts "Server exited. Closing connection...", ""
exit! unless Options[:Permanent]
break
end
sleep(0.5)
end
ensure
service.eval_handler = nil
service.collision_handler = nil
service.handler = nil
end
rescue Exception => error
if Options[:RetryDelay] > 0 then
if not reconnecting then
reconnecting = true
puts "No connection to breakpoint service at #{Options[:ServerURI]} " +
"(#{error.class})"
puts error.backtrace if $DEBUG
puts "Tries to connect will be made every #{Options[:RetryDelay]} seconds..."
end
sleep Options[:RetryDelay]
retry
else
raise
end
end
end
......@@ -17,3 +17,15 @@ def tail(log_file)
end
tail_thread
end
def start_debugger
begin
require_library_or_gem 'ruby-debug'
Debugger.start
# Debugger.settings[:autoirb] = true
puts "=> Debugger enabled"
rescue Exception
puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
exit
end
end
\ No newline at end of file
......@@ -12,13 +12,15 @@
:port => 3000,
:ip => "0.0.0.0",
:environment => (ENV['RAILS_ENV'] || "development").dup,
:detach => false
:detach => false,
:debugger => false
}
ARGV.clone.options do |opts|
opts.on("-p", "--port=port", Integer, "Runs Rails on the specified port.", "Default: 3000") { |v| OPTIONS[:port] = v }
opts.on("-b", "--binding=ip", String, "Binds Rails to the specified ip.", "Default: 0.0.0.0") { |v| OPTIONS[:ip] = v }
opts.on("-d", "--daemon", "Make server run as a Daemon.") { OPTIONS[:detach] = true }
opts.on("-u", "--debugger", "Enable ruby-debugging for the server.") { OPTIONS[:debugger] = true }
opts.on("-e", "--environment=name", String,
"Specifies the environment to run this server under (test/development/production).",
"Default: development") { |v| OPTIONS[:environment] = v }
......@@ -46,6 +48,8 @@
ENV["RAILS_ENV"] = OPTIONS[:environment]
RAILS_ENV.replace(OPTIONS[:environment]) if defined?(RAILS_ENV)
start_debugger if OPTIONS[:debugger]
require 'initializer'
Rails::Initializer.run(:initialize_logger)
......
......@@ -2,13 +2,15 @@
require 'optparse'
OPTIONS = {
:port => 3000,
:ip => "0.0.0.0",
:environment => (ENV['RAILS_ENV'] || "development").dup,
:server_root => File.expand_path(RAILS_ROOT + "/public/"),
:server_type => WEBrick::SimpleServer,
:charset => "UTF-8",
:mime_types => WEBrick::HTTPUtils::DefaultMimeTypes
:port => 3000,
:ip => "0.0.0.0",
:environment => (ENV['RAILS_ENV'] || "development").dup,
:server_root => File.expand_path(RAILS_ROOT + "/public/"),
:server_type => WEBrick::SimpleServer,
:charset => "UTF-8",
:mime_types => WEBrick::HTTPUtils::DefaultMimeTypes,
:debugger => false
}
ARGV.options do |opts|
......@@ -34,6 +36,8 @@
"Make Rails run as a Daemon (only works if fork is available -- meaning on *nix)."
) { OPTIONS[:server_type] = WEBrick::Daemon }
opts.on("-u", "--debugger", "Enable ruby-debugging for the server.") { OPTIONS[:debugger] = true }
opts.on("-c", "--charset=charset", String,
"Set default charset for output.",
"Default: UTF-8") { |v| OPTIONS[:charset] = v }
......@@ -46,6 +50,8 @@
opts.parse!
end
start_debugger if OPTIONS[:debugger]
ENV["RAILS_ENV"] = OPTIONS[:environment]
RAILS_ENV.replace(OPTIONS[:environment]) if defined?(RAILS_ENV)
......
......@@ -104,7 +104,6 @@ def prepare_application
self.preparation_callbacks_run = false
end
prepare_breakpoint
require_dependency 'application' unless Object.const_defined?(:ApplicationController)
ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord)
run_preparation_callbacks
......@@ -112,16 +111,6 @@ def prepare_application
def reset_after_dispatch
reset_application! if Dependencies.load?
Breakpoint.deactivate_drb if defined?(BREAKPOINT_SERVER_PORT)
end
def prepare_breakpoint
return unless defined?(BREAKPOINT_SERVER_PORT)
require 'breakpoint'
Breakpoint.activate_drb("druby://localhost:#{BREAKPOINT_SERVER_PORT}", nil, !defined?(FastCGI))
true
rescue
nil
end
def run_preparation_callbacks
......
......@@ -9,8 +9,7 @@ class RailsFCGIHandler
'INT' => :exit_now,
'TERM' => :exit_now,
'USR1' => :exit,
'USR2' => :restart,
'SIGTRAP' => :breakpoint
'USR2' => :restart
}
GLOBAL_SIGNALS = SIGNALS.keys - %w(USR1)
......@@ -131,11 +130,6 @@ def restart_handler(signal)
@when_ready = :restart
end
def breakpoint_handler(signal)
dispatcher_log :info, "asked to breakpoint ASAP"
@when_ready = :breakpoint
end
def process_each_request!(provider)
cgi = nil
provider.each_cgi do |cgi|
......@@ -152,9 +146,6 @@ def process_each_request!(provider)
when :exit
close_connection(cgi)
break
when :breakpoint
close_connection(cgi)
breakpoint!
end
gc_countdown
......@@ -198,15 +189,6 @@ def restore!
ActionController::Routing::Routes.reload
end
def breakpoint!
require 'breakpoint'
port = defined?(BREAKPOINT_SERVER_PORT) ? BREAKPOINT_SERVER_PORT : 42531
Breakpoint.activate_drb("druby://localhost:#{port}", nil, !defined?(FastCGI))
dispatcher_log :info, "breakpointing"
breakpoint
@when_ready = nil
end
def run_gc!
@gc_request_countdown = gc_request_period
GC.enable; GC.start; GC.disable
......
......@@ -69,7 +69,6 @@ def initialize(configuration)
# * #initialize_framework_logging
# * #initialize_framework_views
# * #initialize_dependency_mechanism
# * #initialize_breakpoints
# * #initialize_whiny_nils
# * #initialize_framework_settings
# * #load_environment
......@@ -98,7 +97,6 @@ def process
initialize_framework_logging
initialize_framework_views
initialize_dependency_mechanism
initialize_breakpoints
initialize_whiny_nils
initialize_temporary_directories
initialize_framework_settings
......@@ -298,12 +296,6 @@ def initialize_dependency_mechanism
Dependencies.mechanism = configuration.cache_classes ? :require : :load
end
# Sets the +BREAKPOINT_SERVER_PORT+ if Configuration#breakpoint_server
# is true.
def initialize_breakpoints
silence_warnings { Object.const_set("BREAKPOINT_SERVER_PORT", 42531) if configuration.breakpoint_server }
end
# Loads support for "whiny nil" (noisy warnings when methods are invoked
# on +nil+ values) if Configuration#whiny_nils is true.
def initialize_whiny_nils
......@@ -385,9 +377,6 @@ class Configuration
# A stub for setting options on ActiveRecord::Base
attr_accessor :active_resource
# Whether or not to use the breakpoint server (boolean)
attr_accessor :breakpoint_server
# Whether or not classes should be cached (set to false if you want
# application classes to be reloaded on each request)
attr_accessor :cache_classes
......@@ -474,7 +463,6 @@ def initialize
self.view_path = default_view_path
self.controller_paths = default_controller_paths
self.cache_classes = default_cache_classes
self.breakpoint_server = default_breakpoint_server
self.whiny_nils = default_whiny_nils
self.plugins = default_plugins
self.plugin_paths = default_plugin_paths
......@@ -634,10 +622,6 @@ def default_cache_classes
false
end
def default_breakpoint_server
false
end
def default_whiny_nils
false
end
......
......@@ -67,7 +67,7 @@ def manifest
m.file "environments/test.rb", "config/environments/test.rb"
# Scripts
%w( about breakpointer console destroy generate performance/benchmarker performance/profiler process/reaper process/spawner process/inspector runner server plugin ).each do |file|
%w( about console destroy generate performance/benchmarker performance/profiler process/reaper process/spawner process/inspector runner server plugin ).each do |file|
m.file "bin/#{file}", "script/#{file}", script_options
end
......
......@@ -8,7 +8,6 @@
require 'active_record/fixtures'
require 'action_controller/test_process'
require 'action_controller/integration'
require 'breakpoint'
Test::Unit::TestCase.fixture_path = RAILS_ROOT + "/test/fixtures/"
ActionController::IntegrationTest.fixture_path = Test::Unit::TestCase.fixture_path
......
......@@ -12,7 +12,6 @@
# Stubs
require 'fcgi_handler'
require 'routes'
require 'stubbed_breakpoint'
require 'stubbed_kernel'
class RailsFCGIHandler
......@@ -35,9 +34,6 @@ def send_signal(which)
@signal_handlers[which].call(which)
end
def breakpoint
end
alias_method :old_run_gc!, :run_gc!
def run_gc!
@gc_runs ||= 0
......@@ -71,14 +67,6 @@ def test_process_exit
@handler.process!
end
def test_process_breakpoint
@handler.stubs(:when_ready).returns(:breakpoint)
@handler.expects(:close_connection)
@handler.expects(:breakpoint!)
@handler.process!
end
def test_process_with_system_exit_exception
@handler.stubs(:process_request).raises(SystemExit)
......@@ -93,13 +81,6 @@ def test_restart_handler
assert_equal :restart, @handler.when_ready
end
def test_breakpoint_handler
@handler.expects(:dispatcher_log).with(:info, "asked to breakpoint ASAP")
@handler.send(:breakpoint_handler, nil)
assert_equal :breakpoint, @handler.when_ready
end
def test_install_signal_handler_should_log_on_bad_signal
@handler.stubs(:trap).raises(ArgumentError)
......@@ -143,15 +124,6 @@ def test_restore!
@handler.send(:restore!)
end
def test_breakpoint!
@handler.expects(:require).with('breakpoint')
Breakpoint.expects(:activate_drb)
@handler.expects(:breakpoint)
@handler.expects(:dispatcher_log).with(:info, "breakpointing")
@handler.send(:breakpoint!)
assert_nil @handler.when_ready
end
def test_uninterrupted_processing
@handler.process!
assert_nil @handler.exit_code
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册