[macruby-changes] [4317] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sun Jul 4 05:32:30 PDT 2010


Revision: 4317
          http://trac.macosforge.org/projects/ruby/changeset/4317
Author:   eloy.de.enige at gmail.com
Date:     2010-07-04 05:32:27 -0700 (Sun, 04 Jul 2010)
Log Message:
-----------
Update DietRB to 75ec79, which includes the specs: $ rake spec:irb

Modified Paths:
--------------
    MacRuby/trunk/lib/irb/formatter.rb
    MacRuby/trunk/rakelib/spec.rake
    MacRuby/trunk/spec/macruby.mspec

Added Paths:
-----------
    MacRuby/trunk/spec/dietrb/
    MacRuby/trunk/spec/dietrb/context_spec.rb
    MacRuby/trunk/spec/dietrb/ext/
    MacRuby/trunk/spec/dietrb/ext/colorize_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/regression/
    MacRuby/trunk/spec/dietrb/regression/context_spec.rb
    MacRuby/trunk/spec/dietrb/source_spec.rb
    MacRuby/trunk/spec/dietrb/spec_helper.rb

Modified: MacRuby/trunk/lib/irb/formatter.rb
===================================================================
--- MacRuby/trunk/lib/irb/formatter.rb	2010-07-02 13:13:23 UTC (rev 4316)
+++ MacRuby/trunk/lib/irb/formatter.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -38,7 +38,9 @@
     
     def inspect_object(object)
       if @inspect
-        object.respond_to?(:pretty_inspect) ? object.pretty_inspect : object.inspect
+        result = object.respond_to?(:pretty_inspect) ? object.pretty_inspect : object.inspect
+        result.strip!
+        result
       else
         address = object.__id__ * 2
         address += 0x100000000 if address < 0

Modified: MacRuby/trunk/rakelib/spec.rake
===================================================================
--- MacRuby/trunk/rakelib/spec.rake	2010-07-02 13:13:23 UTC (rev 4316)
+++ MacRuby/trunk/rakelib/spec.rake	2010-07-04 12:32:27 UTC (rev 4317)
@@ -44,6 +44,11 @@
     mspec :ci, ":library"
   end
   
+  desc "Run the DietRB specs"
+  task :irb do
+    mspec :ci, "./spec/dietrb"
+  end
+  
   desc "Run language examples that are known to fail"
   task :fails do
     mspec :run, "-g fails :full"

