On 10/12/06, Dr Nic [email protected] wrote:
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.