[macruby-changes] [4862] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sun Oct 31 16:03:20 PDT 2010


Revision: 4862
          http://trac.macosforge.org/projects/ruby/changeset/4862
Author:   eloy.de.enige at gmail.com
Date:     2010-10-31 16:03:17 -0700 (Sun, 31 Oct 2010)
Log Message:
-----------
Update DietRB to r4861, which adds auto-indentation.

Revision Links:
--------------
    http://trac.macosforge.org/projects/ruby/changeset/4861

Modified Paths:
--------------
    MacRuby/trunk/lib/irb/context.rb
    MacRuby/trunk/lib/irb/deprecated.rb
    MacRuby/trunk/lib/irb/driver/tty.rb
    MacRuby/trunk/lib/irb/ext/colorize.rb
    MacRuby/trunk/lib/irb/formatter.rb
    MacRuby/trunk/lib/irb/source.rb
    MacRuby/trunk/spec/dietrb/context_spec.rb
    MacRuby/trunk/spec/dietrb/driver/readline_spec.rb
    MacRuby/trunk/spec/dietrb/driver/tty_spec.rb
    MacRuby/trunk/spec/dietrb/formatter_spec.rb

Modified: MacRuby/trunk/lib/irb/context.rb
===================================================================
--- MacRuby/trunk/lib/irb/context.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/lib/irb/context.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -11,13 +11,14 @@
   class Context
     IGNORE_RESULT = :irb_ignore_result
     
-    attr_reader :object, :binding, :line, :source
+    attr_reader :object, :binding, :line, :level, :source
     attr_accessor :formatter
     
     def initialize(object, explicit_binding = nil)
       @object  = object
       @binding = explicit_binding || object.instance_eval { binding }
       @line    = 1
+      @level   = 0
       clear_buffer
       
       @last_result_assigner = __evaluate__("_ = nil; proc { |val| _ = val }")
@@ -59,10 +60,17 @@
     # But at code block indentation level 0, `quit' means exit the runloop:
     #
     #   process_line("quit") # => false
+    #
+    # If re-indenting the line results in a new line, the reformatted line and
+    # prompt are yielded to the optional block. This happens *before* the line
+    # is actually processed, so the caller (driver) has the opportunity to
+    # update the last printed line.
     def process_line(line)
-      @source << line
+      prompt_and_line = formatter.reindent_last_line(self) { @source << line }
+      yield(*prompt_and_line) if prompt_and_line && block_given?
+
       return false if @source.terminate?
-      
+
       if @source.syntax_error?
         output(formatter.syntax_error(@line, @source.syntax_error))
         @source.pop
@@ -71,22 +79,27 @@
         clear_buffer
       end
       @line += 1
+      @level = source.level
       
       true
     end
     
+    def driver
+      IRB::Driver.current
+    end
+
     # Output is directed to the IRB::Driver.current driver’s output if a
     # current driver is available. Otherwise it’s simply printed to $stdout.
     def output(string)
-      if driver = IRB::Driver.current
+      if driver = self.driver
         driver.output.puts(string)
       else
         puts(string)
       end
     end
     
-    def prompt
-      formatter.prompt(self)
+    def prompt(ignore_auto_indent = false)
+      formatter.prompt(self, ignore_auto_indent)
     end
     
     def input_line(line)

Modified: MacRuby/trunk/lib/irb/deprecated.rb
===================================================================
--- MacRuby/trunk/lib/irb/deprecated.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/lib/irb/deprecated.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -1,5 +1,6 @@
 module IRB
   def self.deprecated(message, caller)
+    return unless $DEBUG
     caller = caller.first.split(':')[0..-2].join(':')
     warn "[!] Deprecation warning from #{caller}: #{message}"
   end
@@ -31,6 +32,9 @@
       when :PROMPT_MODE
         message = "use `IRB.formatter.prompt = :#{value.downcase}'"
         IRB.formatter.prompt = "#{value.to_s.downcase}".to_sym
