formtastic-bootstrap 1.0.0

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