semanticgap_date_time_form 0.1

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.
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
@@ -0,0 +1,36 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "semanticgap_date_time_form"
3
+ s.version = "0.1"
4
+
5
+ s.authors = ["SemanticGap"]
6
+ s.date = "2010-05-08"
7
+ s.description = "An improved date time selector for Rails."
8
+ s.email = "info@semanticgap.com"
9
+ s.add_dependency "nayutaya-active-form"
10
+ s.files = [ "./lib/semanticgap_date_time_form/active_record_mixin.rb",
11
+ "./lib/semanticgap_date_time_form/form.rb",
12
+ "./lib/semanticgap_date_time_form/form_builder_mixin.rb",
13
+ "./lib/semanticgap_date_time_form/spec.rb",
14
+ "./lib/semanticgap_date_time_form.rb",
15
+ "./MIT-LICENSE",
16
+ "./public/stylesheets/semanticgap_date_time_form.css",
17
+ "./rails/init.rb",
18
+ "./rails/install.rb",
19
+ "./rails/uninstall.rb",
20
+ "./Rakefile",
21
+ "./README",
22
+ "./semanticgap_date_time_form.gemspec",
23
+ "./semanticgap_date_time_form.gemspec~",
24
+ "./spec/application.rb",
25
+ "./spec/integration/post_spec.rb",
26
+ "./spec/spec_helper.rb",
27
+ "./spec/unit/active_record_mixin_spec.rb",
28
+ "./spec/unit/form_builder_mixin_spec.rb",
29
+ "./spec/unit/form_spec.rb",
30
+ "./tasks/semanticgap_datetime_fields_tasks.rake" ]
31
+ s.homepage = "http://git.oss.semanticgap.com/ruby/semanticgap_date_time_form.git
32
+ "
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.5}
35
+ s.summary = "Improved date time selector"
36
+ end
@@ -0,0 +1,39 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "refinerycms-events"
3
+ s.version = "0.0.1"
4
+
5
+ s.authors = ["SemanticGap"]
6
+ s.date = "2010-05-07"
7
+ s.default_executable = "refinerycms-events-install"
8
+ s.description = "A really straightforward open source Ruby on Rails events plugin designed for integration with RefineryCMS."
9
+ s.email = "info@semanticgap.com"
10
+ s.add_dependency "nayutaya-active-form"
11
+ s.add_dependency "elevation_event_calendar"
12
+ s.executables = ["refinerycms-events-install"]
13
+ s.files = [ "db/migrate/20100430163757_create_events.rb",
14
+ "db/migrate/20100501234548_add_color_to_events.rb",
15
+ "db/migrate/20100502004451_add_all_day_to_events.rb",
16
+ "app/models/calendar.rb",
17
+ "app/models/event.rb",
18
+ "app/controllers/events_controller.rb",
19
+ "app/controllers/admin/events_controller.rb",
20
+ "app/helpers/calendars_helper.rb",
21
+ "app/views/events/index.html.erb",
22
+ "app/views/events/show.html.erb",
23
+ "app/views/events/_event_list.html.erb",
24
+ "app/views/admin/events/_event.html.erb",
25
+ "app/views/admin/events/_form.html.erb",
26
+ "app/views/admin/events/_sortable_list.html.erb",
27
+ "app/views/admin/events/edit.html.erb",
28
+ "app/views/admin/events/index.html.erb",
29
+ "app/views/admin/events/new.html.erb",
30
+ "config/routes.rb",
31
+ "public/stylesheets/event_calendar.css",
32
+ "public/javascripts/event_calendar.js",
33
+ "rails/init.rb",
34
+ "bin/refinerycms-events-install" ]
35
+ s.homepage = "http://github.com/semanticgap/refinerycms-events"
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.5}
38
+ s.summary = "Ruby on Rails events plugin for RefineryCMS."
39
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(__FILE__), '../spec_helper')
2
+ require 'semanticgap_date_time_form/spec'
3
+
4
+ class Post < ActiveRecord::Base
5
+ class Migration < ActiveRecord::Migration
6
+ def self.up
7
+ create_table :posts do |t|
8
+ t.datetime :published_at
9
+ t.datetime :created_at
10
+ end
11
+ end
12
+ end
13
+
14
+ datetime_fields_for :created_at
15
+ datetime_fields_for :published_at, :allow_blank => true
16
+ end
17
+
18
+ describe Post do
19
+ include SemanticGap::DateTimeForm::Spec
20
+
21
+ before(:all) do
22
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'test.sqlite3')
23
+ Post::Migration.up
24
+ end
25
+
26
+ after(:all) do
27
+ FileUtils.rm('test.sqlite3')
28
+ end
29
+
30
+ before(:each) do
31
+ subject.created_at = DateTime.now
32
+ end
33
+
34
+ it_has_datetime_fields_for :published_at, :allow_blank => true
35
+ it_has_datetime_fields_for :created_at
36
+ end
@@ -0,0 +1,18 @@
1
+ RAILS_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
2
+ module Rails
3
+ module VERSION
4
+ STRING = '0.0.1'
5
+ end
6
+ end
7
+
8
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'vendor', 'active_form', 'lib'))
9
+
10
+ require 'rubygems'
11
+ require 'active_record'
12
+ require 'active_form'
13
+ require 'action_controller'
14
+ require 'action_view'
15
+ require 'semanticgap_date_time_form'
16
+
17
+ require 'spec'
18
+ require 'spec/rails'
@@ -0,0 +1,41 @@
1
+ require File.join(File.dirname(__FILE__), '../spec_helper')
2
+
3
+ describe SemanticGap::DateTimeForm::ActiveRecordMixin::ClassMethods do
4
+ describe '#datetime_fields_for' do
5
+ before(:each) do
6
+ @klass = Class.new do
7
+ def self.validate(meth); end
8
+ def self.before_save(meth); end
9
+
10
+ include SemanticGap::DateTimeForm::ActiveRecordMixin
11
+ datetime_fields_for :published_at
12
+ end
13
+ end
14
+
15
+ subject { @klass.new }
16
+
17
+ context 'for a field named "published_at"' do
18
+ it "defines 'published_at_fields'" do
19
+ subject.should respond_to(:published_at_fields)
20
+ end
21
+
22
+ it "defines 'publihsed_at_fields='" do
23
+ subject.should respond_to(:published_at_fields=)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ describe SemanticGap::DateTimeForm::ActiveRecordMixin do
30
+ it "is included into ActiveRecord::Base" do
31
+ ActiveRecord::Base.should include(SemanticGap::DateTimeForm::ActiveRecordMixin)
32
+ end
33
+
34
+ describe '.included' do
35
+ it "adds #datetime_fields_for to the class" do
36
+ klass = Class.new
37
+ klass.send(:include, SemanticGap::DateTimeForm::ActiveRecordMixin)
38
+ klass.should respond_to(:datetime_fields_for)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,98 @@
1
+ require File.join(File.dirname(__FILE__), '../spec_helper')
2
+
3
+ describe SemanticGap::DateTimeForm::FormBuilderMixin do
4
+ include ActionController::Assertions::SelectorAssertions
5
+
6
+ def build_view
7
+ v = ActionView::Base.new
8
+ v.send(:extend, ActionView::Helpers::FormHelper)
9
+ v.send(:extend, ActionView::Helpers::DateHelper)
10
+ v.send(:extend, ActionView::Helpers::FormOptionsHelper)
11
+ v.send(:extend, ActionView::Helpers::TagHelper)
12
+ v
13
+ end
14
+
15
+ before(:each) do
16
+ @fields = SemanticGap::DateTimeForm::Form.new(:time_zone => ActiveSupport::TimeZone.new('Eastern Time (US & Canada)'))
17
+ @object = mock('object', :published_at_fields => @fields)
18
+ @template = build_view
19
+ @options = { }
20
+ end
21
+
22
+ subject { ActionView::Helpers::FormBuilder.new('object', @object, @template, @options, nil) }
23
+
24
+ it "is included into ActionView::Helpers::FormBuilder" do
25
+ ActionView::Helpers::FormBuilder.should include(SemanticGap::DateTimeForm::FormBuilderMixin)
26
+ end
27
+
28
+ describe '#datetime_form' do
29
+ TagArgs = {
30
+ :year => [ 'input[type=?][size=?][name=?]', 'text', '4', 'object[published_at_fields][year]' ],
31
+ :month => [ 'select[name=?]', 'object[published_at_fields][month]' ],
32
+ :day => [ 'input[type=?][size=?][name=?]', 'text', '2', 'object[published_at_fields][day]' ],
33
+ :hour => [ 'input[type=?][size=?][name=?]', 'text', '2', 'object[published_at_fields][hour]' ],
34
+ :minute => [ 'input[type=?][size=?][name=?]', 'text', '2', 'object[published_at_fields][minute]' ],
35
+ :ampm => [ 'select[name=?]', 'object[published_at_fields][ampm]' ],
36
+ :time_zone => [ 'span[class=?]', 'timezone', 'Eastern Time (US & Canada)' ]
37
+ }
38
+
39
+ context 'basic datetime form' do
40
+ before(:each) do
41
+ @result = subject.datetime_form(:published_at)
42
+ end
43
+
44
+ it "returns a div with class 'sg-datetime-form'" do
45
+ @result.should have_tag('div', :class => 'sg-datetime-form') do
46
+ with_tag(*TagArgs[:year])
47
+ with_tag(*TagArgs[:month])
48
+ with_tag(*TagArgs[:day])
49
+ with_tag(*TagArgs[:hour])
50
+ with_tag(*TagArgs[:minute])
51
+ with_tag(*TagArgs[:ampm])
52
+ with_tag(*TagArgs[:time_zone])
53
+ end
54
+ end
55
+
56
+ it "has a text field for the year" do
57
+ @result.should have_tag(*TagArgs[:year])
58
+ end
59
+
60
+ it "has a select field for the month" do
61
+ @result.should have_tag(*TagArgs[:month])
62
+ end
63
+
64
+ it "has a text field for the day" do
65
+ @result.should have_tag(*TagArgs[:day])
66
+ end
67
+
68
+ it "has a text field for the hour" do
69
+ @result.should have_tag(*TagArgs[:hour])
70
+ end
71
+
72
+ it "has a text field for the minute" do
73
+ @result.should have_tag(*TagArgs[:minute])
74
+ end
75
+
76
+ it "has a select field for ampm" do
77
+ @result.should have_tag(*TagArgs[:ampm])
78
+ end
79
+
80
+ it "has shows the time zone" do
81
+ @result.should have_tag(*TagArgs[:time_zone])
82
+ end
83
+ end
84
+
85
+ context 'when the fields allow blank' do
86
+ before(:each) do
87
+ @fields.stub!(:allow_blank?).and_return(true)
88
+ @result = subject.datetime_form(:published_at)
89
+ end
90
+
91
+ it "includes a blank option in the month select field" do
92
+ @result.should have_tag(*TagArgs[:month]) do
93
+ with_tag('option[value=?]', '')
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,583 @@
1
+ require File.join(File.dirname(__FILE__), '../spec_helper')
2
+
3
+ describe SemanticGap::DateTimeForm::Form do
4
+ def self.it_has_the_attributes(*attrs)
5
+ attrs.each do |attr|
6
+ describe "\##{attr}" do
7
+ it "is an accessor for @#{attr}" do
8
+ subject.send(:instance_variable_set, "@#{attr}", :hello)
9
+ subject.send(attr).should == :hello
10
+ end
11
+ end
12
+
13
+ describe "\##{attr}=" do
14
+ it "changes @#{attr}" do
15
+ lambda { subject.send("#{attr}=", :hello) }.
16
+ should change { subject.send(:instance_variable_get, "@#{attr}") }.
17
+ to(:hello)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ Attributes = [ :year, :month, :day, :hour, :minute, :ampm ]
24
+
25
+ it "is an active form" do
26
+ subject.should be_kind_of(ActiveForm)
27
+ end
28
+
29
+ it_has_the_attributes :year, :month, :day
30
+ it_has_the_attributes :hour, :minute, :ampm
31
+ it_has_the_attributes :time_zone
32
+
33
+ describe '#initialize' do
34
+ context 'no arguments' do
35
+ subject { described_class.new }
36
+
37
+ context 'when Time.zone is set' do
38
+ before(:each) do
39
+ @old_zone = Time.zone
40
+ Time.zone = ActiveSupport::TimeZone.new('Eastern Time (US & Canada)')
41
+ Time.zone.should_not be_nil
42
+ end
43
+
44
+ after(:each) do
45
+ Time.zone = @old_zone
46
+ end
47
+
48
+ it "sets the time zone to Time.zone" do
49
+ subject.time_zone.should == Time.zone
50
+ end
51
+ end
52
+
53
+ context 'when Time.zone is unset' do
54
+ before(:each) do
55
+ @old_zone = Time.zone
56
+ Time.zone = nil
57
+ end
58
+
59
+ after(:each) do
60
+ Time.zone = @old_zone
61
+ end
62
+
63
+ it "sets the time zone to UTC" do
64
+ subject.time_zone.should == ActiveSupport::TimeZone.new('UTC')
65
+ end
66
+ end
67
+
68
+ it "does NOT allow blanks" do
69
+ subject.should_not be_allow_blank
70
+ end
71
+
72
+ it "is not valid" do
73
+ subject.should_not be_valid
74
+ end
75
+
76
+ it "leaves the attributes blank" do
77
+ Attributes.each do |attr|
78
+ subject.send(attr).should be_nil
79
+ end
80
+ end
81
+ end
82
+
83
+ context 'options hash' do
84
+ context 'with :allow_blank' do
85
+ subject { described_class.new(:allow_blank => true) }
86
+
87
+ it "allows blanks" do
88
+ subject.should be_allow_blank
89
+ end
90
+
91
+ it "is valid" do
92
+ subject.should be_valid
93
+ end
94
+ end
95
+
96
+ context 'with :time_zone' do
97
+ before(:each) do
98
+ @zone = ActiveSupport::TimeZone.new('Eastern (US & Canada)')
99
+ end
100
+
101
+ subject do
102
+ described_class.new(:time_zone => @zone)
103
+ end
104
+
105
+ it "sets the time zone to the supplied value" do
106
+ subject.time_zone.should == @zone
107
+ end
108
+ end
109
+ end
110
+
111
+ context 'with a DateTime' do
112
+ { DateTime.new(2010, 5, 6, 20, 1) => %W(2010 5 6 08 01 PM),
113
+ DateTime.new(2010, 5, 6, 8, 59) => %W(2010 5 6 08 59 AM),
114
+ }.each do |date, (year, month, day, hour, minute, ampm)|
115
+ context "with #{date}" do
116
+ subject { described_class.new(date) }
117
+
118
+ it "sets the attributes to the DateTime's components" do
119
+ subject.year.should == year.to_i
120
+ subject.month.should == month.to_i
121
+ subject.day.should == day.to_i
122
+ subject.hour.should == hour
123
+ subject.minute.should == minute
124
+ subject.ampm.should == ampm
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ context 'with a DateTime and options Hash' do
131
+ before(:each) do
132
+ @date = DateTime.new(2010, 5, 6, 20, 1)
133
+ @zone = ActiveSupport::TimeZone.new('Eastern Time (US & Canada)')
134
+ end
135
+
136
+ subject { described_class.new(@date, :allow_blank => true, :time_zone => @zone) }
137
+
138
+ it "sets the date to the DateTime" do
139
+ subject.to_datetime.should == @date
140
+ end
141
+
142
+ it "sets the options" do
143
+ subject.should be_allow_blank
144
+ subject.time_zone.should == @zone
145
+ end
146
+ end
147
+ end
148
+
149
+ describe 'validations' do
150
+ describe 'when blanks are allowed' do
151
+ subject { described_class.new(:allow_blank => true) }
152
+
153
+ it "is valid when all attributes are blank" do
154
+ subject.should be_valid
155
+ end
156
+
157
+ it "is valid when all attributes are blank except ampm" do
158
+ subject.ampm = 'AM'
159
+ subject.should be_valid
160
+ end
161
+
162
+ [ :year, :month, :day, :hour, :minute ].each do |attr|
163
+ it "is invalid if #{attr} has a value" do
164
+ subject.send("#{attr}=", 1)
165
+ subject.should_not be_valid
166
+ end
167
+ end
168
+ end
169
+
170
+ describe 'on year' do
171
+ { 1 => true,
172
+ 2010 => true,
173
+ 0 => true,
174
+ 14 => true,
175
+ -1 => true,
176
+ '-10' => true,
177
+ '-1' => true,
178
+ 'A' => false,
179
+ 'abcd' => false,
180
+ '' => false,
181
+ ' ' => false
182
+ }.each do |value, valid|
183
+ it "is #{valid ? 'valid' : 'invalid'} for #{value}" do
184
+ subject.year = value
185
+
186
+ if valid
187
+ subject.should_not have(:any).errors_on(:year)
188
+ else
189
+ subject.should have_at_least(1).error_on(:year)
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ describe 'on month' do
196
+ it "must be between 1 and 12" do
197
+ (1..12).each do |i|
198
+ subject.month = i
199
+ subject.should_not have(:any).errors_on(:month)
200
+ end
201
+ end
202
+
203
+ { 1 => true,
204
+ 12 => true,
205
+ '10' => true,
206
+ 0 => false,
207
+ 14 => false,
208
+ -1 => false,
209
+ '-10' => false,
210
+ '-1' => false,
211
+ 'A' => false,
212
+ '' => false,
213
+ ' ' => false
214
+ }.each do |value, valid|
215
+ it "is #{valid ? 'valid' : 'invalid'} for #{value}" do
216
+ subject.month = value
217
+
218
+ if valid
219
+ subject.should_not have(:any).errors_on(:month)
220
+ else
221
+ subject.should have_at_least(1).error_on(:month)
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ describe 'on day' do
228
+ context 'with a blank month' do
229
+ before(:each) do
230
+ subject.month = nil
231
+ end
232
+
233
+ it "must be between 1 and 31" do
234
+ (1..31).each do |i|
235
+ subject.day = i
236
+ subject.should_not have(:any).errors_on(:day)
237
+ end
238
+ end
239
+
240
+ { '1' => true,
241
+ '31' => true,
242
+ '10' => true,
243
+ 0 => false,
244
+ 32 => false,
245
+ -1 => false,
246
+ '-10' => false,
247
+ '-1' => false,
248
+ 'A' => false,
249
+ '' => false,
250
+ ' ' => false
251
+ }.each do |value, valid|
252
+ it "is #{valid ? 'valid' : 'invalid'} for #{value}" do
253
+ subject.day = value
254
+
255
+ if valid
256
+ subject.should_not have(:any).errors_on(:day)
257
+ else
258
+ subject.should have_at_least(1).error_on(:day)
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ { 2010 => {
265
+ 1 => 31,
266
+ 2 => 28,
267
+ 3 => 31,
268
+ 4 => 30,
269
+ 5 => 31,
270
+ 6 => 30,
271
+ 7 => 31,
272
+ 8 => 31,
273
+ 9 => 30,
274
+ 10 => 31,
275
+ 11 => 30,
276
+ 12 => 31
277
+ },
278
+ 2008 => {
279
+ 1 => 31,
280
+ 2 => 29,
281
+ 3 => 31,
282
+ 4 => 30,
283
+ 5 => 31,
284
+ 6 => 30,
285
+ 7 => 31,
286
+ 8 => 31,
287
+ 9 => 30,
288
+ 10 => 31,
289
+ 11 => 30,
290
+ 12 => 31
291
+ }
292
+ }.each do |year, months|
293
+ context "in the year #{year}" do
294
+ subject { described_class.new(:allow_blank => true) }
295
+
296
+ before(:each) do
297
+ subject.year = year
298
+ end
299
+
300
+ months.each do |month, num_days|
301
+ context "with month set to #{month}" do
302
+ before(:each) do
303
+ subject.month = month
304
+ end
305
+
306
+ it "is valid when day is set to #{num_days - 1}" do
307
+ subject.day = num_days - 1
308
+ subject.should be_valid
309
+ end
310
+
311
+ it "is valid when day is set to #{num_days}" do
312
+ subject.day = num_days
313
+ subject.should be_valid
314
+ end
315
+
316
+ it "is invalid when day is set to #{num_days + 1}" do
317
+ subject.day = num_days + 1
318
+ subject.should_not be_valid
319
+ subject.should have_at_least(1).error_on(:day)
320
+ end
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+
327
+ describe 'hour' do
328
+ it "must be between 0 and 23" do
329
+ (0..23).each do |i|
330
+ subject.hour = i
331
+ subject.should_not have(:any).errors_on(:hour)
332
+ end
333
+ end
334
+
335
+ { '0' => true,
336
+ '12' => true,
337
+ 23 => true,
338
+ '10' => true,
339
+ 24 => false,
340
+ 25 => false,
341
+ -1 => false,
342
+ '-10' => false,
343
+ '-1' => false,
344
+ 'A' => false,
345
+ '' => false,
346
+ ' ' => false
347
+ }.each do |value, valid|
348
+ it "is #{valid ? 'valid' : 'invalid'} for #{value.inspect}" do
349
+ subject.hour = value
350
+
351
+ if valid
352
+ subject.should_not have(:any).errors_on(:hour)
353
+ else
354
+ subject.should have_at_least(1).error_on(:hour)
355
+ end
356
+ end
357
+ end
358
+ end
359
+
360
+ describe 'minute' do
361
+ it "must be between 0 and 59" do
362
+ (0..59).each do |i|
363
+ subject.minute = i
364
+ subject.should_not have(:any).errors_on(:minute)
365
+ end
366
+ end
367
+
368
+ { '0' => true,
369
+ '59' => true,
370
+ 59 => true,
371
+ '10' => true,
372
+ 60 => false,
373
+ 61 => false,
374
+ -1 => false,
375
+ '-10' => false,
376
+ '-1' => false,
377
+ 'A' => false,
378
+ '' => false,
379
+ ' ' => false
380
+ }.each do |value, valid|
381
+ it "is #{valid ? 'valid' : 'invalid'} for #{value.inspect}" do
382
+ subject.minute = value
383
+
384
+ if valid
385
+ subject.should_not have(:any).errors_on(:minute)
386
+ else
387
+ subject.should have_at_least(1).error_on(:minute)
388
+ end
389
+ end
390
+ end
391
+ end
392
+
393
+ describe 'ampm' do
394
+ %W(am AM aM Am pm PM pM Pm).each do |value|
395
+ it "is valid with #{value.inspect}" do
396
+ subject.ampm = value
397
+ subject.should_not have(:any).errors_on(:ampm)
398
+ end
399
+ end
400
+
401
+ values = %W(a p A P AB JM Hello hello pay)
402
+ values << "" << " " << " "
403
+ values.each do |value|
404
+ it "is invalid with #{value.inspect}" do
405
+ subject.ampm = value
406
+ subject.should have_at_least(1).errors_on(:ampm)
407
+ end
408
+ end
409
+ end
410
+ end
411
+
412
+ describe '#date=' do
413
+ it "adjusts the date to local time" do
414
+ @utc = DateTime.parse("2010/05/06 16:00 PM UTC")
415
+ @zone = ActiveSupport::TimeZone.new('Eastern Time (US & Canada)')
416
+ subject.time_zone = @zone
417
+
418
+ subject.date = @utc
419
+ subject.hour.should == '12'
420
+ subject.should be_pm
421
+ end
422
+
423
+ { DateTime.new(2010, 5, 6, 20, 1) => %W(2010 5 6 08 01 PM),
424
+ DateTime.new(2010, 5, 6, 8, 59) => %W(2010 5 6 08 59 AM),
425
+ DateTime.new(2010, 5, 6, 12, 1) => %W(2010 5 6 12 01 PM),
426
+ DateTime.new(2010, 5, 6, 0, 59) => %W(2010 5 6 12 59 AM),
427
+ Date.new(2010, 5, 6) => %W(2010 5 6 12 00 AM),
428
+ Time.parse('2010/5/6 0:00 UTC') => %W(2010 5 6 12 00 AM)
429
+ }.each do |date, (year, month, day, hour, minute, ampm)|
430
+ context "with #{date}" do
431
+ before(:each) do
432
+ subject.date = date
433
+ end
434
+
435
+ it "sets year to #{year.to_i.inspect}" do
436
+ subject.year.should == year.to_i
437
+ end
438
+
439
+ it "sets month to #{month.to_i.inspect}" do
440
+ subject.month.should == month.to_i
441
+ end
442
+
443
+ it "sets day to #{day.to_i.inspect}" do
444
+ subject.day.should == day.to_i
445
+ end
446
+
447
+ it "sets hour to #{hour.inspect}" do
448
+ subject.hour.should == hour
449
+ end
450
+
451
+ it "sets minute to #{minute.inspect}" do
452
+ subject.minute.should == minute
453
+ end
454
+
455
+ it "sets ampm to #{ampm.inspect}" do
456
+ subject.ampm.should == ampm
457
+ end
458
+
459
+ it "converts to the supplied date" do
460
+ subject.to_datetime.should == date
461
+ end
462
+ end
463
+ end
464
+ end
465
+
466
+ describe '#time_zone_name' do
467
+ it "returns the time zone's name" do
468
+ subject.time_zone = mock('zone', :name => 'TZ')
469
+ subject.time_zone.name.should == 'TZ'
470
+ end
471
+ end
472
+
473
+ describe '#time_zone_name=' do
474
+ before(:each) do
475
+ @utc = ActiveSupport::TimeZone.new('UTC')
476
+ @eastern = ActiveSupport::TimeZone.new('Eastern Time (US & Canada)')
477
+ ActiveSupport::TimeZone.stub!(:new).and_return(@utc)
478
+ end
479
+
480
+ it "creates a new TimeZone from the value" do
481
+ ActiveSupport::TimeZone.should_receive(:new).
482
+ with('Eastern Time (US & Canada)').
483
+ and_return(@eastern)
484
+
485
+ subject.time_zone_name = 'Eastern Time (US & Canada)'
486
+ end
487
+
488
+ context 'valid time zone' do
489
+ it "changes the time zone" do
490
+ ActiveSupport::TimeZone.should_receive(:new).and_return(@eastern)
491
+
492
+ lambda { subject.time_zone_name = 'Eastern Time (US & Canada)' }.should change(subject, :time_zone)
493
+ end
494
+ end
495
+
496
+ context 'invalid time zone' do
497
+ it "does not change the time zone" do
498
+ lambda { subject.time_zone_name = 'WTF' }.should_not change(subject, :time_zone_name)
499
+ end
500
+ end
501
+ end
502
+
503
+ describe '#to_datetime' do
504
+ context 'when valid' do
505
+ before(:each) do
506
+ @time = DateTime.new(2010, 5, 5, 20, 27)
507
+ end
508
+
509
+ subject { described_class.new(@time) }
510
+
511
+ it "returns a DateTime created from the attributes, but adjusted to the time zone" do
512
+ subject.to_datetime.should == subject.time_zone.utc_to_local(@time)
513
+ end
514
+ end
515
+
516
+ context 'when invalid' do
517
+ before(:each) do
518
+ subject.hour = 25
519
+ end
520
+
521
+ it "returns nil" do
522
+ subject.to_datetime.should be_nil
523
+ end
524
+ end
525
+ end
526
+
527
+ describe '#pm?' do
528
+ %W(am Am AM aM a hello).each do |v|
529
+ context "with #{v.inspect}" do
530
+ before(:each) do
531
+ subject.ampm = v
532
+ end
533
+
534
+ it "is false for #{v.inspect}" do
535
+ subject.should_not be_pm
536
+ end
537
+ end
538
+ end
539
+
540
+ %W(pm Pm PM pM p).each do |v|
541
+ context "with #{v.inspect}" do
542
+ before(:each) do
543
+ subject.ampm = v
544
+ end
545
+
546
+ it "is true for #{v.inspect}" do
547
+ subject.should be_pm
548
+ end
549
+ end
550
+ end
551
+ end
552
+
553
+ describe '#blank?' do
554
+ it "is true if all the attributes are blank" do
555
+ subject.should be_blank
556
+ end
557
+
558
+ [ :year, :month, :day, :hour, :minute ].each do |attr|
559
+ it "is false if #{attr} has a value" do
560
+ subject.send("#{attr}=", 1)
561
+ subject.should_not be_blank
562
+ end
563
+ end
564
+ end
565
+
566
+ describe '#allow_blank?' do
567
+ context 'when :allow_blank was true during creation' do
568
+ subject { described_class.new(:allow_blank => true) }
569
+
570
+ it "is true" do
571
+ subject.should be_allow_blank
572
+ end
573
+ end
574
+
575
+ context 'when :allow_blank was false during creation' do
576
+ subject { described_class.new(:allow_blank => false) }
577
+
578
+ it "is true" do
579
+ subject.should_not be_allow_blank
580
+ end
581
+ end
582
+ end
583
+ end