+      when :AUTO_INDENT
+        message = "use `IRB.formatter.auto_indent = #{value}'"
+        IRB.formatter.auto_indent = value
       when :USE_READLINE
         message = "for now DietRB only has a readline module"
       when :SAVE_HISTORY
@@ -40,4 +44,4 @@
       value
     end
   end
-end
\ No newline at end of file
+end

Modified: MacRuby/trunk/lib/irb/driver/tty.rb
===================================================================
--- MacRuby/trunk/lib/irb/driver/tty.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/lib/irb/driver/tty.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -3,6 +3,11 @@
 module IRB
   module Driver
     class TTY
+      move_one_line_up      = "\e[1A"
+      move_to_begin_of_line = "\r"
+      clear_to_end_of_line  = "\e[0K"
+      CLEAR_LAST_LINE       = move_one_line_up + move_to_begin_of_line + clear_to_end_of_line
+
       attr_reader :input, :output, :context_stack
       
       def initialize(input = $stdin, output = $stdout)
@@ -14,7 +19,7 @@
       def context
         @context_stack.last
       end
-      
+
       def readline
         @output.print(context.prompt)
         @input.gets
@@ -27,6 +32,17 @@
         context.clear_buffer
         ""
       end
+
+      def update_last_line(prompt, reformatted_line)
+        @output.print CLEAR_LAST_LINE
+        @output.puts("#{prompt}#{reformatted_line}")
+      end
+
+      def process_input(line)
+        context.process_line(line) do |prompt, line|
+          update_last_line(prompt, line)
+        end
+      end
       
       # Feeds input into a given context.
       #
@@ -35,7 +51,8 @@
       def run(context)
         @context_stack << context
         while line = consume
-          break unless context.process_line(line)
+          continue = process_input(line)
+          break unless continue
         end
       ensure
         @context_stack.pop

Modified: MacRuby/trunk/lib/irb/ext/colorize.rb
===================================================================
--- MacRuby/trunk/lib/irb/ext/colorize.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/lib/irb/ext/colorize.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -169,7 +169,7 @@
       Ripper.lex(str).map { |_, type, token| colorize_token(type, token) }.join
     end
     
-    def prompt(context)
+    def prompt(context, ignore_auto_indent = false, level = nil)
       colorize_token(:prompt, super)
     end
     
@@ -183,4 +183,4 @@
   end
 end
 
-IRB.formatter = IRB::ColoredFormatter.new
\ No newline at end of file
+IRB.formatter = IRB::ColoredFormatter.new

Modified: MacRuby/trunk/lib/irb/formatter.rb
===================================================================
--- MacRuby/trunk/lib/irb/formatter.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/lib/irb/formatter.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -14,26 +14,35 @@
     SIMPLE_PROMPT  = ">> "
     NO_PROMPT      = ""
     RESULT_PREFIX  = "=>"
+    INDENTATION    = "  "
     SYNTAX_ERROR   = "SyntaxError: compile error\n(irb):%d: %s"
-    SOURCE_ROOT    = /^#{File.expand_path('../../../', __FILE__)}/
+    SOURCE_ROOT    = Regexp.new("^#{File.expand_path('../../../', __FILE__)}")
     
     attr_writer   :prompt
     attr_accessor :inspect
+    attr_accessor :auto_indent
     attr_reader   :filter_from_backtrace
     
     def initialize
-      @prompt  = :default
-      @inspect = true
+      @prompt      = :default
+      @inspect     = true
+      @auto_indent = true
       @filter_from_backtrace = [SOURCE_ROOT]
     end
+
+    def indentation(level)
+      INDENTATION * level
+    end
     
-    def prompt(context)
-      case @prompt
-      when :default then DEFAULT_PROMPT % [context.object.inspect, context.line, context.source.level]
+    def prompt(context, ignore_auto_indent = false, level = nil)
+      level ||= context.level
+      prompt = case @prompt
+      when :default then DEFAULT_PROMPT % [context.object.inspect, context.line, level]
       when :simple  then SIMPLE_PROMPT
       else
         NO_PROMPT
       end
