From abfd9dfebcc5649b225f4fc2b9676e36ada7bcd7 Mon Sep 17 00:00:00 2001 From: Eloy Duran Date: Wed, 14 Jul 2010 19:08:44 +0200 Subject: [PATCH] Some final cleaning of the hacking spree, before speccing --- bin/dietrb | 4 +- lib/irb/context.rb | 14 +++---- lib/irb/driver.rb | 60 +++++++++++++++++++++++++++ lib/irb/driver/socket.rb | 12 +----- lib/irb/driver/tty.rb | 87 ++++------------------------------------ spec/driver/tty_spec.rb | 5 +++ 6 files changed, 81 insertions(+), 101 deletions(-) create mode 100644 lib/irb/driver.rb create mode 100644 spec/driver/tty_spec.rb diff --git a/bin/dietrb b/bin/dietrb index c6d652b..88ccbcf 100755 --- a/bin/dietrb +++ b/bin/dietrb @@ -32,7 +32,9 @@ end IRB.formatter.filter_from_backtrace << /^#{__FILE__}/ if ARGV.empty? - require 'irb/driver/readline' + # require 'irb/driver/readline' + # require 'irb/driver/tty' + require 'irb/driver/socket' else path = ARGV.shift require 'irb/driver/file' diff --git a/lib/irb/context.rb b/lib/irb/context.rb index 8fbbb1c..bedc575 100644 --- a/lib/irb/context.rb +++ b/lib/irb/context.rb @@ -15,7 +15,7 @@ def processors end attr_reader :object, :binding, :line, :source, :processors - attr_accessor :driver, :formatter + attr_accessor :formatter def initialize(object, explicit_binding = nil) @object = object @@ -34,11 +34,11 @@ def __evaluate__(source, file = __FILE__, line = __LINE__) def evaluate(source) result = __evaluate__(source.to_s, '(irb)', @line - @source.buffer.size + 1) store_result(result) - output.puts(formatter.result(result)) + puts(formatter.result(result)) result rescue Exception => e store_exception(e) - output.puts(formatter.exception(e)) + puts(formatter.exception(e)) end # Returns whether or not the user wants to continue the current runloop. @@ -61,7 +61,7 @@ def process_line(line) return false if @source.terminate? if @source.syntax_error? - output.puts(formatter.syntax_error(@line, @source.syntax_error)) + puts(formatter.syntax_error(@line, @source.syntax_error)) @source.pop elsif @source.code_block? evaluate(@source) @@ -77,14 +77,10 @@ def prompt end def input_line(line) - output.puts(formatter.prompt(self) + line) + puts(formatter.prompt(self) + line) process_line(line) end - def output - @driver || $stdout - end - def formatter @formatter ||= IRB.formatter end diff --git a/lib/irb/driver.rb b/lib/irb/driver.rb new file mode 100644 index 0000000..55bd5d4 --- /dev/null +++ b/lib/irb/driver.rb @@ -0,0 +1,60 @@ +module IRB + class << self + attr_accessor :driver_class + + def driver=(driver) + Thread.current[:irb_driver] = driver + end + + def driver + current_thread = Thread.current + current_thread[:irb_driver] ||= begin + if group = current_thread.group + group.list.each do |thread| + break(driver) if driver = thread[:irb_driver] + end + end + end + end + end + + module Driver + class OutputRedirector + def self.target + if driver = IRB.driver + driver.output + else + $stderr + end + end + + # A standard output object has only one mandatory method: write. + # It returns the number of characters written + def write(object) + string = object.respond_to?(:to_str) ? object : object.to_s + send_to_target :write, string + string.length + end + + # if puts is not there, Ruby will automatically use the write + # method when calling Kernel#puts, but defining it has 2 advantages: + # - if puts is not defined, you cannot of course use $stdout.puts directly + # - (objc) when Ruby emulates puts, it calls write twice + # (once for the string and once for the carriage return) + # but here we send the calls to another thread so it's nice + # to be able to save up one (slow) interthread call + def puts(*args) + send_to_target :puts, *args + nil + end + + # Override this if for your situation you need to dispatch from a thread + # in a special manner. + # + # TODO: for macruby send to main thread + def send_to_target(method, *args) + self.class.target.__send__(method, *args) + end + end + end +end \ No newline at end of file diff --git a/lib/irb/driver/socket.rb b/lib/irb/driver/socket.rb index 668e0d4..65f697e 100644 --- a/lib/irb/driver/socket.rb +++ b/lib/irb/driver/socket.rb @@ -3,16 +3,6 @@ module IRB module Driver - class SocketTTY < TTY - # We don't want to put the real standard output object on the - # OutputRedirector target stack. - def assign_output_redirector! - before = $stdout - $stdout = IRB::Driver::OutputRedirector.new - before - end - end - class Socket # Initializes with the object and binding that each new connection will # get as Context. The binding is shared, so local variables will stay @@ -34,7 +24,7 @@ def run connection = @server.accept Thread.new do # assign driver with connection to current thread and start runloop - IRB.driver = SocketTTY.new(connection, connection) + IRB.driver = TTY.new(connection, connection) irb(@object, @binding) connection.close end diff --git a/lib/irb/driver/tty.rb b/lib/irb/driver/tty.rb index d7ab2da..16f4195 100644 --- a/lib/irb/driver/tty.rb +++ b/lib/irb/driver/tty.rb @@ -1,80 +1,13 @@ +require 'irb/driver' + module IRB - class << self - attr_accessor :driver_class - - def driver=(driver) - Thread.current[:irb_driver] = driver - end - - def driver - current_thread = Thread.current - current_thread[:irb_driver] ||= begin - driver = nil - if group = current_thread.group - group.list.each do |thread| - break if driver = thread[:irb_driver] - end - end - driver || driver_class.new - end - end - end - module Driver - class OutputRedirector - # The output object for the current thread. - def self.target=(output) - Thread.current[:irb_stdout_target] = output - end - - # TODO cache, or not to cache? - def self.target - current_thread = Thread.current - if target = current_thread[:irb_stdout_target] - elsif group = current_thread.group - group.list.each do |thread| - break if target = thread[:irb_stdout_target] - end - end - target || $stderr - end - - # A standard output object has only one mandatory method: write. - # It returns the number of characters written - def write(object) - string = object.respond_to?(:to_str) ? object : object.to_s - send_to_target :write, string - string.length - end - - # if puts is not there, Ruby will automatically use the write - # method when calling Kernel#puts, but defining it has 2 advantages: - # - if puts is not defined, you cannot of course use $stdout.puts directly - # - (objc) when Ruby emulates puts, it calls write twice - # (once for the string and once for the carriage return) - # but here we send the calls to another thread so it's nice - # to be able to save up one (slow) interthread call - def puts(*args) - send_to_target :puts, *args - nil - end - - # Override this if for your situation you need to dispatch from a thread - # in a special manner. - # - # TODO: for macruby send to main thread - def send_to_target(method, *args) - self.class.target.__send__(method, *args) - end - end - class TTY - attr_accessor :current_context + attr_reader :input, :output def initialize(input = $stdin, output = $stdout) @input = input @output = output - OutputRedirector.target = output @thread_group = ThreadGroup.new @thread_group.add(Thread.current) @@ -104,7 +37,6 @@ def print(*args) def run(context) ensure_output_redirector do - context.driver = self while line = consume(context) continue = context.process_line(line) break unless continue @@ -115,27 +47,22 @@ def run(context) # Ensure that the standard output object is a OutputRedirector. If it's # already a OutputRedirector, do nothing. def ensure_output_redirector - before = assign_output_redirector! unless $stdout.is_a?(IRB::Driver::OutputRedirector) + unless $stdout.is_a?(IRB::Driver::OutputRedirector) + before, $stdout = $stdout, IRB::Driver::OutputRedirector.new + end yield ensure $stdout = before if before end - - def assign_output_redirector! - before = IRB::Driver::OutputRedirector.target = $stdout - $stdout = IRB::Driver::OutputRedirector.new - before - end end end end -IRB.driver_class = IRB::Driver::TTY +IRB.driver = IRB::Driver::TTY.new module Kernel # Creates a new IRB::Context with the given +object+ and runs it. def irb(object, binding = nil) - # IRB.driver.run(IRB::Context.new(IRB.driver, object, binding)) IRB.driver.run(IRB::Context.new(object, binding)) end diff --git a/spec/driver/tty_spec.rb b/spec/driver/tty_spec.rb new file mode 100644 index 0000000..13d7d10 --- /dev/null +++ b/spec/driver/tty_spec.rb @@ -0,0 +1,5 @@ +require File.expand_path('../../spec_helper', __FILE__) + +describe "IRB::Driver::TTY" do + +end \ No newline at end of file