[macruby-changes] [4376] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sat Jul 24 08:11:25 PDT 2010


Revision: 4376
          http://trac.macosforge.org/projects/ruby/changeset/4376
Author:   eloy.de.enige at gmail.com
Date:     2010-07-24 08:11:24 -0700 (Sat, 24 Jul 2010)
Log Message:
-----------
Update DietRB to 0.5.1 (ee35b7726a48c036e78623f111353ef2b8294a38)

Modified Paths:
--------------
    MacRuby/trunk/bin/irb
    MacRuby/trunk/lib/irb/completion.rb
    MacRuby/trunk/lib/irb/context.rb
    MacRuby/trunk/lib/irb/ext/completion.rb
    MacRuby/trunk/lib/irb/ext/history.rb
    MacRuby/trunk/lib/irb/version.rb
    MacRuby/trunk/lib/irb.rb
    MacRuby/trunk/spec/dietrb/context_spec.rb
    MacRuby/trunk/spec/dietrb/ext/completion_spec.rb
    MacRuby/trunk/spec/dietrb/ext/history_spec.rb
    MacRuby/trunk/spec/dietrb/formatter_spec.rb
    MacRuby/trunk/spec/dietrb/spec_helper.rb

Added Paths:
-----------
    MacRuby/trunk/lib/irb/driver/
    MacRuby/trunk/lib/irb/driver/readline.rb
    MacRuby/trunk/lib/irb/driver/socket.rb
    MacRuby/trunk/lib/irb/driver/tty.rb
    MacRuby/trunk/lib/irb/driver.rb
    MacRuby/trunk/spec/dietrb/driver/
    MacRuby/trunk/spec/dietrb/driver/readline_spec.rb
    MacRuby/trunk/spec/dietrb/driver/tty_spec.rb
    MacRuby/trunk/spec/dietrb/driver_spec.rb

Removed Paths:
-------------
    MacRuby/trunk/lib/irb/ext/macruby.rb

Modified: MacRuby/trunk/bin/irb
===================================================================
--- MacRuby/trunk/bin/irb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/bin/irb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -2,41 +2,55 @@
 
 require 'irb'
 
-unless ARGV.empty?
-  require 'optparse'
-  
-  ignore_irbrc = false
-  
-  OptionParser.new do |opt|
-    bin = File.basename($0)
-    opt.banner = "Usage:  #{bin} [options] [programfile] [arguments]"
-    opt.on("-f",              "Ignore ~/.irbrc") { |ignore| ignore_irbrc = ignore  }
-    opt.on("-r load-lib",     "Loads the given library (same as `ruby -r')") { |lib| require lib }
-    opt.on("-d",              "Set $DEBUG to true (same as `ruby -d')") { $DEBUG = true }
-    opt.on("-I path",         "Add path to $LOAD_PATH") { |path| $LOAD_PATH.unshift(path) }
-    opt.on("--noinspect",     "Don't use inspect for output") { IRB.formatter.inspect = false }
-    opt.on("--simple-prompt", "Simple prompt mode") { IRB.formatter.prompt = :simple }
-    opt.on("--noprompt",      "No prompt mode") { IRB.formatter.prompt = nil }
-    opt.on("-v", "--version", "Print the version of #{bin}") do
-      puts IRB::VERSION::DESCRIPTION
-      exit
+IRB_CONTEXT_TOPLEVEL_ARGS = [self, TOPLEVEL_BINDING.dup]
+
+module IRB
+  # Just a namespace so not to pollute the toplevel namespace with lvars.
+  module Bin
+    driver = nil
+    ignore_irbrc = false
+    
+    unless ARGV.empty?
+      require 'optparse'
+      
+      OptionParser.new do |opt|
+        bin = File.basename($0)
+        opt.banner = "Usage:  #{bin} [options] [programfile] [arguments]"
+        opt.on("-f",              "Ignore ~/.irbrc")                                 { |i| ignore_irbrc = i }
+        opt.on("-r load-lib",     "Loads the given library (same as `ruby -r')")     { |l| require l }
+        opt.on("-d",              "Set $DEBUG to true (same as `ruby -d')")          { $DEBUG = true }
+        opt.on("-I path",         "Add path to $LOAD_PATH")                          { |p| $LOAD_PATH.unshift(p) }
+        opt.on("--driver name",   "As driver, use one of: tty, readline, or socket") { |d| driver = d }
+        opt.on("--noinspect",     "Don't use inspect for output")                    { IRB.formatter.inspect = false }
+        opt.on("--simple-prompt", "Simple prompt mode")                              { IRB.formatter.prompt = :simple }
+        opt.on("--noprompt",      "No prompt mode")                                  { IRB.formatter.prompt = nil }
+        opt.on("-v", "--version", "Print the version of #{bin}") do
+          $stdout.puts IRB::VERSION::DESCRIPTION
+          exit
+        end
+      end.parse!(ARGV)
     end