+      @auto_indent && !ignore_auto_indent ? "#{prompt}#{indentation(level)}" : prompt
     end
     
     def inspect_object(object)
@@ -42,12 +51,37 @@
         result.strip!
         result
       else
-        address = object.__id__ * 2
-        address += 0x100000000 if address < 0
-        "#<#{object.class}:0x%x>" % address
+        minimal_inspect_object(object)
       end
     end
-    
+
+    def minimal_inspect_object(object)
+      address = object.__id__ * 2
+      address += 0x100000000 if address < 0
+      "#<#{object.class}:0x%x>" % address
+    end
+
+    def reindent_last_line(context)
+      unless @auto_indent
+        yield
+        nil
+      else
+        source    = context.source
+        old_level = source.level
+        yield
+        if line = source.buffer[-1]
+          # only if the level raises do we use the new value
+          level = source.level < old_level ? source.level : old_level
+          new_line = "#{indentation(level)}#{line.lstrip}"
+          # don't return anything if the new line and level are the same
+          unless line == new_line && level == old_level
+            source.buffer[-1] = new_line
+            [prompt(context, true, level), new_line]
+          end
+        end
+      end
+    end
+
     def result(object)
       "#{RESULT_PREFIX} #{inspect_object(object)}"
     end
@@ -69,4 +103,4 @@
   end
 end
 
-IRB.formatter = IRB::Formatter.new
\ No newline at end of file
+IRB.formatter = IRB::Formatter.new

Modified: MacRuby/trunk/lib/irb/source.rb
===================================================================
--- MacRuby/trunk/lib/irb/source.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/lib/irb/source.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -16,7 +16,7 @@
     
     # Adds a source line to the buffer and flushes the cached reflection.
     def <<(source)
-      source = source.strip
+      source = source.rstrip
       unless source.empty?
         @reflection = nil
         @buffer << source

Modified: MacRuby/trunk/spec/dietrb/context_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/context_spec.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/spec/dietrb/context_spec.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -117,28 +117,43 @@
     @output = setup_current_driver.output
     @context = IRB::Context.new(main)
     @context.extend(InputStubMixin)
+    @context.formatter.auto_indent = true
   end
+
+  after do
+    @context.formatter.auto_indent = false
+  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"
+    @context.source.to_s.should == "def foo\n  p :ok"
   end
   
-  it "clears the source buffer" do
-    @context.process_line("def foo")
-    @context.clear_buffer
-    @context.source.to_s.should == ""
+  it "yields the line if it changed, *after* reindenting" do
+    prompt_and_line = nil
+    @context.process_line("def foo") { |p, l| prompt_and_line = [p, l] }
+    prompt_and_line.should == nil
+    @context.process_line("p :ok") { |p, l| prompt_and_line = [p, l] }
+    prompt_and_line.should == ["irb(main):002:1> ", "  p :ok"]
   end
-  
-  it "increases the current line number" do
+
+  it "increases the current line number, *after* yielding the new re-indented line" do
     @context.line.should == 1
     @context.process_line("def foo")
     @context.line.should == 2
-    @context.process_line("p :ok")
+    @context.process_line("p :ok") 
     @context.line.should == 3
   end
   
+  it "increases the current source level, *after* yielding the new re-indented line" do
+    @context.level.should == 0
+    @context.process_line("def foo")
+    @context.level.should == 1
+    @context.process_line("end") { |_| @context.level.should == 1 }
+    @context.level.should == 0
+  end
+  
   it "evaluates the buffered source once it's a valid code block" do
     def @context.evaluate(source); @evaled = source; end
     
@@ -147,7 +162,7 @@
     @context.process_line("end; p foo")
     
     source = @context.instance_variable_get(:@evaled)
