formtastic 1.2.5 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +2 -0
  3. data/.yardopts +1 -0
  4. data/CHANGELOG +279 -0
  5. data/Gemfile +3 -0
  6. data/README.textile +155 -172
  7. data/RELEASE_PROCESS +7 -0
  8. data/Rakefile +52 -0
  9. data/app/assets/stylesheets/formtastic.css +275 -0
  10. data/app/assets/stylesheets/formtastic_ie6.css +27 -0
  11. data/app/assets/stylesheets/formtastic_ie7.css +17 -0
  12. data/formtastic.gemspec +51 -0
  13. data/lib/formtastic.rb +21 -1960
  14. data/lib/formtastic/engine.rb +7 -0
  15. data/lib/formtastic/form_builder.rb +83 -0
  16. data/lib/formtastic/helpers.rb +16 -0
  17. data/lib/formtastic/helpers/buttons_helper.rb +277 -0
  18. data/lib/formtastic/helpers/errors_helper.rb +113 -0
  19. data/lib/formtastic/helpers/fieldset_wrapper.rb +75 -0
  20. data/lib/formtastic/helpers/file_column_detection.rb +16 -0
  21. data/lib/formtastic/helpers/form_helper.rb +198 -0
  22. data/lib/formtastic/helpers/input_helper.rb +366 -0
  23. data/lib/formtastic/helpers/inputs_helper.rb +392 -0
  24. data/lib/formtastic/helpers/reflection.rb +33 -0
  25. data/lib/formtastic/helpers/semantic_form_helper.rb +11 -0
  26. data/lib/formtastic/html_attributes.rb +21 -0
  27. data/lib/formtastic/i18n.rb +1 -0
  28. data/lib/formtastic/inputs.rb +31 -0
  29. data/lib/formtastic/inputs/base.rb +61 -0
  30. data/lib/formtastic/inputs/base/associations.rb +31 -0
  31. data/lib/formtastic/inputs/base/choices.rb +103 -0
  32. data/lib/formtastic/inputs/base/collections.rb +94 -0
  33. data/lib/formtastic/inputs/base/database.rb +17 -0
  34. data/lib/formtastic/inputs/base/errors.rb +58 -0
  35. data/lib/formtastic/inputs/base/fileish.rb +23 -0
  36. data/lib/formtastic/inputs/base/grouped_collections.rb +77 -0
  37. data/lib/formtastic/inputs/base/hints.rb +31 -0
  38. data/lib/formtastic/inputs/base/html.rb +52 -0
  39. data/lib/formtastic/inputs/base/labelling.rb +55 -0
  40. data/lib/formtastic/inputs/base/naming.rb +42 -0
  41. data/lib/formtastic/inputs/base/options.rb +18 -0
  42. data/lib/formtastic/inputs/base/stringish.rb +35 -0
  43. data/lib/formtastic/inputs/base/timeish.rb +128 -0
  44. data/lib/formtastic/inputs/base/validations.rb +166 -0
  45. data/lib/formtastic/inputs/base/wrapping.rb +40 -0
  46. data/lib/formtastic/inputs/boolean_input.rb +96 -0
  47. data/lib/formtastic/inputs/check_boxes_input.rb +179 -0
  48. data/lib/formtastic/inputs/country_input.rb +66 -0
  49. data/lib/formtastic/inputs/date_input.rb +14 -0
  50. data/lib/formtastic/inputs/datetime_input.rb +9 -0
  51. data/lib/formtastic/inputs/email_input.rb +40 -0
  52. data/lib/formtastic/inputs/file_input.rb +42 -0
  53. data/lib/formtastic/inputs/hidden_input.rb +66 -0
  54. data/lib/formtastic/inputs/number_input.rb +118 -0
  55. data/lib/formtastic/inputs/numeric_input.rb +21 -0
  56. data/lib/formtastic/inputs/password_input.rb +40 -0
  57. data/lib/formtastic/inputs/phone_input.rb +41 -0
  58. data/lib/formtastic/inputs/radio_input.rb +157 -0
  59. data/lib/formtastic/inputs/range_input.rb +119 -0
  60. data/lib/formtastic/inputs/search_input.rb +40 -0
  61. data/lib/formtastic/inputs/select_input.rb +210 -0
  62. data/lib/formtastic/inputs/string_input.rb +34 -0
  63. data/lib/formtastic/inputs/text_input.rb +47 -0
  64. data/lib/formtastic/inputs/time_input.rb +14 -0
  65. data/lib/formtastic/inputs/time_zone_input.rb +48 -0
  66. data/lib/formtastic/inputs/url_input.rb +40 -0
  67. data/lib/formtastic/localized_string.rb +105 -0
  68. data/lib/formtastic/railtie.rb +5 -7
  69. data/lib/formtastic/semantic_form_builder.rb +11 -0
  70. data/lib/formtastic/util.rb +6 -19
  71. data/lib/formtastic/version.rb +3 -0
  72. data/lib/generators/formtastic/install/install_generator.rb +28 -6
  73. data/lib/generators/templates/_form.html.erb +10 -4
  74. data/lib/generators/templates/_form.html.haml +8 -4
  75. data/lib/generators/templates/formtastic.rb +25 -32
  76. data/lib/locale/en.yml +1 -0
  77. data/lib/tasks/verify_rcov.rb +44 -0
  78. data/sample/basic_inputs.html +182 -0
  79. data/sample/config.ru +69 -0
  80. data/sample/index.html +14 -0
  81. data/spec/builder/custom_builder_spec.rb +109 -0
  82. data/spec/builder/error_proc_spec.rb +27 -0
  83. data/spec/builder/errors_spec.rb +193 -0
  84. data/spec/builder/semantic_fields_for_spec.rb +88 -0
  85. data/spec/helpers/buttons_helper_spec.rb +150 -0
  86. data/spec/helpers/commit_button_helper_spec.rb +470 -0
  87. data/spec/helpers/form_helper_spec.rb +135 -0
  88. data/spec/helpers/input_helper_spec.rb +837 -0
  89. data/spec/helpers/inputs_helper_spec.rb +562 -0
  90. data/spec/helpers/semantic_errors_helper_spec.rb +112 -0
  91. data/spec/i18n_spec.rb +199 -0
  92. data/spec/inputs/boolean_input_spec.rb +184 -0
  93. data/spec/inputs/check_boxes_input_spec.rb +375 -0
  94. data/spec/inputs/country_input_spec.rb +133 -0
  95. data/spec/inputs/custom_input_spec.rb +52 -0
  96. data/spec/inputs/date_input_spec.rb +110 -0
  97. data/spec/inputs/datetime_input_spec.rb +115 -0
  98. data/spec/inputs/email_input_spec.rb +55 -0
  99. data/spec/inputs/file_input_spec.rb +59 -0
  100. data/spec/inputs/hidden_input_spec.rb +120 -0
  101. data/spec/inputs/include_blank_spec.rb +70 -0
  102. data/spec/inputs/label_spec.rb +104 -0
  103. data/spec/inputs/number_input_spec.rb +487 -0
  104. data/spec/inputs/numeric_input_spec.rb +41 -0
  105. data/spec/inputs/password_input_spec.rb +69 -0
  106. data/spec/inputs/phone_input_spec.rb +55 -0
  107. data/spec/inputs/placeholder_spec.rb +71 -0
  108. data/spec/inputs/radio_input_spec.rb +234 -0
  109. data/spec/inputs/range_input_spec.rb +477 -0
  110. data/spec/inputs/search_input_spec.rb +55 -0
  111. data/spec/inputs/select_input_spec.rb +545 -0
  112. data/spec/inputs/string_input_spec.rb +163 -0
  113. data/spec/inputs/text_input_spec.rb +158 -0
  114. data/spec/inputs/time_input_spec.rb +155 -0
  115. data/spec/inputs/time_zone_input_spec.rb +87 -0
  116. data/spec/inputs/url_input_spec.rb +55 -0
  117. data/spec/spec.opts +2 -0
  118. data/spec/spec_helper.rb +361 -0
  119. data/spec/support/custom_macros.rb +656 -0
  120. data/spec/support/deferred_garbage_collection.rb +21 -0
  121. data/spec/support/deprecation.rb +6 -0
  122. data/spec/support/test_environment.rb +30 -0
  123. metadata +306 -88
  124. data/generators/form/USAGE +0 -16
  125. data/generators/form/form_generator.rb +0 -111
  126. data/generators/formtastic/formtastic_generator.rb +0 -26
  127. data/init.rb +0 -5
  128. data/lib/formtastic/layout_helper.rb +0 -12
  129. data/lib/generators/formtastic/form/form_generator.rb +0 -84
  130. data/lib/generators/templates/formtastic.css +0 -145
  131. data/lib/generators/templates/formtastic_changes.css +0 -14
  132. data/lib/generators/templates/rails2/_form.html.erb +0 -5
  133. data/lib/generators/templates/rails2/_form.html.haml +0 -4
  134. data/rails/init.rb +0 -2