Added: MacRuby/trunk/spec/dietrb/context_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/context_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/context_spec.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -0,0 +1,244 @@
+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
+  end
+end
+
+main = self
+
+describe "IRB::Context" do
+  before do
+    @context = IRB::Context.new(main)
+  end
+  
+  it "initializes with an object and stores a copy of its binding" do
+    @context.object.should == main
+    eval("self", @context.binding).should == main
+    eval("x = :ok", @context.binding)
+    eval("y = x", @context.binding)
+    eval("y", @context.binding).should == :ok
+  end
+  
+  it "initializes with an object and an explicit binding" do
+    context = IRB::Context.new(Object.new, TOPLEVEL_BINDING)
+    eval("class InTopLevel; end", context.binding)
+    lambda { ::InTopLevel }.should_not raise_error(NameError)
+  end
+  
+  it "initializes with an 'empty' state" do
+    @context.line.should == 1
+    @context.source.class.should == IRB::Source
+    @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
+    IRB.formatter = IRB::Formatter.new
+  end
+  
+  it "evaluates code with the object's binding" do
+    @context.__evaluate__("self").should == main
+  end
+  
+  it "prints the result" do
+    @context.evaluate("Hash[:foo, :foo]")
+    @context.printed.should == "=> {:foo=>:foo}\n"
+  end
+  
+  it "assigns the result to the local variable `_'" do
+    result = @context.evaluate("Object.new")
+    @context.evaluate("_").should == result
+    @context.evaluate("_").should == result
+  end
+  
+  it "coerces the given source to a string first" do
+    o = Object.new
+    def o.to_s; "self"; end
+    @context.evaluate(o).should == main
+  end
+  
+  it "rescues any type of exception" do
+    lambda {
+      @context.evaluate("DoesNotExist")
+      @context.evaluate("raise Exception")
+    }.should_not.raise_error
+  end
+  
+  it "assigns the last raised exception to the global variable `$EXCEPTION' / `$e'" do
+    @context.evaluate("DoesNotExist")
+    $EXCEPTION.class.should == NameError
+    $EXCEPTION.message.should include('DoesNotExist')
+    $e.should == $EXCEPTION
+  end
+  
+  it "prints the exception that occurs" do
+    @context.evaluate("DoesNotExist")
+    @context.printed.should =~ /^NameError:.+DoesNotExist/
+  end
+  
+  it "uses the line number of the *first* line in the buffer, for the line parameter of eval" do
+    @context.process_line("DoesNotExist")
+    @context.printed.should =~ /\(irb\):1:in/
+    @context.process_line("class A")
+    @context.process_line("DoesNotExist")
+    @context.process_line("end")
+    @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
+  end
+end
+
+describe "IRB::Context, when receiving input" do
+  before do
+    @context = IRB::Context.new(main)
+  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
+  end
+  
+  it "increases the current line number" do
+    @context.line.should == 1
+    @context.process_line("def foo")
+    @context.line.should == 2
+    @context.process_line("p :ok")
+    @context.line.should == 3
+  end
+  
+  it "evaluates the buffered source once it's a valid code block" do
+    def @context.evaluate(source); @evaled = source; end
+    
+    @context.process_line("def foo")
+    @context.process_line(":ok")
+    @context.process_line("end; p foo")
+    
+    source = @context.instance_variable_get(:@evaled)
+    source.to_s.should == "def foo\n:ok\nend; p foo"
+  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 '}'"
+  end
+  
+  it "returns whether or not the runloop should continue, but only if the level is 0" do
+    @context.process_line("def foo").should == true
+    @context.process_line("quit").should == true
+    @context.process_line("end").should == true
+    
+    @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"
+  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/ext/colorize_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/ext/colorize_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/ext/colorize_spec.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -0,0 +1,58 @@
+require File.expand_path('../../spec_helper', __FILE__)
+require 'irb/ext/colorize'
+
+main = self
+  
+describe "IRB::ColoredFormatter" do
+  before do
+    @formatter = IRB::ColoredFormatter.new
+    @context = IRB::Context.new(main)
+  end
+  
+  it "colorizes a constant" do
+    @formatter.result(Hash).should == "=> \e[1;32mHash\e[0;0m"
+  end
+  
+  it "colorizes a numeric" do
+    @formatter.result(1).should == "=> \e[0;36m1\e[0;0m"
+    @formatter.result(1.2).should == "=> \e[0;36m1.2\e[0;0m"
+  end
+  
+  # Not Wirble compliant
+  it "colorizes a Range" do
+    # @formatter.result(1..3).should == "=> \e[0;36m1\e[0;0m\e[0;31m..\e[0;0m\e[0;36m3\e[0;0m"
+    @formatter.result(1..3).should == "=> \e[0;36m1\e[0;0m\e[0;34m..\e[0;0m\e[0;36m3\e[0;0m"
+  end
+  
+  it "colorizes a String" do
+    @formatter.result("foo bar").should == "=> \e[0;31m\"\e[0;0m\e[0;36mfoo bar\e[0;0m\e[0;31m\"\e[0;0m"
+  end
+  
+  it "colorizes a Hash" do
+    @formatter.result(:ok => :foo).should == "=> \e[0;32m{\e[0;0m\e[1;33m:\e[0;0m\e[1;33mok\e[0;0m\e[0;34m=>\e[0;0m\e[1;33m:\e[0;0m\e[1;33mfoo\e[0;0m\e[0;32m}\e[0;0m"
+  end
+  
+  it "colorizes an Array" do
+    @formatter.result([1, 2]).should == "=> \e[0;32m[\e[0;0m\e[0;36m1\e[0;0m\e[0;34m,\e[0;0m \e[0;36m2\e[0;0m\e[0;32m]\e[0;0m"
+  end
+  
+  it "colorizes the prompt" do
+    @formatter.colors[:prompt] = :light_green
+    @formatter.prompt(@context).should == "\e[1;32m#{IRB::Formatter.new.prompt(@context)}\e[0;0m"
+  end
+  
+  it "colorizes the result prefix" do
+    @formatter.colors[:result_prefix] = :light_red
+    @formatter.result("").should == "\e[1;31m=>\e[0;0m \e[0;31m\"\e[0;0m\e[0;31m\"\e[0;0m"
+  end
+  
+  it "uses the dark_background color scheme by default" do
+    @formatter.color_scheme.should == :dark_background
+  end
+  
+  it "changes color scheme" do
+    @formatter.color_scheme = :fresh
+    @formatter.color_scheme.should == :fresh
+    @formatter.colors[:result_prefix].should == :light_purple
+  end
+end
\ No newline at end of file