-    source.to_s.should == "def foo\n:ok\nend; p foo"
+    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

Modified: MacRuby/trunk/spec/dietrb/driver/readline_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/driver/readline_spec.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/spec/dietrb/driver/readline_spec.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -41,8 +41,13 @@
     @driver = IRB::Driver::Readline.new(InputStub.new, OutputStub.new)
     @context = IRB::Context.new(Object.new)
     @driver.context_stack << @context
+    Readline.clear_printed!
   end
 
+  after do
+    @context.formatter.auto_indent = false
+  end
+
   it "is a subclass of IRB::Driver::TTY" do
     IRB::Driver::Readline.superclass.should == IRB::Driver::TTY
   end
@@ -57,10 +62,25 @@
   end
 
   it "reads a line through the Readline module" do
-    Readline.stub_input "nom nom nom"
+    Readline.stub_input("nom nom nom")
     @driver.readline.should == "nom nom nom"
   end
 
+  it "prints a prompt" do
+    @context.process_line("def foo")
+    Readline.stub_input("nom nom nom")
+    @driver.readline
+    Readline.printed.should == @context.prompt
+  end
+
+  it "prints a prompt with indentation if it's configured" do
+    @context.formatter.auto_indent = true
+    @context.process_line("def foo")
+    Readline.stub_input("nom nom nom")
+    @driver.readline
+    Readline.printed[-2,2].should == "  "
+  end
+
   it "tells the Readline module to use the history" do
     Readline.use_history = false
     Readline.stub_input "nom nom nom"

Modified: MacRuby/trunk/spec/dietrb/driver/tty_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/driver/tty_spec.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/spec/dietrb/driver/tty_spec.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -1,21 +1,36 @@
 require File.expand_path('../../spec_helper', __FILE__)
 require 'irb/driver/tty'
 
+main = self
+
 describe "IRB::Driver::TTY" do
   before do
     @driver = IRB::Driver::TTY.new(InputStub.new, OutputStub.new)
-    @context = IRB::Context.new(Object.new)
+    @context = IRB::Context.new(main)
     @driver.context_stack << @context
   end
-  
+
+  after do
+    @context.formatter.auto_indent = false
+  end
+
   it "prints the prompt and reads a line of input" do
-    @driver.input.stub_input "calzone"
+    @context.process_line("def foo")
+    @driver.input.stub_input("calzone")
     @driver.readline.should == "calzone"
     @driver.output.printed.should == @context.prompt
   end
+
+  it "prints a prompt with indentation if it's configured" do
+    @context.formatter.auto_indent = true
+    @context.process_line("def foo")
+    @driver.input.stub_input("calzone")
+    @driver.readline
+    @driver.output.printed[-2,2].should == "  "
+  end
   
   it "consumes input" do
-    @driver.input.stub_input "calzone"
+    @driver.input.stub_input("calzone")
     @driver.consume.should == "calzone"
   end
   
@@ -25,6 +40,22 @@
     @driver.consume.should == ""
     @context.source.to_s.should == ""
   end
+
+  it "feeds the input into the context" do
+    @driver.process_input("def foo")
+    @context.source.to_s.should == "def foo"
+  end
+
+  it "updates the previously printed line on the console, if a change to the input occurs (such as re-indenting)" do
+    @context.formatter.auto_indent = true
+    @driver.process_input("def foo")
+    @driver.process_input("p :ok")
+    @driver.process_input("  end")
+    @driver.output.printed.strip.should == [
+      IRB::Driver::TTY::CLEAR_LAST_LINE + "irb(main):002:1>   p :ok",
+      IRB::Driver::TTY::CLEAR_LAST_LINE + "irb(main):003:0> end"
+    ].join("\n")
+  end
 end
 
 describe "IRB::Driver::TTY, when starting the runloop" do
@@ -36,7 +67,7 @@
   
   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.input.stub_input("$from_context = IRB::Driver.current.context")
     @driver.run(@context)
     $from_context.should == @context
     IRB::Driver.current.context.should == nil
