repeatable 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|