On 10/12/06, Brian Mitchell <binary42 / gmail.com> wrote:
> On 10/12/06, Dr Nic <drnicwilliams / gmail.com> wrote:
> > I recently discovered that I can create a .irbrc file to run setup for
> > my irb/console. I am in love.
> >
> > My current .irbrc is:
> >
> > require 'irb/completion'
> > require 'map_by_method'
> > require 'what_methods'
> > require 'pp'
> > IRB.conf[:AUTO_INDENT]=true
> >
> > Explanation of the different libraries:
> > http://drnicwilliams.com/2006/10/12/my-irbrc-for-consoleirb/
> >
> > Does anyone any interesting things in their .irbrc file?
> >
>
> Mine is rather large and in flux right now but I will post a few
> nuggets from it bellow:
>
> require 'rubygems'
>
> # Very basic prelude of enhancements for Object
> module ObjectEnhancer
>
>   def clone!
>     self.clone rescue self
>   end
>
>   def tap
>     yield self
>     self
>   end
>
>   def _
>     yield if block_given?
>     nil
>   end
>
> end
>
> class Object
>   include ObjectEnhancer
> end
>
> # Lazy loading prety print support
> class Object
>   def pp(*a, &b) # pass the block just-in-case this changes.
>     require 'pp'
>     pp(*a, &b)
>   end
> end
>
> # Tab completion
> require 'irb/completion'
> IRB.conf[:USE_READLINE] = true
>
> # Histories
> require 'irb/ext/save-history'
> IRB.conf[:SAVE_HISTORY] = 1000
> IRB.conf[:EVAL_HISTORY] = 100
>
> # Prompts
> IRB.conf[:PROMPT][:CUSTOM] = {
>     :PROMPT_N => ">> ",
>     :PROMPT_I => ">> ",
>     :PROMPT_S => nil,
>     :PROMPT_C => " > ",
>     :RETURN => "=> %s\n"
> }
>
> # Set default prompt
> IRB.conf[:PROMPT_MODE] = :CUSTOM
>
> # Simple ri integration
> def ri(*names)
>   system("ri #{names.map {|name| name.to_s}.join(" ")}")
> end
>
> # fresh irb. It uses an at_exit handler to yield it a block is given.
> def reset_irb
>   at_exit {exec($0)} # first registered is last to run
>   at_exit {yield if block_given?}
>
>   # From finalizer code in irb/ext/save-history.rb.. very ugly way to
> do it :S.. who wants to rewrite irb?
>   if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0
>     if hf = IRB.conf[:HISTORY_FILE]
>       file = File.expand_path(hf)
>     end
>     file = IRB.rc_file("_history") unless file
>     open(file, 'w') do |file|
>       hist = IRB::HistorySavingAbility::HISTORY.to_a
>       file.puts(hist[-num..-1] || hist)
>     end
>   end
>
>   # Make irb give us a clean exit (up until our at_exit handler above)
>   throw :IRB_EXIT, 0
> end
>
> # clear the screen.. with some self destruction ;-)
> def clear
>   eval "def clear; print #{`clear`.inspect} end"
>   clear
> end
> private :clear
>
> # Simple webserver (Loazy loading)
> def serve_files(opts = {})
>   require 'webrick'
>
>   opts[:host] ||= Socket.gethostname
>   opts[:dir]  ||= Dir.pwd
>   opts[:port] ||= opts[:dir].hash % 1000 + 10000
>   opts[:log] ||= Nop.new # hidden and simple.
>
>   server = WEBrick::HTTPServer.new(
>     :Host => opts[:host],
>     :Port => opts[:port],
>     :DocumentRoot => opts[:dir],
>     :Logger => opts[:log]
>   )
>
>   trap("INT") {server.shutdown}
>
>   puts "Serving \"#{opts[:dir]}\" at http://#{opts[:host]}:#{opts[:port]}/"
>   server.start
>   nil
> rescue
>   puts "Failed to start server! See $webrick_error for the exception."
>   $webrick_error = $!
>   nil
> end
> private :serve_files
>
> # SSH support. Needs a lot of work still but it is nice to have.
> # This was just a 5 min hack. Thanks goes to Jamis for the
> # nice library.
> # Note that you must sleep to have the event loop run.
> def ssh_session(opts = {})
>   puts "Note: You must 'sleep' in order for the event loop to run in
> irb." if require 'net/ssh'
>
>   dynamic_session_class = Class.new do
>     @@default_opts = {
>       :user => ENV['USER'] || ENV['USERNAME'],
>       :port => 22
>     }.freeze
>
>     def initialize(opts = {}, aux = {})
>       opts, opts[:host] = aux, opts unless Hash === opts
>       opts = aux.merge opts
>       opts = @@default_opts.merge opts
>
>       @shutdown = false
>       @queue = []
>
>       ready = false
>       Thread.new {
>         begin
>           Net::SSH.start(opts[:host],
>             :username => opts[:user],
>             :password => opts[:password],
>             :port     => opts[:port]
>           ) do |session|
>             ready = true
>             loop {
>               break if self.shutdown?
>               self.process(session)
>               session.loop
>               sleep 0.01
>             }
>           end
>         rescue
>           puts "Failed while running ssh session! See $ssh_error for
> the exception."
>           $ssh_error = $!
>         ensure
>           ready = true
>         end
>       }
>       sleep 0 until ready
>     end
>
>     def shutdown?
>       @shutdown
>     end
>
>     def shutdown
>       @shutdown = true
>     end
>
>     def execute(&blk)
>       raise "Session shutdown" if shutdown?
>       @queue << blk
>       nil
>     end
>
>     def process(session)
>       while proc = @queue.pop
>         proc.call(session)
>       end
>     end
>
>     def forward_local(port, host, aux_port = port)
>       execute {|session|
>         session.forward.local('0.0.0.0', port, host, aux_port)
>       }
>     end
>     alias outgoing forward_local
>
>     def forward_remote(port, host, aux_port = port)
>       execute {|session|
>         session.forward.remote_to(port, host, aux_port)
>       }
>     end
>
>     def shell
>       require 'termios'
>       puts "Note: You will need to interrupt 'sleep' when your shell
> is done (usually ^C)."
>       execute {|session|
>         stdin_buffer = lambda do |enable|
>           attrs = Termios::getattr($stdin)
>           if enable
>             attrs.c_lflag |= Termios::ICANON | Termios::ECHO
>           else
>             attrs.c_lflag &= ~(Termios::ICANON | Termios::ECHO)
>           end
>           Termios::setattr($stdin, Termios::TCSANOW, attrs)
>         end
>
>         begin
>           stdin_buffer[false]
>
>           shell = session.shell.open(:pty => true)
>
>           loop do
>             break unless shell.open?
>             if IO.select([$stdin],nil,nil,0.01)
>               data = $stdin.sysread(1)
>               shell.send_data data
>             end
>
>             $stdout.print shell.stdout while shell.stdout?
>             $stdout.flush
>           end
>         ensure
>           stdin_buffer[true]
>         end
>       }
>       sleep
>     end
>     alias incoming forward_remote
>
>   end
>
>   Object.const_set('DynamicSSHSession', dynamic_session_class) unless
> Object.constants.include? 'DynamicSSHSession'
>
>   dynamic_session_class.new(opts)
> rescue
>   puts "Failed to create an ssh session! See $ssh_error for the exception."
>   $ssh_error = $!
> end
> private :ssh_session
>
> # Like haskell's sequence. Really nice to have but recursive.
> # I should change this it an iterative solution sometime.
> # Recursion is usually not a problem for realistic inputs.
> class Array
>   def sequence(i = 0, *a)
>     return [a] if i == size
>     self[i].map {|x|
>       sequence(i+1, *(a + [x]))
>     }.inject([]) {|m, x| m + x}
>   end
> end
>
> class Symbol
>   def to_proc
>     lambda {|*args| args.shift.__send__(self, *args)}
>   end
> end
>
> # Modulized blank slate. Only removes current not future
> # methods for simplicities sake.
> module Blank
>   def self.append_features(base)
>     base.module_eval {
>       instance_methods.each {|m| undef_method m unless m =~ /^__/}
>     }
>   end
> end
>
> # This is mostly a toy but it has been useful in a few cases
> # where I needed to slowly build up a proc inside multiple
> # calls
> class It < Proc
>   instance_methods.each {|m| undef_method m unless m =~ /^__/}
>
>   def method_missing(*args, &blk)
>     It.new {|x|
> Proc.instance_method(:call).bind(self).call(x).send(*args, &blk)}
>   end
> end
>
> def it
>   if block_given?
>     It.new
>   else
>     It.new {|x| x}
>   end
> end
> private :it
>
> That is about half of it. I've got more stuff like gray number stuf,
> unbound method extensions, and some new meta-programming stuff but it
> all needs a little more work first. I should also note that I wrap my
> irbrc file with a begin rescue end. The rescue just prints the
> presence of an error and then shoves $! into $irbrc_error. This is
> nice for occasions when you might be trying out new 1.9 builds or use
> rails (they don't correctly initialize IRB so it causes failed loads
> of irbrc -- keeps the output a little cleaner).
>
> I will probably do another clean-up before RubyConf so we can all
> share .irbrc's ;-). I'll probably end up removing more things then I
> add (i.e. I really don't use Symbol#to_proc that much).
>
> One last thing, I was wondering if anyone would be interested in a
> series of gems that act as automatic irb plugins? it might be fun to
> gemify some of these things.
>
> Brian.
>

Funny reading through the code. I spotted a few screw-ups. Probably a
side effect of doing rapid and small changes between irb_reset's.

Brian.