formtastic-rails3 0.9.7

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.
Files changed (58) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +558 -0
  3. data/Rakefile +103 -0
  4. data/generators/form/USAGE +16 -0
  5. data/generators/form/form_generator.rb +120 -0
  6. data/generators/form/templates/view__form.html.erb +5 -0
  7. data/generators/form/templates/view__form.html.haml +4 -0
  8. data/generators/formtastic/formtastic_generator.rb +24 -0
  9. data/generators/formtastic/templates/formtastic.css +144 -0
  10. data/generators/formtastic/templates/formtastic.rb +54 -0
  11. data/generators/formtastic/templates/formtastic_changes.css +10 -0
  12. data/generators/formtastic_stylesheets/formtastic_stylesheets_generator.rb +16 -0
  13. data/lib/formtastic.rb +1724 -0
  14. data/lib/formtastic/i18n.rb +32 -0
  15. data/lib/formtastic/layout_helper.rb +10 -0
  16. data/lib/generators/formtastic/form/form_generator.rb +85 -0
  17. data/lib/generators/formtastic/form/templates/_form.html.erb +5 -0
  18. data/lib/generators/formtastic/form/templates/_form.html.haml +4 -0
  19. data/lib/generators/formtastic/install/install_generator.rb +23 -0
  20. data/lib/generators/formtastic/install/templates/formtastic.css +144 -0
  21. data/lib/generators/formtastic/install/templates/formtastic.rb +58 -0
  22. data/lib/generators/formtastic/install/templates/formtastic_changes.css +10 -0
  23. data/lib/locale/en.yml +8 -0
  24. data/spec/buttons_spec.rb +149 -0
  25. data/spec/commit_button_spec.rb +377 -0
  26. data/spec/custom_builder_spec.rb +62 -0
  27. data/spec/custom_macros.rb +460 -0
  28. data/spec/defaults_spec.rb +20 -0
  29. data/spec/error_proc_spec.rb +27 -0
  30. data/spec/errors_spec.rb +85 -0
  31. data/spec/form_helper_spec.rb +110 -0
  32. data/spec/i18n_spec.rb +131 -0
  33. data/spec/include_blank_spec.rb +70 -0
  34. data/spec/input_spec.rb +632 -0
  35. data/spec/inputs/boolean_input_spec.rb +93 -0
  36. data/spec/inputs/check_boxes_input_spec.rb +167 -0
  37. data/spec/inputs/country_input_spec.rb +80 -0
  38. data/spec/inputs/currency_input_spec.rb +80 -0
  39. data/spec/inputs/date_input_spec.rb +143 -0
  40. data/spec/inputs/datetime_input_spec.rb +259 -0
  41. data/spec/inputs/file_input_spec.rb +33 -0
  42. data/spec/inputs/hidden_input_spec.rb +52 -0
  43. data/spec/inputs/numeric_input_spec.rb +44 -0
  44. data/spec/inputs/password_input_spec.rb +46 -0
  45. data/spec/inputs/radio_input_spec.rb +152 -0
  46. data/spec/inputs/select_input_spec.rb +470 -0
  47. data/spec/inputs/string_input_spec.rb +47 -0
  48. data/spec/inputs/text_input_spec.rb +33 -0
  49. data/spec/inputs/time_input_spec.rb +128 -0
  50. data/spec/inputs/time_zone_input_spec.rb +102 -0
  51. data/spec/inputs_spec.rb +395 -0
  52. data/spec/label_spec.rb +48 -0
  53. data/spec/layout_helper_spec.rb +42 -0
  54. data/spec/semantic_errors_spec.rb +98 -0
  55. data/spec/semantic_fields_for_spec.rb +44 -0
  56. data/spec/spec.opts +2 -0
  57. data/spec/spec_helper.rb +238 -0
  58. metadata +205 -0
