forme 0.9.2 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/forme/rails.rb CHANGED
@@ -53,8 +53,8 @@ module Forme
53
53
 
54
54
  # If a block is not given, emit the inputs into the current output
55
55
  # buffer.
56
- def _inputs(*)
57
- if block_given?
56
+ def _inputs(inputs=[], opts={}) # :nodoc:
57
+ if block_given? && !opts[:subform]
58
58
  super
59
59
  else
60
60
  emit(super)
@@ -83,8 +83,8 @@ module Forme
83
83
  template.raw(tag.to_s)
84
84
  end
85
85
  end
86
-
87
- def tag_(type, attr={}, children=[])
86
+
87
+ def tag_(type, attr={}, children=[]) # :nodoc:
88
88
  tag = _tag(type, attr, children)
89
89
  emit(serializer.serialize_open(tag)) if serializer.respond_to?(:serialize_open)
90
90
  Array(tag.children).each{|c| emit(c)}
data/lib/forme/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Forme
2
2
  # Version constant, use <tt>Forme.version</tt> instead.
3
- VERSION = '0.9.2'.freeze
3
+ VERSION = '0.10.0'.freeze
4
4
 
5
5
  # Returns the version as a frozen string (e.g. '0.1.0')
6
6
  def self.version
@@ -15,18 +15,6 @@ module Sequel # :nodoc:
15
15
  # that use a <tt>Sequel::Model</tt> instance as the form's
16
16
  # +obj+.
17
17
  module SequelForm
18
- # Stack of objects used by subform. The current +obj+
19
- # is added to the top of the stack on a call to +subform+,
20
- # the nested associated object is set as the current +obj+ during the
21
- # call to +subform+, and when +subform+ returns, the top of the
22
- # stack is set as the current +obj+.
23
- attr_accessor :nested_associations
24
-
25
- # The namespaces that should be added to the id and name
26
- # attributes for the receiver's inputs. Used as a stack
27
- # by +subform+.
28
- attr_accessor :namespaces
29
-
30
18
  # Use the post method by default for Sequel forms, unless
31
19
  # overridden with the :method attribute.
32
20
  def form(attr={}, &block)
@@ -53,26 +41,31 @@ module Sequel # :nodoc:
53
41
  # :inputs :: Automatically call +inputs+ with the given values. Using
54
42
  # this, it is not required to pass a block to the method,
55
43
  # though it will still work if you do.
56
- # :legend :: If :inputs is also used, this is passed to it to override
57
- # the default :legend used. You can also use a proc as the value,
44
+ # :legend :: Overrides the default :legend used (which is based on the
45
+ # association name). You can also use a proc as the value,
58
46
  # which will called with each associated object (and the position
59
47
  # in the associated object already for *_to_many associations),
60
48
  # and should return the legend string to use for that object.
49
+ # :grid :: Sets up a table with one row per associated object, and
50
+ # one column per field.
51
+ # :labels :: When using the :grid option, override the labels that would
52
+ # be created via the :inputs option. If you are not providing
53
+ # an :inputs option or are using a block with additional inputs,
54
+ # you should specify this option.
61
55
  def subform(association, opts={}, &block)
62
56
  nested_obj = opts.has_key?(:obj) ? opts[:obj] : obj.send(association)
63
57
  ref = obj.class.association_reflection(association)
64
58
  multiple = ref.returns_array?
65
- i = -1
66
- ins = opts[:inputs]
67
- Array(nested_obj).each do |no|
68
- begin
69
- nested_associations << obj
70
- namespaces << "#{association}_attributes"
71
- namespaces << (i+=1) if multiple
72
- @obj = no
73
- emit(input(ref.associated_class.primary_key, :type=>:hidden, :label=>nil)) unless no.new?
74
- if ins
75
- options = opts.dup
59
+ grid = opts[:grid]
60
+ ns = "#{association}_attributes"
61
+
62
+ contents = proc do
63
+ send(multiple ? :each_obj : :with_obj, nested_obj, ns) do |no, i|
64
+ emit(input(ref.associated_class.primary_key, :type=>:hidden, :label=>nil, :wrapper=>nil)) unless no.new?
65
+ options = opts.dup
66
+ if grid
67
+ options.delete(:legend)
68
+ else
76
69
  if options.has_key?(:legend)
77
70
  if options[:legend].respond_to?(:call)
78
71
  options[:legend] = multiple ? options[:legend].call(no, i) : options[:legend].call(no)
@@ -84,32 +77,21 @@ module Sequel # :nodoc:
84
77
  options[:legend] = humanize(association)
85
78
  end
86
79
  end
87
- _inputs(ins, options, &block)
88
- else
89
- yield
90
80
  end
91
- ensure
92
- @obj = nested_associations.pop
93
- namespaces.pop if multiple
94
- namespaces.pop
81
+ options[:subform] = true
82
+ _inputs(options[:inputs]||[], options, &block)
95
83
  end
96
84
  end
85
+
86
+ if grid
87
+ labels = opts.fetch(:labels){opts[:inputs].map{|l, *| humanize(l)} if opts[:inputs]}
88
+ legend = opts.fetch(:legend){humanize(association)}
89
+ inputs({:inputs_wrapper=>:table, :nested_inputs_wrapper=>:tr, :wrapper=>:td, :labeler=>nil, :labels=>labels, :legend=>legend}, &contents)
90
+ else
91
+ contents.call
92
+ end
97
93
  nil
98
94
  end