Added: MacRuby/trunk/spec/dietrb/ext/completion_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/ext/completion_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/ext/completion_spec.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -0,0 +1,237 @@
+require File.expand_path('../../spec_helper', __FILE__)
+require 'irb/ext/completion'
+
+module CompletionHelper
+  def complete(str)
+    IRB::Completion.new(@context, str).results
+  end
+  
+  def imethods(klass, receiver = nil)
+    klass.instance_methods.map { |m| [receiver, m.to_s].compact.join('.') }.sort
+  end
+  
+  def methods(object, receiver = nil)
+    object.methods.map { |m| [receiver, m.to_s].compact.join('.') }.sort
+  end
+end
+
+class CompletionStub
+  def self.a_cmethod
+  end
+  
+  def an_imethod
+  end
+end
+
+class Playground
+  CompletionStub = Object.new
+  def CompletionStub.a_singleton_method; end
+  
+  def a_local_method; end
+end
+
+$a_completion_stub = CompletionStub.new
+
+describe "IRB::Completion" do
+  extend CompletionHelper
+  
+  before do
+    @context = IRB::Context.new(Playground.new)
+  end
+  
+  it "quacks like a Proc" do
+    IRB::Completion.call('//.').should == imethods(Regexp, '//')
+  end
+  
+  describe "when doing a method call on an explicit receiver," do
+    describe "and the source ends with a period," do
+      describe "returns *all* public methods of the receiver that" do
+        it "matches as a local variable" do
+          @context.__evaluate__('foo = ::CompletionStub.new')
+          complete('foo.').should == imethods(::CompletionStub, 'foo')
+          
+          @context.__evaluate__('def foo.singleton_method; end')
+          complete('foo.').should include('foo.singleton_method')
+        end
+        
+        it "matches as a global variable" do
+          complete('$a_completion_stub.').should == imethods(::CompletionStub, '$a_completion_stub')
+        end
+        
+        # TODO: fix
+        # it "matches as a local constant" do
+        #   complete('CompletionStub.').should == methods(Playground::CompletionStub)
+        # end
+        
+        it "matches as a top level constant" do
+          complete('::CompletionStub.').should == methods(::CompletionStub, '::CompletionStub')
+        end
+      end
+      
+      describe "returns *all* public instance methods of the class (the receiver) that" do
+        it "matches as a Regexp literal" do
+          complete('//.').should == imethods(Regexp, '//')
+          complete('/^(:[^:.]+)\.([^.]*)$/.').should == imethods(Regexp, '/^(:[^:.]+)\.([^.]*)$/')
+          complete('/^(#{oops})\.([^.]*)$/.').should == imethods(Regexp, '/^(#{oops})\.([^.]*)$/')
+          complete('%r{/foo/.*/bar}.').should == imethods(Regexp, '%r{/foo/.*/bar}')
+        end
+        
+        it "matches as an Array literal" do
+          complete('[].').should == imethods(Array, '[]')
+          complete('[:ok, {}, "foo",].').should == imethods(Array, '[:ok, {}, "foo",]')
+          complete('[*foo].').should == imethods(Array, '[*foo]')
+          complete('%w{foo}.').should == imethods(Array, '%w{foo}')
+          complete('%W{#{:foo}}.').should == imethods(Array, '%W{#{:foo}}')
+        end
+        
+        # fails on MacRuby
+        it "matches as a lambda literal" do
+          complete('->{}.').should == imethods(Proc, '->{}')
+          complete('->{x=:ok}.').should == imethods(Proc, '->{x=:ok}')
+          complete('->(x){x=:ok}.').should == imethods(Proc, '->(x){x=:ok}')
+        end
+        
+        it "matches as a Hash literal" do
+          complete('{}.').should == imethods(Hash, '{}')
+          complete('{:foo=>:bar,}.').should == imethods(Hash, '{:foo=>:bar,}')
+          complete('{foo:"bar"}.').should == imethods(Hash, '{foo:"bar"}')
+        end
+        
+        it "matches as a Symbol literal" do
+          complete(':foo.').should == imethods(Symbol, ':foo')
+          complete(':"foo.bar".').should == imethods(Symbol, ':"foo.bar"')
+          complete(':"foo.#{"bar"}".').should == imethods(Symbol, ':"foo.#{"bar"}"')
+          complete(':\'foo.#{"bar"}\'.').should == imethods(Symbol, ':\'foo.#{"bar"}\'')
+          complete('%s{foo.bar}.').should == imethods(Symbol, '%s{foo.bar}')
+        end
+        
+        it "matches as a String literal" do
+          complete("'foo\\'bar'.").should == imethods(String, "'foo\\'bar'")
+          complete('"foo\"bar".').should == imethods(String, '"foo\"bar"')
+          complete('"foo#{"bar"}".').should == imethods(String, '"foo#{"bar"}"')
+          complete('%{foobar}.').should == imethods(String, '%{foobar}')
+          complete('%q{foo#{:bar}}.').should == imethods(String, '%q{foo#{:bar}}')
+          complete('%Q{foo#{:bar}}.').should == imethods(String, '%Q{foo#{:bar}}')
+        end
+        
+        it "matches as a Range literal" do
+          complete('1..10.').should == imethods(Range, '1..10')
+          complete('1...10.').should == imethods(Range, '1...10')
+          complete('"a".."z".').should == imethods(Range, '"a".."z"')
+          complete('"a"..."z".').should == imethods(Range, '"a"..."z"')
+        end
+        
+        it "matches as a Fixnum literal" do
+          complete('42.').should == imethods(Fixnum, '42')
+          complete('+42.').should == imethods(Fixnum, '+42')
+          complete('-42.').should == imethods(Fixnum, '-42')
+          complete('42_000.').should == imethods(Fixnum, '42_000')
+        end
+        
+        it "matches as a Bignum literal as a Fixnum" do
+          complete('100_000_000_000_000_000_000.').should == imethods(Fixnum, '100_000_000_000_000_000_000')
+          complete('-100_000_000_000_000_000_000.').should == imethods(Fixnum, '-100_000_000_000_000_000_000')
+          complete('+100_000_000_000_000_000_000.').should == imethods(Fixnum, '+100_000_000_000_000_000_000')
+        end
+        
+        it "matches as a Float with exponential literal" do
+          complete('1.2e-3.').should == imethods(Float, '1.2e-3')
+          complete('+1.2e-3.').should == imethods(Float, '+1.2e-3')
+          complete('-1.2e-3.').should == imethods(Float, '-1.2e-3')
+        end
+        
+        it "matches as a hex literal as a Fixnum" do
+          complete('0xffff.').should == imethods(Fixnum, '0xffff')
+          complete('+0xffff.').should == imethods(Fixnum, '+0xffff')
+          complete('-0xffff.').should == imethods(Fixnum, '-0xffff')
+        end
+        
+        it "matches as a binary literal as a Fixnum" do
+          complete('0b01011.').should == imethods(Fixnum, '0b01011')
+          complete('-0b01011.').should == imethods(Fixnum, '-0b01011')
+          complete('+0b01011.').should == imethods(Fixnum, '+0b01011')
+        end
+        
+        it "matches as an octal literal as a Fixnum" do
+          complete('0377.').should == imethods(Fixnum, '0377')
+          complete('-0377.').should == imethods(Fixnum, '-0377')
+          complete('+0377.').should == imethods(Fixnum, '+0377')
+        end
+        
+        it "matches as a Float literal" do
+          complete('42.0.').should == imethods(Float, '42.0')
+          complete('-42.0.').should == imethods(Float, '-42.0')
+          complete('+42.0.').should == imethods(Float, '+42.0')
+          complete('42_000.0.').should == imethods(Float, '42_000.0')
+        end
+        
+        it "matches as a Bignum float literal as a Float" do
+          complete('100_000_000_000_000_000_000.0.').should == imethods(Float, '100_000_000_000_000_000_000.0')
+          complete('+100_000_000_000_000_000_000.0.').should == imethods(Float, '+100_000_000_000_000_000_000.0')
+          complete('-100_000_000_000_000_000_000.0.').should == imethods(Float, '-100_000_000_000_000_000_000.0')
+        end
+      end
+      
+      it "returns *all* public instance methods of the class (the receiver) that ::new is called on" do
+        complete("Playground.new.").should == imethods(Playground, 'Playground.new')
+        complete("Playground.new.a_local_m").should == %w{ Playground.new.a_local_method }
+        
+        @context.__evaluate__("klass = Playground")
+        complete("klass.new.").should == imethods(Playground, 'klass.new')
+        complete("klass.new.a_local_m").should == %w{ klass.new.a_local_method }
+      end
+    end
+    
+    describe "and the source does *not* end with a period," do
+      it "filters the methods, of the literal receiver, by the given method name" do
+        complete('//.nam').should == %w{ //.named_captures //.names }
+        complete('//.named').should == %w{ //.named_captures }
+      end
+      
+      it "filters the methods, of the variable receiver, by the given method name" do
+        @context.__evaluate__('foo = ::CompletionStub.new')
+        complete('foo.an_im').should == %w{ foo.an_imethod }
+        complete('$a_completion_stub.an_im').should == %w{ $a_completion_stub.an_imethod }
+        # TODO: fix
+        # complete('CompletionStub.a_sing').should == %w{ CompletionStub.a_singleton_method }
+      end
+    end
+  end
+  
+  describe "when *not* doing a method call on an explicit receiver" do
+    before do
+      @context.__evaluate__("a_local_variable = :ok")
+    end
+    
+    it "matches local variables" do
+      complete("a_local_v").should == %w{ a_local_variable }
+    end
+    
+    it "matches instance methods of the context object" do
+      complete("a_local_m").should == %w{ a_local_method }
+    end
+    
+    it "matches local variables and instance method of the context object" do
+      complete("a_loc").should == %w{ a_local_method a_local_variable }
+    end
+    
+    it "matches global variables" do
+      complete("$a_completion_s").should == %w{ $a_completion_stub }
+    end
+    
+    it "matches constants" do
+      complete("Playgr").should == %w{ Playground }
+    end
+    
+    it "matches top level constants" do
+      complete("::CompletionSt").should == %w{ ::CompletionStub }
+    end
+  end
+  
+  it "completes reserved words as variables or constants" do
+    (IRB::Completion::RESERVED_DOWNCASE_WORDS +
+      IRB::Completion::RESERVED_UPCASE_WORDS).each do |word|
+      complete(word[0..-2]).should include(word)
+    end
+  end
+end
\ No newline at end of file

Added: MacRuby/trunk/spec/dietrb/ext/history_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/ext/history_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/ext/history_spec.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -0,0 +1,187 @@
+require File.expand_path('../../spec_helper', __FILE__)
+require "tempfile"
+
+describe "IRB::History, by default," do
+  it "stores the history in ~/.irb_history" do
+    IRB::History.file.should == File.expand_path("~/.irb_history")
+  end
+end
+
+describe "IRB::History" do
+  before do
+    @file = Tempfile.new("irb_history.txt")
+    IRB::History.file = @file.path
+    @history = IRB::History.new(nil)
+  end
+  
+  after do
+    @file.close
+  end
+  
+  it "adds input to the history file" do
+    @history.input "puts :ok"
+    @file.rewind; @file.read.should == "puts :ok\n"
+    @history.input "foo(x)"
+    @file.rewind; @file.read.should == "puts :ok\nfoo(x)\n"
+  end
+  
+  it "returns the same input value" do
+    @history.input("foo(x)").should == "foo(x)"
+  end
+  
+  it "returns the contents of the history file as an array of lines" do
+    @history.input "puts :ok"
+    @history.to_a.should == ["puts :ok"]
+    @history.input "foo(x)"
+    @history.to_a.should == ["puts :ok", "foo(x)"]
+  end
+  
+  it "returns an empty array if the history file doesn't exist yet and create it once input is added" do
+    @file.close
+    FileUtils.rm(@file.path)
+    
+    @history.to_a.should == []
+    File.exist?(@file.path).should == false
+    
+    @history.input "puts :ok"
+    File.exist?(@file.path).should == true
+    @history.to_a.should == ["puts :ok"]
+  end
+  
+  it "stores the contents of the history file in Readline::HISTORY once" do
+    Readline::HISTORY.clear
+    
+    @history.input "puts :ok"
+    @history.input "foo(x)"
+    
+    IRB::History.new(nil)
+    IRB::History.new(nil)
+    
+    Readline::HISTORY.to_a.should == ["puts :ok", "foo(x)"]
+  end
+  
+  it "clears the history and history file" do
+    @history.input "puts :ok"
+    @history.input "foo(x)"
+    @history.clear!
+    
+    @file.rewind; @file.read.should == ""
+    Readline::HISTORY.to_a.should == []
+  end
+end
+
+class IRB::History
+  def printed
+    @printed ||= ""
+  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
+  it "shows a maximum of 50 history entries" do
+    IRB::History.max_entries_in_overview.should == 50
+  end
+end
+
+describe "IRB::History, concerning the user api," do
+  before do
+    sources = [
+      "puts :ok",
+      "x = foo(x)",
+      "class AAA",
+      "  def bar",
+      "    :ok",
+      "  end",
+      "end",
+      "THIS LINE REPRESENTS THE ENTERED COMMAND AND SHOULD BE OMITTED!"
+    ]
+    
+    Readline::HISTORY.clear
+    sources.each { |source| Readline::HISTORY.push(source) }
+    
+    IRB::History.max_entries_in_overview = 5
+    
+    @context = IRB::Context.new(Object.new)
+    IRB::Context.current = @context
+    
+    @history = @context.processors.find { |p| p.is_a?(IRB::History) }
+  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
+  end
+  
+  it "prints a formatted list with, by default IRB::History.max_entries_in_overview, number of history entries" do
+    history
+    
+    @history.printed.should == %{
+2: class AAA
+3:   def bar
+4:     :ok
+5:   end
+6: end
+}.sub(/\n/, '')
+  end
+  
+  it "prints a formatted list of N most recent history entries" do
+    history(7)
+    
+    @history.printed.should == %{
+0: puts :ok
+1: x = foo(x)
+2: class AAA
+3:   def bar
+4:     :ok
+5:   end
+6: end
+}.sub(/\n/, '')
+  end
+  
+  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 == %{
+0: puts :ok
+1: x = foo(x)
+2: class AAA
+3:   def bar
+4:     :ok
+5:   end
+6: end
+}.sub(/\n/, '')
+  end
+  
+  it "evaluates the history entry specified" do
+    @context.__evaluate__("x = 2; def foo(x); x * 2; end")
+    history! 1
+    @context.__evaluate__("x").should == 4
+  end
+  
+  it "evaluates the history entries specified by a range" do
+    history! 2..6
+    @context.__evaluate__("AAA.new.bar").should == :ok
+  end
+  
+  it "clears the history and history file" do
+    clear_history!
+    @history.cleared?.should == true
+  end
+end
\ No newline at end of file

Added: MacRuby/trunk/spec/dietrb/formatter_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/formatter_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/formatter_spec.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -0,0 +1,78 @@
+require File.expand_path('../spec_helper', __FILE__)
+
+main = self
+
+describe "IRB::Formatter" do
+  before do
+    @formatter = IRB::Formatter.new
+    @context = IRB::Context.new(main)
+  end
+  
+  it "returns a prompt string, displaying line number and code indentation level" do
+    @formatter.prompt(@context).should == "irb(main):001:0> "
+    @context.instance_variable_set(:@line, 23)
+    @formatter.prompt(@context).should == "irb(main):023:0> "
+    @context.source << "def foo"
+    @formatter.prompt(@context).should == "irb(main):023:1> "
+  end
+  
+  it "describes the context's object in the prompt" do
+    o = Object.new
+    @formatter.prompt(IRB::Context.new(o)).should == "irb(#{o.inspect}):001:0> "
+  end
+  
+  it "returns a very simple prompt if specified" do
+    @formatter.prompt = :simple
+    @formatter.prompt(@context).should == ">> "
+  end
+  
+  it "returns no prompt if specified" do
+    @formatter.prompt = nil
+    @formatter.prompt(@context).should == ""
+  end
+  
+  it "returns a formatted exception message, with the lines, regarding dietrb, filtered out of the backtrace" do
+    begin; @context.__evaluate__('DoesNotExist'); rescue NameError => e; exception = e; end
+    backtrace = exception.backtrace.reject { |f| f =~ /#{ROOT}/ }
+    @formatter.exception(exception).should ==
+      "NameError: uninitialized constant IRB::Context::DoesNotExist\n\t#{backtrace.join("\n\t")}"
+  end
+  
+  it "does not filter the backtrace if $DEBUG is true" do
+    begin
+      before, $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
+    end
+  end
+  
+  it "prints the result" do
+    @formatter.result(:foo => :foo).should == "=> {:foo=>:foo}"
+  end
+  
+  it "prints the result with object#pretty_inspect, if it responds to it" do
+    object = Object.new
+    def object.pretty_inspect; "foo"; end
+    @formatter.result(object).should == "=> foo"
+  end
+  
+  it "prints only the class name and memory address in `no inspect' mode" do
+    @formatter.inspect = false
+    
+    object = Object.new
+    def object.inspect; @inspected = true; "Never called!"; end
+    def object.__id__; 2158110700; end
+    
+    @formatter.result(object).should == "=> #<Object:0x101444fd8>"
+    object.instance_variable_get(:@inspected).should_not == true
+  end
+  
+  it "prints that a syntax error occurred on the last line and reset the buffer to the previous line" do
+    @formatter.syntax_error(2, "syntax error, unexpected '}'").should ==
+      "SyntaxError: compile error\n(irb):2: syntax error, unexpected '}'"
+  end
+end
\ No newline at end of file

Added: MacRuby/trunk/spec/dietrb/regression/context_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/regression/context_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/regression/context_spec.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -0,0 +1,16 @@
+require File.expand_path('../../spec_helper', __FILE__)
+
+main = self
+
+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
+  end
+  
+  it "does not assign the result to the `_' variable in one go, so it doesn't show up in a syntax error" do
+    @context.evaluate("'banana;")
+    @context.printed.should_not include("_ = ('banana;)")
+  end
+end
\ No newline at end of file

Added: MacRuby/trunk/spec/dietrb/source_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/source_spec.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/source_spec.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -0,0 +1,196 @@
+require File.expand_path('../spec_helper', __FILE__)
+
+describe "IRB::Source" do
+  before do
+    @source = IRB::Source.new
+  end
+  
+  it "initializes with an empty buffer" do
+    @source.buffer.should == []
+  end
+  
+  it "appends source to the buffer, removing trailing newlines" do
+    @source << "foo\n"
+    @source << "bar\r\n"
+    @source.buffer.should == %w{ foo bar }
+  end
+  
+  it "ignores empty strings" do
+    @source << ""
+    @source << " \n"
+    @source.buffer.should == []
+  end
+  
+  it "removes the last line from the buffer" do
+    @source << "foo\n"
+    @source << "bar\r\n"
+    @source.pop.should == "bar"
+    @source.buffer.should == %w{ foo }
+  end
+  
+  it "returns the full buffered source, joined by newlines" do
+    @source.source.should == ""
+    @source << "foo\n"
+    @source.source.should == "foo"
+    @source << "bar\r\n"
+    @source.source.should == "foo\nbar"
+  end
+  
+  it "aliases #to_s to #source" do
+    @source << "foo"
+    @source << "bar"
+    @source.to_s.should == "foo\nbar"
+  end
+  
+  it "returns that the accumulated source is a valid code block" do
+    [
+      ["def foo", "p :ok", "end"],
+      ["class A; def", "foo(x); p x", "end; end"]
+    ].each do |buffer|
+      IRB::Source.new(buffer).code_block?.should == true
+    end
+  end
+  
+  it "returns that the accumulated source is not a valid code block" do
+    [
+      ["def foo", "p :ok"],
+      ["class A; def", "foo(x); p x", "end"]
+    ].each do |buffer|
+      IRB::Source.new(buffer).code_block?.should == false
+    end
+  end
+  
+  it "returns whether or not the accumulated source contains a syntax error" do
+    @source.syntax_error?.should == false
+    @source << "def foo"
+    @source.syntax_error?.should == false
+    @source << "  def;"
+    @source.syntax_error?.should == true
+  end
+  
+  it "returns the current code block indentation level" do
+    @source.level.should == 0
+    @source << "class A"
+    @source.level.should == 1
+    @source << "  def foo"
+    @source.level.should == 2
+    @source << "    p :ok"
+    @source.level.should == 2
+    @source << "  end"
+    @source.level.should == 1
+    @source << "  class B"
+    @source.level.should == 2
+    @source << "    def bar"
+    @source.level.should == 3
+    @source << "      p :ok; end"
+    @source.level.should == 2
+    @source << "  end; end"
+    @source.level.should == 0
+  end
+  
+  it "caches the reflection when possible" do
+    @source << "def foo"
+    reflection = @source.reflect
+    @source.level
+    @source.code_block?
+    @source.reflect.should == reflection
+    
+    @source << "end"
+    @source.level
+    new_reflection = @source.reflect
+    new_reflection.should_not == reflection
+    @source.code_block?
+    @source.reflect.should == new_reflection
+    
+    reflection = new_reflection
+    
+    @source.pop
+    @source.level
+    new_reflection = @source.reflect
+    new_reflection.should_not == reflection
+    @source.syntax_error?
+    @source.reflect.should == new_reflection
+  end
+end
+
+describe "IRB::Source::Reflector" do
+  def reflect(source)
+    IRB::Source::Reflector.new(source)
+  end
+  
+  it "returns whether or not the source is a valid code block" do
+    reflect("def foo").code_block?.should == false
+    reflect("def foo; p :ok").code_block?.should == false
+    reflect("def foo; p :ok; end").code_block?.should == true
+    
+    reflect("if true").code_block?.should == false
+    reflect("p :ok if true").code_block?.should == true
+  end
+
+  it "returns whether or not the current session should be terminated" do
+    reflect("exit").terminate?.should == true
+    reflect("quit").terminate?.should == true
+    reflect("def foo; end; exit").terminate?.should == true
+    reflect("def foo; end; quit").terminate?.should == true
+
+    reflect("def foo; exit; end").terminate?.should == false
+    reflect("def foo; quit; end").terminate?.should == false
+  end
+  
+  it "returns whether or not the source contains a syntax error, except a code block not ending" do
+    reflect("def;").syntax_error?.should == true
+    reflect("def;").syntax_error?.should == true
+    reflect("def foo").syntax_error?.should == false
+    reflect("class A; }").syntax_error?.should == true
+    reflect("class A; {" ).syntax_error?.should == false
+    reflect("class A def foo").syntax_error?.should == true
+    reflect("class A; def foo" ).syntax_error?.should == false
+  end
+  
+  it "returns the actual syntax error message if one occurs" do
+    reflect("def foo").syntax_error.should == nil
+    reflect("}").syntax_error.should == "syntax error, unexpected '}'"
+  end
+  
+  it "returns the code block indentation level" do
+    reflect("").level.should == 0
+    reflect("class A").level.should == 1
+    reflect("class A; def foo").level.should == 2
+    reflect("class A; def foo; p :ok").level.should == 2
+    reflect("class A; def foo; p :ok; end").level.should == 1
+    reflect("class A; class B").level.should == 2
+    reflect("class A; class B; def bar").level.should == 3
+    reflect("class A; class B; def bar; p :ok; end").level.should == 2
+    reflect("class A; class B; def bar; p :ok; end; end; end").level.should == 0
+  end
+  
+  it "correctly increases and decreases the code block indentation level for keywords" do
+    [
+      "class A",
+      "module A",
+      "def foo",
+      "begin",
+      "if x == :ok",
+      "unless x == :ko",
+      "case x",
+      "while x",
+      "for x in xs",
+      "x.each do"
+    ].each do |open|
+      reflect(open).level.should == 1
+      reflect("#{open}\nend").level.should == 0
+    end
+  end
+  
+  it "correctly increases and decreases the code block indentation level for literals" do
+    [
+      ["lambda { |x|", "}"],
+      ["{", "}"],
+      ['"#{', '}"'],
+      ["[", "]"]
+    ].each do |open, close|
+      reflect(open).level.should == 1
+      reflect("#{open}\n#{close}").level.should == 0
+    end
+  end
+end

Added: MacRuby/trunk/spec/dietrb/spec_helper.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/spec_helper.rb	                        (rev 0)
+++ MacRuby/trunk/spec/dietrb/spec_helper.rb	2010-07-04 12:32:27 UTC (rev 4317)
@@ -0,0 +1,17 @@
+unless defined?(MSpec)
+  require 'rubygems'
+  require 'mspec'
+end
+
+ENV['SPECCING'] = 'true'
+
+root = File.expand_path('../../', __FILE__)
+if File.basename(root) == 'spec'
+  # running from the MacRuby repo
+  ROOT = File.expand_path('../../../', __FILE__)
+else
+  ROOT = root
+end
+$:.unshift File.join(ROOT, 'lib')
+
+require 'irb'
\ No newline at end of file

Modified: MacRuby/trunk/spec/macruby.mspec
===================================================================
--- MacRuby/trunk/spec/macruby.mspec	2010-07-02 13:13:23 UTC (rev 4316)
+++ MacRuby/trunk/spec/macruby.mspec	2010-07-04 12:32:27 UTC (rev 4317)
@@ -68,9 +68,11 @@
     ENV['DYLD_LIBRARY_PATH'] = source_root
     # Setup the proper load paths for lib and extensions
     load_paths = %w{ -I. -I./lib -I./ext }
+    load_paths << '-I./ext/ripper/lib' # ripper specific load path fix
     load_paths.concat Dir.glob('./ext/**/*.bundle').map { |filename| "-I#{File.dirname(filename)}" }.uniq
     load_paths.concat(get(:flags)) if get(:flags)
     set :flags, load_paths
+    
     # The default implementation to run the specs.
     set :target, File.join(source_root, 'macruby')
   end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100704/13bdca19/attachment-0001.html>


More information about the macruby-changes mailing list