rrule 0.4.1 → 0.4.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.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +25 -0
  4. data/.travis.yml +6 -1
  5. data/Gemfile +9 -0
  6. data/Rakefile +9 -3
  7. data/lib/rrule.rb +4 -0
  8. data/lib/rrule/context.rb +5 -3
  9. data/lib/rrule/filters/by_month.rb +2 -0
  10. data/lib/rrule/filters/by_month_day.rb +2 -0
  11. data/lib/rrule/filters/by_week_day.rb +2 -0
  12. data/lib/rrule/filters/by_week_number.rb +2 -0
  13. data/lib/rrule/filters/by_year_day.rb +3 -1
  14. data/lib/rrule/frequencies/daily.rb +2 -0
  15. data/lib/rrule/frequencies/frequency.rb +4 -12
  16. data/lib/rrule/frequencies/monthly.rb +2 -0
  17. data/lib/rrule/frequencies/simple_weekly.rb +6 -6
  18. data/lib/rrule/frequencies/weekly.rb +2 -0
  19. data/lib/rrule/frequencies/yearly.rb +2 -0
  20. data/lib/rrule/generators/all_occurrences.rb +2 -0
  21. data/lib/rrule/generators/by_set_position.rb +2 -0
  22. data/lib/rrule/generators/generator.rb +3 -1
  23. data/lib/rrule/rule.rb +18 -33
  24. data/lib/rrule/version.rb +5 -0
  25. data/lib/rrule/weekday.rb +3 -1
  26. data/rrule.gemspec +16 -10
  27. data/scripts/benchmark.rb +3 -1
  28. metadata +13 -56
  29. data/spec/context_spec.rb +0 -261
  30. data/spec/filters/by_month_day_spec.rb +0 -35
  31. data/spec/filters/by_month_spec.rb +0 -35
  32. data/spec/filters/by_week_day_spec.rb +0 -35
  33. data/spec/filters/by_week_number_spec.rb +0 -41
  34. data/spec/filters/by_year_day_spec.rb +0 -35
  35. data/spec/frequencies/daily_spec.rb +0 -62
  36. data/spec/frequencies/monthly_spec.rb +0 -63
  37. data/spec/frequencies/simple_weekly_spec.rb +0 -32
  38. data/spec/frequencies/weekly_spec.rb +0 -92
  39. data/spec/frequencies/yearly_spec.rb +0 -54
  40. data/spec/generators/all_occurrences_spec.rb +0 -44
  41. data/spec/generators/by_set_position_spec.rb +0 -39
  42. data/spec/generators/generator_spec.rb +0 -110
  43. data/spec/rule_spec.rb +0 -2338
  44. data/spec/spec_helper.rb +0 -23
  45. data/spec/weekday_spec.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1aad8dd06524a47f1d310b7f077db21f41696bc7
4
- data.tar.gz: f2e1673c1fd07da16c47fc96e944eeabef43578b
2
+ SHA256:
3
+ metadata.gz: 110d8805d4e642767c86d7e23f0b77d8d42a0a11ef3c5edf5c08ee2d8f78d4ab
4
+ data.tar.gz: 8dcd49b64e8300b5facdfb92c72485b6c87b3003ba9dc87116fe13ca9bd44bf5
5
5
  SHA512:
6
- metadata.gz: fa77f6132a2d47a45d8aab0a58af68a1ccd0417e22a9c2fc6ef4a2b14aef90e65040324177893773cba2b06e74373776105a19e078c5d81360f5e894b2cdec3c
7
- data.tar.gz: 4fddc6b136db1d57c8d8e89fe099820e572f13fc447647cdd7c43942a74112255c8720ad2b8c82a0cb1586a8a1bdb0e862ec12014f6f05c5982a86ce58207518
6
+ metadata.gz: 467ad003c49dea6fb320775f59a33f739405edd0b330b87512ed4e183bcd757f8e16e4deda296c6f916055056ba98ae0be623df3f78fc9b8c39b790ca4198db6
7
+ data.tar.gz: c51e63c57919c57c4954b66c4b55d77ed6f513117a338ea76c595239433a1bc983c50706e642ba3b7b596aaf1feb3d111743ba8bd945c61d372f099656170dbb
data/.gitignore CHANGED
@@ -1,4 +1,6 @@
1
+ Gemfile.lock
1
2
  .rspec
