rrule 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 102a445f4ce73b7678d2ba5ce981dd97265cd96eaba985a1a88fc65bef7dd6f5
4
- data.tar.gz: 436d7cf84a7e8673e3909a6b0dc6b629c348ca1b0a2df83b133201e7e46413b0
3
+ metadata.gz: ad88610152ac491684d813f22ced6298dd37075b43c0832bf5ddea6b722e5906
4
+ data.tar.gz: 8c18b1a8f5244cefe797e77a73fd6717cd0e4e754b7858045e2480c24a0d4a12
5
5
  SHA512:
6
- metadata.gz: 6b59c32ff4f679d3f7d1e8944b87e460d1a2ea5aa0bd7c38d3039cd62fb60af56dbc41e23eef63b42add7c3136e4af4ab62ef166e1c1cb643cff89e9a4784d9c
7
- data.tar.gz: 8040ef1e6d6c127e33352032e0bb146a46a1ba22c01237fac1a14343bac6f751803cd2582ec7058dd1d32cf0e319aa8e439be5f312ff189a755b28c48efaa985
6
+ metadata.gz: 97d4c45d2cc25a7624f4b237b8b309d878f27cff652e2f45b50141d57b2273da3b715f1f967e6885e2b669904e8e748bd2f09c34c9aa91d6b03ca759c567f387
7
+ data.tar.gz: fa4a974eb0acd3244232acafaf97a3220e2539673da54efcc116f6042272919805828a9b7aff3668675f25d22f295e21ac172764a085f4e1ea0749c35770c489
@@ -0,0 +1,41 @@
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.0.0
14
+ - 3.1.0
15
+ - 3.2.0
16
+ - 3.3.0
17
+ gemfile:
18
+ - gemfiles/activesupport_6_1.gemfile
19
+ - gemfiles/activesupport_7_0.gemfile
20
+ - gemfiles/activesupport_7_1.gemfile
21
+
22
+ name: Ruby ${{ matrix.ruby }} using Gemfile ${{ matrix.gemfile }}
23
+ env:
24
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
25
+ steps:
26
+ - uses: actions/checkout@v3
27
+ - uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby }}
30
+ - name: 'Update gem command'
31
+ run: yes | gem update --system --force
32
+ - name: 'Update Bundler'
33
+ run: gem install bundler
34
+ - uses: actions/cache@v2
35
+ with:
36
+ path: vendor/bundle
37
+ key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
38
+ restore-keys: |
39
+ ${{ runner.os }}-gems-
40
+ - run: bundle install
41
+ - run: bundle exec rake
data/.rubocop.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.6
3
+ NewCops: disable
3
4
  Exclude:
4
5
  - 'gemfiles/**/*'
5
6
  - Appraisals
data/CHANGELOG.md CHANGED
@@ -1,9 +1,30 @@
1
1
  Change Log
2
2
  ==========
3
3
 
4
+ Version 0.6.0 *(2024-03-07)*
5
+ ----------------------------
6
+ ## What's Changed
7
+ * Test support for Ruby 3.1 by @rmitchell-sq in https://github.com/square/ruby-rrule/pull/43
8
+ * Rule#between didn't work when `limit` was provided by @edruder in https://github.com/square/ruby-rrule/pull/44
9
+ * Added Rule#from by @edruder in https://github.com/square/ruby-rrule/pull/45
10
+ * Added Rule#to_s by @Andy9822 in https://github.com/square/ruby-rrule/pull/50
11
+ * Implement `RRule::Rule#humanize` by @craigmcnamara in https://github.com/square/ruby-rrule/pull/49
12
+ * Update missing documentation for version 0.5.0 by @rmitchell-sq in https://github.com/square/ruby-rrule/pull/53
13
+ * Pivot from Travis CI to GitHub Actions by @leoarnold in https://github.com/square/ruby-rrule/pull/48
14
+ * Updating supported Rubies to add new versions and remove EOL ones by @rmitchell-sq in https://github.com/square/ruby-rrule/pull/56
15
+ * Implement `RRule::Rule#is_finite?` by @bahriddin in https://github.com/square/ruby-rrule/pull/55
16
+
17
+ ## New Contributors
18
+ * @edruder made their first contribution in https://github.com/square/ruby-rrule/pull/44
19
+ * @Andy9822 made their first contribution in https://github.com/square/ruby-rrule/pull/50
20
+ * @craigmcnamara made their first contribution in https://github.com/square/ruby-rrule/pull/49
21
+ * @bahriddin made their first contribution in https://github.com/square/ruby-rrule/pull/55
22
+
23
+ **Full Changelog**: https://github.com/square/ruby-rrule/compare/v0.4.4...v0.5.1
24
+
4
25
  Version 0.5.0 *(2022-03-14)*