99
-
100
- # Return a unique id attribute for the +field+, handling
101
- # nested attributes use.
102
- def namespaced_id(field)
103
- "#{namespaces.join('_')}_#{field}"
104
- end
105
-
106
- # Return a unique name attribute for the +field+, handling nested
107
- # attribute use. If +multiple+ is true, end the name
108
- # with [] so that param parsing will treat the name as part of an array.
109
- def namespaced_name(field, multiple=false)
110
- root, *nsps = namespaces
111
- "#{root}#{nsps.map{|n| "[#{n}]"}.join}[#{field}]#{'[]' if multiple}"
112
- end
113
95
  end
114
96
 
115
97
  # Helper class for dealing with Forme/Sequel integration.
@@ -157,8 +139,7 @@ module Sequel # :nodoc:
157
139
  type = opts[:type]
158
140
  if !type && (sch = obj.db_schema[field])
159
141
  meth = :"input_#{sch[:type]}"
160
- opts[:id] = form.namespaced_id(field) unless opts.has_key?(:id)
161
- opts[:name] = form.namespaced_name(field) unless opts.has_key?(:name)
142
+ opts[:key] = field unless opts.has_key?(:key)
162
143
  opts[:required] = true if !opts.has_key?(:required) && sch[:allow_null] == false && sch[:type] != :boolean
163
144
  handle_label(field)
164
145
 
@@ -183,8 +164,7 @@ module Sequel # :nodoc:
183
164
  raise(Error, "Unrecognized field used: #{field}") unless rt || type
184
165
  meth = :"input_#{type}"
185
166
  opts[:value] = nil unless rt || opts.has_key?(:value)
186
- opts[:id] = form.namespaced_id(field) unless opts.has_key?(:id)
187
- opts[:name] = form.namespaced_name(field, opts[:multiple]) unless opts.has_key?(:name)
167
+ opts[:key] = field unless opts.has_key?(:key)
188
168
  handle_label(field)
189
169
  if respond_to?(meth, true)
190
170
  opts.delete(:type)
@@ -217,22 +197,6 @@ module Sequel # :nodoc:
217
197
  opts[:label] = [opts[:label], form._tag(:abbr, {:title=>'required'}, '*')] if opts[:required]
218
198
  end
219
199
 
220
- # Add the label to the start of the array, returning the array.
221
- def add_label(label, array)
222
- array.unshift(form._tag(:span, {:class=>:label}, label)) if label
223
- array
224
- end
225
-
226
- # Unset the wrapper and tag_wrapper options and return a
227
- # array with the wrapper and tag_wrapper to use. The tag_wrapper
228
- # is for wrapping each individual tag.
229
- def get_wrappers
230
- tag_wrapper = opts.delete(:tag_wrapper) || :default
231
- wrapper = form.transformer(:wrapper, opts)
232
- opts.delete(:wrapper)
233
- [wrapper, tag_wrapper]
234
- end
235
-
236
200
  # Update the attributes and options for any recognized validations
237
201
  def handle_validations(f)
238
202
  m = obj.model
@@ -296,19 +260,13 @@ module Sequel # :nodoc:
296
260
  def association_many_to_one(ref)
297
261
  key = ref[:key]
298
262
  handle_errors(key)
299
- opts[:name] = form.namespaced_name(key) unless opts.has_key?(:name)
263
+ opts[:key] = key unless opts.has_key?(:key)
300
264
  opts[:value] = obj.send(key) unless opts.has_key?(:value)
301
265
  opts[:options] = association_select_options(ref) unless opts.has_key?(:options)
302
266
  if opts.delete(:as) == :radio
303
267
  handle_label(field)
304
- label = opts.delete(:label)
305
- val = opts.delete(:value)
306
- wrapper, tag_wrapper = get_wrappers
307
- radios = opts.delete(:options).map{|l, pk| _input(:radio, opts.merge(:value=>pk, :id=>"#{form.namespaced_id(key)}_#{pk}", :wrapper=>tag_wrapper, :label=>l, :label_attr=>{:class=>:option}, :checked=>(pk == val)))}
308
- add_label(label, radios)
309
- wrapper ? wrapper.call(radios, _input(:radio, opts)) : radios
268
+ _input(:radioset, opts)
310
269
  else
311
- opts[:id] = form.namespaced_id(key) unless opts.has_key?(:id)
312
270
  opts[:required] = true if !opts.has_key?(:required) && (sch = obj.model.db_schema[key]) && !sch[:allow_null]
313
271
  opts[:add_blank] = true if !opts.has_key?(:add_blank) && !(opts[:required] && opts[:value])
314
272
  handle_label(field)
@@ -327,19 +285,16 @@ module Sequel # :nodoc:
327
285
  klass = ref.associated_class
328
286
  pk = klass.primary_key
329
287
  field = "#{klass.send(:singularize, ref[:name])}_pks"
330
- opts[:name] = form.namespaced_name(field, :multiple) unless opts.has_key?(:name)
288
+ unless opts.has_key?(:key)
289
+ opts[:array] = true unless opts.has_key?(:array)
290
+ opts[:key] = field
291
+ end
331
292
  opts[:value] = obj.send(ref[:name]).map{|x| x.send(pk)} unless opts.has_key?(:value)
332
293
  opts[:options] = association_select_options(ref) unless opts.has_key?(:options)
333
294
  handle_label(field)
334
295
  if opts.delete(:as) == :checkbox
335
- label = opts.delete(:label)
336
- val = opts.delete(:value)
337
- wrapper, tag_wrapper = get_wrappers
338
- cbs = opts.delete(:options).map{|l, pk| _input(:checkbox, opts.merge(:value=>pk, :id=>"#{form.namespaced_id(field)}_#{pk}", :wrapper=>tag_wrapper, :label=>l, :label_attr=>{:class=>:option}, :checked=>val.include?(pk), :no_hidden=>true))}
339
- add_label(label, cbs)
340
- wrapper ? wrapper.call(cbs, _input(:checkbox, opts)) : cbs
296
+ _input(:checkboxset, opts)
341
297
  else
342
- opts[:id] = form.namespaced_id(field) unless opts.has_key?(:id)
343
298
  opts[:multiple] = true unless opts.has_key?(:multiple)
344
299
  _input(:select, opts)
345
300
  end
@@ -385,19 +340,14 @@ module Sequel # :nodoc:
385
340
 
386
341
  case opts[:as]
387
342
  when :radio
388
- wrapper, tag_wrapper = get_wrappers
389
- true_opts = opts.merge(:value=>opts[:true_value]||'t', :label=>opts[:true_label]||'Yes', :label_attr=>{:class=>:option}, :error=>nil, :wrapper=>tag_wrapper, :wrapper_attr=>{})
390
- false_opts = opts.merge(:value=>opts[:false_value]||'f', :label=>opts[:false_label]||'No', :label_attr=>{:class=>:option}, :wrapper=>tag_wrapper, :wrapper_attr=>{})
391
- if i = opts[:id]
392
- true_opts[:id] = "#{i}_yes"
393
- false_opts[:id] = "#{i}_no"
394
- end
395
343
  v = opts.has_key?(:value) ? opts[:value] : obj.send(field)
344
+ true_value = opts[:true_value]||'t'
345
+ false_value = opts[:false_value]||'f'
346
+ opts[:options] = [[opts[:true_label]||'Yes', {:value=>true_value, :key_id=>'yes'}], [opts[:false_label]||'No', {:value=>false_value, :key_id=>'no'}]]
396
347
  unless v.nil?
397
- (v ? true_opts : false_opts)[:checked] = true
348
+ opts[:value] = v ? true_value : false_value
398
349
  end
399
- array = add_label(opts[:label], [_input(:radio, true_opts), _input(:radio, false_opts)])
400
- wrapper ? wrapper.call(array, _input(:radio, opts)) : array
350
+ _input(:radioset, opts)
401
351
  when :select
402
352
  v = opts[:value] || obj.send(field)
403
353
  opts[:value] = (v ? 't' : 'f') unless v.nil?
@@ -487,8 +437,7 @@ module Sequel # :nodoc:
487
437
  # specific code, such as support for nested attributes.
488
438
  def forme_config(form)
489
439
  form.extend(SequelForm)
490
- form.nested_associations = []
491
- form.namespaces = [model.send(:underscore, model.name)]
440
+ form.namespaces << model.send(:underscore, model.name)
492
441
  form.extend(SinatraSequelForm) if defined?(::Forme::Sinatra::Form) && form.is_a?(::Forme::Sinatra::Form)
493
442
  end
494
443
 
@@ -0,0 +1,13 @@
1
+ require 'coverage'
2
+ require 'simplecov'
3
+
4
+ def SimpleCov.forme_coverage(opts = {})
5
+ start do
6
+ add_filter "/spec/"
7
+ add_group('Missing'){|src| src.covered_percent < 100}
8
+ add_group('Covered'){|src| src.covered_percent == 100}
9
+ yield self if block_given?
10
+ end
11
+ end
12
+
13
+ ENV.delete('COVERAGE')
data/spec/forme_spec.rb CHANGED
@@ -45,6 +45,136 @@ describe "Forme plain forms" do
45
45
  @f.input(:text, :style=>"foo").to_s.should == '<input style="foo" type="text"/>'
46
46
  end
47
47
 
48
+ specify "should use :key option as name and id attributes" do
49
+ @f.input(:text, :key=>"foo").to_s.should == '<input id="foo" name="foo" type="text"/>'
50
+ end
51
+
52
+ specify "should use :key_id option as suffix for :key option id attributes" do
53
+ @f.input(:text, :key=>"foo", :key_id=>'bar').to_s.should == '<input id="foo_bar" name="foo" type="text"/>'
54
+ end
55
+
56
+ specify "should have :key option respect :multiple option" do
57
+ @f.input(:text, :key=>"foo", :multiple=>true).to_s.should == '<input id="foo" name="foo[]" type="text"/>'
58
+ end
59
+
60
+ specify "should use :key option respect form's current namespace" do
61
+ @f.with_opts(:namespace=>['bar']) do
62
+ @f.input(:text, :key=>"foo").to_s.should == '<input id="bar_foo" name="bar[foo]" type="text"/>'
63
+ @f.input(:text, :key=>"foo", :multiple=>true).to_s.should == '<input id="bar_foo" name="bar[foo][]" type="text"/>'
64
+ @f.with_opts(:namespace=>['bar', 'baz']) do
65
+ @f.input(:text, :key=>"foo").to_s.should == '<input id="bar_baz_foo" name="bar[baz][foo]" type="text"/>'
66
+ end
67
+ end
68
+ end
69
+
70
+ specify "should consider form's :values hash for default values based on the :key option if :value is not present" do
71
+ @f.opts[:values] = {'foo'=>'baz'}
72
+ @f.input(:text, :key=>"foo").to_s.should == '<input id="foo" name="foo" type="text" value="baz"/>'
73
+ @f.input(:text, :key=>"foo", :value=>'x').to_s.should == '<input id="foo" name="foo" type="text" value="x"/>'
74
+
75
+ @f.input(:text, :key=>:foo).to_s.should == '<input id="foo" name="foo" type="text" value="baz"/>'
76
+ @f.opts[:values] = {:foo=>'baz'}
77
+ @f.input(:text, :key=>:foo).to_s.should == '<input id="foo" name="foo" type="text" value="baz"/>'
78
+ end
79
+
80
+ specify "should consider form's :values hash for default values based on the :key option when using namespaces" do
81
+ @f.opts[:values] = {'bar'=>{'foo'=>'baz'}}
82
+ @f.with_opts(:namespace=>['bar']) do
83
+ @f.input(:text, :key=>"foo").to_s.should == '<input id="bar_foo" name="bar[foo]" type="text" value="baz"/>'
84
+ @f.input(:text, :key=>"foo", :value=>'x').to_s.should == '<input id="bar_foo" name="bar[foo]" type="text" value="x"/>'
85
+ @f.input(:text, :key=>:foo).to_s.should == '<input id="bar_foo" name="bar[foo]" type="text" value="baz"/>'
86
+ end
87
+
88
+ @f.with_opts(:namespace=>[:bar]) do
89
+ @f.input(:text, :key=>:foo).to_s.should == '<input id="bar_foo" name="bar[foo]" type="text" value="baz"/>'
90
+
91
+ @f.opts[:values] = {:bar=>{:foo=>'baz'}}
92
+ @f.input(:text, :key=>:foo).to_s.should == '<input id="bar_foo" name="bar[foo]" type="text" value="baz"/>'
93
+ @f.opts[:values] = {:bar=>{}}
94
+ @f.input(:text, :key=>:foo).to_s.should == '<input id="bar_foo" name="bar[foo]" type="text"/>'
95
+ @f.opts[:values] = {}
96
+ @f.input(:text, :key=>:foo).to_s.should == '<input id="bar_foo" name="bar[foo]" type="text"/>'
97
+
98
+ @f.opts[:values] = {'bar'=>{'quux'=>{'foo'=>'baz'}}}
99
+ @f.with_opts(:namespace=>['bar', 'quux']) do
100
+ @f.input(:text, :key=>"foo").to_s.should == '<input id="bar_quux_foo" name="bar[quux][foo]" type="text" value="baz"/>'
101
+ end
102
+ end
103
+ end
104
+
105
+ specify "should support a with_obj method that changes the object and namespace for the given block" do
106
+ @f.with_obj([:a, :c], 'bar') do
107
+ @f.input(:first).to_s.should == '<input id="bar_first" name="bar[first]" type="text" value="a"/>'
108
+ @f.with_obj([:b], 'baz') do
109
+ @f.input(:first).to_s.should == '<input id="bar_baz_first" name="bar[baz][first]" type="text" value="b"/>'
110
+ end
111
+ @f.with_obj([:b], %w'baz quux') do
112
+ @f.input(:first).to_s.should == '<input id="bar_baz_quux_first" name="bar[baz][quux][first]" type="text" value="b"/>'
113
+ end
114
+ @f.with_obj([:b]) do
115
+ @f.input(:first).to_s.should == '<input id="bar_first" name="bar[first]" type="text" value="b"/>'
116
+ end
117
+ @f.input(:last).to_s.should == '<input id="bar_last" name="bar[last]" type="text" value="c"/>'
118
+ end
119
+ end
120
+
121
+ specify "should support a each_obj method that changes the object and namespace for multiple objects for the given block" do
122
+ @f.tag(:form) do
123
+ @f.each_obj([[:a, :c], [:b, :d]], 'bar') do
124
+ @f.input(:first)
125
+ @f.input(:last)
126
+ end
127
+ end.to_s.should == '<form><input id="bar_0_first" name="bar[0][first]" type="text" value="a"/><input id="bar_0_last" name="bar[0][last]" type="text" value="c"/><input id="bar_1_first" name="bar[1][first]" type="text" value="b"/><input id="bar_1_last" name="bar[1][last]" type="text" value="d"/></form>'
128
+
129
+ @f.tag(:form) do
130
+ @f.each_obj([[:a, :c], [:b, :d]], %w'bar baz') do
131
+ @f.input(:first)
132
+ @f.input(:last)
133
+ end
134
+ end.to_s.should == '<form><input id="bar_baz_0_first" name="bar[baz][0][first]" type="text" value="a"/><input id="bar_baz_0_last" name="bar[baz][0][last]" type="text" value="c"/><input id="bar_baz_1_first" name="bar[baz][1][first]" type="text" value="b"/><input id="bar_baz_1_last" name="bar[baz][1][last]" type="text" value="d"/></form>'
135
+
136
+ @f.tag(:form) do
137
+ @f.each_obj([[:a, :c], [:b, :d]]) do
138
+ @f.input(:first)
139
+ @f.input(:last)
140
+ end
141
+ end.to_s.should == '<form><input id="0_first" name="0[first]" type="text" value="a"/><input id="0_last" name="0[last]" type="text" value="c"/><input id="1_first" name="1[first]" type="text" value="b"/><input id="1_last" name="1[last]" type="text" value="d"/></form>'
142
+ end
143
+
144
+ specify "should allow overriding form inputs on a per-block basis" do
145
+ @f.input(:text).to_s.should == '<input type="text"/>'
146
+ @f.with_opts(:wrapper=>:div){@f.input(:text).to_s}.should == '<div><input type="text"/></div>'
147
+ @f.with_opts(:wrapper=>:div){@f.input(:text).to_s.should == '<div><input type="text"/></div>'}
148
+ @f.with_opts(:wrapper=>:div) do
149
+ @f.input(:text).to_s.should == '<div><input type="text"/></div>'
150
+ @f.with_opts(:wrapper=>:li){@f.input(:text).to_s.should == '<li><input type="text"/></li>'}
151
+ @f.input(:text).to_s.should == '<div><input type="text"/></div>'
152
+ end
153
+ @f.input(:text).to_s.should == '<input type="text"/>'
154
+ end
155
+
156
+ specify "should handle delayed formatting when overriding form inputs on a per-block basis" do
157
+ @f.form do
158
+ @f.input(:text)
159
+ @f.with_opts(:wrapper=>:div) do
160
+ @f.input(:text)
161
+ @f.with_opts(:wrapper=>:li){@f.input(:text)}
162
+ @f.input(:text)
163
+ end
164
+ @f.input(:text)
165
+ end.to_s.should == '<form><input type="text"/><div><input type="text"/></div><li><input type="text"/></li><div><input type="text"/></div><input type="text"/></form>'
166
+ end
167
+
168
+ specify "should support :obj method to with_opts for changing the obj inside the block" do
169
+ @f.form do
170
+ @f.with_opts(:obj=>[:a, :c]) do
171
+ @f.input(:first)
172
+ @f.with_opts(:obj=>[:b]){@f.input(:first)}
173
+ @f.input(:last)
174
+ end
175
+ end.to_s.should == '<form><input id="first" name="first" type="text" value="a"/><input id="first" name="first" type="text" value="b"/><input id="last" name="last" type="text" value="c"/></form>'
176
+ end
177
+
48
178
  specify "should allow arbitrary attributes using the :attr option" do
49
179
  @f.input(:text, :attr=>{:bar=>"foo"}).to_s.should == '<input bar="foo" type="text"/>'
50
180
  end
@@ -157,10 +287,95 @@ describe "Forme plain forms" do
157
287
  @f.input(:select, :options=>[[:b, 2], [:c, 3]], :add_blank=>true, :value=>2).to_s.should == '<select><option value=""></option><option selected="selected" value="2">b</option><option value="3">c</option></select>'
158
288
  end
159
289
 
290
+ specify "should use Forme.default_add_blank_prompt value if :add_blank option is true" do
291
+ begin
292
+ Forme.default_add_blank_prompt = 'foo'
293
+ @f.input(:select, :options=>[[:b, 2], [:c, 3]], :add_blank=>true, :value=>2).to_s.should == '<select><option value="">foo</option><option selected="selected" value="2">b</option><option value="3">c</option></select>'
294
+ ensure
295
+ Forme.default_add_blank_prompt = nil
296
+ end
297
+ end
298
+
160
299
  specify "should use :add_blank option value as prompt if it is a String" do
161
300
  @f.input(:select, :options=>[[:b, 2], [:c, 3]], :add_blank=>"Prompt Here", :value=>2).to_s.should == '<select><option value="">Prompt Here</option><option selected="selected" value="2">b</option><option value="3">c</option></select>'
162
301
  end
163
302
 
303
+ specify "should create set of radio buttons" do
304
+ @f.input(:radioset, :options=>[1, 2, 3], :selected=>2).to_s.should == '<label class="option"><input type="radio" value="1"/> 1</label><label class="option"><input checked="checked" type="radio" value="2"/> 2</label><label class="option"><input type="radio" value="3"/> 3</label>'
305
+ @f.input(:radioset, :options=>[1, 2, 3], :value=>2).to_s.should == '<label class="option"><input type="radio" value="1"/> 1</label><label class="option"><input checked="checked" type="radio" value="2"/> 2</label><label class="option"><input type="radio" value="3"/> 3</label>'
306
+ end
307
+
308
+ specify "should create set of radio buttons with options and values" do
309
+ @f.input(:radioset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :selected=>2).to_s.should == '<label class="option"><input type="radio" value="1"/> a</label><label class="option"><input checked="checked" type="radio" value="2"/> b</label><label class="option"><input type="radio" value="3"/> c</label>'
310
+ end
311
+
312
+ specify "should create set of radio buttons with options and values with hashes" do
313
+ @f.input(:radioset, :options=>[[:a, {:attr=>{:foo=>1}}], [:b, {:class=>'foo', :value=>2}], [:c, {:id=>:baz}]], :selected=>2).to_s.should == '<label class="option"><input foo="1" type="radio" value="a"/> a</label><label class="option"><input checked="checked" class="foo" type="radio" value="2"/> b</label><label class="option"><input id="baz" type="radio" value="c"/> c</label>'
314
+ end
315
+
316
+ specify "should create set of radio buttons with options and values using given method" do
317
+ @f.input(:radioset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :text_method=>:last, :selected=>2).to_s.should == '<label class="option"><input type="radio" value="1"/> 1</label><label class="option"><input checked="checked" type="radio" value="2"/> 2</label><label class="option"><input type="radio" value="3"/> 3</label>'
318
+ @f.input(:radioset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :text_method=>:last, :value_method=>:first, :selected=>:b).to_s.should == '<label class="option"><input type="radio" value="a"/> 1</label><label class="option"><input checked="checked" type="radio" value="b"/> 2</label><label class="option"><input type="radio" value="c"/> 3</label>'
319
+ end
320
+
321
+ specify "should support :add_blank option for radioset inputs" do
322
+ @f.input(:radioset, :options=>[[:b, 2], [:c, 3]], :add_blank=>true, :value=>2).to_s.should == '<label class="option"><input type="radio" value=""/> </label><label class="option"><input checked="checked" type="radio" value="2"/> b</label><label class="option"><input type="radio" value="3"/> c</label>'
323
+ end
324
+
325
+ specify "should use :add_blank option value as prompt if it is a String" do
326
+ @f.input(:radioset, :options=>[[:b, 2], [:c, 3]], :add_blank=>"Prompt Here", :value=>2).to_s.should == '<label class="option"><input type="radio" value=""/> Prompt Here</label><label class="option"><input checked="checked" type="radio" value="2"/> b</label><label class="option"><input type="radio" value="3"/> c</label>'
327
+ end
328
+
329
+ specify "should respect the :key option for radio sets" do
330
+ @f.input(:radioset, :options=>[1, 2, 3], :key=>:foo, :value=>2).to_s.should == '<label class="option"><input id="foo_1" name="foo" type="radio" value="1"/> 1</label><label class="option"><input checked="checked" id="foo_2" name="foo" type="radio" value="2"/> 2</label><label class="option"><input id="foo_3" name="foo" type="radio" value="3"/> 3</label>'
331
+ end
332
+
333
+ specify "should create set of checkbox buttons" do
334
+ @f.input(:checkboxset, :options=>[1, 2, 3], :selected=>2).to_s.should == '<label class="option"><input type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" type="checkbox" value="2"/> 2</label><label class="option"><input type="checkbox" value="3"/> 3</label>'
335
+ @f.input(:checkboxset, :options=>[1, 2, 3], :value=>2).to_s.should == '<label class="option"><input type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" type="checkbox" value="2"/> 2</label><label class="option"><input type="checkbox" value="3"/> 3</label>'
336
+ end
337
+
338
+ specify "should create set of checkbox buttons with options and values" do
339
+ @f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :selected=>2).to_s.should == '<label class="option"><input type="checkbox" value="1"/> a</label><label class="option"><input checked="checked" type="checkbox" value="2"/> b</label><label class="option"><input type="checkbox" value="3"/> c</label>'
340
+ end
341
+
342
+ specify "should create set of checkbox buttons with options and values with hashes" do
343
+ @f.input(:checkboxset, :options=>[[:a, {:attr=>{:foo=>1}}], [:b, {:class=>'foo', :value=>2}], [:c, {:id=>:baz}]], :selected=>2).to_s.should == '<label class="option"><input foo="1" type="checkbox" value="a"/> a</label><label class="option"><input checked="checked" class="foo" type="checkbox" value="2"/> b</label><label class="option"><input id="baz" type="checkbox" value="c"/> c</label>'
344
+ end
345
+
346
+ specify "should create set of checkbox buttons with options and values using given method" do
347
+ @f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :text_method=>:last, :selected=>2).to_s.should == '<label class="option"><input type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" type="checkbox" value="2"/> 2</label><label class="option"><input type="checkbox" value="3"/> 3</label>'
348
+ @f.input(:checkboxset, :options=>[[:a, 1], [:b, 2], [:c, 3]], :text_method=>:last, :value_method=>:first, :selected=>:b).to_s.should == '<label class="option"><input type="checkbox" value="a"/> 1</label><label class="option"><input checked="checked" type="checkbox" value="b"/> 2</label><label class="option"><input type="checkbox" value="c"/> 3</label>'
349
+ end
350
+
351
+ specify "should support :add_blank option for checkboxset inputs" do
352
+ @f.input(:checkboxset, :options=>[[:b, 2], [:c, 3]], :add_blank=>true, :value=>2).to_s.should == '<label class="option"><input type="checkbox" value=""/> </label><label class="option"><input checked="checked" type="checkbox" value="2"/> b</label><label class="option"><input type="checkbox" value="3"/> c</label>'
353
+ end
354
+
355
+ specify "should use :add_blank option value as prompt if it is a String" do
356
+ @f.input(:checkboxset, :options=>[[:b, 2], [:c, 3]], :add_blank=>"Prompt Here", :value=>2).to_s.should == '<label class="option"><input type="checkbox" value=""/> Prompt Here</label><label class="option"><input checked="checked" type="checkbox" value="2"/> b</label><label class="option"><input type="checkbox" value="3"/> c</label>'
357
+ end
358
+
359
+ specify "should respect the :key option for checkbox sets" do
360
+ @f.input(:checkboxset, :options=>[1, 2, 3], :key=>:foo, :value=>2).to_s.should == '<label class="option"><input id="foo_1" name="foo[]" type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" id="foo_2" name="foo[]" type="checkbox" value="2"/> 2</label><label class="option"><input id="foo_3" name="foo[]" type="checkbox" value="3"/> 3</label>'
361
+ end
362
+
363
+ specify "should prefer the :name option to :key option for checkbox sets" do
364
+ @f.input(:checkboxset, :options=>[1, 2, 3], :key=>:foo, :name=>'bar[]', :value=>2).to_s.should == '<label class="option"><input id="foo_1" name="bar[]" type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" id="foo_2" name="bar[]" type="checkbox" value="2"/> 2</label><label class="option"><input id="foo_3" name="bar[]" type="checkbox" value="3"/> 3</label>'
365
+ end
366
+
367
+ specify "should prefer the :name and :id option to :key option for checkbox sets" do
368
+ @f.input(:checkboxset, :options=>[1, 2, 3], :key=>:foo, :name=>'bar[]', :id=>:baz, :value=>2).to_s.should == '<label class="option"><input id="baz_1" name="bar[]" type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" id="baz_2" name="bar[]" type="checkbox" value="2"/> 2</label><label class="option"><input id="baz_3" name="bar[]" type="checkbox" value="3"/> 3</label>'
369
+ end
370
+
371
+ specify "should respect the :error option for checkbox sets" do
372
+ @f.input(:checkboxset, :options=>[1, 2, 3], :error=>'foo', :value=>2).to_s.should == '<label class="option"><input type="checkbox" value="1"/> 1</label><label class="option"><input checked="checked" type="checkbox" value="2"/> 2</label><label class="option"><input class="error" type="checkbox" value="3"/> 3</label><span class="error_message">foo</span>'
373
+ end
374
+
375
+ specify "should raise an Error for empty checkbox sets" do
376
+ @f.input(:checkboxset, :options=>[], :error=>'foo', :value=>2).to_s.should == '<span class="error_message">foo</span>'
377
+ end
378
+
164
379
  specify "radio and checkbox inputs should handle :checked option" do
