F1e3ab214a976a39cfd713bc93deb10f

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

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 !

A8d3f35baafdaea851914b17dae9e1fc

Adam

January 9, 2009, January 09, 2009 21:11, permalink

1 rating. Login to rate!

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
F1e3ab214a976a39cfd713bc93deb10f

Tj Holowaychuk

January 9, 2009, January 09, 2009 23:28, permalink

No rating. Login to rate!

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

60888d58de3bf08cbc0c73e67fd6fd86

Josh Nussbaum

January 10, 2009, January 10, 2009 04:40, permalink

1 rating. Login to rate!

_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
F1e3ab214a976a39cfd713bc93deb10f

Tj Holowaychuk

January 10, 2009, January 10, 2009 17:21, permalink

No rating. Login to rate!

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

F1e3ab214a976a39cfd713bc93deb10f

Tj Holowaychuk

January 10, 2009, January 10, 2009 17:29, permalink

No rating. Login to rate!

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

Your refactoring





Format Copy from initial code

or Cancel