2
3
  *.gem
3
4
  *.sublime-project
4
5
  *.sublime-workspace
6
+ Gemfile.lock
@@ -0,0 +1,25 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+
4
+ Layout:
5
+ Enabled: false
6
+
7
+ Lint/NonLocalExitFromIterator:
8
+ Enabled: false
9
+
10
+ Metrics:
11
+ Enabled: false
12
+
13
+ Naming:
14
+ Enabled: false
15
+
16
+ Style/Documentation:
17
+ Enabled: false
18
+ Style/MultilineBlockChain:
19
+ Enabled: false
20
+ Style/NumericPredicate:
21
+ Enabled: false
22
+ Style/RescueModifier:
23
+ Enabled: false
24
+ Style/TrailingCommaInArrayLiteral:
25
+ EnforcedStyleForMultiline: comma
@@ -1,3 +1,8 @@
1
1
  language: ruby
2
+ sudo: false
2
3
  rvm:
3
- - 2.3.1
4
+ - 2.3.8
5
+ - 2.4.5
6
+ - 2.5.3
7
+ - 2.6.0
8
+ - ruby-head
data/Gemfile CHANGED
@@ -1,5 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
5
+ gem 'pry'
3
6
  gem 'rake'
7
+ gem 'rspec', '~> 3.8'
8
+ gem 'rubocop', '0.63.1'
9
+
10
+ platform :mri do
11
+ gem 'pry-byebug'
12
+ end
4
13
 
5
14
  gemspec
data/Rakefile CHANGED
@@ -1,12 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rubygems'
2
4
  require 'rake'
5
+ require 'bundler/gem_tasks'
3
6
  require 'rspec/core/rake_task'
4
- require File.expand_path('../lib/rrule', __FILE__)
7
+ require File.expand_path('lib/rrule', __dir__)
5
8
 
6
9
  RSpec::Core::RakeTask.new(:spec)
7
10
 
11
+ require 'rubocop/rake_task'
12
+ RuboCop::RakeTask.new
13
+
8
14
  namespace :spec do
9
- task :all => ['spec']
15
+ task all: ['spec']
10
16
  end
11
17
 
12
- task :default => 'spec:all'
18
+ task default: %w[spec:all rubocop]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/all'
2
4
 
3
5
  module RRule
@@ -22,6 +24,8 @@ module RRule
22
24
  autoload :AllOccurrences, 'rrule/generators/all_occurrences'
23
25
  autoload :BySetPosition, 'rrule/generators/by_set_position'
24
26
 
27
+ WEEKDAYS = %w[SU MO TU WE TH FR SA].freeze
28
+
25
29
  def self.parse(rrule, **options)
26
30
  Rule.new(rrule, **options)
27
31
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Context
3
5
  attr_reader :options, :dtstart, :tz, :day_of_year_mask, :year
@@ -17,14 +19,14 @@ module RRule
17
19
  possible_date_ranges = []
18
20
  if options[:freq] == 'YEARLY'
19
21
  if options[:bymonth]
20
- options[:bymonth].each do |month|
21
- possible_date_ranges.push(elapsed_days_in_year_by_month[(month - 1)..(month)])
22
+ options[:bymonth].each do |mon|
23
+ possible_date_ranges.push(elapsed_days_in_year_by_month[(mon - 1)..mon])
22
24
  end
23
25
  else
24
26
  possible_date_ranges = [[0, year_length_in_days]]
25
27
  end
