repeatable 0.5.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. data/.git-blame-ignore-revs +13 -0
  3. data/.github/workflows/ci.yml +72 -0
  4. data/.gitignore +0 -1
  5. data/.rspec +0 -1
  6. data/.standard.yml +3 -0
  7. data/CHANGELOG.md +58 -3
  8. data/CODE_OF_CONDUCT.md +128 -0
  9. data/Gemfile +11 -3
  10. data/Gemfile.lock +95 -0
  11. data/README.md +49 -9
  12. data/Rakefile +9 -3
  13. data/lib/repeatable/conversions.rb +5 -1
  14. data/lib/repeatable/expression/base.rb +37 -11
  15. data/lib/repeatable/expression/biweekly.rb +14 -6
  16. data/lib/repeatable/expression/date.rb +11 -8
  17. data/lib/repeatable/expression/day_in_month.rb +11 -1
  18. data/lib/repeatable/expression/difference.rb +37 -0
  19. data/lib/repeatable/expression/exact_date.rb +21 -0
  20. data/lib/repeatable/expression/intersection.rb +9 -0
  21. data/lib/repeatable/expression/range_in_year.rb +39 -9
  22. data/lib/repeatable/expression/set.rb +15 -7
  23. data/lib/repeatable/expression/union.rb +9 -0
  24. data/lib/repeatable/expression/weekday.rb +4 -0
  25. data/lib/repeatable/expression/weekday_in_month.rb +35 -4
  26. data/lib/repeatable/expression.rb +1 -0
  27. data/lib/repeatable/last_date_of_month.rb +11 -0
  28. data/lib/repeatable/parse_error.rb +1 -0
  29. data/lib/repeatable/parser.rb +14 -2
  30. data/lib/repeatable/schedule.rb +23 -9
  31. data/lib/repeatable/types.rb +6 -0
  32. data/lib/repeatable/version.rb +2 -1
  33. data/lib/repeatable.rb +25 -19
  34. data/rbi/repeatable.rbi +310 -0
  35. data/repeatable.gemspec +15 -15
  36. data/sorbet/config +3 -0
  37. data/sorbet/rbi/gems/ast.rbi +49 -0
  38. data/sorbet/rbi/gems/coderay.rbi +285 -0
  39. data/sorbet/rbi/gems/commander.rbi +197 -0
  40. data/sorbet/rbi/gems/docile.rbi +36 -0
  41. data/sorbet/rbi/gems/highline.rbi +577 -0
  42. data/sorbet/rbi/gems/method_source.rbi +64 -0
  43. data/sorbet/rbi/gems/parallel.rbi +83 -0
  44. data/sorbet/rbi/gems/parlour.rbi +840 -0
  45. data/sorbet/rbi/gems/parser.rbi +1950 -0
  46. data/sorbet/rbi/gems/pry.rbi +1898 -0
  47. data/sorbet/rbi/gems/rainbow.rbi +118 -0
  48. data/sorbet/rbi/gems/rake.rbi +646 -0
  49. data/sorbet/rbi/gems/regexp_parser.rbi +926 -0
  50. data/sorbet/rbi/gems/repeatable.rbi +13 -0
  51. data/sorbet/rbi/gems/rexml.rbi +583 -0
  52. data/sorbet/rbi/gems/rspec-core.rbi +1919 -0
  53. data/sorbet/rbi/gems/rspec-expectations.rbi +1150 -0
  54. data/sorbet/rbi/gems/rspec-mocks.rbi +1100 -0
  55. data/sorbet/rbi/gems/rspec-support.rbi +280 -0
  56. data/sorbet/rbi/gems/rspec.rbi +15 -0
  57. data/sorbet/rbi/gems/rubocop-ast.rbi +1356 -0
  58. data/sorbet/rbi/gems/rubocop-performance.rbi +487 -0
  59. data/sorbet/rbi/gems/rubocop.rbi +7923 -0
  60. data/sorbet/rbi/gems/ruby-progressbar.rbi +304 -0
  61. data/sorbet/rbi/gems/simplecov-html.rbi +35 -0
  62. data/sorbet/rbi/gems/simplecov.rbi +419 -0
  63. data/sorbet/rbi/gems/simplecov_json_formatter.rbi +47 -0
  64. data/sorbet/rbi/gems/standard.rbi +130 -0
  65. data/sorbet/rbi/gems/unicode-display_width.rbi +20 -0
  66. data/sorbet/rbi/hidden-definitions/errors.txt +4273 -0
  67. data/sorbet/rbi/hidden-definitions/hidden.rbi +9013 -0
  68. data/sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi +276 -0
  69. data/sorbet/rbi/sorbet-typed/lib/rake/all/rake.rbi +645 -0
  70. data/sorbet/rbi/sorbet-typed/lib/rspec-core/all/rspec-core.rbi +24 -0
  71. data/sorbet/rbi/sorbet-typed/lib/rubocop/>=1.8/rubocop.rbi +12 -0
  72. data/sorbet/rbi/sorbet-typed/lib/rubocop-performance/~>1.6/rubocop-performance.rbi +149 -0
  73. metadata +62 -45
  74. data/.travis.yml +0 -10