165
380
  @f.input(:radio, :checked=>true).to_s.should == '<input checked="checked" type="radio"/>'
166
381
  @f.input(:radio, :checked=>false).to_s.should == '<input type="radio"/>'
@@ -168,6 +383,11 @@ describe "Forme plain forms" do
168
383
  @f.input(:checkbox, :checked=>false).to_s.should == '<input type="checkbox"/>'
169
384
  end
170
385
 
386
+ specify "inputs should handle :autofocus option" do
387
+ @f.input(:text, :autofocus=>true).to_s.should == '<input autofocus="autofocus" type="text"/>'
388
+ @f.input(:text, :autofocus=>false).to_s.should == '<input type="text"/>'
389
+ end
390
+
171
391
  specify "inputs should handle :required option" do
172
392
  @f.input(:text, :required=>true).to_s.should == '<input required="required" type="text"/>'
173
393
  @f.input(:text, :required=>false).to_s.should == '<input type="text"/>'
@@ -283,6 +503,14 @@ describe "Forme plain forms" do
283
503
  @f.inputs([[:textarea, {:name=>'foo'}], [:text, {:id=>'bar'}]]).to_s.should == '<fieldset class="inputs"><textarea name="foo"></textarea><input id="bar" type="text"/></fieldset>'
284
504
  end
