formtastic 3.0.0 → 3.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.travis.yml +1 -0
  2. data/Appraisals +4 -0
  3. data/CHANGELOG +12 -22
  4. data/DEPRECATIONS +47 -0
  5. data/README.textile +9 -4
  6. data/formtastic.gemspec +3 -3
  7. data/gemfiles/rails_4.2.gemfile +7 -0
  8. data/lib/formtastic.rb +13 -7
  9. data/lib/formtastic/action_class_finder.rb +18 -0
  10. data/lib/formtastic/deprecation.rb +42 -0
  11. data/lib/formtastic/form_builder.rb +12 -6
  12. data/lib/formtastic/helpers/action_helper.rb +43 -6
  13. data/lib/formtastic/helpers/form_helper.rb +2 -2
  14. data/lib/formtastic/helpers/input_helper.rb +71 -31
  15. data/lib/formtastic/html_attributes.rb +12 -1
  16. data/lib/formtastic/input_class_finder.rb +18 -0
  17. data/lib/formtastic/inputs.rb +1 -0
  18. data/lib/formtastic/inputs/base.rb +11 -12
  19. data/lib/formtastic/inputs/base/choices.rb +1 -1
  20. data/lib/formtastic/inputs/base/collections.rb +1 -1
  21. data/lib/formtastic/inputs/base/html.rb +3 -3
  22. data/lib/formtastic/inputs/datalist_input.rb +41 -0
  23. data/lib/formtastic/inputs/file_input.rb +2 -2
  24. data/lib/formtastic/namespaced_class_finder.rb +89 -0
  25. data/lib/formtastic/util.rb +1 -1
  26. data/lib/formtastic/version.rb +1 -1
  27. data/lib/generators/templates/formtastic.rb +20 -0
  28. data/spec/action_class_finder_spec.rb +12 -0
  29. data/spec/builder/custom_builder_spec.rb +2 -2
  30. data/spec/builder/semantic_fields_for_spec.rb +4 -4
  31. data/spec/helpers/action_helper_spec.rb +9 -355
  32. data/spec/helpers/form_helper_spec.rb +11 -1
  33. data/spec/helpers/input_helper_spec.rb +1 -916
  34. data/spec/helpers/namespaced_action_helper_spec.rb +43 -0
  35. data/spec/helpers/namespaced_input_helper_spec.rb +36 -0
  36. data/spec/input_class_finder_spec.rb +10 -0
  37. data/spec/inputs/check_boxes_input_spec.rb +2 -2
  38. data/spec/inputs/datalist_input_spec.rb +61 -0
  39. data/spec/inputs/select_input_spec.rb +1 -1
  40. data/spec/localizer_spec.rb +2 -2
  41. data/spec/namespaced_class_finder_spec.rb +79 -0
  42. data/spec/spec_helper.rb +17 -7
  43. data/spec/support/custom_macros.rb +22 -4
  44. data/spec/support/shared_examples.rb +1244 -0
  45. data/spec/support/specialized_class_finder_shared_example.rb +27 -0
  46. data/spec/support/test_environment.rb +1 -1
  47. data/spec/util_spec.rb +20 -6
  48. metadata +66 -15
  49. checksums.yaml +0 -15
@@ -42,7 +42,7 @@ module Formtastic
42
42
  end
43
43
 
44
44
  def deprecated_version_of_rails?
45
- rails_version < Gem::Version.new("4.0.4")
45
+ rails_version < Gem::Version.new("4.1.0")
46
46
  end
47
47
 
48
48
  def rails_version
@@ -1,3 +1,3 @@
1
1
  module Formtastic
2
- VERSION = "3.0.0"
2
+ VERSION = "3.1.0.rc1"
3
3
  end
@@ -88,3 +88,23 @@
88
88
  # this to true. Doing so will add a `novalidate` attribute to the `<form>` tag.
89
89
  # See http://diveintohtml5.org/forms.html#validation for more info.
90
90
  # Formtastic::FormBuilder.perform_browser_validations = true