5
26
  ----------------------------
6
- Add #from method to Rule object
27
+ Added `#from` method. Added test support for Ruby 3.1. Fixed bug in `#between` method when `limit` was provided.
7
28
 
8
29
  Version 0.4.4 *(2022-03-01)*
9
30
  ----------------------------
data/Gemfile CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'pry', '~> 0.12.2'
5
+ gem 'pry', '~> 0.14.1'
6
6
  gem 'rake'
7
7
  gem 'rspec', '~> 3.8'
8
8
  gem 'rubocop', '0.63.1'
9
9
 
10
10
  platform :mri do
11
- gem 'pry-byebug'
11
+ gem 'pry-byebug', '~> 3.10.1'
12
12
  end
13
13
 
14
14
  gemspec
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,11 +2,11 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "pry", "~> 0.12.2"
5
+ gem "pry", "~> 0.14.1"
6
6
  gem "rake"
7
7
  gem "rspec", "~> 3.8"
8
8
  gem "rubocop", "0.63.1"
9
- gem "activesupport", "~> 5"
9
+ gem "activesupport", "~> 6.1"
10
10
 
11
11
  platforms :mri do
12
12
  gem "pry-byebug"
@@ -2,11 +2,11 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "pry", "~> 0.12.2"
5
+ gem "pry", "~> 0.14.1"
6
6
  gem "rake"
7
7
  gem "rspec", "~> 3.8"
8
8
  gem "rubocop", "0.63.1"
9
- gem "activesupport", "~> 6"
9
+ gem "activesupport", "~> 7.0"
10
10
 
11
11
  platforms :mri do
12
12
  gem "pry-byebug"
@@ -2,11 +2,11 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "pry", "~> 0.12.2"
5
+ gem "pry", "~> 0.14.1"
6
6
  gem "rake"
7
7
  gem "rspec", "~> 3.8"
8
8
  gem "rubocop", "0.63.1"
9
- gem "activesupport", "~> 7"
9
+ gem "activesupport", "~> 7.1"
10
10
 
11
11
  platforms :mri do
