Class: Forme::Form

Inherits:
Object
  • Object
show all
Defined in:
lib/forme.rb

Overview

The Form class is the main entry point to the library.

Using the form, input, tag, and inputs methods, one can easily build an abstract syntax tree of Tag and Input instances, which can be serialized to a string using to_s.

Direct Known Subclasses

Rails::Form, Sinatra::Form

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(obj = nil, opts = {}) ⇒ Form

Creates a Form object. Arguments:

obj

Sets the obj for the form. If a hash, is merged with the opts argument to set the opts.

opts

A hash of options for the form



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/forme.rb', line 194

def initialize(obj=nil, opts={})
  @opts = opts.merge(obj.is_a?(Hash) ? obj : {:obj=>obj})
  @opts[:namespace] = Array(@opts[:namespace])

  if obj && obj.respond_to?(:forme_config)
    obj.forme_config(self)
  end

  config = CONFIGURATIONS[@opts[:config]||Forme.default_config]
  copy_inputs_wrapper_from_wrapper(@opts)

  TRANSFORMER_TYPES.each do |t|
    case @opts[t]
    when Symbol
      @opts[t] = Forme.transformer(t, @opts[t], @opts)
    when nil
      @opts[t] = Forme.transformer(t, config, @opts)
    end
  end

  @serializer = @opts[:serializer]
  @input_defaults = @opts[:input_defaults] || {}
  @hidden_tags = @opts[:hidden_tags]
  @nesting = []
end

Instance Attribute Details

#hidden_tagsObject (readonly)

The hidden tags to automatically add to the form.



141
142
143
# File 'lib/forme.rb', line 141

def hidden_tags
  @hidden_tags
end

#input_defaultsObject (readonly)

Set the default options for inputs by type. This should be a hash with input type keys and values that are hashes of input options.



138
139
140
# File 'lib/forme.rb', line 138

def input_defaults
  @input_defaults
end

#namespacesObject

The current namespaces for the form, if any.



145
146
147
# File 'lib/forme.rb', line 145

def namespaces
  @namespaces
end

#optsObject (readonly)

A hash of options for the form.



134
135
136
# File 'lib/forme.rb', line 134

def opts
  @opts
end

#serializerObject (readonly)

The serializer determines how Tag objects are transformed into strings. Must respond to call or be a registered symbol.



149
150
151
# File 'lib/forme.rb', line 149

def serializer
  @serializer
end

Class Method Details

.form(obj = nil, attr = {}, opts = {}, &block) ⇒ Object

Create a Form instance and yield it to the block, injecting the opening form tag before yielding and the closing form tag after yielding.

Argument Handling:

No args

Creates a Form object with no options and not associated to an obj, and with no attributes in the opening tag.

1 hash arg

Treated as opening form tag attributes, creating a Form object with no options.

1 non-hash arg

Treated as the Form‘s obj, with empty options and no attributes in the opening tag.

2 hash args

First hash is opening attributes, second hash is Form options.

1 non-hash arg, 1-2 hash args

First argument is Form‘s obj, second is opening attributes, third if provided is Form’s options.



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/forme.rb', line 167

def self.form(obj=nil, attr={}, opts={}, &block)
  f = if obj.is_a?(Hash)
    raise Error, "Can't provide 3 hash arguments to form" unless opts.empty?
    opts = attr
    attr = obj
    new(opts)
  else
    new(obj, opts)
  end

  ins = opts[:inputs]
  button = opts[:button]
  if ins || button
    block = Proc.new do |form|
      form._inputs(ins, opts) if ins
      yield form if block_given?
      form.emit(form.button(button)) if button
    end
  end

  f.form(attr, &block)
end

Instance Method Details

#<<(tag) ⇒ Object

Add the Input/Tag instance given to the currently open tag.



390
391
392
393
394
# File 'lib/forme.rb', line 390

def <<(tag)
  if n = @nesting.last
    n << tag
  end
end

#_input(*a) ⇒ Object

Create a new Input associated with the receiver with the given arguments, doing no other processing.



275
276
277
# File 'lib/forme.rb', line 275

def _input(*a)
  Input.new(self, *a)
end

#_inputs(inputs = [], opts = {}) ⇒ Object

Internals of #inputs, should be used internally by the library, where #inputs is designed for external use.



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/forme.rb', line 310

def _inputs(inputs=[], opts={}) # :nodoc:
  if inputs.is_a?(Hash)
    opts = inputs.merge(opts)
    inputs = []
  end

  form_opts = {}
  form_opts[:inputs_wrapper] = opts[:nested_inputs_wrapper] if opts[:nested_inputs_wrapper]
  TRANSFORMER_TYPES.each do |t|
    if opts.has_key?(t) && t != :inputs_wrapper
      form_opts[t] = opts[t]
    end
  end

  Forme.transform(:inputs_wrapper, opts, @opts, self, opts) do
    with_opts(form_opts) do
      inputs.each do |i|
        emit(input(*i))
      end
      yield if block_given?
    end
  end
end

#_tag(*a, &block) ⇒ Object

Create a Tag associated to the receiver with the given arguments and block, doing no other processing.



348
349
350
# File 'lib/forme.rb', line 348

def _tag(*a, &block)
  tag = Tag.new(self, *a, &block)
end

#button(opts = {}) ⇒ Object

Creates a :submit Input with the given opts, adding it to the list of children for the currently open tag.



382
383
384
385
386
387
# File 'lib/forme.rb', line 382

