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

Reply via email to