Module: Sqrbl::MethodMissingDelegation
Overview
When used as directed, Sqrbl will create a graph of objects with bidirectional references to one another. The graph will have the following general shape (where –> indicates a relationship that is generally one-to-many):
Conversion –> Group –> StepPair –> Step
Also, because these various objects are created with blocks that are instance_eval’d, those blocks can define helper methods that will be added to the appropriate objects in the graph.
Taken together, these two features (back-references and instance_eval) let us provide a useful facility for defining helper methods inside a block, and accessing them using scoping rules that work in an intuitive manner. For example, if a Conversion defines a method #foo, which is later called from inside a Step’s block, the Step can catch that call using method_missing and delegate it to its StepPair, which in turn will delegate to its Group, which in turn will delegate to its Conversion.
Confused yet? Here’s a slightly modified version of the example in README.txt:
Sqrbl.conversion "Convert from old widgets to new widgets" do
def new_widget_insert()
insert_into("new_widgets", {
:name => 'widget_name',
:part_num => 'CONCAT("X_", part_number)',
:note => '"Imported from old_widgets"',
})
end
group "Widgets" do
step "Create widgets" do
up do
action "Migrate old_widgets" {
"#{new_widget_insert()} FROM old_widgets"
}
end
down do
action "Drop imported organizational contacts" {
'DELETE FROM new_widgets WHERE note LIKE "Imported from old_widgets"'
}
end
end
end
end
Note that the call to new_widget_insert occurs several layers of nesting down from its definition. By using this method_missing delegation strategy, we can effectively hide Sqrbl’s object model from the user and provide something that “just works.”
(Without this strategy, the above example would need to define new_widget_insert as a lambda function that gets invoked using either #call or the square-bracket syntax, but I find that more awkward – hence this wee bit of metaprogramming.)
Class Method Summary collapse
Class Method Details
.included(receiver) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/sqrbl/mixins/method_missing_delegation.rb', line 62 def self.included(receiver) receiver.class_eval(<<-EOF, __FILE__, __LINE__) @@mm_delegate_accessor = nil # Defines the accessor method that instances of this class should use # when delegating +method_missing+ calls. def self.delegate_method_missing_to(accessor) @@mm_delegate_accessor = accessor end # If +delegate_method_missing_to+ was called on the class, # use the accessor defined there to find a delegate and # pass the unknown method to it. def method_missing(method, *args, &block) return super unless defined?(@@mm_delegate_accessor) && !@@mm_delegate_accessor.nil? delegate = self.send(@@mm_delegate_accessor) delegate.send(method, *args, &block) end EOF end |