Mon25Jan

  1. Ruby 1.9 broke your ish…

    Ruby 1.9 has been here for a minute now. If you’re not already using it in production, get ready to because Rails, that opinionated little bugger, really wants you to use it with 3.0

    I’m sure you have seen this pattern for extending objects with your own functionality before:

    module IncredibleFunctionality
      def wozers
        # Your insanely great code here…
      end
    end
    
    ActiveRecord::Base.send :include, IncredibleFunctionality
    

    Slow down fast lane

    irb(main):001:0> Module.private_method_defined? :include
    => true

    This will blow up in your face with Ruby 1.9. include is a private method of Module and you can no longer use send to externally call private methods on an object in 1.9.

    Great. So what are our options?

    Open the class:

    class ActiveRecord::Base
      def wozers
        # Your insanely great code here…
      end
    end

    Yuck. Or slightly better:

    module IncredibleFunctionality
      def wozers
        # Your insanely great code here…
      end
    end
    class ActiveRecord::Base
      include IncredibleFunctionality
    end

    To me this is insanely horrible. There might be nothing wrong with this, but this just smells to me, from an aesthetic point at the very least. If it could be done in one line AND in a readble, sensible way before, that’s the way I want to do it now too.

    HACK AWAY:

    module IncredibleFunctionality
      def wozers
        # Your insanely great code here…
      end
    end
    
    ActiveRecord::Base.__send! :include, IncredibleFunctionality
    

    You can continue to use send to call private methods using __send! Although for me, it’s anathema to continue something that the Ruby maintainers thought badly enough of to change the API.

    Also worth mentioning that __send! is new for 1.9. so this will not work on the 1.8 branch, which makes this method kind of useless if you’re hoping that a lot of people might use your code.

    class_eval:

    module IncredibleFunctionality
      def wozers
        # Your insanely great code here…
      end
    end
    
    ActiveRecord::Base.class_eval { include IncredibleFunctionality }
    

    Sets the context of self in the block to the receiver. Allows us to call include with the implicit receiver being that of the object we wish to extend.

    WIN!

    These are the ways I’ve come up with to work around this issue. What are yours?