12
12
  gem "pry-byebug"
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
- if options[:freq] == 'YEARLY'
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
- elsif options[:freq] == 'MONTHLY'
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,214 @@
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
+ def initialize(rrule, options)
22
+ @rrule = rrule
23
+ @options = options
24
+
25
+ # Define instance method for each of the options.
26
+ options.each { |name, value| define_singleton_method("#{name}_option") { value } }
27
+ end
28
+
29
+ def to_s
30
+ @buffer = 'every'
31
+
32
+ send freq_option.downcase
33
+
34
+ raise 'Implement Until' if until_option
35
+ if count_option
36
+ add 'for'
37
+ add count_option
38
+ add plural?(count_option) ? 'times' : 'time'
39
+ end
40
+
41
+ @buffer
42
+ end
43
+
44
+ # Return nil if we're trying to access an option that isn't present.
45
+ def method_missing(method_name, *args)
46
+ if method_name.to_s.match?(OPTION_ATTRIBUTE_RE)
47
+ nil
48
+ else
49
+ super
50
+ end
51
+ end
52
+
53
+ def respond_to_missing?(method_name)
54
+ super || method_name.to_s.match?(OPTION_ATTRIBUTE_RE)
55
+ end
56
+
57
+ protected
58
+
59
+ def list(arr, formatter, final_delimiter = nil, delimiter: ',')
60
+ *rest, middle, tail = arr.map(&formatter)
61
+
62
+ if final_delimiter
63
+ [*rest, [middle, tail].compact.join(" #{final_delimiter} ")].join("#{delimiter} ")
64
+ else
65
+ [*rest, middle, tail].compact.join("#{delimiter} ")
66
+ end
67
+ end
68
+
69
+ def add(string)
70
+ @buffer += " #{string}"
71
+ end
72
+
73
+ def plural?(num)
74
+ num.to_i % 100 != 1
75
+ end
76
+
77
+ def daily
78
+ add interval_option if interval_option != 1
79
+
80
+ if byweekday_option && weekdays?
81
+ add plural?(interval_option) ? 'weekdays' : 'weekday'
82
+ else
83
+ add plural?(interval_option) ? 'days' : 'day'
84
+ end
85
+
86
+ if bymonth_option
87
+ add 'in'
88
+ _bymonth
89
+ end
90
+
91
+ if bymonthday_option
92
+ _bymonthday
93
+ elsif byweekday_option
94
+ _byweekday
95
+ elsif byhour_option
96
+ _byhour
97
+ end
98
+ end
99
+
100
+ def weekly
101
+ if interval_option != 1
102
+ add interval_option
103
+ add plural?(interval_option) ? 'weeks' : 'week'
104
+ end
105
+
106
+ if byweekday_option && weekdays?
107
+ if interval_option == 1
108
+ add plural?(interval_option) ? 'weekdays' : 'weekday'
109
+ else
110
+ add 'on'
111
+ add 'weekdays'
112
+ end
113
+ elsif byweekday_option && every_day?
114
+ add plural?(interval_option) ? 'days' : 'day'
115
+ else
116
+ add 'week' if interval_option == 1
117
+
118
+ if bymonth_option
119
+ add 'in'
120
+ _bymonth
121
+ end
122
+
123
+ if bymonthday_option
124
+ _bymonthday
125
+ elsif byweekday_option
126
+ _byweekday
127
+ end
128
+ end
129
+ end
130
+
131
+ def monthly
132
+ if bymonth_option
133
+ if interval_option != 1
134
+ add interval_option
135
+ add 'months'
136
+ add 'in' if plural?(interval_option)
137
+ end
138
+
139
+ _bymonth
140
+ else
141
+ add interval_option if interval_option != 1
142
+
143
+ add plural?(interval_option) ? 'months' : 'month'
144
+ end
145
+
146
+ if bymonthday_option
147
+ _bymonthday
148
+ elsif byweekday_option && weekdays?
149
+ add 'on'
150
+ add 'weekdays'
151
+ elsif byweekday_option || bynweekday_option
152
+ _byweekday
153
+ end
154
+ end
155
+
156
+ def weekdaytext(day)
157
+ [day.ordinal && nth(day.ordinal), DAY_NAMES[day.index]].compact.join(' ')
158
+ end
159
+
160
+ def all_weeks?
161
+ bynweekday_option.all? { |option| option.ordinal.nil? }
162
+ end
163
+
164
+ def every_day?
165
+ byweekday_option.sort_by(&:index).map { |day| WEEKDAYS[day.index]} == RRule::WEEKDAYS
166
+ end
167
+
168
+ def weekdays?
169
+ return false if byweekday_option.none?
170
+
171
+ byweekday_option.sort_by(&:index).map { |day| WEEKDAYS[day.index]} == RRule::WEEKDAYS - %w[SA SU]
172
+ end
173
+
174
+ def _bymonth
175
+ add list(this.options.bymonth, method(:monthtext), 'and')
176
+ end
177
+
178
+ def _byweekday
179
+ if byweekday_option.any?
180
+ add 'on'
181
+ add list(byweekday_option, method(:weekdaytext))
182
+ end
183
+
184
+ return unless bynweekday_option.any?
185
+
186
+ add 'and' if all_weeks?
187
+ add 'on the'
188
+ add list(bynweekday_option, method(:weekdaytext), 'and')
189
+ end
190
+
191
+ def _byhour
192
+ add 'at'
193
+ add list byhour_option, :to_s, 'and'
194
+ end
195
+
196
+ def nth(ordinal)
197
+ return 'last' if ordinal == -1
198
+
199
+ nth =
200
+ case npos = ordinal.abs
201
+ when 1, 21, 31
202
+ "#{npos}st"
203
+ when 2, 22
204
+ "#{npos}nd"
205
+ when 3, 23
206
+ "#{npos}rd"
207
+ else
208
+ "#{npos}th"
209
+ end
210
+
211
+ ordinal < 0 ? "#{nth} last" : nth
212
+ end
213
+ end
214
+ 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
data/lib/rrule/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RRule
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
data/lib/rrule/weekday.rb CHANGED
@@ -12,7 +12,7 @@ module RRule
12
12
  def self.parse(weekday)
