I have a magical proposal for the anti-magic web framework.
Controller methods do not use arguments and yet expect arguments. This
is handled through this params hash because we don't know in advance
what parameters a client could pass to Merb. But in almost every
instance, it is too much to know all the query parameters - one
doesn't care if the user threw in an extraneous variable - one only
cares about the variables we need to process the action.
Instead of using params we could make actions more functional by
taking advantage of this cool programming concept called 'arguments'.
An example
class ProductController
def show(id) # GET /products/show?id=12
@product = Product.find(id)
render
end
def index(page = 1) # GET /products?page=2
@products = Product.paginate_all(page)
render
end
end
Getting a parameter list for a method is rather difficult, but using
zenspider's ParseTree, it is possible. (Attached is a proof of
concept. It is also viewable at http://pastie.caboo.se/93218 )
ParseTree is slow, but it only needs to be run once at load - we can
cache the argument lists for each method.
It is extremely magical, but the magic is limited in scope - we are
not going to be using this all around the the source tree. Only for
controller actions.
It does not increase the frame stack and should have zero effect on performance.
Advantages:
- Less to type. No more params[:username], just username
- Cleaner API. At a glance it is visible what parameters actions take.
- params in its current state is slightly dangerous. Clients can pass
to it whatever (key, value) pairs they want and Merb will blindly
symbolizes the keys. These symbols are never garbage collected.
- We can automatically raise a BadRequest if the user does not supply
all of the arguments needed.
I would happily implement this if Ezra and the list thinks that this
would be a welcome feature.
ry
require 'rubygems'
require 'parse_tree'
class Class
def arguments(method)
@_args = Hash.new unless @_args # for caching the values
unless @_args.has_key?(method)
sexp_array = ParseTree.translate(self, method)
@_args[method] = self.class.arg_search(sexp_array)
end
@_args[method]
end
private
def self.arg_search(sexp_array)
if sexp_array.shift == :args
sexp_array.find_all { |e| e.kind_of?(Symbol) }
else
sexp_array.each do |node|
if node.kind_of?(Array)
args = arg_search(node)
return args if args
end
end
nil
end
end
end
class X
def y(a, b, d = 2, e = 'hello world')
end
def z
end
def w(alpha, beta, gamma)
end
end
puts X.arguments(:y).inspect
puts X.arguments(:z).inspect
puts X.arguments(:w).inspect_______________________________________________
Merb-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/merb-devel