Monday, May 21, 2007

Ruby Require Idiom

Ruby's "require" command can accidentally load the same file twice.

The following example shows this problem (2 files)...

#----------
# file: problem.rb
puts "#{__FILE__} loaded"

#----------
# file: run_me.rb
require '././problem' #=> .\problem.rb loaded
require 'problem' #=> ./problem.rb loaded



When run_me requires problem.rb using slightly different paths, Kernel#require loads it twice. This happens because Kernel#require tracks the files it has loaded in the $" array. It only does a String compare, so if the file names differ it doesn't find the match.

There are several ways to avoid loading the same file twice. The first technique is to call require using the absolute path of the file. Since every file only has one absolute path, Kernal#require will not get confused. To get the absolute path, we can use File.expand_path as shown in the following example.
#----------
# file: ok.rb
puts "#{__FILE__} loaded"

#----------
# file: run_me.rb
require File.expand_path('././ok') #=> C:/ruby/require/expand_path/ok.rb loaded
require File.expand_path('ok') #=>



Another effective technique is using indirection. That is, require a file that requires other files. This technique works really well for loading libraries and gems. The first file may get loaded multiple times because of arguments to Kernel#require. But once inside this file, all calls to Kernel#require are the same. So the sub-files are not loaded multiple times. The following example illustrates this solution.

#----------
# file: run_me.rb
require 'base' #=> ./required_by_base.rb loaded
require '././base'

#----------
# file: base.rb
$:.unshift(File.expand_path(File.dirname(__FILE__))) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))

require 'required_by_base'

#----------
# file: required_by_base.rb
puts "#{__FILE__} loaded"



See how "base.rb" is required twice using different file paths. Kernel#require actually loaded "base.rb" twice. But "base.rb" didn't do anything except call Kernel#require to load other files. Since the parameter 'required_by_base' was the same in both calls, "required_by_base.rb" was only loaded once.

The first two lines of "base.rb" add the current directory to the search path. This wasn't really necessary for this example since the "required_by_base.rb" file is in the same directory. However, if the require used a relative path to another directory, it would have failed. By adding the current directory to the front of the search path this ensures the correct files are loaded.

If you look closely, you will see that the File.expand_path is used to put the absolute path into the search path. This avoids adding the same path twice.

Wednesday, May 02, 2007

DLR is here! Ruby soon to follow!

IronPython (2.0 Alpha) is now available with the Dynamic Language Runtime (DLR).

Microsoft also announced support for JScript on the DLR. They say releases of Ruby and VB will soon follow. (source: Jim Hugunin's Thinking Dynamic: A Dynamic Language Runtime)

This is great news to me.

Wednesday, April 25, 2007

Microsoft to support dynamic languages?

ZDNet published news that Microsoft will publish a "Dynammic Language Runtime" (DLR) to provide support for dynamic languages like Ruby to run on the .Net CLR.  This is great news to me.  I've tried many dynamic languages for .Net, but haven't found anything I could use in production.  IronPython is the best I've found.  But you can't fully integrate it into existing C# projects.  IronPython can use C# classes, but C# can't use IronPython classes.  I cant wait until the day I can run Ruby on .Net, with full integration to non-dynamic language projects.

Wednesday, April 18, 2007

RSpec

I been using RSpec for about 1 week now. I must say I really love it. Anyone who has worked with me knows I'm a test-first style developer. Now I switched to a spec-first developer!

RSpec is a ruby library for Behavior Driven Development (BDD). It accomplishes the same purpose as Unit Testing, automated tests for development. The big difference is BDD changes the way you think about tests.

With BDD, you begin by defining a "context" which is a situation or state of the system under test. For example, for a Stack object one context would be an "empty stack".

Next, you define the "specifications" for the "context". BDD uses language such as "should be", "should not" to describe the specification. In the "empty stack" context, the specification might include "should be empty", and "pop should throw exception". Within the specification we add the test code to check that the specification is followed. Here is the ruby code for this example:

context "A new stack" do

setup do
@stack = Stack.new
end

specify "should be empty" do
@stack.should be_empty
end

specify "pop must throw exception" do
lambda { @stack.pop }.should raise_error
end
end


Notice how easy it is to read the code above. This is what I like about RSpec verses xUnit. The contexts and specifications provide guidance about how to orginize your tests.

RSpec does not stop there. RSpec also includes RCov so you can easily see a report of test coverage. This is very handy to find holes in your specifications and tests. RSpec includes a mock object framework to help isolate the system under test. You can also use the mock objects to test the object interation of the system under test. RSpec does support Rails development.

Anyone interested in learning Behavior Driven Development or RSpec, I highly recommend working through the RSpec tutorial. The tutorial really provides a great exercise in BDD. I had read about BDD, but it wasn't until I completed the tutorial that I internalized it. (If you need Ruby, you can download it from ruby-lang.org, I use the Windows One-Click Install. Then type "gem install rspec" on the command-line to get rspec. Very quick and easy!)

Sunday, January 07, 2007

XBox 360

I joined the ranks of XBox 360 players this holiday season. My gamer profile link is NeverSleep360. I've also put my gamer card on the side bar. Game On!

Friday, January 05, 2007

I'm on Google EngEDU!

Jack Herrington in his presentation Code Generation With Ruby (Google Video), a comment references Dave Thomas's Blog post Rails and the Legacy World which talks about my post Let ActiveRecord support Enterprise Databases! The reference is part of the after presentation discussion at about 35 min in the video. One of the developers talks about the technique I used to modify ActiveRecord to support Sql Server, and references my blog post. Wow! I only thought a couple of my friends read this blog.

Mr. Herrington's presentation provides a good overview of Code Generation, different options, and notes about when it is appropriate or not. He then shows some implementations of Code Generation using Ruby and ERb. The discussion after the presentation is very interesting. They talk about different experiences with Code Generation and Active Record.

A couple of months ago I did some SQL code generation in Ruby. I should create a post about it soon.