13
13
  match = /([+-]?\d+)?([A-Z]{2})/.match(weekday)
14
14
  index = RRule::WEEKDAYS.index(match[2])
15
- ordinal = match[1] ? match[1].to_i : nil
15
+ ordinal = match[1]&.to_i
16
16
  new(index, ordinal)
17
17
  end
18
18
  end
data/lib/rrule.rb CHANGED
@@ -6,6 +6,7 @@ module RRule
6
6
  autoload :Rule, 'rrule/rule'
7
7
  autoload :Context, 'rrule/context'
8
8
  autoload :Weekday, 'rrule/weekday'
9
+ autoload :Humanizer, 'rrule/humanizer'
9
10
 
10
11
  autoload :Frequency, 'rrule/frequencies/frequency'
11
12
  autoload :Daily, 'rrule/frequencies/daily'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rrule
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Mitchell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-14 00:00:00.000000000 Z
11
+ date: 2024-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -44,9 +44,9 @@ executables: []
44
44
  extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
+ - ".github/workflows/test.yml"
47
48
  - ".gitignore"
48
49
  - ".rubocop.yml"
49
- - ".travis.yml"
50
50
  - Appraisals
51
51
  - CHANGELOG.md
52
52
  - CONTRIBUTING.md
@@ -54,12 +54,9 @@ files:
54
54
  - LICENSE.txt
55
55
  - README.md
56
56
  - Rakefile
57
- - gemfiles/activesupport_2.3_LTS.gemfile
58
- - gemfiles/activesupport_3.gemfile
59
- - gemfiles/activesupport_4.gemfile
60
- - gemfiles/activesupport_5.gemfile
61
- - gemfiles/activesupport_6.gemfile
62
- - gemfiles/activesupport_7.gemfile
57
+ - gemfiles/activesupport_6_1.gemfile
58
+ - gemfiles/activesupport_7_0.gemfile
59
+ - gemfiles/activesupport_7_1.gemfile
63
60
  - lib/rrule.rb
64
61
  - lib/rrule/context.rb
65
62
  - lib/rrule/filters/by_month.rb
@@ -76,6 +73,7 @@ files:
76
73
  - lib/rrule/generators/all_occurrences.rb
77
74
  - lib/rrule/generators/by_set_position.rb
78
75
  - lib/rrule/generators/generator.rb
76
+ - lib/rrule/humanizer.rb
79
77
  - lib/rrule/rule.rb
80
78
  - lib/rrule/version.rb
81
79
  - lib/rrule/weekday.rb
@@ -104,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
102
  - !ruby/object:Gem::Version
105
103
  version: '0'
106
104
  requirements: []
107
- rubygems_version: 3.1.6
105
+ rubygems_version: 3.2.33
108
106
  signing_key:
109
107
  specification_version: 4
110
108
  summary: RRule expansion
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: "../"
@@ -1,15 +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", "~> 4"
10
-
11
- platforms :mri do
12
- gem "pry-byebug"
13
- end
14
-
15
- gemspec path: "../"