@@ -1,23 +1,31 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class Biweekly < Date
5
+ sig { params(weekday: Integer, start_after: Object).void }
4
6
  def initialize(weekday:, start_after: ::Date.today)
5
7
  @weekday = weekday
6
- @start_after = Date(start_after)
8
+ @start_after = T.let(Conversions::Date(start_after), ::Date)
9
+ @_first_occurrence = T.let(find_first_occurrence, ::Date)
7
10
  end
8
11
 
12
+ sig { override.params(date: ::Date).returns(T::Boolean) }
9
13
  def include?(date)
10
- date >= start_after && (date - first_occurrence) % 14 == 0
14
+ date >= start_after && (date - _first_occurrence) % 14 == 0
11
15
  end
12
16
 
13
17
  private
14
18
 
15
- attr_reader :weekday, :start_after
19
+ sig { returns(Integer) }
20
+ attr_reader :weekday
16
21
 
17
- def first_occurrence
18
- @first_occurrence ||= find_first_occurrence
19
- end
22
+ sig { returns(::Date) }
23
+ attr_reader :start_after
24
+
25
+ sig { returns(::Date) }
26
+ attr_reader :_first_occurrence
20
27
 
28
+ sig { returns(::Date) }
21
29
  def find_first_occurrence
22
30
  days_away = weekday - start_after.wday
23
31
  days_away += 7 if days_away <= 0
@@ -1,30 +1,33 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class Date < Base
5
+ abstract!
4
6
 
5
- def to_h
6
- Hash[hash_key, attributes]
7
- end
8
-
7
+ sig { params(other: Object).returns(T::Boolean) }
9
8
  def ==(other)
10
9
  other.is_a?(self.class) && attributes == other.attributes
11
10
  end
11
+ alias_method :eql?, :==
12
12
 
13
- alias eql? ==
14
-
13
+ sig { returns(Integer) }
15
14
  def hash
16
15
  [attributes.values, self.class.name].hash
17
16
  end
18
17
 
19
18
  protected
20
19
 
20
+ sig { returns(Types::SymbolHash) }
21
21
  def attributes
22
22
  instance_variables.each_with_object({}) do |name, hash|
23
- key = name.to_s.gsub(/^@/, '').to_sym
24
- hash[key] = normalize_attribute_value(instance_variable_get(name))
23
+ key = name.to_s.gsub(/^@/, "")
24
+ next if key.start_with?("_")
25
+ hash[key.to_sym] = normalize_attribute_value(instance_variable_get(name))
25
26
  end
26
27
  end
28
+ alias_method :hash_value, :attributes
27
29
 
30
+ sig { params(value: BasicObject).returns(T.untyped) }
28
31
  def normalize_attribute_value(value)
29
32
  case value
30
33
  when ::Date
@@ -1,16 +1,26 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class DayInMonth < Date
5
+ include LastDateOfMonth
6
+
7
+ sig { params(day: Integer).void }
4
8
  def initialize(day:)
5
9
  @day = day
6
10
  end
7
11
 
12
+ sig { override.params(date: ::Date).returns(T::Boolean) }
8
13
  def include?(date)
9
- date.day == day
14
+ if day < 0
15
+ date - last_date_of_month(date) - 1 == day
16
+ else
17
+ date.day == day
18
+ end
10
19
  end
11
20
 
12
21
  private
13
22
 
23
+ sig { returns(Integer) }
14
24
  attr_reader :day
15
25
  end
16
26
  end
