formtastic 3.1.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +1 -0
  3. data/.github/workflows/test.yml +61 -0
  4. data/.gitignore +3 -2
  5. data/CHANGELOG.md +52 -0
  6. data/Gemfile.lock +105 -0
  7. data/MIT-LICENSE +1 -1
  8. data/{README.textile → README.md} +178 -167
  9. data/RELEASE_PROCESS +3 -1
  10. data/Rakefile +20 -1
  11. data/app/assets/stylesheets/formtastic.css +1 -1
  12. data/bin/appraisal +8 -0
  13. data/formtastic.gemspec +10 -16
  14. data/gemfiles/rails_5.2/Gemfile +5 -0
  15. data/gemfiles/rails_6.0/Gemfile +5 -0
  16. data/gemfiles/rails_6.1/Gemfile +5 -0
  17. data/gemfiles/rails_edge/Gemfile +13 -0
  18. data/lib/formtastic.rb +9 -11
  19. data/lib/formtastic/actions.rb +6 -3
  20. data/lib/formtastic/deprecation.rb +1 -38
  21. data/lib/formtastic/engine.rb +3 -1
  22. data/lib/formtastic/form_builder.rb +11 -24
  23. data/lib/formtastic/helpers.rb +1 -1
  24. data/lib/formtastic/helpers/action_helper.rb +1 -48
  25. data/lib/formtastic/helpers/enum.rb +13 -0
  26. data/lib/formtastic/helpers/errors_helper.rb +2 -2
  27. data/lib/formtastic/helpers/fieldset_wrapper.rb +13 -9
  28. data/lib/formtastic/helpers/form_helper.rb +1 -1
  29. data/lib/formtastic/helpers/input_helper.rb +23 -77
  30. data/lib/formtastic/helpers/inputs_helper.rb +27 -22
  31. data/lib/formtastic/i18n.rb +1 -1
  32. data/lib/formtastic/inputs.rb +32 -29
  33. data/lib/formtastic/inputs/base/choices.rb +1 -1
  34. data/lib/formtastic/inputs/base/collections.rb +43 -10
  35. data/lib/formtastic/inputs/base/database.rb +7 -2
  36. data/lib/formtastic/inputs/base/errors.rb +4 -4
  37. data/lib/formtastic/inputs/base/hints.rb +1 -1
  38. data/lib/formtastic/inputs/base/html.rb +7 -6
  39. data/lib/formtastic/inputs/base/naming.rb +4 -4
  40. data/lib/formtastic/inputs/base/options.rb +2 -3
  41. data/lib/formtastic/inputs/base/timeish.rb +5 -1
  42. data/lib/formtastic/inputs/base/validations.rb +38 -12
  43. data/lib/formtastic/inputs/check_boxes_input.rb +13 -5
  44. data/lib/formtastic/inputs/color_input.rb +0 -1
  45. data/lib/formtastic/inputs/country_input.rb +3 -1
  46. data/lib/formtastic/inputs/radio_input.rb +20 -0
  47. data/lib/formtastic/inputs/select_input.rb +29 -1
  48. data/lib/formtastic/inputs/time_zone_input.rb +16 -6
  49. data/lib/formtastic/localizer.rb +20 -22
  50. data/lib/formtastic/namespaced_class_finder.rb +1 -1
  51. data/lib/formtastic/version.rb +1 -1
  52. data/lib/generators/formtastic/form/form_generator.rb +1 -1
  53. data/lib/generators/formtastic/input/input_generator.rb +46 -0
  54. data/lib/generators/templates/formtastic.rb +14 -13
  55. data/lib/generators/templates/input.rb +19 -0
  56. data/sample/basic_inputs.html +1 -1
  57. data/script/integration-template.rb +74 -0
  58. data/script/integration.sh +19 -0
  59. data/spec/action_class_finder_spec.rb +1 -1
  60. data/spec/actions/button_action_spec.rb +8 -8
  61. data/spec/actions/generic_action_spec.rb +60 -60
  62. data/spec/actions/input_action_spec.rb +7 -7
  63. data/spec/actions/link_action_spec.rb +10 -10
  64. data/spec/builder/custom_builder_spec.rb +37 -21
  65. data/spec/builder/error_proc_spec.rb +4 -4
  66. data/spec/builder/semantic_fields_for_spec.rb +27 -27
  67. data/spec/fast_spec_helper.rb +12 -0
  68. data/spec/generators/formtastic/form/form_generator_spec.rb +25 -25
  69. data/spec/generators/formtastic/input/input_generator_spec.rb +124 -0
  70. data/spec/generators/formtastic/install/install_generator_spec.rb +9 -9
  71. data/spec/helpers/action_helper_spec.rb +328 -10
  72. data/spec/helpers/actions_helper_spec.rb +17 -17
  73. data/spec/helpers/form_helper_spec.rb +37 -37
  74. data/spec/helpers/input_helper_spec.rb +975 -2
  75. data/spec/helpers/inputs_helper_spec.rb +120 -105
  76. data/spec/helpers/reflection_helper_spec.rb +3 -3
  77. data/spec/helpers/semantic_errors_helper_spec.rb +22 -22
  78. data/spec/i18n_spec.rb +26 -26
  79. data/spec/input_class_finder_spec.rb +1 -1
  80. data/spec/inputs/base/collections_spec.rb +76 -0
  81. data/spec/inputs/base/validations_spec.rb +480 -0
  82. data/spec/inputs/boolean_input_spec.rb +55 -55
  83. data/spec/inputs/check_boxes_input_spec.rb +155 -108
  84. data/spec/inputs/color_input_spec.rb +51 -63
  85. data/spec/inputs/country_input_spec.rb +20 -20
  86. data/spec/inputs/custom_input_spec.rb +2 -6
  87. data/spec/inputs/datalist_input_spec.rb +1 -1
  88. data/spec/inputs/date_picker_input_spec.rb +42 -42
  89. data/spec/inputs/date_select_input_spec.rb +51 -37
  90. data/spec/inputs/datetime_picker_input_spec.rb +46 -46
  91. data/spec/inputs/datetime_select_input_spec.rb +53 -37
  92. data/spec/inputs/email_input_spec.rb +5 -5
  93. data/spec/inputs/file_input_spec.rb +6 -6
  94. data/spec/inputs/hidden_input_spec.rb +18 -18
  95. data/spec/inputs/include_blank_spec.rb +8 -8
  96. data/spec/inputs/label_spec.rb +20 -20
  97. data/spec/inputs/number_input_spec.rb +112 -112
  98. data/spec/inputs/password_input_spec.rb +5 -5
  99. data/spec/inputs/phone_input_spec.rb +5 -5
  100. data/spec/inputs/placeholder_spec.rb +5 -5
  101. data/spec/inputs/radio_input_spec.rb +84 -58
  102. data/spec/inputs/range_input_spec.rb +66 -66
  103. data/spec/inputs/readonly_spec.rb +50 -0
  104. data/spec/inputs/search_input_spec.rb +5 -5
  105. data/spec/inputs/select_input_spec.rb +149 -93
  106. data/spec/inputs/string_input_spec.rb +23 -23
  107. data/spec/inputs/text_input_spec.rb +16 -16
  108. data/spec/inputs/time_picker_input_spec.rb +43 -43
  109. data/spec/inputs/time_select_input_spec.rb +67 -54
  110. data/spec/inputs/time_zone_input_spec.rb +54 -28
  111. data/spec/inputs/url_input_spec.rb +5 -5
  112. data/spec/inputs/with_options_spec.rb +7 -7
  113. data/spec/localizer_spec.rb +17 -17
  114. data/spec/namespaced_class_finder_spec.rb +2 -2
  115. data/spec/schema.rb +21 -0
  116. data/spec/spec_helper.rb +165 -253
  117. data/spec/support/custom_macros.rb +72 -75
  118. data/spec/support/shared_examples.rb +0 -1232
  119. data/spec/support/test_environment.rb +23 -9
  120. metadata +69 -176
  121. data/.travis.yml +0 -29
  122. data/Appraisals +0 -29
  123. data/CHANGELOG +0 -31
  124. data/DEPRECATIONS +0 -49
  125. data/gemfiles/rails_3.2.gemfile +0 -7
  126. data/gemfiles/rails_4.0.4.gemfile +0 -7
  127. data/gemfiles/rails_4.1.gemfile +0 -7
  128. data/gemfiles/rails_4.2.gemfile +0 -7
  129. data/gemfiles/rails_4.gemfile +0 -7
  130. data/gemfiles/rails_edge.gemfile +0 -10
  131. data/lib/formtastic/util.rb +0 -57
  132. data/spec/helpers/namespaced_action_helper_spec.rb +0 -43
  133. data/spec/helpers/namespaced_input_helper_spec.rb +0 -36
  134. data/spec/support/deferred_garbage_collection.rb +0 -21
  135. data/spec/util_spec.rb +0 -66
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
3
 
