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.
- data/MIT-LICENSE +20 -0
- data/README +50 -0
- data/Rakefile +33 -0
- data/lib/semanticgap_date_time_form.rb +6 -0
- data/lib/semanticgap_date_time_form/active_record_mixin.rb +42 -0
- data/lib/semanticgap_date_time_form/form.rb +117 -0
- data/lib/semanticgap_date_time_form/form_builder_mixin.rb +26 -0
- data/lib/semanticgap_date_time_form/spec.rb +127 -0
- data/public/stylesheets/semanticgap_date_time_form.css +3 -0
- data/rails/init.rb +1 -0
- data/rails/install.rb +8 -0
- data/rails/uninstall.rb +1 -0
- data/semanticgap_date_time_form.gemspec +36 -0
- data/semanticgap_date_time_form.gemspec~ +39 -0
- data/spec/application.rb +2 -0
- data/spec/integration/post_spec.rb +36 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/unit/active_record_mixin_spec.rb +41 -0
- data/spec/unit/form_builder_mixin_spec.rb +98 -0
- data/spec/unit/form_spec.rb +583 -0
- data/tasks/semanticgap_datetime_fields_tasks.rake +4 -0
- metadata +86 -0
data/rails/uninstall.rb
ADDED
@@ -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
|
data/spec/application.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|