14km

Posts tagged ruby

Jan 17

Embedding IRB into your Ruby application

I needed to play around with Capybara/Selenium, but it’s a pain waiting for Firefox to start up every time you make a small change. Fortunately, I’m not the only one with the problem. Drop this somewhere:

require 'irb'

module IRB # :nodoc:
  def self.start_session(binding)
    unless @__initialized
      args = ARGV
      ARGV.replace(ARGV.dup)
      IRB.setup(nil)
      ARGV.replace(args)
      @__initialized = true
    end

    workspace = WorkSpace.new(binding)

    irb = Irb.new(workspace)

    @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
    @CONF[:MAIN_CONTEXT] = irb.context

    catch(:IRB_EXIT) do
      irb.eval_input
    end
  end
end 

And it’s use is quite simple. When you want to drop into an irb session, you simply do

IRB.start_session(binding)

May 27

Mocha doesn’t play nice with Rails 3 & Bundler

Using mocha with edge beta Rails 3, I added Mocha to the Gemfile

gem "mocha"

All was going swimmingly until I ran into a problem. I reduced it to:

The result of running this test was:

#test_mock_doesnt_fail should fail, but doesn’t. Changing the require lines at the top of the file to not load Rails and only load Mocha (+Rubygems+Test::Unit):

require "rubygems"
require "test/unit"
require "mocha"

caused the test to fail as expected. After an hour or two digging around, I stumbled across a post on the Mocha mailing-list that mentioned ordering problems with Mocha and Test::Unit. Sure enough, if I rearranged the modified require lines so that Test::Unit was loaded after Mocha:

require "rubygems"
require "mocha"
require "test/unit"

the test would break — I.e. wouldn’t fail.

Following the advice in the post — modified for bundler — I changed my Gemfile to read:

gem 'mocha', :require => nil

and added:

require "mocha"

to test/test_helper.rb to make sure Mocha was loaded. This isn’t strictly needed, but it’s good to be clear.

Final result, the test fails as expected, and Mocha is seems to be working properly.


Mar 31

Y Combinations

I found myself needing to use a Y-combinator last night, while playing with regular expressions. I wanted to recursively scan a string, finding matches inside other matches. Of course it could have been done by defining a function and calling it recursively, but that seemed unnecessary. I had a vague understanding of what a Y combinator was and what it could do, which allowed me to realise that it was what I needed in my regexp task. But of course I didn’t have one handy in my REPL of choice.

So that motivated me to spend the afternoon learning more about the Y combinator. Richard Gabriel’s Why of Y provided a good overview in Scheme, with me following along in a SBCL REPL — Which was a good experience about the differences between a Lisp-1 and a Lisp-2 in itself. An old post on Raganwald’s weblog had an implementation in Ruby, but it started a few steps in, so I spent some time re-deriving the contents of that post. I doubt that I’d be able to produce a Y combinator by myself yet, but it gave me a good idea how it works.

I ended up with (in Ruby):

def y &h
  lambda { |g|
    g[g]
  }[lambda { |f| lambda { |*args| h[f[f],*args] } }]
end

And in Common-lisp:

(defun y (f) 
  (let ((g (lambda (h)
    (lambda (n) 
      (funcall (funcall f (funcall h h)) n)))))
    (funcall g g)))

But I also just learned about flet, which would simplify the CL version a bit.

There is a simpler Ruby version that they start with on Raganwald’s site:

def y(&f)
    lambda { |*args| f[y(&f)][*args] }
end

And an equivalent Common-lisp version could be made (doesn’t seem very idiomatic, with the double funcall):

(defun y (f)
  (lambda (args)
    (funcall (funcall f (y f) args))))

I should post my working file that I used to nut it all out…