rrule 0.5.0 → 0.7.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/.github/workflows/test.yml +37 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -0
- data/Appraisals +8 -18
- data/CHANGELOG.md +27 -1
- data/Gemfile +3 -6
- data/README.md +10 -0
- data/gemfiles/{activesupport_5.gemfile → activesupport_7_0.gemfile} +4 -7
- data/gemfiles/{activesupport_6.gemfile → activesupport_7_1.gemfile} +4 -7
- data/gemfiles/{activesupport_7.gemfile → activesupport_7_2.gemfile} +4 -7
- data/gemfiles/{activesupport_4.gemfile → activesupport_8_0.gemfile} +4 -7
- data/lib/rrule/context.rb +4 -2
- data/lib/rrule/frequencies/frequency.rb +6 -0
- data/lib/rrule/frequencies/hourly.rb +19 -0
- data/lib/rrule/frequencies/minutely.rb +19 -0
- data/lib/rrule/frequencies/secondly.rb +19 -0
- data/lib/rrule/humanizer.rb +249 -0
- data/lib/rrule/rule.rb +19 -5
- data/lib/rrule/version.rb +1 -1
- data/lib/rrule/weekday.rb +1 -1
- data/lib/rrule.rb +9 -1
- data/rrule.gemspec +0 -1
- metadata +12 -27
- data/.travis.yml +0 -36
- data/gemfiles/activesupport_2.3_LTS.gemfile +0 -16
- data/gemfiles/activesupport_3.gemfile +0 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 18b66d2de18ada244aeacb726282250b2d9790852df19256fbc60427d719e5ec
|
|
4
|
+
data.tar.gz: a89994f6528f083862167f71af7fefca19ecd556376d8d0072dc61644b1d7950
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 54e5ab9633d824c81c72e1fdafada840c77fa3154f7e56e8d553784bc000aac67937bd3860aa28bcdd4f62b19d5192c7fc5783abc02aff3bd0d72bca4bb7be8c
|
|
7
|
+
data.tar.gz: 2603169ed547adea95c88b0377afd6e9707d7845759aceb153c284b81c2b0971dfc4d73c47bcd0634db80c1fb08d3728b4805408ddacb1be3d935dae55657873
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
on:
|
|
2
|
+
pull_request:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- master
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
ruby:
|
|
13
|
+
- 3.2
|
|
14
|
+
- 3.3
|
|
15
|
+
- 3.4
|
|
16
|
+
|
|
17
|
+
name: Ruby ${{ matrix.ruby }}
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v3
|
|
20
|
+
- uses: ruby/setup-ruby@v1
|
|
21
|
+
with:
|
|
22
|
+
ruby-version: ${{ matrix.ruby }}
|
|
23
|
+
- name: 'Update gem command'
|
|
24
|
+
run: yes | gem update --system --force
|
|
25
|
+
- name: 'Update Bundler'
|
|
26
|
+
run: gem install bundler
|
|
27
|
+
- uses: actions/cache@v4
|
|
28
|
+
with:
|
|
29
|
+
path: vendor/bundle
|
|
30
|
+
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
|
31
|
+
restore-keys: |
|
|
32
|
+
${{ runner.os }}-gems-
|
|
33
|
+
- run: bundle install
|
|
34
|
+
- name: 'Ensure appraisals are up to date'
|
|
35
|
+
run: appraisal clean && appraisal generate && git diff --exit-code
|
|
36
|
+
- run: appraisal install
|
|
37
|
+
- run: appraisal rake
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Appraisals
CHANGED
|
@@ -1,27 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
appraise 'activesupport-
|
|
4
|
-
gem '
|
|
5
|
-
gem 'activesupport', '>= 2', git: 'https://github.com/makandra/rails.git', branch: '2-3-lts'
|
|
3
|
+
appraise 'activesupport-7_0' do
|
|
4
|
+
gem 'activesupport', '~> 7.0'
|
|
6
5
|
end
|
|
7
6
|
|
|
8
|
-
appraise 'activesupport-
|
|
9
|
-
gem 'activesupport', '~>
|
|
10
|
-
gem 'tzinfo', '~> 1.2'
|
|
7
|
+
appraise 'activesupport-7_1' do
|
|
8
|
+
gem 'activesupport', '~> 7.1'
|
|
11
9
|
end
|
|
12
10
|
|
|
13
|
-
appraise 'activesupport-
|
|
14
|
-
gem 'activesupport', '~>
|
|
11
|
+
appraise 'activesupport-7_2' do
|
|
12
|
+
gem 'activesupport', '~> 7.2'
|
|
15
13
|
end
|
|
16
14
|
|
|
17
|
-
appraise 'activesupport-
|
|
18
|
-
gem 'activesupport', '~>
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
appraise 'activesupport-6' do
|
|
22
|
-
gem 'activesupport', '~> 6'
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
appraise 'activesupport-7' do
|
|
26
|
-
gem 'activesupport', '~> 7'
|
|
15
|
+
appraise 'activesupport-8_0' do
|
|
16
|
+
gem 'activesupport', '~> 8.0'
|
|
27
17
|
end
|
data/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
1
|
Change Log
|
|
2
2
|
==========
|
|
3
3
|
|
|
4
|
+
Version 0.7.0 *(2025-10-20)*
|
|
5
|
+
----------------------------
|
|
6
|
+
## What's Changed
|
|
7
|
+
* Add support for `YEARLY` `BYMONTHDAY` https://github.com/square/ruby-rrule/pull/69
|
|
8
|
+
|
|
9
|
+
Version 0.6.0 *(2024-03-07)*
|
|
10
|
+
----------------------------
|
|
11
|
+
## What's Changed
|
|
12
|
+
* Test support for Ruby 3.1 by @rmitchell-sq in https://github.com/square/ruby-rrule/pull/43
|
|
13
|
+
* Rule#between didn't work when `limit` was provided by @edruder in https://github.com/square/ruby-rrule/pull/44
|
|
14
|
+
* Added Rule#from by @edruder in https://github.com/square/ruby-rrule/pull/45
|
|
15
|
+
* Added Rule#to_s by @Andy9822 in https://github.com/square/ruby-rrule/pull/50
|
|
16
|
+
* Implement `RRule::Rule#humanize` by @craigmcnamara in https://github.com/square/ruby-rrule/pull/49
|
|
17
|
+
* Update missing documentation for version 0.5.0 by @rmitchell-sq in https://github.com/square/ruby-rrule/pull/53
|
|
18
|
+
* Pivot from Travis CI to GitHub Actions by @leoarnold in https://github.com/square/ruby-rrule/pull/48
|
|
19
|
+
* Updating supported Rubies to add new versions and remove EOL ones by @rmitchell-sq in https://github.com/square/ruby-rrule/pull/56
|
|
20
|
+
* Implement `RRule::Rule#is_finite?` by @bahriddin in https://github.com/square/ruby-rrule/pull/55
|
|
21
|
+
|
|
22
|
+
## New Contributors
|
|
23
|
+
* @edruder made their first contribution in https://github.com/square/ruby-rrule/pull/44
|
|
24
|
+
* @Andy9822 made their first contribution in https://github.com/square/ruby-rrule/pull/50
|
|
25
|
+
* @craigmcnamara made their first contribution in https://github.com/square/ruby-rrule/pull/49
|
|
26
|
+
* @bahriddin made their first contribution in https://github.com/square/ruby-rrule/pull/55
|
|
27
|
+
|
|
28
|
+
**Full Changelog**: https://github.com/square/ruby-rrule/compare/v0.4.4...v0.5.1
|
|
29
|
+
|
|
4
30
|
Version 0.5.0 *(2022-03-14)*
|
|
5
31
|
----------------------------
|
|
6
|
-
|
|
32
|
+
Added `#from` method. Added test support for Ruby 3.1. Fixed bug in `#between` method when `limit` was provided.
|
|
7
33
|
|
|
8
34
|
Version 0.4.4 *(2022-03-01)*
|
|
9
35
|
----------------------------
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -30,6 +30,16 @@ rrule.between(Time.new(2016, 6, 23), Time.new(2016, 6, 24))
|
|
|
30
30
|
=> [2016-06-23 16:45:32 -0700]
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
You can generate all instances starting from a specified date with the `#from` method:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
rrule = RRule::Rule.new('FREQ=DAILY;COUNT=3', dtstart: Time.new(2016, 1, 1))
|
|
37
|
+
rrule.all
|
|
38
|
+
=> [2016-01-01 16:45:32 -0700, 2016-01-02 16:45:32 -0700, 2016-01-03 16:45:32 -0700]
|
|
39
|
+
rrule.from(Time.new(2016, 1, 2))
|
|
40
|
+
=> [2016-01-02 16:45:32 -0700, 2016-01-03 16:45:32 -0700]
|
|
41
|
+
```
|
|
42
|
+
|
|
33
43
|
You can limit the number of instances that are returned with the `limit` option:
|
|
34
44
|
|
|
35
45
|
```ruby
|
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
gem "
|
|
5
|
+
gem "appraisal"
|
|
6
|
+
gem "pry-byebug"
|
|
6
7
|
gem "rake"
|
|
7
|
-
gem "rspec"
|
|
8
|
+
gem "rspec"
|
|
8
9
|
gem "rubocop", "0.63.1"
|
|
9
|
-
gem "activesupport", "~>
|
|
10
|
-
|
|
11
|
-
platforms :mri do
|
|
12
|
-
gem "pry-byebug"
|
|
13
|
-
end
|
|
10
|
+
gem "activesupport", "~> 7.0"
|
|
14
11
|
|
|
15
12
|
gemspec path: "../"
|
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
gem "
|
|
5
|
+
gem "appraisal"
|
|
6
|
+
gem "pry-byebug"
|
|
6
7
|
gem "rake"
|
|
7
|
-
gem "rspec"
|
|
8
|
+
gem "rspec"
|
|
8
9
|
gem "rubocop", "0.63.1"
|
|
9
|
-
gem "activesupport", "~>
|
|
10
|
-
|
|
11
|
-
platforms :mri do
|
|
12
|
-
gem "pry-byebug"
|
|
13
|
-
end
|
|
10
|
+
gem "activesupport", "~> 7.1"
|
|
14
11
|
|
|
15
12
|
gemspec path: "../"
|
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
gem "
|
|
5
|
+
gem "appraisal"
|
|
6
|
+
gem "pry-byebug"
|
|
6
7
|
gem "rake"
|
|
7
|
-
gem "rspec"
|
|
8
|
+
gem "rspec"
|
|
8
9
|
gem "rubocop", "0.63.1"
|
|
9
|
-
gem "activesupport", "~> 7"
|
|
10
|
-
|
|
11
|
-
platforms :mri do
|
|
12
|
-
gem "pry-byebug"
|
|
13
|
-
end
|
|
10
|
+
gem "activesupport", "~> 7.2"
|
|
14
11
|
|
|
15
12
|
gemspec path: "../"
|
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
gem "
|
|
5
|
+
gem "appraisal"
|
|
6
|
+
gem "pry-byebug"
|
|
6
7
|
gem "rake"
|
|
7
|
-
gem "rspec"
|
|
8
|
+
gem "rspec"
|
|
8
9
|
gem "rubocop", "0.63.1"
|
|
9
|
-
gem "activesupport", "~>
|
|
10
|
-
|
|
11
|
-
platforms :mri do
|
|
12
|
-
gem "pry-byebug"
|
|
13
|
-
end
|
|
10
|
+
gem "activesupport", "~> 8.0"
|
|
14
11
|
|
|
15
12
|
gemspec path: "../"
|
data/lib/rrule/context.rb
CHANGED
|
@@ -17,7 +17,9 @@ module RRule
|
|
|
17
17
|
|
|
18
18
|
if options[:bynweekday] && !options[:bynweekday].empty? && (month != last_month || year != last_year)
|
|
19
19
|
possible_date_ranges = []
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
case options[:freq]
|
|
22
|
+
when 'YEARLY'
|
|
21
23
|
if options[:bymonth]
|
|
22
24
|
options[:bymonth].each do |mon|
|
|
23
25
|
possible_date_ranges.push(elapsed_days_in_year_by_month[(mon - 1)..mon])
|
|
@@ -25,7 +27,7 @@ module RRule
|
|
|
25
27
|
else
|
|
26
28
|
possible_date_ranges = [[0, year_length_in_days]]
|
|
27
29
|
end
|
|
28
|
-
|
|
30
|
+
when 'MONTHLY'
|
|
29
31
|
possible_date_ranges = [elapsed_days_in_year_by_month[(month - 1)..month]]
|
|
30
32
|
end
|
|
31
33
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RRule
|
|
4
|
+
class Hourly < Frequency
|
|
5
|
+
def possible_days
|
|
6
|
+
[current_date.yday - 1] # convert to 0-indexed
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def timeset
|
|
10
|
+
super.map { |time| time.merge(hour: current_date.hour) }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def advance_by
|
|
16
|
+
{ hours: context.options[:interval] }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RRule
|
|
4
|
+
class Minutely < Frequency
|
|
5
|
+
def possible_days
|
|
6
|
+
[current_date.yday - 1] # convert to 0-indexed
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def timeset
|
|
10
|
+
super.map { |time| time.merge(hour: current_date.hour, minute: current_date.min) }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def advance_by
|
|
16
|
+
{ minutes: context.options[:interval] }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RRule
|
|
4
|
+
class Secondly < Frequency
|
|
5
|
+
def possible_days
|
|
6
|
+
[current_date.yday - 1] # convert to 0-indexed
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def timeset
|
|
10
|
+
super.map { |time| time.merge(hour: current_date.hour, minute: current_date.min, second: current_date.sec) }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def advance_by
|
|
16
|
+
{ seconds: context.options[:interval] }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RRule
|
|
4
|
+
# Based off https://github.com/jakubroztocil/rrule/blob/master/src/nlp/totext.ts
|
|
5
|
+
#
|
|
6
|
+
class Humanizer
|
|
7
|
+
attr_reader :rrule, :options
|
|
8
|
+
|
|
9
|
+
OPTION_ATTRIBUTE_RE = /_option/.freeze
|
|
10
|
+
|
|
11
|
+
DAY_NAMES = %w[
|
|
12
|
+
Sunday
|
|
13
|
+
Monday
|
|
14
|
+
Tuesday
|
|
15
|
+
Wednesday
|
|
16
|
+
Thursday
|
|
17
|
+
Friday
|
|
18
|
+
Saturday
|
|
19
|
+
].freeze
|
|
20
|
+
|
|
21
|
+
MONTH_NAMES = %w[
|
|
22
|
+
January
|
|
23
|
+
February
|
|
24
|
+
March
|
|
25
|
+
April
|
|
26
|
+
May
|
|
27
|
+
June
|
|
28
|
+
July
|
|
29
|
+
August
|
|
30
|
+
September
|
|
31
|
+
October
|
|
32
|
+
November
|
|
33
|
+
December
|
|
34
|
+
].freeze
|
|
35
|
+
|
|
36
|
+
def initialize(rrule, options)
|
|
37
|
+
@rrule = rrule
|
|
38
|
+
@options = options
|
|
39
|
+
|
|
40
|
+
# Define instance method for each of the options.
|
|
41
|
+
options.each { |name, value| define_singleton_method("#{name}_option") { value } }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_s
|
|
45
|
+
@buffer = 'every'
|
|
46
|
+
|
|
47
|
+
send freq_option.downcase
|
|
48
|
+
|
|
49
|
+
raise 'Implement Until' if until_option
|
|
50
|
+
if count_option
|
|
51
|
+
add 'for'
|
|
52
|
+
add count_option
|
|
53
|
+
add plural?(count_option) ? 'times' : 'time'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
@buffer
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Return nil if we're trying to access an option that isn't present.
|
|
60
|
+
def method_missing(method_name, *args)
|
|
61
|
+
if method_name.to_s.match?(OPTION_ATTRIBUTE_RE)
|
|
62
|
+
nil
|
|
63
|
+
else
|
|
64
|
+
super
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def respond_to_missing?(method_name)
|
|
69
|
+
super || method_name.to_s.match?(OPTION_ATTRIBUTE_RE)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
protected
|
|
73
|
+
|
|
74
|
+
def list(arr, formatter, final_delimiter = nil, delimiter: ',')
|
|
75
|
+
*rest, middle, tail = arr.map(&formatter)
|
|
76
|
+
|
|
77
|
+
if final_delimiter
|
|
78
|
+
[*rest, [middle, tail].compact.join(" #{final_delimiter} ")].join("#{delimiter} ")
|
|
79
|
+
else
|
|
80
|
+
[*rest, middle, tail].compact.join("#{delimiter} ")
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def add(string)
|
|
85
|
+
@buffer += " #{string}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def plural?(num)
|
|
89
|
+
num.to_i % 100 != 1
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def daily
|
|
93
|
+
add interval_option if interval_option != 1
|
|
94
|
+
|
|
95
|
+
if byweekday_option && weekdays?
|
|
96
|
+
add plural?(interval_option) ? 'weekdays' : 'weekday'
|
|
97
|
+
else
|
|
98
|
+
add plural?(interval_option) ? 'days' : 'day'
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if bymonth_option
|
|
102
|
+
add 'in'
|
|
103
|
+
_bymonth
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
if bymonthday_option
|
|
107
|
+
_bymonthday
|
|
108
|
+
elsif byweekday_option
|
|
109
|
+
_byweekday
|
|
110
|
+
elsif byhour_option
|
|
111
|
+
_byhour
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def yearly
|
|
116
|
+
add interval_option if interval_option != 1
|
|
117
|
+
add plural?(interval_option) ? 'years' : 'year'
|
|
118
|
+
|
|
119
|
+
add 'on' if bymonthday_option || bymonth_option
|
|
120
|
+
|
|
121
|
+
add list(options.fetch(:bymonth), method(:monthtext), 'and') if bymonth_option
|
|
122
|
+
|
|
123
|
+
add list (bymonthday_option.map { |o| nth(o) }), :to_s, 'and' if bymonthday_option
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def weekly
|
|
127
|
+
if interval_option != 1
|
|
128
|
+
add interval_option
|
|
129
|
+
add plural?(interval_option) ? 'weeks' : 'week'
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if byweekday_option && weekdays?
|
|
133
|
+
if interval_option == 1
|
|
134
|
+
add plural?(interval_option) ? 'weekdays' : 'weekday'
|
|
135
|
+
else
|
|
136
|
+
add 'on'
|
|
137
|
+
add 'weekdays'
|
|
138
|
+
end
|
|
139
|
+
elsif byweekday_option && every_day?
|
|
140
|
+
add plural?(interval_option) ? 'days' : 'day'
|
|
141
|
+
else
|
|
142
|
+
add 'week' if interval_option == 1
|
|
143
|
+
|
|
144
|
+
if bymonth_option
|
|
145
|
+
add 'in'
|
|
146
|
+
_bymonth
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
if bymonthday_option
|
|
150
|
+
_bymonthday
|
|
151
|
+
elsif byweekday_option
|
|
152
|
+
_byweekday
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def monthly
|
|
158
|
+
if bymonth_option
|
|
159
|
+
if interval_option != 1
|
|
160
|
+
add interval_option
|
|
161
|
+
add 'months'
|
|
162
|
+
add 'in' if plural?(interval_option)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
_bymonth
|
|
166
|
+
else
|
|
167
|
+
add interval_option if interval_option != 1
|
|
168
|
+
|
|
169
|
+
add plural?(interval_option) ? 'months' : 'month'
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
if bymonthday_option
|
|
173
|
+
_bymonthday
|
|
174
|
+
elsif byweekday_option && weekdays?
|
|
175
|
+
add 'on'
|
|
176
|
+
add 'weekdays'
|
|
177
|
+
elsif byweekday_option || bynweekday_option
|
|
178
|
+
_byweekday
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def weekdaytext(day)
|
|
183
|
+
[day.ordinal && nth(day.ordinal), DAY_NAMES[day.index]].compact.join(' ')
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def monthtext(month)
|
|
187
|
+
MONTH_NAMES[month - 1]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def all_weeks?
|
|
191
|
+
bynweekday_option.all? { |option| option.ordinal.nil? }
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def every_day?
|
|
195
|
+
byweekday_option.sort_by(&:index).map { |day| WEEKDAYS[day.index]} == RRule::WEEKDAYS
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def weekdays?
|
|
199
|
+
return false if byweekday_option.none?
|
|
200
|
+
|
|
201
|
+
byweekday_option.sort_by(&:index).map { |day| WEEKDAYS[day.index]} == RRule::WEEKDAYS - %w[SA SU]
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def _bymonth
|
|
205
|
+
add list(options.fetch(:bymonth), method(:monthtext), 'and')
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def _byweekday
|
|
209
|
+
if byweekday_option.any?
|
|
210
|
+
add 'on'
|
|
211
|
+
add list(byweekday_option, method(:weekdaytext))
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
return unless bynweekday_option.any?
|
|
215
|
+
|
|
216
|
+
add 'and' if all_weeks?
|
|
217
|
+
add 'on the'
|
|
218
|
+
add list(bynweekday_option, method(:weekdaytext), 'and')
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def _bymonthday
|
|
222
|
+
add 'on the'
|
|
223
|
+
add list (bymonthday_option.map { |o| nth(o) }), :to_s, 'and'
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def _byhour
|
|
227
|
+
add 'at'
|
|
228
|
+
add list byhour_option, :to_s, 'and'
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def nth(ordinal)
|
|
232
|
+
return 'last' if ordinal == -1
|
|
233
|
+
|
|
234
|
+
nth =
|
|
235
|
+
case npos = ordinal.abs
|
|
236
|
+
when 1, 21, 31
|
|
237
|
+
"#{npos}st"
|
|
238
|
+
when 2, 22
|
|
239
|
+
"#{npos}nd"
|
|
240
|
+
when 3, 23
|
|
241
|
+
"#{npos}rd"
|
|
242
|
+
else
|
|
243
|
+
"#{npos}th"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
ordinal < 0 ? "#{nth} last" : nth
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
data/lib/rrule/rule.rb
CHANGED
|
@@ -8,6 +8,7 @@ module RRule
|
|
|
8
8
|
|
|
9
9
|
def initialize(rrule, dtstart: Time.now, tzid: 'UTC', exdate: [], max_year: nil)
|
|
10
10
|
@tz = tzid
|
|
11
|
+
@rrule = rrule
|
|
11
12
|
@dtstart = dtstart.is_a?(Date) ? dtstart : floor_to_seconds_in_timezone(dtstart)
|
|
12
13
|
@exdate = exdate
|
|
13
14
|
@options = parse_options(rrule)
|
|
@@ -16,6 +17,10 @@ module RRule
|
|
|
16
17
|
@max_date = DateTime.new(@max_year)
|
|
17
18
|
end
|
|
18
19
|
|
|
20
|
+
def to_s
|
|
21
|
+
@rrule
|
|
22
|
+
end
|
|
23
|
+
|
|
19
24
|
def all(limit: nil)
|
|
20
25
|
all_until(limit: limit)
|
|
21
26
|
end
|
|
@@ -78,6 +83,15 @@ module RRule
|
|
|
78
83
|
enumerator.next
|
|
79
84
|
end
|
|
80
85
|
|
|
86
|
+
def humanize
|
|
87
|
+
Humanizer.new(self, options).to_s
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def is_finite?
|
|
91
|
+
keys = %i[count until] & options.keys
|
|
92
|
+
!keys.empty?
|
|
93
|
+
end
|
|
94
|
+
|
|
81
95
|
private
|
|
82
96
|
|
|
83
97
|
attr_reader :options, :max_year, :max_date, :frequency_type
|
|
@@ -154,13 +168,13 @@ module RRule
|
|
|
154
168
|
end
|
|
155
169
|
end
|
|
156
170
|
|
|
157
|
-
unless options[:byweekno] || options[:byyearday] || options[:
|
|
171
|
+
unless options[:byweekno] || options[:byyearday] || options[:byweekday]
|
|
158
172
|
case options[:freq]
|
|
159
173
|
when 'YEARLY'
|
|
160
|
-
options[:bymonth] = [dtstart.month] unless options[:bymonth]
|
|
161
|
-
options[:bymonthday] = [dtstart.day]
|
|
174
|
+
options[:bymonth] = [dtstart.month] unless options[:bymonth] || (options[:bymonthday] && options[:count])
|
|
175
|
+
options[:bymonthday] = [dtstart.day] unless options[:bymonthday]
|
|
162
176
|
when 'MONTHLY'
|
|
163
|
-
options[:bymonthday] = [dtstart.day]
|
|
177
|
+
options[:bymonthday] = [dtstart.day] unless options[:bymonthday]
|
|
164
178
|
when 'WEEKLY'
|
|
165
179
|
options[:simple_weekly] = true
|
|
166
180
|
options[:byweekday] = [Weekday.new(dtstart.wday)]
|
|
@@ -173,7 +187,7 @@ module RRule
|
|
|
173
187
|
# when the associated "DTSTART" property has a DATE value type.
|
|
174
188
|
# These rule parts MUST be ignored in RECUR value that violate the
|
|
175
189
|
# above requirement
|
|
176
|
-
options[:timeset] = [{ hour:
|
|
190
|
+
options[:timeset] = [{ hour: options[:byhour].presence || dtstart.hour, minute: options[:byminute].presence || dtstart.min, second: options[:bysecond].presence || dtstart.sec }] unless dtstart.is_a?(Date)
|
|
177
191
|
|
|
178
192
|
options
|
|
179
193
|
end
|
data/lib/rrule/version.rb
CHANGED
data/lib/rrule/weekday.rb
CHANGED
data/lib/rrule.rb
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'active_support
|
|
3
|
+
require 'active_support'
|
|
4
|
+
require 'active_support/core_ext/time'
|
|
5
|
+
require 'active_support/core_ext/object/blank'
|
|
6
|
+
require 'active_support/core_ext/integer/time'
|
|
7
|
+
require 'active_support/core_ext/array/wrap'
|
|
4
8
|
|
|
5
9
|
module RRule
|
|
6
10
|
autoload :Rule, 'rrule/rule'
|
|
7
11
|
autoload :Context, 'rrule/context'
|
|
8
12
|
autoload :Weekday, 'rrule/weekday'
|
|
13
|
+
autoload :Humanizer, 'rrule/humanizer'
|
|
9
14
|
|
|
10
15
|
autoload :Frequency, 'rrule/frequencies/frequency'
|
|
16
|
+
autoload :Secondly, 'rrule/frequencies/secondly'
|
|
17
|
+
autoload :Minutely, 'rrule/frequencies/minutely'
|
|
18
|
+
autoload :Hourly, 'rrule/frequencies/hourly'
|
|
11
19
|
autoload :Daily, 'rrule/frequencies/daily'
|
|
12
20
|
autoload :Weekly, 'rrule/frequencies/weekly'
|
|
13
21
|
autoload :SimpleWeekly, 'rrule/frequencies/simple_weekly'
|
data/rrule.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rrule
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Mitchell
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -24,29 +23,15 @@ dependencies:
|
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: '2.3'
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: appraisal
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - ">="
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
34
|
-
type: :development
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - ">="
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0'
|
|
41
26
|
description: A gem for expanding dates according to the RRule specification
|
|
42
27
|
email: rmitchell@squareup.com
|
|
43
28
|
executables: []
|
|
44
29
|
extensions: []
|
|
45
30
|
extra_rdoc_files: []
|
|
46
31
|
files:
|
|
32
|
+
- ".github/workflows/test.yml"
|
|
47
33
|
- ".gitignore"
|
|
48
34
|
- ".rubocop.yml"
|
|
49
|
-
- ".travis.yml"
|
|
50
35
|
- Appraisals
|
|
51
36
|
- CHANGELOG.md
|
|
52
37
|
- CONTRIBUTING.md
|
|
@@ -54,12 +39,10 @@ files:
|
|
|
54
39
|
- LICENSE.txt
|
|
55
40
|
- README.md
|
|
56
41
|
- Rakefile
|
|
57
|
-
- gemfiles/
|
|
58
|
-
- gemfiles/
|
|
59
|
-
- gemfiles/
|
|
60
|
-
- gemfiles/
|
|
61
|
-
- gemfiles/activesupport_6.gemfile
|
|
62
|
-
- gemfiles/activesupport_7.gemfile
|
|
42
|
+
- gemfiles/activesupport_7_0.gemfile
|
|
43
|
+
- gemfiles/activesupport_7_1.gemfile
|
|
44
|
+
- gemfiles/activesupport_7_2.gemfile
|
|
45
|
+
- gemfiles/activesupport_8_0.gemfile
|
|
63
46
|
- lib/rrule.rb
|
|
64
47
|
- lib/rrule/context.rb
|
|
65
48
|
- lib/rrule/filters/by_month.rb
|
|
@@ -69,13 +52,17 @@ files:
|
|
|
69
52
|
- lib/rrule/filters/by_year_day.rb
|
|
70
53
|
- lib/rrule/frequencies/daily.rb
|
|
71
54
|
- lib/rrule/frequencies/frequency.rb
|
|
55
|
+
- lib/rrule/frequencies/hourly.rb
|
|
56
|
+
- lib/rrule/frequencies/minutely.rb
|
|
72
57
|
- lib/rrule/frequencies/monthly.rb
|
|
58
|
+
- lib/rrule/frequencies/secondly.rb
|
|
73
59
|
- lib/rrule/frequencies/simple_weekly.rb
|
|
74
60
|
- lib/rrule/frequencies/weekly.rb
|
|
75
61
|
- lib/rrule/frequencies/yearly.rb
|
|
76
62
|
- lib/rrule/generators/all_occurrences.rb
|
|
77
63
|
- lib/rrule/generators/by_set_position.rb
|
|
78
64
|
- lib/rrule/generators/generator.rb
|
|
65
|
+
- lib/rrule/humanizer.rb
|
|
79
66
|
- lib/rrule/rule.rb
|
|
80
67
|
- lib/rrule/version.rb
|
|
81
68
|
- lib/rrule/weekday.rb
|
|
@@ -89,7 +76,6 @@ metadata:
|
|
|
89
76
|
source_code_uri: https://github.com/square/ruby-rrule
|
|
90
77
|
bug_tracker_uri: https://github.com/square/ruby-rrule/issues
|
|
91
78
|
changelog_uri: https://github.com/square/ruby-rrule/blob/master/CHANGELOG.md
|
|
92
|
-
post_install_message:
|
|
93
79
|
rdoc_options: []
|
|
94
80
|
require_paths:
|
|
95
81
|
- lib
|
|
@@ -104,8 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
104
90
|
- !ruby/object:Gem::Version
|
|
105
91
|
version: '0'
|
|
106
92
|
requirements: []
|
|
107
|
-
rubygems_version: 3.
|
|
108
|
-
signing_key:
|
|
93
|
+
rubygems_version: 3.6.9
|
|
109
94
|
specification_version: 4
|
|
110
95
|
summary: RRule expansion
|
|
111
96
|
test_files: []
|
data/.travis.yml
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
language: ruby
|
|
2
|
-
sudo: false
|
|
3
|
-
rvm:
|
|
4
|
-
- 2.6.5
|
|
5
|
-
- 2.7.0
|
|
6
|
-
- 3.0.0
|
|
7
|
-
- 3.1.0
|
|
8
|
-
|
|
9
|
-
gemfile:
|
|
10
|
-
- gemfiles/activesupport_2.3_LTS.gemfile
|
|
11
|
-
- gemfiles/activesupport_3.gemfile
|
|
12
|
-
- gemfiles/activesupport_4.gemfile
|
|
13
|
-
- gemfiles/activesupport_5.gemfile
|
|
14
|
-
- gemfiles/activesupport_6.gemfile
|
|
15
|
-
- gemfiles/activesupport_7.gemfile
|
|
16
|
-
|
|
17
|
-
jobs:
|
|
18
|
-
exclude:
|
|
19
|
-
- rvm: 2.6.5
|
|
20
|
-
gemfile: gemfiles/activesupport_7.gemfile
|
|
21
|
-
- rvm: 2.7.0
|
|
22
|
-
gemfile: gemfiles/activesupport_3.gemfile
|
|
23
|
-
- rvm: 2.7.0
|
|
24
|
-
gemfile: gemfiles/activesupport_4.gemfile
|
|
25
|
-
- rvm: 3.0.0
|
|
26
|
-
gemfile: gemfiles/activesupport_3.gemfile
|
|
27
|
-
- rvm: 3.0.0
|
|
28
|
-
gemfile: gemfiles/activesupport_4.gemfile
|
|
29
|
-
- rvm: 3.1.0
|
|
30
|
-
gemfile: gemfiles/activesupport_3.gemfile
|
|
31
|
-
- rvm: 3.1.0
|
|
32
|
-
gemfile: gemfiles/activesupport_4.gemfile
|
|
33
|
-
|
|
34
|
-
before_install:
|
|
35
|
-
- yes | gem update --system --force
|
|
36
|
-
- gem install bundler
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# This file was generated by Appraisal
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
gem "pry", "~> 0.12.2"
|
|
6
|
-
gem "rake"
|
|
7
|
-
gem "rspec", "~> 3.8"
|
|
8
|
-
gem "rubocop", "0.63.1"
|
|
9
|
-
gem "rexml"
|
|
10
|
-
gem "activesupport", ">= 2", git: "https://github.com/makandra/rails.git", branch: "2-3-lts"
|
|
11
|
-
|
|
12
|
-
platforms :mri do
|
|
13
|
-
gem "pry-byebug"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
gemspec path: "../"
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# This file was generated by Appraisal
|
|
2
|
-
|
|
3
|
-
source "https://rubygems.org"
|
|
4
|
-
|
|
5
|
-
gem "pry", "~> 0.12.2"
|
|
6
|
-
gem "rake"
|
|
7
|
-
gem "rspec", "~> 3.8"
|
|
8
|
-
gem "rubocop", "0.63.1"
|
|
9
|
-
gem "activesupport", "~> 3"
|
|
10
|
-
gem "tzinfo", "~> 1.2"
|
|
11
|
-
|
|
12
|
-
platforms :mri do
|
|
13
|
-
gem "pry-byebug"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
gemspec path: "../"
|