-  end.parse!(ARGV)
-end
-
-unless ignore_irbrc
-  irbrc = File.expand_path("~/.irbrc")
-  load(irbrc) if File.exist?(irbrc)
-end
-
-IRB.formatter.filter_from_backtrace << /^#{__FILE__}/
-
-if ARGV.empty?
-  irb(self, TOPLEVEL_BINDING.dup)
-else
-  path = ARGV.shift
-  context = IRB::Context.new(self, TOPLEVEL_BINDING.dup)
-  File.open(path, 'r') do |file|
-    file.each_line { |line| context.input_line(line) }
+    
+    unless ignore_irbrc
+      irbrc = File.expand_path("~/.irbrc")
+      load(irbrc) if File.exist?(irbrc)
+    end
+    
+    IRB.formatter.filter_from_backtrace << /^#{__FILE__}/
+    
+    if ARGV.empty?
+      driver ||= begin
+        require 'readline'
+        'readline'
+      rescue LoadError
+        'tty'
+      end
+      require "irb/driver/#{driver}"
+      irb(*IRB_CONTEXT_TOPLEVEL_ARGS)
+    else
+      path = ARGV.shift
+      context = IRB::Context.new(*IRB_CONTEXT_TOPLEVEL_ARGS)
+      File.open(path, 'r') { |f| f.each_line { |line| context.input_line(line) } }
+    end
   end
 end
\ No newline at end of file

Modified: MacRuby/trunk/lib/irb/completion.rb
===================================================================
--- MacRuby/trunk/lib/irb/completion.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/lib/irb/completion.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -1 +1 @@
-IRB.deprecated "The file `irb/completion' has moved to `irb/ext/ecompletion' and is loaded by default.", caller
\ No newline at end of file
+IRB.deprecated "The file `irb/completion' has moved to `irb/ext/completion' and is loaded by default.", caller
\ No newline at end of file

Modified: MacRuby/trunk/lib/irb/context.rb
===================================================================
--- MacRuby/trunk/lib/irb/context.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/lib/irb/context.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -5,28 +5,13 @@
 # Copyright (C) 2009-2010, Eloy Duran <eloy.de.enige at gmail.com>
 
 require 'irb/formatter'
-require 'readline'
 
 module IRB
   class Context
-    class << self
-      attr_accessor :current
-      
-      def make_current(context)
-        # Messing with a current context is gonna bite me in the ass when we
-        # get to multi-threading, but we'll it when we get there.
-        before, @current = @current, context
-        yield
-      ensure
-        @current = before
-      end
-      
-      def processors
-        @processors ||= []
-      end
-    end
+    IGNORE_RESULT = :irb_ignore_result
     
-    attr_reader :object, :binding, :line, :source, :processors
+    attr_reader :object, :binding, :line, :source
+    attr_accessor :formatter
     
     def initialize(object, explicit_binding = nil)
       @object  = object
@@ -34,8 +19,8 @@
       @line    = 1
       clear_buffer
       
-      @underscore_assigner = __evaluate__("_ = nil; proc { |val| _ = val }")
-      @processors = self.class.processors.map { |processor| processor.new(self) }
+      @last_result_assigner = __evaluate__("_ = nil; proc { |val| _ = val }")
+      @exception_assigner   = __evaluate__("e = exception = nil; proc { |ex| e = exception = ex }")
     end
     
     def __evaluate__(source, file = __FILE__, line = __LINE__)
@@ -44,33 +29,16 @@
     
     def evaluate(source)
       result = __evaluate__(source.to_s, '(irb)', @line - @source.buffer.size + 1)
-      store_result(result)
-      puts formatter.result(result)
-      result
+      unless result == IGNORE_RESULT
+        store_result(result)
+        puts(formatter.result(result))
+        result
+      end
     rescue Exception => e
       store_exception(e)
-      puts formatter.exception(e)
+      puts(formatter.exception(e))
     end
     
-    # Reads input and passes it to all processors.
-    def readline
-      input = Readline.readline(formatter.prompt(self), true)
-      @processors.each { |processor| input = processor.input(input) }
-      input
-    rescue Interrupt
-      clear_buffer
-      ""
-    end
-    
-    def run
-      self.class.make_current(self) do
-        while line = readline
-          continue = process_line(line)
-          break unless continue
-        end
-      end
-    end
-    
     # Returns whether or not the user wants to continue the current runloop.
     # This can only be done at a code block indentation level of 0.
     #
@@ -88,7 +56,7 @@
       return false if @source.terminate?
       
       if @source.syntax_error?
-        puts formatter.syntax_error(@line, @source.syntax_error)
+        puts(formatter.syntax_error(@line, @source.syntax_error))
         @source.pop
       elsif @source.code_block?
         evaluate(@source)
@@ -99,13 +67,17 @@
       true
     end
     
+    def prompt
+      formatter.prompt(self)
+    end
+    
     def input_line(line)
-      puts formatter.prompt(self) + line
+      puts(formatter.prompt(self) + line)
       process_line(line)
     end
     
     def formatter
-      IRB.formatter
+      @formatter ||= IRB.formatter
     end
     
     def clear_buffer
@@ -113,20 +85,11 @@
     end
     
     def store_result(result)
-      @underscore_assigner.call(result)
+      @last_result_assigner.call(result)
     end
     
     def store_exception(exception)
-      $e = $EXCEPTION = exception
+      @exception_assigner.call(exception)
     end
   end
-end
-
-module Kernel
-  # Creates a new IRB::Context with the given +object+ and runs it.
-  def irb(object, binding = nil)
-    IRB::Context.new(object, binding).run
-  end
-  
-  private :irb
-end
+end
\ No newline at end of file

