include Form::Elements
form :login do
textfield :name, :label => 'Username'
textfield :pass, :label => 'Password'
submit :op, :value => 'Login'
end
form :login do |f|
f.textfield :name, :label => 'Username'
f.textfield :pass, :label => 'Password'
f.submit :op, :value => 'Login'
end
Refactorings
No refactoring yet !
Adam
January 9, 2009, January 09, 2009 21:11, permalink
It is considered bad form and you really should use your second example. However:
class FormBuilder
def initialize(name, &block)
@name = name
instance_eval(&block)
end
def textfield(*args)
# ...
end
def submit(*args)
# ...
end
end
def form(name, &block)
FormBuilder.new(name, &block)
end
# === Example ===
form :login do
textfield :name, :label => 'Username'
end
Tj Holowaychuk
January 9, 2009, January 09, 2009 23:28, permalink
It just makes for a cleaner DSL IMO, but I can see that it may cause some issues, to keep things simple and improve performance a bit I may just go with the second method
Josh Nussbaum
January 10, 2009, January 10, 2009 04:40, permalink
_why had a post about this a few months back. You can support both syntaxes, just check the arity (number of parameters) of block. if the arity==1 then do yield otherwise do instance_eval
def form(name, &block)
builder = FormBuilder.new(name)
if block.arity > 0
yield builder
else
builder.instance_eval(&block)
end
end
Tj Holowaychuk
January 10, 2009, January 10, 2009 17:21, permalink
For sure. I think the main issue in my case is that I would like the low-level methods (button, textarea, etc) to be available to the 'global' scope as well, for times when you are doing an XMLHttpRequest etc, so then it seems at least in my case above that the methods are called at that scope rather than on 'self' which would be the builder. But now that im saying that, does not seem right haha, I will take a look at my code again
Tj Holowaychuk
January 10, 2009, January 10, 2009 17:29, permalink
I do not have a builder object either actually. #form (and #fieldset) would just use this proxy class below in order to capture and render via #join all in one go. This originally worked pretty good but I will revise my thoughts here
class Proxy
def method_missing meth, *args, &block
(@elements ||= []) << Elements.send(meth, *args, &block)
end
end
Below is the syntax I would like. However the only problem I am running into is that even when #form uses a proxy object to redirect method calls to my Elements module, the instance evaluation of the block below still call the methods at the global scope, in turn not 'collecting' results of each invocation. I know I could simply pass an object to the block like the second example but I would way rather have it this way