[macruby-changes] [4628] DietRB/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Oct 8 03:50:52 PDT 2010


Revision: 4628
          http://trac.macosforge.org/projects/ruby/changeset/4628
Author:   eloy.de.enige at gmail.com
Date:     2010-10-08 03:50:50 -0700 (Fri, 08 Oct 2010)
Log Message:
-----------
Start writing a new completion extension, based on Ripper. Now handles the simple literal cases.

From: Eloy Duran <eloy.de.enige at gmail.com>

Modified Paths:
--------------
    DietRB/trunk/lib/irb/ext/completion.rb

Added Paths:
-----------
    DietRB/trunk/spec/completion_spec.rb

Modified: DietRB/trunk/lib/irb/ext/completion.rb
===================================================================
--- DietRB/trunk/lib/irb/ext/completion.rb	2010-10-08 10:50:40 UTC (rev 4627)
+++ DietRB/trunk/lib/irb/ext/completion.rb	2010-10-08 10:50:50 UTC (rev 4628)
@@ -1,209 +1,47 @@
-#
-#   irb/completor.rb - 
-#   	$Release Version: 0.9$
-#   	$Revision: 20880 $
-#   	by Keiju ISHITSUKA(keiju at ishitsuka.com)
-#       From Original Idea of shugo at ruby-lang.org
-#
+require 'ripper'
 
-puts 'hiero!'
-require "readline"
-
 module IRB
-  module InputCompletor
-
-    @RCS_ID='-$Id: completion.rb 20880 2008-12-19 11:37:41Z yugui $-'
-
-    ReservedWords = [
-      "BEGIN", "END",
-      "alias", "and", 
-      "begin", "break", 
-      "case", "class",
-      "def", "defined", "do",
-      "else", "elsif", "end", "ensure",
-      "false", "for", 
-      "if", "in", 
-      "module", 
-      "next", "nil", "not",
-      "or", 
-      "redo", "rescue", "retry", "return",
-      "self", "super",
-      "then", "true",
-      "undef", "unless", "until",
-      "when", "while",
-      "yield",
-    ]
+  class Completion
+    attr_reader :source
+    
+    def initialize(source)
+      @source = source
+    end
+    
+    def results
+      src = @source
       
