Wednesday, December 13, 2006

Have it all : Ruby, irb, autocompletion, autodocumentation

Ruby users live long and happy with irb. But everything is not rosy under default irb's sun. One generally wishes :
  • documentation at your fingertip. what's available from the expression I just started to type ?
  • just.. standard auto completion
  • also correct handling of keys like "[" and "]" (which fails if you are under French or other keyboard layouts) is of occasional use
So for all this, here is a irbrc file, working under windows and Unix.
  1. You need to create a file named .irbrc (for windows user, call it toto.txt then rename it .irbrc from the command line)
  2. Then create an system environment variable called IRBRC, containing the complete path to your .irbrc file.
  3. Then just install the fastri gem and strat the documentation server using the command
        • gem install fastri
        • fastri-server
That'll get you started with everything you need to truly enjoy IRB goodness PS: Credits to eigenclass and the other Rubyist for all this goodness [Updated at 19/12/06] You can either download the file , of copy it from down there [Click to display the .ircrb file]
require 'irb/completion'
require 'rbconfig'

module Kernel
  include Config

  def r(arg)
 (CONFIG["target_alias"] == "i386-mswin32") ?  ( puts `fri.cmd "#{arg}"` ) : (puts `fri "#{arg}"`)

  end
  private :r
end

class Array
  def filter(&predicate)

      self.each do |item| 
          if(predicate(item))

           yield item
           end
      end
  end
end

class Object
  include Config
  def puts_ri_documentation_for(obj, meth)

    case self
    when Module
      candidates = ancestors.map{|klass| "#{klass}::#{meth}"}

      candidates.concat(class << self; ancestors end.map{|k| "#{k}##{meth}"})

    else
      candidates = self.class.ancestors.map{|klass|  "#{klass}##{meth}"}

    end
    candidates.compact.each do |candidate|
      #puts "TRYING #{candidate}"

      desc =  (CONFIG["target_alias"] == "i386-mswin32") ?  ( `fri.cmd "#{candidate}"` ) : ( `fri "#{candidate}"`)

      unless desc == "nil"
        # uncomment to use ri (and some patience)
        #desc = `ri -T '#{candidate}' 2>/dev/null`
        #unless desc.empty?

        puts desc
        return true
      end
    end
    false

  end
  private :puts_ri_documentation_for

  def method_missing(meth, *args, &block)

    if md = /ri_(.*)/.match(meth.to_s)

      unless puts_ri_documentation_for(self,md[1])
        "Ri doesn't know about ##{meth}"
      end

    else
      super
    end
  end

  def ri_(meth)

    unless puts_ri_documentation_for(self,meth.to_s)
      "Ri doesn't know about ##{meth}"
    end

  end
end

RICompletionProc = proc{|input|
  bind = IRB.conf[:MAIN_CONTEXT].workspace.binding

  case input
  when /(\s*(.*)\.ri_)(.*)/
    pre = $1

    receiver = $2
    meth = $3 ? /\A#{Regexp.quote($3)}/ : /./ #}

    begin
      candidates = eval("#{receiver}.methods", bind).map do |m|

        case m
        when /[A-Za-z_]/; m
        else # needs escaping

          %{"#{m}"}
        end
      end
      candidates = candidates.grep(meth)

      candidates.map{|s| pre + s }
    rescue Exception

      candidates = []
    end
  when /([A-Z]\w+)#(\w*)/ #}

    klass = $1
    meth = $2 ? /\A#{Regexp.quote($2)}/ : /./

    candidates = eval("#{klass}.instance_methods(false)", bind)
    candidates = candidates.grep(meth)

    candidates.map{|s| "'" + klass + '#' + s + "'"}

  else
    IRB::InputCompletor::CompletionProc.call(input)
  end

}
#Readline.basic_word_break_characters= " \t\n\"\\'`><=;|&{("
Readline.basic_word_break_characters= " \t\n\\><=;|&"

Readline.completion_proc = RICompletionProc

0 Comments:

Post a Comment

Links to this post:

Create a Link

<< Home