sp-validates_timeliness 3.1.2

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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +183 -0
  3. data/LICENSE +20 -0
  4. data/README.md +323 -0
  5. data/Rakefile +30 -0
  6. data/init.rb +1 -0
  7. data/lib/generators/validates_timeliness/install_generator.rb +16 -0
  8. data/lib/generators/validates_timeliness/templates/en.yml +16 -0
  9. data/lib/generators/validates_timeliness/templates/validates_timeliness.rb +40 -0
  10. data/lib/jc-validates_timeliness.rb +1 -0
  11. data/lib/validates_timeliness.rb +70 -0
  12. data/lib/validates_timeliness/attribute_methods.rb +95 -0
  13. data/lib/validates_timeliness/conversion.rb +70 -0
  14. data/lib/validates_timeliness/extensions.rb +14 -0
  15. data/lib/validates_timeliness/extensions/date_time_select.rb +61 -0
  16. data/lib/validates_timeliness/extensions/multiparameter_handler.rb +80 -0
  17. data/lib/validates_timeliness/helper_methods.rb +23 -0
  18. data/lib/validates_timeliness/orm/active_record.rb +53 -0
  19. data/lib/validates_timeliness/orm/mongoid.rb +63 -0
  20. data/lib/validates_timeliness/railtie.rb +15 -0
  21. data/lib/validates_timeliness/validator.rb +117 -0
  22. data/lib/validates_timeliness/version.rb +3 -0
  23. data/spec/spec_helper.rb +109 -0
  24. data/spec/support/config_helper.rb +36 -0
  25. data/spec/support/model_helpers.rb +27 -0
  26. data/spec/support/tag_matcher.rb +35 -0
  27. data/spec/support/test_model.rb +59 -0
  28. data/spec/validates_timeliness/attribute_methods_spec.rb +86 -0
  29. data/spec/validates_timeliness/conversion_spec.rb +234 -0
  30. data/spec/validates_timeliness/extensions/date_time_select_spec.rb +163 -0
  31. data/spec/validates_timeliness/extensions/multiparameter_handler_spec.rb +44 -0
  32. data/spec/validates_timeliness/helper_methods_spec.rb +30 -0
  33. data/spec/validates_timeliness/orm/active_record_spec.rb +244 -0
  34. data/spec/validates_timeliness/orm/mongoid_spec.rb +189 -0
  35. data/spec/validates_timeliness/validator/after_spec.rb +57 -0
  36. data/spec/validates_timeliness/validator/before_spec.rb +57 -0
  37. data/spec/validates_timeliness/validator/is_at_spec.rb +61 -0
  38. data/spec/validates_timeliness/validator/on_or_after_spec.rb +57 -0
  39. data/spec/validates_timeliness/validator/on_or_before_spec.rb +57 -0
  40. data/spec/validates_timeliness/validator_spec.rb +246 -0
  41. data/spec/validates_timeliness_spec.rb +43 -0
  42. data/validates_timeliness.gemspec +25 -0
  43. metadata +157 -0