285
505
 
506
+ specify "should have #inputs accept transformer options to modify the options inside the inputs" do
507
+ @f.inputs([:textarea, :text], :wrapper=>:div).to_s.should == '<fieldset class="inputs"><div><textarea></textarea></div><div><input type="text"/></div></fieldset>'
508
+ end
509
+
510
+ specify "should have #inputs accept :nested_inputs_wrapper options to modify the :input_wrapper option inside the inputs" do
511
+ @f.inputs(:nested_inputs_wrapper=>:div){@f.inputs([:textarea, :text])}.to_s.should == '<fieldset class="inputs"><div><textarea></textarea><input type="text"/></div></fieldset>'
512
+ end
513
+
286
514
  specify "should escape tag content" do
287
515
  @f.tag(:div, {}, ['<p></p>']).to_s.should == '<div>&lt;p&gt;&lt;/p&gt;</div>'
288
516
  end
@@ -376,8 +604,14 @@ describe "Forme plain forms" do
376
604
  f.input(:textarea, :name=>"foo").to_s.should == '<textarea cols="80" name="foo" rows="6"></textarea>'
377
605
  end
378
606
 
607
+ specify "should work with input_defaults with symbol keys using using inputs with symbol keys" do
608
+ f = Forme::Form.new(:input_defaults=>{:text=>{:size=>20}, 'text'=>{:size=>30}})
609
+ f.input(:text, :name=>"foo").to_s.should == '<input name="foo" size="20" type="text"/>'
610
+ f.input('text', :name=>"foo").to_s.should == '<input name="foo" size="30" type="text"/>'
611
+ end
612
+
379
613
  specify "invalid custom transformers should raise an Error" do
380
- proc{Forme::Form.new(:wrapper=>Object.new)}.should raise_error(Forme::Error)
614
+ proc{Forme::Form.new(:wrapper=>Object.new).input(:text).to_s}.should raise_error(Forme::Error)
381
615
  proc{@f.input(:textarea, :wrapper=>Object.new).to_s}.should raise_error(Forme::Error)
382
616
  proc{@f.input(:textarea, :formatter=>nil).to_s}.should raise_error(Forme::Error)
383
617
  end
@@ -415,11 +649,11 @@ end
415
649
 
416
650
  describe "Forme custom" do
417
651
  specify "formatters can be specified as a proc" do
418
- Forme::Form.new(:formatter=>proc{|i| i.form._tag(:textarea, i.opts.map{|k,v| [v.upcase, k.to_s.downcase]})}).input(:text, :name=>'foo').to_s.should == '<textarea FOO="name"></textarea>'
652
+ Forme::Form.new(:formatter=>proc{|i| i.form._tag(:textarea, i.opts[:name]=>:name)}).input(:text, :name=>'foo').to_s.should == '<textarea foo="name"></textarea>'
419
653
  end
420
654
 
421
655
  specify "serializers can be specified as a proc" do
422
- Forme::Form.new(:serializer=>proc{|t| "#{t.type} = #{t.opts.inspect}"}).input(:textarea, :name=>'foo').to_s.should == 'textarea = {:name=>"foo"}'
656
+ Forme::Form.new(:serializer=>proc{|t| "#{t.type} = #{t.opts[:name]}"}).input(:textarea, :name=>'foo').to_s.should == 'textarea = foo'
423
657
  end
424
658
 
425
659
  specify "labelers can be specified as a proc" do
@@ -441,7 +675,7 @@ end
441
675
 
442
676
  describe "Forme built-in custom" do
443
677
  specify "transformers should raise if the there is no matching transformer" do
444
- proc{Forme::Form.new(:formatter=>:foo)}.should raise_error(Forme::Error)
678
+ proc{Forme::Form.new(:formatter=>:foo).input(:text).to_s}.should raise_error(Forme::Error)
445
679
  end
446
680
 
447
681
  specify "formatter: disabled disables all inputs unless :disabled=>false option" do
@@ -463,28 +697,42 @@ describe "Forme built-in custom" do
463
697
  Forme::Form.new(:labeler=>:explicit).input(:textarea, :id=>'foo', :label=>'bar').to_s.should == '<label for="foo">bar</label><textarea id="foo"></textarea>'
464
698
  end
465
699
 
700
+ specify "labeler: explicit handles the key option correctly" do
701
+ Forme::Form.new(:labeler=>:explicit, :namespace=>:baz).input(:textarea, :key=>'foo', :label=>'bar').to_s.should == '<label for="baz_foo">bar</label><textarea id="baz_foo" name="baz[foo]"></textarea>'
702
+ end
703
+
466
704
  specify "labeler: explicit should handle tags with errors" do
467
705
  Forme::Form.new(:labeler=>:explicit).input(:text, :error=>'Bad Stuff!', :value=>'f', :id=>'foo', :label=>'bar').to_s.should == '<label for="foo">bar</label><input class="error" id="foo" type="text" value="f"/><span class="error_message">Bad Stuff!</span>'
468
706
  end
469
707
 
470
708
  specify "wrapper: li wraps tag in an li" do
471
709
  Forme::Form.new(:wrapper=>:li).input(:textarea, :id=>'foo').to_s.should == '<li><textarea id="foo"></textarea></li>'
710
+ Forme::Form.new(:wrapper=>:li).input(:textarea, :id=>'foo', :wrapper_attr=>{:id=>'bar'}).to_s.should == '<li id="bar"><textarea id="foo"></textarea></li>'
472
711
  end
473
712
 
474
713
  specify "wrapper: p wraps tag in an p" do
475
714
  Forme::Form.new(:wrapper=>:p).input(:textarea, :id=>'foo').to_s.should == '<p><textarea id="foo"></textarea></p>'
715
+ Forme::Form.new(:wrapper=>:p).input(:textarea, :id=>'foo', :wrapper_attr=>{:id=>'bar'}).to_s.should == '<p id="bar"><textarea id="foo"></textarea></p>'
476
716
  end
477
717
 
478
718
  specify "wrapper: div wraps tag in an div" do
479
719
  Forme::Form.new(:wrapper=>:div).input(:textarea, :id=>'foo').to_s.should == '<div><textarea id="foo"></textarea></div>'
720
+ Forme::Form.new(:wrapper=>:div).input(:textarea, :id=>'foo', :wrapper_attr=>{:id=>'bar'}).to_s.should == '<div id="bar"><textarea id="foo"></textarea></div>'
480
721
  end
481
722
 
482
723
  specify "wrapper: span wraps tag in an span" do
483
724
  Forme::Form.new(:wrapper=>:span).input(:textarea, :id=>'foo').to_s.should == '<span><textarea id="foo"></textarea></span>'
725
+ Forme::Form.new(:wrapper=>:span).input(:textarea, :id=>'foo', :wrapper_attr=>{:id=>'bar'}).to_s.should == '<span id="bar"><textarea id="foo"></textarea></span>'
726
+ end
727
+
728
+ specify "wrapper: td wraps tag in an td" do
729
+ Forme::Form.new(:wrapper=>:td).input(:textarea, :id=>'foo').to_s.should == '<td><textarea id="foo"></textarea></td>'
730
+ Forme::Form.new(:wrapper=>:td).input(:textarea, :id=>'foo', :wrapper_attr=>{:id=>'bar'}).to_s.should == '<td id="bar"><textarea id="foo"></textarea></td>'
484
731
  end
485
732
 
486
733
  specify "wrapper: trtd wraps tag in an tr/td" do
487
734
  Forme::Form.new(:wrapper=>:trtd).input(:textarea, :id=>'foo').to_s.should == '<tr><td><textarea id="foo"></textarea></td><td></td></tr>'
735
+ Forme::Form.new(:wrapper=>:trtd).input(:textarea, :id=>'foo', :wrapper_attr=>{:id=>'bar'}).to_s.should == '<tr id="bar"><td><textarea id="foo"></textarea></td><td></td></tr>'
488
736
  end
489
737
 
490
738
  specify "wrapper: trtd supports multiple tags in separate tds" do
@@ -499,12 +747,44 @@ describe "Forme built-in custom" do
499
747
  Forme::Form.new(:wrapper=>:trtd, :labeler=>:explicit).input(:checkbox, :id=>'foo', :name=>'foo', :label=>'Foo').to_s.should == '<tr><td><label for="foo">Foo</label></td><td><input id="foo_hidden" name="foo" type="hidden" value="0"/><input id="foo" name="foo" type="checkbox"/></td></tr>'
500
748
  end
501
749
 
750
+ specify "wrapper: tr should use a td wrapper and tr inputs_wrapper" do
751
+ Forme::Form.new(:wrapper=>:tr).inputs([:textarea]).to_s.should == '<tr><td><textarea></textarea></td></tr>'
752
+ f = Forme::Form.new
753
+ f.with_opts(:wrapper=>:tr){f.inputs([:textarea])}.to_s.should == '<tr><td><textarea></textarea></td></tr>'
754
+ end
755
+
756
+ specify "wrapper: table should use a trtd wrapper and table inputs_wrapper" do
757
+ Forme::Form.new(:wrapper=>:table).inputs([:textarea]).to_s.should == '<table><tr><td><textarea></textarea></td><td></td></tr></table>'
758
+ f = Forme::Form.new
759
+ f.with_opts(:wrapper=>:table){f.inputs([:textarea])}.to_s.should == '<table><tr><td><textarea></textarea></td><td></td></tr></table>'
760
+ end
761
+
762
+ specify "wrapper: ol should use an li wrapper and ol inputs_wrapper" do
763
+ Forme::Form.new(:wrapper=>:ol).inputs([:textarea]).to_s.should == '<ol><li><textarea></textarea></li></ol>'
764
+ f = Forme::Form.new
765
+ f.with_opts(:wrapper=>:ol){f.inputs([:textarea])}.to_s.should == '<ol><li><textarea></textarea></li></ol>'
766
+ end
767
+
768
+ specify "wrapper: fieldset_ol should use an li wrapper and fieldset_ol inputs_wrapper" do
769
+ Forme::Form.new(:wrapper=>:fieldset_ol).inputs([:textarea]).to_s.should == '<fieldset class="inputs"><ol><li><textarea></textarea></li></ol></fieldset>'
770
+ f = Forme::Form.new
771
+ f.with_opts(:wrapper=>:fieldset_ol){f.inputs([:textarea])}.to_s.should == '<fieldset class="inputs"><ol><li><textarea></textarea></li></ol></fieldset>'
772
+ end
773
+
774
+ specify "wrapper should not override inputs_wrapper if both given" do
775
+ Forme::Form.new(:wrapper=>:tr, :inputs_wrapper=>:div).inputs([:textarea]).to_s.should == '<div><td><textarea></textarea></td></div>'
776
+ f = Forme::Form.new
777
+ f.with_opts(:wrapper=>:tr, :inputs_wrapper=>:div){f.inputs([:textarea])}.to_s.should == '<div><td><textarea></textarea></td></div>'
778
+ end
779
+
502
780
  specify "inputs_wrapper: ol wraps tags in an ol" do
503
781
  Forme::Form.new(:inputs_wrapper=>:ol, :wrapper=>:li).inputs([:textarea]).to_s.should == '<ol><li><textarea></textarea></li></ol>'
782
+ Forme::Form.new(:inputs_wrapper=>:ol, :wrapper=>:li).inputs([:textarea], :attr=>{:foo=>1}).to_s.should == '<ol foo="1"><li><textarea></textarea></li></ol>'
504
783
  end
505
784
 
506
785
  specify "inputs_wrapper: fieldset_ol wraps tags in a fieldset and an ol" do
507
786
  Forme::Form.new(:inputs_wrapper=>:fieldset_ol, :wrapper=>:li).inputs([:textarea]).to_s.should == '<fieldset class="inputs"><ol><li><textarea></textarea></li></ol></fieldset>'
787
+ Forme::Form.new(:inputs_wrapper=>:fieldset_ol, :wrapper=>:li).inputs([:textarea], :attr=>{:foo=>1}).to_s.should == '<fieldset class="inputs" foo="1"><ol><li><textarea></textarea></li></ol></fieldset>'
508
788
  end
509
789
 
510
790
  specify "inputs_wrapper: fieldset_ol supports a :legend option" do
@@ -513,10 +793,33 @@ describe "Forme built-in custom" do
513
793
 
514
794
  specify "inputs_wrapper: div wraps tags in a div" do
515
795
  Forme::Form.new(:inputs_wrapper=>:div, :wrapper=>:span).inputs([:textarea]).to_s.should == '<div><span><textarea></textarea></span></div>'
796
+ Forme::Form.new(:inputs_wrapper=>:div, :wrapper=>:span).inputs([:textarea], :attr=>{:foo=>1}).to_s.should == '<div foo="1"><span><textarea></textarea></span></div>'
797
+ end
798
+
799
+ specify "inputs_wrapper: tr wraps tags in an tr" do
800
+ Forme::Form.new(:inputs_wrapper=>:tr, :wrapper=>:td).inputs([:textarea]).to_s.should == '<tr><td><textarea></textarea></td></tr>'
801
+ Forme::Form.new(:inputs_wrapper=>:tr, :wrapper=>:td).inputs([:textarea], :attr=>{:foo=>1}).to_s.should == '<tr foo="1"><td><textarea></textarea></td></tr>'
516
802
  end
517
803
 
518
804
  specify "inputs_wrapper: table wraps tags in an table" do
519
805
  Forme::Form.new(:inputs_wrapper=>:table, :wrapper=>:trtd).inputs([:textarea]).to_s.should == '<table><tr><td><textarea></textarea></td><td></td></tr></table>'
806
+ Forme::Form.new(:inputs_wrapper=>:table, :wrapper=>:trtd).inputs([:textarea], :attr=>{:foo=>1}).to_s.should == '<table foo="1"><tr><td><textarea></textarea></td><td></td></tr></table>'
807
+ end
808
+
809
+ specify "inputs_wrapper: table accepts a :legend option" do
810
+ Forme::Form.new(:inputs_wrapper=>:table, :wrapper=>:trtd).inputs([:textarea], :legend=>'Inputs').to_s.should == '<table><caption>Inputs</caption><tr><td><textarea></textarea></td><td></td></tr></table>'
811
+ end
812
+
813
+ specify "inputs_wrapper: table accepts a :legend_attr option" do
814
+ Forme::Form.new(:inputs_wrapper=>:table, :wrapper=>:trtd).inputs([:textarea], :legend=>'Inputs', :legend_attr=>{:class=>'foo'}).to_s.should == '<table><caption class="foo">Inputs</caption><tr><td><textarea></textarea></td><td></td></tr></table>'
815
+ end
816
+
817
+ specify "inputs_wrapper: table accepts a :labels option" do
818
+ Forme::Form.new(:inputs_wrapper=>:table).inputs(:labels=>%w'A B C').to_s.should == '<table><tr><th>A</th><th>B</th><th>C</th></tr></table>'
819
+ end
820
+
821
+ specify "inputs_wrapper: table doesn't add empty header row for :labels=>[]" do
822
+ Forme::Form.new(:inputs_wrapper=>:table).inputs(:labels=>[]).to_s.should == '<table></table>'
520
823
  end
521
824
 
522
825
  specify "serializer: html_usa formats dates and datetimes in American format without timezones" do
@@ -630,6 +933,14 @@ describe "Forme object forms" do
630
933
  Forme::Form.new([:foo]).input(:first, :attr=>{:x=>'bar'}).to_s.should == '<input id="first" name="first" type="text" value="foo" x="bar"/>'
631
934
  end
632
935
 
936
+ specify "should respect current namespace" do
937
+ Forme::Form.new([:foo], :namespace=>'a').input(:first).to_s.should == '<input id="a_first" name="a[first]" type="text" value="foo"/>'
938
+ end
939
+
940
+ specify "should get values for hashes using #[]" do
941
+ Forme::Form.new(:obj=>{:bar=>:foo}, :namespace=>'a').input(:bar).to_s.should == '<input id="a_bar" name="a[bar]" type="text" value="foo"/>'
942
+ end
943
+
633
944
  specify "should handle obj passed in via :obj hash key" do
634
945
  Forme::Form.new(:obj=>[:foo]).input(:first).to_s.should == '<input id="first" name="first" type="text" value="foo"/>'
635
946
  end