Added: MacRuby/trunk/lib/irb/driver/readline.rb
===================================================================
--- MacRuby/trunk/lib/irb/driver/readline.rb	                        (rev 0)
+++ MacRuby/trunk/lib/irb/driver/readline.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -0,0 +1,26 @@
+require 'readline'
+require 'irb/driver/tty'
+require 'irb/ext/history'
+require 'irb/ext/completion'
+
+module IRB
+  module Driver
+    class Readline < TTY
+      
+      def initialize(input = $stdin, output = $stdout)
+        super
+        ::Readline.input  = @input
+        ::Readline.output = @output
+        ::Readline.completion_proc = IRB::Completion.new
+      end
+      
+      def readline
+        source = ::Readline.readline(context.prompt, true)
+        IRB::History.input(source)
+        source
+      end
+    end
+  end
+end
+
+IRB::Driver.current = IRB::Driver::Readline.new

Added: MacRuby/trunk/lib/irb/driver/socket.rb
===================================================================
--- MacRuby/trunk/lib/irb/driver/socket.rb	                        (rev 0)
+++ MacRuby/trunk/lib/irb/driver/socket.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -0,0 +1,58 @@
+require 'irb/driver/tty'
+require 'socket'
+
+module IRB
+  module Driver
+    class Socket
+      class << self
+        attr_reader :instance
+        
+        def run(object, binding)
+          @instance = new(object, binding)
+          @instance.run
+        end
+      end
+      
+      # Initializes with the object and binding that each new connection will
+      # get as Context. The binding is shared, so local variables will stay
+      # around. The benefit of this is that a socket based irb session is most
+      # probably used to debug a running application in development. In this
+      # scenario it could be beneficial to keep local vars in between sessions.
+      #
+      # TODO see if that actually works out ok.
+      def initialize(object, binding, host = '127.0.0.1', port = 7829)
+        @object, @binding = object, binding
+        @host, @port = host, port
+        @server = TCPServer.new(host, port)
+      end
+      
+      # TODO libedit doesn't use the right input and output, so we can't use Readline for now!!
+      def run
+        $stderr.puts "[!] Running IRB server on #{@host}:#{@port}"
+        loop do
+          connection = @server.accept
+          Thread.new do
+            # assign driver with connection to current thread and start runloop
+            IRB::Driver.current = TTY.new(connection, connection)
+            irb(@object, @binding)
+            connection.close
+          end
+        end
+      end
+    end
+  end
+end
+
+module Kernel
+  alias_method :irb_before_socket, :irb
+  
+  def irb(object, binding = nil)
+    if IRB::Driver::Socket.instance.nil?
+      IRB::Driver::Socket.run(object, binding)
+    else
+      irb_before_socket(object, binding)
+    end
+  end
+  
+  private :irb, :irb_before_socket
+end
\ No newline at end of file

Added: MacRuby/trunk/lib/irb/driver/tty.rb
===================================================================
--- MacRuby/trunk/lib/irb/driver/tty.rb	                        (rev 0)
+++ MacRuby/trunk/lib/irb/driver/tty.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -0,0 +1,58 @@
+require 'irb/driver'
+
+module IRB
+  module Driver
+    class TTY
+      attr_reader :input, :output, :context_stack
+      
+      def initialize(input = $stdin, output = $stdout)
+        @input  = input
+        @output = output
+        @context_stack = []
+      end
+      
+      def context
+        @context_stack.last
+      end
+      
+      def readline
+        @output.print(context.prompt)
+        @input.gets
+      end
+      
+      # TODO make it take the current context instead of storing it
+      def consume
+        readline
+      rescue Interrupt
+        context.clear_buffer
+        ""
+      end
+      
+      # Feeds input into a given context.
+      #
+      # Ensures that the standard output object is a OutputRedirector, or a
+      # subclass thereof.
+      def run(context)
+        @context_stack << context
+        before, $stdout = $stdout, OutputRedirector.new unless $stdout.is_a?(OutputRedirector)
+        while line = consume
+          break unless context.process_line(line)
+        end
+      ensure
+        @context_stack.pop
+        $stdout = before if before
+      end
+    end
+  end
+end
+
+IRB::Driver.current = 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.current.run(IRB::Context.new(object, binding))
+  end
+  
+  private :irb
+end

Added: MacRuby/trunk/lib/irb/driver.rb
===================================================================
--- MacRuby/trunk/lib/irb/driver.rb	                        (rev 0)
+++ MacRuby/trunk/lib/irb/driver.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -0,0 +1,61 @@
+module IRB
+  module Driver
+    class << self
+      def current=(driver)
+        ThreadGroup.new.add(Thread.current)
+        Thread.current[:irb_driver] = driver
+      end
+      
+      def current
+        current_thread = Thread.current
+        current_thread[:irb_driver] ||= begin
+          if group = current_thread.group
+            driver = nil
+            group.list.each do |thread|
+              break if driver = thread[:irb_driver]
+            end
+            driver
+          end
+        end
+      end
+    end
+    
+    class OutputRedirector
+      def self.target
+        if driver = IRB::Driver.current
+          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

Modified: MacRuby/trunk/lib/irb/ext/completion.rb
===================================================================
--- MacRuby/trunk/lib/irb/ext/completion.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/lib/irb/ext/completion.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -36,22 +36,23 @@
       yield
     }
     
+    attr_reader :source
+    
+    def context
+      IRB::Driver.current.context
+    end
+    
     # Returns an array of possible completion results, with the current
     # IRB::Context.
     #
     # This is meant to be used with Readline which takes a completion proc.
-    def self.call(source)
-      new(IRB::Context.current, source).results
+    def call(source)
+      @source = source
+      results
     end
     