26
28
  elsif options[:freq] == 'MONTHLY'
27
- possible_date_ranges = [elapsed_days_in_year_by_month[(month - 1)..(month)]]
29
+ possible_date_ranges = [elapsed_days_in_year_by_month[(month - 1)..month]]
28
30
  end
29
31
 
30
32
  unless possible_date_ranges.empty?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class ByMonth
3
5
  def initialize(by_months, context)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class ByMonthDay
3
5
  def initialize(by_month_days, context)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class ByWeekDay
3
5
  def initialize(weekdays, context)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class ByWeekNumber
3
5
  def initialize(by_week_numbers, context)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class ByYearDay
3
5
  def initialize(by_year_days, context)
@@ -6,7 +8,7 @@ module RRule
6
8
  end
7
9
 
8
10
  def reject?(i)
9
- !by_year_days.empty? &&
11
+ !by_year_days.empty? &&
10
12
  ((i < context.year_length_in_days && !by_year_days.include?(i + 1) && !by_year_days.include?(i - context.year_length_in_days)) ||
11
13
  (i >= context.year_length_in_days && !by_year_days.include?(i + 1 - context.year_length_in_days) && !by_year_days.include?(i - context.year_length_in_days - context.next_year_length_in_days)))
12
14
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Daily < Frequency
3
5
  def possible_days
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Frequency
3
5
  attr_reader :current_date, :filters, :generator, :timeset
@@ -12,9 +14,7 @@ module RRule
12
14
 
13
15
  def advance
14
16
  @current_date = current_date.advance(advance_by).tap do |new_date|
15
- unless same_month(current_date, new_date)
16
- context.rebuild(new_date.year, new_date.month)
17
- end
17
+ context.rebuild(new_date.year, new_date.month) unless same_month(current_date, new_date)
18
18
  end
19
19
  end
20
20
 
@@ -32,10 +32,6 @@ module RRule
32
32
  end
33
33
  end
34
34
 
35
- def possible_days
36
- fail NotImplementedError
37
- end
38
-
39
35
  def self.for_options(options)
40
36
  case options[:freq]
41
37
  when 'DAILY'
@@ -51,7 +47,7 @@ module RRule
51
47
  when 'YEARLY'
52
48
  Yearly
53
49
  else
54
- raise InvalidRRule, "Valid FREQ value is required"
50
+ raise InvalidRRule, 'Valid FREQ value is required'
55
51
  end
56
52
  end
57
53
 
@@ -62,9 +58,5 @@ module RRule
62
58
  def same_month(first_date, second_date)
63
59
  first_date.month == second_date.month && first_date.year == second_date.year
64
60
  end
65
-
66
- def advance_by
67
- fail NotImplementedError
68
- end
69
61
  end
70
62
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Monthly < Frequency
3
5
  def possible_days
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class SimpleWeekly < Frequency
3
5
  def next_occurrences
@@ -8,15 +10,13 @@ module RRule
8
10
  end
9
11
 
10
12
  def correct_current_date_if_needed
11
- if context.options[:byweekday].present?
12
- target_wday = context.options[:byweekday].first.index
13
+ target_wday = if context.options[:byweekday].present?
14
+ context.options[:byweekday].first.index
13
15
  else
14
- target_wday = context.dtstart.wday
16
+ context.dtstart.wday
15
17
  end
16
18
 
17
- while @current_date.wday != target_wday
18
- @current_date = @current_date + 1.day
19
- end
19
+ @current_date += 1.day while @current_date.wday != target_wday
20
20
  end
21
21
  end
22
22
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Weekly < Frequency
3
5
  def possible_days
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Yearly < Frequency
3
5
  def possible_days
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class AllOccurrences < Generator
3
5
  def combine_dates_and_times(dayset, timeset)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class BySetPosition < Generator
3
5
  attr_reader :by_set_positions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Generator
3
5
  attr_reader :context
@@ -31,4 +33,4 @@ module RRule
31
33
  end.flatten
