Monday, March 15, 2010

Ruby BlankSlate Issue.. or The Problem Of Accidental Monkey Patching

I was updating a Rails app recently and found the tests weren't running.
The error was reported in HoboField (an ace gem that lets define your model fields within your model and auto-generate your migrations by 'diff'ing between schema and models).

The error was .../hobo_fields/field_declaration_dsl.rb:22 'field': wrong number of arguments (1 for 2)

This was being thrown when ruby was getting to a model class like this...

class SomeModel < ActiveRecord::Base
fields do

The error turns out to be because the DSL class in Hobofields uses BlankSlate as it's base class. ActiveSupport also has a definition for BlankSlate, so Hobofields does an 'unless defined? BlankSlate' check before it defines one.

However... I was also using 'Riot' for my testing. Riot also defines BlankSlate.
The ActiveSupport version leaves the instance_eval method on the BlankSlate class. The Riot version removes it and doesn't check to see that BlankSlate is not already defined. Riot was accidentally Monkey Patching ActiveSupport.

As both libraries were being loaded, so the Riot definition was extending the ActiveSupport version and it was loosing it's instance_eval method. This leads to missing method picking up calls it shouldn't and eventually ends in the error I was getting.

I patched Riot and the problem went away. I expect to run into this sort of problem again in the future.

Do me a favor :) If you are developing a gem, please be really careful what you define in global space. It is best to namespace any classes you define so you don't risk cross over.


No comments:

GitHub Projects