scheduling 0.1.1 → 0.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.
@@ -1,4 +1,8 @@
1
- === 0.1.0 / 2013-08-16
1
+ === 0.1.1 / 2013-08-19
2
2
 
3
3
  * Initial release:
4
4
 
5
+ === 0.1.2 / 2013-08-19
6
+
7
+ Add Quarterly regularity class, which brings Date.quarterly, Date.q1, Date.q2, Date.q3, Date.q4, Date#qday, Date#quarter, and Date#next_quarter.
8
+
@@ -6,7 +6,7 @@
6
6
 
7
7
  == Description
8
8
 
9
- Plan and keep track of project/activity scheduling, including budgeting and accounting.
9
+ Classes for making schedules, that are regular (yearly, monthly, quarterly, etc.), irregular, or both (compound). Once a schedule is made, and given a target date range, the date of all occurances can be determined.
10
10
 
11
11
  == Features
12
12
 
@@ -2,6 +2,7 @@ require 'scheduling/version'
2
2
  require 'scheduling/intersection'
3
3
 
4
4
  require 'scheduling/regularity/monthly'
5
+ require 'scheduling/regularity/quarterly'
5
6
  require 'scheduling/regularity/yearly'
6
7
 
7
8
  require 'scheduling/schedule/regular_schedule'
@@ -0,0 +1,82 @@
1
+ class Date
2
+ def self.q1(year)
3
+ Date.new(year,1)
4
+ end
5
+
6
+ def self.q2(year)
7
+ Date.new(year,4)
8
+ end
9
+
10
+ def self.q3(year)
11
+ Date.new(year,7)
12
+ end
13
+
14
+ def self.q4(year)
15
+ Date.new(year,10)
16
+ end
17
+
18
+ def quarter
19
+ 1 + ((month - 1) / 3)
20
+ end
21
+
22
+ def self.quarterly year, quarter = 1, qday = 1
23
+ case quarter
24
+ when 1
25
+ self.q1(year) + (qday - 1)
26
+ when 2
27
+ self.q2(year) + (qday - 1)
28
+ when 3
29
+ self.q3(year) + (qday - 1)
30
+ when 4
31
+ self.q4(year) + (qday - 1)
32
+ else
33
+ raise ArgumentError, "quarter #{quarter} is not 1-4"
34
+ end
35
+ end
36
+
37
+ def qday
38
+ 1 + (self - Date.quarterly(self.year, quarter)).to_i
39
+ end
40
+
41
+ def next_quarter count = 1
42
+ raise ArgumentError, "count #{count} is < 1" if count < 1
43
+
44
+ quarter = self.quarter + count % 4
45
+ year = self.year + count / 4
46
+
47
+ if quarter > 4
48
+ year += 1
49
+ quarter = (quarter - 4)
50
+ end
51
+
52
+ Date.quarterly(year, quarter, self.qday)
53
+ end
54
+ end
55
+
56
+ module Scheduling
57
+ class Quarterly < Struct.new(:qday)
58
+ def occurances time_range
59
+ raise RangeDecreasingError if time_range.decreasing?
60
+ cur = Date.quarterly(time_range.min.year, time_range.min.quarter, qday)
61
+
62
+ start = time_range.min
63
+ if cur < start
64
+ cur = cur.next_quarter
65
+ end
66
+
67
+ occurances = []
68
+
69
+ stop = time_range.last
70
+ if time_range.exclude_end?
71
+ stop -= 1
72
+ end
73
+
74
+ while cur <= stop
75
+ occurances.push cur
76
+ cur = cur.next_quarter
77
+ end
78
+
79
+ return occurances
80
+ end
81
+ end
82
+ end
@@ -1,4 +1,4 @@
1
1
  module Scheduling
2
2
  # scheduling version
3
- VERSION = "0.1.1"
3
+ VERSION = "0.1.2"
4
4
  end
