formtastic-bootstrap 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. data/README.md +11 -2
  2. data/VERSION +1 -1
  3. data/vendor/assets/stylesheets/formtastic-bootstrap.css +4 -0
  4. metadata +51 -154
  5. data/.rspec +0 -1
  6. data/Gemfile +0 -14
  7. data/Gemfile.lock +0 -131
  8. data/Rakefile +0 -49
  9. data/formtastic-bootstrap.gemspec +0 -166
  10. data/lib/action_view/helpers/text_field_date_helper.rb +0 -166
  11. data/lib/formtastic-bootstrap/actions.rb +0 -10
  12. data/lib/formtastic-bootstrap/actions/base.rb +0 -22
  13. data/lib/formtastic-bootstrap/actions/button_action.rb +0 -13
  14. data/lib/formtastic-bootstrap/actions/input_action.rb +0 -13
  15. data/lib/formtastic-bootstrap/actions/link_action.rb +0 -12
  16. data/lib/formtastic-bootstrap/engine.rb +0 -4
  17. data/lib/formtastic-bootstrap/form_builder.rb +0 -40
  18. data/lib/formtastic-bootstrap/helpers.rb +0 -17
  19. data/lib/formtastic-bootstrap/helpers/action_helper.rb +0 -12
  20. data/lib/formtastic-bootstrap/helpers/actions_helper.rb +0 -24
  21. data/lib/formtastic-bootstrap/helpers/fieldset_wrapper.rb +0 -35
  22. data/lib/formtastic-bootstrap/helpers/input_helper.rb +0 -12
  23. data/lib/formtastic-bootstrap/helpers/inputs_helper.rb +0 -34
  24. data/lib/formtastic-bootstrap/inputs.rb +0 -36
  25. data/lib/formtastic-bootstrap/inputs/base.rb +0 -45
  26. data/lib/formtastic-bootstrap/inputs/base/choices.rb +0 -20
  27. data/lib/formtastic-bootstrap/inputs/base/collections.rb +0 -9
  28. data/lib/formtastic-bootstrap/inputs/base/errors.rb +0 -48
  29. data/lib/formtastic-bootstrap/inputs/base/grouped_collections.rb +0 -9
  30. data/lib/formtastic-bootstrap/inputs/base/hints.rb +0 -27
  31. data/lib/formtastic-bootstrap/inputs/base/html.rb +0 -21
  32. data/lib/formtastic-bootstrap/inputs/base/labelling.rb +0 -29
  33. data/lib/formtastic-bootstrap/inputs/base/numeric.rb +0 -9
  34. data/lib/formtastic-bootstrap/inputs/base/stringish.rb +0 -17
  35. data/lib/formtastic-bootstrap/inputs/base/timeish.rb +0 -55
  36. data/lib/formtastic-bootstrap/inputs/base/wrapping.rb +0 -55
  37. data/lib/formtastic-bootstrap/inputs/boolean_input.rb +0 -29
  38. data/lib/formtastic-bootstrap/inputs/check_boxes_input.rb +0 -40
  39. data/lib/formtastic-bootstrap/inputs/date_input.rb +0 -10
  40. data/lib/formtastic-bootstrap/inputs/date_select_input.rb +0 -8
  41. data/lib/formtastic-bootstrap/inputs/datetime_input.rb +0 -10
  42. data/lib/formtastic-bootstrap/inputs/datetime_select_input.rb +0 -8
  43. data/lib/formtastic-bootstrap/inputs/email_input.rb +0 -15
  44. data/lib/formtastic-bootstrap/inputs/file_input.rb +0 -14
  45. data/lib/formtastic-bootstrap/inputs/hidden_input.rb +0 -12
  46. data/lib/formtastic-bootstrap/inputs/number_input.rb +0 -15
  47. data/lib/formtastic-bootstrap/inputs/password_input.rb +0 -15
  48. data/lib/formtastic-bootstrap/inputs/phone_input.rb +0 -15
  49. data/lib/formtastic-bootstrap/inputs/radio_input.rb +0 -46
  50. data/lib/formtastic-bootstrap/inputs/range_input.rb +0 -15
  51. data/lib/formtastic-bootstrap/inputs/search_input.rb +0 -15
  52. data/lib/formtastic-bootstrap/inputs/select_input.rb +0 -16
  53. data/lib/formtastic-bootstrap/inputs/string_input.rb +0 -8
  54. data/lib/formtastic-bootstrap/inputs/text_input.rb +0 -14
  55. data/lib/formtastic-bootstrap/inputs/time_input.rb +0 -10
  56. data/lib/formtastic-bootstrap/inputs/time_select_input.rb +0 -8
  57. data/lib/formtastic-bootstrap/inputs/time_zone_input.rb +0 -14
  58. data/lib/formtastic-bootstrap/inputs/url_input.rb +0 -14
  59. data/spec/actions/button_action_spec.rb +0 -63
  60. data/spec/actions/input_action_spec.rb +0 -59
  61. data/spec/actions/link_action_spec.rb +0 -92
  62. data/spec/builder/semantic_fields_for_spec.rb +0 -130
  63. data/spec/helpers/action_helper_spec.rb +0 -368
  64. data/spec/helpers/actions_helper_spec.rb +0 -147
  65. data/spec/helpers/input_helper_spec.rb +0 -935
  66. data/spec/helpers/inputs_helper_spec.rb +0 -636
  67. data/spec/inputs/boolean_input_spec.rb +0 -226
  68. data/spec/inputs/check_boxes_input_spec.rb +0 -454
  69. data/spec/inputs/date_select_input_spec.rb +0 -164
  70. data/spec/inputs/datetime_select_input_spec.rb +0 -112
  71. data/spec/inputs/deprecated_time_date_datetime_inputs_spec.rb +0 -48
  72. data/spec/inputs/email_input_spec.rb +0 -86
  73. data/spec/inputs/file_input_spec.rb +0 -90
  74. data/spec/inputs/hidden_input_spec.rb +0 -153
  75. data/spec/inputs/number_input_spec.rb +0 -816
  76. data/spec/inputs/password_input_spec.rb +0 -100
  77. data/spec/inputs/phone_input_spec.rb +0 -86
  78. data/spec/inputs/radio_input_spec.rb +0 -267
  79. data/spec/inputs/range_input_spec.rb +0 -506
  80. data/spec/inputs/search_input_spec.rb +0 -85
  81. data/spec/inputs/select_input_spec.rb +0 -624
  82. data/spec/inputs/string_input_spec.rb +0 -210
  83. data/spec/inputs/text_input_spec.rb +0 -188
  84. data/spec/inputs/time_select_input_spec.rb +0 -191
  85. data/spec/inputs/time_zone_input_spec.rb +0 -118
  86. data/spec/inputs/url_input_spec.rb +0 -86
  87. data/spec/spec_helper.rb +0 -30
  88. data/spec/support/custom_macros.rb +0 -537
  89. data/spec/support/fb_custom_macros.rb +0 -23