-    CompletionProc = proc { |input|
-      # bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
-      bind = IRB::Context.current.binding
+      # if ends with period, remove it to remove the syntax error it causes
+      call = (src[-1,1] == '.')
+      src = src[0..-2] if call
       
-#      puts "input: #{input}"
-
-      case input
-      when /^(\/[^\/]*\/)\.([^.]*)$/
-	# Regexp
-	receiver = $1
-	message = Regexp.quote($2)
-
-	candidates = Regexp.instance_methods.collect{|m| m.to_s}
-	select_message(receiver, message, candidates)
-
-      when /^([^\]]*\])\.([^.]*)$/
-	# Array
-	receiver = $1
-	message = Regexp.quote($2)
-
-	candidates = Array.instance_methods.collect{|m| m.to_s}
-	select_message(receiver, message, candidates)
-
-      when /^([^\}]*\})\.([^.]*)$/
-	# Proc or Hash
-	receiver = $1
-	message = Regexp.quote($2)
-
-	candidates = Proc.instance_methods.collect{|m| m.to_s}
-	candidates |= Hash.instance_methods.collect{|m| m.to_s}
-	select_message(receiver, message, candidates)
-	
-      when /^(:[^:.]*)$/
- 	# Symbol
-	if Symbol.respond_to?(:all_symbols)
-	  sym = $1
-	  candidates = Symbol.all_symbols.collect{|s| ":" + s.id2name}
-	  candidates.grep(/^#{sym}/)
-	else
-	  []
-	end
-
-      when /^::([A-Z][^:\.\(]*)$/
-	# Absolute Constant or class methods
-	receiver = $1
-	candidates = Object.constants.collect{|m| m.to_s}
-	candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
-
-      when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/
-	# Constant or class methods
-	receiver = $1
-	message = Regexp.quote($4)
-	begin
-	  candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
-	  candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
-	rescue Exception
-	  candidates = []
-	end
-	candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e}
-
-      when /^(:[^:.]+)\.([^.]*)$/
-	# Symbol
-	receiver = $1
-	message = Regexp.quote($2)
-
-	candidates = Symbol.instance_methods.collect{|m| m.to_s}
-	select_message(receiver, message, candidates)
-
-      when /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/
-	# Numeric
-	receiver = $1
-	message = Regexp.quote($5)
-
-	begin
-	  candidates = eval(receiver, bind).methods.collect{|m| m.to_s}
-	rescue Exception
-	  candidates = []
-	end
-	select_message(receiver, message, candidates)
-
-      when /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/
-	# Numeric(0xFFFF)
-	receiver = $1
-	message = Regexp.quote($2)
-
-	begin
-	  candidates = eval(receiver, bind).methods.collect{|m| m.to_s}
-	rescue Exception
-	  candidates = []
-	end
-	select_message(receiver, message, candidates)
-
-      when /^(\$[^.]*)$/
-	regmessage = Regexp.new(Regexp.quote($1))
-	candidates = global_variables.collect{|m| m.to_s}.grep(regmessage)
-
-#      when /^(\$?(\.?[^.]+)+)\.([^.]*)$/
-      when /^((\.?[^.]+)+)\.([^.]*)$/
-	# variable
-	receiver = $1
-	message = Regexp.quote($3)
-
-	gv = eval("global_variables", bind).collect{|m| m.to_s}
-	lv = eval("local_variables", bind).collect{|m| m.to_s}
-	cv = eval("self.class.constants", bind).collect{|m| m.to_s}
-	
-	if (gv | lv | cv).include?(receiver)
-	  # foo.func and foo is local var.
-	  candidates = eval("#{receiver}.methods", bind).collect{|m| m.to_s}
-	elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
-	  # Foo::Bar.func
-	  begin
-	    candidates = eval("#{receiver}.methods", bind).collect{|m| m.to_s}
-	  rescue Exception
-	    candidates = []
-	  end
-	else
-	  # func1.func2
-	  candidates = []
-	  ObjectSpace.each_object(Module){|m|
-	    begin
-	      name = m.name
-	    rescue Exception
-	      name = ""
-	    end
-	    next if name != "IRB::Context" and 
-	      /^(IRB|SLex|RubyLex|RubyToken)/ =~ name
-	    candidates.concat m.instance_methods(false).collect{|x| x.to_s}
-	  }
-	  candidates.sort!
-	  candidates.uniq!
-	end
-	select_message(receiver, message, candidates)
-
-      when /^\.([^.]*)$/
-	# unknown(maybe String)
-
-	receiver = ""
-	message = Regexp.quote($1)
-
-	candidates = String.instance_methods(true).collect{|m| m.to_s}
-	select_message(receiver, message, candidates)
-
-      else
-	candidates = eval("methods | private_methods | local_variables | self.class.constants", bind).collect{|m| m.to_s}
-			  
-	(candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/)
+      # p src, call
+      results = Ripper::SexpBuilder.new(src).parse
+      # p results
+      
+      # [:program, [:stmts_add, [:stmts_new], [x, …]]]
+      #                                        ^
+      sub = results[1][2]
+      klass = case sub[0]
+      when :regexp_literal then Regexp
+      when :array, :words_add, :qwords_add then Array
+      when :lambda then Proc
+      when :hash then Hash
+      when :symbol_literal, :dyna_symbol then Symbol
+      when :string_literal then String
+      when :dot2, :dot3 then Range
+      when :@int then Fixnum
+      when :@float then Float
+      when :unary then
+        # [:program, [:stmts_add, [:stmts_new], [:unary, :-@, [x, …]]]]
+        #                                                      ^
+        case sub[2][0]
+        when :@int then Fixnum
+        when :@float then Float
+        end
       end
-    }
-
-    Operators = ["%", "&", "*", "**", "+",  "-",  "/",
-      "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
-      "[]", "[]=", "^",]
-
-    def self.select_message(receiver, message, candidates)
-      candidates.grep(/^#{message}/).collect do |e|
-	case e
-	when /^[a-zA-Z_]/
-	  receiver + "." + e
-	when /^[0-9]/
-	when *Operators
-	  #receiver + " " + e
-	end
-      end
+      
+      klass.instance_methods.map(&:to_s)
     end
   end
 end
-
-if Readline.respond_to?("basic_word_break_characters=")
-  Readline.basic_word_break_characters= " \t\n\"\\'`><=;|&{("
-end
-Readline.completion_append_character = nil
-Readline.completion_proc = IRB::InputCompletor::CompletionProc

Added: DietRB/trunk/spec/completion_spec.rb
===================================================================
--- DietRB/trunk/spec/completion_spec.rb	                        (rev 0)
+++ DietRB/trunk/spec/completion_spec.rb	2010-10-08 10:50:50 UTC (rev 4628)
@@ -0,0 +1,118 @@
+require File.expand_path('../spec_helper', __FILE__)
+require 'irb/ext/completion'
+
+module CompletionHelper
+  def complete(str)
+    IRB::Completion.new(str).results
+  end
+  
+  def imethods(klass)
+    klass.instance_methods.map(&:to_s)
+  end
+end
+
+describe "IRB::Completion, returns all instance methods if the source ends with a period and" do
+  extend CompletionHelper
+  
+  it "matches a Regexp literal" do
+    complete('//.').should == imethods(Regexp)
+    complete('/^(:[^:.]+)\.([^.]*)$/.').should == imethods(Regexp)
+    complete('/^(#{oops})\.([^.]*)$/.').should == imethods(Regexp)
+    complete('%r{/foo/.*/bar}.').should == imethods(Regexp)
+  end
+  
+  it "matches an Array literal" do
+    complete('[].').should == imethods(Array)
+    complete('[:ok, {}, "foo",].').should == imethods(Array)
+    complete('[*foo].').should == imethods(Array)
+    complete('%w{foo}.').should == imethods(Array)
+    complete('%W{#{:foo}}.').should == imethods(Array)
+  end
+  
+  # fails on MacRuby
+  it "matches a lambda literal" do
+    complete('->{}.').should == imethods(Proc)
+    complete('->{x=:ok}.').should == imethods(Proc)
+    complete('->(x){x=:ok}.').should == imethods(Proc)
+  end
+  
+  it "matches a Hash literal" do
+    complete('{}.').should == imethods(Hash)
+    complete('{:foo=>:bar,}.').should == imethods(Hash)
+    complete('{foo:"bar"}.').should == imethods(Hash)
+  end
+  
+  it "matches a Symbol literal" do
+    complete(':foo.').should == imethods(Symbol)
+    complete(':"foo.bar".').should == imethods(Symbol)
+    complete(':"foo.#{"bar"}".').should == imethods(Symbol)
+    complete(':\'foo.#{"bar"}\'.').should == imethods(Symbol)
+    complete('%s{foo.bar}.').should == imethods(Symbol)
+  end
+  
+  it "matches a String literal" do
+    complete("'foo\\'bar'.").should == imethods(String)
+    complete('"foo\"bar".').should == imethods(String)
+    complete('"foo#{"bar"}".').should == imethods(String)
+    complete('%{foobar}.').should == imethods(String)
+    complete('%q{foo#{:bar}}.').should == imethods(String)
+    complete('%Q{foo#{:bar}}.').should == imethods(String)
+  end
+  
+  it "matches a Range literal" do
+    complete('1..10.').should == imethods(Range)
+    complete('1...10.').should == imethods(Range)
+    complete('"a".."z".').should == imethods(Range)
+    complete('"a"..."z".').should == imethods(Range)
+  end
+  
+  it "matches a Fixnum literal" do
+    complete('42.').should == imethods(Fixnum)
+    complete('+42.').should == imethods(Fixnum)
+    complete('-42.').should == imethods(Fixnum)
+    complete('42_000.').should == imethods(Fixnum)
+  end
+  
+  it "matches a Bignum literal as a Fixnum" do
+    complete('100_000_000_000_000_000_000.').should == imethods(Fixnum)
+    complete('-100_000_000_000_000_000_000.').should == imethods(Fixnum)
+    complete('+100_000_000_000_000_000_000.').should == imethods(Fixnum)
+  end
+  
+  it "matches a Float with exponential literal" do
+    complete('1.2e-3.').should == imethods(Float)
+    complete('+1.2e-3.').should == imethods(Float)
+    complete('-1.2e-3.').should == imethods(Float)
+  end
+  
+  it "matches a hex literal as a Fixnum" do
+    complete('0xffff').should == imethods(Fixnum)
+    complete('+0xffff').should == imethods(Fixnum)
+    complete('-0xffff').should == imethods(Fixnum)
+  end
+  
+  it "matches a binary literal as a Fixnum" do
+    complete('0b01011').should == imethods(Fixnum)
+    complete('-0b01011').should == imethods(Fixnum)
+    complete('+0b01011').should == imethods(Fixnum)
+  end
+  
+  it "matches an octal literal as a Fixnum" do
+    complete('0377').should == imethods(Fixnum)
+    complete('-0377').should == imethods(Fixnum)
+    complete('+0377').should == imethods(Fixnum)
+  end
+  
+  it "matches a Float literal" do
+    complete('42.0.').should == imethods(Float)
+    complete('-42.0.').should == imethods(Float)
+    complete('+42.0.').should == imethods(Float)
+    complete('42_000.0.').should == imethods(Float)
+  end
+  
+  it "matches a Bignum float literal as a Float" do
+    complete('100_000_000_000_000_000_000.0.').should == imethods(Float)
+    complete('+100_000_000_000_000_000_000.0.').should == imethods(Float)
+    complete('-100_000_000_000_000_000_000.0.').should == imethods(Float)
+  end
+end
\ No newline at end of file
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20101008/3ef8c67f/attachment-0001.html>


More information about the macruby-changes mailing list