formtastic 1.2.5 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +2 -0
  3. data/.yardopts +1 -0
  4. data/CHANGELOG +279 -0
  5. data/Gemfile +3 -0
  6. data/README.textile +155 -172
  7. data/RELEASE_PROCESS +7 -0
  8. data/Rakefile +52 -0
  9. data/app/assets/stylesheets/formtastic.css +275 -0
  10. data/app/assets/stylesheets/formtastic_ie6.css +27 -0
  11. data/app/assets/stylesheets/formtastic_ie7.css +17 -0
  12. data/formtastic.gemspec +51 -0
  13. data/lib/formtastic.rb +21 -1960
  14. data/lib/formtastic/engine.rb +7 -0
  15. data/lib/formtastic/form_builder.rb +83 -0
  16. data/lib/formtastic/helpers.rb +16 -0
  17. data/lib/formtastic/helpers/buttons_helper.rb +277 -0
  18. data/lib/formtastic/helpers/errors_helper.rb +113 -0
  19. data/lib/formtastic/helpers/fieldset_wrapper.rb +75 -0
  20. data/lib/formtastic/helpers/file_column_detection.rb +16 -0
  21. data/lib/formtastic/helpers/form_helper.rb +198 -0
  22. data/lib/formtastic/helpers/input_helper.rb +366 -0
  23. data/lib/formtastic/helpers/inputs_helper.rb +392 -0
  24. data/lib/formtastic/helpers/reflection.rb +33 -0
  25. data/lib/formtastic/helpers/semantic_form_helper.rb +11 -0
  26. data/lib/formtastic/html_attributes.rb +21 -0
  27. data/lib/formtastic/i18n.rb +1 -0
  28. data/lib/formtastic/inputs.rb +31 -0
  29. data/lib/formtastic/inputs/base.rb +61 -0
  30. data/lib/formtastic/inputs/base/associations.rb +31 -0
  31. data/lib/formtastic/inputs/base/choices.rb +103 -0
  32. data/lib/formtastic/inputs/base/collections.rb +94 -0
  33. data/lib/formtastic/inputs/base/database.rb +17 -0
  34. data/lib/formtastic/inputs/base/errors.rb +58 -0
  35. data/lib/formtastic/inputs/base/fileish.rb +23 -0
  36. data/lib/formtastic/inputs/base/grouped_collections.rb +77 -0
  37. data/lib/formtastic/inputs/base/hints.rb +31 -0
  38. data/lib/formtastic/inputs/base/html.rb +52 -0
  39. data/lib/formtastic/inputs/base/labelling.rb +55 -0
  40. data/lib/formtastic/inputs/base/naming.rb +42 -0
  41. data/lib/formtastic/inputs/base/options.rb +18 -0
  42. data/lib/formtastic/inputs/base/stringish.rb +35 -0
  43. data/lib/formtastic/inputs/base/timeish.rb +128 -0
  44. data/lib/formtastic/inputs/base/validations.rb +166 -0
  45. data/lib/formtastic/inputs/base/wrapping.rb +40 -0
  46. data/lib/formtastic/inputs/boolean_input.rb +96 -0
  47. data/lib/formtastic/inputs/check_boxes_input.rb +179 -0
  48. data/lib/formtastic/inputs/country_input.rb +66 -0
  49. data/lib/formtastic/inputs/date_input.rb +14 -0
  50. data/lib/formtastic/inputs/datetime_input.rb +9 -0
  51. data/lib/formtastic/inputs/email_input.rb +40 -0
  52. data/lib/formtastic/inputs/file_input.rb +42 -0
  53. data/lib/formtastic/inputs/hidden_input.rb +66 -0
  54. data/lib/formtastic/inputs/number_input.rb +118 -0
  55. data/lib/formtastic/inputs/numeric_input.rb +21 -0
  56. data/lib/formtastic/inputs/password_input.rb +40 -0
  57. data/lib/formtastic/inputs/phone_input.rb +41 -0
  58. data/lib/formtastic/inputs/radio_input.rb +157 -0
  59. data/lib/formtastic/inputs/range_input.rb +119 -0
  60. data/lib/formtastic/inputs/search_input.rb +40 -0
  61. data/lib/formtastic/inputs/select_input.rb +210 -0
  62. data/lib/formtastic/inputs/string_input.rb +34 -0
  63. data/lib/formtastic/inputs/text_input.rb +47 -0
  64. data/lib/formtastic/inputs/time_input.rb +14 -0
  65. data/lib/formtastic/inputs/time_zone_input.rb +48 -0
  66. data/lib/formtastic/inputs/url_input.rb +40 -0
  67. data/lib/formtastic/localized_string.rb +105 -0
  68. data/lib/formtastic/railtie.rb +5 -7
  69. data/lib/formtastic/semantic_form_builder.rb +11 -0
  70. data/lib/formtastic/util.rb +6 -19
  71. data/lib/formtastic/version.rb +3 -0
  72. data/lib/generators/formtastic/install/install_generator.rb +28 -6
  73. data/lib/generators/templates/_form.html.erb +10 -4
  74. data/lib/generators/templates/_form.html.haml +8 -4
  75. data/lib/generators/templates/formtastic.rb +25 -32
  76. data/lib/locale/en.yml +1 -0
  77. data/lib/tasks/verify_rcov.rb +44 -0
  78. data/sample/basic_inputs.html +182 -0
  79. data/sample/config.ru +69 -0
  80. data/sample/index.html +14 -0
  81. data/spec/builder/custom_builder_spec.rb +109 -0
  82. data/spec/builder/error_proc_spec.rb +27 -0
  83. data/spec/builder/errors_spec.rb +193 -0
  84. data/spec/builder/semantic_fields_for_spec.rb +88 -0
  85. data/spec/helpers/buttons_helper_spec.rb +150 -0
  86. data/spec/helpers/commit_button_helper_spec.rb +470 -0
  87. data/spec/helpers/form_helper_spec.rb +135 -0
  88. data/spec/helpers/input_helper_spec.rb +837 -0
  89. data/spec/helpers/inputs_helper_spec.rb +562 -0
  90. data/spec/helpers/semantic_errors_helper_spec.rb +112 -0
  91. data/spec/i18n_spec.rb +199 -0
  92. data/spec/inputs/boolean_input_spec.rb +184 -0
  93. data/spec/inputs/check_boxes_input_spec.rb +375 -0
  94. data/spec/inputs/country_input_spec.rb +133 -0
  95. data/spec/inputs/custom_input_spec.rb +52 -0
  96. data/spec/inputs/date_input_spec.rb +110 -0
  97. data/spec/inputs/datetime_input_spec.rb +115 -0
  98. data/spec/inputs/email_input_spec.rb +55 -0
  99. data/spec/inputs/file_input_spec.rb +59 -0
  100. data/spec/inputs/hidden_input_spec.rb +120 -0
  101. data/spec/inputs/include_blank_spec.rb +70 -0
  102. data/spec/inputs/label_spec.rb +104 -0
  103. data/spec/inputs/number_input_spec.rb +487 -0
  104. data/spec/inputs/numeric_input_spec.rb +41 -0
  105. data/spec/inputs/password_input_spec.rb +69 -0
  106. data/spec/inputs/phone_input_spec.rb +55 -0
  107. data/spec/inputs/placeholder_spec.rb +71 -0
  108. data/spec/inputs/radio_input_spec.rb +234 -0
  109. data/spec/inputs/range_input_spec.rb +477 -0
  110. data/spec/inputs/search_input_spec.rb +55 -0
  111. data/spec/inputs/select_input_spec.rb +545 -0
  112. data/spec/inputs/string_input_spec.rb +163 -0
  113. data/spec/inputs/text_input_spec.rb +158 -0
  114. data/spec/inputs/time_input_spec.rb +155 -0
  115. data/spec/inputs/time_zone_input_spec.rb +87 -0
  116. data/spec/inputs/url_input_spec.rb +55 -0
  117. data/spec/spec.opts +2 -0
  118. data/spec/spec_helper.rb +361 -0
  119. data/spec/support/custom_macros.rb +656 -0
  120. data/spec/support/deferred_garbage_collection.rb +21 -0
  121. data/spec/support/deprecation.rb +6 -0
  122. data/spec/support/test_environment.rb +30 -0
  123. metadata +306 -88
  124. data/generators/form/USAGE +0 -16
  125. data/generators/form/form_generator.rb +0 -111
  126. data/generators/formtastic/formtastic_generator.rb +0 -26
  127. data/init.rb +0 -5
  128. data/lib/formtastic/layout_helper.rb +0 -12
  129. data/lib/generators/formtastic/form/form_generator.rb +0 -84
  130. data/lib/generators/templates/formtastic.css +0 -145
  131. data/lib/generators/templates/formtastic_changes.css +0 -14
  132. data/lib/generators/templates/rails2/_form.html.erb +0 -5
  133. data/lib/generators/templates/rails2/_form.html.haml +0 -4
  134. data/rails/init.rb +0 -2
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe "*select: options[:include_blank]" do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+
12
+ @new_post.stub!(:author_id).and_return(nil)
13
+ @new_post.stub!(:publish_at).and_return(nil)
14
+
15
+ @select_input_types = {
16
+ :select => :author,
17
+ :datetime => :publish_at,
18
+ :date => :publish_at,
19
+ :time => :publish_at
20
+ }
21
+ end
22
+
23
+ describe 'when :include_blank is not set' do
24
+ it 'blank value should be included if the default value specified in config is true' do
25
+ Formtastic::FormBuilder.include_blank_for_select_by_default = true
26
+ @select_input_types.each do |as, attribute|
27
+ concat(semantic_form_for(@new_post) do |builder|
28
+ concat(builder.input(attribute, :as => as))
29
+ end)
30
+ output_buffer.should have_tag("form li select option[@value='']", "")
31
+ end
32
+ end
33
+
34
+ it 'blank value should not be included if the default value specified in config is false' do
35
+ Formtastic::FormBuilder.include_blank_for_select_by_default = false
36
+ @select_input_types.each do |as, attribute|
37
+ concat(semantic_form_for(@new_post) do |builder|
38
+ concat(builder.input(attribute, :as => as))
39
+ end)
40
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
41
+ end
42
+ end
43
+
44
+ after do
45
+ Formtastic::FormBuilder.include_blank_for_select_by_default = true
46
+ end
47
+ end
48
+
49
+ describe 'when :include_blank is set to false' do
50
+ it 'should not have a blank option' do
51
+ @select_input_types.each do |as, attribute|
52
+ concat(semantic_form_for(@new_post) do |builder|
53
+ concat(builder.input(attribute, :as => as, :include_blank => false))
54
+ end)
55
+ output_buffer.should_not have_tag("form li select option[@value='']", "")
56
+ end
57
+ end
58
+ end
59
+
60
+ describe 'when :include_blank => true is set' do
61
+ it 'should have a blank select option' do
62
+ @select_input_types.each do |as, attribute|
63
+ concat(semantic_form_for(@new_post) do |builder|
64
+ concat(builder.input(attribute, :as => as, :include_blank => true))
65
+ end)
66
+ output_buffer.should have_tag("form li select option[@value='']", "")
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Formtastic::FormBuilder#label' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+ end
12
+
13
+ it 'should humanize the given attribute' do
14
+ concat(semantic_form_for(@new_post) do |builder|
15
+ builder.input(:title)
16
+ end)
17
+ output_buffer.should have_tag('label', /Title/)
18
+ end
19
+
20
+ it 'should humanize the given attribute for date fields' do
21
+ concat(semantic_form_for(@new_post) do |builder|
22
+ builder.input(:publish_at)
23
+ end)
24
+ output_buffer.should have_tag('label', /Publish at/)
25
+ end
26
+
27
+ describe 'when required is given' do
28
+ it 'should append a required note' do
29
+ concat(semantic_form_for(@new_post) do |builder|
30
+ builder.input(:title, :required => true)
31
+ end)
32
+ output_buffer.should have_tag('label abbr', '*')
33
+ end
34
+ end
35
+
36
+ describe 'when a collection is given' do
37
+ it 'should use a supplied label_method for simple collections' do
38
+ concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
39
+ concat(builder.input(:author_id, :as => :check_boxes, :collection => [:a, :b, :c], :member_value => :to_s, :member_label => proc {|f| ('Label_%s' % [f])}))
40
+ end)
41
+ output_buffer.should have_tag('form li fieldset ol li label', /Label_[abc]/, :count => 3)
42
+ end
43
+
44
+ it 'should use a supplied value_method for simple collections' do
45
+ concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
46
+ concat(builder.input(:author_id, :as => :check_boxes, :collection => [:a, :b, :c], :member_value => proc {|f| ('Value_%s' % [f.to_s])}))
47
+ end)
48
+ output_buffer.should have_tag('form li fieldset ol li label input[value="Value_a"]')
49
+ output_buffer.should have_tag('form li fieldset ol li label input[value="Value_b"]')
50
+ output_buffer.should have_tag('form li fieldset ol li label input[value="Value_c"]')
51
+ end
52
+ end
53
+
54
+ describe 'when label is given' do
55
+ it 'should allow the text to be given as label option' do
56
+ concat(semantic_form_for(@new_post) do |builder|
57
+ builder.input(:title, :label => 'My label')
58
+ end)
59
+ output_buffer.should have_tag('label', /My label/)
60
+ end
61
+
62
+ it 'should allow the text to be given as label option for date fields' do
63
+ concat(semantic_form_for(@new_post) do |builder|
64
+ builder.input(:publish_at, :label => 'My other label')
65
+ end)
66
+ output_buffer.should have_tag('label', /My other label/)
67
+ end
68
+
69
+ it 'should return nil if label is false' do
70
+ concat(semantic_form_for(@new_post) do |builder|
71
+ builder.input(:title, :label => false)
72
+ end)
73
+ output_buffer.should_not have_tag('label')
74
+ output_buffer.should_not include(">")
75
+ end
76
+
77
+ it 'should html escape the label string by default' do
78
+ concat(semantic_form_for(@new_post) do |builder|
79
+ builder.input(:title, :label => '<b>My label</b>')
80
+ end)
81
+ output_buffer.should include('&lt;b&gt;')
82
+ output_buffer.should_not include('<b>')
83
+ end
84
+
85
+ it 'should not html escape the label if configured that way' do
86
+ Formtastic::FormBuilder.escape_html_entities_in_hints_and_labels = false
87
+ concat(semantic_form_for(@new_post) do |builder|
88
+ builder.input(:title, :label => '<b>My label</b>')
89
+ end)
90
+ output_buffer.should have_tag("label b", "My label")
91
+ end
92
+
93
+ it 'should not html escape the label string for html_safe strings' do
94
+ Formtastic::FormBuilder.escape_html_entities_in_hints_and_labels = true
95
+ concat(semantic_form_for(@new_post) do |builder|
96
+ builder.input(:title, :label => '<b>My label</b>'.html_safe)
97
+ end)
98
+ output_buffer.should have_tag('label b')
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+
@@ -0,0 +1,487 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'number input' do
5
+
6
+ include FormtasticSpecHelper
7
+
8
+ before do
9
+ @output_buffer = ''
10
+ mock_everything
11
+
12
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
13
+ active_model_numericality_validator([:title], {:only_integer=>false, :allow_nil=>false, :greater_than=>2})
14
+ ])
15
+ end
16
+
17
+ describe "all cases" do
18
+
19
+ before do
20
+ concat(
21
+ semantic_form_for(@new_post) do |builder|
22
+ concat(builder.input(:title, :as => :number))
23
+ end
24
+ )
25
+ end
26
+
27
+ it_should_have_input_wrapper_with_class(:number)
28
+ it_should_have_input_wrapper_with_class(:input)
29
+ it_should_have_input_wrapper_with_class(:stringish)
30
+ it_should_have_input_wrapper_with_id("post_title_input")
31
+ it_should_have_label_with_text(/Title/)
32
+ it_should_have_label_for("post_title")
33
+ it_should_have_input_with_id("post_title")
34
+ it_should_have_input_with_type(:number)
35
+ it_should_have_input_with_name("post[title]")
36
+ it_should_use_default_text_field_size_when_not_nil(:string)
37
+ it_should_not_use_default_text_field_size_when_nil(:string)
38
+ it_should_apply_custom_input_attributes_when_input_html_provided(:string)
39
+ it_should_apply_custom_for_to_label_when_input_html_id_provided(:string)
40
+ it_should_apply_error_logic_for_input_type(:number)
41
+
42
+ end
43
+
44
+ describe "when no object is provided" do
45
+ before do
46
+ concat(semantic_form_for(:project, :url => 'http://test.host/') do |builder|
47
+ concat(builder.input(:title, :as => :number, :input_html => { :min => 1, :max => 2 }))
48
+ end)
49
+ end
50
+
51
+ it_should_have_label_with_text(/Title/)
52
+ it_should_have_label_for("project_title")
53
+ it_should_have_input_with_id("project_title")
54
+ it_should_have_input_with_type(:number)
55
+ it_should_have_input_with_name("project[title]")
56
+ end
57
+
58
+ describe "when namespace provided" do
59
+ before do
60
+ concat(semantic_form_for(@new_post, :namespace => :context2) do |builder|
61
+ concat(builder.input(:title, :as => :number))
62
+ end)
63
+ end
64
+
65
+ it_should_have_input_wrapper_with_id("context2_post_title_input")
66
+ it_should_have_label_and_input_with_id("context2_post_title")
67
+ end
68
+
69
+ describe "when required" do
70
+ it "should add the required attribute to the input's html options" do
71
+ concat(semantic_form_for(@new_post) do |builder|
72
+ concat(builder.input(:title, :as => :number, :required => true))
73
+ end)
74
+ output_buffer.should have_tag("input[@required]")
75
+ end
76
+ end
77
+
78
+ describe "when validations require a minimum value (:greater_than)" do
79
+ before do
80
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
81
+ active_model_numericality_validator([:title], {:only_integer=>false, :allow_nil=>false, :greater_than=>2})
82
+ ])
83
+ end
84
+
85
+ it "should allow :input_html to override :min" do
86
+ concat(semantic_form_for(@new_post) do |builder|
87
+ builder.input(:title, :as => :number, :input_html => { :min => 5 })
88
+ end)
89
+ output_buffer.should have_tag('input[@min="5"]')
90
+ end
91
+
92
+ it "should allow :input_html to override :min through :in" do
93
+ concat(semantic_form_for(@new_post) do |builder|
94
+ builder.input(:title, :as => :number, :input_html => { :in => 5..102 })
95
+ end)
96
+ output_buffer.should have_tag('input[@min="5"]')
97
+ end
98
+
99
+ it "should allow options to override :min" do
100
+ concat(semantic_form_for(@new_post) do |builder|
101
+ builder.input(:title, :as => :number, :min => 5)
102
+ end)
103
+ output_buffer.should have_tag('input[@min="5"]')
104
+ end
105
+
106
+ it "should allow options to override :min through :in" do
107
+ concat(semantic_form_for(@new_post) do |builder|
108
+ builder.input(:title, :as => :number, :in => 5..102)
109
+ end)
110
+ output_buffer.should have_tag('input[@min="5"]')
111
+ end
112
+
113
+ describe "and the column is an integer" do
114
+ before do
115
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :integer))
116
+ end
117
+
118
+ it "should add a min attribute to the input one greater than the validation" do
119
+ concat(semantic_form_for(@new_post) do |builder|
120
+ builder.input(:title, :as => :number)
121
+ end)
122
+ output_buffer.should have_tag('input[@min="3"]')
123
+ end
124
+ end
125
+
126
+ describe "and the column is a float" do
127
+ before do
128
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :float))
129
+ end
130
+
131
+ it "should raise an error" do
132
+ lambda {
133
+ concat(semantic_form_for(@new_post) do |builder|
134
+ builder.input(:title, :as => :number)
135
+ end)
136
+ }.should raise_error(Formtastic::Inputs::Base::Validations::IndeterminableMinimumAttributeError)
137
+ end
138
+ end
139
+
140
+ describe "and the column is a big decimal" do
141
+ before do
142
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :decimal))
143
+ end
144
+
145
+ it "should raise an error" do
146
+ lambda {
147
+ concat(semantic_form_for(@new_post) do |builder|
148
+ builder.input(:title, :as => :number)
149
+ end)
150
+ }.should raise_error(Formtastic::Inputs::Base::Validations::IndeterminableMinimumAttributeError)
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+ describe "when validations require a minimum value (:greater_than_or_equal_to)" do
157
+ before do
158
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
159
+ active_model_numericality_validator([:title], {:only_integer=>false, :allow_nil=>false, :greater_than_or_equal_to=>2})
160
+ ])
161
+ end
162
+
163
+ it "should allow :input_html to override :min" do
164
+ concat(semantic_form_for(@new_post) do |builder|
165
+ builder.input(:title, :as => :number, :input_html => { :min => 5 })
166
+ end)
167
+ output_buffer.should have_tag('input[@min="5"]')
168
+ end
169
+
170
+ it "should allow options to override :min" do
171
+ concat(semantic_form_for(@new_post) do |builder|
172
+ builder.input(:title, :as => :number, :min => 5)
173
+ end)
174
+ output_buffer.should have_tag('input[@min="5"]')
175
+ end
176
+
177
+ it "should allow :input_html to override :min with :in" do
178
+ concat(semantic_form_for(@new_post) do |builder|
179
+ builder.input(:title, :as => :number, :input_html => { :in => 5..102 })
180
+ end)
181
+ output_buffer.should have_tag('input[@min="5"]')
182
+ end
183
+
184
+ it "should allow options to override :min with :in" do
185
+ concat(semantic_form_for(@new_post) do |builder|
186
+ builder.input(:title, :as => :number, :in => 5..102)
187
+ end)
188
+ output_buffer.should have_tag('input[@min="5"]')
189
+ end
190
+
191
+
192
+ [:integer, :decimal, :float].each do |column_type|
193
+ describe "and the column is a #{column_type}" do
194
+ before do
195
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => column_type))
196
+ end
197
+
198
+ it "should add a max attribute to the input equal to the validation" do
199
+ concat(semantic_form_for(@new_post) do |builder|
200
+ builder.input(:title, :as => :number)
201
+ end)
202
+ output_buffer.should have_tag('input[@min="2"]')
203
+ end
204
+ end
205
+ end
206
+
207
+ describe "and there is no column" do
208
+ before do
209
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(nil)
210
+ end
211
+
212
+ it "should add a max attribute to the input equal to the validation" do
213
+ concat(semantic_form_for(@new_post) do |builder|
214
+ builder.input(:title, :as => :number)
215
+ end)
216
+ output_buffer.should have_tag('input[@min="2"]')
217
+ end
218
+ end
219
+ end
220
+
221
+ describe "when validations require a maximum value (:less_than)" do
222
+ before do
223
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
224
+ active_model_numericality_validator([:title], {:only_integer=>false, :allow_nil=>false, :less_than=>20})
225
+ ])
226
+ end
227
+
228
+ it "should allow :input_html to override :max" do
229
+ concat(semantic_form_for(@new_post) do |builder|
230
+ builder.input(:title, :as => :number, :input_html => { :max => 102 })
231
+ end)
232
+ output_buffer.should have_tag('input[@max="102"]')
233
+ end
234
+
235
+ it "should allow option to override :max" do
236
+ concat(semantic_form_for(@new_post) do |builder|
237
+ builder.input(:title, :as => :number, :max => 102)
238
+ end)
239
+ output_buffer.should have_tag('input[@max="102"]')
240
+ end
241
+
242
+ it "should allow :input_html to override :max with :in" do
243
+ concat(semantic_form_for(@new_post) do |builder|
244
+ builder.input(:title, :as => :number, :input_html => { :in => 1..102 })
245
+ end)
246
+ output_buffer.should have_tag('input[@max="102"]')
247
+ end
248
+
249
+ it "should allow option to override :max with :in" do
250
+ concat(semantic_form_for(@new_post) do |builder|
251
+ builder.input(:title, :as => :number, :in => 1..102)
252
+ end)
253
+ output_buffer.should have_tag('input[@max="102"]')
254
+ end
255
+
256
+ describe "and the column is an integer" do
257
+ before do
258
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :integer))
259
+ end
260
+
261
+ it "should add a max attribute to the input one greater than the validation" do
262
+ concat(semantic_form_for(@new_post) do |builder|
263
+ builder.input(:title, :as => :number)
264
+ end)
265
+ output_buffer.should have_tag('input[@max="19"]')
266
+ end
267
+ end
268
+
269
+ describe "and the column is a float" do
270
+ before do
271
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :float))
272
+ end
273
+
274
+ it "should raise an error" do
275
+ lambda {
276
+ concat(semantic_form_for(@new_post) do |builder|
277
+ builder.input(:title, :as => :number)
278
+ end)
279
+ }.should raise_error(Formtastic::Inputs::Base::Validations::IndeterminableMaximumAttributeError)
280
+ end
281
+ end
282
+
283
+ describe "and the column is a big decimal" do
284
+ before do
285
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :decimal))
286
+ end
287
+
288
+ it "should raise an error" do
289
+ lambda {
290
+ concat(semantic_form_for(@new_post) do |builder|
291
+ builder.input(:title, :as => :number)
292
+ end)
293
+ }.should raise_error(Formtastic::Inputs::Base::Validations::IndeterminableMaximumAttributeError)
294
+ end
295
+ end
296
+
297
+ end
298
+
299
+ describe "when validations require a maximum value (:less_than_or_equal_to)" do
300
+ before do
301
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
302
+ active_model_numericality_validator([:title], {:only_integer=>false, :allow_nil=>false, :less_than_or_equal_to=>20})
303
+ ])
304
+ end
305
+
306
+ it "should allow :input_html to override :max" do
307
+ concat(semantic_form_for(@new_post) do |builder|
308
+ builder.input(:title, :as => :number, :input_html => { :max => 102 })
309
+ end)
310
+ output_buffer.should have_tag('input[@max="102"]')
311
+ end
312
+
313
+ it "should allow options to override :max" do
314
+ concat(semantic_form_for(@new_post) do |builder|
315
+ builder.input(:title, :as => :number, :max => 102)
316
+ end)
317
+ output_buffer.should have_tag('input[@max="102"]')
318
+ end
319
+
320
+ it "should allow :input_html to override :max with :in" do
321
+ concat(semantic_form_for(@new_post) do |builder|
322
+ builder.input(:title, :as => :number, :input_html => { :in => 1..102 })
323
+ end)
324
+ output_buffer.should have_tag('input[@max="102"]')
325
+ end
326
+
327
+ it "should allow options to override :max with :in" do
328
+ concat(semantic_form_for(@new_post) do |builder|
329
+ builder.input(:title, :as => :number, :in => 1..102)
330
+ end)
331
+ output_buffer.should have_tag('input[@max="102"]')
332
+ end
333
+
334
+ [:integer, :decimal, :float].each do |column_type|
335
+ describe "and the column is a #{column_type}" do
336
+ before do
337
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => column_type))
338
+ end
339
+
340
+ it "should add a max attribute to the input equal to the validation" do
341
+ concat(semantic_form_for(@new_post) do |builder|
342
+ builder.input(:title, :as => :number)
343
+ end)
344
+ output_buffer.should have_tag('input[@max="20"]')
345
+ end
346
+ end
347
+ end
348
+
349
+ describe "and there is no column" do
350
+ before do
351
+ @new_post.stub!(:column_for_attribute).with(:title).and_return(nil)
352
+ end
353
+
354
+ it "should add a max attribute to the input equal to the validation" do
355
+ concat(semantic_form_for(@new_post) do |builder|
356
+ builder.input(:title, :as => :number)
357
+ end)
358
+ output_buffer.should have_tag('input[@max="20"]')
359
+ end
360
+ end
361
+ end
362
+
363
+ describe "when validations require conflicting minimum values (:greater_than, :greater_than_or_equal_to)" do
364
+ before do
365
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
366
+ active_model_numericality_validator([:title], {:only_integer=>false, :allow_nil=>false, :greater_than => 20, :greater_than_or_equal_to=>2})
367
+ ])
368
+ end
369
+
370
+ it "should add a max attribute to the input equal to the :greater_than_or_equal_to validation" do
371
+ concat(semantic_form_for(@new_post) do |builder|
372
+ builder.input(:title, :as => :number)
373
+ end)
374
+ output_buffer.should have_tag('input[@min="2"]')
375
+ end
376
+ end
377
+
378
+ describe "when validations require conflicting maximum values (:less_than, :less_than_or_equal_to)" do
379
+ before do
380
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
381
+ active_model_numericality_validator([:title], {:only_integer=>false, :allow_nil=>false, :less_than => 20, :less_than_or_equal_to=>2})
382
+ ])
383
+ end
384
+
385
+ it "should add a max attribute to the input equal to the :greater_than_or_equal_to validation" do
386
+ concat(semantic_form_for(@new_post) do |builder|
387
+ builder.input(:title, :as => :number)
388
+ end)
389
+ output_buffer.should have_tag('input[@max="2"]')
390
+ end
391
+ end
392
+
393
+ describe "when validations require only an integer (:only_integer)" do
394
+
395
+ before do
396
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
397
+ active_model_numericality_validator([:title], {:allow_nil=>false, :only_integer=>true})
398
+ ])
399
+ end
400
+
401
+ it "should add a step=1 attribute to the input to signify that only whole numbers are allowed" do
402
+ concat(semantic_form_for(@new_post) do |builder|
403
+ builder.input(:title, :as => :number)
404
+ end)
405
+ output_buffer.should have_tag('input[@step="1"]')
406
+ end
407
+
408
+ it "should let input_html override :step" do
409
+ concat(semantic_form_for(@new_post) do |builder|
410
+ builder.input(:title, :as => :number, :input_html => { :step => 3 })
411
+ end)
412
+ output_buffer.should have_tag('input[@step="3"]')
413
+ end
414
+
415
+ it "should let options override :step" do
416
+ concat(semantic_form_for(@new_post) do |builder|
417
+ builder.input(:title, :as => :number, :step => 3)
418
+ end)
419
+ output_buffer.should have_tag('input[@step="3"]')
420
+ end
421
+
422
+ end
423
+
424
+ describe "when validations require a :step (non standard)" do
425
+
426
+ before do
427
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
428
+ active_model_numericality_validator([:title], {:allow_nil=>false, :only_integer=>true, :step=>2})
429
+ ])
430
+ end
431
+
432
+ it "should add a step=1 attribute to the input to signify that only whole numbers are allowed" do
433
+ concat(semantic_form_for(@new_post) do |builder|
434
+ builder.input(:title, :as => :number)
435
+ end)
436
+ output_buffer.should have_tag('input[@step="2"]')
437
+ end
438
+
439
+ it "should let input_html override :step" do
440
+ concat(semantic_form_for(@new_post) do |builder|
441
+ builder.input(:title, :as => :number, :input_html => { :step => 3 })
442
+ end)
443
+ output_buffer.should have_tag('input[@step="3"]')
444
+ end
445
+
446
+ it "should let options override :step" do
447
+ concat(semantic_form_for(@new_post) do |builder|
448
+ builder.input(:title, :as => :number, :step => 3)
449
+ end)
450
+ output_buffer.should have_tag('input[@step="3"]')
451
+ end
452
+
453
+ end
454
+
455
+ describe "when validations do not specify :step (non standard) or :only_integer" do
456
+
457
+ before do
458
+ @new_post.class.stub!(:validators_on).with(:title).and_return([
459
+ active_model_numericality_validator([:title], {:allow_nil=>false})
460
+ ])
461
+ end
462
+
463
+ it "should default step to 1" do
464
+ concat(semantic_form_for(@new_post) do |builder|
465
+ builder.input(:title, :as => :number)
466
+ end)
467
+ output_buffer.should have_tag('input[@step="1"]')
468
+ end
469
+
470
+ it "should let input_html set :step" do
471
+ concat(semantic_form_for(@new_post) do |builder|
472
+ builder.input(:title, :as => :number, :input_html => { :step => 3 })
473
+ end)
474
+ output_buffer.should have_tag('input[@step="3"]')
475
+ end
476
+
477
+ it "should let options set :step" do
478
+ concat(semantic_form_for(@new_post) do |builder|
479
+ builder.input(:title, :as => :number, :step => 3)
480
+ end)
481
+ output_buffer.should have_tag('input[@step="3"]')
482
+ end
483
+
484
+ end
485
+
486
+ end
487
+