@@ -0,0 +1,37 @@
1
+ # typed: strict
2
+ module Repeatable
3
+ module Expression
4
+ class Difference < Base
5
+ sig { params(included: Expression::Base, excluded: Expression::Base).void }
6
+ def initialize(included:, excluded:)
7
+ @included = included
8
+ @excluded = excluded
9
+ end
10
+
11
+ sig { override.params(date: ::Date).returns(T::Boolean) }
12
+ def include?(date)
13
+ included.include?(date) && !excluded.include?(date)
14
+ end
15
+
16
+ sig { params(other: Object).returns(T::Boolean) }
17
+ def ==(other)
18
+ other.is_a?(self.class) &&
19
+ included == other.included &&
20
+ excluded == other.excluded
21
+ end
22
+
23
+ protected
24
+
25
+ sig { returns(Expression::Base) }
26
+ attr_reader :included
27
+
28
+ sig { returns(Expression::Base) }
29
+ attr_reader :excluded
30
+
31
+ sig { override.returns(Types::SymbolHash) }
32
+ def hash_value
33
+ {included: included.to_h, excluded: excluded.to_h}
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ # typed: strict
2
+ module Repeatable
3
+ module Expression
4
+ class ExactDate < Date
5
+ sig { params(date: Object).void }
6
+ def initialize(date:)
7
+ @date = T.let(Conversions::Date(date), ::Date)
8
+ end
9
+
10
+ sig { override.params(other_date: ::Date).returns(T::Boolean) }
11
+ def include?(other_date)
12
+ date == other_date
13
+ end
14
+
15
+ private
16
+
17
+ sig { returns(::Date) }
18
+ attr_reader :date
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,15 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class Intersection < Set
5
+ sig { params(elements: T.any(Expression::Base, T::Array[Expression::Base])).void }
6
+ def initialize(*elements)
7
+ other_intersections, not_intersections = elements.partition { |e| e.is_a?(self.class) }
8
+ other_intersections = T.cast(other_intersections, T::Array[Expression::Intersection])
9
+ super(other_intersections.flat_map(&:elements).concat(not_intersections))
10
+ end
11
+
12
+ sig { override.params(date: ::Date).returns(T::Boolean) }
4
13
  def include?(date)
5
14
  elements.all? { |e| e.include?(date) }
6
15
  end
@@ -1,6 +1,15 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class RangeInYear < Date
5
+ sig do
6
+ params(
7
+ start_month: Integer,
8
+ end_month: Integer,
9
+ start_day: Integer,
10
+ end_day: Integer
11
+ ).void
12
+ end
4
13
  def initialize(start_month:, end_month: start_month, start_day: 0, end_day: 0)
5
14
  @start_month = start_month
6
15
  @end_month = end_month
@@ -8,33 +17,54 @@ module Repeatable
8
17
  @end_day = end_day
9
18
  end
10
19
 
20
+ sig { override.params(date: ::Date).returns(T::Boolean) }
11
21
  def include?(date)
12
- months_include?(date) || start_month_include?(date) || end_month_include?(date)
13
- end
22
+ return true if months_include?(date)
14
23
 
15
- def to_h
16
- args = { start_month: start_month }
17
- args[:end_month] = end_month unless end_month == start_month
18
- args[:start_day] = start_day unless start_day.zero?
19
- args[:end_day] = end_day unless end_day.zero?
20
- { range_in_year: args }
24
+ if start_month == end_month
25
+ start_month_include?(date) && end_month_include?(date)
26
+ else
27
+ start_month_include?(date) || end_month_include?(date)
28
+ end
21
29
  end
22
30
 
23
31
  private
24
32
 
25
- attr_reader :start_month, :end_month, :start_day, :end_day
33
+ sig { returns(Integer) }
34
+ attr_reader :start_month
35
+
36
+ sig { returns(Integer) }
37
+ attr_reader :end_month
38
+
39
+ sig { returns(Integer) }
40
+ attr_reader :start_day
26
41
 
42
+ sig { returns(Integer) }
43
+ attr_reader :end_day
44
+
45
+ sig { params(date: ::Date).returns(T::Boolean) }
27
46
  def months_include?(date)
28
47
  date.month > start_month && date.month < end_month
29
48
  end
30
49
 
50
+ sig { params(date: ::Date).returns(T::Boolean) }
31
51
  def start_month_include?(date)
