Eager to please annonymous objects

6 09 2008

I’ve been doing a lot of unit testing recently, and often find myself wishing that my mock objects actually had a state. So I could push a dumb object into the system and have a look at it when it comes out, without needing to tightly couple the stubbed methods on it to the implimentation. So I’ve written up a little method that’ll help you do exactly that. It allows for javascript style annonymous objects. As soon as you try to write to an attribute or read from one the getters and setters for that attribute are created.

def annon
  # Create a new blank, basic object
  annonymous_object = Object.new

  # If a attribute is called on this object that doesn't exist
  # we want to fake it
  def annonymous_object.method_missing name, *args
    # Figure out the base name of the attribute
    method_name = name.to_s[/[^=]*/]

    # Define the getter and setter
    self.instance_eval <<-METHODS
      def #{method_name}= value
        @#{method_name} = value
      end
      def #{method_name}
        @#{method_name}
      end
    METHODS

    # Call the attribute again
    send name, *args
  end

  # Now that we've created our annonymous object
  # we'll pass it to the block. Here attributes and
  # default values to be added to the object.
  yield annonymous_object if block_given?

  # Finally return the object we've built
  annonymous_object
end
Advertisements




Dynamically Loaded Classes

20 02 2008

Defining the class name of rails models when we’ve already named the file didn’t seem very DRY to me. So I wanted to find out if I could load files into a class named after the file (ie. Products.rb gets loaded in to Product class)

#!/usr/bin/env ruby

# Loop over all ruby files in the classes directory
Dir["classes/*.rb"].map do |file_name|
  # Save file name without extention or directories
  class_name = file_name[/[^\/]*(?=\.)/].to_sym

  # Execute the contents of the file inside a blank object
  class_object = Class.new
  class_object.instance_eval(File::read(file_name))

  # Bind the class to the name at the highest level
  Kernel.const_set(class_name, class_object)
end

This assumes that you have a bunch of ruby files inside a sub directory called ‘classes’ and all your ruby files have ‘.rb’ extension.