13 Apr 2008
The Ruby on Rails core is now hosted on Git This is great news for Git fans like myself. For those of Rails core contributors who are coming late to the party, here’s a quick list of tips I’ve put together especially for you. This no substitute for a proper tutorial but rather a Rails biased supplement to one.
The first thing you do should be configure a real name and email. By default, Git chooses a default name based on the GECOS data (which is probably right) and a default email based on your login and hostname (which is almost certainly wrong). Best practices dictate you use your real name and email here, not your login, IRC handle, or any other aliases you may have. These fields will be immortalized in the repository history so make sure you get them right.
$ git config --global user.name "Tim Pope"
$ git config --global user.email "foo@gmail.com"
While you’re configuring, you may want to enable coloring for some commands:
$ git config --global color.diff auto
$ git config --global color.status auto
$ git config --global color.branch auto
$ git config --global color.interactive auto
While Git will accept just about any commit message you feed to it, sticking to best practices makes the log a lot easier to work with. A model commit message is shown below.
Short (50 chars or less) summary of changes
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.
Write your commit message in the present tense: "Fix bug" and not "Fixed
bug." This convention matches up with commit messages generated by
commands like git merge and git revert.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded by a
single space, with blank lines in between, but conventions vary here
As far as submitting your work to the Rails core, the workflow here is still being fleshed out. For now, either give a public URL and branch where your contribution can be found, or use the following series of commands to get a file that can be easily applied by anyone with the git am command to reconstruct your history locally.
$ git checkout my_funky_branch
$ git rebase origin/master
$ git format-patch --stdout origin/master.. > my_funky_patches
Here’s a tip for keeping up to date: In lieu of using git pull to download the latest changes, use git pull --rebase. Instead of cluttering the history with a merge commit, it reapplies your changes to the latest upstream. The only caveat is that you shouldn’t use this method if you’ve already published the changes to another repository. Doing so would cause problems for anyone who has already downloaded the original commits.
03 May 2007
Today I devised a little script to generate Ruby examples showing code and output.
% rubydemo '[1,2,3].inject {|m,o|m+o}'
[1,2,3].inject {|m,o|m+o} #=> 6
% rubydemo 1/0
1/0 #=> #<ZeroDivisionError: divided by 0>
Here’s the script I used for generation. (It could have been one line if I didn’t care so much about exception formatting.)
#!/usr/bin/env ruby
print ARGV.join(" ") + " #=> "
begin
p(eval(ARGV.join(" "),binding,"(demo)"))
rescue Exception => e
puts "#<#{e.class}: #{e.message[/.*/]}>"
end
The real killer app, though, is using it in conjunction with IRC. Here’s the alias I used in Irssi.
/alias rd exec -nosh - -out rubydemo $*
Now I need merely do /rd 2+2 to get a beautifully formatted 2+2 #=>
4 in any conversation.
11 Feb 2007
An incredibly useful technique when using Ruby is to auto-load at start-up a custom library written for exactly that purpose. This is easy to accomplish with a couple of environment variables, but I see very little discussion on the subject. Thus, I’ve written a nice summary of how to go about setting this up.
The secret to running code at start-up is RUBYOPT. You’ve probably seen this environment variable before if you’ve used RubyGems. It is recommended to set this to a value of rubygems. This is equivalent to always calling ruby as ruby -rubygems. The -r option requires a library, so this option essentially does a require 'ubygems' each time Ruby is started. (The odd name of ubygems was picked to look nice next to -r.)
We’re going to be doing something similar, but with our own library. I’ve traditionally put this file in ~/.ruby/lib/tpope.rb, but I will be using the more user-agnostic mine.rb for the purposes of this example.
The first thing we need to do is find the right place to set this environment variable, along with setting RUBYLIB to a path that holds our file. If you are using a bourne compatible shell, like bash, add this to your shell’s rc file (~/.bashrc for bash):
if [ -f "$HOME/.ruby/lib/mine.rb" ]; then
RUBYLIB="$HOME/.ruby/lib"
RUBYOPT="rmine"
export RUBYLIB RUBYOPT
fi
For C shells, add the following to ~/.cshrc:
if ( -f "$HOME/.ruby/lib/mine.rb" ) then
setenv RUBYLIB "$HOME/.ruby/lib"
setenv RUBYOPT "rmine"
endif
If you are running under a GUI environment, you will want to make this variables known to the top level GUI as well. Both Windows and Mac OS X have interfaces to set environment variables. Some desktop environments running under X11 provide such an interface as well, or you can just add similar lines to ~/.xsession or ~/.xinitrc, depending on your setup.
So now that we have this configured, what can we add to this new file? Plenty of things. Let’s start by enhancing the $LOAD_PATH (also known as $:). My strategy here is to pop the current working directory off the end, add a few more directories, then restore it.
old_current = $LOAD_PATH.pop if $LOAD_PATH.last == '.'
%w(.ruby/lib ruby/lib .ruby ruby).each do |dir|
$LOAD_PATH.unshift(File.expand_path("~/#{dir}"))
end
Dir[File.expand_path('~/ruby/*/lib')].each do |dir|
$LOAD_PATH << dir
end
$LOAD_PATH << old_current if old_current
$LOAD_PATH.uniq!
I add a wide variety of directories here, feel free to adjust as you see fit. Note the addition of every directory matching ~/ruby/*/lib, which makes it easy to install new libraries in ~/ruby. This is something that would be tricky to do just by adjusting RUBYLIB.
Next, let’s load RubyGems. We can do this in such a way that it won’t fail on systems where it’s not installed.
begin
require 'rubygems'
rescue LoadError
end
What else? How about always keeping good old Symbol#to_proc handy.
class Symbol
def to_proc
Proc.new { |*args| args.shift.__send__(self,*args) }
end
end
One thing to be careful about is not letting your code grow dependent on this auto-loaded library. For example, if you add the above snippet and start doing pets.each(&:feed) all over the place, your code will break for other people without your library. I still define Symbol#to_proc because it’s handy for debug statements and quick scripts and it’s easy enough to avoid using where it’s important. But I avoid something more invasive like require 'active_support' because it’s harder to keep track of everything it provides. Use your own best judgement.