-    attr_reader :context, :source
-    
-    def initialize(context, source)
-      @context, @source = context, source
-    end
-    
     def evaluate(s)
-      @context.__evaluate__(s)
+      context.__evaluate__(s)
     end
     
     def local_variables
@@ -59,7 +60,7 @@
     end
     
     def instance_methods
-      @context.object.methods.map(&:to_s)
+      context.object.methods.map(&:to_s)
     end
     
     def instance_methods_of(klass)
@@ -190,5 +191,5 @@
     # * Hash: = and >
     Readline.basic_word_break_characters= " \t\n`<;|&("
   end
-  Readline.completion_proc = IRB::Completion
-end
\ No newline at end of file
+  # Readline.completion_proc = IRB::Completion
+end

Modified: MacRuby/trunk/lib/irb/ext/history.rb
===================================================================
--- MacRuby/trunk/lib/irb/ext/history.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/lib/irb/ext/history.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -7,91 +7,86 @@
 # Portions Copyright (C) 2006-2010 Ben Bleything <ben at bleything.net> (Kernel#history & Kernel#history!)
 
 module IRB
-  class History
+  module History
     class << self
       attr_accessor :file, :max_entries_in_overview
       
-      def current
-        IRB::Context.current.processors.find do |processor|
-          processor.is_a?(IRB::History)
-        end
+      def setup
+        to_a.each do |source|
+          Readline::HISTORY.push(source)
+        end if Readline::HISTORY.to_a.empty?
       end
-    end
-    
-    def initialize(context)
-      @context = context
       
-      to_a.each do |source|
-        Readline::HISTORY.push(source)
-      end if Readline::HISTORY.to_a.empty?
-    end
-    
-    def input(source)
-      File.open(self.class.file, "a") { |f| f.puts(source) }
-      source
-    end
-    
-    def to_a
-      file = self.class.file
-      File.exist?(file) ? File.read(file).split("\n") : []
-    end
-    
-    def clear!
-      File.open(self.class.file, "w") { |f| f << "" }
-      Readline::HISTORY.clear
-    end
-    
-    def history(number_of_entries = max_entries_in_overview)
-      history_size = Readline::HISTORY.size
-      start_index = 0
+      def context
+        IRB::Driver.current.context
+      end
       
-      # always remove one extra, because that's the `history' command itself
-      if history_size <= number_of_entries
-        end_index = history_size - 2
-      else
-        end_index = history_size - 2
-        start_index = history_size - number_of_entries - 1
+      def input(source)
+        File.open(file, "a") { |f| f.puts(source) }
+        source
       end
       
-      start_index.upto(end_index) do |i|
-        puts "#{i}: #{Readline::HISTORY[i]}"
+      def to_a
+        File.exist?(file) ? File.read(file).split("\n") : []
       end
-    end
-    
-    def history!(entry_or_range)
-      # we don't want to execute history! again
-      @context.clear_buffer
       
-      if entry_or_range.is_a?(Range)
-        entry_or_range.to_a.each do |i|
-          @context.input_line(Readline::HISTORY[i])
+      def clear!
+        File.open(file, "w") { |f| f << "" }
+        Readline::HISTORY.clear
+      end
+      
+      def history(number_of_entries = max_entries_in_overview)
+        history_size = Readline::HISTORY.size
+        start_index = 0
+        
+        # always remove one extra, because that's the `history' command itself
+        if history_size <= number_of_entries
+          end_index = history_size - 2
+        else
+          end_index = history_size - 2
+          start_index = history_size - number_of_entries - 1
         end
-      else
-        @context.input_line(Readline::HISTORY[entry_or_range])
+        
+        start_index.upto(end_index) do |i|
+          puts "#{i}: #{Readline::HISTORY[i]}"
+        end
       end
+      
+      def history!(entry_or_range)
+        # we don't want to execute history! again
+        context.clear_buffer
+        
+        if entry_or_range.is_a?(Range)
+          entry_or_range.to_a.each do |i|
+            context.input_line(Readline::HISTORY[i])
+          end
+        else
+          context.input_line(Readline::HISTORY[entry_or_range])
+        end
+      end
     end
   end
 end
 
 module Kernel
   def history(number_of_entries = IRB::History.max_entries_in_overview)
-    IRB::History.current.history(number_of_entries)
-    nil
+    IRB::History.history(number_of_entries)
+    IRB::Context::IGNORE_RESULT
   end
   alias_method :h, :history
   
   def history!(entry_or_range)
-    IRB::History.current.history!(entry_or_range)
-    nil
+    IRB::History.history!(entry_or_range)
+    IRB::Context::IGNORE_RESULT
   end
   alias_method :h!, :history!
   
   def clear_history!
-    IRB::History.current.clear!
-    nil
+    IRB::History.clear!
+    true
   end
 end
 
-IRB::Context.processors << IRB::History
 IRB::History.file = File.expand_path("~/.irb_history")
-IRB::History.max_entries_in_overview = 50
\ No newline at end of file
+IRB::History.max_entries_in_overview = 50
+IRB::History.setup
\ No newline at end of file

