repeatable 0.5.0 → 0.6.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -3
- data/CHANGELOG.md +17 -1
- data/Gemfile +4 -1
- data/README.md +24 -3
- data/lib/repeatable.rb +2 -0
- data/lib/repeatable/expression/base.rb +16 -0
- data/lib/repeatable/expression/day_in_month.rb +5 -1
- data/lib/repeatable/expression/difference.rb +28 -0
- data/lib/repeatable/expression/exact_date.rb +17 -0
- data/lib/repeatable/expression/range_in_year.rb +7 -1
- data/lib/repeatable/expression/weekday_in_month.rb +25 -3
- data/lib/repeatable/parser.rb +6 -0
- data/lib/repeatable/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a36439cf2a982c3ef546a1d7247517788a7f013
|
4
|
+
data.tar.gz: 81df50553e0f1e6894feed2b03f4512321c6973c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d489cdad639be6b5cd0dbbb9e320bc73bbacdc4df5fb402fd0c54d2355d8ca6cdb26015804d50378c020b1c677cc368e9669d182d4611d7899e37cb57f75a36b
|
7
|
+
data.tar.gz: 3cad5c6ff55fb408a85a4ebbea1ad5ba3c90db7b2733050af10bb8d7f3ffa79534a52a87c6d163fa505c30cdf52962d57b47a36e7b319449cf95eec021817d78
|
data/.travis.yml
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.1.
|
4
|
-
- 2.2.
|
5
|
-
- 2.3.
|
3
|
+
- 2.1.9
|
4
|
+
- 2.2.5
|
5
|
+
- 2.3.1
|
6
6
|
sudo: false
|
7
7
|
addons:
|
8
8
|
code_climate:
|
9
9
|
repo_token:
|
10
10
|
secure: fyZ7Ycc23fzfh8bBiqPUhlJGcIcnanZWqVc4nsKDJeE1G5ScW01+ot1g4miDWxo7w80gKRKP/PfoYf6lOQ1B5yJJCV0Z5fjoTW3y+EKksMuGNCFaWh8R73MIPlVtfOazGyI2t3l4zDWoik906wHHNQJFveMZawvZGrVMWF6YxKg=
|
11
|
+
after_success:
|
12
|
+
- bundle exec codeclimate-test-reporter
|
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,21 @@
|
|
2
2
|
|
3
3
|
### Unreleased
|
4
4
|
|
5
|
-
[Commits](https://github.com/molawson/repeatable/compare/v0.
|
5
|
+
[Commits](https://github.com/molawson/repeatable/compare/v0.6.0...master)
|
6
|
+
|
7
|
+
### 0.6.0 (2017-05-04)
|
8
|
+
|
9
|
+
Features:
|
10
|
+
|
11
|
+
* Add `Expression::Difference` for set differences between 2 schedules ([@danott][])
|
12
|
+
* Allow `Expression::DayInMonth` to take `:last` (or `'last'`) for its `day:` argument ([@PatrickLerner][])
|
13
|
+
* Allow `Expression::WeekdayInMonth` to take negative `count` argument for last, second-to-last, etc. of a given weekday ([@danielma][])
|
14
|
+
|
15
|
+
Bugfixes:
|
16
|
+
|
17
|
+
* Fix `Expression::RangeInYear` to properly handle using `start_day` and `end_day` when `start_month == end_month` ([@danielma][])
|
18
|
+
|
19
|
+
[Commits](https://github.com/molawson/repeatable/compare/v0.5.0...v0.6.0)
|
6
20
|
|
7
21
|
### 0.5.0 (2016-01-27)
|
8
22
|
|
@@ -65,3 +79,5 @@ Initial Release
|
|
65
79
|
|
66
80
|
|
67
81
|
[@danott]: https://github.com/danott
|
82
|
+
[@PatrickLerner]: https://github.com/PatrickLerner
|
83
|
+
[@danielma]: https://github.com/danielma
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -22,6 +22,10 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
$ gem install repeatable
|
24
24
|
|
25
|
+
## Requirements
|
26
|
+
|
27
|
+
Because this gem relies heavily on required keyword arguments, especially to make dumping and parsing of schedules simpler, this code will only work on **Ruby 2.1** and higher.
|
28
|
+
|
25
29
|
## Usage
|
26
30
|
|
27
31
|
### Building a Schedule
|
@@ -33,9 +37,9 @@ You can create a schedule in one of two ways.
|
|
33
37
|
Instantiate and compose each of the `Repeatable::Expression` objects manually.
|
34
38
|
|
35
39
|
```ruby
|
36
|
-
second_monday =
|
40
|
+
second_monday = Repeatable::Expression::WeekdayInMonth.new(weekday: 1, count: 2)
|
37
41
|
oct_thru_dec = Repeatable::Expression::RangeInYear.new(start_month: 10, end_month: 12)
|
38
|
-
intersection = Repeatable::
|
42
|
+
intersection = Repeatable::Expression::Intersection.new(second_monday, oct_thru_dec)
|
39
43
|
|
40
44
|
schedule = Repeatable::Schedule.new(intersection)
|
41
45
|
```
|
@@ -49,7 +53,8 @@ Or describe the same structure with a `Hash`, and the gem will handle instantiat
|
|
49
53
|
arg = {
|
50
54
|
intersection: [
|
51
55
|
{ weekday_in_month: { weekday: 1, count: 2 } },
|
52
|
-
{ range_in_year: { start_month: 10, end_month: 12 } }
|
56
|
+
{ range_in_year: { start_month: 10, end_month: 12 } },
|
57
|
+
{ exact_date: { date: "2015-08-01" } }
|
53
58
|
]
|
54
59
|
}
|
55
60
|
|
@@ -73,6 +78,10 @@ Repeatable::Expression::Union.new(expressions)
|
|
73
78
|
{ intersection: [] }
|
74
79
|
Repeatable::Expression::Intersection.new(expressions)
|
75
80
|
|
81
|
+
# Date is part of the first set (`included`) but not part of the second set (`excluded`)
|
82
|
+
{ difference: { included: expression, excluded: another_expression } }
|
83
|
+
Repeatable::Expression::Difference.new(included: expression, excluded: another_expression)
|
84
|
+
|
76
85
|
|
77
86
|
# DATES
|
78
87
|
|
@@ -84,6 +93,10 @@ Repeatable::Expression::Weekday.new(weekday: 0)
|
|
84
93
|
{ weekday_in_month: { weekday: 1, count: 3 } }
|
85
94
|
Repeatable::Expression::WeekdayInMonth.new(weekday: 1, count: 3)
|
86
95
|
|
96
|
+
# The last Thursday of every month
|
97
|
+
{ weekday_in_month: { weekday: 4, count: -1 } }
|
98
|
+
Repeatable::Expression::WeekdayInMonth.new(weekday: 4, count: -1)
|
99
|
+
|
87
100
|
# Every other Monday, starting from December 1, 2015
|
88
101
|
{ biweekly: { weekday: 1, start_date: '2015-12-01' } }
|
89
102
|
Repeatable::Expression::Biweekly.new(weekday: 1, start_date: Date.new(2015, 12, 1))
|
@@ -92,6 +105,10 @@ Repeatable::Expression::Biweekly.new(weekday: 1, start_date: Date.new(2015, 12,
|
|
92
105
|
{ day_in_month: { day: 13 } }
|
93
106
|
Repeatable::Expression::DayInMonth.new(day: 13)
|
94
107
|
|
108
|
+
# The last day of every month
|
109
|
+
{ day_in_month: { day: :last } }
|
110
|
+
Repeatable::Expression::DayInMonth.new(day: :last)
|
111
|
+
|
95
112
|
# All days in October
|
96
113
|
{ range_in_year: { start_month: 10 } }
|
97
114
|
Repeatable::Expression::RangeInYear.new(start_month: 10)
|
@@ -103,6 +120,10 @@ Repeatable::Expression::RangeInYear.new(start_month: 10, end_month: 12)
|
|
103
120
|
# All days from October 1 through December 20
|
104
121
|
{ range_in_year: { start_month: 10, end_month: 12, start_day: 1, end_day: 20 } }
|
105
122
|
Repeatable::Expression::RangeInYear.new(start_month: 10, end_month: 12, start_day: 1, end_day: 20)
|
123
|
+
|
124
|
+
# only December 21, 2012
|
125
|
+
{ exact_date: { date: '2012-12-21' } }
|
126
|
+
Repeatable::Expression::ExactDate.new(date: Date.new(2012, 12, 21)
|
106
127
|
```
|
107
128
|
|
108
129
|
#### Schedule Errors
|
data/lib/repeatable.rb
CHANGED
@@ -14,6 +14,7 @@ require 'repeatable/expression'
|
|
14
14
|
require 'repeatable/expression/base'
|
15
15
|
|
16
16
|
require 'repeatable/expression/date'
|
17
|
+
require 'repeatable/expression/exact_date'
|
17
18
|
require 'repeatable/expression/weekday'
|
18
19
|
require 'repeatable/expression/biweekly'
|
19
20
|
require 'repeatable/expression/weekday_in_month'
|
@@ -23,6 +24,7 @@ require 'repeatable/expression/range_in_year'
|
|
23
24
|
require 'repeatable/expression/set'
|
24
25
|
require 'repeatable/expression/union'
|
25
26
|
require 'repeatable/expression/intersection'
|
27
|
+
require 'repeatable/expression/difference'
|
26
28
|
|
27
29
|
require 'repeatable/schedule'
|
28
30
|
require 'repeatable/parser'
|
@@ -24,6 +24,22 @@ module Repeatable
|
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
27
|
+
def union(other)
|
28
|
+
Union.new(self, other)
|
29
|
+
end
|
30
|
+
alias + union
|
31
|
+
alias | union
|
32
|
+
|
33
|
+
def intersection(other)
|
34
|
+
Intersection.new(self, other)
|
35
|
+
end
|
36
|
+
alias & intersection
|
37
|
+
|
38
|
+
def difference(other)
|
39
|
+
Difference.new(included: self, excluded: other)
|
40
|
+
end
|
41
|
+
alias - difference
|
42
|
+
|
27
43
|
private
|
28
44
|
|
29
45
|
def hash_key
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Repeatable
|
2
|
+
module Expression
|
3
|
+
class Difference < Base
|
4
|
+
def initialize(included:, excluded:)
|
5
|
+
@included = included
|
6
|
+
@excluded = excluded
|
7
|
+
end
|
8
|
+
|
9
|
+
def include?(date)
|
10
|
+
included.include?(date) && !excluded.include?(date)
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
Hash[hash_key, { included: included.to_h, excluded: excluded.to_h }]
|
15
|
+
end
|
16
|
+
|
17
|
+
def ==(other)
|
18
|
+
other.is_a?(self.class) &&
|
19
|
+
included == other.included &&
|
20
|
+
excluded == other.excluded
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
attr_reader :included, :excluded
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -9,7 +9,13 @@ module Repeatable
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def include?(date)
|
12
|
-
|
12
|
+
return true if months_include?(date)
|
13
|
+
|
14
|
+
if start_month == end_month
|
15
|
+
start_month_include?(date) && end_month_include?(date)
|
16
|
+
else
|
17
|
+
start_month_include?(date) || end_month_include?(date)
|
18
|
+
end
|
13
19
|
end
|
14
20
|
|
15
21
|
def to_h
|
@@ -19,11 +19,33 @@ module Repeatable
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def week_matches?(date)
|
22
|
-
|
22
|
+
if negative_count?
|
23
|
+
week_from_end(date) == count
|
24
|
+
else
|
25
|
+
week_from_beginning(date) == count
|
26
|
+
end
|
23
27
|
end
|
24
28
|
|
25
|
-
def
|
26
|
-
(
|
29
|
+
def week_from_beginning(date)
|
30
|
+
week_in_month(date.day - 1)
|
31
|
+
end
|
32
|
+
|
33
|
+
def week_from_end(date)
|
34
|
+
-week_in_month(last_date_of_month(date).day - date.day)
|
35
|
+
end
|
36
|
+
|
37
|
+
def week_in_month(zero_indexed_day)
|
38
|
+
(zero_indexed_day / 7) + 1
|
39
|
+
end
|
40
|
+
|
41
|
+
def last_date_of_month(date)
|
42
|
+
next_month = date.next_month
|
43
|
+
first_day_of_next_month = ::Date.new(next_month.year, next_month.month, 1)
|
44
|
+
first_day_of_next_month.prev_day
|
45
|
+
end
|
46
|
+
|
47
|
+
def negative_count?
|
48
|
+
count < 0
|
27
49
|
end
|
28
50
|
end
|
29
51
|
end
|
data/lib/repeatable/parser.rb
CHANGED
@@ -32,6 +32,12 @@ module Repeatable
|
|
32
32
|
when Repeatable::Expression::Set
|
33
33
|
args = value.map { |hash| build_expression(hash) }
|
34
34
|
klass.new(*args)
|
35
|
+
when Repeatable::Expression::Difference
|
36
|
+
value = symbolize_keys(value)
|
37
|
+
klass.new(
|
38
|
+
included: build_expression(value[:included]),
|
39
|
+
excluded: build_expression(value[:excluded])
|
40
|
+
)
|
35
41
|
else
|
36
42
|
klass.new(symbolize_keys(value))
|
37
43
|
end
|
data/lib/repeatable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: repeatable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mo Lawson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -77,6 +77,8 @@ files:
|
|
77
77
|
- lib/repeatable/expression/biweekly.rb
|
78
78
|
- lib/repeatable/expression/date.rb
|
79
79
|
- lib/repeatable/expression/day_in_month.rb
|
80
|
+
- lib/repeatable/expression/difference.rb
|
81
|
+
- lib/repeatable/expression/exact_date.rb
|
80
82
|
- lib/repeatable/expression/intersection.rb
|
81
83
|
- lib/repeatable/expression/range_in_year.rb
|
82
84
|
- lib/repeatable/expression/set.rb
|
@@ -108,9 +110,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
110
|
version: '0'
|
109
111
|
requirements: []
|
110
112
|
rubyforge_project:
|
111
|
-
rubygems_version: 2.
|
113
|
+
rubygems_version: 2.5.2
|
112
114
|
signing_key:
|
113
115
|
specification_version: 4
|
114
116
|
summary: Describe recurring event schedules and calculate their occurrences
|
115
117
|
test_files: []
|
116
|
-
has_rdoc:
|