32
52
  date.month == start_month && (start_day == 0 || date.day >= start_day)
33
53
  end
34
54
 
55
+ sig { params(date: ::Date).returns(T::Boolean) }
35
56
  def end_month_include?(date)
36
57
  date.month == end_month && (end_day == 0 || date.day <= end_day)
37
58
  end
59
+
60
+ sig { override.returns(T::Hash[Symbol, Integer]) }
61
+ def hash_value
62
+ args = {start_month: start_month}
63
+ args[:end_month] = end_month unless end_month == start_month
64
+ args[:start_day] = start_day unless start_day.zero?
65
+ args[:end_day] = end_day unless end_day.zero?
66
+ args
67
+ end
38
68
  end
39
69
  end
40
70
  end
@@ -1,28 +1,36 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class Set < Base
5
+ abstract!
6
+
7
+ sig { returns(T::Array[Expression::Base]) }
8
+ attr_reader :elements
9
+
10
+ sig { params(elements: T.any(Expression::Base, T::Array[Expression::Base])).void }
4
11
  def initialize(*elements)
5
- @elements = elements.flatten.uniq
12
+ @elements = T.let(elements.flatten.uniq, T::Array[Expression::Base])
6
13
  end
7
14
 
15
+ sig { params(element: T.untyped).returns(Repeatable::Expression::Set) }
8
16
  def <<(element)
9
17
  elements << element unless elements.include?(element)
10
18
  self
11
19
  end
12
20
 
13
- def to_h
14
- Hash[hash_key, elements.map(&:to_h)]
15
- end
16
-
21
+ sig { params(other: Object).returns(T::Boolean) }
17
22
  def ==(other)
18
23
  other.is_a?(self.class) &&
19
24
  elements.size == other.elements.size &&
20
25
  other.elements.all? { |e| elements.include?(e) }
21
26
  end
22
27
 
23
- protected
28
+ private
24
29
 
25
- attr_reader :elements
30
+ sig { override.returns(T::Array[Types::SymbolHash]) }
31
+ def hash_value
32
+ elements.map(&:to_h)
33
+ end
26
34
  end
27
35
  end
28
36
  end
@@ -1,6 +1,15 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class Union < Set
5
+ sig { params(elements: T.any(Expression::Base, T::Array[Expression::Base])).void }
6
+ def initialize(*elements)
7
+ other_unions, not_unions = elements.partition { |e| e.is_a?(self.class) }
8
+ other_unions = T.cast(other_unions, T::Array[Expression::Union])
9
+ super(other_unions.flat_map(&:elements).concat(not_unions))
10
+ end
11
+
12
+ sig { override.params(date: ::Date).returns(T::Boolean) }
4
13
  def include?(date)
5
14
  elements.any? { |e| e.include?(date) }
6
15
  end
@@ -1,16 +1,20 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class Weekday < Date
5
+ sig { params(weekday: Integer).void }
4
6
  def initialize(weekday:)
5
7
  @weekday = weekday
6
8
  end
7
9
 
10
+ sig { override.params(date: ::Date).returns(T::Boolean) }
8
11
  def include?(date)
9
12
  date.wday == weekday
10
13
  end
11
14
 
12
15
  private
13
16
 
17
+ sig { returns(Integer) }
14
18
  attr_reader :weekday
15
19
  end
16
20
  end
@@ -1,29 +1,60 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  class WeekdayInMonth < Date
5
+ include LastDateOfMonth
6
+
7
+ sig { params(weekday: Integer, count: Integer).void }
4
8
  def initialize(weekday:, count:)
5
9
  @weekday = weekday
6
10
  @count = count
7
11
  end
8
12
 
13
+ sig { override.params(date: ::Date).returns(T::Boolean) }
9
14
  def include?(date)
10
15
  day_matches?(date) && week_matches?(date)
11
16
  end
12
17
 
13
18
  private
14
19
 
15
- attr_reader :weekday, :count
20
+ sig { returns(Integer) }
21
+ attr_reader :weekday
22
+
23
+ sig { returns(Integer) }
24
+ attr_reader :count
16
25
 
26
+ sig { params(date: ::Date).returns(T::Boolean) }
17
27
  def day_matches?(date)
18
28
  date.wday == weekday
19
29
  end
20
30
 