@@ -0,0 +1,656 @@
1
+ # encoding: utf-8
2
+
3
+ module CustomMacros
4
+
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def it_should_have_input_wrapper_with_class(class_name)
12
+ it "should have input wrapper with class '#{class_name}'" do
13
+ output_buffer.should have_tag("form li.#{class_name}")
14
+ end
15
+ end
16
+
17
+ def it_should_have_input_wrapper_with_id(id_string)
18
+ it "should have input wrapper with id '#{id_string}'" do
19
+ output_buffer.should have_tag("form li##{id_string}")
20
+ end
21
+ end
22
+
23
+ def it_should_not_have_a_label
24
+ it "should not have a label" do
25
+ output_buffer.should_not have_tag("form li label")
26
+ end
27
+ end
28
+
29
+ def it_should_have_a_nested_fieldset
30
+ it "should have a nested_fieldset" do
31
+ output_buffer.should have_tag("form li fieldset")
32
+ end
33
+ end
34
+
35
+ def it_should_have_a_nested_fieldset_with_class(klass)
36
+ it "should have a nested_fieldset with class #{klass}" do
37
+ output_buffer.should have_tag("form li fieldset.#{klass}")
38
+ end
39
+ end
40
+
41
+ def it_should_have_a_nested_ordered_list_with_class(klass)
42
+ it "should have a nested fieldset with class #{klass}" do
43
+ output_buffer.should have_tag("form li ol.#{klass}")
44
+ end
45
+ end
46
+
47
+ def it_should_have_label_with_text(string_or_regex)
48
+ it "should have a label with text '#{string_or_regex}'" do
49
+ output_buffer.should have_tag("form li label", string_or_regex)
50
+ end
51
+ end
52
+
53
+ def it_should_have_label_for(element_id)
54
+ it "should have a label for ##{element_id}" do
55
+ output_buffer.should have_tag("form li label.label[@for='#{element_id}']")
56
+ end
57
+ end
58
+
59
+ def it_should_have_an_inline_label_for(element_id)
60
+ it "should have a label for ##{element_id}" do
61
+ output_buffer.should have_tag("form li label[@for='#{element_id}']")
62
+ end
63
+ end
64
+
65
+ def it_should_have_input_with_id(element_id)
66
+ it "should have an input with id '#{element_id}'" do
67
+ output_buffer.should have_tag("form li input##{element_id}")
68
+ end
69
+ end
70
+
71
+ def it_should_have_select_with_id(element_id)
72
+ it "should have a select box with id '#{element_id}'" do
73
+ output_buffer.should have_tag("form li select##{element_id}")
74
+ end
75
+ end
76
+
77
+ def it_should_have_input_with_type(input_type)
78
+ it "should have a #{input_type} input" do
79
+ output_buffer.should have_tag("form li input[@type=\"#{input_type}\"]")
80
+ end
81
+ end
82
+
83
+ def it_should_have_input_with_name(name)
84
+ it "should have an input named #{name}" do
85
+ output_buffer.should have_tag("form li input[@name=\"#{name}\"]")
86
+ end
87
+ end
88
+
89
+ def it_should_have_textarea_with_name(name)
90
+ it "should have an input named #{name}" do
91
+ output_buffer.should have_tag("form li textarea[@name=\"#{name}\"]")
92
+ end
93
+ end
94
+
95
+ def it_should_have_textarea_with_id(element_id)
96
+ it "should have an input with id '#{element_id}'" do
97
+ output_buffer.should have_tag("form li textarea##{element_id}")
98
+ end
99
+ end
100
+
101
+ def it_should_have_label_and_input_with_id(element_id)
102
+ it "should have an input with id '#{element_id}'" do
103
+ output_buffer.should have_tag("form li input##{element_id}")
104
+ output_buffer.should have_tag("form li label[@for='#{element_id}']")
105
+ end
106
+ end
107
+
108
+ def it_should_use_default_text_field_size_when_not_nil(as)
109
+ it 'should use default_text_field_size when not nil' do
110
+ with_config :default_text_field_size, 30 do
111
+ concat(semantic_form_for(@new_post) do |builder|
112
+ concat(builder.input(:title, :as => as))
113
+ end)
114
+ output_buffer.should have_tag("form li input[@size='#{Formtastic::FormBuilder.default_text_field_size}']")
115
+ end
116
+ end
117
+ end
118
+
119
+ def it_should_not_use_default_text_field_size_when_nil(as)
120
+ it 'should not use default_text_field_size when nil' do
121
+ with_config :default_text_field_size, nil do
122
+ concat(semantic_form_for(@new_post) do |builder|
123
+ concat(builder.input(:title, :as => as))
124
+ end)
125
+ output_buffer.should have_tag("form li input")
126
+ output_buffer.should_not have_tag("form li input[@size]")
127
+ end
128
+ end
129
+ end
130
+
131
+ def it_should_apply_custom_input_attributes_when_input_html_provided(as)
132
+ it 'it should apply custom input attributes when input_html provided' do
133
+ concat(semantic_form_for(@new_post) do |builder|
134
+ concat(builder.input(:title, :as => as, :input_html => { :class => 'myclass' }))
135
+ end)
136
+ output_buffer.should have_tag("form li input.myclass")
137
+ end
138
+ end
139
+
140
+ def it_should_apply_custom_for_to_label_when_input_html_id_provided(as)
141
+ it 'it should apply custom for to label when input_html :id provided' do
142
+ concat(semantic_form_for(@new_post) do |builder|
143
+ concat(builder.input(:title, :as => as, :input_html => { :id => 'myid' }))
144
+ end)
145
+ output_buffer.should have_tag('form li label[@for="myid"]')
146
+ end
147
+ end
148
+
149
+ def it_should_have_maxlength_matching_column_limit
150
+ it 'should have a maxlength matching column limit' do
151
+ @new_post.column_for_attribute(:title).limit.should == 50
152
+ output_buffer.should have_tag("form li input[@maxlength='50']")
153
+ end
154
+ end
155
+
156
+ def it_should_use_column_size_for_columns_shorter_than_default_text_field_size(as)
157
+ it 'should use the column size for columns shorter than default_text_field_size' do
158
+ column_limit_shorted_than_default = 1
159
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => as, :limit => column_limit_shorted_than_default))
160
+
161
+ concat(semantic_form_for(@new_post) do |builder|
162
+ concat(builder.input(:title, :as => as))
163
+ end)
164
+
165
+ output_buffer.should have_tag("form li input[@size='#{column_limit_shorted_than_default}']")
166
+ end
167
+ end
168
+
169
+ def it_should_apply_error_logic_for_input_type(type)
170
+ describe 'when there are errors on the object for this method' do
171
+ before do
172
+ @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome']
173
+ @errors = mock('errors')
174
+ @errors.stub!(:[]).with(:title).and_return(@title_errors)
175
+ Formtastic::FormBuilder.file_metadata_suffixes.each do |suffix|
176
+ @errors.stub!(:[]).with("title_#{suffix}".to_sym).and_return(nil)
177
+ end
178
+ @new_post.stub!(:errors).and_return(@errors)
179
+ end
180
+
181
+ it 'should apply an errors class to the list item' do
182
+ concat(semantic_form_for(@new_post) do |builder|
183
+ concat(builder.input(:title, :as => type))
184
+ end)
185
+ output_buffer.should have_tag('form li.error')
186
+ end
187
+
188
+ it 'should not wrap the input with the Rails default error wrapping' do
189
+ concat(semantic_form_for(@new_post) do |builder|
190
+ concat(builder.input(:title, :as => type))
191
+ end)
192
+ output_buffer.should_not have_tag('div.fieldWithErrors')
193
+ end
194
+
195
+ it 'should render a paragraph for the errors' do
196
+ Formtastic::FormBuilder.inline_errors = :sentence
197
+ concat(semantic_form_for(@new_post) do |builder|
198
+ concat(builder.input(:title, :as => type))
199
+ end)
200
+ output_buffer.should have_tag('form li.error p.inline-errors')
201
+ end
202
+
203
+ it 'should not display an error list' do
204
+ Formtastic::FormBuilder.inline_errors = :list
205
+ concat(semantic_form_for(@new_post) do |builder|
206
+ concat(builder.input(:title, :as => type))
207
+ end)
208
+ output_buffer.should have_tag('form li.error ul.errors')
209
+ end
210
+ end
211
+
212
+ describe 'when there are no errors on the object for this method' do
213
+ before do
214
+ @form = semantic_form_for(@new_post) do |builder|
215
+ concat(builder.input(:title, :as => type))
216
+ end
217
+ end
218
+
219
+ it 'should not apply an errors class to the list item' do
220
+ output_buffer.should_not have_tag('form li.error')
221
+ end
222
+
223
+ it 'should not render a paragraph for the errors' do
224
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
225
+ end
226
+
227
+ it 'should not display an error list' do
228
+ output_buffer.should_not have_tag('form li.error ul.errors')
229
+ end
230
+ end
231
+
232
+ describe 'when no object is provided' do
233
+ before do
234
+ concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
235
+ concat(builder.input(:title, :as => type))
236
+ end)
237
+ end
238
+
239
+ it 'should not apply an errors class to the list item' do
240
+ output_buffer.should_not have_tag('form li.error')
241
+ end
242
+
243
+ it 'should not render a paragraph for the errors' do
244
+ output_buffer.should_not have_tag('form li.error p.inline-errors')
245
+ end
246
+
247
+ it 'should not display an error list' do
248
+ output_buffer.should_not have_tag('form li.error ul.errors')
249
+ end
250
+ end
251
+ end
252
+
253
+ def it_should_call_find_on_association_class_when_no_collection_is_provided(as)
254
+ it "should call find on the association class when no collection is provided" do
255
+ ::Author.should_receive(:where)
256
+ concat(semantic_form_for(@new_post) do |builder|
257
+ concat(builder.input(:author, :as => as))
258
+ end)
259
+ end
260
+ end
261
+
262
+ def it_should_use_the_collection_when_provided(as, countable)
263
+ describe 'when the :collection option is provided' do
264
+
265
+ before do
266
+ @authors = ::Author.all * 2
267
+ output_buffer.replace ''
268
+ end
269
+
270
+ it 'should use the provided collection' do
271
+ concat(semantic_form_for(@new_post) do |builder|
272
+ concat(builder.input(:author, :as => as, :collection => @authors))
273
+ end)
274
+ output_buffer.should have_tag("form li.#{as} #{countable}", :count => @authors.size + (as == :select ? 1 : 0))
275
+ end
276
+
277
+ describe 'and the :collection is an array of strings' do
278
+ before do
279
+ @categories = [ 'General', 'Design', 'Development', 'Quasi-Serious Inventions' ]
280
+ end
281
+
282
+ it "should use the string as the label text and value for each #{countable}" do
283
+ concat(semantic_form_for(@new_post) do |builder|
284
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
285
+ end)
286
+
287
+ @categories.each do |value|
288
+ output_buffer.should have_tag("form li.#{as}", /#{value}/)
289
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
290
+ end
291
+ end
292
+
293
+ if as == :radio
294
+ it 'should generate a sanitized label for attribute' do
295
+ @bob.stub!(:category_name).and_return(@categories)
296
+ concat(semantic_form_for(@new_post) do |builder|
297
+ fields = builder.semantic_fields_for(@bob) do |bob_builder|
298
+ concat(bob_builder.input(:category_name, :as => as, :collection => @categories))
299
+ end
300
+ concat(fields)
301
+ end)
302
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_general']")
303
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_design']")
304
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_development']")
305
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_category_name_quasi-serious_inventions']")
306
+ end
307
+ end
308
+ end
309
+
310
+ describe 'and the :collection is a hash of strings' do
311
+ before do
312
+ @categories = { 'General' => 'gen', 'Design' => 'des','Development' => 'dev' }
313
+ end
314
+
315
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
316
+ concat(semantic_form_for(@new_post) do |builder|
317
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
318
+ end)
319
+
320
+ @categories.each do |label, value|
321
+ output_buffer.should have_tag("form li.#{as}", /#{label}/)
322
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
323
+ end
324
+ end
325
+ end
326
+
327
+ describe 'and the :collection is an array of arrays' do
328
+ before do
329
+ @categories = { 'General' => 'gen', 'Design' => 'des', 'Development' => 'dev' }.to_a
330
+ end
331
+
332
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
333
+ concat(semantic_form_for(@new_post) do |builder|
334
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
335
+ end)
336
+
337
+ @categories.each do |text, value|
338
+ label = as == :select ? :option : :label
339
+ output_buffer.should have_tag("form li.#{as} #{label}", /#{text}/i)
340
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value.to_s}']")
341
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_#{value.to_s}") if as == :radio
342
+ end
343
+ end
344
+ end
345
+
346
+ if as == :radio
347
+ describe 'and the :collection is an array of arrays with boolean values' do
348
+ before do
349
+ @choices = { 'Yeah' => true, 'Nah' => false }.to_a
350
+ end
351
+
352
+ it "should use the first value as the label text and the last value as the value attribute for #{countable}" do
353
+ concat(semantic_form_for(@new_post) do |builder|
354
+ concat(builder.input(:category_name, :as => as, :collection => @choices))
355
+ end)
356
+
357
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_true")
358
+ output_buffer.should have_tag("form li.#{as} #{countable}#post_category_name_false")
359
+ end
360
+ end
361
+ end
362
+
363
+ describe 'and the :collection is an array of symbols' do
364
+ before do
365
+ @categories = [ :General, :Design, :Development ]
366
+ end
367
+
368
+ it "should use the symbol as the label text and value for each #{countable}" do
369
+ concat(semantic_form_for(@new_post) do |builder|
370
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
371
+ end)
372
+
373
+ @categories.each do |value|
374
+ label = as == :select ? :option : :label
375
+ output_buffer.should have_tag("form li.#{as} #{label}", /#{value}/i)
376
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value.to_s}']")
377
+ end
378
+ end
379
+ end
380
+
381
+ describe 'and the :collection is an OrderedHash of strings' do
382
+ before do
383
+ @categories = ActiveSupport::OrderedHash.new('General' => 'gen', 'Design' => 'des','Development' => 'dev')
384
+ end
385
+
386
+ it "should use the key as the label text and the hash value as the value attribute for each #{countable}" do
387
+ concat(semantic_form_for(@new_post) do |builder|
388
+ concat(builder.input(:category_name, :as => as, :collection => @categories))
389
+ end)
390
+
391
+ @categories.each do |label, value|
392
+ output_buffer.should have_tag("form li.#{as}", /#{label}/)
393
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{value}']")
394
+ end
395
+ end
396
+
397
+ end
398
+
399
+ describe 'when the :member_label option is provided' do
400
+
401
+ describe 'as a symbol' do
402
+ before do
403
+ concat(semantic_form_for(@new_post) do |builder|
404
+ concat(builder.input(:author, :as => as, :member_label => :login))
405
+ end)
406
+ end
407
+
408
+ it 'should have options with text content from the specified method' do
409
+ ::Author.all.each do |author|
410
+ output_buffer.should have_tag("form li.#{as}", /#{author.login}/)
411
+ end
412
+ end
413
+ end
414
+
415
+ describe 'as a proc' do
416
+ before do
417
+ concat(semantic_form_for(@new_post) do |builder|
418
+ concat(builder.input(:author, :as => as, :member_label => Proc.new {|a| a.login.reverse }))
419
+ end)
420
+ end
421
+
422
+ it 'should have options with the proc applied to each' do
423
+ ::Author.all.each do |author|
424
+ output_buffer.should have_tag("form li.#{as}", /#{author.login.reverse}/)
425
+ end
426
+ end
427
+ end
428
+
429
+ describe 'as a method object' do
430
+ before do
431
+ def reverse_login(a)
432
+ a.login.reverse
433
+ end
434
+ concat(semantic_form_for(@new_post) do |builder|
435
+ concat(builder.input(:author, :as => as, :member_label => method(:reverse_login)))
436
+ end)
437
+ end
438
+
439
+ it 'should have options with the proc applied to each' do
440
+ ::Author.all.each do |author|
441
+ output_buffer.should have_tag("form li.#{as}", /#{author.login.reverse}/)
442
+ end
443
+ end
444
+ end
445
+ end
446
+
447
+ describe 'when the :member_label option is not provided' do
448
+ Formtastic::FormBuilder.collection_label_methods.each do |label_method|
449
+
450
+ describe "when the collection objects respond to #{label_method}" do
451
+ before do
452
+ @fred.stub!(:respond_to?).and_return { |m| m.to_s == label_method || m.to_s == 'id' }
453
+ ::Author.all.each { |a| a.stub!(label_method).and_return('The Label Text') }
454
+
455
+ concat(semantic_form_for(@new_post) do |builder|
456
+ concat(builder.input(:author, :as => as))
457
+ end)
458
+ end
459
+
460
+ it "should render the options with #{label_method} as the label" do
461
+ ::Author.all.each do |author|
462
+ output_buffer.should have_tag("form li.#{as}", /The Label Text/)
463
+ end
464
+ end
465
+ end
466
+
467
+ end
468
+ end
469
+
470
+ describe 'when the :member_value option is provided' do
471
+
472
+ describe 'as a symbol' do
473
+ before do
474
+ concat(semantic_form_for(@new_post) do |builder|
475
+ concat(builder.input(:author, :as => as, :member_value => :login))
476
+ end)
477
+ end
478
+
479
+ it 'should have options with values from specified method' do
480
+ ::Author.all.each do |author|
481
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login}']")
482
+ end
483
+ end
484
+ end
485
+
486
+ describe 'as a proc' do
487
+ before do
488
+ concat(semantic_form_for(@new_post) do |builder|
489
+ concat(builder.input(:author, :as => as, :member_value => Proc.new {|a| a.login.reverse }))
490
+ end)
491
+ end
492
+
493
+ it 'should have options with the proc applied to each value' do
494
+ ::Author.all.each do |author|
495
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login.reverse}']")
496
+ end
497
+ end
498
+ end
499
+
500
+ describe 'as a method object' do
501
+ before do
502
+ def reverse_login(a)
503
+ a.login.reverse
504
+ end
505
+ concat(semantic_form_for(@new_post) do |builder|
506
+ concat(builder.input(:author, :as => as, :member_value => method(:reverse_login)))
507
+ end)
508
+ end
509
+
510
+ it 'should have options with the proc applied to each value' do
511
+ ::Author.all.each do |author|
512
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login.reverse}']")
513
+ end
514
+ end
515
+ end
516
+ end
517
+
518
+ describe 'when the deprecated :label_method option is provided' do
519
+
520
+ describe 'as a symbol' do
521
+ before do
522
+ with_deprecation_silenced do
523
+ concat(semantic_form_for(@new_post) do |builder|
524
+ concat(builder.input(:author, :as => as, :label_method => :login))
525
+ end)
526
+ end
527
+ end
528
+
529
+ it 'should have options with text content from the specified method' do
530
+ ::Author.all.each do |author|
531
+ output_buffer.should have_tag("form li.#{as}", /#{author.login}/)
532
+ end
533
+ end
534
+ end
535
+
536
+ describe 'as a proc' do
537
+
538
+ before do
539
+ with_deprecation_silenced do
540
+ concat(semantic_form_for(@new_post) do |builder|
541
+ concat(builder.input(:author, :as => as, :label_method => Proc.new {|a| a.login.reverse }))
542
+ end)
543
+ end
544
+ end
545
+
546
+ it 'should have options with the proc applied to each' do
547
+ ::Author.all.each do |author|
548
+ output_buffer.should have_tag("form li.#{as}", /#{author.login.reverse}/)
549
+ end
550
+ end
551
+ end
552
+
553
+ describe 'as a method object' do
554
+ before do
555
+ def reverse_login(a)
556
+ a.login.reverse
557
+ end
558
+ with_deprecation_silenced do
559
+ concat(semantic_form_for(@new_post) do |builder|
560
+ concat(builder.input(:author, :as => as, :label_method => method(:reverse_login)))
561
+ end)
562
+ end
563
+ end
564
+
565
+ it 'should have options with the proc applied to each' do
566
+ ::Author.all.each do |author|
567
+ output_buffer.should have_tag("form li.#{as}", /#{author.login.reverse}/)
568
+ end
569
+ end
570
+ end
571
+ end
572
+
573
+ describe 'when the deprecated :label_method option is not provided' do
574
+ Formtastic::FormBuilder.collection_label_methods.each do |label_method|
575
+
576
+ describe "when the collection objects respond to #{label_method}" do
577
+ before do
578
+ @fred.stub!(:respond_to?).and_return { |m| m.to_s == label_method || m.to_s == 'id' }
579
+ ::Author.all.each { |a| a.stub!(label_method).and_return('The Label Text') }
580
+
581
+ with_deprecation_silenced do
582
+ concat(semantic_form_for(@new_post) do |builder|
583
+ concat(builder.input(:author, :as => as))
584
+ end)
585
+ end
586
+ end
587
+
588
+ it "should render the options with #{label_method} as the label" do
589
+ ::Author.all.each do |author|
590
+ output_buffer.should have_tag("form li.#{as}", /The Label Text/)
591
+ end
592
+ end
593
+ end
594
+
595
+ end
596
+ end
597
+
598
+ describe 'when the deprecated :value_method option is provided' do
599
+
600
+ describe 'as a symbol' do
601
+ before do
602
+ with_deprecation_silenced do
603
+ concat(semantic_form_for(@new_post) do |builder|
604
+ concat(builder.input(:author, :as => as, :value_method => :login))
605
+ end)
606
+ end
607
+ end
608
+
609
+ it 'should have options with values from specified method' do
610
+ ::Author.all.each do |author|
611
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login}']")
612
+ end
613
+ end
614
+ end
615
+
616
+ describe 'as a proc' do
617
+ before do
618
+ with_deprecation_silenced do
619
+ concat(semantic_form_for(@new_post) do |builder|
620
+ concat(builder.input(:author, :as => as, :value_method => Proc.new {|a| a.login.reverse }))
621
+ end)
622
+ end
623
+ end
624
+
625
+ it 'should have options with the proc applied to each value' do
626
+ ::Author.all.each do |author|
627
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login.reverse}']")
628
+ end
629
+ end
630
+ end
631
+
632
+ describe 'as a method object' do
633
+ before do
634
+ def reverse_login(a)
635
+ a.login.reverse
636
+ end
637
+ with_deprecation_silenced do
638
+ concat(semantic_form_for(@new_post) do |builder|
639
+ concat(builder.input(:author, :as => as, :value_method => method(:reverse_login)))
640
+ end)
641
+ end
642
+ end
643
+
644
+ it 'should have options with the proc applied to each value' do
645
+ ::Author.all.each do |author|
646
+ output_buffer.should have_tag("form li.#{as} #{countable}[@value='#{author.login.reverse}']")
647
+ end
648
+ end
649
+ end
650
+ end
651
+
652
+ end
653
+ end
654
+
655
+ end
656
+ end