91
+
92
+ # By creating custom input class finder, you can change how input classes are looked up.
93
+ # For example you can make it to search for TextInputFilter instead of TextInput.
94
+ # See # TODO: add link # for more information
95
+ # NOTE: this behavior will be default from Formtastic 4.0
96
+ Formtastic::FormBuilder.input_class_finder = Formtastic::InputClassFinder
97
+
98
+ # Define custom namespaces in which to look up your Input classes. Default is
99
+ # to look up in the global scope and in Formtastic::Inputs.
100
+ # Formtastic::FormBuilder.input_namespaces = [ ::Object, ::MyInputsModule, ::Formtastic::Inputs ]
101
+
102
+ # By creating custom action class finder, you can change how action classes are looked up.
103
+ # For example you can make it to search for MyButtonAction instead of ButtonAction.
104
+ # See # TODO: add link # for more information
105
+ # NOTE: this behavior will be default from Formtastic 4.0
106
+ Formtastic::FormBuilder.action_class_finder = Formtastic::ActionClassFinder
107
+
108
+ # Define custom namespaces in which to look up your Action classes. Default is
109
+ # to look up in the global scope and in Formtastic::Actions.
110
+ # Formtastic::FormBuilder.action_namespaces = [ ::Object, ::MyActionsModule, ::Formtastic::Actions ]
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'formtastic/action_class_finder'
4
+
5
+ describe Formtastic::ActionClassFinder do
6
+ include FormtasticSpecHelper
7
+
8
+ it_behaves_like 'Specialized Class Finder' do
9
+ let(:default) { Formtastic::Actions }
10
+ let(:namespaces_setting) { :action_namespaces }
11
+ end
12
+ end
@@ -39,8 +39,8 @@ describe 'Formtastic::Helpers::FormHelper.builder' do
39
39
  with_config(:all_fields_required_by_default, true) do
40
40
  MyCustomFormBuilder.all_fields_required_by_default = false
41
41
 
42
- MyCustomFormBuilder.all_fields_required_by_default.should be_false
43
- Formtastic::FormBuilder.all_fields_required_by_default.should be_true
42
+ MyCustomFormBuilder.all_fields_required_by_default.should be_falsey
43
+ Formtastic::FormBuilder.all_fields_required_by_default.should be_truthy
44
44
  end
45
45
  end
46
46
 
@@ -29,16 +29,16 @@ describe 'Formtastic::FormBuilder#fields_for' do
29
29
 
30
30
  it 'should respond to input' do
31
31
  semantic_fields_for(@new_post) do |nested_builder|
32
- nested_builder.respond_to?(:input).should be_true
32
+ nested_builder.respond_to?(:input).should be_truthy
33
33
  end
34
34
  semantic_fields_for(@new_post.author) do |nested_builder|
35
- nested_builder.respond_to?(:input).should be_true
35
+ nested_builder.respond_to?(:input).should be_truthy
36
36
  end
37
37
  semantic_fields_for(:author, @new_post.author) do |nested_builder|
38
- nested_builder.respond_to?(:input).should be_true
38
+ nested_builder.respond_to?(:input).should be_truthy
39
39
  end
40
40
  semantic_fields_for(:author, @hash_backed_author) do |nested_builder|
41
- nested_builder.respond_to?(:input).should be_true
41
+ nested_builder.respond_to?(:input).should be_truthy
42
42
  end
43
43
  end
44
44
  end
@@ -2,364 +2,18 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe 'Formtastic::FormBuilder#action' do
5
+ include_context 'Action Helper' # from spec/support/shared_examples.rb
5
6
 
