August 20, 2007

Introducing Argible: Simplifing your Ruby on Rails Controllers

Argible is a RubyForge project that was created to simplify Action methods within your Ruby on Rails Controllers. Argible annotated action methods will allow your Actions to define argument. These argument names will be used in conjunction with request parameters to automatically resolve these argument values. Have a look at the FoobarController code below:

class FoobarController < ApplicationController

argible
def action_one(alpha)
...
end

argible(:date => Date.method(:parse))
def action_two(date)
...
end

argible(:date => lambda {|v| Date.parse(v) } )
def action_three(date)
...
end

argible(:value => :to_i)
def action_four(value)
...
end
end

The first method action_one(alpha) is annotated with the method argible. When the action_one method is executed Argible will intercept the call and look up the request parameter value associated with alpha. Next the action_one method will be called with this resolved value.

The second action, action_two(date), provides an example of how more complex processing can occur on argument values. As in the first example the argument, this time named date, is resolved against the request parameters. The resulting value will then be passed to the Date#parse method. The result from Date#parse will then be used when action_two is called. **NOTE: any method can be used, Date#parse is simply used as an example.

The action action_three(date) provides an example of using a Proc (lambda) as alternative to a named method.

The fourth example action action_four(value) illustrates how you can call methods directly on the string value returned from
the request parameter.

Argible 0.1.0 is available for immediate use from http://rubyforge.org/projects/argible. RDoc can be found at http://argible.rubyforge.org.

5 comments:

Aslak Helles√ły said...

Although obviously nifty (ParseTree yay!) I'm not sure I understand what this simplifies for the programmer. Consider this plain rails equivalent:

class FoobarController < ApplicationController
def action_one
alpha = params[:alpha]
...
end

def action_two
date = Date.parse(params[:date])
...
end

def action_three
date = Date.parse(params[:date])
...
end

def action_four
value = params[:date].to_i
...
end
end

It has the same amount of code. Since it doesn't introduce a new "magic" concept, it's easier to understand - this is the same argument used against Java AOP for years.

We should be careful with accidental complexity

I would consider trying it out if I didn't have to use the argible method - this is where the accidental complexity comes in. The important benefit is the method args, converting them is less important - I can do that myself inside the method.

Michael Ward said...

Aslak - I agree completely that we don't want to add accidental complexity. The examples in this post were undoubtedly contrived. Those project that choose to use Argible are not required to use them on each and action. They can choose to use it only on actions where its use simplifies things.

Additionally, argument value resolution can be replaced/extended with a more advanced resolver implementation. For example, parameter value misses could proceed to search a users session level. This also means that Argible is NOT just suitable for rails projects, plug-in a custom resolver and use it in any ruby application.

Peter Ryan said...

I have to say I am a fan of argible - it will help me write less code. How often are my example more like this:

def action
a = params[:a]
b = params[:b]
c = params[:c]
...
end


It's a hassle to keep writing params[:whatever]. Maybe I am just being lazy but I quite like this:

argible
def action(a, b, c)
...
end

In which case I am writing 2 less lines of code.

That said Mike - you mention that I don't have to use it everywhere but what if I want to? Is it possible for me to add the the argible annotation to all actions so I could instead just write my actions like below and actually have something like this?

# no conversion argible
def action(a,b,c)
...
end

# argument transformation
argible :a => :to_i
def action_b(a)
@three_plus_a = 3 + a
end

# legacy code
def action_c
@a = params[:a]
end

Brian Guthrie said...

Is it just me, or does argible look suspiciously like Waffle's ActionMethod notation? :D

Kurman said...

I quite like the idea behind argible. It basically closes the gap in Rails where the programming approach looks like thick client model. HTTP is stateless and views are in-charge of converting actual objects to their string representations (be it Object ID in drop downs or hidden fields with selected row). By delegating rendering HTML representation of objects to views we can work with real object at controller level.

However, this type of abstraction is missing from postbacks and we have to explicitly create objects from strings sent back. I believe in majority of argible controllers can use global declarations if you keep controllers to perform actions limited to a single concern within the app. In addition to that it can make testing much clearer.

I would suggest to use some other examples that for instance work with some domain objects.