4
- describe 'Formtastic::Helpers::Reflection' do
4
+ RSpec.describe 'Formtastic::Helpers::Reflection' do
5
5
 
6
6
  include FormtasticSpecHelper
7
7
 
@@ -20,11 +20,11 @@ describe 'Formtastic::Helpers::Reflection' do
20
20
  context 'with an ActiveRecord object' do
21
21
  it "should return association details on an ActiveRecord association" do
22
22
  @reflection_tester = ReflectionTester.new(@new_post)
23
- @reflection_tester.reflection_for(:sub_posts).should_not be_nil
23
+ expect(@reflection_tester.reflection_for(:sub_posts)).not_to be_nil
24
24
  end
25
25
  it "should return association details on a MongoMapper association" do
26
26
  @reflection_tester = ReflectionTester.new(@new_mm_post)
27
- @reflection_tester.reflection_for(:sub_posts).should_not be_nil
27
+ expect(@reflection_tester.reflection_for(:sub_posts)).not_to be_nil
28
28
  end
29
29
  end
30
30
 
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
3
 
4
- describe 'Formtastic::FormBuilder#semantic_errors' do
4
+ RSpec.describe 'Formtastic::FormBuilder#semantic_errors' do
5
5
 
6
6
  include FormtasticSpecHelper
7
7
 
@@ -12,31 +12,31 @@ describe 'Formtastic::FormBuilder#semantic_errors' do
12
12
  @base_errors = ['base error message', 'nasty error']
13
13
  @base_error = 'one base error'
14
14
  @errors = double('errors')
15
- @new_post.stub(:errors).and_return(@errors)
15
+ allow(@new_post).to receive(:errors).and_return(@errors)
16
16
  end
17
17
 
18
18
  describe 'when there is only one error on base' do
19
19
  before do
20
- @errors.stub(:[]).with(errors_matcher(:base)).and_return(@base_error)
20
+ allow(@errors).to receive(:[]).with(errors_matcher(:base)).and_return(@base_error)
21
21
  end
22
22
 
23
23
  it 'should render an unordered list' do