Deleted: MacRuby/trunk/lib/irb/ext/macruby.rb
===================================================================
--- MacRuby/trunk/lib/irb/ext/macruby.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/lib/irb/ext/macruby.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -1,25 +0,0 @@
-# MacRuby implementation of IRB.
-#
-# This file is covered by the Ruby license. See COPYING for more details.
-# 
-# Copyright (C) 2009-2010, Eloy Duran <eloy.de.enige at gmail.com>
-
-framework 'AppKit'
-
-module IRB
-  class Context
-    alias_method :_run, :run
-    
-    def run
-      if NSApplication.sharedApplication.running?
-        _run
-      else
-        Thread.new do
-          _run
-          NSApplication.sharedApplication.terminate(self)
-        end
-        NSApplication.sharedApplication.run
-      end
-    end
-  end
-end
\ No newline at end of file

Modified: MacRuby/trunk/lib/irb/version.rb
===================================================================
--- MacRuby/trunk/lib/irb/version.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/lib/irb/version.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -8,8 +8,8 @@
   module VERSION #:nodoc:
     NAME  = 'DietRB'
     MAJOR = 0
-    MINOR = 4
-    TINY  = 7
+    MINOR = 5
+    TINY  = 1
     
     STRING = [MAJOR, MINOR, TINY].join('.')
     DESCRIPTION = "#{NAME} (#{STRING})"

Modified: MacRuby/trunk/lib/irb.rb
===================================================================
--- MacRuby/trunk/lib/irb.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/lib/irb.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -10,13 +10,6 @@
 
 require 'irb/deprecated'
 
-require 'irb/ext/history'
-require 'irb/ext/completion'
-
-# if !ENV['SPECCING'] && defined?(RUBY_ENGINE) && RUBY_ENGINE == "macruby"
-#   require 'irb/ext/macruby'
-# end
-
 module IRB
   class << self
     # This is just here for so the ruby 1.9 IRB will seemingly work, but actually

Modified: MacRuby/trunk/spec/dietrb/context_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/context_spec.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/spec/dietrb/context_spec.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -1,22 +1,6 @@
 require File.expand_path('../spec_helper', __FILE__)
 require 'tempfile'
 
-def stub_Readline
-  class << Readline
-    attr_reader :received
-    
-    def stub_input(*input)
-      @input = input
-    end
-    
-    def readline(prompt, history)
-      @received = [prompt, history]
-      @input.shift
-    end
-  end
-end
-stub_Readline
-
 class TestProcessor
   def input(s)
     s * 2
@@ -28,6 +12,7 @@
 describe "IRB::Context" do
   before do
     @context = IRB::Context.new(main)
+    @context.extend(OutputStubMixin)
   end
   
   it "initializes with an object and stores a copy of its binding" do
@@ -50,37 +35,15 @@
     @context.source.to_s.should == ""
   end
   
-  it "initializes with an instance of each processor" do
-    before = IRB::Context.processors.dup
-    begin
-      IRB::Context.processors << TestProcessor
-      @context = IRB::Context.new(main)
-      @context.processors.last.class.should == TestProcessor
-    ensure
-      IRB::Context.processors.replace(before)
-    end
-  end
-  
   it "does not use the same binding copy of the top level object" do
     lambda { eval("x", @context.binding) }.should raise_error(NameError)
   end
-  
-  it "makes itself the current running context during the runloop and resigns once it's done" do
-    IRB::Context.current.should == nil
-    
-    Readline.stub_input("current_during_run = IRB::Context.current")
-    @context.run
-    eval('current_during_run', @context.binding).should == @context
-    
-    IRB::Context.current.should == nil
-  end
 end
 
 describe "IRB::Context, when evaluating source" do
   before do
     @context = IRB::Context.new(main)
-    def @context.printed;      @printed ||= ''          end
-    def @context.puts(string); printed << "#{string}\n" end
+    @context.extend(OutputStubMixin)
     IRB.formatter = IRB::Formatter.new
   end
   
@@ -112,11 +75,11 @@
     }.should_not.raise_error
   end
   
-  it "assigns the last raised exception to the global variable `$EXCEPTION' / `$e'" do
+  it "assigns the last raised exception to the variables `exception' / `e'" do
     @context.evaluate("DoesNotExist")
-    $EXCEPTION.class.should == NameError
-    $EXCEPTION.message.should include('DoesNotExist')
-    $e.should == $EXCEPTION
+    @context.__evaluate__("exception").class.should == NameError
+    @context.__evaluate__("exception").message.should include('DoesNotExist')
+    @context.__evaluate__("e").should == @context.__evaluate__("exception")
   end
   
   it "prints the exception that occurs" do
@@ -133,59 +96,31 @@
     @context.printed.should =~ /\(irb\):3:in.+\(irb\):2:in/m
   end
   
-  it "inputs a line to be processed, skipping readline" do
-    expected = "#{@context.formatter.prompt(@context)}2 * 21\n=> 42\n"
-    @context.input_line("2 * 21")
-    @context.printed.should == expected
+  it "ignores the result if it's IRB::Context::IGNORE_RESULT" do
+    @context.evaluate(":bananas")
+    @context.evaluate("IRB::Context::IGNORE_RESULT").should == nil
+    @context.printed.should == "=> :bananas\n"
+    @context.evaluate("_").should == :bananas
   end
 end
 
 describe "IRB::Context, when receiving input" do
   before do
     @context = IRB::Context.new(main)
+    @context.extend(InputStubMixin)
+    @context.extend(OutputStubMixin)
   end
   
