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.