24
24
  semantic_form_for(@new_post) do |builder|
25
- builder.semantic_errors.should have_tag('ul.errors li', @base_error)
25
+ expect(builder.semantic_errors).to have_tag('ul.errors li', :text => @base_error)
26
26
  end
27
27
  end
28
28
  end
29
29
 
30
30
  describe 'when there is more than one error on base' do
31
31
  before do
32
- @errors.stub(:[]).with(errors_matcher(:base)).and_return(@base_errors)
32
+ allow(@errors).to receive(:[]).with(errors_matcher(:base)).and_return(@base_errors)
33
33
  end
34
34
 
35
35
  it 'should render an unordered list' do
36
36
  semantic_form_for(@new_post) do |builder|
37
- builder.semantic_errors.should have_tag('ul.errors')
37
+ expect(builder.semantic_errors).to have_tag('ul.errors')
38
38
  @base_errors.each do |error|
39
- builder.semantic_errors.should have_tag('ul.errors li', error)
39
+ expect(builder.semantic_errors).to have_tag('ul.errors li', :text => error)
40
40
  end
41
41
  end
42
42
  end
@@ -44,67 +44,67 @@ describe 'Formtastic::FormBuilder#semantic_errors' do
44
44
 
45
45
  describe 'when there are errors on title' do
46
46
  before do
47
- @errors.stub(:[]).with(errors_matcher(:title)).and_return(@title_errors)
48
- @errors.stub(:[]).with(errors_matcher(:base)).and_return([])
47
+ allow(@errors).to receive(:[]).with(errors_matcher(:title)).and_return(@title_errors)
48
+ allow(@errors).to receive(:[]).with(errors_matcher(:base)).and_return([])
49
49
  end
50
50
 
51
51
  it 'should render an unordered list' do
52
52
  semantic_form_for(@new_post) do |builder|
53
53
  title_name = builder.send(:localized_string, :title, :title, :label) || builder.send(:humanized_attribute_name, :title)
54
- builder.semantic_errors(:title).should have_tag('ul.errors li', title_name << " " << @title_errors.to_sentence)
54
+ expect(builder.semantic_errors(:title)).to have_tag('ul.errors li', :text => title_name << " " << @title_errors.to_sentence)
55
55
  end
56
56
  end
57
57
  end
58
58
 
59
59
  describe 'when there are errors on title and base' do
60
60
  before do
61
- @errors.stub(:[]).with(errors_matcher(:title)).and_return(@title_errors)
62
- @errors.stub(:[]).with(errors_matcher(:base)).and_return(@base_error)
61
+ allow(@errors).to receive(:[]).with(errors_matcher(:title)).and_return(@title_errors)
62
+ allow(@errors).to receive(:[]).with(errors_matcher(:base)).and_return(@base_error)
63
63
  end
64
64
 
65
65
  it 'should render an unordered list' do
66
66
  semantic_form_for(@new_post) do |builder|
67
67
  title_name = builder.send(:localized_string, :title, :title, :label) || builder.send(:humanized_attribute_name, :title)
68
- builder.semantic_errors(:title).should have_tag('ul.errors li', title_name << " " << @title_errors.to_sentence)
69
- builder.semantic_errors(:title).should have_tag('ul.errors li', @base_error)
68
+ expect(builder.semantic_errors(:title)).to have_tag('ul.errors li', :text => title_name << " " << @title_errors.to_sentence)
69
+ expect(builder.semantic_errors(:title)).to have_tag('ul.errors li', :text => @base_error)
70
70
  end
71
71
  end
72
72
  end
73
73
 
74
74
  describe 'when there are no errors' do
75
75
  before do
76
- @errors.stub(:[]).with(errors_matcher(:title)).and_return(nil)
77
- @errors.stub(:[]).with(errors_matcher(:base)).and_return(nil)
76
+ allow(@errors).to receive(:[]).with(errors_matcher(:title)).and_return(nil)
77
+ allow(@errors).to receive(:[]).with(errors_matcher(:base)).and_return(nil)
78
78
  end
79
79
 
80
80
  it 'should return nil' do
81
81
  semantic_form_for(@new_post) do |builder|
82
- builder.semantic_errors(:title).should be_nil
82
+ expect(builder.semantic_errors(:title)).to be_nil
83
83
  end
84
84
  end
85
85
  end
86
86
 
87
87
  describe 'when there is one error on base and options with class is passed' do
88
88
  before do
89
- @errors.stub(:[]).with(errors_matcher(:base)).and_return(@base_error)
89
+ allow(@errors).to receive(:[]).with(errors_matcher(:base)).and_return(@base_error)
90
90
  end
91
91
 
92
92
  it 'should render an unordered list with given class' do
93
93
  semantic_form_for(@new_post) do |builder|
94
- builder.semantic_errors(:class => "awesome").should have_tag('ul.awesome li', @base_error)
94
+ expect(builder.semantic_errors(:class => "awesome")).to have_tag('ul.awesome li', :text => @base_error)
95
95
  end
96
96
  end
97
97
  end
98
98
 
99
99
  describe 'when :base is passed in as an argument' do
100
100
  before do
101
- @errors.stub(:[]).with(errors_matcher(:base)).and_return(@base_error)
101
+ allow(@errors).to receive(:[]).with(errors_matcher(:base)).and_return(@base_error)
102
102
  end
103
103
 
104
104
  it 'should ignore :base and only render base errors once' do
105
105
  semantic_form_for(@new_post) do |builder|