-  it "prints the prompt, reads a line, saves it to the history and returns it" do
-    Readline.stub_input("def foo")
-    @context.readline.should == "def foo"
-    Readline.received.should == ["irb(main):001:0> ", true]
-  end
-  
-  it "passes the input to all processors, which may return a new value" do
-    @context.processors << TestProcessor.new
-    Readline.stub_input("foo")
-    @context.readline.should == "foofoo"
-  end
-  
-  it "processes the output" do
-    Readline.stub_input("def foo")
-    def @context.process_line(line); @received = line; false; end
-    @context.run
-    @context.instance_variable_get(:@received).should == "def foo"
-  end
-  
   it "adds the received code to the source buffer" do
     @context.process_line("def foo")
     @context.process_line("p :ok")
     @context.source.to_s.should == "def foo\np :ok"
   end
   
-  it "clears the source buffer when an Interrupt signal is received" do
-    begin
-      @context.process_line("def foo")
-      
-      def Readline.readline(*args)
-        unless @raised
-          @raised = true
-          raise Interrupt
-        end
-      end
-      
-      lambda { @context.run }.should_not raise_error(Interrupt)
-      @context.source.to_s.should == ""
-    ensure
-      stub_Readline
-    end
+  it "clears the source buffer" do
+    @context.process_line("def foo")
+    @context.clear_buffer
+    @context.source.to_s.should == ""
   end
   
   it "increases the current line number" do
@@ -208,14 +143,11 @@
   end
   
   it "prints that a syntax error occurred on the last line and reset the buffer to the previous line" do
-    def @context.puts(str); @printed = str; end
-    
     @context.process_line("def foo")
     @context.process_line("  };")
     
     @context.source.to_s.should == "def foo"
-    printed = @context.instance_variable_get(:@printed)
-    printed.should == "SyntaxError: compile error\n(irb):2: syntax error, unexpected '}'"
+    @context.printed.should == "SyntaxError: compile error\n(irb):2: syntax error, unexpected '}'\n"
   end
   
   it "returns whether or not the runloop should continue, but only if the level is 0" do
@@ -226,19 +158,9 @@
     @context.process_line("quit").should == false
   end
   
-  it "exits the runloop if the user wishes so" do
-    Readline.stub_input("quit", "def foo")
-    def @context.process_line(line); @received = line; super; end
-    @context.run
-    @context.instance_variable_get(:@received).should_not == "def foo"
+  it "inputs a line to be processed" do
+    expected = "#{@context.formatter.prompt(@context)}2 * 21\n=> 42\n"
+    @context.input_line("2 * 21")
+    @context.printed.should == expected
   end
 end
-
-describe "Kernel::irb" do
-  it "creates a new context for the given object and runs it" do
-    Readline.stub_input("::IRBRan = self")
-    o = Object.new
-    irb(o)
-    IRBRan.should == o
-  end
-end

Added: MacRuby/trunk/spec/dietrb/driver/readline_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/driver/readline_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/driver/readline_spec.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -0,0 +1,70 @@
+require File.expand_path("../../spec_helper", __FILE__)
+require "irb/driver/readline"
+
+module Readline
+  extend InputStubMixin
+  extend OutputStubMixin
+
+  def self.input=(input)
+    @given_input = input
+  end
+
+  def self.given_input
+    @given_input
+  end
+
+  def self.output=(output)
+    @given_output = output
+  end
+
+  def self.given_output
+    @given_output
+  end
+
+  def self.use_history=(use_history)
+    @use_history = use_history
+  end
+
+  def self.use_history
+    @use_history
+  end
+
+  def self.readline(prompt, use_history)
+    @use_history = use_history
+    print prompt
+    @input.shift
+  end
+end
+
+describe "IRB::Driver::Readline" do
+  before do
+    @driver = IRB::Driver::Readline.new(InputStub.new, OutputStub.new)
+    @context = IRB::Context.new(Object.new)
+    @driver.context_stack << @context
+  end
+
+  it "is a subclass of IRB::Driver::TTY" do
+    IRB::Driver::Readline.superclass.should == IRB::Driver::TTY
+  end
+
+  it "assigns the given input and output to the Readline module" do
+    Readline.given_input.should == @driver.input
+    Readline.given_output.should == @driver.output
+  end
+
+  it "assigns a completion object" do
+    Readline.completion_proc.class.should == IRB::Completion
+  end
+
+  it "reads a line through the Readline module" do
+    Readline.stub_input "nom nom nom"
+    @driver.readline.should == "nom nom nom"
+  end
+
+  it "tells the Readline module to use the history" do
+    Readline.use_history = false
+    Readline.stub_input "nom nom nom"
+    @driver.readline
+    Readline.use_history.should == true
+  end
+end

