From a75dd6e8a8308e3e83d8285c4aa6ff9b3d149cc2 Mon Sep 17 00:00:00 2001 From: Jack Nagel Date: Wed, 6 Feb 2013 18:46:36 -0600 Subject: [PATCH] Split debrew up to faciliate test isolation We want to be able to test the raise functionality without monkey-patching #raise on every object in the system, which is one of the side effects of loading debrew.rb. --- Library/Homebrew/debrew.rb | 125 ++------------------------ Library/Homebrew/debrew/exception.rb | 7 ++ Library/Homebrew/debrew/irb.rb | 33 +++++++ Library/Homebrew/debrew/menu.rb | 39 ++++++++ Library/Homebrew/debrew/raise_plus.rb | 44 +++++++++ 5 files changed, 128 insertions(+), 120 deletions(-) create mode 100644 Library/Homebrew/debrew/exception.rb create mode 100644 Library/Homebrew/debrew/irb.rb create mode 100644 Library/Homebrew/debrew/menu.rb create mode 100644 Library/Homebrew/debrew/raise_plus.rb diff --git a/Library/Homebrew/debrew.rb b/Library/Homebrew/debrew.rb index 4ec2b8270f..5e51228ec4 100644 --- a/Library/Homebrew/debrew.rb +++ b/Library/Homebrew/debrew.rb @@ -2,88 +2,12 @@ def can_use_readline? not ENV['HOMEBREW_NO_READLINE'] end -require 'irb' if can_use_readline? -require 'continuation' if RUBY_VERSION.to_f >= 1.9 +require 'debrew/menu' +require 'debrew/raise_plus' +require 'debrew/irb' if can_use_readline? -class Menu - attr_accessor :prompt - attr_accessor :entries - - def initialize - @entries = [] - end - - def choice(name, &action) - entries << { :name => name, :action => action } - end -end - -def choose - menu = Menu.new - yield menu - - choice = nil - while choice.nil? - menu.entries.each_with_index do |entry, i| - puts "#{i+1}. #{entry[:name]}" - end - print menu.prompt unless menu.prompt.nil? - reply = $stdin.gets.chomp - - i = reply.to_i - if i > 0 - choice = menu.entries[i-1] - else - possible = menu.entries.find_all {|e| e[:name].to_s.start_with? reply } - case possible.size - when 0 then puts "No such option" - when 1 then choice = possible.first - else puts "Multiple options match: #{possible.map{|e| e[:name]}.join(' ')}" - end - end - end - choice[:action].call -end - - -module IRB - @setup_done = false - - def IRB.start_within(binding) - unless @setup_done - # make IRB ignore our command line arguments - saved_args = ARGV.shift(ARGV.size) - IRB.setup(nil) - ARGV.concat(saved_args) - @setup_done = true - end - - workspace = WorkSpace.new(binding) - irb = Irb.new(workspace) - - @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] - @CONF[:MAIN_CONTEXT] = irb.context - - trap("SIGINT") do - irb.signal_handle - end - - begin - catch(:IRB_EXIT) do - irb.eval_input - end - ensure - irb_at_exit - end - end -end if can_use_readline? - -class Exception - attr_accessor :continuation - - def restart(&block) - continuation.call block - end +class Object + include RaisePlus end def has_debugger? @@ -131,42 +55,3 @@ def debrew(exception, formula=nil) end end while again end - -module RaisePlus - alias :original_raise :raise - - def raise(*args) - exception = case - when args.size == 0 - $!.nil? ? RuntimeError.exception : $! - when args.size == 1 && args[0].is_a?(String) - RuntimeError.exception(args[0]) - when args.size == 2 && args[0].is_a?(Exception) - args[0].exception(args[1]) - when args[0].is_a?(Class) && args[0].ancestors.include?(Exception) - args[0].exception(args[1]) - else - args[0] - end - - # passing something other than a String or Exception is illegal, but if someone does it anyway, - # that object won't have backtrace or continuation methods. in that case, let's pass it on to - # the original raise, which will reject it - return super exception unless exception.is_a?(Exception) - - # keep original backtrace if reraising - exception.set_backtrace(args.size >= 3 ? args[2] : caller) if exception.backtrace.nil? - - blk = callcc do |cc| - exception.continuation = cc - super exception - end - blk.call unless blk.nil? - end - - alias :fail :raise -end - -class Object - include RaisePlus -end diff --git a/Library/Homebrew/debrew/exception.rb b/Library/Homebrew/debrew/exception.rb new file mode 100644 index 0000000000..da8e56dae0 --- /dev/null +++ b/Library/Homebrew/debrew/exception.rb @@ -0,0 +1,7 @@ +class Exception + attr_accessor :continuation + + def restart(&block) + continuation.call block + end +end diff --git a/Library/Homebrew/debrew/irb.rb b/Library/Homebrew/debrew/irb.rb new file mode 100644 index 0000000000..c81e3cf4ba --- /dev/null +++ b/Library/Homebrew/debrew/irb.rb @@ -0,0 +1,33 @@ +require 'irb' + +module IRB + @setup_done = false + + def IRB.start_within(binding) + unless @setup_done + # make IRB ignore our command line arguments + saved_args = ARGV.shift(ARGV.size) + IRB.setup(nil) + ARGV.concat(saved_args) + @setup_done = true + end + + workspace = WorkSpace.new(binding) + irb = Irb.new(workspace) + + @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] + @CONF[:MAIN_CONTEXT] = irb.context + + trap("SIGINT") do + irb.signal_handle + end + + begin + catch(:IRB_EXIT) do + irb.eval_input + end + ensure + irb_at_exit + end + end +end diff --git a/Library/Homebrew/debrew/menu.rb b/Library/Homebrew/debrew/menu.rb new file mode 100644 index 0000000000..c59c500b8e --- /dev/null +++ b/Library/Homebrew/debrew/menu.rb @@ -0,0 +1,39 @@ +class Menu + attr_accessor :prompt + attr_accessor :entries + + def initialize + @entries = [] + end + + def choice(name, &action) + entries << { :name => name, :action => action } + end +end + +def choose + menu = Menu.new + yield menu + + choice = nil + while choice.nil? + menu.entries.each_with_index do |entry, i| + puts "#{i+1}. #{entry[:name]}" + end + print menu.prompt unless menu.prompt.nil? + reply = $stdin.gets.chomp + + i = reply.to_i + if i > 0 + choice = menu.entries[i-1] + else + possible = menu.entries.find_all {|e| e[:name].to_s.start_with? reply } + case possible.size + when 0 then puts "No such option" + when 1 then choice = possible.first + else puts "Multiple options match: #{possible.map{|e| e[:name]}.join(' ')}" + end + end + end + choice[:action].call +end diff --git a/Library/Homebrew/debrew/raise_plus.rb b/Library/Homebrew/debrew/raise_plus.rb new file mode 100644 index 0000000000..74f59aa46a --- /dev/null +++ b/Library/Homebrew/debrew/raise_plus.rb @@ -0,0 +1,44 @@ +require 'continuation' if RUBY_VERSION.to_f >= 1.9 + +class Exception + attr_accessor :continuation + + def restart(&block) + continuation.call block + end +end + +module RaisePlus + alias :original_raise :raise + + def raise(*args) + exception = case + when args.size == 0 + $!.nil? ? RuntimeError.exception : $! + when args.size == 1 && args[0].is_a?(String) + RuntimeError.exception(args[0]) + when args.size == 2 && args[0].is_a?(Exception) + args[0].exception(args[1]) + when args[0].is_a?(Class) && args[0].ancestors.include?(Exception) + args[0].exception(args[1]) + else + args[0] + end + + # passing something other than a String or Exception is illegal, but if someone does it anyway, + # that object won't have backtrace or continuation methods. in that case, let's pass it on to + # the original raise, which will reject it + return super exception unless exception.is_a?(Exception) + + # keep original backtrace if reraising + exception.set_backtrace(args.size >= 3 ? args[2] : caller) if exception.backtrace.nil? + + blk = callcc do |cc| + exception.continuation = cc + super exception + end + blk.call unless blk.nil? + end + + alias :fail :raise +end