@@ -0,0 +1,35 @@
1
+ require 'nokogiri'
2
+
3
+ module TagMatcher
4
+ extend RSpec::Matchers::DSL
5
+
6
+ matcher :have_tag do |selector|
7
+ match do |subject|
8
+ matches = doc(subject).search(selector)
9
+
10
+ if @inner_text
11
+ matches = matches.select { |element| element.inner_text == @inner_text }
12
+ end
13
+
14
+ matches.any?
15
+ end
16
+
17
+ chain :with_inner_text do |inner_text|
18
+ @inner_text = inner_text
19
+ end
20
+
21
+ private
22
+
23
+ def body(subject)
24
+ if subject.respond_to?(:body)
25
+ subject.body
26
+ else
27
+ subject.to_s
28
+ end
29
+ end
30
+
31
+ def doc(subject)
32
+ @doc ||= Nokogiri::HTML(body(subject))
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,59 @@
1
+ module TestModel
2
+ extend ActiveSupport::Concern
3
+ extend ActiveModel::Translation
4
+ include ActiveModel::Validations
5
+ include ActiveModel::AttributeMethods
6
+
7
+ included do
8
+ attribute_method_suffix "="
9
+ cattr_accessor :model_attributes
10
+ end
11
+
12
+ module ClassMethods
13
+ def attribute(name, type)
14
+ self.model_attributes ||= {}
15
+ self.model_attributes[name] = type
16
+ end
17
+
18
+ def define_method_attribute=(attr_name)
19
+ generated_attribute_methods.module_eval("def #{attr_name}=(new_value); @attributes['#{attr_name}']=self.class.type_cast('#{attr_name}', new_value); end", __FILE__, __LINE__)
20
+ end
21
+
22
+ def define_method_attribute(attr_name)
23
+ generated_attribute_methods.module_eval("def #{attr_name}; @attributes['#{attr_name}']; end", __FILE__, __LINE__)
24
+ end
25
+
26
+ def type_cast(attr_name, value)
27
+ return value unless value.is_a?(String)
28
+ value.send("to_#{model_attributes[attr_name.to_sym]}") rescue nil
29
+ end
30
+ end
31
+
32
+ def initialize(attributes = nil)
33
+ @attributes = self.class.model_attributes.keys.inject({}) do |hash, column|
34
+ hash[column.to_s] = nil
35
+ hash
36
+ end
37
+ self.attributes = attributes unless attributes.nil?
38
+ end
39
+
40
+ def attributes
41
+ @attributes
42
+ end
43
+
44
+ def attributes=(new_attributes={})
45
+ new_attributes.each do |key, value|
46
+ send "#{key}=", value
47
+ end
48
+ end
49
+
50
+ def method_missing(method_id, *args, &block)
51
+ if match_attribute_method?(method_id.to_s)
52
+ self.class.define_attribute_methods self.class.model_attributes.keys
53
+ send(method_id, *args, &block)
54
+ else
55
+ super
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe ValidatesTimeliness::AttributeMethods do
4
+ it 'should define _timeliness_raw_value_for instance method' do
5
+ expect(PersonWithShim.new).to respond_to(:_timeliness_raw_value_for)
6
+ end
7
+
8
+ describe ".timeliness_validated_attributes" do
9
+ it 'should return attributes validated with plugin validator' do
10
+ PersonWithShim.timeliness_validated_attributes = []
11
+ PersonWithShim.validates_date :birth_date
12
+ PersonWithShim.validates_time :birth_time
13
+ PersonWithShim.validates_datetime :birth_datetime
14
+
15
+ expect(PersonWithShim.timeliness_validated_attributes).to eq([ :birth_date, :birth_time, :birth_datetime ])
16
+ end
17
+ end
18
+
19
+ context "attribute write method" do
20
+ class PersonWithCache
21
+ include TestModel
22
+ include TestModelShim
23
+ attribute :birth_date, :date
24
+ attribute :birth_time, :time
25
+ attribute :birth_datetime, :datetime
26
+ validates_date :birth_date
27
+ validates_time :birth_time
28
+ validates_datetime :birth_datetime
29
+ end
30
+
31
+ it 'should cache attribute raw value' do
32
+ r = PersonWithCache.new
33
+ r.birth_datetime = date_string = '2010-01-01'
34
+ expect(r._timeliness_raw_value_for('birth_datetime')).to eq(date_string)
35
+ end
36
+
37
+ it 'should not overwrite user defined methods' do
38
+ e = Employee.new
39
+ e.birth_date = '2010-01-01'
40
+ expect(e.redefined_birth_date_called).to be_truthy
41
+ end
42
+
43
+ it 'should be undefined if model class has dynamic attribute methods reset' do
44
+ # Force method definitions
45
+ PersonWithShim.validates_date :birth_date
46
+ r = PersonWithShim.new
47
+ r.birth_date = Time.now
48
+
49
+ write_method = RUBY_VERSION < '1.9' ? 'birth_date=' : :birth_date=
50
+
51
+ expect(PersonWithShim.send(:generated_timeliness_methods).instance_methods).to include(write_method)
52
+
53
+ PersonWithShim.undefine_attribute_methods
54
+
55
+ expect(PersonWithShim.send(:generated_timeliness_methods).instance_methods).not_to include(write_method)
56
+ end
57
+
58
+ context "with plugin parser" do
59
+ with_config(:use_plugin_parser, true)
60
+
61
+ class PersonWithParser
62
+ include TestModel
63
+ include TestModelShim
64
+ attribute :birth_date, :date
65
+ attribute :birth_time, :time
66
+ attribute :birth_datetime, :datetime
67
+ validates_date :birth_date
68
+ validates_time :birth_time
69
+ validates_datetime :birth_datetime
70
+ end
71
+
72
+ it 'should parse a string value' do
73
+ expect(Timeliness::Parser).to receive(:parse)
74
+ r = PersonWithParser.new
75
+ r.birth_date = '2010-01-01'
76
+ end
77
+
78
+ end
79
+ end
80
+
81
+ context "before_type_cast method" do
82
+ it 'should not be defined if ORM does not support it' do
83
+ expect(PersonWithShim.new).not_to respond_to(:birth_datetime_before_type_cast)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,234 @@
1
+ require 'spec_helper'
2
+
3
+ describe ValidatesTimeliness::Conversion do
4
+ include ValidatesTimeliness::Conversion
5
+
6
+ let(:options) { Hash.new }
7
+
8
+ before do
9
+ Timecop.freeze(Time.mktime(2010, 1, 1, 0, 0, 0))
10
+ end
11
+
12
+ describe "#type_cast_value" do
13
+ describe "for date type" do
14
+ it "should return same value for date value" do
15
+ expect(type_cast_value(Date.new(2010, 1, 1), :date)).to eq(Date.new(2010, 1, 1))
16
+ end
17
+
18
+ it "should return date part of time value" do
19
+ expect(type_cast_value(Time.mktime(2010, 1, 1, 0, 0, 0), :date)).to eq(Date.new(2010, 1, 1))
20
+ end
21
+
22
+ it "should return date part of datetime value" do
23
+ expect(type_cast_value(DateTime.new(2010, 1, 1, 0, 0, 0), :date)).to eq(Date.new(2010, 1, 1))
24
+ end
25
+
26
+ it 'should return nil for invalid value types' do
27
+ expect(type_cast_value(12, :date)).to eq(nil)
28
+ end
29
+ end
30
+
31
+ describe "for time type" do
32
+ it "should return same value for time value matching dummy date part" do
33
+ expect(type_cast_value(Time.utc(2000, 1, 1, 0, 0, 0), :time)).to eq(Time.utc(2000, 1, 1, 0, 0, 0))
34
+ end
35
+
36
+ it "should return dummy time value with same time part for time value with different date" do
37
+ expect(type_cast_value(Time.utc(2010, 1, 1, 0, 0, 0), :time)).to eq(Time.utc(2000, 1, 1, 0, 0, 0))
38
+ end
39
+
40
+ it "should return dummy time only for date value" do
41
+ expect(type_cast_value(Date.new(2010, 1, 1), :time)).to eq(Time.utc(2000, 1, 1, 0, 0, 0))
42
+ end
43
+
44
+ it "should return dummy date with time part for datetime value" do
45
+ expect(type_cast_value(DateTime.civil_from_format(:utc, 2010, 1, 1, 12, 34, 56), :time)).to eq(Time.utc(2000, 1, 1, 12, 34, 56))
46
+ end
47
+
48
+ it 'should return nil for invalid value types' do
49
+ expect(type_cast_value(12, :time)).to eq(nil)
50
+ end
51
+ end
52
+
53
+ describe "for datetime type" do
54
+ it "should return Date as Time value" do
55
+ expect(type_cast_value(Date.new(2010, 1, 1), :datetime)).to eq(Time.local_time(2010, 1, 1, 0, 0, 0))
56
+ end
57
+
58
+ it "should return same Time value" do
59
+ value = Time.utc(2010, 1, 1, 12, 34, 56)
60
+ expect(type_cast_value(Time.utc(2010, 1, 1, 12, 34, 56), :datetime)).to eq(value)
61
+ end
62
+
63
+ it "should return as Time with same component values" do
64
+ expect(type_cast_value(DateTime.civil_from_format(:utc, 2010, 1, 1, 12, 34, 56), :datetime)).to eq(Time.utc(2010, 1, 1, 12, 34, 56))
65
+ end
66
+
67
+ it "should return same Time in correct zone if timezone aware" do
68
+ @timezone_aware = true
69
+ value = Time.utc(2010, 1, 1, 12, 34, 56)
70
+ result = type_cast_value(value, :datetime)
71
+ expect(result).to eq(Time.zone.local(2010, 1, 1, 23, 34, 56))
72
+ expect(result.zone).to eq('AEDT') # 'Australia/Melbourne'
73
+ end
74
+
75
+ it 'should return nil for invalid value types' do
76
+ expect(type_cast_value(12, :datetime)).to eq(nil)
77
+ end
78
+ end
79
+
80
+ describe "ignore_usec option" do
81
+ let(:options) { {:ignore_usec => true} }
82
+
83
+ it "should ignore usec on time values when evaluated" do
84
+ value = Time.utc(2010, 1, 1, 12, 34, 56, 10000)
85
+ expect(type_cast_value(value, :datetime)).to eq(Time.utc(2010, 1, 1, 12, 34, 56))
86
+ end
87
+
88
+ it "should ignore usec and return time in correct zone if timezone aware" do
89
+ @timezone_aware = true
90
+ value = Time.utc(2010, 1, 1, 12, 34, 56, 10000)
91
+ result = type_cast_value(value, :datetime)
92
+ expect(result).to eq(Time.zone.local(2010, 1, 1, 23, 34, 56))
93
+ expect(result.zone).to eq('AEDT') # 'Australia/Melbourne'
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "#dummy_time" do
99
+ it 'should return Time with dummy date values but same time components' do
100
+ expect(dummy_time(Time.utc(2010, 11, 22, 12, 34, 56))).to eq(Time.utc(2000, 1, 1, 12, 34, 56))
101
+ end
102
+
103
+ it 'should return same value for Time which already has dummy date values' do
104
+ expect(dummy_time(Time.utc(2000, 1, 1, 12, 34, 56))).to eq(Time.utc(2000, 1, 1, 12, 34, 56))
105
+ end
106
+
107
+ it 'should return time component values shifted to current zone if timezone aware' do
108
+ @timezone_aware = true
109
+ expect(dummy_time(Time.utc(2000, 1, 1, 12, 34, 56))).to eq(Time.zone.local(2000, 1, 1, 23, 34, 56))
110
+ end
111
+
112
+ it 'should return base dummy time value for Date value' do
113
+ expect(dummy_time(Date.new(2010, 11, 22))).to eq(Time.utc(2000, 1, 1, 0, 0, 0))
114
+ end
115
+
116
+ describe "with custom dummy date" do
117
+ it 'should return dummy time with custom dummy date' do
118
+ with_config(:dummy_date_for_time_type, [2010, 1, 1] ) do
119
+ expect(dummy_time(Time.utc(1999, 11, 22, 12, 34, 56))).to eq(Time.utc(2010, 1, 1, 12, 34, 56))
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ describe "#evaluate_option_value" do
126
+ let(:person) { Person.new }
127
+
128
+ it 'should return Date object as is' do
129
+ value = Date.new(2010,1,1)
130
+ expect(evaluate_option_value(value, person)).to eq(value)
131
+ end
132
+
133
+ it 'should return Time object as is' do
134
+ value = Time.mktime(2010,1,1)
135
+ expect(evaluate_option_value(value, person)).to eq(value)
136
+ end
137
+
138
+ it 'should return DateTime object as is' do
139
+ value = DateTime.new(2010,1,1,0,0,0)
140
+ expect(evaluate_option_value(value, person)).to eq(value)
141
+ end
142
+
143
+ it 'should return Time value returned from proc with 0 arity' do
144
+ value = Time.mktime(2010,1,1)
145
+ expect(evaluate_option_value(lambda { value }, person)).to eq(value)
146
+ end
147
+
148
+ it 'should return Time value returned by record attribute call in proc arity of 1' do
149
+ value = Time.mktime(2010,1,1)
150
+ person.birth_time = value
151
+ expect(evaluate_option_value(lambda {|r| r.birth_time }, person)).to eq(value)
152
+ end
153
+
154
+ it 'should return Time value for attribute method symbol which returns Time' do
155
+ value = Time.mktime(2010,1,1)
156
+ person.birth_time = value
157
+ expect(evaluate_option_value(:birth_time, person)).to eq(value)
158
+ end
159
+
160
+ it 'should return Time value is default zone from string time value' do
161
+ value = '2010-01-01 12:00:00'
162
+ expect(evaluate_option_value(value, person)).to eq(Time.utc(2010,1,1,12,0,0))
163
+ end
164
+
165
+ it 'should return Time value is current zone from string time value if timezone aware' do
166
+ @timezone_aware = true
167
+ value = '2010-01-01 12:00:00'
168
+ expect(evaluate_option_value(value, person)).to eq(Time.zone.local(2010,1,1,12,0,0))
169
+ end
170
+
171
+ it 'should return Time value in default zone from proc which returns string time' do
172
+ value = '2010-01-01 12:00:00'
173
+ expect(evaluate_option_value(lambda { value }, person)).to eq(Time.utc(2010,1,1,12,0,0))
174
+ end
175
+
176
+ it 'should return Time value for attribute method symbol which returns string time value' do
177
+ value = '2010-01-01 12:00:00'
178
+ person.birth_time = value
179
+ expect(evaluate_option_value(:birth_time, person)).to eq(Time.utc(2010,1,1,12,0,0))
180
+ end
181
+
182
+ context "restriction shorthand" do
183
+ before do
184
+ Timecop.freeze(Time.mktime(2010, 1, 1, 0, 0, 0))
185
+ end
186
+
187
+ it 'should evaluate :now as current time' do
188
+ expect(evaluate_option_value(:now, person)).to eq(Time.now)
189
+ end
190
+
191
+ it 'should evaluate :today as current time' do
192
+ expect(evaluate_option_value(:today, person)).to eq(Date.today)
193
+ end
194
+
195
+ it 'should not use shorthand if symbol if is record method' do
196
+ time = 1.day.from_now
197
+ allow(person).to receive(:now).and_return(time)
198
+ expect(evaluate_option_value(:now, person)).to eq(time)
199
+ end
200
+ end
201
+ end
202
+
203
+ describe "#parse" do
204
+ context "use_plugin_parser setting is true" do
205
+ with_config(:use_plugin_parser, true)
206
+
207
+ it 'should use timeliness' do
208
+ expect(Timeliness::Parser).to receive(:parse)
209
+ parse('2000-01-01')
210
+ end
211
+ end
212
+
213
+ context "use_plugin_parser setting is false" do
214
+ with_config(:use_plugin_parser, false)
215
+
216
+ it 'should use Time.zone.parse attribute is timezone aware' do
217
+ @timezone_aware = true
218
+ expect(Time.zone).to receive(:parse)
219
+ parse('2000-01-01')
220
+ end
221
+
222
+ it 'should use value#to_time if use_plugin_parser setting is false and attribute is not timezone aware' do
223
+ @timezone_aware = false
224
+ value = '2000-01-01'
225
+ expect(value).to receive(:to_time)
226
+ parse(value)
227
+ end
228
+ end
229
+
230
+ it 'should return nil if value is nil' do
231
+ expect(parse(nil)).to be_nil
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,163 @@
1
+ require 'spec_helper'
2
+
3
+ describe ValidatesTimeliness::Extensions::DateTimeSelect do
4
+ include ActionView::Helpers::DateHelper
5
+ attr_reader :person, :params
6
+
7
+ with_config(:use_plugin_parser, true)
8
+
9
+ before do
10
+ @person = Person.new
11
+ @params = {}
12
+ end
13
+
14
+ describe "datetime_select" do
15
+ it "should use param values when attribute is nil" do
16
+ @params["person"] = {
17
+ "birth_datetime(1i)" => '2009',
18
+ "birth_datetime(2i)" => '2',
19
+ "birth_datetime(3i)" => '29',
20
+ "birth_datetime(4i)" => '12',
21
+ "birth_datetime(5i)" => '13',
22
+ "birth_datetime(6i)" => '14',
23
+ }
24
+ person.birth_datetime = nil
25
+ @output = datetime_select(:person, :birth_datetime, :include_blank => true, :include_seconds => true)
26
+ should_have_datetime_selected(:birth_datetime, :year => 2009, :month => 'February', :day => 29, :hour => 12, :min => 13, :sec => 14)
27
+ end
28
+
29
+ it "should override object values and use params if present" do
30
+ @params["person"] = {
31
+ "birth_datetime(1i)" => '2009',
32
+ "birth_datetime(2i)" => '2',
33
+ "birth_datetime(3i)" => '29',
34
+ "birth_datetime(4i)" => '12',
35
+ "birth_datetime(5i)" => '13',
36
+ "birth_datetime(6i)" => '14',
37
+ }
38
+ person.birth_datetime = "2010-01-01 15:16:17"
39
+ @output = datetime_select(:person, :birth_datetime, :include_blank => true, :include_seconds => true)
40
+ should_have_datetime_selected(:birth_datetime, :year => 2009, :month => 'February', :day => 29, :hour => 12, :min => 13, :sec => 14)
41
+ end
42
+
43
+ it "should use attribute values from object if no params" do
44
+ person.birth_datetime = "2009-01-02 12:13:14"
45
+ @output = datetime_select(:person, :birth_datetime, :include_blank => true, :include_seconds => true)
46
+ should_have_datetime_selected(:birth_datetime, :year => 2009, :month => 'January', :day => 2, :hour => 12, :min => 13, :sec => 14)
47
+ end
48
+
49
+ it "should use attribute values if params does not contain attribute params" do
50
+ person.birth_datetime = "2009-01-02 12:13:14"
51
+ @params["person"] = { }
52
+ @output = datetime_select(:person, :birth_datetime, :include_blank => true, :include_seconds => true)
53
+ should_have_datetime_selected(:birth_datetime, :year => 2009, :month => 'January', :day => 2, :hour => 12, :min => 13, :sec => 14)
54
+ end
55
+
56
+ it "should not select values when attribute value is nil and has no param values" do
57
+ person.birth_datetime = nil
58
+ @output = datetime_select(:person, :birth_datetime, :include_blank => true, :include_seconds => true)
59
+ should_not_have_datetime_selected(:birth_datetime, :year, :month, :day, :hour, :min, :sec)
60
+ end
61
+ end
62
+
63
+ describe "date_select" do
64
+ it "should use param values when attribute is nil" do
65
+ @params["person"] = {
66
+ "birth_date(1i)" => '2009',
67
+ "birth_date(2i)" => '2',
68
+ "birth_date(3i)" => '29',
69
+ }
70
+ person.birth_date = nil
71
+ @output = date_select(:person, :birth_date, :include_blank => true)
72
+ should_have_datetime_selected(:birth_date, :year => 2009, :month => 'February', :day => 29)
73
+ end
74
+
75
+ it "should override object values and use params if present" do
76
+ @params["person"] = {
77
+ "birth_date(1i)" => '2009',
78
+ "birth_date(2i)" => '2',
79
+ "birth_date(3i)" => '29',
80
+ }
81
+ person.birth_date = "2009-03-01"
82
+ @output = date_select(:person, :birth_date, :include_blank => true)
83
+ should_have_datetime_selected(:birth_date, :year => 2009, :month => 'February', :day => 29)
84
+ end
85
+
86
+ it "should select attribute values from object if no params" do
87
+ person.birth_date = "2009-01-02"
88
+ @output = date_select(:person, :birth_date, :include_blank => true)
89
+ should_have_datetime_selected(:birth_date, :year => 2009, :month => 'January', :day => 2)
90
+ end
91
+
92
+ it "should select attribute values if params does not contain attribute params" do
93
+ person.birth_date = "2009-01-02"
94
+ @params["person"] = { }
95
+ @output = date_select(:person, :birth_date, :include_blank => true)
96
+ should_have_datetime_selected(:birth_date, :year => 2009, :month => 'January', :day => 2)
97
+ end
98
+
99
+ it "should not select values when attribute value is nil and has no param values" do
100
+ person.birth_date = nil
101
+ @output = date_select(:person, :birth_date, :include_blank => true)
102
+ should_not_have_datetime_selected(:birth_time, :year, :month, :day)
103
+ end
104
+
105
+ it "should allow the day part to be discarded" do
106
+ @params["person"] = {
107
+ "birth_date(1i)" => '2009',
108
+ "birth_date(2i)" => '2',
109
+ }
110
+
111
+ @output = date_select(:person, :birth_date, :include_blank => true, :discard_day => true)
112
+ should_have_datetime_selected(:birth_date, :year => 2009, :month => 'February')
113
+ should_not_have_datetime_selected(:birth_time, :day)
114
+ expect(@output).to have_tag("input[id=person_birth_date_3i][type=hidden][value='1']")
115
+ end
116
+ end
117
+
118
+ describe "time_select" do
119
+ before do
120
+ Timecop.freeze Time.mktime(2009,1,1)
121
+ end
122
+
123
+ it "should use param values when attribute is nil" do
124
+ @params["person"] = {
125
+ "birth_time(1i)" => '2000',
126
+ "birth_time(2i)" => '1',
127
+ "birth_time(3i)" => '1',
128
+ "birth_time(4i)" => '12',
129
+ "birth_time(5i)" => '13',
130
+ "birth_time(6i)" => '14',
131
+ }
132
+ person.birth_time = nil
133
+ @output = time_select(:person, :birth_time, :include_blank => true, :include_seconds => true)
134
+ should_have_datetime_selected(:birth_time, :hour => 12, :min => 13, :sec => 14)
135
+ end
136
+
137
+ it "should select attribute values from object if no params" do
138
+ person.birth_time = "2000-01-01 12:13:14"
139
+ @output = time_select(:person, :birth_time, :include_blank => true, :include_seconds => true)
140
+ should_have_datetime_selected(:birth_time, :hour => 12, :min => 13, :sec => 14)
141
+ end
142
+
143
+ it "should not select values when attribute value is nil and has no param values" do
144
+ person.birth_time = nil
145
+ @output = time_select(:person, :birth_time, :include_blank => true, :include_seconds => true)
146
+ should_not_have_datetime_selected(:birth_time, :hour, :min, :sec)
147
+ end
148
+ end
149
+
150
+ def should_have_datetime_selected(field, datetime_hash)
151
+ datetime_hash.each do |key, value|
152
+ index = {:year => 1, :month => 2, :day => 3, :hour => 4, :min => 5, :sec => 6}[key]
153
+ expect(@output).to have_tag("select[id=person_#{field}_#{index}i] option[selected=selected]").with_inner_text(value.to_s)
154
+ end
155
+ end
156
+
157
+ def should_not_have_datetime_selected(field, *attributes)
158
+ attributes.each do |attribute|
159
+ index = {:year => 1, :month => 2, :day => 3, :hour => 4, :min => 5, :sec => 6}[attribute]
160
+ expect(@output).not_to have_tag("select[id=person_#{attribute}_#{index}i] option[selected=selected]")
161
+ end
162
+ end
163
+ end