Musings from the life of a developer, improvisor

Inherited resourcing and the power of subclassing

Posted: November 27th, 2008 | Author: Ari | Filed under: Code, Ruby, poolparty, poolparty internals |

In this edition of PoolParty internals, I’m going to show you how the basic resourcing is done. Virtual resourcing is out of the scope of this blog post, but we’ll come back to that on another blog post.

If you are not familiar with PoolParty, I urge you to check it out

From within PoolParty, resources are a cornerstone. Most all the resources implemented in PoolParty have the same basic structure of each other, but require different parameters. For instance, a file resource can have content associated with it, while an exec cannot. However, they both behave like each other in the context of usage.

Most of the resource classes in PoolParty are tiny. For instance, the Host resource is 4 lines long without a method defined.

module PoolParty
  module Resources        

    class Host < Resource
      default_options({
        :name => "$hostname",
        :ip => "$ipaddress"
      })
    end

  end
end

When the following code is in the pool.spec, the a new host resource is created (we’ll see later that it means a new instance of the Host class is instantiated) and stored in the containing class.

	has_host(:name => "orca", :ip => "67.125.84.125")
	# Note that this is the same as calling
	host(:name => "orca", :ip => "67.125.84.125")

Almost all of the resources implementation are that small. So how do we do this?

	def self.inherited(subclass)
	end

Because we already use the method_missing to create methods from on the cloud to keep our DSL clean, we will use inherited to create the methods we want on our containing class as well as to build a list of the available resources. Let’s look at the method currently implemented in PoolParty:

def self.inherited(subclass)
  subclass = subclass.to_s.split("::")[-1] if subclass.to_s.index("::")
  lowercase_class_name = subclass.to_s.underscore

  # Add add resource method to the Resources module
  unless PoolParty::Resources.respond_to?(lowercase_class_name.to_sym)
    method =<<-EOE
      def #{lowercase_class_name}(opts={}, parent=self, &blk)
        add_resource(:#{lowercase_class_name}, opts, parent, &blk)
      end
      def get_#{lowercase_class_name}(name)
        get_resource(:#{lowercase_class_name}, name) if in_a_resource_store?(:#{lowercase_class_name}, name)
      end
    EOE
    PoolParty::Resources.module_eval method
    PoolParty::Resources.add_has_and_does_not_have_methods_for(lowercase_class_name.to_sym)

    available_resources << subclass
  end
end
def self.add_has_and_does_not_have_methods_for(type=:file)
  module_eval <<-EOE
    def has_#{type}(opts={}, parent=self, &block)
      #{type}(#{type == :exec ? "opts" : "{:is_present => ''}.merge(opts)"}, parent, &block)
    end
    def does_not_have_#{type}(opts={}, parent=self, &block)
      #{type}(#{type == :exec ? "opts" : "{:is_absent => ''}.merge(opts)"}, parent, &block)
    end
  EOE
end

I’m going to make this quick, but feel free to stop me and ask me if something is confusing…

Whenever a class is subclassed, the parent class receives a callback hook called “inherited.” This method is called on any class that gets subclassed, for instance:

class A
  def self.inherited(sublcass)
    puts "inherited from #{sublcass}"
  end
end
class B < A
end

# inherited from B

This way, in order to add a resource to PoolParty, all we have to do is subclass the PoolParty::Resources::Resource class.

I’m making sure that we only have to run this method once, so that both the method doesn’t get uselessly overwritten and second that it’s nicer on GC. Second, we are adding two methods at the time to the resources (note, that clouds, pools, and plugins all include the Resources module, thus all these methods are allowed within those contexts.

Finally, we add the methods onto the class, add the add_has_and_does_not_have_methods_for methods to the class (this is where the has_ and does_not_have methods get added).

One thing you’ll note from this is that every single resource created can be called 3 ways, resource_name, has_resource_name and does_not_have_resource_name. Finally, we add it to the available_resources array just so we keep track of these.

I hope that works for you and that you can find a use for self.inherited.

Update: Stay tuned for a special inside PoolParty about rspec extensions… pretty hot stuff, IMHO.

Share and Enjoy:
  • Digg
  • LinkedIn
  • description
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • MySpace
  • Pownce
  • Print this article!
  • Reddit
  • Slashdot
  • ThisNext
  • TwitThis

One Comment on “Inherited resourcing and the power of subclassing”

  1. #1 Xnot.org » Blog Archive » Introducing Dslify! said at 8:17 pm on December 21st, 2008:

    [...] working on PoolParty was the DSL syntax. Because I wanted the syntax to be light enough where simple inheritance would allow you to introduce new class types and parented models, I wanted to be able to give any [...]


Leave a Reply