A mighty factory worker

In my last post i ranted slightly about having a factory instead of fixtures and why i think it's worth doing. The problem with Dan Marges' Factory is, however that it tends to create a whole lot of junk you don't need.

Allow me to explain. Let's take this snippet

def self.create_newspaper(attributes = {})
  default_attributes = {
    :customer => create_customer,
    :headline => "Read all about it!"
    :paperboy => create_paperboy
  }
  Newspaper.create! default_attributes.merge(attributes)
end
Let's say we had a paperboy already created in this particular situation and we passed it to the method via the attributes param. After this call, like it or not, we'll be stuck with two paperboys. Add to this validations and the fact that the point of factory is to write less test data than you would with fixtures and you'll most likely see my point.

So let's recap what we'd like. We'd like something that creates all attached models to the one we call, and we'd like it to do so without screwing up every single thing in the universe. Sounds easy enough.

Let's say we have pickle which belongs to jar which belongs to shelf. When we call create_shelf we'd like our mighty class to also create pickles and jars to go along with our nice green shelf.

Now at the time i had realised the simplicity of my needs, i had already gone into a great deal of trouble and writing to order my functions in a 'factory' sort of way. I had create_pickle, create_jar and create_shelf all ready, and waiting for my signal. Not wanting to reformat all my code, i namely my newly-created method 'clever_create'. Its story was as follows

  def self.clever_create(klass, existing = {})
    call_stack = [:pickle, :jar, :shelf]

    create_params = {}

    call_stack.each do |current|
      create_params[current] = existing[current] || eval("self.create_#{current}(create_params)")
      break if current == klass
    end

    create_params
  end
That should pretty much take care of creating your objects for you and return your whole bunch of stuff in one neatly packed hash. The only problem is that, since you're doing a merge on the create_params in your create functions, some of those keys might not have methods in your models. As such, you should change your merge to an exclusive merge, which, oh noes, is not present in the manual ! What are we to do ? One option would be to run around screaming in anguish and dismay until we feint, another would be, as we are in ruby, to just create one.
class Hash
  def exclusive_merge(other)
    self.each_key do |key|
      self[key] = other[key] if other.has_key?(key)
    end
  end
end
So there it is. If there is one already, i couldn't find it because it isn't called 'exclusive_merge'. If there isn't, then it's all good.

There would be more to add, but sadly my alcoholic beverage of choice is getting quite warm by now, and i must continue another time. As such, i bid you farewell and good fortune !

Even more metaprogramming

Well, it's been a couple of weeks since i've posted anything and i do feel quite guilty about it. Therefore, i shall post more metaprogramming ! In the project i'm currently working on, it has been my great displeasure to encounter blocks similar to the following

def xml_goats
  configuration_node.root.elements["goats"].text.strip
end
  
def xml_apples
  configuration_node.root.elements["apples"].text.strip
end
  
def xml_cherries
  configuration_node.root.elements["cherries"].text.strip
end

I don't know about you, but to me, that just screams "metametametameta !!!". And it's not just because i'll use any excuse to stick some metaprogramming in my classes, but it genuinely looks like a load of nasty copy-paste malarkey. As such, i proceeded with my evil deeds

class Margerine
  %w[goats apples cherries].each{|x| 
    class_eval(%Q{
      def xml_#{x}
        configuration_node.root.elements["#{x}"].text.strip
      end
    })
  }
end

This by all means pretty much works as expected, and defines all those lovely functions for me. However, it still leaves me feeling a bit empty and unsatisfied. What if someday, somehow, we have more of these functions and they require a different set of method calls on the given node ? What will happen to our beautiful code then ? Will it be thrown to the gutter, like an old mistress with a dirty stocking ? Will it be fed to the wolves, like a lovingly furry squirrel who has eaten one too many hazelnuts ? That would most certainly not do. As such, we must make our code better, stronger, and even more delicious.

class Margerine
  def self.attr_xml_reader(items,submethod = "text.strip")
    items.each{|item|
      class_eval( %Q{
        def xml_#{item}
          configuration_node.root.elements["#{item}"].#{submethod}
        end
      }	)
    }
  end

  attr_xml_reader %w[goats apples cherries], "text.strip.downcase"

end

Now we are indeed satisfied with our work, and knowing that all damsels and squirrels the world over are safe and sound, we rest to code another day

Tasting the sweet nectar of metaprogramming

Metaprogramming is something you hear a lot about when you're around ruby, and with good reason. It's insanely powerful and hands down the most fun you can have with a programming language. Given that it's quite a complex topic, i'll start off slow - custom getters and setters. If you've used ruby for more than 20 minutes, you've probably seen attr_reader / attr_writer / attr_accessor. They're snippets of metaprogramming that just generate methods. Take attr_accessor, for instance. It gets you something to the tune of
def #{name}
  @#{name}
end

def #{name}=(value)
  @#{name} = value
end
But let's say you need something slightly more complex than that. Let's say you're writing an application which features sock possession reporting for animals with silly names. At least in my line of work, that's quite a common requirement. Being the magnificent human being you are, you'd like to write as little as possible. Therefore, you define a module
module Sockless
  def no_socks_for( *names )
    names.each { |name|
      class_eval("
        def #{name}_has_no_socks
          @#{name} + ' is a ghastly beast with no socks'
        end

        def #{name}=(value)
          @#{name} = value*2
        end")
    }
  end
end
Now you just have to extend your desired class with the Sockless module and you're home free
class TheSockZoo
  extend Sockless
  no_socks_for :pig, :sheep
end
Subsequently, you can amaze all sentient beings within a 10 mile radius by just adding these three lines of code and viewing the wonders of modern technology in action
r = TheSockZoo.new
r.pig,r.sheep = "gi","dee"
p r.pig_has_no_socks, r.sheep_has_no_socks