@@ -1,147 +0,0 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
3
-
4
- describe 'FormtasticBootstrap::FormBuilder#actions' do
5
-
6
- include FormtasticSpecHelper
7
-
8
- before do
9
- @output_buffer = ''
10
- mock_everything
11
- end
12
-
13
- describe 'with a block' do
14
- describe 'when no options are provided' do
15
- before do
16
- concat(semantic_form_for(@new_post) do |builder|
17
- concat(builder.actions do
18
- concat('hello')
19
- end)
20
- end)
21
- end
22
-
23
- it 'should render a fieldset inside the form, with a class of "actions"' do
24
- output_buffer.should have_tag("form fieldset.form-actions")
25
- end
26
-
27
- it 'should not render an ol inside the fieldset' do
28
- output_buffer.should_not have_tag("form fieldset.form-actions ol")
29
- end
30
-
31
- it 'should render the contents of the block inside the fieldset' do
32
- output_buffer.should have_tag("form fieldset.form-actions", /hello/)
33
- end
34
-
35
- it 'should not render a legend inside the fieldset' do
36
- output_buffer.should_not have_tag("form fieldset.form-actions legend")
37
- end
38
- end
39
-
40
- describe 'when a :name option is provided' do
41
- before do
42
- @legend_text = "Advanced options"
43
-
44
- concat(semantic_form_for(@new_post) do |builder|
45
- builder.actions :name => @legend_text do
46
- end
47
- end)
48
- end
49
- it 'should render a fieldset inside the form' do
50
- output_buffer.should have_tag("form fieldset.form-actions legend", /#{@legend_text}/)
51
- end
52
- end
53
-
54
- describe 'when other options are provided' do
55
- before do
56
- @id_option = 'advanced'
57
- @class_option = 'wide'
58
-
59
- concat(semantic_form_for(@new_post) do |builder|
60
- builder.actions :id => @id_option, :class => @class_option do
61
- end
62
- end)
63
- end
64
- it 'should pass the options into the fieldset tag as attributes' do
65
- output_buffer.should have_tag("form fieldset##{@id_option}")
66
- output_buffer.should have_tag("form fieldset.#{@class_option}")
67
- end
68
- end
69
-
70
- end
71
-
72
- describe 'without a block' do
73
-
74
- describe 'with no args (default buttons)' do
75
-
76
- before do
77
- concat(semantic_form_for(@new_post) do |builder|
78
- concat(builder.actions)
79
- end)
80
- end
81
-
82
- it 'should render a form' do
83
- output_buffer.should have_tag('form')
84
- end
85
-
86
- it 'should render an actions fieldset inside the form' do
87
- output_buffer.should have_tag('form fieldset.form-actions')
88
- end
89
-
90
- it 'should not render a legend in the fieldset' do
91
- output_buffer.should_not have_tag('form fieldset.form-actions legend')
92
- end
93
-
94
- it 'should not render an ol in the fieldset' do
95
- output_buffer.should_not have_tag('form fieldset.form-actions ol')
96
- end
97
-
98
- it 'should render a button in the fieldset for each default action' do
99
- output_buffer.should have_tag('form fieldset.form-actions input.btn', :count => 1)
100
- end
101
-
102
- end
103
-
104
- describe 'with button names as args' do
105
-
106
- before do
107
- concat(semantic_form_for(@new_post) do |builder|
108
- concat(builder.actions(:submit, :cancel, :reset))
109
- end)
110
- end
111
-
112
- it 'should not render a form with a fieldset containing a list item for each button arg' do
113
- output_buffer.should_not have_tag('form > fieldset.form-actions > ol > li.action', :count => 3)
114
- end
115
-
116
- it 'should render a form with a fieldset containing each button arg' do
117
- output_buffer.should_not have_tag('form > fieldset.form-actions > input.btn', :count => 3)
118
- end
119
-
120
- end
121
-
122
- describe 'with button names as args and an options hash' do
123
-
124
- before do
125
- concat(semantic_form_for(@new_post) do |builder|
126
- concat(builder.actions(:submit, :cancel, :reset, :name => "Now click a button", :id => "my-id"))
127
- end)
128
- end
129
-
130
- it 'should render a form with a fieldset containing each button arg' do
131
- output_buffer.should have_tag('form > fieldset.form-actions > .btn', :count => 3)
132
- end
133
-
134
- it 'should pass the options down to the fieldset' do
135
- output_buffer.should have_tag('form > fieldset#my-id.form-actions')
136
- end
137
-
138
- it 'should use the special :name option as a text for the legend tag' do
139
- output_buffer.should have_tag('form > fieldset#my-id.form-actions > legend', /Now click a button/)
140
- end
141
-
142
- end
143
-
144
- end
145
-
146
- end
147
-
@@ -1,935 +0,0 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
3
-
4
- describe 'FormtasticBootstrap::FormBuilder#input' do
5
-
6
- include FormtasticSpecHelper
7
-
8
- before do
9
- @output_buffer = ''
10
- mock_everything
11
-
12
- @errors = mock('errors')
13
- @errors.stub!(:[]).and_return([])
14
- @new_post.stub!(:errors).and_return(@errors)
15
- end
16
-
17
- after do
18
- ::I18n.backend.reload!
19
- end
20
-
21
- describe 'arguments and options' do
22
-
23
- it 'should require the first argument (the method on form\'s object)' do
24
- lambda {
25
- concat(semantic_form_for(@new_post) do |builder|
26
- concat(builder.input()) # no args passed in at all
27
- end)
28
- }.should raise_error(ArgumentError)
29
- end
30
-
31
- describe ':required option' do
32
-
33
- describe 'when true' do
34
-
35
- it 'should set a "required" class' do
36
- with_config :required_string, " required yo!" do
37
- concat(semantic_form_for(@new_post) do |builder|
38
- concat(builder.input(:title, :required => true))
39
- end)
40
- output_buffer.should_not have_tag('form div.optional')
41
- output_buffer.should have_tag('form div.required')
42
- end
43
- end
44
-
45
- it 'should append the "required" string to the label' do
46
- with_config :required_string, " required yo!" do
47
- concat(semantic_form_for(@new_post) do |builder|
48
- concat(builder.input(:title, :required => true))
49
- end)
50
- output_buffer.should have_tag('form div.required label', /required yo/)
51
- end
52
- end
53
- end
54
-
55
- describe 'when false' do
56
-
57
- before do
58
- @string = Formtastic::FormBuilder.optional_string = " optional yo!" # ensure there's something in the string
59
- @new_post.class.should_not_receive(:reflect_on_all_validations)
60
- end
61
-
62
- after do
63
- Formtastic::FormBuilder.optional_string = ''
64
- end
65
-
66
- it 'should set an "optional" class' do
67
- concat(semantic_form_for(@new_post) do |builder|
68
- concat(builder.input(:title, :required => false))
69
- end)
70
- output_buffer.should_not have_tag('form div.required')
71
- output_buffer.should have_tag('form div.optional')
72
- end
73
-
74
- it 'should set and "optional" class also when there is presence validator' do
75
- @new_post.class.should_receive(:validators_on).with(:title).any_number_of_times.and_return([
76
- active_model_presence_validator([:title])
77
- ])
78
- concat(semantic_form_for(@new_post) do |builder|
79
- concat(builder.input(:title, :required => false))
80
- end)
81
- output_buffer.should_not have_tag('form div.required')
82
- output_buffer.should have_tag('form div.optional')
83
- end
84
-
85
- it 'should append the "optional" string to the label' do
86
- concat(semantic_form_for(@new_post) do |builder|
87
- concat(builder.input(:title, :required => false))
88
- end)
89
- output_buffer.should have_tag('form div.optional label', /#{@string}$/)
90
- end
91
-
92
- end
93
-
94
- describe 'when not provided' do
95
-
96
- describe 'and an object was not given' do
97
-
98
- it 'should use the default value' do
99
- Formtastic::FormBuilder.all_fields_required_by_default.should == true
100
- Formtastic::FormBuilder.all_fields_required_by_default = false
101
-
102
- concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
103
- concat(builder.input(:title))
104
- end)
105
- output_buffer.should_not have_tag('form div.required')
106
- output_buffer.should have_tag('form div.optional')
107
-
108
- Formtastic::FormBuilder.all_fields_required_by_default = true
109
- end
110
-
111
- end
112
-
113
- describe 'and an object with :validators_on was given (ActiveModel, Active Resource)' do
114
- before do
115
- @new_post.stub!(:class).and_return(::PostModel)
116
- end
117
-
118
- after do
119
- @new_post.stub!(:class).and_return(::Post)
120
- end
121
- describe 'and validates_presence_of was called for the method' do
122
- it 'should be required' do
123
-
124
- @new_post.class.should_receive(:validators_on).with(:title).any_number_of_times.and_return([
125
- active_model_presence_validator([:title])
126
- ])
127
-
128
- @new_post.class.should_receive(:validators_on).with(:body).any_number_of_times.and_return([
129
- active_model_presence_validator([:body], {:if => true})
130
- ])
131
-
132
- concat(semantic_form_for(@new_post) do |builder|
133
- concat(builder.input(:title))
134
- concat(builder.input(:body))
135
- end)
136
- output_buffer.should have_tag('form div.required')
137
- output_buffer.should_not have_tag('form div.optional')
138
- end
139
-
140
- it 'should be required when there is :on => :create option on create' do
141
- with_config :required_string, " required yo!" do
142
- @new_post.class.should_receive(:validators_on).with(:title).any_number_of_times.and_return([
143
- active_model_presence_validator([:title], {:on => :create})
144
- ])
145
- concat(semantic_form_for(@new_post) do |builder|
146
- concat(builder.input(:title))
147
- end)
148
- output_buffer.should have_tag('form div.required')
149
- output_buffer.should_not have_tag('form div.optional')
150
- end
151
- end
152
-
153
- it 'should be required when there is :on => :save option on create' do
154
- with_config :required_string, " required yo!" do
155
- @new_post.class.should_receive(:validators_on).with(:title).any_number_of_times.and_return([
156
- active_model_presence_validator([:title], {:on => :save})
157
- ])
158
- concat(semantic_form_for(@new_post) do |builder|
159
- concat(builder.input(:title))
160
- end)
161
- output_buffer.should have_tag('form div.required')
162
- output_buffer.should_not have_tag('form div.optional')
163
- end
164
- end
165
-
166
- it 'should be required when there is :on => :save option on update' do
167
- with_config :required_string, " required yo!" do
168
- @fred.class.should_receive(:validators_on).with(:login).any_number_of_times.and_return([
169
- active_model_presence_validator([:login], {:on => :save})
170
- ])
171
- concat(semantic_form_for(@fred) do |builder|
172
- concat(builder.input(:login))
173
- end)
174
- output_buffer.should have_tag('form div.required')
175
- output_buffer.should_not have_tag('form div.optional')
176
- end
177
- end
178
-
179
- it 'should not be required when there is :on => :create option on update' do
180
- @fred.class.should_receive(:validators_on).with(:login).any_number_of_times.and_return([
181
- active_model_presence_validator([:login], {:on => :create})
182
- ])
183
- concat(semantic_form_for(@fred) do |builder|
184
- concat(builder.input(:login))
185
- end)
186
- output_buffer.should_not have_tag('form div.required')
187
- output_buffer.should have_tag('form div.optional')
188
- end
189
-
190
- it 'should not be required when there is :on => :update option on create' do
191
- @new_post.class.should_receive(:validators_on).with(:title).any_number_of_times.and_return([
192
- active_model_presence_validator([:title], {:on => :update})
193
- ])
194
- concat(semantic_form_for(@new_post) do |builder|
195
- concat(builder.input(:title))
196
- end)
197
- output_buffer.should_not have_tag('form div.required')
198
- output_buffer.should have_tag('form div.optional')
199
- end
200
-
201
- it 'should be not be required if the optional :if condition is not satisifed' do
202
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => false })
203
- end
204
-
205
- it 'should not be required if the optional :if proc evaluates to false' do
206
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => proc { |record| false } })
207
- end
208
-
209
- it 'should be required if the optional :if proc evaluates to true' do
210
- presence_should_be_required(:required => true, :tag => :body, :options => { :if => proc { |record| true } })
211
- end
212
-
213
- it 'should not be required if the optional :unless proc evaluates to true' do
214
- presence_should_be_required(:required => false, :tag => :body, :options => { :unless => proc { |record| true } })
215
- end
216
-
217
- it 'should be required if the optional :unless proc evaluates to false' do
218
- presence_should_be_required(:required => true, :tag => :body, :options => { :unless => proc { |record| false } })
219
- end
220
-
221
- it 'should be required if the optional :if with a method string evaluates to true' do
222
- @new_post.should_receive(:required_condition).and_return(true)
223
- presence_should_be_required(:required => true, :tag => :body, :options => { :if => :required_condition })
224
- end
225
-
226
- it 'should be required if the optional :if with a method string evaluates to false' do
227
- @new_post.should_receive(:required_condition).and_return(false)
228
- presence_should_be_required(:required => false, :tag => :body, :options => { :if => :required_condition })
229
- end
230
-
231
- it 'should be required if the optional :unless with a method string evaluates to false' do
232
- @new_post.should_receive(:required_condition).and_return(false)
233
- presence_should_be_required(:required => true, :tag => :body, :options => { :unless => :required_condition })
234
- end
235
-
236
- it 'should not be required if the optional :unless with a method string evaluates to true' do
237
- @new_post.should_receive(:required_condition).and_return(true)
238
- presence_should_be_required(:required => false, :tag => :body, :options => { :unless => :required_condition })
239
- end
240
- end
241
-
242
- describe 'and validates_inclusion_of was called for the method' do
243
- it 'should be required' do
244
- @new_post.class.should_receive(:validators_on).with(:published).any_number_of_times.and_return([
245
- active_model_inclusion_validator([:published], {:in => [false, true]})
246
- ])
247
- should_be_required(:tag => :published, :required => true)
248
- end
249
-
250
- it 'should not be required if allow_blank is true' do
251
- @new_post.class.should_receive(:validators_on).with(:published).any_number_of_times.and_return([
252
- active_model_inclusion_validator([:published], {:in => [false, true], :allow_blank => true})
253
- ])
254
- should_be_required(:tag => :published, :required => false)
255
- end
256
- end
257
-
258
- describe 'and validates_length_of was called for the method' do
259
- it 'should be required if minimum is set' do
260
- length_should_be_required(:tag => :title, :required => true, :options => {:minimum => 1})
261
- end
262
-
263
- it 'should be required if :within is set' do
264
- length_should_be_required(:tag => :title, :required => true, :options => {:within => 1..5})
265
- end
266
-
267
- it 'should not be required if :within allows zero length' do
268
- length_should_be_required(:tag => :title, :required => false, :options => {:within => 0..5})
269
- end
270
-
271
- it 'should not be required if only :minimum is zero' do
272
- length_should_be_required(:tag => :title, :required => false, :options => {:minimum => 0})
273
- end
274
-
275
- it 'should not be required if only :minimum is not set' do
276
- length_should_be_required(:tag => :title, :required => false, :options => {:maximum => 5})
277
- end
278
-
279
- it 'should not be required if allow_blank is true' do
280
- length_should_be_required(:tag => :published, :required => false, :options => {:allow_blank => true})
281
- end
282
- end
283
-
284
- def add_presence_validator(options)
285
- @new_post.class.stub!(:validators_on).with(options[:tag]).and_return([
286
- active_model_presence_validator([options[:tag]], options[:options])
287
- ])
288
- end
289
-
290
- def add_length_validator(options)
291
- @new_post.class.should_receive(:validators_on).with(options[:tag]).any_number_of_times {[
292
- active_model_length_validator([options[:tag]], options[:options])
293
- ]}
294
- end
295
-
296
- # TODO make a matcher for this?
297
- def should_be_required(options)
298
- concat(semantic_form_for(@new_post) do |builder|
299
- concat(builder.input(options[:tag]))
300
- end)
301
-
302
- if options[:required]
303
- output_buffer.should_not have_tag('form div.optional')
304
- output_buffer.should have_tag('form div.required')
305
- else
306
- output_buffer.should have_tag('form div.optional')
307
- output_buffer.should_not have_tag('form div.required')
308
- end
309
- end
310
-
311
- def presence_should_be_required(options)
312
- add_presence_validator(options)
313
- should_be_required(options)
314
- end
315
-
316
- def length_should_be_required(options)
317
- add_length_validator(options)
318
- should_be_required(options)
319
- end
320
-
321
- # TODO JF reversed this during refactor, need to make sure
322
- describe 'and there are no requirement validations on the method' do
323
- before do
324
- @new_post.class.should_receive(:validators_on).with(:title).and_return([])
325
- end
326
-
327
- it 'should not be required' do
328
- concat(semantic_form_for(@new_post) do |builder|
329
- concat(builder.input(:title))
330
- end)
331
- output_buffer.should_not have_tag('form div.required')
332
- output_buffer.should have_tag('form div.optional')
333
- end
334
- end
335
-
336
- end
337
-
338
- describe 'and an object without :validators_on' do
339
-
340
- it 'should use the default value' do
341
- Formtastic::FormBuilder.all_fields_required_by_default.should == true
342
- Formtastic::FormBuilder.all_fields_required_by_default = false
343
-
344
- concat(semantic_form_for(@new_post) do |builder|
345
- concat(builder.input(:title))
346
- end)
347
- output_buffer.should_not have_tag('form div.required')
348
- output_buffer.should have_tag('form div.optional')
349
-
350
- Formtastic::FormBuilder.all_fields_required_by_default = true
351
- end
352
-
353
- end
354
-
355
- end
356
-
357
- end
358
-
359
- describe ':as option' do
360
-
361
- describe 'when not provided' do
362
-
363
- it 'should default to a string for forms without objects unless column is password' do
364
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
365
- concat(builder.input(:anything))
366
- end)
367
- output_buffer.should have_tag('form div.string')
368
- end
369
-
370
- it 'should default to password for forms without objects if column is password' do
371
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
372
- concat(builder.input(:password))
373
- concat(builder.input(:password_confirmation))
374
- concat(builder.input(:confirm_password))
375
- end)
376
- output_buffer.should have_tag('form div.password', :count => 3)
377
- end
378
-
379
- it 'should default to a string for methods on objects that don\'t respond to "column_for_attribute"' do
380
- @new_post.stub!(:method_without_a_database_column)
381
- @new_post.stub!(:column_for_attribute).and_return(nil)
382
- default_input_type(nil, :method_without_a_database_column).should == :string
383
- end
384
-
385
- it 'should default to :password for methods that don\'t have a column in the database but "password" is in the method name' do
386
- @new_post.stub!(:password_method_without_a_database_column)
387
- @new_post.stub!(:column_for_attribute).and_return(nil)
388
- default_input_type(nil, :password_method_without_a_database_column).should == :password
389
- end
390
-
391
- it 'should default to :password for methods on objects that don\'t respond to "column_for_attribute" but "password" is in the method name' do
392
- @new_post.stub!(:password_method_without_a_database_column)
393
- @new_post.stub!(:column_for_attribute).and_return(nil)
394
- default_input_type(nil, :password_method_without_a_database_column).should == :password
395
- end
396
-
397
- it 'should default to :number for "integer" column with name ending in "_id"' do
398
- @new_post.stub!(:aws_instance_id)
399
- @new_post.stub!(:column_for_attribute).with(:aws_instance_id).and_return(mock('column', :type => :integer))
400
- default_input_type(:integer, :aws_instance_id).should == :number
401
- end
402
-
403
- it 'should default to :select for associations' do
404
- @new_post.class.stub!(:reflect_on_association).with(:user_id).and_return(mock('ActiveRecord::Reflection::AssociationReflection'))
405
- @new_post.class.stub!(:reflect_on_association).with(:section_id).and_return(mock('ActiveRecord::Reflection::AssociationReflection'))
406
- default_input_type(:integer, :user_id).should == :select
407
- default_input_type(:integer, :section_id).should == :select
408
- end
409
-
410
- it 'should default to :password for :string column types with "password" in the method name' do
411
- default_input_type(:string, :password).should == :password
412
- default_input_type(:string, :hashed_password).should == :password
413
- default_input_type(:string, :password_hash).should == :password
414
- end
415
-
416
- it 'should default to :text for :text column types' do
417
- default_input_type(:text).should == :text
418
- end
419
-
420
- it 'should default to :date_select for :date column types' do
421
- default_input_type(:date).should == :date_select
422
- end
423
-
424
- it 'should default to :datetime_select for :datetime and :timestamp column types' do
425
- default_input_type(:datetime).should == :datetime_select
426
- default_input_type(:timestamp).should == :datetime_select
427
- end
428
-
429
- it 'should default to :time_select for :time column types' do
430
- default_input_type(:time).should == :time_select
431
- end
432
-
433
- it 'should default to :boolean for :boolean column types' do
434
- default_input_type(:boolean).should == :boolean
435
- end
436
-
437
- it 'should default to :string for :string column types' do
438
- default_input_type(:string).should == :string
439
- end
440
-
441
- it 'should default to :number for :integer, :float and :decimal column types' do
442
- default_input_type(:integer).should == :number
443
- default_input_type(:float).should == :number
444
- default_input_type(:decimal).should == :number
445
- end
446
-
447
- it 'should default to :country for :string columns named country' do
448
- default_input_type(:string, :country).should == :country
449
- end
450
-
451
- it 'should default to :email for :string columns matching email' do
452
- default_input_type(:string, :email).should == :email
453
- default_input_type(:string, :customer_email).should == :email
454
- default_input_type(:string, :email_work).should == :email
455
- end
456
-
457
- it 'should default to :url for :string columns named url or website' do
458
- default_input_type(:string, :url).should == :url
459
- default_input_type(:string, :website).should == :url
460
- default_input_type(:string, :my_url).should == :url
461
- default_input_type(:string, :hurl).should_not == :url
462
- end
463
-
464
- it 'should default to :phone for :string columns named phone or fax' do
465
- default_input_type(:string, :phone).should == :phone
466
- default_input_type(:string, :fax).should == :phone
467
- end
468
-
469
- it 'should default to :search for :string columns named search' do
470
- default_input_type(:string, :search).should == :search
471
- end
472
-
473
- describe 'defaulting to file column' do
474
- Formtastic::FormBuilder.file_methods.each do |method|
475
- it "should default to :file for attributes that respond to ##{method}" do
476
- column = mock('column')
477
-
478
- Formtastic::FormBuilder.file_methods.each do |test|
479
- ### TODO: Check if this is ok
480
- column.stub!(method).with(test).and_return(method == test)
481
- end
482
-
483
- @new_post.should_receive(method).and_return(column)
484
-
485
- semantic_form_for(@new_post) do |builder|
486
- builder.send(:default_input_type, method).should == :file
487
- end
488
- end
489
- end
490
-
491
- end
492
- end
493
-
494
- it 'should call the corresponding input class with .to_html' do
495
- [:select, :time_zone, :radio, :date_select, :datetime_select, :time_select, :boolean, :check_boxes, :hidden, :string, :password, :number, :text, :file].each do |input_style|
496
- @new_post.stub!(:generic_column_name)
497
- @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
498
- semantic_form_for(@new_post) do |builder|
499
- input_instance = mock('Input instance')
500
- input_class = "#{input_style.to_s}_input".classify
501
- input_constant = "FormtasticBootstrap::Inputs::#{input_class}".constantize
502
-
503
- input_constant.should_receive(:new).and_return(input_instance)
504
- input_instance.should_receive(:to_html).and_return("some HTML")
505
-
506
- concat(builder.input(:generic_column_name, :as => input_style))
507
- end
508
- end
509
- end
510
-
511
- end
512
-
513
- describe ':label option' do
514
-
515
- describe 'when provided' do
516
- it 'should be passed down to the label tag' do
517
- concat(semantic_form_for(@new_post) do |builder|
518
- concat(builder.input(:title, :label => "Kustom"))
519
- end)
520
- output_buffer.should have_tag("form div label", /Kustom/)
521
- end
522
-
523
- it 'should not generate a label if false' do
524
- concat(semantic_form_for(@new_post) do |builder|
525
- concat(builder.input(:title, :label => false))
526
- end)
527
- output_buffer.should_not have_tag("form div label")
528
- end
529
-
530
- it 'should be dupped if frozen' do
531
- concat(semantic_form_for(@new_post) do |builder|
532
- concat(builder.input(:title, :label => "Kustom".freeze))
533
- end)
534
- output_buffer.should have_tag("form div label", /Kustom/)
535
- end
536
- end
537
-
538
- describe 'when not provided' do
539
- describe 'when localized label is provided' do
540
- describe 'and object is given' do
541
- describe 'and label_str_method not :humanize' do
542
- it 'should render a label with localized text and not apply the label_str_method' do
543
- with_config :label_str_method, :reverse do
544
- @localized_label_text = 'Localized title'
545
- @new_post.stub!(:meta_description)
546
- ::I18n.backend.store_translations :en,
547
- :formtastic => {
548
- :labels => {
549
- :meta_description => @localized_label_text
550
- }
551
- }
552
-
553
- concat(semantic_form_for(@new_post) do |builder|
554
- concat(builder.input(:meta_description))
555
- end)
556
- output_buffer.should have_tag('form div label', /Localized title/)
557
- end
558
- end
559
- end
560
- end
561
- end
562
-
563
- describe 'when localized label is NOT provided' do
564
- describe 'and object is not given' do
565
- it 'should default the humanized method name, passing it down to the label tag' do
566
- ::I18n.backend.store_translations :en, :formtastic => {}
567
- with_config :label_str_method, :humanize do
568
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
569
- concat(builder.input(:meta_description))
570
- end)
571
- output_buffer.should have_tag("form div label", /#{'meta_description'.humanize}/)
572
- end
573
- end
574
- end
575
-
576
- describe 'and object is given' do
577
- it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
578
- @new_post.stub!(:meta_description) # a two word method name
579
- @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
580
-
581
- concat(semantic_form_for(@new_post) do |builder|
582
- concat(builder.input(:meta_description))
583
- end)
584
- output_buffer.should have_tag("form div label", /#{'meta_description'.humanize}/)
585
- end
586
- end
587
-
588
- describe 'and object is given with label_str_method set to :capitalize' do
589
- it 'should capitalize method name, passing it down to the label tag' do
590
- with_config :label_str_method, :capitalize do
591
- @new_post.stub!(:meta_description)
592
-
593
- concat(semantic_form_for(@new_post) do |builder|
594
- concat(builder.input(:meta_description))
595
- end)
596
- output_buffer.should have_tag("form div label", /#{'meta_description'.capitalize}/)
597
- end
598
- end
599
- end
600
- end
601
-
602
- describe 'when localized label is provided' do
603
- before do
604
- @localized_label_text = 'Localized title'
605
- @default_localized_label_text = 'Default localized title'
606
- ::I18n.backend.store_translations :en,
607
- :formtastic => {
608
- :labels => {
609
- :title => @default_localized_label_text,
610
- :published => @default_localized_label_text,
611
- :post => {
612
- :title => @localized_label_text,
613
- :published => @default_localized_label_text
614
- }
615
- }
616
- }
617
- end
618
-
619
- it 'should render a label with localized label (I18n)' do
620
- with_config :i18n_lookups_by_default, false do
621
- concat(semantic_form_for(@new_post) do |builder|
622
- concat(builder.input(:title, :label => true))
623
- concat(builder.input(:published, :as => :boolean, :label => true))
624
- end)
625
- output_buffer.should have_tag('form div label', Regexp.new('^' + @localized_label_text))
626
- end
627
- end
628
-
629
- it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
630
- with_config :i18n_lookups_by_default, false do
631
- ::I18n.backend.store_translations :en,
632
- :formtastic => {
633
- :labels => {
634
- :post => {
635
- :title => nil,
636
- :published => nil
637
- }
638
- }
639
- }
640
- concat(semantic_form_for(@new_post) do |builder|
641
- concat(builder.input(:title, :label => true))
642
- concat(builder.input(:published, :as => :boolean, :label => true))
643
- end)
644
- output_buffer.should have_tag('form div label', Regexp.new('^' + @default_localized_label_text))
645
- end
646
- end
647
- end
648
- end
649
-
650
- end
651
-
652
- describe ':hint option' do
653
-
654
- describe 'when provided' do
655
-
656
- after do
657
- Formtastic::FormBuilder.default_hint_class = "inline-hints"
658
- end
659
-
660
- it 'should be passed down to the paragraph tag' do
661
- hint_text = "this is the title of the post"
662
- concat(semantic_form_for(@new_post) do |builder|
663
- concat(builder.input(:title, :hint => hint_text))
664
- end)
665
- output_buffer.should have_tag("form div p.inline-hints", hint_text)
666
- end
667
-
668
- it 'should have a custom hint class if I ask for one' do
669
- with_deprecation_silenced do
670
- hint_text = "this is the title of the post"
671
- concat(semantic_form_for(@new_post) do |builder|
672
- concat(builder.input(:title, :hint => hint_text, :hint_class => 'custom-hint-class'))
673
- end)
674
- output_buffer.should have_tag("form div p.custom-hint-class", hint_text)
675
- end
676
- end
677
-
678
- it 'should have a custom hint class defaulted for all forms' do
679
- hint_text = "this is the title of the post"
680
- Formtastic::FormBuilder.default_hint_class = "custom-hint-class"
681
- concat(semantic_form_for(@new_post) do |builder|
682
- concat(builder.input(:title, :hint => hint_text))
683
- end)
684
- output_buffer.should have_tag("form div p.custom-hint-class", hint_text)
685
- end
686
- end
687
-
688
- describe 'when not provided' do
689
- describe 'when localized hint (I18n) is provided' do
690
- before do
691
- @localized_hint_text = "This is the localized hint."
692
- @default_localized_hint_text = "This is the default localized hint."
693
- ::I18n.backend.store_translations :en,
694
- :formtastic => {
695
- :hints => {
696
- :title => @default_localized_hint_text,
697
- }
698
- }
699
- end
700
-
701
- after do
702
- ::I18n.backend.reload!
703
- end
704
-
705
- describe 'when provided value (hint value) is set to TRUE' do
706
- it 'should render a hint paragraph containing a localized hint (I18n)' do
707
- with_config :i18n_lookups_by_default, false do
708
- ::I18n.backend.store_translations :en,
709
- :formtastic => {
710
- :hints => {
711
- :post => {
712
- :title => @localized_hint_text
713
- }
714
- }
715
- }
716
- concat(semantic_form_for(@new_post) do |builder|
717
- concat(builder.input(:title, :hint => true))
718
- end)
719
- output_buffer.should have_tag('form div p.inline-hints', @localized_hint_text)
720
- end
721
- end
722
-
723
- it 'should render a hint paragraph containing a localized hint (I18n) with a custom hint class if i ask for one' do
724
- with_config :i18n_lookups_by_default, false do
725
- ::I18n.backend.store_translations :en,
726
- :formtastic => {
727
- :hints => {
728
- :post => {
729
- :title => @localized_hint_text
730
- }
731
- }
732
- }
733
- with_deprecation_silenced do
734
- concat(semantic_form_for(@new_post) do |builder|
735
- concat(builder.input(:title, :hint => true, :hint_class => 'custom-hint-class'))
736
- end)
737
- end
738
- output_buffer.should have_tag('form div p.custom-hint-class', @localized_hint_text)
739
- end
740
- end
741
-
742
- it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
743
- with_config :i18n_lookups_by_default, false do
744
- concat(semantic_form_for(@new_post) do |builder|
745
- concat(builder.input(:title, :hint => true))
746
- end)
747
- output_buffer.should have_tag('form div p.inline-hints', @default_localized_hint_text)
748
- end
749
- end
750
- end
751
-
752
- describe 'when provided value (label value) is set to FALSE' do
753
- it 'should not render a hint paragraph' do
754
- with_config :i18n_lookups_by_default, false do
755
- concat(semantic_form_for(@new_post) do |builder|
756
- concat(builder.input(:title, :hint => false))
757
- end)
758
- output_buffer.should_not have_tag('form div p.inline-hints', @localized_hint_text)
759
- end
760
- end
761
- end
762
- end
763
-
764
- describe 'when localized hint (I18n) is a model with attribute hints' do
765
- it "should see the provided hash as a blank entry" do
766
- with_config :i18n_lookups_by_default, false do
767
- ::I18n.backend.store_translations :en,
768
- :formtastic => {
769
- :hints => {
770
- :title => { # movie title
771
- :summary => @localized_hint_text # summary of movie
772
- }
773
- }
774
- }
775
- semantic_form_for(@new_post) do |builder|
776
- concat(builder.input(:title, :hint => true))
777
- end
778
- output_buffer.should_not have_tag('form div p.inline-hints', @localized_hint_text)
779
- end
780
- end
781
- end
782
-
783
- describe 'when localized hint (I18n) is not provided' do
784
- it 'should not render a hint paragraph' do
785
- with_config :i18n_lookups_by_default, false do
786
- concat(semantic_form_for(@new_post) do |builder|
787
- concat(builder.input(:title))
788
- end)
789
- output_buffer.should_not have_tag('form div p.inline-hints')
790
- end
791
- end
792
- end
793
- end
794
-
795
- end
796
-
797
- describe ':wrapper_html option' do
798
-
799
- describe 'when provided' do
800
- it 'should be passed down to the div tag' do
801
- concat(semantic_form_for(@new_post) do |builder|
802
- concat(builder.input(:title, :wrapper_html => {:id => :another_id}))
803
- end)
804
- output_buffer.should have_tag("form div#another_id")
805
- end
806
-
807
- it 'should append given classes to div default classes' do
808
- concat(semantic_form_for(@new_post) do |builder|
809
- concat(builder.input(:title, :wrapper_html => {:class => :another_class}, :required => true))
810
- end)
811
- output_buffer.should have_tag("form div.string")
812
- output_buffer.should have_tag("form div.required")
813
- output_buffer.should have_tag("form div.another_class")
814
- end
815
-
816
- it 'should allow classes to be an array' do
817
- concat(semantic_form_for(@new_post) do |builder|
818
- concat(builder.input(:title, :wrapper_html => {:class => [ :my_class, :another_class ]}))
819
- end)
820
- output_buffer.should have_tag("form div.string")
821
- output_buffer.should have_tag("form div.my_class")
822
- output_buffer.should have_tag("form div.another_class")
823
- end
824
- end
825
-
826
- describe 'when not provided' do
827
- it 'should use default id and class' do
828
- concat(semantic_form_for(@new_post) do |builder|
829
- concat(builder.input(:title))
830
- end)
831
- output_buffer.should have_tag("form div#post_title_input")
832
- output_buffer.should have_tag("form div.string")
833
- end
834
- end
835
-
836
- end
837
-
838
- describe ':collection option' do
839
-
840
- it "should be required on polymorphic associations" do
841
- @new_post.stub!(:commentable)
842
- @new_post.class.stub!(:reflections).and_return({
843
- :commentable => mock('macro_reflection', :options => { :polymorphic => true }, :macro => :belongs_to)
844
- })
845
- @new_post.stub!(:column_for_attribute).with(:commentable).and_return(
846
- mock('column', :type => :integer)
847
- )
848
- @new_post.class.stub!(:reflect_on_association).with(:commentable).and_return(
849
- mock('reflection', :macro => :belongs_to, :options => { :polymorphic => true })
850
- )
851
- expect {
852
- concat(semantic_form_for(@new_post) do |builder|
853
- concat(builder.inputs do
854
- concat(builder.input :commentable)
855
- end)
856
- end)
857
- }.to raise_error(Formtastic::PolymorphicInputWithoutCollectionError)
858
- end
859
-
860
- end
861
-
862
- end
863
-
864
- describe 'options re-use' do
865
-
866
- it 'should retain :as option when re-using the same options hash' do
867
- my_options = { :as => :string }
868
- output = ''
869
-
870
- concat(semantic_form_for(@new_post) do |builder|
871
- concat(builder.input(:title, my_options))
872
- concat(builder.input(:publish_at, my_options))
873
- end)
874
- output_buffer.should have_tag 'div.string', :count => 2
875
- end
876
-
877
-
878
- end
879
-
880
- describe 'instantiating an input class' do
881
-
882
- context 'when a class does not exist' do
883
- it "should raise an error" do
884
- lambda {
885
- concat(semantic_form_for(@new_post) do |builder|
886
- builder.input(:title, :as => :non_existant)
887
- end)
888
- }.should raise_error(Formtastic::UnknownInputError)
889
- end
890
- end
891
-
892
- context 'when a customized top-level class does not exist' do
893
-
894
- it 'should instantiate the Formtastic input' do
895
- input = mock('input', :to_html => 'some HTML')
896
- Formtastic::Inputs::StringInput.should_receive(:new).and_return(input)
897
- concat(semantic_form_for(@new_post) do |builder|
898
- builder.input(:title, :as => :string)
899
- end)
900
- end
901
-
902
- end
903
-
904
- describe 'when a top-level input class exists' do
905
- it "should instantiate the top-level input instead of the Formtastic one" do
906
- class ::StringInput < Formtastic::Inputs::StringInput
907
- end
908
-
909
- input = mock('input', :to_html => 'some HTML')
910
- Formtastic::Inputs::StringInput.should_not_receive(:new).and_return(input)
911
- ::StringInput.should_receive(:new).and_return(input)
912
-
913
- concat(semantic_form_for(@new_post) do |builder|
914
- builder.input(:title, :as => :string)
915
- end)
916
- end
917
- end
918
-
919
- describe 'when instantiated multiple times with the same input type' do
920
-
921
- it "should be cached (not calling the internal methods)" do
922
- # TODO this is really tied to the underlying implementation
923
- concat(semantic_form_for(@new_post) do |builder|
924
- builder.should_receive(:custom_input_class_name).with(:string).once.and_return(::Formtastic::Inputs::StringInput)
925
- builder.input(:title, :as => :string)
926
- builder.input(:title, :as => :string)
927
- end)
928
- end
929
-
930
- end
931
-
932
- end
933
-
934
- end
935
-