31
+ sig { params(date: ::Date).returns(T::Boolean) }
21
32
  def week_matches?(date)
22
- week_in_month(date.day) == count
33
+ if negative_count?
34
+ week_from_end(date) == count
35
+ else
36
+ week_from_beginning(date) == count
37
+ end
38
+ end
39
+
40
+ sig { params(date: ::Date).returns(Integer) }
41
+ def week_from_beginning(date)
42
+ week_in_month(date.day - 1)
43
+ end
44
+
45
+ sig { params(date: ::Date).returns(Integer) }
46
+ def week_from_end(date)
47
+ -week_in_month(last_date_of_month(date).day - date.day)
48
+ end
49
+
50
+ sig { params(zero_indexed_day: Integer).returns(Integer) }
51
+ def week_in_month(zero_indexed_day)
52
+ (zero_indexed_day / 7) + 1
23
53
  end
24
54
 
25
- def week_in_month(day)
26
- ((day - 1) / 7) + 1
55
+ sig { returns(T::Boolean) }
56
+ def negative_count?
57
+ count < 0
27
58
  end
28
59
  end
29
60
  end
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  module Expression
3
4
  end
@@ -0,0 +1,11 @@
1
+ # typed: strict
2
+ module Repeatable
3
+ module LastDateOfMonth
4
+ extend T::Sig
5
+
6
+ sig { params(date: ::Date).returns(::Date) }
7
+ def last_date_of_month(date)
8
+ ::Date.new(date.next_month.year, date.next_month.month, 1).prev_day
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  class ParseError < StandardError
3
4
  end
@@ -1,13 +1,19 @@
1
+ # typed: false
1
2
  module Repeatable
2
3
  class Parser
4
+ extend T::Sig
5
+
6
+ sig { params(hash: T::Hash[T.any(String, Symbol), T.untyped]).void }
3
7
  def initialize(hash)
4
8
  @hash = hash
5
9
  end
6
10
 
11
+ sig { params(hash: T::Hash[T.any(String, Symbol), T.untyped]).returns(Expression::Base) }
7
12
  def self.call(hash)
8
13
  new(hash).call
9
14
  end
10
15
 
16
+ sig { returns(Expression::Base) }
11
17
  def call
12
18
  build_expression(hash)
13
19
  end
@@ -32,8 +38,14 @@ module Repeatable
32
38
  when Repeatable::Expression::Set
33
39
  args = value.map { |hash| build_expression(hash) }
34
40
  klass.new(*args)
41
+ when Repeatable::Expression::Difference
42
+ value = symbolize_keys(value)
43
+ klass.new(
44
+ included: build_expression(value[:included]),
45
+ excluded: build_expression(value[:excluded])
46
+ )
35
47
  else
36
- klass.new(symbolize_keys(value))
48
+ klass.new(**symbolize_keys(value))
37
49
  end
38
50
  end
39
51
 
@@ -44,7 +56,7 @@ module Repeatable
44
56
  def expression_klass(string)
45
57
  camel_cased_string = string
46
58
  .capitalize
47
- .gsub(/(?:_)(?<word>[a-z\d]+)/i) { Regexp.last_match[:word].capitalize }
59
+ .gsub(/(?:_)(?<word>[a-z\d]+)/i) { T.must(Regexp.last_match)[:word]&.capitalize }
48
60
  Repeatable::Expression.const_get(camel_cased_string)
49
61
  rescue NameError => e
50
62
  raise if e.name && e.name.to_s != camel_cased_string
@@ -1,9 +1,13 @@
1
+ # typed: strict
1
2
  module Repeatable
2
3
  class Schedule
4
+ extend T::Sig
5
+
6
+ sig { params(arg: Object).void }
3
7
  def initialize(arg)
4
8
  case arg
5
9
  when Repeatable::Expression::Base
6
- @expression = arg
10
+ @expression = T.let(arg, Expression::Base)
7
11
  when Hash
8
12
  @expression = Parser.call(arg)
9
13
  else
@@ -11,43 +15,53 @@ module Repeatable
11
15
  end
12
16
  end
13
17
 
18
+ sig { params(start_date: Object, end_date: Object).returns(T::Array[::Date]) }
14
19
  def occurrences(start_date, end_date)
15
- start_date = Date(start_date)
16
- end_date = Date(end_date)
20
+ start_date = Conversions::Date(start_date)
21
+ end_date = Conversions::Date(end_date)
17
22
 