32
34
  end
33
35
  end
34
- end
36
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Rule
3
5
  include Enumerable
@@ -25,11 +27,8 @@ module RRule
25
27
  end
26
28
 
27
29
  def each(floor_date: nil)
28
- floor_date ||= dtstart
29
30
  # If we have a COUNT or INTERVAL option, we have to start at dtstart, because those are relative to dtstart
30
- if count_or_interval_present?
31
- floor_date = dtstart
32
- end
31
+ floor_date = dtstart if count_or_interval_present? || floor_date.nil? || dtstart > floor_date
33
32
 
34
33
  return enum_for(:each, floor_date: floor_date) unless block_given?
35
34
  context = Context.new(options, dtstart, tz)
@@ -39,30 +38,20 @@ module RRule
39
38
  count = options[:count]
40
39
 
41
40
  filters = []
42
- if options[:bymonth]
43
- filters.push(ByMonth.new(options[:bymonth], context))
44
- end
41
+ filters.push(ByMonth.new(options[:bymonth], context)) if options[:bymonth]
45
42
 
46
- if options[:byweekno]
47
- filters.push(ByWeekNumber.new(options[:byweekno], context))
48
- end
43
+ filters.push(ByWeekNumber.new(options[:byweekno], context)) if options[:byweekno]
49
44
 
50
- if options[:byweekday]
51
- filters.push(ByWeekDay.new(options[:byweekday], context))
52
- end
45
+ filters.push(ByWeekDay.new(options[:byweekday], context)) if options[:byweekday]
53
46
 
54
- if options[:byyearday]
55
- filters.push(ByYearDay.new(options[:byyearday], context))
56
- end
47
+ filters.push(ByYearDay.new(options[:byyearday], context)) if options[:byyearday]
57
48
 
58
- if options[:bymonthday]
59
- filters.push(ByMonthDay.new(options[:bymonthday], context))
60
- end
49
+ filters.push(ByMonthDay.new(options[:bymonthday], context)) if options[:bymonthday]
61
50
 
62
- if options[:bysetpos]
63
- generator = BySetPosition.new(options[:bysetpos], context)
51
+ generator = if options[:bysetpos]
52
+ BySetPosition.new(options[:bysetpos], context)
64
53
  else
65
- generator = AllOccurrences.new(context)
54
+ AllOccurrences.new(context)
66
55
  end
67
56
 
68
57
  frequency = Frequency.for_options(options).new(context, filters, generator, timeset, start_date: floor_date)
@@ -117,15 +106,15 @@ module RRule
117
106
  i = begin
118
107
  Integer(value)
119
108
  rescue ArgumentError
120
- raise InvalidRRule, "COUNT must be a non-negative integer"
109
+ raise InvalidRRule, 'COUNT must be a non-negative integer'
121
110
  end
122
- raise InvalidRRule, "COUNT must be a non-negative integer" if i < 0
111
+ raise InvalidRRule, 'COUNT must be a non-negative integer' if i < 0
123
112
  options[:count] = i
124
113
  when 'UNTIL'
125
114
  options[:until] = Time.parse(value)
126
115
  when 'INTERVAL'
127
116
  i = Integer(value) rescue 0
128
- raise InvalidRRule, "INTERVAL must be a positive integer" unless i > 0
117
+ raise InvalidRRule, 'INTERVAL must be a positive integer' unless i > 0
129
118
  options[:interval] = i
130
119
  when 'BYHOUR'
131
120
  options[:byhour] = value.split(',').compact.map(&:to_i)
@@ -138,7 +127,7 @@ module RRule
138
127
  when 'BYSETPOS'
139
128
  options[:bysetpos] = value.split(',').map(&:to_i)
140
129
  when 'WKST'
141
- options[:wkst] = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'].index(value)
130
+ options[:wkst] = RRule::WEEKDAYS.index(value)
142
131
  when 'BYMONTH'