@@ -0,0 +1,377 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe 'SemanticFormBuilder#commit_button' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ActiveSupport::SafeBuffer.new
10
+ mock_everything
11
+ end
12
+
13
+ describe 'when used on any record' do
14
+
15
+ before do
16
+ @new_post.stub!(:new_record?).and_return(false)
17
+ semantic_form_for(@new_post) do |builder|
18
+ concat(builder.commit_button)
19
+ end
20
+ end
21
+
22
+ it 'should render a commit li' do
23
+ output_buffer.should have_tag('li.commit')
24
+ end
25
+
26
+ it 'should render an input with a type attribute of "submit"' do
27
+ output_buffer.should have_tag('li.commit input[@type="submit"]')
28
+ end
29
+
30
+ it 'should render an input with a name attribute of "commit"' do
31
+ output_buffer.should have_tag('li.commit input[@name="commit"]')
32
+ end
33
+
34
+ it 'should pass options given in :button_html to the button' do
35
+ @new_post.stub!(:new_record?).and_return(false)
36
+ semantic_form_for(@new_post) do |builder|
37
+ concat(builder.commit_button('text', :button_html => {:class => 'my_class', :id => 'my_id'}))
38
+ end
39
+
40
+ output_buffer.should have_tag('li.commit input#my_id')
41
+ output_buffer.should have_tag('li.commit input.my_class')
42
+ end
43
+
44
+ end
45
+
46
+ describe "its accesskey" do
47
+
48
+ it 'should allow nil default' do
49
+ with_config :default_commit_button_accesskey, nil do
50
+ output_buffer.should_not have_tag('li.commit input[@accesskey]')
51
+ end
52
+ end
53
+
54
+ it 'should use the default if set' do
55
+ with_config :default_commit_button_accesskey, 's' do
56
+ @new_post.stub!(:new_record?).and_return(false)
57
+ semantic_form_for(@new_post) do |builder|
58
+ concat(builder.commit_button('text', :button_html => {}))
59
+ end
60
+ output_buffer.should have_tag('li.commit input[@accesskey="s"]')
61
+ end
62
+ end
63
+
64
+ it 'should use the value set in options over the default' do
65
+ with_config :default_commit_button_accesskey, 's' do
66
+ @new_post.stub!(:new_record?).and_return(false)
67
+ semantic_form_for(@new_post) do |builder|
68
+ concat(builder.commit_button('text', :accesskey => 'o'))
69
+ end
70
+ output_buffer.should_not have_tag('li.commit input[@accesskey="s"]')
71
+ output_buffer.should have_tag('li.commit input[@accesskey="o"]')
72
+ end
73
+ end
74
+
75
+ it 'should use the value set in button_html over options' do
76
+ with_config :default_commit_button_accesskey, 's' do
77
+ @new_post.stub!(:new_record?).and_return(false)
78
+ semantic_form_for(@new_post) do |builder|
79
+ concat(builder.commit_button('text', :accesskey => 'o', :button_html => {:accesskey => 't'}))
80
+ end
81
+ output_buffer.should_not have_tag('li.commit input[@accesskey="s"]')
82
+ output_buffer.should_not have_tag('li.commit input[@accesskey="o"]')
83
+ output_buffer.should have_tag('li.commit input[@accesskey="t"]')
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ describe 'when the first option is a string and the second is a hash' do
90
+
91
+ before do
92
+ @new_post.stub!(:new_record?).and_return(false)
93
+ semantic_form_for(@new_post) do |builder|
94
+ concat(builder.commit_button("a string", :button_html => { :class => "pretty"}))
95
+ end
96
+ end
97
+
98
+ it "should render the string as the value of the button" do
99
+ output_buffer.should have_tag('li input[@value="a string"]')
100
+ end
101
+
102
+ it "should deal with the options hash" do
103
+ output_buffer.should have_tag('li input.pretty')
104
+ end
105
+
106
+ end
107
+
108
+ describe 'when the first option is a hash' do
109
+
110
+ before do
111
+ @new_post.stub!(:new_record?).and_return(false)
112
+ semantic_form_for(@new_post) do |builder|
113
+ concat(builder.commit_button(:button_html => { :class => "pretty"}))
114
+ end
115
+ end
116
+
117
+ it "should deal with the options hash" do
118
+ output_buffer.should have_tag('li input.pretty')
119
+ end
120
+
121
+ end
122
+
123
+ describe 'label' do
124
+
125
+ # No object
126
+ describe 'when used without object' do
127
+ describe 'when explicit label is provided' do
128
+ it 'should render an input with the explicitly specified label' do
129
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
130
+ concat(builder.commit_button("Click!"))
131
+ end
132
+ output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="submit"]')
133
+ end
134
+ end
135
+
136
+ describe 'when no explicit label is provided' do
137
+ describe 'when no I18n-localized label is provided' do
138
+ before do
139
+ ::I18n.backend.store_translations :en, :formtastic => {:submit => 'Submit {{model}}'}
140
+ end
141
+
142
+ after do
143
+ ::I18n.backend.store_translations :en, :formtastic => {:submit => nil}
144
+ end
145
+
146
+ it 'should render an input with default I18n-localized label (fallback)' do
147
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
148
+ concat(builder.commit_button)
149
+ end
150
+ output_buffer.should have_tag('li.commit input[@value="Submit Post"][@class~="submit"]')
151
+ end
152
+ end
153
+
154
+ describe 'when I18n-localized label is provided' do
155
+ before do
156
+ ::I18n.backend.store_translations :en,
157
+ :formtastic => {
158
+ :actions => {
159
+ :submit => 'Custom Submit',
160
+ :post => {
161
+ :submit => 'Custom Submit {{model}}'
162
+ }
163
+ }
164
+ }
165
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
166
+ end
167
+
168
+ it 'should render an input with localized label (I18n)' do
169
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
170
+ concat(builder.commit_button)
171
+ end
172
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit Post"][@class~="submit"]})
173
+ end
174
+
175
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
176
+ ::I18n.backend.store_translations :en,
177
+ :formtastic => {
178
+ :actions => {
179
+ :post => {
180
+ :submit => nil
181
+ }
182
+ }
183
+ }
184
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
185
+ concat(builder.commit_button)
186
+ end
187
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit"][@class~="submit"]})
188
+ end
189
+
190
+ end
191
+ end
192
+ end
193
+
194
+ # New record
195
+ describe 'when used on a new record' do
196
+ before do
197
+ @new_post.stub!(:new_record?).and_return(true)
198
+ end
199
+
200
+ describe 'when explicit label is provided' do
201
+ it 'should render an input with the explicitly specified label' do
202
+ semantic_form_for(@new_post) do |builder|
203
+ concat(builder.commit_button("Click!"))
204
+ end
205
+ output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="create"]')
206
+ end
207
+ end
208
+
209
+ describe 'when no explicit label is provided' do
210
+ describe 'when no I18n-localized label is provided' do
211
+ before do
212
+ ::I18n.backend.store_translations :en, :formtastic => {:create => 'Create {{model}}'}
213
+ end
214
+
215
+ after do
216
+ ::I18n.backend.store_translations :en, :formtastic => {:create => nil}
217
+ end
218
+
219
+ it 'should render an input with default I18n-localized label (fallback)' do
220
+ semantic_form_for(@new_post) do |builder|
221
+ concat(builder.commit_button)
222
+ end
223
+ output_buffer.should have_tag('li.commit input[@value="Create Post"][@class~="create"]')
224
+ end
225
+ end
226
+
227
+ describe 'when I18n-localized label is provided' do
228
+ before do
229
+ ::I18n.backend.store_translations :en,
230
+ :formtastic => {
231
+ :actions => {
232
+ :create => 'Custom Create',
233
+ :post => {
234
+ :create => 'Custom Create {{model}}'
235
+ }
236
+ }
237
+ }
238
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
239
+ end
240
+
241
+ after do
242
+ ::I18n.backend.store_translations :en, :formtastic => nil
243
+ end
244
+
245
+ it 'should render an input with localized label (I18n)' do
246
+ semantic_form_for(@new_post) do |builder|
247
+ concat(builder.commit_button)
248
+ end
249
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create Post"][@class~="create"]})
250
+ end
251
+
252
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
253
+ ::I18n.backend.store_translations :en,
254
+ :formtastic => {
255
+ :actions => {
256
+ :post => {
257
+ :create => nil
258
+ }
259
+ }
260
+ }
261
+ semantic_form_for(@new_post) do |builder|
262
+ concat(builder.commit_button)
263
+ end
264
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create"][@class~="create"]})
265
+ ::I18n.backend.store_translations :en, :formtastic => nil
266
+
267
+ end
268
+
269
+ end
270
+ end
271
+ end
272
+
273
+ # Existing record
274
+ describe 'when used on an existing record' do
275
+ before do
276
+ @new_post.stub!(:new_record?).and_return(false)
277
+ end
278
+
279
+ describe 'when explicit label is provided' do
280
+ it 'should render an input with the explicitly specified label' do
281
+ semantic_form_for(@new_post) do |builder|
282
+ concat(builder.commit_button("Click!"))
283
+ end
284
+ output_buffer.should have_tag('li.commit input[@value="Click!"][@class~="update"]')
285
+ end
286
+ end
287
+
288
+ describe 'when no explicit label is provided' do
289
+ describe 'when no I18n-localized label is provided' do
290
+ before do
291
+ ::I18n.backend.store_translations :en, :formtastic => {:update => 'Save {{model}}'}
292
+ end
293
+
294
+ after do
295
+ ::I18n.backend.store_translations :en, :formtastic => {:update => nil}
296
+ end
297
+
298
+ it 'should render an input with default I18n-localized label (fallback)' do
299
+ semantic_form_for(@new_post) do |builder|
300
+ concat(builder.commit_button)
301
+ end
302
+ output_buffer.should have_tag('li.commit input[@value="Save Post"][@class~="update"]')
303
+ end
304
+ end
305
+
306
+ describe 'when I18n-localized label is provided' do
307
+ before do
308
+ ::I18n.backend.store_translations :en,
309
+ :formtastic => {
310
+ :actions => {
311
+ :update => 'Custom Save',
312
+ :post => {
313
+ :update => 'Custom Save {{model}}'
314
+ }
315
+ }
316
+ }
317
+ ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
318
+ end
319
+
320
+ it 'should render an input with localized label (I18n)' do
321
+ semantic_form_for(@new_post) do |builder|
322
+ concat(builder.commit_button)
323
+ end
324
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save Post"][@class~="update"]})
325
+ end
326
+
327
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
328
+ ::I18n.backend.store_translations :en,
329
+ :formtastic => {
330
+ :actions => {
331
+ :post => {
332
+ :update => nil
333
+ }
334
+ }
335
+ }
336
+ semantic_form_for(@new_post) do |builder|
337
+ concat(builder.commit_button)
338
+ end
339
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save"][@class~="update"]})
340
+ ::I18n.backend.store_translations :en, :formtastic => {}
341
+ end
342
+
343
+ end
344
+ end
345
+ end
346
+ end
347
+
348
+ describe 'when the model is two words' do
349
+ before do
350
+ output_buffer = ''
351
+
352
+ class ::UserPost
353
+ extend ActiveModel::Naming
354
+
355
+ def id
356
+ end
357
+
358
+ def self.human_name
359
+ "Userpost" # Rails does crappy human_name
360
+ end
361
+ end
362
+
363
+ @new_user_post = ::UserPost.new
364
+
365
+ @new_user_post.stub!(:new_record?).and_return(true)
366
+ semantic_form_for(@new_user_post, :url => '') do |builder|
367
+ concat(builder.commit_button())
368
+ end
369
+ end
370
+
371
+ it "should render the string as the value of the button" do
372
+ output_buffer.should have_tag('li input[@value="Create User post"]')
373
+ end
374
+
375
+ end
376
+
377
+ end
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe 'Formtastic::SemanticFormHelper.builder' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ class MyCustomFormBuilder < ::Formtastic::SemanticFormBuilder
9
+ def awesome_input(method, options)
10
+ self.text_field(method)
11
+ end
12
+ end
13
+
14
+ before do
15
+ @output_buffer = ActiveSupport::SafeBuffer.new
16
+ mock_everything
17
+ end
18
+
19
+ it 'is the Formtastic::SemanticFormBuilder by default' do
20
+ ::Formtastic::SemanticFormHelper.builder.should == ::Formtastic::SemanticFormBuilder
21
+ end
22
+
23
+ it 'can be configured to use your own custom form builder' do
24
+ # Set it to a custom builder class
25
+ ::Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
26
+ ::Formtastic::SemanticFormHelper.builder.should == MyCustomFormBuilder
27
+
28
+ # Reset it to the default
29
+ ::Formtastic::SemanticFormHelper.builder = ::Formtastic::SemanticFormBuilder
30
+ ::Formtastic::SemanticFormHelper.builder.should == ::Formtastic::SemanticFormBuilder
31
+ end
32
+
33
+ describe "when using a custom builder" do
34
+
35
+ before do
36
+ @new_post.stub!(:title)
37
+ ::Formtastic::SemanticFormHelper.builder = MyCustomFormBuilder
38
+ end
39
+
40
+ after do
41
+ ::Formtastic::SemanticFormHelper.builder = ::Formtastic::SemanticFormBuilder
42
+ end
43
+
44
+ describe "semantic_form_for" do
45
+
46
+ it "should yeild and instance of the custom builder" do
47
+ semantic_form_for(@new_post) do |builder|
48
+ builder.class.should == MyCustomFormBuilder
49
+ end
50
+ end
51
+
52
+ it "should allow me to call my custom input" do
53
+ semantic_form_for(@new_post) do |builder|
54
+ concat(builder.input(:title, :as => :awesome))
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,460 @@
1
+ module CustomMacros
2
+
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ def it_should_have_input_wrapper_with_class(class_name)
10
+ it "should have input wrapper with class '#{class_name}'" do
11
+ output_buffer.should have_tag("form li.#{class_name}")
12
+ end
13
+ end
14
+
15
+ def it_should_have_input_wrapper_with_id(id_string)
16
+ it "should have input wrapper with id '#{id_string}'" do
17
+ output_buffer.should have_tag("form li##{id_string}")
18
+ end
19
+ end
20
+
21
+ def it_should_not_have_a_label
22
+ it "should not have a label" do
23
+ output_buffer.should_not have_tag("form li label")
24
+ end
25
+ end
26
+
27
+ def it_should_have_a_nested_fieldset
28
+ it "should have a nested_fieldset" do
29
+ output_buffer.should have_tag("form li fieldset")
30
+ end
31
+ end
32
+
33
+ def it_should_have_label_with_text(string_or_regex)
34
+ it "should have a label with text '#{string_or_regex}'" do
35
+ output_buffer.should have_tag("form li label", string_or_regex)
36
+ end
37
+ end
38
+
39
+ def it_should_have_label_for(element_id)
40
+ it "should have a label for ##{element_id}" do
41
+ output_buffer.should have_tag("form li label[@for='#{element_id}']")
42
+ end
43
+ end
44
+
45
+ def it_should_have_input_with_id(element_id)
46
+ it "should have an input with id '#{element_id}'" do
47
+ output_buffer.should have_tag("form li input##{element_id}")
48
+ end
49
+ end
50
+
51
+ def it_should_have_input_with_type(input_type)
52
+ it "should have a #{input_type} input" do
53
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
54
+ end
55
+ end
56
+
57
+ def it_should_have_input_with_name(name)
58
+ it "should have an input named #{name}" do
59
+ output_buffer.should have_tag("form li input[@name=\"#{name}\"]")
60
+ end
61
+ end
62
+
63
+ def it_should_have_textarea_with_name(name)
64
+ it "should have an input named #{name}" do
65
+ output_buffer.should have_tag("form li textarea[@name=\"#{name}\"]")
66
+ end
67
+ end
68
+
69
+ def it_should_have_textarea_with_id(element_id)
70
+ it "should have an input with id '#{element_id}'" do
71
+ output_buffer.should have_tag("form li textarea##{element_id}")
72
+ end
73
+ end
74
+
75
+ def it_should_use_default_text_field_size_when_method_has_no_database_column(as)
76
+ it 'should use default_text_field_size when method has no database column' do
77
+ @new_post.stub!(:column_for_attribute).and_return(nil) # Return a nil column
78
+
79
+ semantic_form_for(@new_post) do |builder|
80
+ concat(builder.input(:title, :as => as))
81
+ end
82
+ output_buffer.should have_tag("form li input[@size='#{Formtastic::SemanticFormBuilder.default_text_field_size}']")
83
+ end
84
+ end
85
+
86
+ def it_should_apply_custom_input_attributes_when_input_html_provided(as)
87
+ it 'it should apply custom input attributes when input_html provided' do
88
+ semantic_form_for(@new_post) do |builder|
89
+ concat(builder.input(:title, :as => as, :input_html => { :class => 'myclass' }))
90
+ end
91
+ output_buffer.should have_tag("form li input.myclass")
92
+ end
93
+ end
94
+
95
+ def it_should_apply_custom_for_to_label_when_input_html_id_provided(as)
96
+ it 'it should apply custom for to label when input_html :id provided' do
97
+ semantic_form_for(@new_post) do |builder|
98
+ concat(builder.input(:title, :as => as, :input_html => { :id => 'myid' }))
99
+ end
100
+ output_buffer.should have_tag('form li label[@for="myid"]')
101
+ end
102
+ end
103
+
104
+ def it_should_have_maxlength_matching_column_limit
105
+ it 'should have a maxlength matching column limit' do
106
+ @new_post.column_for_attribute(:title).limit.should == 50
107
+ output_buffer.should have_tag("form li input[@maxlength='50']")
108
+ end
109
+ end
110
+
111
+ def it_should_use_default_text_field_size_for_columns_longer_than_default_text_field_size(as)
112
+ it 'should use default_text_field_size for columns longer than default_text_field_size' do
113
+ default_size = Formtastic::SemanticFormBuilder.default_text_field_size
114
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => as, :limit => default_size * 2))
115
+
116
+ semantic_form_for(@new_post) do |builder|
117
+ concat(builder.input(:title, :as => as))
118
+ end
119
+
120
+ output_buffer.should have_tag("form li input[@size='#{default_size}']")
121
+ end
122
+ end
123
+
124
+ def it_should_use_column_size_for_columns_shorter_than_default_text_field_size(as)
125
+ it 'should use the column size for columns shorter than default_text_field_size' do
126
+ column_limit_shorted_than_default = 1
127
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => as, :limit => column_limit_shorted_than_default))
128
+
129
+ semantic_form_for(@new_post) do |builder|
130
+ concat(builder.input(:title, :as => as))
131
+ end
132
+
133
+ output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
134
+ end
135
+ end
136
+
137
+ def it_should_apply_error_logic_for_input_type(type)
138
+ describe 'when there are errors on the object for this method' do
139
+ before do
140
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
141
+ @errors = mock('errors')
142
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
143
+ @new_post.stub!(:errors).and_return(@errors)
144
+ end
145
+
146
+ it 'should apply an errors class to the list item' do
147
+ semantic_form_for(@new_post) do |builder|
148
+ concat(builder.input(:title, :as => type))
149
+ end
150
+ output_buffer.should have_tag('form li.error')
151
+ end
152
+
153
+ it 'should not wrap the input with the Rails default error wrapping' do
154
+ semantic_form_for(@new_post) do |builder|
155
+ concat(builder.input(:title, :as => type))
156
+ end
157
+ output_buffer.should_not have_tag('div.fieldWithErrors')
158
+ end
159
+
160
+ it 'should render a paragraph for the errors' do
161
+ ::Formtastic::SemanticFormBuilder.inline_errors = :sentence
162
+ semantic_form_for(@new_post) do |builder|
163
+ concat(builder.input(:title, :as => type))
164
+ end
165
+ output_buffer.should have_tag('form li.error p.inline-errors')
166
+ end
167
+
168
+ it 'should not display an error list' do
169
+ ::Formtastic::SemanticFormBuilder.inline_errors = :list
170
+ semantic_form_for(@new_post) do |builder|
171
+ concat(builder.input(:title, :as => type))
172
+ end
173
+ output_buffer.should have_tag('form li.error ul.errors')
174
+ end
175
+ end
176
+
177
+ describe 'when there are no errors on the object for this method' do
178
+ before do
179
+ semantic_form_for(@new_post) do |builder|
180
+ concat(builder.input(:title, :as => type))
181
+ end
182
+ end
183
+
184
+ it 'should not apply an errors class to the list item' do
185
+ output_buffer.should_not have_tag('form li.error')
186
+ end
187
+
188
+ it 'should not render a paragraph for the errors' do
189
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
190
+ end
191
+
192
+ it 'should not display an error list' do
193
+ output_buffer.should_not have_tag('form li.error ul.errors')
194
+ end
195
+ end
196
+
197
+ describe 'when no object is provided' do
198
+ before do
199
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
200
+ concat(builder.input(:title, :as => type))
201
+ end
202
+ end
203
+
204
+ it 'should not apply an errors class to the list item' do
205
+ output_buffer.should_not have_tag('form li.error')
206
+ end
207
+
208
+ it 'should not render a paragraph for the errors' do
209
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
210
+ end
211
+
212
+ it 'should not display an error list' do
213
+ output_buffer.should_not have_tag('form li.error ul.errors')
214
+ end
215
+ end
216
+ end
217
+
218
+ def it_should_call_find_on_association_class_when_no_collection_is_provided(as)
219
+ it "should call find on the association class when no collection is provided" do
220
+ ::Author.should_receive(:find)
221
+ semantic_form_for(@new_post) do |builder|
222
+ concat(builder.input(:author, :as => as))
223
+ end
224
+ end
225
+ end
226
+
227
+ def it_should_use_the_collection_when_provided(as, countable)
228
+ describe 'when the :collection option is provided' do
229
+
230
+ before do
231
+ @authors = ::Author.find(:all) * 2
232
+ output_buffer.replace '' # clears the output_buffer from the before block, hax!
233
+ end
234
+
235
+ it 'should not call find() on the parent class' do
236
+ ::Author.should_not_receive(:find)
237
+ semantic_form_for(@new_post) do |builder|
238
+ concat(builder.input(:author, :as => as, :collection => @authors))
239
+ end
240
+ end
241
+
242
+ it 'should use the provided collection' do
243
+ semantic_form_for(@new_post) do |builder|
244
+ concat(builder.input(:author, :as => as, :collection => @authors))
245
+ end
246
+ output_buffer.should have_tag("form li.#{as} #{countable}", :count => @authors.size + (as == :select ? 1 : 0))
247
+ end
248
+
249
+ describe 'and the :collection is an array of strings' do
250
+ before do
251
+ @categories = [ 'General', 'Design', 'Development', 'Quasi-Serious Inventions' ]
252
+ end
253
+
254
+ it "should use the string as the label text and value for each #{countable}" do
255
+ semantic_form_for(@new_post) do |builder|
256
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
257
+ end
258
+
259
+ @categories.each do |value|
260
+ output_buffer.should have_tag("form li.#{as}", /#{value}/)
261
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
262
+ end
263
+ end
264
+
265
+ if as == :radio
266
+ it 'should generate a sanitized label for attribute' do
267
+ @bob.stub!(:category_name).and_return(@categories)
268
+ semantic_form_for(@new_post) do |builder|
269
+ builder.semantic_fields_for(@bob) do |bob_builder|
270
+ concat(bob_builder.input(:category_name, :as => as, :collection => @categories))
271
+ end
272
+ end
273
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_general']")
274
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_design']")
275
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_development']")
276
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_quasiserious_inventions']")
277
+ end
278
+ end
279
+ end
280
+
281
+ describe 'and the :collection is a hash of strings' do
282
+ before do
283
+ @categories = { 'General' => 'gen', 'Design' => 'des','Development' => 'dev' }
284
+ end
285
+
286
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
287
+ semantic_form_for(@new_post) do |builder|
288
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
289
+ end
290
+
291
+ @categories.each do |label, value|
292
+ output_buffer.should have_tag("form li.#{as}", /#{label}/)
293
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
294
+ end
295
+ end
296
+ end
297
+
298
+ describe 'and the :collection is an array of arrays' do
299
+ before do
300
+ @categories = { 'General' => 'gen', 'Design' => 'des', 'Development' => 'dev' }.to_a
301
+ end
302
+
303
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
304
+ semantic_form_for(@new_post) do |builder|
305
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
306
+ end
307
+
308
+ @categories.each do |text, value|
309
+ label = as == :select ? :option : :label
310
+ output_buffer.should have_tag("form li.#{as} #{label}", /#{text}/i)
311
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value.to_s}']")
312
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_#{value.to_s}") if as == :radio
313
+ end
314
+ end
315
+ end
316
+
317
+ if as == :radio
318
+ describe 'and the :collection is an array of arrays with boolean values' do
319
+ before do
320
+ @choices = { 'Yeah' => true, 'Nah' => false }.to_a
321
+ end
322
+
323
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
324
+ semantic_form_for(@new_post) do |builder|
325
+ concat(builder.input(:category_name, :as => as, :collection => @choices))
326
+ end
327
+
328
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_true")
329
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_false")
330
+ end
331
+ end
332
+ end
333
+
334
+ describe 'and the :collection is an array of symbols' do
335
+ before do
336
+ @categories = [ :General, :Design, :Development ]
337
+ end
338
+
339
+ it "should use the symbol as the label text and value for each #{countable}" do
340
+ semantic_form_for(@new_post) do |builder|
341
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
342
+ end
343
+
344
+ @categories.each do |value|
345
+ label = as == :select ? :option : :label
346
+ output_buffer.should have_tag("form li.#{as} #{label}", /#{value}/i)
347
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value.to_s}']")
348
+ end
349
+ end
350
+ end
351
+
352
+ describe 'and the :collection is an OrderedHash of strings' do
353
+ before do
354
+ @categories = ActiveSupport::OrderedHash.new('General' => 'gen', 'Design' => 'des','Development' => 'dev')
355
+ end
356
+
357
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
358
+ semantic_form_for(@new_post) do |builder|
359
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
360
+ end
361
+
362
+ @categories.each do |label, value|
363
+ output_buffer.should have_tag("form li.#{as}", /#{label}/)
364
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
365
+ end
366
+ end
367
+
368
+ end
369
+
370
+ describe 'when the :label_method option is provided' do
371
+
372
+ describe 'as a symbol' do
373
+ before do
374
+ semantic_form_for(@new_post) do |builder|
375
+ concat(builder.input(:author, :as => as, :label_method => :login))
376
+ end
377
+ end
378
+
379
+ it 'should have options with text content from the specified method' do
380
+ ::Author.find(:all).each do |author|
381
+ output_buffer.should have_tag("form li.#{as}", /#{author.login}/)
382
+ end
383
+ end
384
+ end
385
+
386
+ describe 'as a proc' do
387
+ before do
388
+ semantic_form_for(@new_post) do |builder|
389
+ concat(builder.input(:author, :as => as, :label_method => Proc.new {|a| a.login.reverse }))
390
+ end
391
+ end
392
+
393
+ it 'should have options with the proc applied to each' do
394
+ ::Author.find(:all).each do |author|
395
+ output_buffer.should have_tag("form li.#{as}", /#{author.login.reverse}/)
396
+ end
397
+ end
398
+ end
399
+
400
+ end
401
+
402
+ describe 'when the :label_method option is not provided' do
403
+ ::Formtastic::SemanticFormBuilder.collection_label_methods.each do |label_method|
404
+
405
+ describe "when the collection objects respond to #{label_method}" do
406
+ before do
407
+ @fred.stub!(:respond_to?).and_return { |m| m.to_s == label_method }
408
+ ::Author.find(:all).each { |a| a.stub!(label_method).and_return('The Label Text') }
409
+
410
+ semantic_form_for(@new_post) do |builder|
411
+ concat(builder.input(:author, :as => as))
412
+ end
413
+ end
414
+
415
+ it "should render the options with #{label_method} as the label" do
416
+ ::Author.find(:all).each do |author|
417
+ output_buffer.should have_tag("form li.#{as}", /The Label Text/)
418
+ end
419
+ end
420
+ end
421
+
422
+ end
423
+ end
424
+
425
+ describe 'when the :value_method option is provided' do
426
+
427
+ describe 'as a symbol' do
428
+ before do
429
+ semantic_form_for(@new_post) do |builder|
430
+ concat(builder.input(:author, :as => as, :value_method => :login))
431
+ end
432
+ end
433
+
434
+ it 'should have options with values from specified method' do
435
+ ::Author.find(:all).each do |author|
436
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login}']")
437
+ end
438
+ end
439
+ end
440
+
441
+ describe 'as a proc' do
442
+ before do
443
+ semantic_form_for(@new_post) do |builder|
444
+ concat(builder.input(:author, :as => as, :value_method => Proc.new {|a| a.login.reverse }))
445
+ end
446
+ end
447
+
448
+ it 'should have options with the proc applied to each value' do
449
+ ::Author.find(:all).each do |author|
450
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login.reverse}']")
451
+ end
452
+ end
453
+ end
454
+ end
455
+
456
+ end
457
+ end
458
+
459
+ end
460
+ end