zone_ranger 0.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/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+ .ruby-version
15
+ .rbenv*
16
+ .DS_Store
17
+
18
+ # YARD artifacts
19
+ .yardoc
20
+ _yardoc
21
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ zone_ranger (0.0.1)
5
+ activesupport (~> 3.0.20)
6
+ i18n
7
+ tzinfo (~> 0.3.35)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (3.0.20)
13
+ diff-lcs (1.2.4)
14
+ i18n (0.6.5)
15
+ rake (10.1.0)
16
+ rspec (2.14.1)
17
+ rspec-core (~> 2.14.0)
18
+ rspec-expectations (~> 2.14.0)
19
+ rspec-mocks (~> 2.14.0)
20
+ rspec-core (2.14.5)
21
+ rspec-expectations (2.14.2)
22
+ diff-lcs (>= 1.1.3, < 2.0)
23
+ rspec-mocks (2.14.3)
24
+ timecop (0.3.5)
25
+ tzinfo (0.3.37)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ bundler (~> 1.3)
32
+ rake
33
+ rspec
34
+ timecop (~> 0.3.5)
35
+ zone_ranger!
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Rigor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ zone-ranger
2
+ ===========
3
+
4
+ To determine if a time falls between two points
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,182 @@
1
+ require 'active_support/all'
2
+
3
+ module ZoneRanger
4
+ class Core
5
+
6
+ attr_reader :start_time_string, :repeat_type
7
+ attr_reader :duration_in_minutes
8
+
9
+ def initialize start_date_time, duration_in_minutes, timezone, options={}
10
+
11
+ @start_time_string = start_date_time
12
+ @duration_in_minutes = duration_in_minutes
13
+ @timezone = timezone
14
+
15
+ @ending = options.fetch(:ending, nil)
16
+
17
+ @repeat_type = options.fetch(:repeat, nil)
18
+
19
+ end
20
+
21
+ def repeat?
22
+ !!@repeat_type
23
+ end
24
+
25
+ def daily?
26
+ @repeat_type == :daily
27
+ end
28
+
29
+ def weekly?
30
+ @repeat_type == :weekly
31
+ end
32
+
33
+ def monthly_by_day_of_week?
34
+ @repeat_type == :monthly_by_day_of_week
35
+ end
36
+
37
+ def monthly_by_day_of_month?
38
+ @repeat_type == :monthly_by_day_of_month
39
+ end
40
+
41
+ def timezone_object
42
+ ActiveSupport::TimeZone.new((@timezone || "UTC"))
43
+ end
44
+
45
+ def includes? time_point=Time.now.utc
46
+ return false if not_started_yet?(time_point) || expired?(time_point)
47
+
48
+ if repeat?
49
+ included_in_repeating_timeframe? time_point
50
+ else
51
+ static_include? time_point
52
+ end
53
+ end
54
+
55
+ def static_include? time_point
56
+ zoned_time(time_point).between?(*time_range(time_point))
57
+ end
58
+
59
+ def expired? time=Time.now.utc
60
+ return false unless @ending
61
+ zoned_time(time) > zoned_end_date
62
+ end
63
+
64
+ def zoned_time time=nil
65
+ tzone = timezone_object
66
+ if time.nil?
67
+ tzone.now
68
+ else
69
+ time.in_time_zone(tzone)
70
+ end
71
+ end
72
+
73
+ def zoned_date time=Time.now.utc
74
+ zoned_time(time).to_date
75
+ end
76
+
77
+ def zoned_end_date
78
+ timezone_object.parse("#{@ending} 23:59:59 #{utc_offset}")
79
+ end
80
+
81
+ def utc_offset
82
+ ActiveSupport::TimeZone.seconds_to_utc_offset(zoned_time.utc_offset)
83
+ end
84
+
85
+ def not_started_yet? time
86
+ start_on > zoned_date
87
+ end
88
+
89
+ def start_on
90
+ parsed_time_string.to_date
91
+ end
92
+
93
+ def started?
94
+ !not_started_yet?
95
+ end
96
+
97
+ def time_range current_day=Time.now.utc, options={}
98
+
99
+ offset = options.fetch(:offset, 0)
100
+
101
+ start_date = if repeat?
102
+ #if daily?
103
+ # shift to the day being checked
104
+ start_time = zoned_time(current_day + offset.days)
105
+ start_time.to_date
106
+ #end
107
+ else
108
+ parsed_time_string.to_date
109
+ end
110
+
111
+ b_start = timezone_object.parse(parsed_time_string.strftime("#{start_date} %H:%M")).in_time_zone(timezone_object)
112
+ b_end = b_start + duration_in_minutes.minutes
113
+
114
+ [b_start, b_end]
115
+ end
116
+
117
+ def parsed_time_string
118
+ timezone_object.parse(start_time_string)
119
+ end
120
+
121
+ protected
122
+
123
+ def included_in_repeating_timeframe? time_point
124
+ repeat? && (daily? && include_for_daily?(time_point) ||
125
+ weekly? && include_for_weekly?(time_point) ||
126
+ monthly_by_day_of_week? && include_for_monthly_dow?(time_point) ||
127
+ monthly_by_day_of_month? && include_for_monthly_dom?(time_point))
128
+ end
129
+
130
+ def include_for_daily? time_point
131
+ zoned_time(time_point).between?(*time_range(time_point, :offset => -1)) || zoned_time(time_point).between?(*time_range(time_point))
132
+ end
133
+
134
+ def include_for_weekly? time_point
135
+ start_date = zoned_time(time_point).to_date
136
+ start_at, end_at = time_range(time_point)
137
+
138
+ if crosses_midnight?
139
+ wday1 = parsed_time_string.wday
140
+ wday2 = parsed_time_string.tomorrow.wday
141
+
142
+ case start_date.wday
143
+ when wday1
144
+ zoned_time(time_point).between?(start_at, end_at)
145
+ when wday2
146
+ yesterday_start, yesterday_end = time_range(zoned_time(time_point), :offset => -1)
147
+ zoned_time(time_point).between?(yesterday_start, yesterday_end)
148
+ else false
149
+ end
150
+ else
151
+ Util.wday_match?(start_at, parsed_time_string) && zoned_time(time_point).between?(start_at, end_at)
152
+ end
153
+ end
154
+
155
+ def include_for_monthly_dow? time_point
156
+ start_date = parsed_time_string.to_date
157
+
158
+ start_week = Util.week_of_month(start_date)
159
+ time_week = Util.week_of_month(zoned_time(time_point))
160
+
161
+ start_week == time_week && include_for_weekly?(time_point)
162
+ end
163
+
164
+ def include_for_monthly_dom? time_point
165
+ original_day = parsed_time_string.day
166
+ today_day = zoned_time(time_point).day
167
+
168
+ if today_day == original_day
169
+ static_include? time_point
170
+ elsif (today_day == parsed_time_string.tomorrow.day) && crosses_midnight?
171
+ zoned_time(time_point).between?(*time_range(time_point, :offset => -1))
172
+ else
173
+ false
174
+ end
175
+ end
176
+
177
+ def crosses_midnight?
178
+ Util.crosses_one_utc_midnight?(parsed_time_string, @duration_in_minutes)
179
+ end
180
+
181
+ end
182
+ end
@@ -0,0 +1,47 @@
1
+ module ZoneRanger
2
+ class Util
3
+
4
+ def self.week_of_month time
5
+ day_num = time.day
6
+ days_in_month = Time.days_in_month(time.month)
7
+
8
+ if day_num < 8
9
+ 1
10
+ elsif day_num < 15
11
+ 2
12
+ elsif day_num < 22
13
+ 3
14
+ elsif day_num < days_in_month - 7
15
+ 4 # fourth but not last
16
+ else
17
+ :last # last
18
+ end
19
+ end
20
+
21
+ def self.crosses_one_utc_midnight? start, duration
22
+ # a utc midnight is when the start day is different the blackout ends on
23
+ day1 = start.utc.to_date
24
+ day2 = (start + duration.minutes).utc.to_date
25
+ day1 != day2
26
+ end
27
+
28
+ def self.wday_match? date1, date2
29
+ date1.wday == date2.wday
30
+ end
31
+
32
+ def self.calculate_duration_in_minutes starting, ending
33
+ start_hour = starting.strftime("%H")
34
+ start_minutes = starting.strftime("%M")
35
+ start_in_minutes = (start_hour.to_i * 60) + start_minutes.to_i
36
+
37
+ finish_hour = ending.strftime("%H").to_i
38
+ finish_minutes = (finish_hour * 60) + ending.strftime("%M").to_i
39
+
40
+ d = finish_minutes - start_in_minutes
41
+ d += 1440 if d < 0
42
+
43
+ d
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ module ZoneRanger
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,3 @@
1
+ require "zone_ranger/version"
2
+ require 'zone_ranger/util'
3
+ require 'zone_ranger/core'
data/spec/core_spec.rb ADDED
@@ -0,0 +1,260 @@
1
+ require 'spec_helper'
2
+
3
+ describe ZoneRanger::Core do
4
+
5
+ def timeize t_or_s
6
+ t_or_s.is_a?(Time) ? t_or_s : Time.parse(t_or_s)
7
+ end
8
+
9
+ def validate_active zr, time
10
+ Timecop.freeze(timeize(time))
11
+ zr.includes?(timeize(time)).should(be_true, "#{time.to_s} expected ACTIVE")
12
+ Timecop.return
13
+ end
14
+
15
+ def validate_inactive zr, time
16
+ Timecop.freeze(timeize(time))
17
+ zr.includes?(timeize(time)).should(be_false, "#{time.to_s} expected INACTIVE")
18
+ Timecop.return
19
+ end
20
+
21
+ describe "standard operation" do
22
+ it "should require a start time, duration, and timezone" do
23
+ expect{ ZoneRanger::Core.new.includes? Time.now, 30 }.to raise_error ArgumentError
24
+ expect{ ZoneRanger::Core.new.includes? Time.now }.to raise_error ArgumentError
25
+ end
26
+
27
+ it "should not throw error if all fields are supplied" do
28
+ ZoneRanger::Core.new("#{Time.now - 300}", 30, "Eastern Time (US & Canada)").includes?
29
+ end
30
+
31
+ it "should accept a Time parameter" do
32
+ ZoneRanger::Core.new("#{Time.now - 300}", 30, "Eastern Time (US & Canada)").includes? Time.now.utc
33
+ end
34
+
35
+ it "should repeat? if told" do
36
+ zr = ZoneRanger::Core.new('2013-04-01 06:00 -04:00', 30, "Eastern Time (US & Canada)", :repeat => :daily)
37
+ zr.repeat?.should be_true
38
+ end
39
+
40
+ it "should have a timezone" do
41
+ zr = ZoneRanger::Core.new('2013-04-01 06:00 -04:00', 30, "Eastern Time (US & Canada)")
42
+ zr.timezone_object.should be_a ActiveSupport::TimeZone
43
+ end
44
+ end
45
+
46
+ describe "#time_range" do
47
+ context "no repeat" do
48
+ it "should return the correct time range - same day" do
49
+ zr = ZoneRanger::Core.new('2013-04-01 06:00 -04:00', 30, "Eastern Time (US & Canada)")
50
+ zr.time_range.should eql([Time.parse('2013-04-01 06:00 -04:00'), Time.parse('2013-04-01 06:30 -04:00')])
51
+ end
52
+
53
+ it "should return the correct time range - crossing midnight in user's timezone" do
54
+ zr = ZoneRanger::Core.new('2013-04-01 23:01 -04:00', 60, "Eastern Time (US & Canada)")
55
+ zr.time_range.should eql([Time.parse('2013-04-01 23:01 -04:00'), Time.parse('2013-04-02 00:01 -04:00')])
56
+ end
57
+
58
+ it "should work with other time zones" do
59
+ zr = ZoneRanger::Core.new('2013-04-01 23:01 -07:00', 60, "Pacific Time (US & Canada)")
60
+ zr.time_range.should eql([Time.parse('2013-04-01 23:01 -07:00'), Time.parse('2013-04-02 00:01 -07:00')])
61
+ end
62
+ end
63
+
64
+ context "repeat daily" do
65
+ it "should return the correct time range - same day" do
66
+ zr = ZoneRanger::Core.new('2013-04-01 06:00 -04:00', 30, "Eastern Time (US & Canada)", :repeat => :daily)
67
+ zr.time_range(Time.parse('2013-04-02 06:00 -04:00')).should eql([Time.parse('2013-04-02 06:00 -04:00'), Time.parse('2013-04-02 06:30 -04:00')])
68
+ end
69
+
70
+ it "should return the correct time range - crossing midnight in user's timezone" do
71
+ zr = ZoneRanger::Core.new('2013-04-01 23:01 -04:00', 60, "Eastern Time (US & Canada)", :repeat => :daily)
72
+ zr.time_range(Time.parse('2013-04-02 06:00 -04:00')).should eql([Time.parse('2013-04-02 23:01 -04:00'), Time.parse('2013-04-03 00:01 -04:00')])
73
+ end
74
+
75
+ it "should work with other time zones" do
76
+ zr = ZoneRanger::Core.new('2013-04-01 23:01 -07:00', 60, "Pacific Time (US & Canada)", :repeat => :daily)
77
+ zr.time_range(Time.parse('2013-04-02 06:00 -07:00')).should eql([Time.parse('2013-04-02 23:01 -07:00'), Time.parse('2013-04-03 00:01 -07:00')])
78
+ end
79
+ end
80
+ end
81
+
82
+ describe "#expired?" do
83
+ let(:zr_daily) { ZoneRanger::Core.new('2013-04-01 23:01 -04:00', 60, "Eastern Time (US & Canada)", :repeat => :daily, :ending => '2013-06-01')}
84
+ let(:zr_weekly) { ZoneRanger::Core.new('2013-04-01 00:01:00 -07:00', 60, "Pacific Time (US & Canada)", :ending => '2013-06-01', :repeat => :weekly)}
85
+ let(:zr_monthly_by_day_of_month) { ZoneRanger::Core.new('2013-04-01 00:01:00 -07:00', 60, "Pacific Time (US & Canada)", :ending => '2013-06-01', :repeat => :monthly_by_day_of_month)}
86
+ let(:zr_monthly_by_day_of_week) { ZoneRanger::Core.new('2013-04-01 00:01:00 -07:00', 60, "Pacific Time (US & Canada)", :ending => '2013-06-01', :repeat => :monthly_by_day_of_week)}
87
+
88
+ it "should return true if the checked time is past the expired time" do
89
+ [zr_daily, zr_weekly, zr_monthly_by_day_of_month, zr_monthly_by_day_of_week].each do |zr|
90
+ zr.expired?(Time.parse('2013-06-02 00:00:00 -07:00')).should(be_true, "#{zr.repeat_type} expected EXPIRED")
91
+ end
92
+ end
93
+
94
+ it "should be false if the checked time is before the expired time" do
95
+ [zr_daily, zr_weekly, zr_monthly_by_day_of_month, zr_monthly_by_day_of_week].each do |zr|
96
+ zr.expired?(Time.parse('2013-06-01 00:00:00 -07:00')).should(be_false, "#{zr.repeat_type} expected ACTIVE")
97
+ zr.expired?(Time.parse('2013-05-01 00:00:00 -07:00')).should(be_false, "#{zr.repeat_type} expected ACTIVE")
98
+ end
99
+ end
100
+ end
101
+
102
+ describe "#includes?" do
103
+
104
+ context "expired" do
105
+ let(:daily_with_end) { ZoneRanger::Core.new("09:58 -04:00", 841, "Eastern Time (US & Canada)", :repeat => :daily, :ending => '2013-07-17') }
106
+
107
+ it "should never return true after the end date - not near UTC midnight" do
108
+ validate_inactive daily_with_end, "Fri Jul 19 11:57:22 -0400 2013"
109
+ validate_active daily_with_end, "Fri Jul 16 11:57:22 -0400 2013"
110
+ validate_active daily_with_end, "Fri Jul 17 23:58:22 -0400 2013"
111
+ end
112
+ end
113
+
114
+ context "giving a time" do # does the present time fall in the given timeframe?
115
+
116
+ let(:zr) { ZoneRanger::Core.new('2013-04-01 23:01:00 -07:00', 60, "Pacific Time (US & Canada)") }
117
+
118
+ context "in timeframe" do # present time is inside timeframe
119
+ it "should be active" do
120
+ validate_active(zr, '2013-04-01 23:01:01 -07:00')
121
+ validate_active(zr, '2013-04-02 00:00:00 -07:00')
122
+ end
123
+ end
124
+ context "outside timeframe" do # present time is outside timeframe
125
+ it "should not be active" do
126
+ validate_inactive(zr, '2013-04-01 23:00:01 -07:00')
127
+ validate_inactive(zr, '2013-04-02 00:02:00 -07:00')
128
+ end
129
+ end
130
+
131
+ context "over utc midnight" do
132
+ let(:set_timeframe_over_two_days){ ZoneRanger::Core.new("2013-07-24 23:01 UTC", 120, "UTC", :repeat => :weekly, :ending => Time.parse("2013-07-25 UTC")) }
133
+
134
+ it "should be active in timeframe" do
135
+ validate_active(set_timeframe_over_two_days, "2013-07-24 23:02 UTC")
136
+ validate_active(set_timeframe_over_two_days, "2013-07-25 01:00 UTC")
137
+ end
138
+
139
+ it "should not be active in timeframe" do
140
+ validate_inactive(set_timeframe_over_two_days, "2013-07-24 23:00 UTC")
141
+ validate_inactive(set_timeframe_over_two_days, "2013-07-25 01:02 UTC")
142
+ end
143
+ end
144
+
145
+ context "repeated" do
146
+ context "daily" do
147
+ let(:zr_daily) { ZoneRanger::Core.new('2013-04-01 23:01:00 -07:00', 60, "Pacific Time (US & Canada)", :repeat => :daily) }
148
+ let(:zr_daily_no_start_date) { ZoneRanger::Core.new('23:01:00 -07:00', 60, "Pacific Time (US & Canada)", :repeat => :daily) }
149
+
150
+ it "should cover until midnight every day" do
151
+ (1..8).each do |i|
152
+ validate_active(zr_daily, "2013-04-0#{i} 23:59:01 -07:00")
153
+ validate_active(zr_daily_no_start_date, "2013-04-0#{i} 23:59:01 -07:00")
154
+ end
155
+ end
156
+
157
+ it "should cover after midnight every day" do
158
+ (1..8).each do |i|
159
+ validate_active(zr_daily, "2013-04-0#{i+1} 00:00:00 -07:00")
160
+ validate_active(zr_daily_no_start_date, "2013-04-0#{i+1} 00:00:00 -07:00")
161
+ end
162
+ end
163
+
164
+ it "should not cover after midnight from the day before if before starting time" do
165
+ validate_inactive(zr_daily, "2013-03-31 00:00:00 -07:00")
166
+ validate_active(zr_daily_no_start_date, "2013-03-31 00:00:00 -07:00")
167
+ end
168
+ end
169
+
170
+ context "weekly" do
171
+ let(:zr_weekly) { ZoneRanger::Core.new('2013-04-01 00:01:00 -07:00', 60, "Pacific Time (US & Canada)", :repeat => :weekly) }
172
+
173
+ it "should cover only on the day of week, and in time range" do
174
+ validate_active(zr_weekly, '2013-04-01 00:01:01 -07:00')
175
+ validate_active(zr_weekly, '2013-04-01 00:59:59 -07:00')
176
+
177
+ # next week
178
+ validate_active(zr_weekly, '2013-04-08 00:01:01 -07:00')
179
+ validate_active(zr_weekly, '2013-04-08 00:59:59 -07:00')
180
+ end
181
+
182
+ it "should not cover if on the day of week, but not in time range" do
183
+ validate_inactive(zr_weekly, '2013-04-08 00:00:59 -07:00')
184
+ validate_inactive(zr_weekly, '2013-04-08 01:02:59 -07:00')
185
+ end
186
+
187
+ it "should not cover if not on the day of week and in time range" do
188
+ validate_inactive(zr_weekly, '2013-04-07 00:01:01 -07:00')
189
+ validate_inactive(zr_weekly, '2013-04-07 00:59:59 -07:00')
190
+ end
191
+ end
192
+
193
+ context "monthly" do
194
+ context "day of the month" do
195
+
196
+ let(:zr_monthly_dom) { ZoneRanger::Core.new('2013-04-01 00:01:00 -07:00', 60, "Pacific Time (US & Canada)", :repeat => :monthly_by_day_of_month) }
197
+ let(:zr_monthly_dom2) { ZoneRanger::Core.new("2013-07-17 09:58 -04:00", 120, "Eastern Time (US & Canada)", :repeat => :monthly_by_day_of_month) }
198
+
199
+ it "should be active if on the day of the month of start_date and within the timeframe" do
200
+ validate_active(zr_monthly_dom, '2013-05-01 00:02:00 -07:00')
201
+ validate_active(zr_monthly_dom, '2013-05-01 00:59:00 -07:00')
202
+ validate_active(zr_monthly_dom, '2013-06-01 00:02:00 -07:00')
203
+ validate_active(zr_monthly_dom, '2013-06-01 00:59:00 -07:00')
204
+ end
205
+
206
+ it "should not be active if on the day of the month of start_date and within the timeframe but start_date is in the future" do
207
+ validate_inactive(zr_monthly_dom, '2013-03-01 00:02:00 -07:00')
208
+ validate_inactive(zr_monthly_dom, '2013-03-01 00:59:00 -07:00')
209
+ end
210
+
211
+ it "should not be active if within the timeframe but not on the day of the month" do
212
+ validate_inactive(zr_monthly_dom, '2013-04-03 00:02:00 -07:00')
213
+ validate_inactive(zr_monthly_dom, '2013-04-03 00:59:00 -07:00')
214
+ validate_inactive(zr_monthly_dom2, "Thu Jul 18 9:59:22 -0400 2013")
215
+ end
216
+
217
+
218
+
219
+ end
220
+
221
+ context "day of the week" do
222
+ let(:zr_monthly_dow) { ZoneRanger::Core.new('2013-04-01 00:01:00 -07:00', 60, "Pacific Time (US & Canada)", :repeat => :monthly_by_day_of_week) }
223
+
224
+ it "should be active if on the same weekday and xth week and inside timeframe" do
225
+ validate_active(zr_monthly_dow, "2013-04-01 00:02:00 -07:00")
226
+ validate_active(zr_monthly_dow, "2013-04-01 01:00:00 -07:00")
227
+
228
+ # next period
229
+ validate_active(zr_monthly_dow, "2013-05-06 00:02:00 -07:00")
230
+ validate_active(zr_monthly_dow, "2013-05-06 01:00:00 -07:00")
231
+ end
232
+
233
+ it "should not be active if on xth week and inside timeframe but not on same weekday" do
234
+ validate_inactive(zr_monthly_dow, "2013-05-05 00:02:00 -07:00")
235
+ validate_inactive(zr_monthly_dow, "2013-05-05 01:00:00 -07:00")
236
+ end
237
+
238
+ it "should not be active if on the same weekday and inside timeframe but not on xth week" do
239
+ validate_inactive(zr_monthly_dow, "2013-04-08 00:02:00 -07:00")
240
+ validate_inactive(zr_monthly_dow, "2013-04-08 01:00:00 -07:00")
241
+ end
242
+
243
+ it "should not be active if on the same weekday and xth week but outside timeframe" do
244
+ validate_inactive(zr_monthly_dow, "2013-04-01 00:00:00 -07:00")
245
+ validate_inactive(zr_monthly_dow, "2013-04-01 01:02:00 -07:00")
246
+
247
+ # next period
248
+ validate_inactive(zr_monthly_dow, "2013-05-06 00:00:00 -07:00")
249
+ validate_inactive(zr_monthly_dow, "2013-05-06 01:02:00 -07:00")
250
+ end
251
+ end
252
+
253
+ end
254
+ end
255
+
256
+ end
257
+
258
+ end
259
+
260
+ end
@@ -0,0 +1,4 @@
1
+ require 'zone_ranger'
2
+ require 'bundler/setup'
3
+
4
+ require 'timecop'
data/spec/util_spec.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe ZoneRanger::Util do
4
+ it "should pass" do
5
+ end
6
+
7
+ describe '#crosses_one_utc_midnight?' do
8
+ # let(:does_cross) { Factory(:check_blackout_period,
9
+ # :repeat_type => "daily",
10
+ # :start_time => "19:58", :end_time => "1:38", :start_date => nil)}
11
+ # let(:does_not_cross) { Factory(:check_blackout_period,
12
+ # :repeat_type => "daily",
13
+ # :start_time => "10:58", :end_time => "11:38", :start_date => nil)}
14
+ # let(:crossing_utc_weekly_blackout) { Factory(:check_blackout_period, :repeat_type => "weekly",
15
+ # :start_time => "19:58", :end_time => "1:30", :start_date => Date.parse('2013-07-17'))}
16
+
17
+ # it "should cross one midnight" do
18
+ # does_cross.send(:crosses_one_utc_midnight?).should be_true
19
+ # does_not_cross.send(:crosses_one_utc_midnight?).should be_false
20
+ # crossing_utc_weekly_blackout.send(:crosses_one_utc_midnight?).should be_true
21
+ # end
22
+ # end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'zone_ranger/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "zone_ranger"
8
+ spec.version = ZoneRanger::VERSION
9
+ spec.authors = ["Hubert Liu"]
10
+ spec.email = ["hubert.liu@rigor.com"]
11
+ spec.description = "Time Zone Ranger"
12
+ spec.summary = "Time Zone Ranger"
13
+ spec.homepage = "https://github.com/Rigor/zone_ranger"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "timecop", "~> 0.3.5"
25
+
26
+ spec.add_runtime_dependency "activesupport", "~> 3.0.20"
27
+ spec.add_runtime_dependency 'i18n' # required by active_support
28
+ spec.add_runtime_dependency 'tzinfo', '~> 0.3.35'
29
+ #spec.add_runtime_dependency 'tzinfo-data'
30
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zone_ranger
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Hubert Liu
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-09-16 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: bundler
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 9
29
+ segments:
30
+ - 1
31
+ - 3
32
+ version: "1.3"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rake
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: timecop
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ~>
70
+ - !ruby/object:Gem::Version
71
+ hash: 25
72
+ segments:
73
+ - 0
74
+ - 3
75
+ - 5
76
+ version: 0.3.5
77
+ type: :development
78
+ version_requirements: *id004
79
+ - !ruby/object:Gem::Dependency
80
+ name: activesupport
81
+ prerelease: false
82
+ requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ hash: 47
88
+ segments:
89
+ - 3
90
+ - 0
91
+ - 20
92
+ version: 3.0.20
93
+ type: :runtime
94
+ version_requirements: *id005
95
+ - !ruby/object:Gem::Dependency
96
+ name: i18n
97
+ prerelease: false
98
+ requirement: &id006 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ type: :runtime
108
+ version_requirements: *id006
109
+ - !ruby/object:Gem::Dependency
110
+ name: tzinfo
111
+ prerelease: false
112
+ requirement: &id007 !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ hash: 85
118
+ segments:
119
+ - 0
120
+ - 3
121
+ - 35
122
+ version: 0.3.35
123
+ type: :runtime
124
+ version_requirements: *id007
125
+ description: Time Zone Ranger
126
+ email:
127
+ - hubert.liu@rigor.com
128
+ executables: []
129
+
130
+ extensions: []
131
+
132
+ extra_rdoc_files: []
133
+
134
+ files:
135
+ - .gitignore
136
+ - Gemfile
137
+ - Gemfile.lock
138
+ - LICENSE
139
+ - README.md
140
+ - Rakefile
141
+ - lib/zone_ranger.rb
142
+ - lib/zone_ranger/core.rb
143
+ - lib/zone_ranger/util.rb
144
+ - lib/zone_ranger/version.rb
145
+ - spec/core_spec.rb
146
+ - spec/spec_helper.rb
147
+ - spec/util_spec.rb
148
+ - zone_ranger.gemspec
149
+ homepage: https://github.com/Rigor/zone_ranger
150
+ licenses:
151
+ - MIT
152
+ post_install_message:
153
+ rdoc_options: []
154
+
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ hash: 3
163
+ segments:
164
+ - 0
165
+ version: "0"
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ none: false
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ hash: 3
172
+ segments:
173
+ - 0
174
+ version: "0"
175
+ requirements: []
176
+
177
+ rubyforge_project:
178
+ rubygems_version: 1.8.15
179
+ signing_key:
180
+ specification_version: 3
181
+ summary: Time Zone Ranger
182
+ test_files:
183
+ - spec/core_spec.rb
184
+ - spec/spec_helper.rb
185
+ - spec/util_spec.rb