Posts

Showing posts from March, 2007

My Commute

Image
Working in downtown Chicago has its advantages -- everyday includes a scenic walk along the Chicago River: And after a hard day of delivering business value, who doesn't enjoy a movie and a nice drink?

Windows vs OSX vs Ubuntu for Ruby/Rails Development

When I first started working with Rails, I had a windows laptop and so that’s where I worked. Later I got on two different Rails projects that used OSX (on Mac minis). Now I’m using Kubuntu . I thought I’d take a minute to compare them all. I’m not going to mince words here -- try to avoid developing in Windows if at all possible for these reasons: Tests will run very slow (by a factor of 10 or more). The mysql drivers are not so good (When I developed in windows, I noticed I kept losing my connection to the database during operations that took more than a second or two and I couldn ’t get any of the replacement drivers to work). A fair amount of the plugins will be much harder to install (we are using the Raspell gem for “did you mean” functionality which needs aspell and the windows dudes still haven’t figured out how to install it. On Ubuntu , it was a simple “aptitude install”). Help online is usually not geared towards the Rails on Windows developer. If yo...

Using OpenStruct to Enhance Your Mocks

So I use RSpec's built in mocking framework for my mocking/stubbing and it works quite well. I sent up a mock like so: mock_active_record_instance = mock("give it a name here, but probably a better one than this") and put some expectations on it like so: mock_active_record_instance.should_receive(:id).and_return(1) but some calls to the mock I don't care about so I can stub them out like so: mock_active_record_instance.stub!(:name). and_return("Arthur, King of the Britons") If I don't need it to return anything I can leave off the and_return and it will return nil. But it's tedious to do that. Lately I tend to use OpenStructs as my mocks like so: mock_active_record_instance = OpenStruct.new mock_active_record_instance.should_receive(:id).and_return(1) Now here's what's cool about that: My spec(test) will fail if the expectation of a call to id isn't met, but any other calls will be ignored (and nil returned). If I had made mock_a...

Rails partials should be explicitly called with locals

Since Rails partials can see all the @variables of their parent view it’s pretty common to see partials with @’s all over the place. But the cool thing about partials is reusing them in other views and if you do you have to remember to populate all the stuff it needs and name everything the way it wants. Bah, I say. More and more I find myself explicitly calling partials with locals even if seems a bit redundant: 'content/poll', :locals => {:poll => @poll}) %> It goes along with this "partials are like methods" analogy I’ve been thinking about lately. And in big complicated pages with lots ‘o partials everything seems more clear. What do you think?

Mocking/Stubbing partials and helper methods in RSpec view specs

In my previous post I whined about not knowing how to mock/stub partials and helper methods in RSpec view specs. Now I have the answer and I’d like to thank the RSpec users mailing list and David Chelimsky for taking my phone call. In short, it’s all about @controller.template @controller.template.stub!(:a_helper_method).and_return(true) Stubs out the appropriately named a_helper_method and returns true. You can mock it out also like so: @controller.template.should_receive(:a_helper_method). at_least(:once).and_return(true) Which is like the stub except that it checks to see that a_helper_method was called at least once For partials you do this: @controller.template.should_receive(:render). with(:partial => 'form', :locals => {:cookie => mock_cookie}) Which checks to make sure the partial _form.rhtml is rendered and that the view attempted to pass mock_cookie in as a local. Since I didn’t specify a return it will return nil and I don’t have to worry about what’s...

What I want from view specs

I got an email today from a friend asking me about specifying views in RSpec in which he admitted he hadn’t done it much and first reaction was “I know what you mean!” Because it’s hard to spec views when you’re not hitting the database. You have to mock or stub out so many calls to your object just to get at the one or two lines you want to spec. And then I realized why I hate specifying views so much: It’s exactly like specifying a huge method. There’s all this stuff going on and you only care about one little bit and so you end up with 10 lines of mocking/stubbing to get to 3 lines of what you really want to say. Now with a ginormous method I have the option of pulling out little pieces of functionality into smaller methods and going straight at them. Then I can stub out those smaller methods when I’m specifying the big one. I can do this a little by creating a bunch of partials and specifying them individually, but when I want to spec the parent of all those partials I need...

Wrapping a Context in a Context (in RSpec)

A few days ago I blogged about solving a sticky problem by overwriting the “new” method on an ActiveRecord object inside a test (spec). Something I should have mentioned is that this is dangerous because if another spec (test) tries to call new and gets executed after the dangerous spec/test is run, then of course it won’t have the original new method. And it’s a very hard error to track down unless you know it’s been redefined. The solution to this, should you need to do it (and you probably won’t – any good mocking framework will probably do what you want), is to wrap a context around all the contexts that need it and use context_setup like this: context 'When the situation demands it' do context_setup do Class SomeObject def some_method_to_overwrite #do whatever I want -- Bwaa ha ha! end end end context 'Some context' do #specs go here end context 'Some other context' do #more specs go here end end After it ...

Rcov/RSpec problem solved in RSpec 0.8.2

I loves me some RSpec, but I’ve had this consistent problem on my last two projects when RSpec and Rcov are run together: Sometimes you get Seg Faults. In a previous post I talked about my solution to this (redefining the new method on ActiveRecord objects), but it was a hacky solution and I’m glad to say that it’s out of the code base as of today. On a hunch this weekend I installed RSpec 0.8.2 (we had been using 0.7.5.1), took out my super-fun hacktacular solution from a spec and it ran fine. But why? Looking through RSpec’s list of bugs fixed I didn’t see any reference to the bug I logged a few months ago (I didn’t really expect too – they were never able to reproduce it) but I do have any idea. David Chelimsky (lead dev of RSpec) had been telling me for awhile about how he was going to change RSpec to stop using method_missing on object because when Rails takes it for its own purposes, then RSpec has to some hacky things to steal it back (David wrote about it in ...

Lemme solve all your problems

Persistent, baffling problem? Windows: restart computer Linux: change file permissions I need to Tattoo this on the back of my hand so I can see it while I type. Long day.

Battle of the method_missings

So if you’ve heard about Ruby, you’ve probably heard about method_missing (short summary: if an object receives a message it doesn’t understand it calls method_missing which you can overwrite. This allows Rails ActiveRecord to handle User.find_by_email_and_name_and_phone_number on the fly -- it parses the message and gives you the method you want dynamically). But when too many things try to use it at once you get some interesting problems. At some point RSpec enabled calling object_instance.should_include('thing') by using method_missing on Object to catch any message that started with should_. So, in the previous example, RSpec would look for a method called include? on the object_instance, pass 'thing' into that, and tell you about it if it failed. Which is pretty cool because instead of saying: assert_equal ['a', 'b', 'c'], object_instance.some_method you could say: object_instance.should_eql ['a', 'b', 'c'] w...