Ruby Versus Java Conventions
Having spent a long time almost exclusively coding Java since about 2001. I have some mental baggage when it comes to adjusting to Ruby. Excepting some tinkering in PHP and Python in the last five years I’ve primarily been living in an IDE with Java when I actually got to code.
I realize I have this bias, and I’m adjusting, but a small bug fix I submitted to RSpec shows that I still probably have more adjustment to do. The problem isn’t important, and in fact it was just a change to one line of code that was necessary.
The line of code was:
def method_missing(sym, *args, &block) if __is_sweetened? sym object = self calls = sym.to_s.split("_") while calls.length > 1 call = calls.shift object = object.__send__(call) break if call == "be" end return object.__send__(calls.join("_"), *args, &block) end __orig_method_missing(sym, *args, &block) end
The important line is
1
|
break if call == "be"
|
. The context isn’t critical, but essentially it needed to add conditions to only break if the next element in the array wasn’t the strings ‘a’ or ‘an’. In my head I thought there was probably a nice clean Ruby way to do this, and heck Array has a lot of nice convenience methods, so I started there.
My first attempt came up as:
break if call == "be" && (calls.first != "a" || calls.first != "an")
I found the
1
|
first
|
method from Array and I liked that, but the rest of the conditional felt exactly like something I’d write in Java except it would have been:
break if call == "be" && (calls[0] != "a" || calls[0] != "an")
OK, time for a little refactoring for readability. Extract out the conditional to a method and give it a better name.
break if call == "be" && a_or_an_follows_be(calls) ... def a_or_an_follows_be(calls) return (calls.first != "a" || calls.first != "an") end
At this point I figured it was reasonable even if not probably the most Rubyesque. Luckily the new release of RSpec fixed this bug and I was able to see what they did:
break if call == "be" unless ["an","a"].include? calls[0]
Much more concise, I would have never thought of just using a simple two element array.
RSpec 0.5.14 Out
Yesterday I found a minor bug in RSpec 0.5.13. Today I got around to adding it to their RubyForge bugtracker complete with a suggested fix. Then I notice RSpec 0.5.14 just got released late tonight July 13, 2006. And there’s a release note on my bug being fixed:
1
|
* Sugar (underscores) now works correctly with should_be_a_kind_of and should_be_an_instance_of
|
The good thing is this is now a non-bug and RSpec appears to be pretty active right now.
A Small Bug in RSpec 0.5.13
I’m doing a recreational Rails project in my infrequent spare time and using RSpec as well. After generating a controller for the
1
|
Game
|
class I noticed it failed on a very simple specification.
controller.should_be_an_instance_of GameController
The failure message was:
undefined method 'an_instance_of?' for #<GameController:0x222df78>
That looked pretty wrong. Why was it trying to call
1
|
an_instance_of?
|
. It turns out
1
|
a
|
and
1
|
an
|
are just syntactic sugar methods that just return
1
|
self
|
. So just for fun I changed to the dot notation without the underscore sugar.
controller.should.be.an.instance.of GameController
That passed with flying colors. OK, so now I know it’s just an issue with the underscores. Writing a spec to show the issue was fairly simple:
context "Underscore Example Error" do specify "should_be_an_instance_of fails with underscore notation" do lambda { "example".should_be_an_instance_of String }.should_raise NoMethodError end specify "should.be.an.instance.of fails with underscore notation" do lambda { "example".should_not_be_an_instance_of Fixnum }.should_raise NoMethodError end specify "should_be_a_kind_of should fails underscore notation" do lambda { "example".should_be_a_kind_of Object }.should_raise NoMethodError end specify "should.not_be_a_kind_of fails with underscore notation" do lambda { "example".should_not_be_a_kind_of Fixnum }.should_raise NoMethodError end end
The bug appears to be with the following method in
def method_missing(sym, *args, &block) if __is_sweetened? sym object = self calls = sym.to_s.split("_") while calls.length > 1 call = calls.shift object = object.__send__(call) break if call == "be" end return object.__send__(calls.join("_"), *args, &block) end __orig_method_missing(sym, *args, &block) end
Hopefully tonight I’ll have time to code up a quick suggested patch and submit it. First I have to download a few gems and run the tests specs for RSpec to see if I might have broken something else with my fix.
I’m enjoying forcing myself to really think about contexts, specifications, and should statements instead of tests. I think I could probably accomplish about the same thing with good old
1
|
Test::Unit
|
, but forcing your brain to think down a different path can sometimes change your perspective.
Bring a Laptop to Your Interview
Apparently the Java developers market in Sacramento is heating up these days with about 20+ positions largely contracting for between $45-$75/hr. On that note one of the developers in the audience mentioned that he was doing a lot of interviewing and that bringing actual code on a laptop to an interview would really impress him, though he hadn’t seen anyone actually do that. As a hiring manager I can vouch that I would be impressed with someone who did that in an interview.
Beyond that at the SACJUG meeting Nick Chalko did a good overview of the TPTP plugin for Eclipse 3.2. Some of my developers are starting to look more into profiling so the overview was helpful. I’ve also heard that the new NetBeans has a really nice profiler.
Rails and RSpec over Lunch
With two small children at home I’ve lately been trying to get in about an hour of coding around lunch. These days thats Ruby on Rails and RSpec. I spent about half an hour today trying to figure out why RSpec was failing on the following:
"bob".should_be "bob"
Seemed reasonable especially since the following passed fine:
2.should_be 2
These were really simplified examples I came to after about the first 15 minutes. Turns out I found the answer by paying closer attention to the RSpec API. It turns out should_be calls the equal? method not the == method. Worked fine with:
"bob".should_be_equal "bob"
I’m enjoying trying out RSpec with Rails so far, though the startup time to run the specs is about 8-10 seconds on my laptop which is a bit annoying.