Using Pry instead of IRB for Rails' console

Pry is a new-ish ruby gem that everyone should be using. Rather than me attempting to explain to you why it's so great, I suggest you skim the README. Highlights include "show-method", "edit-method", and almost everything else.

Rails doesn't make it particularly easy to use an "alternative" console, but if you stick "gem 'pry'" in your Gemfile, and paste the following code in an initializer, everything works just like magic.

# in config/initializers/pry.rb
begin
  require 'pry'
  module Rails
    class Console
      class IRB
        def self.start
          Pry.start
        end
      end 
    end
  end
rescue LoadError
end 

This is only tested in Rails 3.1. It should work in 3.0, but I don't think Rails::Console exists or works the same way in 2.3.x.

Opening Method Definitions from IRB

If you've spent any amount of time mucking around in irb to explore an API, you're familiar with the process. Run some code, go hunt for a method definition. Run some more code, go hunting again. I realized today that newer versions of ruby allow you to get the line number and file name of a method definition interactively, which led me to this handy ~/.irbrc snippet. You'll want to customize the third-to-last line a bit depending on what editor you use. If you're a textmate user, it'll probably just read "mate '#{x.__file__}'". Now, if you run something like "Fixnum.goto_instance_method('months')", your editor will open the ActiveSupport source at the definition of that method. Handy!

# Anywhere in ~/.irbrc...
class Object
  def goto_method(sym)
    __goto_method(method(sym))
  end 
  def goto_instance_method(sym)
    __goto_method(instance_method(sym))
  end 
  def __goto_method(x)
    system("$EDITOR -n '+#{x.__line__}' \"#{x.__file__}\"")
  end 
end 

Ruby's other BEGIN

No, I'm not talking about "begin", like begin/rescue/end begin. Ruby has a very, very strange feature that almost nobody knows about. It goes by the name of "BEGIN". Let's start with an example.

puts :first
BEGIN { puts :second }
# output:
#   second
#   first

Well that was unexpected! Even though "puts :first" should have been evaluated before the second line, the block we passed to BEGIN still somehow executed first. Let's try something else.

puts :first
BEGIN { puts :second }
puts :third
# output:
#   second
#   first
#   third

It seems that what's happening here is that the BEGIN block is evaluated first, no matter what the context. In fact, it's evaluated first even when it shouldn't normally be evaluated at all!

lambda { BEGIN { puts "This lambda is never called." } }
# output:
#   This lambda is never called.

This seems extremely counter-intuitive; however, the explanation is quite simple. You can think of the BEGIN block like C's preprocessor. Anywhere a BEGIN block is encountered, it's automatically run before the rest of the file is executed.

Conversely, there's also an END block available, which runs _after_ all the other code.

lambda { END { puts :first } }
puts :second
# output:
#   second

And yet, END doesn't seem to follow the same rules as BEGIN. It doesn't trigger even from within code that's never executed. Why? The answer is actually pretty simple. To execute BEGIN before the rest of the file's contents, ruby has to do an initial pass to scan for it. Since executing the code twice is a bad idea for several reasons, the least of which is performance, it can't reliably determine whether a BEGIN block is actually evaluated, so assumes that if it appears, and isn't in a comment, it should be evalutated. END, on the other hand, can be detected as it's encountered during the normal execution of the program.

I haven't been able to come up with a valid use for BEGIN or END. The only thing I could think of -- using END to run some chunk of code after the program dies in a horrible fire -- doesn't work, since the END block isn't run if the program terminates prematurely. If you can think of anything useful, please leave a comment.

Rails 3 shell functions