@@ -44,7 +75,7 @@
   
   it "feeds input into a given context" do
     $from_context = false
-    @driver.input.stub_input "$from_context = true", "exit"
+    @driver.input.stub_input("$from_context = true", "exit")
     @driver.run(@context)
     $from_context.should == true
   end
@@ -52,7 +83,7 @@
   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.input.stub_input("$from_context = $stdout", "exit")
     @driver.run(@context)
     $from_context.class == IRB::Driver::OutputRedirector
     $stdout.should == before
@@ -67,4 +98,4 @@
 #     irb(o)
 #     IRBRan.should == o
 #   end
-# end
\ No newline at end of file
+# end

Modified: MacRuby/trunk/spec/dietrb/formatter_spec.rb
===================================================================
--- MacRuby/trunk/spec/dietrb/formatter_spec.rb	2010-10-31 22:58:07 UTC (rev 4861)
+++ MacRuby/trunk/spec/dietrb/formatter_spec.rb	2010-10-31 23:03:17 UTC (rev 4862)
@@ -6,14 +6,15 @@
   before do
     @formatter = IRB::Formatter.new
     @context = IRB::Context.new(main)
+    @formatter.auto_indent = false
   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> "
+    @context.process_line("def foo")
+    @formatter.prompt(@context).should == "irb(main):024:1> "
   end
   
   it "describes the context's object in the prompt" do
@@ -77,4 +78,61 @@
     @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
+
+  it "always skips re-indenting the last line in a Source#buffer if `auto_indent' is turned off" do
+    @context.source << "class A"
+    @formatter.reindent_last_line(@context) { @context.source << "def foo" }.should == nil
+    @context.source.buffer.last.should == "def foo"
+  end
+
+  describe "with auto-indentation" do
+    before do
+      @formatter.auto_indent = true
+    end
+
+    it "returns the whitespace to append to the prompt, based on the given level" do
+      @formatter.indentation(0).should == ""
+      @formatter.indentation(1).should == "  "
+      @formatter.indentation(2).should == "    "
+    end
+
+    it "pads the prompt, based on the source level" do
+      @formatter.prompt(@context).should == "irb(main):001:0> "
+      @context.process_line("class A")
+      @formatter.prompt(@context).should == "irb(main):002:1>   "
+      @context.process_line("def foo")
+      @formatter.prompt(@context).should == "irb(main):003:2>     "
+    end
+
+    it "does not pad the prompt if it's explicitely specified" do
+      @context.process_line("class A")
+      @formatter.prompt(@context, true).should == "irb(main):002:1> "
+    end
+
+    it "reindents the last line in a Source#buffer after execution of the block, and returns the new line" do
+      # the line number in the prompt is irrelevant for this test
+      lines = [
+        ["\tclass A", ["irb(main):001:0> ", "class A"]],
+        ["def foo",   ["irb(main):001:1> ", "  def foo"]],
+        ["    end",   ["irb(main):001:1> ", "  end"]],
+        ["    end",   ["irb(main):001:0> ", "end"]]
+      ]
+      lines.each do |line, expected_prompt_and_line|
+        @formatter.reindent_last_line(@context) do
+          @context.source << line
+        end.should == expected_prompt_and_line
+      end
+      @context.source.to_s.should == lines.map { |x| x[1][1] }.join("\n")
+    end
+
+    it "returns nil if the last line was not reindented and the level didn't change" do
+      @context.source << "class A"
+      @formatter.reindent_last_line(@context) { @context.source << "  def foo" }.should == nil
+      @formatter.reindent_last_line(@context) { @context.source << "  end" }.should_not == nil
+    end
+
+    it "returns nil if the source buffer is empty" do
+      @formatter.reindent_last_line(@context) {}.should == nil
+    end
+  end
+end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20101031/2c9f8c39/attachment-0001.html>


More information about the macruby-changes mailing list