Added: MacRuby/trunk/spec/dietrb/driver/tty_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/driver/tty_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/driver/tty_spec.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -0,0 +1,70 @@
+require File.expand_path('../../spec_helper', __FILE__)
+require 'irb/driver/tty'
+
+describe "IRB::Driver::TTY" do
+  before do
+    @driver = IRB::Driver::TTY.new(InputStub.new, OutputStub.new)
+    @context = IRB::Context.new(Object.new)
+    @driver.context_stack << @context
+  end
+  
+  it "prints the prompt and reads a line of input" do
+    @driver.input.stub_input "calzone"
+    @driver.readline.should == "calzone"
+    @driver.output.printed.should == @context.prompt
+  end
+  
+  it "consumes input" do
+    @driver.input.stub_input "calzone"
+    @driver.consume.should == "calzone"
+  end
+  
+  it "clears the context buffer if an Interrupt signal is received while consuming input" do
+    @context.process_line("class A")
+    def @driver.readline; raise Interrupt; end
+    @driver.consume.should == ""
+    @context.source.to_s.should == ""
+  end
+end
+
+describe "IRB::Driver::TTY, when starting the runloop" do
+  before do
+    @driver = IRB::Driver::TTY.new(InputStub.new, OutputStub.new)
+    IRB::Driver.current = @driver
+    @context = IRB::Context.new(Object.new)
+  end
+  
+  it "makes the given context the current one, for this driver, for the duration of the runloop" do
+    $from_context = nil
+    @driver.input.stub_input "$from_context = IRB::Driver.current.context"
+    @driver.run(@context)
+    $from_context.should == @context
+    IRB::Driver.current.context.should == nil
+  end
+  
+  it "feeds input into a given context" do
+    $from_context = false
+    @driver.input.stub_input "$from_context = true", "exit"
+    @driver.run(@context)
+    $from_context.should == true
+  end
+  
+  it "makes sure there's a global output redirector while running a context" do
+    before = $stdout
+    $from_context = nil
+    @driver.input.stub_input "$from_context = $stdout", "exit"
+    @driver.run(@context)
+    $from_context.class == IRB::Driver::OutputRedirector
+    $stdout.should == before
+  end
+end
+
+# describe "Kernel::irb" do
+#   it "creates a new context for the given object and runs it" do
+#     IRB.io = CaptureIO.new
+#     IRB.io.stub_input("::IRBRan = self")
+#     o = Object.new
+#     irb(o)
+#     IRBRan.should == o
+#   end
+# end
\ No newline at end of file

Added: MacRuby/trunk/spec/dietrb/driver_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/driver_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/driver_spec.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -0,0 +1,65 @@
+require File.expand_path('../spec_helper', __FILE__)
+require 'irb/driver'
+
+describe "IRB::Driver" do
+  before :all do
+    @driver = StubDriver.new
+    IRB::Driver.current = @driver
+  end
+  
+  it "assigns the driver for the current thread" do
+    Thread.current[:irb_driver].should == @driver
+  end
+  
+  it "returns the same driver for child threads" do
+    Thread.new do
+      IRB::Driver.current = other = StubDriver.new
+      Thread.new { IRB::Driver.current.should == other }.join
+    end.join
+    Thread.new { IRB::Driver.current.should == @driver }.join
+  end
+end
+
+describe "IRB::Driver::OutputRedirector" do
+  before :each do
+    @driver = StubDriver.new
+    @driver.output = OutputStub.new
+    IRB::Driver.current = @driver
+    
+    @redirector = IRB::Driver::OutputRedirector.new
+  end
+  
+  it "returns $stderr as the target if no current driver could be found" do
+    IRB::Driver.current = nil
+    IRB::Driver::OutputRedirector.target.should == $stderr
+  end
+  
+  it "returns the current driver's output as the target" do
+    IRB::Driver::OutputRedirector.target.should == @driver.output
+  end
+  
+  it "forwards method calls to the current target" do
+    @redirector.send_to_target(:eql?, @driver.output).should == true
+  end
+  
+  it "writes to the current target's output" do
+    @redirector.write("strawberry coupe")
+    @driver.output.printed.should == "strawberry coupe"
+  end
+  
+  it "returns the amount of bytes written" do
+    @redirector.write("banana coupe").should == 12
+  end
+  
+  it "coerces an object to a string before writing" do
+    o = Object.new
+    def o.to_s; "cherry coupe"; end
+    @redirector.write(o)
+    @driver.output.printed.should == "cherry coupe"
+  end
+  
+  it "forwards puts to the current target's output" do
+    @redirector.puts("double", "coupe")
+    @driver.output.printed.should == "double\ncoupe\n"
+  end
+end
\ No newline at end of file

Modified: MacRuby/trunk/spec/dietrb/ext/completion_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/ext/completion_spec.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/spec/dietrb/ext/completion_spec.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -1,9 +1,11 @@
 require File.expand_path('../../spec_helper', __FILE__)
+require 'irb/driver'
 require 'irb/ext/completion'
 
 module CompletionHelper
   def complete(str)
-    IRB::Completion.new(@context, str).results
+    # IRB::Completion.new(@context, str).results
+    @completion.call(str)
   end
   
   def imethods(klass, receiver = nil)
@@ -35,12 +37,14 @@
 describe "IRB::Completion" do
   extend CompletionHelper
   
-  before do
+  before :all do
+    @completion = IRB::Completion.new
     @context = IRB::Context.new(Playground.new)
+    IRB::Driver.current = StubDriver.new(@context)
   end
   
   it "quacks like a Proc" do
-    IRB::Completion.call('//.').should == imethods(Regexp, '//')
+    @completion.call('//.').should == imethods(Regexp, '//')
   end
   
   describe "when doing a method call on an explicit receiver," do

Modified: MacRuby/trunk/spec/dietrb/ext/history_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/ext/history_spec.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/spec/dietrb/ext/history_spec.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -1,6 +1,10 @@
 require File.expand_path('../../spec_helper', __FILE__)
+require 'readline'
 require "tempfile"
 
+require 'irb/ext/history'
+require 'irb/driver'
+
 describe "IRB::History, by default," do
   it "stores the history in ~/.irb_history" do
     IRB::History.file.should == File.expand_path("~/.irb_history")
@@ -11,7 +15,7 @@
   before do
     @file = Tempfile.new("irb_history.txt")
     IRB::History.file = @file.path
-    @history = IRB::History.new(nil)
+    @history = IRB::History
   end
   
   after do