@@ -0,0 +1,164 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Date do
4
+
5
+ describe '.q1' do
6
+ it 'should produce a date starting Jan 1 of the given year' do
7
+ [1910, 2000, 2111].each do |year|
8
+ date = Date.q1(year)
9
+ date.month.should eq(1)
10
+ date.day.should eq(1)
11
+ end
12
+ end
13
+ end
14
+
15
+ describe '.q2' do
16
+ it 'should produce a date starting Apr 1 of the given year' do
17
+ [1910, 2000, 2111].each do |year|
18
+ date = Date.q2(year)
19
+ date.month.should eq(4)
20
+ date.day.should eq(1)
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '.q3' do
26
+ it 'should produce a date starting July 1 of the given year' do
27
+ [1910, 2000, 2111].each do |year|
28
+ date = Date.q3(year)
29
+ date.month.should eq(7)
30
+ date.day.should eq(1)
31
+ end
32
+ end
33
+ end
34
+
35
+ describe '.q4' do
36
+ it 'should produce a date starting Oct 1 of the given year' do
37
+ [1910, 2000, 2111].each do |year|
38
+ date = Date.q4(year)
39
+ date.month.should eq(10)
40
+ date.day.should eq(1)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#quarter' do
46
+ it 'should return 1 for quarters 1-3' do
47
+ [1,2,3].each do |quarter|
48
+ Date.new(2000,quarter).quarter.should eq(1)
49
+ end
50
+ end
51
+
52
+ it 'should return 2 for quarters 4-6' do
53
+ [4,5,6].each do |quarter|
54
+ Date.new(2000,quarter).quarter.should eq(2)
55
+ end
56
+ end
57
+
58
+ it 'should return 3 for quarters 7-9' do
59
+ [7,8,9].each do |quarter|
60
+ Date.new(2000,quarter).quarter.should eq(3)
61
+ end
62
+ end
63
+
64
+ it 'should return 4 for quarters 10-12' do
65
+ [10,11,12].each do |quarter|
66
+ Date.new(2000,quarter).quarter.should eq(4)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe '.quarterly' do
72
+ it 'should produce a Date instance' do
73
+ Date.quarterly(2000).should be_a Date
74
+ end
75
+
76
+ it 'should produce a date with given qday' do
77
+ [1,10,20,70,89].each do |qday|
78
+ Date.quarterly(1995,2,qday).qday.should eq(qday)
79
+ end
80
+ end
81
+ end
82
+
83
+ describe '#qday' do
84
+ it 'should return the number of days since the start of the last quarter' do
85
+ [
86
+ Date.new(2000,3,28),
87
+ Date.new(1999,10,15),
88
+ Date.new(2006,8,11),
89
+ Date.new(2045,12,31)
90
+ ].each do |date|
91
+ date.qday.should eq(1 + (date - Date.quarterly(date.year, date.quarter)))
92
+ end
93
+ end
94
+ end
95
+
96
+ describe '#next_quarter' do
97
+ it 'should return the a date that is number of quarters in the future' do
98
+ [
99
+ #{ :start => Date.quarterly(2000,3,28), :q_incr => 2, :expected => Date.quarterly(2001, 1, 28) },
100
+ #{ :start => Date.quarterly(2012,1), :q_incr => 5, :expected => Date.quarterly(2013, 2) },
101
+ #{ :start => Date.quarterly(2030,4,45), :q_incr => 11, :expected => Date.quarterly(2033, 3, 45) },
102
+ ].each do |hash|
103
+ hash[:start].next_quarter(hash[:q_incr]).should eq(hash[:expected])
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ describe Quarterly do
110
+ describe '#occurances' do
111
+ context 'time range spans less than 1 quarter' do
112
+ context 'original time not in qday range' do
113
+ it 'should return empty array' do
114
+ [
115
+ {:qday => 15, :range => Date.quarterly(2003,1,16)..Date.quarterly(2003,2,14)},
116
+ {:qday => 15, :range => Date.quarterly(2003,1,16)...Date.quarterly(2003,2,15)},
117
+ {:qday => 2, :range => Date.new(2021,1,3)...Date.new(2021,2,1)},
118
+ ].each do |hash|
119
+ Quarterly.new(hash[:qday]).occurances(hash[:range]).should be_empty
120
+ end
121
+ end
122
+ end
123
+
124
+ context 'original time is in qday range' do
125
+ it 'should return array with 1 element' do
126
+ [
127
+ {:qday => 15, :range => Date.quarterly(2003,1,16)...Date.quarterly(2003,2,16)},
128
+ {:qday => 15, :range => Date.quarterly(2003,1,14)...Date.quarterly(2003,2,15)},
129
+ {:qday => 10, :range => Date.quarterly(2003,3,88)..Date.quarterly(2003,4,22)},
130
+ {:qday => 22, :range => Date.quarterly(2003,3)...Date.quarterly(2003,4)},
131
+ ].each do |hash|
132
+ Quarterly.new(hash[:qday]).occurances(hash[:range]).count.should eq(1)
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ context 'time range spans more than 1 quarter but less than 2' do
139
+ context 'original time not in qday range' do
140
+ it 'should return array with 1 element' do
141
+ [
142
+ {:qday => 15, :range => Date.quarterly(2003,1,16)..Date.quarterly(2003,3,14)},
143
+ {:qday => 15, :range => Date.quarterly(2003,1,14)...Date.quarterly(2003,2,15)},
144
+ {:qday => 2, :range => Date.quarterly(2020,4,3)...Date.quarterly(2021,1,5)},
145
+ ].each do |hash|
146
+ Quarterly.new(hash[:qday]).occurances(hash[:range]).count.should eq(1)
147
+ end
148
+ end
149
+ end
150
+
151
+ context 'original time is in qday range' do
152
+ it 'should return array with 2 elements' do
153
+ [
154
+ {:qday => 15, :range => Date.quarterly(2003,1,15)...Date.quarterly(2003,3,15)},
155
+ {:qday => 15, :range => Date.quarterly(2003,1,16)...Date.quarterly(2003,3,16)},
156
+ {:qday => 22, :range => Date.quarterly(2003,3,1)...Date.quarterly(2004)},
157
+ ].each do |hash|
158
+ Quarterly.new(hash[:qday]).occurances(hash[:range]).count.should eq(2)
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scheduling
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-19 00:00:00.000000000 Z
12
+ date: 2013-08-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -111,6 +111,7 @@ files:
111
111
  - lib/scheduling.rb
