Our installation tour is quickly coming to the end. Today with clean up by talking about three final command-line tools.
Today’s preferred version control system. Made it easy on myself: just installed the binary. Use Dropbox to keep .gitconfig synchronized:
> ln -s Dropbox/Preferences/tilde-slash/dot-gitconfig .gitconfig
My .gitconfig makes output simple and colorful. I use TextMate as my comment editor:
[user]
name = William Taysom
email = wtaysom@gmail.com
[color]
diff = auto
status = auto
branch = auto
[core]
pager = cat
editor = mate -wl1
My Ruby setup is not beautiful. I’ve been running 1.8.7 and 1.9.1. Ruby Version Manager is probably the best solution, but I’ll share my solution with you.
Ruby without other gems will never meet your jeweling needs:
> sudo gem update --system
> sudo gem update # Comes with Rails and a bunch of others.
> sudo gem install assert2 assit bundler capistrano-ext columnize fxruby gchartrb json json_pure linecache passenger rb-appscript redis rspec rspec-rails ruby-debug ruby-debug-base rubydbc echoe rubydbc yajl-ruby unroller
Some of these merit additional comment:
gchartrb provides a Ruby wrapper for Google’s chart API. Everybody needs a chart now and then.rspec is my preferred testing library. I like its lexical scoping goodness. Ruby testing the Lispy way.ruby-debug because hacking without a debugger is hacking in the dark. echoe is my preferred gem builder.unroller — why debug step-by-step when what you really want is a full execution trace?I share my IRB configuration via DropBox:
> ln -s ~/Dropbox/Preferences/tilde-slash/dot-irbrc .irbrc
What sort of configuration do I like? A simple prompt just ?:
IRB.conf[:PROMPT][:WLS_PROMPT] = {
:PROMPT_I => "? ",
:PROMPT_S => '" ',
:PROMPT_C => "| ",
:RETURN => "%s\n"
}
IRB.conf[:PROMPT_MODE] = :WLS_PROMPT
IRB.conf[:AUTO_INDENT] = true
IRB.conf[:USE_READLINE] = true
IRB.conf[:LOAD_MODULES] = [] unless IRB.conf.key?(:LOAD_MODULES)
Get tab to do its most:
## Tab for command completion.
unless IRB.conf[:LOAD_MODULES].include?('irb/completion')
IRB.conf[:LOAD_MODULES] << 'irb/completion'
end
Everyone needs gems:
## I just expect this.
require 'rubygems'
I define r as a method to reload a file of interest:
## For quick loading.
$wl_main_file_name = "main.rb"
def r name = nil
if name
name += ".rb" unless name =~ /.rb$/
elsif $wl_test_file
name = $wl_test_file
elsif Dir.new(Dir.pwd).detect {|n| n == $wl_main_file_name}
name = $wl_main_file_name
else
name = Dir.new(Dir.pwd).detect {|n| n =~ /.rb$/}
end
$wl_test_file = name
load $wl_test_file
end
Back when I started Ruby, Symbol#to_proc wasn’t standard:
## Symbol#to_proc
unless :symbol.respond_to? :to_proc
class Symbol
def to_proc
Proc.new {|*args| args.shift.__send__ self, *args}
end
end
end
Sometimes I want a quick summary of all the methods an object will respond to:
## ObjectSummary
# For quick inspection of an object.
module ObjectSummary
# Prints the public methods of an object grouped by module.
def _summary
header = lambda do |obj|
puts "=== #{obj} ==="
end
body = lambda do |array|
puts " "+array.sort.join(", ") unless array.empty?
end
sm = singleton_methods
unless sm.empty?
header["<< self"]
body[sm]
end
self.class.ancestors.each do |ancestor|
header[ancestor]
body[ancestor.instance_methods(false)]
end
puts "==="
end
def _s
_summary
end
end
include ObjectSummary
Sometimes I know the arguments, I know the return value, but I don’t know the method name:
## MethodFinder
# <http://www.nobugs.org/developer/ruby/method_finder.html>
class MethodFinder
# Find all methods on [anObject] which, when called with [args] return [expectedResult]
def self.find obj, res, *args
obj.methods.select do |name|
obj.method(name).arity == args.size
end.select do |name|
begin
mega_clone(obj).method(name).call(*args) == res
rescue
end
end
end
def self.mega_clone obj
begin obj.clone rescue obj end
end
# Pretty-prints the results of the previous method
def self.show obj, res, *args
find(obj, res, *args).each do |name|
print "#{obj.inspect}.#{name}"
print "(#{args.map{|o| o.inspect}.join(", ")})" unless args.empty?
puts " == #{res.inspect}"
end
end
end
# _why's addition
# <http://redhanded.hobix.com/inspect/stickItInYourIrbrcMethodfinder.html>
class MethodFinder
def initialize obj, *args
@obj = obj
@args = args
end
def ==res
MethodFinder.find @obj, res, *@args
end
end
class Object
def what? *args
MethodFinder.new self, *args
end
end
Though RSpec is now my testing framework of choice, once upon a time I found it useful to Test::Unit tests from within IRB:
## For testing.
def t
require 'test/unit'
require 'test/unit/ui/console/testrunner'
def Kernel.beep
putc ?\a
nil
end
def Test.run *names
u = Test::Unit
# collect tests in Test
tests = []
constants.each do |const_name|
const = const_get const_name
if const.kind_of? Class
if const.subclass? u::TestSuite
tests << const
elsif const.subclass? u::TestCase
tests << const.suite
end
end
end
tests.reject! {|t| not names.include? t.name } unless names.empty?
# build suite of all tests
suite = u::TestSuite.new "all tests"
tests.each {|t| suite << t}
result = u::UI::Console::TestRunner.run suite
beep unless result.passed?
tests.map {|t| t.name}
end
def t *names
Test.run *names
end
end
It’s amazing how the little utilities you make for yourself can become lost and forgotten.
I use sudo port install ruby19 got get ruby1.9, rake1.9, etc. Might not be the best way to manage multiple Ruby versions, but it works well enough for me.
Ruby 1.9 has its own set of gems:
> sudo gem1.9 update --system
> sudo gem1.9 install thin uuid rack-contrib yajl-ruby redis usher em-http-request activerecord sqlite3-ruby mysql rspec
> sudo mv /opt/local/bin/spec /opt/local/bin/spec1.9 # To avoid name conflict.
I like the speed and convenience of local documentation. Though the following document generation commands work, they don’t seem to work well. They take a very long time and seem a bit finicky:
> svn co http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8_7
ruby_1_8_7> rdoc --op ../ruby_1_8_7_doc
> svn co http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_9_1
ruby_1_9_1> rdoc1.9 --op ../ruby_1_9_1_doc # Uses about 4GB of RAM. I sense a memory leak.
For language reference, I keep a local copy of Ruby QuickRef.
Though I’ve never used Haskell for a serious project, I do like reading programming language theory papers. Haskell is the lingua franca for pure functional programming. Haskell helps you distill the essential from the irrelevant. Paul Hudak once observed:
We provided them [DARPA] with a copy of P1 [implemented in Haskell] without explaining that it was a program, and based on preconceptions from their past experience, they had studied P1 under the assumption that it was a mixture of requirements specification and top level design. They were convinced it was incomplete because it did not address issues such as data structure design and execution order.
An addendum with all the cool things I’ve found since Apollo’s initial setup.
Commentary