143
132
  options[:bymonth] = value.split(',').compact.map(&:to_i)
144
133
  when 'BYMONTHDAY'
@@ -150,12 +139,10 @@ module RRule
150
139
  end
151
140
  end
152
141
 
153
- if !(options[:byweekno] || options[:byyearday] || options[:bymonthday] || options[:byweekday])
142
+ unless options[:byweekno] || options[:byyearday] || options[:bymonthday] || options[:byweekday]
154
143
  case options[:freq]
155
144
  when 'YEARLY'
156
- unless options[:bymonth]
157
- options[:bymonth] = [dtstart.month]
158
- end
145
+ options[:bymonth] = [dtstart.month] unless options[:bymonth]
159
146
  options[:bymonthday] = [dtstart.day]
160
147
  when 'MONTHLY'
161
148
  options[:bymonthday] = [dtstart.day]
@@ -165,9 +152,7 @@ module RRule
165
152
  end
166
153
  end
167
154
 
168
- unless options[:byweekday].nil?
169
- options[:byweekday], options[:bynweekday] = options[:byweekday].partition { |wday| wday.ordinal.nil? }
170
- end
155
+ options[:byweekday], options[:bynweekday] = options[:byweekday].partition { |wday| wday.ordinal.nil? } unless options[:byweekday].nil?
171
156
 
172
157
  options[:timeset] = [{ hour: (options[:byhour].presence || dtstart.hour), minute: (options[:byminute].presence || dtstart.min), second: (options[:bysecond].presence || dtstart.sec) }]
173
158
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RRule
4
+ VERSION = '0.4.2'
5
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RRule
2
4
  class Weekday
3
5
  attr_reader :index, :ordinal
@@ -9,7 +11,7 @@ module RRule
9
11
 
10
12
  def self.parse(weekday)
11
13
  match = /([+-]?\d)?([A-Z]{2})/.match(weekday)
12
- index = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'].index(match[2])
14
+ index = RRule::WEEKDAYS.index(match[2])
13
15
  ordinal = match[1] ? match[1].to_i : nil
14
16
  new(index, ordinal)
15
17
  end
@@ -1,20 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'rrule/version'
6
+
1
7
  Gem::Specification.new do |s|
2
8
  s.name = 'rrule'
3
- s.version = '0.4.1'
4
- s.date = '2018-04-24'
9
+ s.version = RRule::VERSION
5
10
  s.summary = 'RRule expansion'
6
11
  s.description = 'A gem for expanding dates according to the RRule specification'
7
12
  s.authors = ['Ryan Mitchell']
8
13
  s.email = 'rmitchell@squareup.com'
9
- s.files = `git ls-files`.split($/)
10
- s.test_files = s.files.grep(%r{^(test|spec|features)/})
14
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
11
15
  s.require_paths = ['lib']
12
- s.homepage = 'http://rubygems.org/gems/rrule'
16
+ s.homepage = 'https://rubygems.org/gems/rrule'
17
+ s.metadata = {
18
+ 'homepage' => 'https://rubygems.org/gems/rrule',
19
+ 'source_code_uri' => 'https://github.com/square/ruby-rrule',
20
+ 'bug_tracker_uri' => 'https://github.com/square/ruby-rrule/issues',
21
+ 'changelog_uri' => 'https://github.com/square/ruby-rrule/blob/master/CHANGELOG.md'
22
+ }
13
23
 
14
- # Since Ruby 1.9.2, Time implementation uses a signed 63 bit integer, Bignum
15
- # or Rational. This enables Time to finally work with years after 2038 which
16
- # is critical for this library.
17
- s.required_ruby_version = '>= 1.9.2'
24
+ s.required_ruby_version = '>= 2.3.0'
18
25
  s.add_runtime_dependency 'activesupport', '>= 4.1'
19
- s.add_development_dependency 'rspec', '~> 3.4'
20
26
  end