106
- builder.semantic_errors(:base).should have_tag('ul li', :count => 1)
107
- builder.semantic_errors(:base).should_not have_tag('ul li', "Base #{@base_error}")
106
+ expect(builder.semantic_errors(:base)).to have_tag('ul li', :count => 1)
107
+ expect(builder.semantic_errors(:base)).not_to have_tag('ul li', :text => "Base #{@base_error}")
108
108
  end
109
109
  end
110
110
  end
data/spec/i18n_spec.rb CHANGED
@@ -1,22 +1,22 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
3
 
4
- describe 'Formtastic::I18n' do
4
+ RSpec.describe 'Formtastic::I18n' do
5
5
 
6
6
  FORMTASTIC_KEYS = [:required, :yes, :no, :create, :update].freeze
7
7
 
8
8
  it "should be defined" do
9
- lambda { Formtastic::I18n }.should_not raise_error
9
+ expect { Formtastic::I18n }.not_to raise_error
10
10
  end
11
11
 
12
12
  describe "default translations" do
13
13
  it "should be defined" do
14
- lambda { Formtastic::I18n::DEFAULT_VALUES }.should_not raise_error
15
- Formtastic::I18n::DEFAULT_VALUES.is_a?(::Hash).should == true
14
+ expect { Formtastic::I18n::DEFAULT_VALUES }.not_to raise_error
15
+ expect(Formtastic::I18n::DEFAULT_VALUES.is_a?(::Hash)).to eq(true)
16
16
  end
17
17
 
18
18
  it "should exists for the core I18n lookup keys" do
19
- (Formtastic::I18n::DEFAULT_VALUES.keys & FORMTASTIC_KEYS).size.should == FORMTASTIC_KEYS.size
19
+ expect((Formtastic::I18n::DEFAULT_VALUES.keys & FORMTASTIC_KEYS).size).to eq(FORMTASTIC_KEYS.size)
20
20
  end
21
21
  end
22
22
 
@@ -42,23 +42,23 @@ describe 'Formtastic::I18n' do
42
42
 
43
43
  it "should translate core strings correctly" do
44
44
  ::I18n.backend.store_translations :en, {:formtastic => {:required => 'Default Required'}}
45
- Formtastic::I18n.t(:required).should == "Default Required"
46
- Formtastic::I18n.t(:yes).should == "Default Yes"
47
- Formtastic::I18n.t(:no).should == "Default No"
48
- Formtastic::I18n.t(:create, :model => 'Post').should == "Default Create Post"
49
- Formtastic::I18n.t(:update, :model => 'Post').should == "Default Update Post"
45
+ expect(Formtastic::I18n.t(:required)).to eq("Default Required")
46
+ expect(Formtastic::I18n.t(:yes)).to eq("Default Yes")
47
+ expect(Formtastic::I18n.t(:no)).to eq("Default No")
48
+ expect(Formtastic::I18n.t(:create, :model => 'Post')).to eq("Default Create Post")
49
+ expect(Formtastic::I18n.t(:update, :model => 'Post')).to eq("Default Update Post")
50
50
  end
51
51
 
52
52
  it "should all belong to scope 'formtastic'" do
53
- Formtastic::I18n.t(:duck, :scope => [:custom_scope]).should == 'Duck'
53
+ expect(Formtastic::I18n.t(:duck, :scope => [:custom_scope])).to eq('Duck')
54
54
  end
55
55
 
56
56
  it "should override default I18n lookup args if these are specified" do
57
- Formtastic::I18n.t(:duck_pond, :scope => [:custom_scope], :ducks => 15).should == '15 ducks in a pond'
57
+ expect(Formtastic::I18n.t(:duck_pond, :scope => [:custom_scope], :ducks => 15)).to eq('15 ducks in a pond')
58
58
  end
59
59
 
60
60
  it "should be possible to override default values" do
61
- Formtastic::I18n.t(:required, :default => 'Nothing found!').should == 'Nothing found!'
61
+ expect(Formtastic::I18n.t(:required, :default => 'Nothing found!')).to eq('Nothing found!')
62
62
  end
63
63
 
64
64
  end
@@ -71,7 +71,7 @@ describe 'Formtastic::I18n' do
71
71
 
72
72
  it "should use default strings" do
73
73
  (Formtastic::I18n::DEFAULT_VALUES.keys).each do |key|
74
- Formtastic::I18n.t(key, :model => '%{model}').should == Formtastic::I18n::DEFAULT_VALUES[key]
74
+ expect(Formtastic::I18n.t(key, :model => '%{model}')).to eq(Formtastic::I18n::DEFAULT_VALUES[key])
75
75
  end
76
76
  end
77
77
 
@@ -98,8 +98,8 @@ describe 'Formtastic::I18n' do
98
98
  }
99
99
  }}
100
100
 
101
- @new_post.stub(:title)
102
- @new_post.stub(:column_for_attribute).with(:title).and_return(double('column', :type => :string, :limit => 255))
101
+ allow(@new_post).to receive(:title)
102
+ allow(@new_post).to receive(:column_for_attribute).with(:title).and_return(double('column', :type => :string, :limit => 255))
103
103
  end
104
104
 
105
105
  after do
@@ -108,7 +108,7 @@ describe 'Formtastic::I18n' do
108
108
 
109
109
  it "lookup scopes should be defined" do
110
110
  with_config :i18n_lookups_by_default, true do
111
- lambda { Formtastic::I18n::SCOPES }.should_not raise_error
111
+ expect { Formtastic::I18n::SCOPES }.not_to raise_error
112
112
  end
113
113
  end
