One of These Days

Instance Evil?

15 Jun 2011

Some playing with dynamic methods in a Ruby class led me into an interesting problem. ‘instance_eval’ was being used to allow for dynamic getting and setting of various attributes. This worked great, until the objects needed to be cached in Rails. An error was being thrown, “TypeError: singleton can’t be dumped”, which didn’t make immediate sense. Some digging and playing however led to the answer that Marshal cannot serialize objects that have had instance_eval used on them, which is probably fair enough as Marshall would have no way of knowing how to redo the eval when the object is loaded back again.

We can add an instance_eval block to add in an instance method, to demonstrate.

class A
  def initialize
    self.instance_eval do
      def unleash(what = nil)
         puts what 
      end
    end
  end
end

a = A.new
a.unleash("the hounds") # the hounds

However, we are not able to serialize the object ):

puts Marshal::dump(a) #> TypeError: singleton can't be dumped

The solution was to use the magical method_missing; we get the same result, but we’re also able to serialize the object.

class A
  def method_missing(m, *args, &block)
    puts "#{m}(#{args})"
  end  
end

a = A.new

a.unleash # unleash([])

a.unleash = 'the hounds' # unleash=(["the hounds"])

puts Marshal::dump(a) # o:A

Happily marshaled (:

(Reverse smilies inspired from Frank Chimero)