112
112
  - lib/scheduling/intersection.rb
113
113
  - lib/scheduling/regularity/monthly.rb
114
+ - lib/scheduling/regularity/quarterly.rb
114
115
  - lib/scheduling/regularity/yearly.rb
115
116
  - lib/scheduling/schedule/compound_schedule.rb
116
117
  - lib/scheduling/schedule/irregular_schedule.rb
@@ -119,6 +120,7 @@ files:
119
120
  - scheduling.gemspec
120
121
  - spec/intersection_spec.rb
121
122
  - spec/regularity/monthly_spec.rb
123
+ - spec/regularity/quarterly_spec.rb
122
124
  - spec/regularity/yearly_spec.rb
123
125
  - spec/schedule/compound_schedule_spec.rb
124
126
  - spec/schedule/irregular_schedule_spec.rb
@@ -140,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
140
142
  version: '0'
141
143
  segments:
142
144
  - 0
143
- hash: -3343969679380982067
145
+ hash: -1329761715509626376
144
146
  required_rubygems_version: !ruby/object:Gem::Requirement
145
147
  none: false
146
148
  requirements:
@@ -149,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
151
  version: '0'
150
152
  segments:
151
153
  - 0
152
- hash: -3343969679380982067
154
+ hash: -1329761715509626376
153
155
  requirements: []
154
156
  rubyforge_project:
155
157
  rubygems_version: 1.8.23
@@ -159,6 +161,7 @@ summary: Make schedules, regular (yearly, monthly, etc.) or otherwise.
159
161
  test_files:
160
162
  - spec/intersection_spec.rb
161
163
  - spec/regularity/monthly_spec.rb
164
+ - spec/regularity/quarterly_spec.rb
162
165
  - spec/regularity/yearly_spec.rb
163
166
  - spec/schedule/compound_schedule_spec.rb
164
167
  - spec/schedule/irregular_schedule_spec.rb