If you've started a new project in Rails 3 yet, you've probably been a little thrown by the new `rails` executable that replaces all the old `script/*` scripts. I found a post this morning with a shell function to choose whichever one exists (http://metaskills.net/2010/2/6/simple-script-console-function). Here's my adaptation of it to search up through the directory structure until it finds a Rakefile. This lets you call, for example, `sgm create_users` in app/models.

find-rakefile () {
  if [ -f $1/Rakefile ]; then
    echo $1
  else 
    echo $(find-rakefile $1/..)
  fi
}

rails-script () {
  rfpath=$(find-rakefile .)
  target=$1; shift
  if [ -f $rfpath/script/rails ]; then 
    $rfpath/script/rails $target $argv
  else
    $rfpath/script/$target $argv
  fi
}

sc () { rails-script "console"  $argv }
ss () { rails-script "server"   $argv }
sg () { rails-script "generate" $argv }
sg () { rails-script "runner"   $argv }
sgm() { rails-script "generate" "migration" $argv }
sgs() { rails-script "generate" "scaffold"  $argv }
sgr() { rails-script "generate" "resource"  $argv }

andand and andand2

I've been using Raganwald's andand quite a bit at work lately. It saves a lot of hassle, and I fells more elegant than the #try(:sym) syntax.

Andand, for those who don't know, is a shortcut for the frequently-used object && object.method pattern. You can instead write object.andand.method. In fact, you can even write object.andand.method1.method2.method3, which will just return nil instead of raising NoMethodError if method1 returns nil. The major problem I have with andand, though, is that if method1 returns non-nil, but method2 returns nil, you still get an error. To protect the entire chain against NoMethodErrors, you'd need to do object.andand.method1.andand.method2.andand.method3. Ugly.

While I realize this is out of andand's original scope, it's something I find myself wanting to do quite a bit, so I wrote my own version of andand that propagates its protection a little more loosely. With my version, anything after andand in the method chain is pretty well incapable of generating a NoMethodError. For example:

andand:

 "my_string".andand.size.to_f.to_s.gArBaGe.this_method_does_NOT_exist.size.foo.bar
 #=> NoMethodError: undefined method `gArBaGe' for "9.0":String 

andand2:

 "my_string".andand.size.to_f.to_s.gArBaGe.this_method_does_NOT_exist.size.foo.bar
 #=> nil 

I find this extremely useful when chaining together large numbers of methods, when any number of them could return nil. 

Check out the source at http://github.com/burke/andand2, or grab the gem "andand2" from gemcutter.

The Konami Code

Here's a quick code snippet to redirect to a new page when the user
enters the Konami code on your website. Yeah, I know. Old news. I just
wanted to try out posterous' syntax highlighting.

 

 
(function(){ 
 var s=0,w=window,k=[38,38,40,40,37,39,37,39,66,65]; 
 $(w).keydown(function(e){ 
  if((e.keyCode==k[s]?++s:s=0)>9)w.location="http://example.com/secret"; 
 }); 
})(); 

MonkeySupport: Monkeypatching Rails with C for significant performance increases

MonkeySupport is a brand new gem I'm working on that should give rails
a significant performance boost. It's still in its infancy, but the
goal is to reimplement parts of rails in C, via the ruby C extension
API. Thus far, I've done a few of the methods in the
ActiveSupport::Inflector, such as camelize, underscore, demodulize,
and so on, with an average runtime decrease of about 75%. You can find
the code on github, at http://github.com/burke/monkeysupport .

 You're welcome to try MonkeySupport out. To use it in your rails app,
just add "config.gem 'burke-monkeysupport', :lib => 'monkeysupport',
:source => 'http://gems.github.com' " to config/environment.rb. You
definitely *don't* want to use it in production yet though. I haven't
bothered to figure out a way to run it against rails' test suite since
I pulled it out of my rails fork a few days ago.

 The next thing I'm going to try to tackle for monkeysupport is html
helpers, like html_escape, link_to, image_tag, and so on. They're
called quite often, and string manipulation functions tend to be
easiest to rewrite in C.

 There are a few ways you can help out if you want: If you're ambitious
enough to port some ruby to C yourself, just fork monkeysupport and
send me a pull request; I'd also love to hear any feedback, comments,
criticisms, etc. you have. Benchmark results, cryptic errors, random
segfaults -- all appreciated.

 I'll get monkeysupport wired up to the rails test suite in the next
few days. releases 0.2.0 and onward will be fully tested. Stay tuned.