18
- fail(ArgumentError, 'end_date must be equal to or after start_date') if end_date < start_date
23
+ fail(ArgumentError, "end_date must be equal to or after start_date") if end_date < start_date
19
24
 
20
25
  (start_date..end_date).select { |date| include?(date) }
21
26
  end
22
27
 
28
+ sig { params(start_date: Object, include_start: T::Boolean, limit: Integer).returns(T.nilable(::Date)) }
23
29
  def next_occurrence(start_date = Date.today, include_start: false, limit: 36525)
24
- date = Date(start_date)
30
+ date = Conversions::Date(start_date)
25
31
 
26
32
  return date if include_start && include?(date)
27
33
 
28
- 1.step do |i|
34
+ result = T.let(nil, T.nilable(Date))
35
+ 1.step(limit) do |i|
29
36
  date = date.next_day
30
37
 
31
- break date if include?(date)
32
- break if i == limit.to_i
38
+ if include?(date)
39
+ result = date
40
+ break
41
+ end
33
42
  end
43
+ result
34
44
  end
35
45
 
46
+ sig { params(date: Object).returns(T::Boolean) }
36
47
  def include?(date = Date.today)
37
- date = Date(date)
48
+ date = Conversions::Date(date)
38
49
  expression.include?(date)
39
50
  end
40
51
 
52
+ sig { returns(T::Hash[Symbol, T.any(Types::SymbolHash, T::Array[Types::SymbolHash])]) }
41
53
  def to_h
42
54
  expression.to_h
43
55
  end
44
56
 
57
+ sig { params(other: Object).returns(T::Boolean) }
45
58
  def ==(other)
46
59
  other.is_a?(self.class) && expression == other.expression
47
60
  end
48
61
 
49
62
  protected
50
63
 
64
+ sig { returns(Expression::Base) }
51
65
  attr_reader :expression
52
66
  end
53
67
  end
@@ -0,0 +1,6 @@
1
+ # typed: strict
2
+ module Repeatable
3
+ module Types
4
+ SymbolHash = T.type_alias { T::Hash[Symbol, T.untyped] }
5
+ end
6
+ end
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  module Repeatable
2
- VERSION = '0.5.0'
3
+ VERSION = "1.1.0"
3
4
  end
data/lib/repeatable.rb CHANGED
@@ -1,28 +1,34 @@
1
- require 'date'
1
+ # typed: strict
2
+ require "date"
3
+ require "sorbet-runtime"
2
4
 
3
- require 'repeatable/version'
4
-
5
- require 'repeatable/conversions'
6
- include Repeatable::Conversions
5
+ require "repeatable/version"
7
6
 
8
7
  module Repeatable
9
8
  end
10
9
 
11
- require 'repeatable/parse_error'
10
+ require "repeatable/parse_error"
11
+
12
+ require "repeatable/types"
13
+
14
+ require "repeatable/conversions"
15
+ require "repeatable/last_date_of_month"
12
16
 
13
- require 'repeatable/expression'
14
- require 'repeatable/expression/base'
17
+ require "repeatable/expression"
18
+ require "repeatable/expression/base"
15
19
 
16
- require 'repeatable/expression/date'
17
- require 'repeatable/expression/weekday'
18
- require 'repeatable/expression/biweekly'
19
- require 'repeatable/expression/weekday_in_month'
20
- require 'repeatable/expression/day_in_month'
21
- require 'repeatable/expression/range_in_year'
20
+ require "repeatable/expression/date"
21
+ require "repeatable/expression/exact_date"
22
+ require "repeatable/expression/weekday"
23
+ require "repeatable/expression/biweekly"
24
+ require "repeatable/expression/weekday_in_month"
25
+ require "repeatable/expression/day_in_month"
26
+ require "repeatable/expression/range_in_year"
22
27
 
23
- require 'repeatable/expression/set'
24
- require 'repeatable/expression/union'
25
- require 'repeatable/expression/intersection'
28
+ require "repeatable/expression/set"
29
+ require "repeatable/expression/union"
30
+ require "repeatable/expression/intersection"
31
+ require "repeatable/expression/difference"
26
32
 
27
- require 'repeatable/schedule'
28
- require 'repeatable/parser'
33
+ require "repeatable/schedule"
34
+ require "repeatable/parser"