6
- include FormtasticSpecHelper
7
-
8
- before do
9
- @output_buffer = ''
10
- mock_everything
11
- end
12
-
13
- after do
14
- ::I18n.backend.reload!
15
- end
16
-
17
- describe 'arguments and options' do
18
-
19
- it 'should require the first argument (the action method)' do
20
- lambda {
21
- concat(semantic_form_for(@new_post) do |builder|
22
- concat(builder.action()) # no args passed in at all
23
- end)
24
- }.should raise_error(ArgumentError)
25
- end
26
-
27
- describe ':as option' do
28
-
29
- describe 'when not provided' do
30
-
31
- it 'should default to a commit for commit' do
32
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
33
- concat(builder.action(:submit))
34
- end)
35
- output_buffer.should have_tag('form li.action.input_action', :count => 1)
36
- end
37
-
38
- it 'should default to a button for reset' do
39
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
40
- concat(builder.action(:reset))
41
- end)
42
- output_buffer.should have_tag('form li.action.input_action', :count => 1)
43
- end
44
-
45
- it 'should default to a link for cancel' do
46
- concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
47
- concat(builder.action(:cancel))
48
- end)
49
- output_buffer.should have_tag('form li.action.link_action', :count => 1)
50
- end
51
- end
52
-
53
- it 'should call the corresponding action class with .to_html' do
54
- [:input, :button, :link].each do |action_style|
55
- semantic_form_for(:project, :url => "http://test.host") do |builder|
56
- action_instance = double('Action instance')
57
- action_class = "#{action_style.to_s}_action".classify
58
- action_constant = "Formtastic::Actions::#{action_class}".constantize
59
-
60
- action_constant.should_receive(:new).and_return(action_instance)
61
- action_instance.should_receive(:to_html).and_return("some HTML")
62
-
63
- concat(builder.action(:submit, :as => action_style))
64
- end
65
- end
66
- end
67
-
68
- end
69
-
70
- #describe ':label option' do
71
- #
72
- # describe 'when provided' do
73
- # it 'should be passed down to the label tag' do
74
- # concat(semantic_form_for(@new_post) do |builder|
75
- # concat(builder.input(:title, :label => "Kustom"))
76
- # end)
77
- # output_buffer.should have_tag("form li label", /Kustom/)
78
- # end
79
- #
80
- # it 'should not generate a label if false' do
81
- # concat(semantic_form_for(@new_post) do |builder|
82
- # concat(builder.input(:title, :label => false))
83
- # end)
84
- # output_buffer.should_not have_tag("form li label")
85
- # end
86
- #
87
- # it 'should be dupped if frozen' do
88
- # concat(semantic_form_for(@new_post) do |builder|
89
- # concat(builder.input(:title, :label => "Kustom".freeze))
90
- # end)
91
- # output_buffer.should have_tag("form li label", /Kustom/)
92
- # end
93
- # end
94
- #
95
- # describe 'when not provided' do
96
- # describe 'when localized label is provided' do
97
- # describe 'and object is given' do
98
- # describe 'and label_str_method not :humanize' do
99
- # it 'should render a label with localized text and not apply the label_str_method' do
100
- # with_config :label_str_method, :reverse do
101
- # @localized_label_text = 'Localized title'
102
- # @new_post.stub(:meta_description)
103
- # ::I18n.backend.store_translations :en,
104
- # :formtastic => {
105
- # :labels => {
106
- # :meta_description => @localized_label_text
107
- # }
108
- # }
109
- #
110
- # concat(semantic_form_for(@new_post) do |builder|
111
- # concat(builder.input(:meta_description))
112
- # end)
113
- # output_buffer.should have_tag('form li label', /Localized title/)
114
- # end
115
- # end
116
- # end
117
- # end
118
- # end
119
- #
120
- # describe 'when localized label is NOT provided' do
121
- # describe 'and object is not given' do
122
- # it 'should default the humanized method name, passing it down to the label tag' do
123
- # ::I18n.backend.store_translations :en, :formtastic => {}
124
- # with_config :label_str_method, :humanize do
125
- # concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
126
- # concat(builder.input(:meta_description))
127
- # end)
128
- # output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
129
- # end
130
- # end
131
- # end
132
- #
133
- # describe 'and object is given' do
134
- # it 'should delegate the label logic to class human attribute name and pass it down to the label tag' do
135
- # @new_post.stub(:meta_description) # a two word method name
136
- # @new_post.class.should_receive(:human_attribute_name).with('meta_description').and_return('meta_description'.humanize)
137
- #
138
- # concat(semantic_form_for(@new_post) do |builder|
139
- # concat(builder.input(:meta_description))
140
- # end)
141
- # output_buffer.should have_tag("form li label", /#{'meta_description'.humanize}/)
142
- # end
143
- # end
144
- #
145
- # describe 'and object is given with label_str_method set to :capitalize' do
146
- # it 'should capitalize method name, passing it down to the label tag' do
147
- # with_config :label_str_method, :capitalize do
148
- # @new_post.stub(:meta_description)
149
- #
150
- # concat(semantic_form_for(@new_post) do |builder|
151
- # concat(builder.input(:meta_description))
152
- # end)
153
- # output_buffer.should have_tag("form li label", /#{'meta_description'.capitalize}/)
154
- # end
155
- # end
156
- # end
157
- # end
158
- #
159
- # describe 'when localized label is provided' do
160
- # before do
161
- # @localized_label_text = 'Localized title'
162
- # @default_localized_label_text = 'Default localized title'
163
- # ::I18n.backend.store_translations :en,
164
- # :formtastic => {
165
- # :labels => {
166
- # :title => @default_localized_label_text,
167
- # :published => @default_localized_label_text,
168
- # :post => {
169
- # :title => @localized_label_text,
170
- # :published => @default_localized_label_text
171
- # }
172
- # }
173
- # }
174
- # end
175
- #
176
- # it 'should render a label with localized label (I18n)' do
177
- # with_config :i18n_lookups_by_default, false do
178
- # concat(semantic_form_for(@new_post) do |builder|
179
- # concat(builder.input(:title, :label => true))
180
- # concat(builder.input(:published, :as => :boolean, :label => true))
181
- # end)
182
- # output_buffer.should have_tag('form li label', Regexp.new('^' + @localized_label_text))
183
- # end
184
- # end
185
- #
186
- # it 'should render a hint paragraph containing an optional localized label (I18n) if first is not set' do
187
- # with_config :i18n_lookups_by_default, false do
188
- # ::I18n.backend.store_translations :en,
189
- # :formtastic => {
190
- # :labels => {
191
- # :post => {
192
- # :title => nil,
193
- # :published => nil
194
- # }
195
- # }
196
- # }
197
- # concat(semantic_form_for(@new_post) do |builder|
198
- # concat(builder.input(:title, :label => true))
199
- # concat(builder.input(:published, :as => :boolean, :label => true))
200
- # end)
201
- # output_buffer.should have_tag('form li label', Regexp.new('^' + @default_localized_label_text))
202
- # end
203
- # end
204
- # end
205
- # end
206
- #
207
- #end
208
- #
209
- describe ':wrapper_html option' do
210
-
211
- describe 'when provided' do
212
- it 'should be passed down to the li tag' do
213
- concat(semantic_form_for(@new_post) do |builder|
214
- concat(builder.action(:submit, :wrapper_html => {:id => :another_id}))
215
- end)
216
- output_buffer.should have_tag("form li#another_id")
217
- end
218
-
219
- it 'should append given classes to li default classes' do
220
- concat(semantic_form_for(@new_post) do |builder|
221
- concat(builder.action(:submit, :wrapper_html => {:class => :another_class}))
222
- end)
223
- output_buffer.should have_tag("form li.action")
224
- output_buffer.should have_tag("form li.input_action")
225
- output_buffer.should have_tag("form li.another_class")
226
- end
227
-
228
- it 'should allow classes to be an array' do
229
- concat(semantic_form_for(@new_post) do |builder|
230
- concat(builder.action(:submit, :wrapper_html => {:class => [ :my_class, :another_class ]}))
231
- end)
232
- output_buffer.should have_tag("form li.action")
233
- output_buffer.should have_tag("form li.input_action")
234
- output_buffer.should have_tag("form li.my_class")
235
- output_buffer.should have_tag("form li.another_class")
236
- end
237
- end
238
-
239
- describe 'when not provided' do
240
- it 'should use default id and class' do
241
- concat(semantic_form_for(@new_post) do |builder|
242
- concat(builder.action(:submit))
243
- end)
244
- output_buffer.should have_tag("form li#post_submit_action")
245
- output_buffer.should have_tag("form li.action")
246
- output_buffer.should have_tag("form li.input_action")
247
- end
248
- end
249
-
250
- end
251
-
252
- end
253
-
7
+ # TODO: remove this in Formtastic 4.0
254
8
  describe 'instantiating an action class' do