@@ -54,8 +58,8 @@
     @history.input "puts :ok"
     @history.input "foo(x)"
     
-    IRB::History.new(nil)
-    IRB::History.new(nil)
+    IRB::History.setup
+    IRB::History.setup
     
     Readline::HISTORY.to_a.should == ["puts :ok", "foo(x)"]
   end
@@ -70,25 +74,16 @@
   end
 end
 
-class IRB::History
-  def printed
-    @printed ||= ""
+module IRB::History
+  class << self
+    def clear!
+      @cleared = true
+    end
+    
+    def cleared?
+      @cleared
+    end
   end
-  
-  def print(s)
-    printed << s
-  end
-  
-  def puts(s)
-    printed << "#{s}\n"
-  end
-  
-  def clear!
-    @cleared = true
-  end
-  def cleared?
-    @cleared
-  end
 end
 
 describe "IRB::History, concerning the user api, by default," do
@@ -115,24 +110,22 @@
     
     IRB::History.max_entries_in_overview = 5
     
-    @context = IRB::Context.new(Object.new)
-    IRB::Context.current = @context
+    IRB::History.extend(OutputStubMixin)
+    IRB::History.clear_printed!
     
-    @history = @context.processors.find { |p| p.is_a?(IRB::History) }
+    @context = IRB::Context.new(Object.new)
+    @context.extend(OutputStubMixin)
+    IRB::Driver.current = StubDriver.new(@context)
   end
   
-  after do
-    IRB::Context.current = nil
-  end
-  
   it "returns nil so that IRB doesn't cache some arbitrary line number" do
-    history.should == nil
+    history.should == IRB::Context::IGNORE_RESULT
   end
   
-  it "prints a formatted list with, by default IRB::History.max_entries_in_overview, number of history entries" do
+  it "prints a formatted list with IRB::History.max_entries_in_overview number of history entries" do
     history
     
-    @history.printed.should == %{
+    IRB::History.printed.should == %{
 2: class AAA
 3:   def bar
 4:     :ok
@@ -144,7 +137,7 @@
   it "prints a formatted list of N most recent history entries" do
     history(7)
     
-    @history.printed.should == %{
+    IRB::History.printed.should == %{
 0: puts :ok
 1: x = foo(x)
 2: class AAA
@@ -158,7 +151,7 @@
   it "prints a formatted list of all history entries if the request number of entries is more than there is" do
     history(777)
 
-    @history.printed.should == %{
+    IRB::History.printed.should == %{
 0: puts :ok
 1: x = foo(x)
 2: class AAA
@@ -182,6 +175,6 @@
   
   it "clears the history and history file" do
     clear_history!
-    @history.cleared?.should == true
+    IRB::History.cleared?.should == true
   end
 end
\ No newline at end of file

Modified: MacRuby/trunk/spec/dietrb/formatter_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/formatter_spec.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/spec/dietrb/formatter_spec.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -40,13 +40,15 @@
   
   it "does not filter the backtrace if $DEBUG is true" do
     begin
-      before, $DEBUG = $DEBUG, true
+      stderr, $stderr = $stderr, OutputStub.new
+      debug, $DEBUG = $DEBUG, true
       
       begin; @context.__evaluate__('DoesNotExist'); rescue NameError => e; exception = e; end
       @formatter.exception(exception).should ==
         "NameError: uninitialized constant IRB::Context::DoesNotExist\n\t#{exception.backtrace.join("\n\t")}"
     ensure
-      $DEBUG = before
+      $stderr = stderr
+      $DEBUG = debug
     end
   end
   
@@ -67,7 +69,7 @@
     def object.inspect; @inspected = true; "Never called!"; end
     def object.__id__; 2158110700; end
     
-    @formatter.result(object).should == "=> #<Object:0x101444fd8>"
+    @formatter.result(object).should == "=> #<#{object.class.name}:0x101444fd8>"
     object.instance_variable_get(:@inspected).should_not == true
   end
   

Modified: MacRuby/trunk/spec/dietrb/spec_helper.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/spec_helper.rb	2010-07-24 03:06:27 UTC (rev 4375)
+++ MacRuby/trunk/spec/dietrb/spec_helper.rb	2010-07-24 15:11:24 UTC (rev 4376)
@@ -14,4 +14,62 @@
 end
 $:.unshift File.join(ROOT, 'lib')
 
-require 'irb'
\ No newline at end of file
+require 'irb'
+
+module InputStubMixin
+  def stub_input(*input)
+    @input = input
+  end
+  
+  def readline(prompt)
+    # print prompt
+    @input.shift
+  end
+  
+  def gets
+    @input.shift
+  end
+end
+
+class InputStub
+  include InputStubMixin
+end
+
+module OutputStubMixin
+  def printed
+    @printed ||= ''
+  end
+  
+  def write(string)
+    printed << string
+  end
+  
+  def print(string)
+    printed << string
+  end
+  
+  def puts(*args)
+    print "#{args.join("\n")}\n"
+  end
+  
+  def clear_printed!
+    @printed = ''
+  end
+end
+
+class OutputStub
+  include OutputStubMixin
+end
+
+class StubDriver
+  attr_reader :context
+  attr_writer :output
+  
+  def initialize(context = nil)
+    @context = context
+  end
+  
+  def output
+    @output || $stdout
+  end
+end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100724/fa8b8bde/attachment-0001.html>


More information about the macruby-changes mailing list