Created
June 27, 2009 08:24
-
-
Save josevalim/136948 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# PROBLEM | |
# | |
# In order to provide agnosticism, a controller generator should know | |
# which methods the ORM make available to find, save, update, etc. | |
# | |
# SOLUTION #1 | |
# | |
# ORM should expose a generator builder that tell us what to do. | |
# This builder exposes AR methods and return custom implementations. | |
# | |
module ActiveRecord | |
module Generators | |
class Builder | |
# Builder.find("Foo", "1") #=> "Foo.find(1)" | |
def self.find(class_name, param) | |
"#{class_name}.find(#{param})" | |
end | |
def initialize(name) | |
@name = name | |
end | |
# builder = Builder.new("@foo") | |
# builder.save #=> "@foo.save" | |
def save | |
"#{name}.save" | |
end | |
end | |
end | |
end | |
# SOLUTION #2 | |
# | |
# Unfortunately, SOLUTION #1 does not solve test frameworks problem. | |
# Since some follow a mock approach, the builder above does not provide | |
# structured information. For example, there is no way to know what is | |
# the save method for Sequel ORM without reverse engineering the string. | |
# | |
# Another approach would be define a simple syntax to specify how any | |
# of these methods should be built. | |
# | |
module ActiveRecord | |
module Generators | |
class Builder | |
# Invoking: | |
# | |
# Builder.construct_find("Foo", "1") | |
# | |
# Returns: | |
# | |
# [ "Foo", [ :find, [ 1 ] ] ] | |
# | |
def self.construct_find(class_name, param) | |
[ class_name, [ :find, [ param ] ] ] | |
end | |
# Method missing will then be responsible for creating the string. | |
# If the user do "Builder.find", method missing will invoke | |
# construct_find and build the string. | |
# | |
# This is needed to deal with Ruby different ways to invoke a method: | |
# | |
# 1) a + b | |
# 2) a[b] | |
# 3) a[b] = c | |
# 4) a.method | |
# 5) a.method = c | |
# | |
# Builders returns arrays similar do s-expressions: | |
# | |
# ["Foo", [:find, [1]]] #=> Foo.find(1) | |
# ["Foo", [:find, [1,2]]] #=> Foo.find(1, 2) | |
# | |
# But it's somehow simplified because expressions can be given as arg: | |
# | |
# ["Foo", [:find, ["1 + 2"]]] #=> Foo.find(1 + 2) | |
# | |
# Consequently, strings must be inspected: | |
# | |
# ["Foo", [:find, ["foo".inspect]]] #=> Foo.find("foo") | |
# | |
# More examples: | |
# | |
# ["Foo", [:where, [1], :all]] #=> Foo.where(1).all | |
# | |
# And blocks? Since we do not need to know the code inside the block | |
# we just need to specify it and give hard coded content: | |
# | |
# ["Foo", [:build, [ [:block, "{ |b| b.where(1) }"] ], :all]] #=> Foo.build{ |b| b.where(1) }.all | |
# | |
def method_missing(method, *args, &block) | |
# magic | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment