forme 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +1 -0
- data/MIT-LICENSE +18 -0
- data/README.rdoc +231 -0
- data/Rakefile +97 -0
- data/lib/forme.rb +1178 -0
- data/lib/forme/sinatra.rb +89 -0
- data/lib/forme/version.rb +9 -0
- data/lib/sequel/plugins/forme.rb +435 -0
- data/spec/forme_spec.rb +579 -0
- data/spec/sequel_plugin_spec.rb +405 -0
- data/spec/sinatra_integration_spec.rb +96 -0
- data/spec/spec_helper.rb +2 -0
- metadata +93 -0
data/spec/forme_spec.rb
ADDED
@@ -0,0 +1,579 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
describe "Forme plain forms" do
|
5
|
+
def sel(opts, s)
|
6
|
+
opts.map{|o| "<option #{'selected="selected" ' if o == s}value=\"#{o}\">#{sprintf("%02i", o)}</option>"}.join
|
7
|
+
end
|
8
|
+
|
9
|
+
before do
|
10
|
+
@f = Forme::Form.new
|
11
|
+
end
|
12
|
+
|
13
|
+
specify "Forme.version should return version string" do
|
14
|
+
Forme.version.should =~ /\A\d+\.\d+\.\d+\z/
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "should create a simple input tags" do
|
18
|
+
@f.input(:text).to_s.should == '<input type="text"/>'
|
19
|
+
@f.input(:radio).to_s.should == '<input type="radio"/>'
|
20
|
+
@f.input(:password).to_s.should == '<input type="password"/>'
|
21
|
+
@f.input(:checkbox).to_s.should == '<input type="checkbox"/>'
|
22
|
+
@f.input(:submit).to_s.should == '<input type="submit"/>'
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should use :name option as attribute" do
|
26
|
+
@f.input(:text, :name=>"foo").to_s.should == '<input name="foo" type="text"/>'
|
27
|
+
end
|
28
|
+
|
29
|
+
specify "should use :id option as attribute" do
|
30
|
+
@f.input(:text, :id=>"foo").to_s.should == '<input id="foo" type="text"/>'
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should use :class option as attribute" do
|
34
|
+
@f.input(:text, :class=>"foo").to_s.should == '<input class="foo" type="text"/>'
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should use :value option as attribute" do
|
38
|
+
@f.input(:text, :value=>"foo").to_s.should == '<input type="text" value="foo"/>'
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should use :placeholder option as attribute" do
|
42
|
+
@f.input(:text, :placeholder=>"foo").to_s.should == '<input placeholder="foo" type="text"/>'
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "should allow arbitrary attributes using the :attr option" do
|
46
|
+
@f.input(:text, :attr=>{:bar=>"foo"}).to_s.should == '<input bar="foo" type="text"/>'
|
47
|
+
end
|
48
|
+
|
49
|
+
specify "should convert the :data option into attributes" do
|
50
|
+
@f.input(:text, :data=>{:bar=>"foo"}).to_s.should == '<input data-bar="foo" type="text"/>'
|
51
|
+
end
|
52
|
+
|
53
|
+
specify "should not have standard options override the :attr option" do
|
54
|
+
@f.input(:text, :name=>:bar, :attr=>{:name=>"foo"}).to_s.should == '<input name="foo" type="text"/>'
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "should combine :class standard option with :attr option" do
|
58
|
+
@f.input(:text, :class=>:bar, :attr=>{:class=>"foo"}).to_s.should == '<input class="foo bar" type="text"/>'
|
59
|
+
end
|
60
|
+
|
61
|
+
specify "should not have :data options override the :attr option" do
|
62
|
+
@f.input(:text, :data=>{:bar=>"baz"}, :attr=>{:"data-bar"=>"foo"}).to_s.should == '<input data-bar="foo" type="text"/>'
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "should create hidden input with value 0 for each checkbox with a name" do
|
66
|
+
@f.input(:checkbox, :name=>"foo").to_s.should == '<input name="foo" type="hidden" value="0"/><input name="foo" type="checkbox"/>'
|
67
|
+
end
|
68
|
+
|
69
|
+
specify "should not create hidden input with value 0 for each checkbox with a name if :no_hidden option is used" do
|
70
|
+
@f.input(:checkbox, :name=>"foo", :no_hidden=>true).to_s.should == '<input name="foo" type="checkbox"/>'
|
71
|
+
end
|
72
|
+
|
73
|
+
specify "should create hidden input with _hidden appened to id for each checkbox with a name and id" do
|
74
|
+
@f.input(:checkbox, :name=>"foo", :id=>"bar").to_s.should == '<input id="bar_hidden" name="foo" type="hidden" value="0"/><input id="bar" name="foo" type="checkbox"/>'
|
75
|
+
end
|
76
|
+
|
77
|
+
specify "should create hidden input with value f for each checkbox with a name and value t" do
|
78
|
+
@f.input(:checkbox, :name=>"foo", :value=>"t").to_s.should == '<input name="foo" type="hidden" value="f"/><input name="foo" type="checkbox" value="t"/>'
|
79
|
+
end
|
80
|
+
|
81
|
+
specify "should use :hidden_value option for value of hidden input for checkbox" do
|
82
|
+
@f.input(:checkbox, :name=>"foo", :hidden_value=>"no").to_s.should == '<input name="foo" type="hidden" value="no"/><input name="foo" type="checkbox"/>'
|
83
|
+
end
|
84
|
+
|
85
|
+
specify "should handle :checked option" do
|
86
|
+
@f.input(:checkbox, :checked=>true).to_s.should == '<input checked="checked" type="checkbox"/>'
|
87
|
+
@f.input(:checkbox, :checked=>false).to_s.should == '<input type="checkbox"/>'
|
88
|
+
end
|
89
|
+
|
90
|
+
specify "should create textarea tag" do
|
91
|
+
@f.input(:textarea).to_s.should == '<textarea></textarea>'
|
92
|
+
end
|
93
|
+
|
94
|
+
specify "should create select tag" do
|
95
|
+
@f.input(:select).to_s.should == '<select></select>'
|
96
|
+
end
|
97
|
+
|
98
|
+
specify "should create date tag" do
|
99
|
+
@f.input(:date).to_s.should == '<input type="date"/>'
|
100
|
+
end
|
101
|
+
|
102
|
+
specify "should not error for input type :input" do
|
103
|
+
@f.input(:input).to_s.should == '<input type="input"/>'
|
104
|
+
end
|
105
|
+
|
106
|
+
specify "should use multiple select boxes for dates if the :as=>:select option is given" do
|
107
|
+
@f.input(:date, :name=>"foo", :id=>"bar", :as=>:select, :value=>Date.new(2011, 6, 5)).to_s.should == %{<select id="bar_year" name="foo[year]">#{sel(1900..2050, 2011)}</select>-<select id="bar_month" name="foo[month]">#{sel(1..12, 6)}</select>-<select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select>}
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "should have explicit labeler and trtd wrapper work with multiple select boxes for dates" do
|
111
|
+
@f.input(:date, :name=>"foo", :id=>"bar", :as=>:select, :value=>Date.new(2011, 6, 5), :wrapper=>:trtd, :labeler=>:explicit, :label=>'Baz').to_s.should == %{<tr><td><label for="bar_year">Baz</label></td><td><select id="bar_year" name="foo[year]">#{sel(1900..2050, 2011)}</select>-<select id="bar_month" name="foo[month]">#{sel(1..12, 6)}</select>-<select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select></td></tr>}
|
112
|
+
end
|
113
|
+
|
114
|
+
specify "should use multiple select boxes for datetimes if the :as=>:select option is given" do
|
115
|
+
@f.input(:datetime, :name=>"foo", :id=>"bar", :as=>:select, :value=>DateTime.new(2011, 6, 5, 4, 3, 2)).to_s.should == %{<select id="bar_year" name="foo[year]">#{sel(1900..2050, 2011)}</select>-<select id="bar_month" name="foo[month]">#{sel(1..12, 6)}</select>-<select id="bar_day" name="foo[day]">#{sel(1..31, 5)}</select> <select id="bar_hour" name="foo[hour]">#{sel(0..23, 4)}</select>:<select id="bar_minute" name="foo[minute]">#{sel(0..59, 3)}</select>:<select id="bar_second" name="foo[second]">#{sel(0..59, 2)}</select>}
|
116
|
+
end
|
117
|
+
|
118
|
+
specify "should create select tag with options" do
|
119
|
+
@f.input(:select, :options=>[1, 2, 3], :selected=>2).to_s.should == '<select><option>1</option><option selected="selected">2</option><option>3</option></select>'
|
120
|
+
@f.input(:select, :options=>[1, 2, 3], :value=>2).to_s.should == '<select><option>1</option><option selected="selected">2</option><option>3</option></select>'
|
121
|
+
end
|
122
|
+
|
123
|
+
specify "should create select tag with options and values" do
|
124
|
+
@f.input(:select, :options=>[[:a, 1], [:b, 2], [:c, 3]], :selected=>2).to_s.should == '<select><option value="1">a</option><option selected="selected" value="2">b</option><option value="3">c</option></select>'
|
125
|
+
end
|
126
|
+
|
127
|
+
specify "should create select tag with options and values with hashes" do
|
128
|
+
@f.input(:select, :options=>[[:a, {:foo=>1}], [:b, {:bar=>4, :value=>2}], [:c, {:baz=>3}]], :selected=>2).to_s.should == '<select><option foo="1">a</option><option bar="4" selected="selected" value="2">b</option><option baz="3">c</option></select>'
|
129
|
+
end
|
130
|
+
|
131
|
+
specify "should create select tag with options and values using given method" do
|
132
|
+
@f.input(:select, :options=>[[:a, 1], [:b, 2], [:c, 3]], :text_method=>:last, :selected=>2).to_s.should == '<select><option>1</option><option selected="selected">2</option><option>3</option></select>'
|
133
|
+
@f.input(:select, :options=>[[:a, 1], [:b, 2], [:c, 3]], :text_method=>:last, :value_method=>:first, :selected=>:b).to_s.should == '<select><option value="a">1</option><option selected="selected" value="b">2</option><option value="c">3</option></select>'
|
134
|
+
end
|
135
|
+
|
136
|
+
specify "should use html attributes specified in options" do
|
137
|
+
@f.input(:text, :value=>'foo', :name=>'bar').to_s.should == '<input name="bar" type="text" value="foo"/>'
|
138
|
+
@f.input(:textarea, :value=>'foo', :name=>'bar').to_s.should == '<textarea name="bar">foo</textarea>'
|
139
|
+
@f.input(:select, :name=>'bar', :options=>[1, 2, 3]).to_s.should == '<select name="bar"><option>1</option><option>2</option><option>3</option></select>'
|
140
|
+
end
|
141
|
+
|
142
|
+
specify "should support :add_blank option for select inputs" do
|
143
|
+
@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>'
|
144
|
+
end
|
145
|
+
|
146
|
+
specify "should use :add_blank option value as prompt if it is a String" do
|
147
|
+
@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>'
|
148
|
+
end
|
149
|
+
|
150
|
+
specify "radio and checkbox inputs should handle :checked option" do
|
151
|
+
@f.input(:radio, :checked=>true).to_s.should == '<input checked="checked" type="radio"/>'
|
152
|
+
@f.input(:radio, :checked=>false).to_s.should == '<input type="radio"/>'
|
153
|
+
@f.input(:checkbox, :checked=>true).to_s.should == '<input checked="checked" type="checkbox"/>'
|
154
|
+
@f.input(:checkbox, :checked=>false).to_s.should == '<input type="checkbox"/>'
|
155
|
+
end
|
156
|
+
|
157
|
+
specify "inputs should handle :required option" do
|
158
|
+
@f.input(:text, :required=>true).to_s.should == '<input required="required" type="text"/>'
|
159
|
+
@f.input(:text, :required=>false).to_s.should == '<input type="text"/>'
|
160
|
+
end
|
161
|
+
|
162
|
+
specify "inputs should handle :disabled option" do
|
163
|
+
@f.input(:text, :disabled=>true).to_s.should == '<input disabled="disabled" type="text"/>'
|
164
|
+
@f.input(:text, :disabled=>false).to_s.should == '<input type="text"/>'
|
165
|
+
end
|
166
|
+
|
167
|
+
specify "inputs should not include options with nil values" do
|
168
|
+
@f.input(:text, :name=>nil).to_s.should == '<input type="text"/>'
|
169
|
+
@f.input(:textarea, :name=>nil).to_s.should == '<textarea></textarea>'
|
170
|
+
end
|
171
|
+
|
172
|
+
specify "inputs should include options with false values" do
|
173
|
+
@f.input(:text, :name=>false).to_s.should == '<input name="false" type="text"/>'
|
174
|
+
end
|
175
|
+
|
176
|
+
specify "should automatically create a label if a :label option is used" do
|
177
|
+
@f.input(:text, :label=>'Foo', :value=>'foo').to_s.should == '<label>Foo: <input type="text" value="foo"/></label>'
|
178
|
+
end
|
179
|
+
|
180
|
+
specify "should automatically note the input has errors if :error option is used" do
|
181
|
+
@f.input(:text, :error=>'Bad Stuff!', :value=>'foo').to_s.should == '<input class="error" type="text" value="foo"/><span class="error_message">Bad Stuff!</span>'
|
182
|
+
end
|
183
|
+
|
184
|
+
specify "should add to existing :class option if :error option is used" do
|
185
|
+
@f.input(:text, :error=>'Bad Stuff!', :class=>'bar', :value=>'foo').to_s.should == '<input class="bar error" type="text" value="foo"/><span class="error_message">Bad Stuff!</span>'
|
186
|
+
end
|
187
|
+
|
188
|
+
specify "#open should return an opening tag" do
|
189
|
+
@f.open(:action=>'foo', :method=>'post').to_s.should == '<form action="foo" method="post">'
|
190
|
+
end
|
191
|
+
|
192
|
+
specify "#close should return a closing tag" do
|
193
|
+
@f.close.to_s.should == '</form>'
|
194
|
+
end
|
195
|
+
|
196
|
+
specify "#button should return a submit tag" do
|
197
|
+
@f.button.to_s.should == '<input type="submit"/>'
|
198
|
+
end
|
199
|
+
|
200
|
+
specify "#button should accept an options hash" do
|
201
|
+
@f.button(:name=>'foo', :value=>'bar').to_s.should == '<input name="foo" type="submit" value="bar"/>'
|
202
|
+
end
|
203
|
+
|
204
|
+
specify "#button should accept a string to use as a value" do
|
205
|
+
@f.button('foo').to_s.should == '<input type="submit" value="foo"/>'
|
206
|
+
end
|
207
|
+
|
208
|
+
specify "#tag should return a serialized_tag" do
|
209
|
+
@f.tag(:textarea).to_s.should == '<textarea></textarea>'
|
210
|
+
@f.tag(:textarea, :name=>:foo).to_s.should == '<textarea name="foo"></textarea>'
|
211
|
+
@f.tag(:textarea, {:name=>:foo}, :bar).to_s.should == '<textarea name="foo">bar</textarea>'
|
212
|
+
end
|
213
|
+
|
214
|
+
specify "should have an #inputs method for multiple inputs wrapped in a fieldset" do
|
215
|
+
@f.inputs([:textarea, :text]).to_s.should == '<fieldset class="inputs"><textarea></textarea><input type="text"/></fieldset>'
|
216
|
+
end
|
217
|
+
|
218
|
+
specify "should have default #inputs method accept an :attr option" do
|
219
|
+
@f.inputs([:textarea, :text], :legend=>'Inputs', :attr=>{:class=>'foo', :bar=>'baz'}).to_s.should == '<fieldset bar="baz" class="foo inputs"><legend>Inputs</legend><textarea></textarea><input type="text"/></fieldset>'
|
220
|
+
end
|
221
|
+
|
222
|
+
specify "should have default #inputs method accept a :legend option" do
|
223
|
+
@f.inputs([:textarea, :text], :legend=>'Inputs').to_s.should == '<fieldset class="inputs"><legend>Inputs</legend><textarea></textarea><input type="text"/></fieldset>'
|
224
|
+
end
|
225
|
+
|
226
|
+
specify "should have default #inputs method accept a :legend_attr option" do
|
227
|
+
@f.inputs([:textarea, :text], :legend=>'Inputs', :legend_attr=>{:class=>'foo'}).to_s.should == '<fieldset class="inputs"><legend class="foo">Inputs</legend><textarea></textarea><input type="text"/></fieldset>'
|
228
|
+
end
|
229
|
+
|
230
|
+
specify "should have an #inputs method take a block and yield to it" do
|
231
|
+
@f.inputs{@f.input(:textarea); @f.input(:text)}.to_s.should == '<fieldset class="inputs"><textarea></textarea><input type="text"/></fieldset>'
|
232
|
+
end
|
233
|
+
|
234
|
+
specify "should have an #inputs method work with both args and block" do
|
235
|
+
@f.inputs([:textarea]){@f.input(:text)}.to_s.should == '<fieldset class="inputs"><textarea></textarea><input type="text"/></fieldset>'
|
236
|
+
end
|
237
|
+
|
238
|
+
specify "should have an #inputs method support array arguments and creating inputs with the array as argument list" do
|
239
|
+
@f.inputs([[:textarea, {:name=>'foo'}], [:text, {:id=>'bar'}]]).to_s.should == '<fieldset class="inputs"><textarea name="foo"></textarea><input id="bar" type="text"/></fieldset>'
|
240
|
+
end
|
241
|
+
|
242
|
+
specify "should escape tag content" do
|
243
|
+
@f.tag(:div, {}, ['<p></p>']).to_s.should == '<div><p></p></div>'
|
244
|
+
end
|
245
|
+
|
246
|
+
specify "should not escape raw tag content" do
|
247
|
+
@f.tag(:div, {}, ['<p></p>'.extend(Forme::Raw)]).to_s.should == '<div><p></p></div>'
|
248
|
+
end
|
249
|
+
|
250
|
+
specify "should escape tag content in attribute values" do
|
251
|
+
@f.tag(:div, :foo=>'<p></p>').to_s.should == '<div foo="<p></p>"></div>'
|
252
|
+
end
|
253
|
+
|
254
|
+
specify "should not escape raw tag content in attribute values" do
|
255
|
+
@f.tag(:div, :foo=>'<p></p>'.extend(Forme::Raw)).to_s.should == '<div foo="<p></p>"></div>'
|
256
|
+
end
|
257
|
+
|
258
|
+
specify "should format dates, times, and datetimes in ISO format" do
|
259
|
+
@f.tag(:div, :foo=>Date.new(2011, 6, 5)).to_s.should == '<div foo="2011-06-05"></div>'
|
260
|
+
@f.tag(:div, :foo=>DateTime.new(2011, 6, 5, 4, 3, 2)).to_s.should == '<div foo="2011-06-05 04:03:02+00:00"></div>'
|
261
|
+
@f.tag(:div, :foo=>Time.utc(2011, 6, 5, 4, 3, 2)).to_s.should =~ /<div foo="2011-06-05 04:03:02(GMT|UTC)"><\/div>/
|
262
|
+
end
|
263
|
+
|
264
|
+
specify "inputs should accept a :wrapper option to use a custom wrapper" do
|
265
|
+
@f.input(:text, :wrapper=>:li).to_s.should == '<li><input type="text"/></li>'
|
266
|
+
end
|
267
|
+
|
268
|
+
specify "inputs should accept a :wrapper_attr option to use custom wrapper attributes" do
|
269
|
+
@f.input(:text, :wrapper=>:li, :wrapper_attr=>{:class=>"foo"}).to_s.should == '<li class="foo"><input type="text"/></li>'
|
270
|
+
end
|
271
|
+
|
272
|
+
specify "inputs should accept a :formatter option to use a custom formatter" do
|
273
|
+
@f.input(:text, :formatter=>:readonly, :value=>'1', :label=>'Foo').to_s.should == '<label>Foo: <span>1</span></label>'
|
274
|
+
@f.input(:text, :formatter=>:default, :value=>'1', :label=>'Foo').to_s.should == '<label>Foo: <input type="text" value="1"/></label>'
|
275
|
+
end
|
276
|
+
|
277
|
+
specify "inputs should accept a :labeler option to use a custom labeler" do
|
278
|
+
@f.input(:textarea, :labeler=>:explicit, :label=>'bar', :id=>:foo).to_s.should == '<label for="foo">bar</label><textarea id="foo"></textarea>'
|
279
|
+
end
|
280
|
+
|
281
|
+
specify "inputs should accept a :error_handler option to use a custom error_handler" do
|
282
|
+
@f.input(:textarea, :error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}, :error=>'bar', :id=>:foo).to_s.should == '<textarea id="foo"></textarea>!!! bar'
|
283
|
+
end
|
284
|
+
|
285
|
+
specify "#inputs should accept a :inputs_wrapper option to use a custom inputs_wrapper" do
|
286
|
+
@f.inputs([:textarea], :inputs_wrapper=>:ol).to_s.should == '<ol><textarea></textarea></ol>'
|
287
|
+
end
|
288
|
+
|
289
|
+
specify "inputs should accept a :wrapper=>nil option to not use a wrapper" do
|
290
|
+
Forme::Form.new(:wrapper=>:li).input(:text, :wrapper=>nil).to_s.should == '<input type="text"/>'
|
291
|
+
end
|
292
|
+
|
293
|
+
specify "inputs should accept a :labeler=>nil option to not use a labeler" do
|
294
|
+
@f.input(:textarea, :labeler=>nil, :label=>'bar', :id=>:foo).to_s.should == '<textarea id="foo"></textarea>'
|
295
|
+
end
|
296
|
+
|
297
|
+
specify "inputs should accept a :error_handler=>nil option to not use an error_handler" do
|
298
|
+
@f.input(:textarea, :error_handler=>nil, :error=>'bar', :id=>:foo).to_s.should == '<textarea id="foo"></textarea>'
|
299
|
+
end
|
300
|
+
|
301
|
+
specify "#inputs should accept a :inputs_wrapper=>nil option to not use an inputs_wrapper" do
|
302
|
+
@f.form{|f| f.inputs([:textarea], :inputs_wrapper=>nil)}.to_s.should == '<form><textarea></textarea></form>'
|
303
|
+
end
|
304
|
+
|
305
|
+
specify "invalid custom transformers should raise an Error" do
|
306
|
+
proc{Forme::Form.new(:wrapper=>Object.new)}.should raise_error(Forme::Error)
|
307
|
+
proc{@f.input(:textarea, :wrapper=>Object.new).to_s}.should raise_error(Forme::Error)
|
308
|
+
proc{@f.input(:textarea, :formatter=>nil).to_s}.should raise_error(Forme::Error)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "Forme custom" do
|
313
|
+
specify "formatters can be specified as a proc" do
|
314
|
+
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>'
|
315
|
+
end
|
316
|
+
|
317
|
+
specify "serializers can be specified as a proc" do
|
318
|
+
Forme::Form.new(:serializer=>proc{|t| "#{t.type} = #{t.opts.inspect}"}).input(:textarea, :name=>'foo').to_s.should == 'textarea = {:name=>"foo"}'
|
319
|
+
end
|
320
|
+
|
321
|
+
specify "labelers can be specified as a proc" do
|
322
|
+
Forme::Form.new(:labeler=>proc{|t, i| ["#{i.opts[:label]}: ", t]}).input(:textarea, :name=>'foo', :label=>'bar').to_s.should == 'bar: <textarea name="foo"></textarea>'
|
323
|
+
end
|
324
|
+
|
325
|
+
specify "error_handlers can be specified as a proc" do
|
326
|
+
Forme::Form.new(:error_handler=>proc{|t, i| [t, "!!! #{i.opts[:error]}"]}).input(:textarea, :name=>'foo', :error=>'bar').to_s.should == '<textarea name="foo"></textarea>!!! bar'
|
327
|
+
end
|
328
|
+
|
329
|
+
specify "wrappers can be specified as a proc" do
|
330
|
+
Forme::Form.new(:wrapper=>proc{|t, i| t.tag(:div, {:bar=>i.opts[:name]}, t)}).input(:textarea, :name=>'foo').to_s.should == '<div bar="foo"><textarea name="foo"></textarea></div>'
|
331
|
+
end
|
332
|
+
|
333
|
+
specify "inputs_wrappers can be specified as a proc" do
|
334
|
+
Forme::Form.new(:inputs_wrapper=>proc{|f, opts, &block| f.tag(:div, &block)}).inputs([:textarea]).to_s.should == '<div><textarea></textarea></div>'
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
describe "Forme built-in custom" do
|
339
|
+
specify "transformers should raise if the there is no matching transformer" do
|
340
|
+
proc{Forme::Form.new(:formatter=>:foo)}.should raise_error(Forme::Error)
|
341
|
+
end
|
342
|
+
|
343
|
+
specify "formatter: disabled disables all inputs unless :disabled=>false option" do
|
344
|
+
Forme::Form.new(:formatter=>:disabled).input(:textarea).to_s.should == '<textarea disabled="disabled"></textarea>'
|
345
|
+
Forme::Form.new(:formatter=>:disabled).input(:textarea, :disabled=>false).to_s.should == '<textarea></textarea>'
|
346
|
+
end
|
347
|
+
|
348
|
+
specify "formatter: readonly uses spans for most input fields and disables radio/checkbox fields" do
|
349
|
+
Forme::Form.new(:formatter=>:readonly).input(:textarea, :label=>"Foo", :value=>"Bar").to_s.should == "<label>Foo: <span>Bar</span></label>"
|
350
|
+
Forme::Form.new(:formatter=>:readonly).input(:text, :label=>"Foo", :value=>"Bar").to_s.should == "<label>Foo: <span>Bar</span></label>"
|
351
|
+
Forme::Form.new(:formatter=>:readonly).input(:radio, :label=>"Foo", :value=>"Bar").to_s.should == "<label><input disabled=\"disabled\" type=\"radio\" value=\"Bar\"/> Foo</label>"
|
352
|
+
Forme::Form.new(:formatter=>:readonly).input(:radio, :label=>"Foo", :value=>"Bar", :checked=>true).to_s.should == "<label><input checked=\"checked\" disabled=\"disabled\" type=\"radio\" value=\"Bar\"/> Foo</label>"
|
353
|
+
Forme::Form.new(:formatter=>:readonly).input(:checkbox, :label=>"Foo", :value=>"Bar").to_s.should == "<label><input disabled=\"disabled\" type=\"checkbox\" value=\"Bar\"/> Foo</label>"
|
354
|
+
Forme::Form.new(:formatter=>:readonly).input(:checkbox, :label=>"Foo", :value=>"Bar", :checked=>true).to_s.should == "<label><input checked=\"checked\" disabled=\"disabled\" type=\"checkbox\" value=\"Bar\"/> Foo</label>"
|
355
|
+
Forme::Form.new(:formatter=>:readonly).input(:select, :label=>"Foo", :options=>[1, 2, 3], :value=>2).to_s.should == "<label>Foo: <span>2</span></label>"
|
356
|
+
end
|
357
|
+
|
358
|
+
specify "labeler: explicit uses an explicit label with for attribute" do
|
359
|
+
Forme::Form.new(:labeler=>:explicit).input(:textarea, :id=>'foo', :label=>'bar').to_s.should == '<label for="foo">bar</label><textarea id="foo"></textarea>'
|
360
|
+
end
|
361
|
+
|
362
|
+
specify "labeler: explicit should handle tags with errors" do
|
363
|
+
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>'
|
364
|
+
end
|
365
|
+
|
366
|
+
specify "wrapper: li wraps tag in an li" do
|
367
|
+
Forme::Form.new(:wrapper=>:li).input(:textarea, :id=>'foo').to_s.should == '<li><textarea id="foo"></textarea></li>'
|
368
|
+
end
|
369
|
+
|
370
|
+
specify "wrapper: p wraps tag in an p" do
|
371
|
+
Forme::Form.new(:wrapper=>:p).input(:textarea, :id=>'foo').to_s.should == '<p><textarea id="foo"></textarea></p>'
|
372
|
+
end
|
373
|
+
|
374
|
+
specify "wrapper: div wraps tag in an div" do
|
375
|
+
Forme::Form.new(:wrapper=>:div).input(:textarea, :id=>'foo').to_s.should == '<div><textarea id="foo"></textarea></div>'
|
376
|
+
end
|
377
|
+
|
378
|
+
specify "wrapper: span wraps tag in an span" do
|
379
|
+
Forme::Form.new(:wrapper=>:span).input(:textarea, :id=>'foo').to_s.should == '<span><textarea id="foo"></textarea></span>'
|
380
|
+
end
|
381
|
+
|
382
|
+
specify "wrapper: trtd wraps tag in an tr/td" do
|
383
|
+
Forme::Form.new(:wrapper=>:trtd).input(:textarea, :id=>'foo').to_s.should == '<tr><td><textarea id="foo"></textarea></td></tr>'
|
384
|
+
end
|
385
|
+
|
386
|
+
specify "wrapper: trtd supports multiple tags in separate tds" do
|
387
|
+
Forme::Form.new(:wrapper=>:trtd, :labeler=>:explicit).input(:textarea, :id=>'foo', :label=>'Foo').to_s.should == '<tr><td><label for="foo">Foo</label></td><td><textarea id="foo"></textarea></td></tr>'
|
388
|
+
end
|
389
|
+
|
390
|
+
specify "wrapper: trtd should use at most 2 td tags" do
|
391
|
+
Forme::Form.new(:wrapper=>:trtd, :labeler=>:explicit).input(:textarea, :id=>'foo', :label=>'Foo', :error=>'Bar').to_s.should == '<tr><td><label for="foo">Foo</label></td><td><textarea class="error" id="foo"></textarea><span class="error_message">Bar</span></td></tr>'
|
392
|
+
end
|
393
|
+
|
394
|
+
specify "inputs_wrapper: ol wraps tags in an ol" do
|
395
|
+
Forme::Form.new(:inputs_wrapper=>:ol, :wrapper=>:li).inputs([:textarea]).to_s.should == '<ol><li><textarea></textarea></li></ol>'
|
396
|
+
end
|
397
|
+
|
398
|
+
specify "inputs_wrapper: fieldset_ol wraps tags in a fieldset and an ol" do
|
399
|
+
Forme::Form.new(:inputs_wrapper=>:fieldset_ol, :wrapper=>:li).inputs([:textarea]).to_s.should == '<fieldset class="inputs"><ol><li><textarea></textarea></li></ol></fieldset>'
|
400
|
+
end
|
401
|
+
|
402
|
+
specify "inputs_wrapper: fieldset_ol supports a :legend option" do
|
403
|
+
Forme.form({}, :inputs_wrapper=>:fieldset_ol, :wrapper=>:li, :legend=>'Foo', :inputs=>[:textarea]).to_s.should == '<form><fieldset class="inputs"><legend>Foo</legend><ol><li><textarea></textarea></li></ol></fieldset></form>'
|
404
|
+
end
|
405
|
+
|
406
|
+
specify "inputs_wrapper: div wraps tags in a div" do
|
407
|
+
Forme::Form.new(:inputs_wrapper=>:div, :wrapper=>:span).inputs([:textarea]).to_s.should == '<div><span><textarea></textarea></span></div>'
|
408
|
+
end
|
409
|
+
|
410
|
+
specify "inputs_wrapper: table wraps tags in an table" do
|
411
|
+
Forme::Form.new(:inputs_wrapper=>:table, :wrapper=>:trtd).inputs([:textarea]).to_s.should == '<table><tr><td><textarea></textarea></td></tr></table>'
|
412
|
+
end
|
413
|
+
|
414
|
+
specify "serializer: html_usa formats dates and datetimes in American format without timezones" do
|
415
|
+
Forme::Form.new(:serializer=>:html_usa).tag(:div, :foo=>Date.new(2011, 6, 5)).to_s.should == '<div foo="06/05/2011"></div>'
|
416
|
+
Forme::Form.new(:serializer=>:html_usa).tag(:div, :foo=>DateTime.new(2011, 6, 5, 16, 3, 2)).to_s.should == '<div foo="06/05/2011 04:03:02PM"></div>'
|
417
|
+
Forme::Form.new(:serializer=>:html_usa).tag(:div, :foo=>Time.utc(2011, 6, 5, 4, 3, 2)).to_s.should == '<div foo="06/05/2011 04:03:02AM"></div>'
|
418
|
+
end
|
419
|
+
|
420
|
+
specify "serializer: text uses plain text output instead of html" do
|
421
|
+
Forme::Form.new(:serializer=>:text).input(:textarea, :label=>"Foo", :value=>"Bar").to_s.should == "Foo: Bar\n\n"
|
422
|
+
Forme::Form.new(:serializer=>:text).input(:text, :label=>"Foo", :value=>"Bar").to_s.should == "Foo: Bar\n\n"
|
423
|
+
Forme::Form.new(:serializer=>:text).input(:radio, :label=>"Foo", :value=>"Bar").to_s.should == "___ Foo\n"
|
424
|
+
Forme::Form.new(:serializer=>:text).input(:radio, :label=>"Foo", :value=>"Bar", :checked=>true).to_s.should == "_X_ Foo\n"
|
425
|
+
Forme::Form.new(:serializer=>:text).input(:checkbox, :label=>"Foo", :value=>"Bar").to_s.should == "___ Foo\n"
|
426
|
+
Forme::Form.new(:serializer=>:text).input(:checkbox, :label=>"Foo", :value=>"Bar", :checked=>true).to_s.should == "_X_ Foo\n"
|
427
|
+
Forme::Form.new(:serializer=>:text).input(:select, :label=>"Foo", :options=>[1, 2, 3], :value=>2).to_s.should == "Foo: \n___ 1\n_X_ 2\n___ 3\n\n"
|
428
|
+
Forme::Form.new(:serializer=>:text).input(:password, :label=>"Pass").to_s.should == "Pass: ********\n\n"
|
429
|
+
Forme::Form.new(:serializer=>:text).button().to_s.should == ""
|
430
|
+
Forme::Form.new(:serializer=>:text).inputs([[:textarea, {:label=>"Foo", :value=>"Bar"}]], :legend=>'Baz').to_s.should == "Baz\n---\nFoo: Bar\n\n"
|
431
|
+
Forme::Form.new(:serializer=>:text).tag(:p){|f| f.input(:textarea, :label=>"Foo", :value=>"Bar")}.to_s.should == "Foo: Bar\n\n"
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
describe "Forme registering custom transformers" do
|
436
|
+
specify "should have #register_transformer register a transformer object for later use" do
|
437
|
+
Forme.register_transformer(:wrapper, :div, proc{|t, i| t.tag(:div, {}, [t])})
|
438
|
+
Forme::Form.new(:wrapper=>:div).input(:textarea).to_s.should == '<div><textarea></textarea></div>'
|
439
|
+
end
|
440
|
+
|
441
|
+
specify "should have #register_transformer register a transformer block for later use" do
|
442
|
+
Forme.register_transformer(:wrapper, :div1){|t, i| t.tag(:div1, {}, [t])}
|
443
|
+
Forme::Form.new(:wrapper=>:div1).input(:textarea).to_s.should == '<div1><textarea></textarea></div1>'
|
444
|
+
end
|
445
|
+
|
446
|
+
specify "should have #register_transformer raise an error if given a block and an object" do
|
447
|
+
proc do
|
448
|
+
Forme.register_transformer(:wrapper, :div1, proc{|t, i| t}){|t| t.tag(:div1, {}, [t])}
|
449
|
+
end.should raise_error(Forme::Error)
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
describe "Forme configurations" do
|
454
|
+
after do
|
455
|
+
Forme.default_config = :default
|
456
|
+
end
|
457
|
+
|
458
|
+
specify "config: :formastic uses fieldset_ol inputs_wrapper and li wrapper, and explicit labeler" do
|
459
|
+
Forme::Form.new(:config=>:formtastic).inputs([[:textarea, {:id=>:foo, :label=>'Foo'}]]).to_s.should == '<fieldset class="inputs"><ol><li><label for="foo">Foo</label><textarea id="foo"></textarea></li></ol></fieldset>'
|
460
|
+
end
|
461
|
+
|
462
|
+
specify "should be able to set a default configuration with Forme.default_config=" do
|
463
|
+
Forme.default_config = :formtastic
|
464
|
+
Forme::Form.new.inputs([[:textarea, {:id=>:foo, :label=>'Foo'}]]).to_s.should == '<fieldset class="inputs"><ol><li><label for="foo">Foo</label><textarea id="foo"></textarea></li></ol></fieldset>'
|
465
|
+
end
|
466
|
+
|
467
|
+
specify "should have #register_config register a configuration for later use" do
|
468
|
+
Forme.register_config(:foo, :wrapper=>:li, :labeler=>:explicit)
|
469
|
+
Forme::Form.new(:config=>:foo).input(:textarea, :id=>:foo, :label=>'Foo').to_s.should == '<li><label for="foo">Foo</label><textarea id="foo"></textarea></li>'
|
470
|
+
end
|
471
|
+
|
472
|
+
specify "should have #register_config support a :base option to base it on an existing config" do
|
473
|
+
Forme.register_config(:foo2, :labeler=>:default, :base=>:formtastic)
|
474
|
+
Forme::Form.new(:config=>:foo2).inputs([[:textarea, {:id=>:foo, :label=>'Foo'}]]).to_s.should == '<fieldset class="inputs"><ol><li><label>Foo: <textarea id="foo"></textarea></label></li></ol></fieldset>'
|
475
|
+
end
|
476
|
+
|
477
|
+
end
|
478
|
+
|
479
|
+
describe "Forme object forms" do
|
480
|
+
specify "should handle a simple case" do
|
481
|
+
obj = Class.new{def forme_input(form, field, opts) form._input(:text, :name=>"obj[#{field}]", :id=>"obj_#{field}", :value=>"#{field}_foo") end}.new
|
482
|
+
Forme::Form.new(obj).input(:field).to_s.should == '<input id="obj_field" name="obj[field]" type="text" value="field_foo"/>'
|
483
|
+
end
|
484
|
+
|
485
|
+
specify "should handle more complex case with multiple different types and opts" do
|
486
|
+
obj = Class.new do
|
487
|
+
def self.name() "Foo" end
|
488
|
+
|
489
|
+
attr_reader :x, :y
|
490
|
+
|
491
|
+
def initialize(x, y)
|
492
|
+
@x, @y = x, y
|
493
|
+
end
|
494
|
+
def forme_input(form, field, opts={})
|
495
|
+
t = opts[:type]
|
496
|
+
t ||= (field == :x ? :textarea : :text)
|
497
|
+
s = field.to_s
|
498
|
+
form._input(t, {:label=>s.upcase, :name=>"foo[#{s}]", :id=>"foo_#{s}", :value=>send(field)}.merge!(opts))
|
499
|
+
end
|
500
|
+
end.new('&foo', 3)
|
501
|
+
f = Forme::Form.new(obj)
|
502
|
+
f.input(:x).to_s.should == '<label>X: <textarea id="foo_x" name="foo[x]">&foo</textarea></label>'
|
503
|
+
f.input(:y, :attr=>{:brain=>'no'}).to_s.should == '<label>Y: <input brain="no" id="foo_y" name="foo[y]" type="text" value="3"/></label>'
|
504
|
+
end
|
505
|
+
|
506
|
+
specify "should handle case where obj doesn't respond to forme_input" do
|
507
|
+
Forme::Form.new([:foo]).input(:first).to_s.should == '<input id="first" name="first" type="text" value="foo"/>'
|
508
|
+
obj = Class.new{attr_accessor :foo}.new
|
509
|
+
obj.foo = 'bar'
|
510
|
+
Forme::Form.new(obj).input(:foo).to_s.should == '<input id="foo" name="foo" type="text" value="bar"/>'
|
511
|
+
end
|
512
|
+
|
513
|
+
specify "should respect opts hash when obj doesn't respond to forme_input" do
|
514
|
+
Forme::Form.new([:foo]).input(:first, :name=>'bar').to_s.should == '<input id="first" name="bar" type="text" value="foo"/>'
|
515
|
+
Forme::Form.new([:foo]).input(:first, :id=>'bar').to_s.should == '<input id="bar" name="first" type="text" value="foo"/>'
|
516
|
+
Forme::Form.new([:foo]).input(:first, :value=>'bar').to_s.should == '<input id="first" name="first" type="text" value="bar"/>'
|
517
|
+
Forme::Form.new([:foo]).input(:first, :attr=>{:x=>'bar'}).to_s.should == '<input id="first" name="first" type="text" value="foo" x="bar"/>'
|
518
|
+
end
|
519
|
+
|
520
|
+
specify "should handle obj passed in via :obj hash key" do
|
521
|
+
Forme::Form.new(:obj=>[:foo]).input(:first).to_s.should == '<input id="first" name="first" type="text" value="foo"/>'
|
522
|
+
end
|
523
|
+
|
524
|
+
specify "should be able to turn off obj handling per input using :obj=>nil option" do
|
525
|
+
Forme::Form.new([:foo]).input(:checkbox, :name=>"foo", :hidden_value=>"no", :obj=>nil).to_s.should == '<input name="foo" type="hidden" value="no"/><input name="foo" type="checkbox"/>'
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
describe "Forme.form DSL" do
|
530
|
+
specify "should return a form tag" do
|
531
|
+
Forme.form.to_s.should == '<form></form>'
|
532
|
+
end
|
533
|
+
|
534
|
+
specify "should yield a Form object to the block" do
|
535
|
+
Forme.form{|f| f.should be_a_kind_of(Forme::Form)}
|
536
|
+
end
|
537
|
+
|
538
|
+
specify "should have inputs called instead the block be added to the existing form" do
|
539
|
+
Forme.form{|f| f.input(:text)}.to_s.should == '<form><input type="text"/></form>'
|
540
|
+
end
|
541
|
+
|
542
|
+
specify "should be able to nest inputs inside tags" do
|
543
|
+
Forme.form{|f| f.tag(:div){f.input(:text)}}.to_s.should == '<form><div><input type="text"/></div></form>'
|
544
|
+
Forme.form{|f| f.tag(:div){f.tag(:fieldset){f.input(:text)}}}.to_s.should == '<form><div><fieldset><input type="text"/></fieldset></div></form>'
|
545
|
+
Forme.form{|f| f.tag(:div){f.tag(:fieldset){f.tag(:span){f.input(:text)}}}}.to_s.should == '<form><div><fieldset><span><input type="text"/></span></fieldset></div></form>'
|
546
|
+
Forme.form{|f| f.tag(:div){f.input(:text)}; f.input(:radio)}.to_s.should == '<form><div><input type="text"/></div><input type="radio"/></form>'
|
547
|
+
Forme.form{|f| f.tag(:div){f.tag(:fieldset){f.input(:text); f.input(:radio)}; f.input(:checkbox)}}.to_s.should == '<form><div><fieldset><input type="text"/><input type="radio"/></fieldset><input type="checkbox"/></div></form>'
|
548
|
+
end
|
549
|
+
|
550
|
+
specify "should handle an :inputs option to automatically create inputs" do
|
551
|
+
Forme.form({}, :inputs=>[:text, :textarea]).to_s.should == '<form><fieldset class="inputs"><input type="text"/><textarea></textarea></fieldset></form>'
|
552
|
+
end
|
553
|
+
|
554
|
+
specify "should handle a :legend option if inputs is used" do
|
555
|
+
Forme.form({}, :inputs=>[:text, :textarea], :legend=>'Foo').to_s.should == '<form><fieldset class="inputs"><legend>Foo</legend><input type="text"/><textarea></textarea></fieldset></form>'
|
556
|
+
end
|
557
|
+
|
558
|
+
specify "should still work with a block if :inputs is used" do
|
559
|
+
Forme.form({}, :inputs=>[:text]){|f| f.input(:textarea)}.to_s.should == '<form><fieldset class="inputs"><input type="text"/></fieldset><textarea></textarea></form>'
|
560
|
+
end
|
561
|
+
|
562
|
+
specify "should handle an :button option to automatically create a button" do
|
563
|
+
Forme.form({}, :button=>'Foo').to_s.should == '<form><input type="submit" value="Foo"/></form>'
|
564
|
+
end
|
565
|
+
|
566
|
+
specify "should allow :button option value to be a hash" do
|
567
|
+
Forme.form({}, :button=>{:value=>'Foo', :name=>'bar'}).to_s.should == '<form><input name="bar" type="submit" value="Foo"/></form>'
|
568
|
+
end
|
569
|
+
|
570
|
+
specify "should handle an :button option work with a block" do
|
571
|
+
Forme.form({}, :button=>'Foo'){|f| f.input(:textarea)}.to_s.should == '<form><textarea></textarea><input type="submit" value="Foo"/></form>'
|
572
|
+
end
|
573
|
+
|
574
|
+
specify "should have an :button and :inputs option work together" do
|
575
|
+
Forme.form({}, :inputs=>[:text, :textarea], :button=>'Foo').to_s.should == '<form><fieldset class="inputs"><input type="text"/><textarea></textarea></fieldset><input type="submit" value="Foo"/></form>'
|
576
|
+
end
|
577
|
+
|
578
|
+
end
|
579
|
+
|