def button(opts={})
  opts = {:value=>opts} if opts.is_a?(String)
  input = _input(:submit, opts)
  self << input
  input
end

#closeObject

Returns a string representing the closing of the form tag, for serializers that support closing tags.



342
343
344
# File 'lib/forme.rb', line 342

def close
  serializer.serialize_close(_tag(:form)) if serializer.respond_to?(:serialize_close)
end

#each_obj(objs, namespace = nil) ⇒ Object

Calls the block for each object in objs, using with_obj with the given namespace and an index namespace (starting at 0).



398
399
400
401
402
403
404
# File 'lib/forme.rb', line 398

def each_obj(objs, namespace=nil)
  objs.each_with_index do |obj, i|
    with_obj(obj, Array(namespace) + [i]) do
      yield obj, i
    end
  end
end

#emit(tag) ⇒ Object

Empty method designed to ease integration with other libraries where Forme is used in template code and some output implicitly created by Forme needs to be injected into the template output.



228
229
# File 'lib/forme.rb', line 228

def emit(tag)
end

#form(attr = {}, &block) ⇒ Object

Create a form tag with the given attributes.



221
222
223
# File 'lib/forme.rb', line 221

def form(attr={}, &block)
  tag(:form, attr, method(:hidden_form_tags), &block)
end

#input(field, opts = {}) ⇒ Object

Creates an Input with the given field and opts associated with the receiver, and add it to the list of children to the currently open tag.

If the form is associated with an obj, or the :obj key exists in the opts argument, treats the field as a call to the obj. If obj responds to forme_input, that method is called with the field and a copy of opts. Otherwise, the field is used as a method call on the obj and a text input is created with the result.

If no obj is associated with the receiver, field represents an input type (e.g. :text, :textarea, :select), and an input is created directly with the field and opts.



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/forme.rb', line 244

def input(field, opts={})
  if opts.has_key?(:obj)
    opts = opts.dup
    obj = opts.delete(:obj)
  else
    obj = self.obj
  end
  input = if obj
    if obj.respond_to?(:forme_input)
      obj.forme_input(self, field, opts.dup)
    else
      opts = opts.dup
      opts[:key] = field unless opts.has_key?(:key)
      unless opts.has_key?(:value)
        opts[:value] = if obj.is_a?(Hash)
          obj[field]
        else
          obj.send(field)
        end
      end
      _input(:text, opts)
    end
  else
    _input(field, opts)
  end
  self << input
  input
end

#inputs(inputs = [], opts = {}, &block) ⇒ Object

Creates a tag using the inputs_wrapper (a fieldset by default), calls input on each element of inputs, and yields if given a block. You can use array arguments if you want inputs to be created with specific options:

inputs([:field1, :field2])
inputs([[:field1, {:name=>'foo'}], :field2])

The given opts are passed to the inputs_wrapper, and the default inputs_wrapper supports a :legend option that is used to set the legend for the fieldset.

opts can also include transformer options itself (e.g. :wrapper), which override the form’s current transformer options for the duration of the block. The exception is the :inputs_wrapper transformer option, which affects the wrapper to use for this inputs call. You can use the :nested_inputs_wrapper option to set the default :inputs_wrapper option for the duration of the block.

This can also be called with a single hash argument to just use an options hash:

inputs(:legend=>'Foo'){...}

or even without any arguments:

inputs{...}


304
305
306
# File 'lib/forme.rb', line 304

def inputs(inputs=[], opts={}, &block)
  _inputs(inputs, opts, &block)
end

#objObject

The object associated with this form, if any. If the Form has an associated obj, then calls to input are assumed to be accessing fields of the object instead to directly representing input types.



355
356
357
# File 'lib/forme.rb', line 355

def obj
  @opts[:obj]
end

#open(attr) ⇒ Object

Returns a string representing the opening of the form tag for serializers that support opening tags.



336
337
338
# File 'lib/forme.rb', line 336

def open(attr)
  serializer.serialize_open(_tag(:form, attr)) if serializer.respond_to?(:serialize_open)
end

#tag(*a, &block) ⇒ Object

Creates a Tag associated to the receiver with the given arguments. Add the tag to the the list of children for the currently open tag. If a block is given, make this tag the currently open tag while inside the block.



368
369
370
371
372
373
# File 'lib/forme.rb', line 368

def tag(*a, &block)
  tag = _tag(*a)
  self << tag
  nest(tag, &block) if block
  tag
end

#tag_(*a, &block) ⇒ Object

Aliased for tag. Workaround for issue with rails plugin.



376
377
378
# File 'lib/forme.rb', line 376

def tag_(*a, &block) # :nodoc:
  tag(*a, &block)
end

#with_obj(obj, namespace = nil) ⇒ Object

Temporarily override the given object and namespace for the form. Any given namespaces are appended to the form’s current namespace.



408
409
410
411
412
# File 'lib/forme.rb', line 408

def with_obj(obj, namespace=nil)
  with_opts(:obj=>obj, :namespace=>@opts[:namespace]+Array(namespace)) do
    yield obj
  end
end

#with_opts(opts) ⇒ Object

Temporarily override the opts for the form for the duration of the block. This merges the given opts with the form’s current opts, restoring the previous opts before returning.



417
418
419
420
421
422
423
424
# File 'lib/forme.rb', line 417

def with_opts(opts)
  orig_opts = @opts
  @opts = orig_opts.merge(opts)
  copy_inputs_wrapper_from_wrapper(opts, @opts)
  yield
ensure
  @opts = orig_opts if orig_opts
end