114
114
 
@@ -117,7 +117,7 @@ describe 'Formtastic::I18n' do
117
117
  concat(semantic_form_for(@new_post) do |builder|
118
118
  concat(builder.input(:title))
119
119
  end)
120
- output_buffer.should have_tag("form label", /Hello post!/)
120
+ expect(output_buffer).to have_tag("form label", :text => /Hello post!/)
121
121
  end
122
122
  end
123
123
 
@@ -126,7 +126,7 @@ describe 'Formtastic::I18n' do
126
126
  concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
127
127
  concat(builder.input(:title))
128
128
  end)
129
- output_buffer.should have_tag("form label", /Hello project!/)
129
+ expect(output_buffer).to have_tag("form label", :text => /Hello project!/)
130
130
  end
131
131
  end
132
132
 
@@ -135,7 +135,7 @@ describe 'Formtastic::I18n' do
135
135
  concat(semantic_form_for(:project, :url => 'http://test.host') do |builder|
136
136
  concat(builder.input(:author))
137
137
  end)
138
- output_buffer.should have_tag("form label", /Author/)
138
+ expect(output_buffer).to have_tag("form label", :text => /Author/)
139
139
  end
140
140
  end
141
141
 
@@ -146,7 +146,7 @@ describe 'Formtastic::I18n' do
146
146
  concat(f.input(:name))
147
147
  end)
148
148
  end)
149
- output_buffer.should have_tag("form label", /Hello author name!/)
149
+ expect(output_buffer).to have_tag("form label", :text => /Hello author name!/)
150
150
  end
151
151
  end
152
152
 
@@ -157,7 +157,7 @@ describe 'Formtastic::I18n' do
157
157
  concat(f.input(:name))
158
158
  end
159
159
  end)
160
- output_buffer.should have_tag("form label", /Hello author name!/)
160
+ expect(output_buffer).to have_tag("form label", :text => /Hello author name!/)
161
161
  end
162
162
  end
163
163
 
@@ -168,7 +168,7 @@ describe 'Formtastic::I18n' do
168
168
  concat(f.input(:title))
169
169
  end
170
170
  end)
171
- output_buffer.should have_tag("form label", /Hello project!/)
171
+ expect(output_buffer).to have_tag("form label", :text => /Hello project!/)
172
172
  end
173
173
  end
174
174
 
@@ -179,7 +179,7 @@ describe 'Formtastic::I18n' do
179
179
  concat(f.input(:name))
180
180
  end
181
181
  end)
182
- output_buffer.should have_tag("form label", /Hello author name!/)
182
+ expect(output_buffer).to have_tag("form label", :text => /Hello author name!/)
183
183
  end
184
184
  end
185
185
 
@@ -188,7 +188,7 @@ describe 'Formtastic::I18n' do
188
188
  concat(semantic_form_for(@new_post) do |builder|
189
189
  concat(builder.input(:body))
190
190
  end)
191
- output_buffer.should have_tag("form label", /Elaborate/)
191
+ expect(output_buffer).to have_tag("form label", :text => /Elaborate/)
192
192
  end
193
193
  end
194
194
 
@@ -199,7 +199,7 @@ describe 'Formtastic::I18n' do
199
199
  concat(f.input(:login))
200
200
  end)
201
201
  end)
202
- output_buffer.should have_tag("form label", /Hello login/)
202
+ expect(output_buffer).to have_tag("form label", :text => /Hello login/)
203
203
  end
204
204
  end
205
205
 
@@ -2,7 +2,7 @@
2
2
  require 'spec_helper'
3
3
  require 'formtastic/input_class_finder'
4
4
 
5
- describe Formtastic::InputClassFinder do
5
+ RSpec.describe Formtastic::InputClassFinder do
6
6
  it_behaves_like 'Specialized Class Finder' do
7
7
  let(:default) { Formtastic::Inputs }
8
8
  let(:namespaces_setting) { :input_namespaces }