255
-
256
- context 'when a class does not exist' do
257
- it "should raise an error" do
258
- lambda {
259
- concat(semantic_form_for(@new_post) do |builder|
260
- builder.action(:submit, :as => :non_existant)
261
- end)
262
- }.should raise_error(Formtastic::UnknownActionError)
263
- end
264
- end
265
-
266
- context 'when a customized top-level class does not exist' do
267
-
268
- it 'should instantiate the Formtastic action' do
269
- action = double('action', :to_html => 'some HTML')
270
- Formtastic::Actions::ButtonAction.should_receive(:new).and_return(action)
271
- concat(semantic_form_for(@new_post) do |builder|
272
- builder.action(:commit, :as => :button)
273
- end)
274
- end
275
-
276
- end
277
-
278
- describe 'when a top-level (custom) action class exists' do
279
- it "should instantiate the top-level action instead of the Formtastic one" do
280
- class ::ButtonAction < Formtastic::Actions::ButtonAction
281
- end
282
-
283
- action = double('action', :to_html => 'some HTML')
284
- Formtastic::Actions::ButtonAction.should_not_receive(:new)
285
- ::ButtonAction.should_receive(:new).and_return(action)
286
-
287
- concat(semantic_form_for(@new_post) do |builder|
288
- builder.action(:commit, :as => :button)
289
- end)
290
- end
291
- end
292
-
293
- describe 'when instantiated multiple times with the same action type' do
294
-
295
- it "should be cached (not calling the internal methods)" do
296
- # TODO this is really tied to the underlying implementation
297
- concat(semantic_form_for(@new_post) do |builder|
298
- builder.should_receive(:custom_action_class_name).with(:button).once.and_return(::Formtastic::Actions::ButtonAction)
299
- builder.action(:submit, :as => :button)
300
- builder.action(:submit, :as => :button)
301
- end)
302
- end
303
-
304
- end
305
-
306
- describe 'support for :as on each action' do
307
-
308
- it "should raise an error when the action does not support the :as" do
309
- lambda {
310
- concat(semantic_form_for(@new_post) do |builder|
311
- concat(builder.action(:submit, :as => :link))
312
- end)
313
- }.should raise_error(Formtastic::UnsupportedMethodForAction)
314
-
315
- lambda {
316
- concat(semantic_form_for(@new_post) do |builder|
317
- concat(builder.action(:cancel, :as => :input))
318
- end)
319
- }.should raise_error(Formtastic::UnsupportedMethodForAction)
320
-
321
- lambda {
322
- concat(semantic_form_for(@new_post) do |builder|
323
- concat(builder.action(:cancel, :as => :button))
324
- end)
325
- }.should raise_error(Formtastic::UnsupportedMethodForAction)
326
- end
327
-
328
- it "should not raise an error when the action does not support the :as" do
329
- lambda {
330
- concat(semantic_form_for(@new_post) do |builder|
331
- concat(builder.action(:cancel, :as => :link))
332
- end)
333
- }.should_not raise_error
334
-
335
- lambda {
336
- concat(semantic_form_for(@new_post) do |builder|
337
- concat(builder.action(:submit, :as => :input))
338
- end)
339
- }.should_not raise_error
340
-
341
- lambda {
342
- concat(semantic_form_for(@new_post) do |builder|
343
- concat(builder.action(:submit, :as => :button))
344
- end)
345
- }.should_not raise_error
346
-
347
- lambda {
348
- concat(semantic_form_for(@new_post) do |builder|
349
- concat(builder.action(:reset, :as => :input))
350
- end)
351
- }.should_not raise_error
352
-
353
- lambda {
354
- concat(semantic_form_for(@new_post) do |builder|
355
- concat(builder.action(:reset, :as => :button))
356
- end)
357
- }.should_not raise_error
9
+ context 'of unknown action' do
10
+ it "should try to load class named as the action" do
11
+ expect {
12
+ semantic_form_for(@new_post) do |builder|
13
+ builder.action(:destroy)
14
+ end
15
+ }.to raise_error(Formtastic::UnknownActionError, 'Unable to find action destroy')
358
16
  end
359
-
360
17
  end
361
-
362
18
  end
363
-
364
19
  end
365
-