@@ -0,0 +1,76 @@
1
+ require 'fast_spec_helper'
2
+ require 'inputs/base/collections'
3
+
4
+ class MyInput
5
+ include Formtastic::Inputs::Base::Collections
6
+ end
7
+
8
+ RSpec.describe MyInput do
9
+ let(:builder) { double }
10
+ let(:template) { double }
11
+ let(:model_class) { double }
12
+ let(:model) { double(:class => model_class) }
13
+ let(:model_name) { "post" }
14
+ let(:method) { double }
15
+ let(:options) { Hash.new }
16
+
17
+ let(:instance) { MyInput.new(builder, template, model, model_name, method, options) }
18
+
19
+ # class Whatever < ActiveRecord::Base
20
+ # enum :status => [:active, :archived]
21
+ # end
22
+ #
23
+ # Whatever.statuses
24
+ #
25
+ # Whatever.new.status
26
+ #
27
+ # f.input :status
28
+ describe "#collection_from_enum" do
29
+
30
+ let(:method) { :status }
31
+
32
+ context "when an enum is defined for the method" do
33
+ before do
34
+ statuses = ActiveSupport::HashWithIndifferentAccess.new("active"=>0, "inactive"=>1)
35
+ allow(model_class).to receive(:statuses) { statuses }
36
+ allow(model).to receive(:defined_enums) { {"status" => statuses } }
37
+ end
38
+
39
+ context 'no translations available' do
40
+ it 'returns an Array of EnumOption objects based on the enum options hash' do
41
+ expect(instance.collection_from_enum).to eq [["Active", "active"],["Inactive", "inactive"]]
42
+ end
43
+ end
44
+
45
+ context 'with translations' do
46
+ before do
47
+ ::I18n.backend.store_translations :en, :activerecord => {
48
+ :attributes => {
49
+ :post => {
50
+ :statuses => {
51
+ :active => "I am active",
52
+ :inactive => "I am inactive"
53
+ }
54
+ }
55
+ }
56
+ }
57
+ end
58
+ it 'returns an Array of EnumOption objects based on the enum options hash' do
59
+ expect(instance.collection_from_enum).to eq [["I am active", "active"],["I am inactive", "inactive"]]
60
+ end
61
+
62
+ after do
63
+ ::I18n.backend.store_translations :en, {}
64
+ end
65
+ end
66
+ end
67
+
68
+ context "when an enum is not defined" do
69
+ it 'returns nil' do
70
+ expect(instance.collection_from_enum).to eq nil
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+
@@ -0,0 +1,480 @@
1
+ require 'fast_spec_helper'
2
+ require 'active_model'
3
+ require 'inputs/base/validations'
4
+
5
+ class MyInput
6
+ attr_accessor :validations
7
+ include Formtastic::Inputs::Base::Validations
8
+
9
+ def validations?
10
+ true
11
+ end
12
+ end
13
+
14
+ RSpec.describe MyInput do
15
+ let(:builder) { double }
16
+ let(:template) { double }
17
+ let(:model_class) { double }
18
+ let(:model) { double(:class => model_class) }
19
+ let(:model_name) { "post" }
20
+ let(:method) { double }
21
+ let(:options) { Hash.new }
22
+ let(:validator) { double }
23
+ let(:instance) do
24
+ MyInput.new(builder, template, model, model_name, method, options).tap do |my_input|
25
+ my_input.validations = validations
26
+ end
27
+ end
28
+
29
+ describe '#required?' do
30
+ context 'with a single validator' do
31
+ let(:validations) { [validator] }
32
+
33
+ context 'with options[:required] being true' do
34
+ let(:options) { {required: true} }
35
+
36
+ it 'is required' do
37
+ expect(instance.required?).to be_truthy
38
+ end
39
+ end
40
+
41
+ context 'with options[:required] being false' do
42
+ let(:options) { {required: false} }
43
+
44
+ it 'is not required' do
45
+ expect(instance.required?).to be_falsey
46
+ end
47
+ end
48
+
49
+ context 'with negated validation' do
50
+ it 'is not required' do
51
+ instance.not_required_through_negated_validation!
52
+ expect(instance.required?).to be_falsey
53
+ end
54
+ end
55
+
56
+ context 'with presence validator' do
57
+ let (:validator) { double(options: {}, kind: :presence) }
58
+
59
+ it 'is required' do
60
+ expect(instance.required?).to be_truthy
61
+ end
62
+
63
+ context 'with options[:on] as symbol' do
64
+ context 'with save context' do
65
+ let (:validator) { double(options: {on: :save}, kind: :presence) }
66
+
67
+ it 'is required' do
68
+ expect(instance.required?).to be_truthy
69
+ end
70
+ end
71
+
72
+ context 'with create context' do
73
+ let (:validator) { double(options: {on: :create}, kind: :presence) }
74
+
75
+ it 'is required for new records' do
76
+ allow(model).to receive(:new_record?).and_return(true)
77
+ expect(instance.required?).to be_truthy
78
+ end
79
+
80
+ it 'is not required for existing records' do
81
+ allow(model).to receive(:new_record?).and_return(false)
82
+ expect(instance.required?).to be_falsey
83
+ end
84
+ end
85
+
86
+ context 'with update context' do
87
+ let (:validator) { double(options: {on: :update}, kind: :presence) }
88
+
89
+ it 'is not required for new records' do
90
+ allow(model).to receive(:new_record?).and_return(true)
91
+ expect(instance.required?).to be_falsey
92
+ end
93
+
94
+ it 'is required for existing records' do
95
+ allow(model).to receive(:new_record?).and_return(false)
96
+ expect(instance.required?).to be_truthy
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'with options[:on] as array' do
102
+ context 'with save context' do
103
+ let (:validator) { double(options: {on: [:save]}, kind: :presence) }
104
+
105
+ it 'is required' do
106
+ expect(instance.required?).to be_truthy
107
+ end
108
+ end
109
+
110
+ context 'with create context' do
111
+ let (:validator) { double(options: {on: [:create]}, kind: :presence) }
112
+
113
+ it 'is required for new records' do
114
+ allow(model).to receive(:new_record?).and_return(true)
115
+ expect(instance.required?).to be_truthy
116
+ end
117
+
118
+ it 'is not required for existing records' do
119
+ allow(model).to receive(:new_record?).and_return(false)
120
+ expect(instance.required?).to be_falsey
121
+ end
122
+ end
123
+
124
+ context 'with update context' do
125
+ let (:validator) { double(options: {on: [:update]}, kind: :presence) }
126
+
127
+ it 'is not required for new records' do
128
+ allow(model).to receive(:new_record?).and_return(true)
129
+ expect(instance.required?).to be_falsey
130
+ end
131
+
132
+ it 'is required for existing records' do
133
+ allow(model).to receive(:new_record?).and_return(false)
134
+ expect(instance.required?).to be_truthy
135
+ end
136
+ end
137
+
138
+ context 'with save and create context' do
139
+ let (:validator) { double(options: {on: [:save, :create]}, kind: :presence) }
140
+
141
+ it 'is required for new records' do
142
+ allow(model).to receive(:new_record?).and_return(true)
143
+ expect(instance.required?).to be_truthy
144
+ end
145
+
146
+ it 'is required for existing records' do
147
+ allow(model).to receive(:new_record?).and_return(false)
148
+ expect(instance.required?).to be_truthy
149
+ end
150
+ end
151
+
152
+ context 'with save and update context' do
153
+ let (:validator) { double(options: {on: [:save, :create]}, kind: :presence) }
154
+
155
+ it 'is required for new records' do
156
+ allow(model).to receive(:new_record?).and_return(true)
157
+ expect(instance.required?).to be_truthy
158
+ end
159
+
160
+ it 'is required for existing records' do
161
+ allow(model).to receive(:new_record?).and_return(false)
162
+ expect(instance.required?).to be_truthy
163
+ end
164
+ end
165
+
166
+ context 'with create and update context' do
167
+ let (:validator) { double(options: {on: [:create, :update]}, kind: :presence) }
168
+
169
+ it 'is required for new records' do
170
+ allow(model).to receive(:new_record?).and_return(true)
171
+ expect(instance.required?).to be_truthy
172
+ end
173
+
174
+ it 'is required for existing records' do
175
+ allow(model).to receive(:new_record?).and_return(false)
176
+ expect(instance.required?).to be_truthy
177
+ end
178
+ end
179
+
180
+ context 'with save and other context' do
181
+ let (:validator) { double(options: {on: [:save, :foo]}, kind: :presence) }
182
+
183
+ it 'is required for new records' do
184
+ allow(model).to receive(:new_record?).and_return(true)
185
+ expect(instance.required?).to be_truthy
186
+ end
187
+
188
+ it 'is required for existing records' do
189
+ allow(model).to receive(:new_record?).and_return(false)
190
+ expect(instance.required?).to be_truthy
191
+ end
192
+ end
193
+
194
+ context 'with create and other context' do
195
+ let (:validator) { double(options: {on: [:create, :foo]}, kind: :presence) }
196
+
197
+ it 'is required for new records' do
198
+ allow(model).to receive(:new_record?).and_return(true)
199
+ expect(instance.required?).to be_truthy
200
+ end
201
+
202
+ it 'is not required for existing records' do
203
+ allow(model).to receive(:new_record?).and_return(false)
204
+ expect(instance.required?).to be_falsey
205
+ end
206
+ end
207
+
208
+ context 'with update and other context' do
209
+ let (:validator) { double(options: {on: [:update, :foo]}, kind: :presence) }
210
+
211
+ it 'is not required for new records' do
212
+ allow(model).to receive(:new_record?).and_return(true)
213
+ expect(instance.required?).to be_falsey
214
+ end
215
+
216
+ it 'is required for existing records' do
217
+ allow(model).to receive(:new_record?).and_return(false)
218
+ expect(instance.required?).to be_truthy
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ context 'with inclusion validator' do
225
+ context 'with allow blank' do
226
+ let (:validator) { double(options: {allow_blank: true}, kind: :inclusion) }
227
+
228
+ it 'is not required' do
229
+ expect(instance.required?).to be_falsey
230
+ end
231
+ end
232
+
233
+ context 'without allow blank' do
234
+ let (:validator) { double(options: {allow_blank: false}, kind: :inclusion) }
235
+
236
+ it 'is required' do
237
+ expect(instance.required?).to be_truthy
238
+ end
239
+ end
240
+ end
241
+
242
+ context 'with a length validator' do
243
+ context 'with allow blank' do
244
+ let (:validator) { double(options: {allow_blank: true}, kind: :length) }
245
+
246
+ it 'is not required' do
247
+ expect(instance.required?).to be_falsey
248
+ end
249
+ end
250
+
251
+ context 'without allow blank' do
252
+ let (:validator) { double(options: {allow_blank: false}, kind: :length) }
253
+
254
+ it 'is not required' do
255
+ expect(instance.required?).to be_falsey
256
+ end
257
+
258
+ context 'with a minimum > 0' do
259
+ let (:validator) { double(options: {allow_blank: false, minimum: 1}, kind: :length) }
260
+
261
+ it 'is required' do
262
+ expect(instance.required?).to be_truthy
263
+ end
264
+ end
265
+
266
+ context 'with a minimum <= 0' do
267
+ let (:validator) { double(options: {allow_blank: false, minimum: 0}, kind: :length) }
268
+
269
+ it 'is not required' do
270
+ expect(instance.required?).to be_falsey
271
+ end
272
+ end
273
+
274
+ context 'with a defined range starting with > 0' do
275
+ let (:validator) { double(options: {allow_blank: false, within: 1..5}, kind: :length) }
276
+
277
+ it 'is required' do
278
+ expect(instance.required?).to be_truthy
279
+ end
280
+ end
281
+
282
+ context 'with a defined range starting with <= 0' do
283
+ let (:validator) { double(options: {allow_blank: false, within: 0..5}, kind: :length) }
284
+
285
+ it 'is not required' do
286
+ expect(instance.required?).to be_falsey
287
+ end
288
+ end
289
+ end
290
+ end
291
+
292
+ context 'with another validator' do
293
+ let (:validator) { double(options: {allow_blank: true}, kind: :foo) }
294
+
295
+ it 'is not required' do
296
+ expect(instance.required?).to be_falsey
297
+ end
298
+ end
299
+ end
300
+
301
+ context 'with multiple validators' do
302
+ let(:validations) { [validator1, validator2] }
303
+
304
+ context 'with a on create presence validator and a on update presence validator' do
305
+ let(:validator1) { double(options: {on: :create}, kind: :presence) }
306
+ let(:validator2) { double(options: {}, kind: :presence) }
307
+
308
+ before :example do
309
+ allow(model).to receive(:new_record?).and_return(false)
310
+ end
311
+
312
+ it 'is required' do
313
+ expect(instance.required?).to be_truthy
314
+ end
315
+ end
316
+
317
+ context 'with a on create presence validator and a presence validator' do
318
+ let (:validator1) { double(options: {on: :create}, kind: :presence) }
319
+ let (:validator2) { double(options: {}, kind: :presence) }
320
+
321
+ before :example do
322
+ allow(model).to receive(:new_record?).and_return(false)
323
+ end
324
+
325
+ it 'is required' do
326
+ expect(instance.required?).to be_truthy
327
+ end
328
+ end
329
+
330
+ context 'with a on create presence validator and a allow blank inclusion validator' do
331
+ let(:validator1) { double(options: {on: :create}, kind: :presence) }
332
+ let(:validator2) { double(options: {allow_blank: true}, kind: :inclusion) }
333
+
334
+ before :example do
335
+ allow(model).to receive(:new_record?).and_return(false)
336
+ end
337
+
338
+ it 'is required' do
339
+ expect(instance.required?).to be_falsey
340
+ end
341
+ end
342
+ end
343
+ end
344
+
345
+ describe '#validation_min' do
346
+ let(:validations) { [validator] }
347
+
348
+ context 'with a greater_than numericality validator' do
349
+ let(:validator) { double(options: { greater_than: option_value }, kind: :numericality) }
350
+
351
+ context 'with a symbol' do
352
+ let(:option_value) { :a_symbol }
353
+
354
+ it 'returns one greater' do
355
+ allow(model).to receive(:send).with(option_value).and_return(14)
356
+ expect(instance.validation_min).to eq 15
357
+ end
358
+ end
359
+
360
+ context 'with a proc' do
361
+ let(:option_value) { Proc.new { 10 } }
362
+
363
+ it 'returns one greater' do
364
+ expect(instance.validation_min).to eq 11
365
+ end
366
+ end
367
+
368
+ context 'with a number' do
369
+ let(:option_value) { 8 }
370
+
371
+ it 'returns one greater' do
372
+ expect(instance.validation_min).to eq 9
373
+ end
374
+ end
375
+ end
376
+
377
+ context 'with a greater_than_or_equal_to numericality validator' do
378
+ let(:validator) do
379
+ double(
380
+ options: { greater_than_or_equal_to: option_value },
381
+ kind: :numericality
382
+ )
383
+ end
384
+
385
+ context 'with a symbol' do
386
+ let(:option_value) { :a_symbol }
387
+
388
+ it 'returns the instance method amount' do
389
+ allow(model).to receive(:send).with(option_value).and_return(14)
390
+ expect(instance.validation_min).to eq 14
391
+ end
392
+ end
393
+
394
+ context 'with a proc' do
395
+ let(:option_value) { Proc.new { 10 } }
396
+
397
+ it 'returns the proc amount' do
398
+ expect(instance.validation_min).to eq 10
399
+ end
400
+ end
401
+
402
+ context 'with a number' do
403
+ let(:option_value) { 8 }
404
+
405
+ it 'returns the number' do
406
+ expect(instance.validation_min).to eq 8
407
+ end
408
+ end
409
+ end
410
+ end
411
+
412
+ describe '#validation_max' do
413
+ let(:validations) do
414
+ [
415
+ ActiveModel::Validations::NumericalityValidator.new(
416
+ validator_options.merge(attributes: :an_attribute)
417
+ )
418
+ ]
419
+ end
420
+
421
+ context 'with a less_than numericality validator' do
422
+ let(:validator_options) { { less_than: option_value } }
423
+
424
+ context 'with a symbol' do
425
+ let(:option_value) { :a_symbol }
426
+
427
+ it 'returns one less' do
428
+ allow(model).to receive(:send).with(option_value).and_return(14)
429
+ expect(instance.validation_max).to eq 13
430
+ end
431
+ end
432
+
433
+ context 'with a proc' do
434
+ let(:option_value) { proc { 10 } }
435
+
436
+ it 'returns one less' do
437
+ expect(instance.validation_max).to eq 9
438
+ end
439
+ end
440
+
441
+ context 'with a number' do
442
+ let(:option_value) { 8 }
443
+
444
+ it 'returns one less' do
445
+ expect(instance.validation_max).to eq 7
446
+ end
447
+ end
448
+ end
449
+
450
+ context 'with a less_than_or_equal_to numericality validator' do
451
+ let(:validator_options) { { less_than_or_equal_to: option_value } }
452
+
453
+ context 'with a symbol' do
454
+ let(:option_value) { :a_symbol }
455
+
456
+ it 'returns the instance method amount' do
457
+ allow(model).to receive(:send).with(option_value).and_return(14)
458
+ expect(instance.validation_max).to eq 14
459
+ end
460
+ end
461
+
462
+ context 'with a proc' do
463
+ let(:option_value) { proc { 10 } }
464
+
465
+ it 'returns the proc amount' do
466
+ expect(instance.validation_max).to eq 10
467
+ end
468
+ end
469
+
470
+ context 'with a number' do
471
+ let(:option_value) { 8 }
472
+
473
+ it 'returns the number' do
474
+ expect(instance.validation_max).to eq 8
475
+ end
476
+ end
477
+ end
478
+ end
479
+ end
480
+