repeatable 1.0.0 → 1.2.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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +77 -0
  3. data/CHANGELOG.md +27 -1
  4. data/CODE_OF_CONDUCT.md +128 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +89 -24
  7. data/README.md +44 -8
  8. data/Rakefile +5 -1
  9. data/bin/tapioca +29 -0
  10. data/lib/repeatable/conversions.rb +7 -2
  11. data/lib/repeatable/expression/base.rb +27 -11
  12. data/lib/repeatable/expression/biweekly.rb +15 -6
  13. data/lib/repeatable/expression/date.rb +11 -6
  14. data/lib/repeatable/expression/day_in_month.rb +5 -0
  15. data/lib/repeatable/expression/difference.rb +15 -5
  16. data/lib/repeatable/expression/exact_date.rb +6 -1
  17. data/lib/repeatable/expression/intersection.rb +8 -2
  18. data/lib/repeatable/expression/range_in_year.rb +34 -9
  19. data/lib/repeatable/expression/set.rb +17 -6
  20. data/lib/repeatable/expression/union.rb +7 -1
  21. data/lib/repeatable/expression/weekday.rb +5 -0
  22. data/lib/repeatable/expression/weekday_in_month.rb +15 -1
  23. data/lib/repeatable/expression.rb +2 -0
  24. data/lib/repeatable/last_date_of_month.rb +5 -0
  25. data/lib/repeatable/parse_error.rb +2 -0
  26. data/lib/repeatable/parser.rb +8 -1
  27. data/lib/repeatable/schedule.rb +24 -4
  28. data/lib/repeatable/types.rb +7 -0
  29. data/lib/repeatable/version.rb +3 -1
  30. data/lib/repeatable.rb +5 -0
  31. data/rbi/repeatable.rbi +316 -0
  32. data/repeatable.gemspec +3 -0
  33. data/sorbet/config +4 -0
  34. data/sorbet/rbi/annotations/.gitattributes +1 -0
  35. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  36. data/sorbet/rbi/gems/.gitattributes +1 -0
  37. data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
  38. data/sorbet/rbi/gems/coderay@1.1.3.rbi +3426 -0
  39. data/sorbet/rbi/gems/commander@4.6.0.rbi +8 -0
  40. data/sorbet/rbi/gems/diff-lcs@1.4.4.rbi +1082 -0
  41. data/sorbet/rbi/gems/docile@1.4.0.rbi +376 -0
  42. data/sorbet/rbi/gems/erubi@1.12.0.rbi +145 -0
  43. data/sorbet/rbi/gems/highline@2.0.3.rbi +8 -0
  44. data/sorbet/rbi/gems/json@2.7.2.rbi +1561 -0
  45. data/sorbet/rbi/gems/language_server-protocol@3.17.0.3.rbi +14237 -0
  46. data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +239 -0
  47. data/sorbet/rbi/gems/method_source@1.0.0.rbi +272 -0
  48. data/sorbet/rbi/gems/netrc@0.11.0.rbi +158 -0
  49. data/sorbet/rbi/gems/parallel@1.24.0.rbi +280 -0
  50. data/sorbet/rbi/gems/parlour@8.1.0.rbi +3053 -0
  51. data/sorbet/rbi/gems/parser@3.3.1.0.rbi +7320 -0
  52. data/sorbet/rbi/gems/prism@0.28.0.rbi +37903 -0
  53. data/sorbet/rbi/gems/pry@0.14.0.rbi +10072 -0
  54. data/sorbet/rbi/gems/racc@1.7.3.rbi +161 -0
  55. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +402 -0
  56. data/sorbet/rbi/gems/rake@13.0.3.rbi +3024 -0
  57. data/sorbet/rbi/gems/rbi@0.1.13.rbi +3071 -0
  58. data/sorbet/rbi/gems/regexp_parser@2.9.0.rbi +3771 -0
  59. data/sorbet/rbi/gems/rexml@3.2.6.rbi +4781 -0
  60. data/sorbet/rbi/gems/rspec-core@3.10.1.rbi +10837 -0
  61. data/sorbet/rbi/gems/rspec-expectations@3.10.1.rbi +7930 -0
  62. data/sorbet/rbi/gems/rspec-mocks@3.10.2.rbi +5247 -0
  63. data/sorbet/rbi/gems/rspec-support@3.10.2.rbi +1594 -0
  64. data/sorbet/rbi/gems/rspec@3.10.0.rbi +76 -0
  65. data/sorbet/rbi/gems/rubocop-ast@1.31.3.rbi +7014 -0
  66. data/sorbet/rbi/gems/rubocop-performance@1.20.2.rbi +8 -0
  67. data/sorbet/rbi/gems/rubocop@1.62.1.rbi +57542 -0
  68. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1317 -0
  69. data/sorbet/rbi/gems/simplecov-html@0.12.3.rbi +216 -0
  70. data/sorbet/rbi/gems/simplecov@0.21.2.rbi +2135 -0
  71. data/sorbet/rbi/gems/simplecov_json_formatter@0.1.4.rbi +8 -0
  72. data/sorbet/rbi/gems/spoom@1.3.2.rbi +4420 -0
  73. data/sorbet/rbi/gems/standard-custom@1.0.2.rbi +8 -0
  74. data/sorbet/rbi/gems/standard-performance@1.3.1.rbi +8 -0
  75. data/sorbet/rbi/gems/standard@1.35.1.rbi +850 -0
  76. data/sorbet/rbi/gems/tapioca@0.13.3.rbi +3527 -0
  77. data/sorbet/rbi/gems/thor@1.3.1.rbi +4351 -0
  78. data/sorbet/rbi/gems/unicode-display_width@2.5.0.rbi +65 -0
  79. data/sorbet/rbi/gems/yard-sorbet@0.8.1.rbi +428 -0
  80. data/sorbet/rbi/gems/yard@0.9.36.rbi +18220 -0
  81. data/sorbet/tapioca/config.yml +13 -0
  82. data/sorbet/tapioca/require.rb +4 -0
  83. metadata +75 -6
  84. data/.travis.yml +0 -18
@@ -1,23 +1,32 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class Biweekly < Date
6
+ sig { params(weekday: Integer, start_after: Object).void }
4
7
  def initialize(weekday:, start_after: ::Date.today)
5
8
  @weekday = weekday
6
- @start_after = Conversions::Date(start_after)
9
+ @start_after = T.let(Conversions::Date(start_after), ::Date)
10
+ @_first_occurrence = T.let(find_first_occurrence, ::Date)
7
11
  end
8
12
 
13
+ sig { override.params(date: ::Date).returns(T::Boolean) }
9
14
  def include?(date)
10
- date >= start_after && (date - first_occurrence) % 14 == 0
15
+ date >= start_after && (date - _first_occurrence) % 14 == 0
11
16
  end
12
17
 
13
18
  private
14
19
 
15
- attr_reader :weekday, :start_after
20
+ sig { returns(Integer) }
21
+ attr_reader :weekday
16
22
 
17
- def first_occurrence
18
- @first_occurrence ||= find_first_occurrence
19
- end
23
+ sig { returns(::Date) }
24
+ attr_reader :start_after
25
+
26
+ sig { returns(::Date) }
27
+ attr_reader :_first_occurrence
20
28
 
29
+ sig { returns(::Date) }
21
30
  def find_first_occurrence
22
31
  days_away = weekday - start_after.wday
23
32
  days_away += 7 if days_away <= 0
@@ -1,29 +1,34 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class Date < Base
4
- def to_h
5
- Hash[hash_key, attributes]
6
- end
6
+ abstract!
7
7
 
8
+ sig { params(other: Object).returns(T::Boolean) }
8
9
  def ==(other)
9
10
  other.is_a?(self.class) && attributes == other.attributes
10
11
  end
11
-
12
12
  alias_method :eql?, :==
13
13
 
14
+ sig { returns(Integer) }
14
15
  def hash
15
16
  [attributes.values, self.class.name].hash
16
17
  end
17
18
 
18
19
  protected
19
20
 
21
+ sig { returns(Types::SymbolHash) }
20
22
  def attributes
21
23
  instance_variables.each_with_object({}) do |name, hash|
22
- key = name.to_s.gsub(/^@/, "").to_sym
23
- hash[key] = normalize_attribute_value(instance_variable_get(name))
24
+ key = name.to_s.gsub(/^@/, "")
25
+ next if key.start_with?("_")
26
+ hash[key.to_sym] = normalize_attribute_value(instance_variable_get(name))
24
27
  end
25
28
  end
29
+ alias_method :hash_value, :attributes
26
30
 
31
+ sig { params(value: BasicObject).returns(T.untyped) }
27
32
  def normalize_attribute_value(value)
28
33
  case value
29
34
  when ::Date
@@ -1,12 +1,16 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class DayInMonth < Date
4
6
  include LastDateOfMonth
5
7
 
8
+ sig { params(day: Integer).void }
6
9
  def initialize(day:)
7
10
  @day = day
8
11
  end
9
12
 
13
+ sig { override.params(date: ::Date).returns(T::Boolean) }
10
14
  def include?(date)
11
15
  if day < 0
12
16
  date - last_date_of_month(date) - 1 == day
@@ -17,6 +21,7 @@ module Repeatable
17
21
 
18
22
  private
19
23
 
24
+ sig { returns(Integer) }
20
25
  attr_reader :day
21
26
  end
22
27
  end
@@ -1,19 +1,20 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class Difference < Base
6
+ sig { params(included: Expression::Base, excluded: Expression::Base).void }
4
7
  def initialize(included:, excluded:)
5
8
  @included = included
6
9
  @excluded = excluded
7
10
  end
8
11
 
12
+ sig { override.params(date: ::Date).returns(T::Boolean) }
9
13
  def include?(date)
10
14
  included.include?(date) && !excluded.include?(date)
11
15
  end
12
16
 
13
- def to_h
14
- Hash[hash_key, {included: included.to_h, excluded: excluded.to_h}]
15
- end
16
-
17
+ sig { params(other: Object).returns(T::Boolean) }
17
18
  def ==(other)
18
19
  other.is_a?(self.class) &&
19
20
  included == other.included &&
@@ -22,7 +23,16 @@ module Repeatable
22
23
 
23
24
  protected
24
25
 
25
- attr_reader :included, :excluded
26
+ sig { returns(Expression::Base) }
27
+ attr_reader :included
28
+
29
+ sig { returns(Expression::Base) }
30
+ attr_reader :excluded
31
+
32
+ sig { override.returns(Types::SymbolHash) }
33
+ def hash_value
34
+ {included: included.to_h, excluded: excluded.to_h}
35
+ end
26
36
  end
27
37
  end
28
38
  end
@@ -1,16 +1,21 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class ExactDate < Date
6
+ sig { params(date: Object).void }
4
7
  def initialize(date:)
5
- @date = Conversions::Date(date)
8
+ @date = T.let(Conversions::Date(date), ::Date)
6
9
  end
7
10
 
11
+ sig { override.params(other_date: ::Date).returns(T::Boolean) }
8
12
  def include?(other_date)
9
13
  date == other_date
10
14
  end
11
15
 
12
16
  private
13
17
 
18
+ sig { returns(::Date) }
14
19
  attr_reader :date
15
20
  end
16
21
  end
@@ -1,11 +1,17 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class Intersection < Set
6
+ sig { params(elements: T.any(Expression::Base, T::Array[Expression::Base])).void }
4
7
  def initialize(*elements)
5
- other_intersection, not_intersection = elements.partition { |e| e.is_a?(self.class) }
6
- super(other_intersection.flat_map(&:elements) + not_intersection)
8
+ elements = Array(elements).flatten
9
+ other_intersections, not_intersections = elements.partition { |e| e.is_a?(self.class) }
10
+ other_intersections = T.cast(other_intersections, T::Array[Expression::Intersection])
11
+ super(other_intersections.flat_map(&:elements).concat(not_intersections))
7
12
  end
8
13
 
14
+ sig { override.params(date: ::Date).returns(T::Boolean) }
9
15
  def include?(date)
10
16
  elements.all? { |e| e.include?(date) }
11
17
  end
@@ -1,6 +1,16 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class RangeInYear < Date
6
+ sig do
7
+ params(
8
+ start_month: Integer,
9
+ end_month: Integer,
10
+ start_day: Integer,
11
+ end_day: Integer
12
+ ).void
13
+ end
4
14
  def initialize(start_month:, end_month: start_month, start_day: 0, end_day: 0)
5
15
  @start_month = start_month
6
16
  @end_month = end_month
@@ -8,6 +18,7 @@ module Repeatable
8
18
  @end_day = end_day
9
19
  end
10
20
 
21
+ sig { override.params(date: ::Date).returns(T::Boolean) }
11
22
  def include?(date)
12
23
  return true if months_include?(date)
13
24
 
@@ -18,29 +29,43 @@ module Repeatable
18
29
  end
19
30
  end
20
31
 
21
- def to_h
22
- args = {start_month: start_month}
23
- args[:end_month] = end_month unless end_month == start_month
24
- args[:start_day] = start_day unless start_day.zero?
25
- args[:end_day] = end_day unless end_day.zero?
26
- {range_in_year: args}
27
- end
28
-
29
32
  private
30
33
 
31
- attr_reader :start_month, :end_month, :start_day, :end_day
34
+ sig { returns(Integer) }
35
+ attr_reader :start_month
36
+
37
+ sig { returns(Integer) }
38
+ attr_reader :end_month
32
39
 
40
+ sig { returns(Integer) }
41
+ attr_reader :start_day
42
+
43
+ sig { returns(Integer) }
44
+ attr_reader :end_day
45
+
46
+ sig { params(date: ::Date).returns(T::Boolean) }
33
47
  def months_include?(date)
34
48
  date.month > start_month && date.month < end_month
35
49
  end
36
50
 
51
+ sig { params(date: ::Date).returns(T::Boolean) }
37
52
  def start_month_include?(date)
38
53
  date.month == start_month && (start_day == 0 || date.day >= start_day)
39
54
  end
40
55
 
56
+ sig { params(date: ::Date).returns(T::Boolean) }
41
57
  def end_month_include?(date)
42
58
  date.month == end_month && (end_day == 0 || date.day <= end_day)
43
59
  end
60
+
61
+ sig { override.returns(T::Hash[Symbol, Integer]) }
62
+ def hash_value
63
+ args = {start_month: start_month}
64
+ args[:end_month] = end_month unless end_month == start_month
65
+ args[:start_day] = start_day unless start_day.zero?
66
+ args[:end_day] = end_day unless end_day.zero?
67
+ args
68
+ end
44
69
  end
45
70
  end
46
71
  end
@@ -1,26 +1,37 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class Set < Base
6
+ abstract!
7
+
8
+ sig { returns(T::Array[Expression::Base]) }
4
9
  attr_reader :elements
5
10
 
6
- def initialize(*elements)
7
- @elements = elements.flatten.uniq
11
+ sig { params(elements: T::Array[Expression::Base]).void }
12
+ def initialize(elements)
13
+ @elements = T.let(elements.flatten.uniq, T::Array[Expression::Base])
8
14
  end
9
15
 
16
+ sig { params(element: T.untyped).returns(Repeatable::Expression::Set) }
10
17
  def <<(element)
11
18
  elements << element unless elements.include?(element)
12
19
  self
13
20
  end
14
21
 
15
- def to_h
16
- Hash[hash_key, elements.map(&:to_h)]
17
- end
18
-
22
+ sig { params(other: Object).returns(T::Boolean) }
19
23
  def ==(other)
20
24
  other.is_a?(self.class) &&
21
25
  elements.size == other.elements.size &&
22
26
  other.elements.all? { |e| elements.include?(e) }
23
27
  end
28
+
29
+ private
30
+
31
+ sig { override.returns(T::Array[Types::SymbolHash]) }
32
+ def hash_value
33
+ elements.map(&:to_h)
34
+ end
24
35
  end
25
36
  end
26
37
  end
@@ -1,11 +1,17 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class Union < Set
6
+ sig { params(elements: T.any(Expression::Base, T::Array[Expression::Base])).void }
4
7
  def initialize(*elements)
8
+ elements = Array(elements).flatten
5
9
  other_unions, not_unions = elements.partition { |e| e.is_a?(self.class) }
6
- super(other_unions.flat_map(&:elements) + not_unions)
10
+ other_unions = T.cast(other_unions, T::Array[Expression::Union])
11
+ super(other_unions.flat_map(&:elements).concat(not_unions))
7
12
  end
8
13
 
14
+ sig { override.params(date: ::Date).returns(T::Boolean) }
9
15
  def include?(date)
10
16
  elements.any? { |e| e.include?(date) }
11
17
  end
@@ -1,16 +1,21 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class Weekday < Date
6
+ sig { params(weekday: Integer).void }
4
7
  def initialize(weekday:)
5
8
  @weekday = weekday
6
9
  end
7
10
 
11
+ sig { override.params(date: ::Date).returns(T::Boolean) }
8
12
  def include?(date)
9
13
  date.wday == weekday
10
14
  end
11
15
 
12
16
  private
13
17
 
18
+ sig { returns(Integer) }
14
19
  attr_reader :weekday
15
20
  end
16
21
  end
@@ -1,25 +1,35 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  class WeekdayInMonth < Date
4
6
  include LastDateOfMonth
5
7
 
8
+ sig { params(weekday: Integer, count: Integer).void }
6
9
  def initialize(weekday:, count:)
7
10
  @weekday = weekday
8
11
  @count = count
9
12
  end
10
13
 
14
+ sig { override.params(date: ::Date).returns(T::Boolean) }
11
15
  def include?(date)
12
16
  day_matches?(date) && week_matches?(date)
13
17
  end
14
18
 
15
19
  private
16
20
 
17
- attr_reader :weekday, :count
21
+ sig { returns(Integer) }
22
+ attr_reader :weekday
23
+
24
+ sig { returns(Integer) }
25
+ attr_reader :count
18
26
 
27
+ sig { params(date: ::Date).returns(T::Boolean) }
19
28
  def day_matches?(date)
20
29
  date.wday == weekday
21
30
  end
22
31
 
32
+ sig { params(date: ::Date).returns(T::Boolean) }
23
33
  def week_matches?(date)
24
34
  if negative_count?
25
35
  week_from_end(date) == count
@@ -28,18 +38,22 @@ module Repeatable
28
38
  end
29
39
  end
30
40
 
41
+ sig { params(date: ::Date).returns(Integer) }
31
42
  def week_from_beginning(date)
32
43
  week_in_month(date.day - 1)
33
44
  end
34
45
 
46
+ sig { params(date: ::Date).returns(Integer) }
35
47
  def week_from_end(date)
36
48
  -week_in_month(last_date_of_month(date).day - date.day)
37
49
  end
38
50
 
51
+ sig { params(zero_indexed_day: Integer).returns(Integer) }
39
52
  def week_in_month(zero_indexed_day)
40
53
  (zero_indexed_day / 7) + 1
41
54
  end
42
55
 
56
+ sig { returns(T::Boolean) }
43
57
  def negative_count?
44
58
  count < 0
45
59
  end
@@ -1,3 +1,5 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module Expression
3
5
  end
@@ -1,5 +1,10 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  module LastDateOfMonth
5
+ extend T::Sig
6
+
7
+ sig { params(date: ::Date).returns(::Date) }
3
8
  def last_date_of_month(date)
4
9
  ::Date.new(date.next_month.year, date.next_month.month, 1).prev_day
5
10
  end
@@ -1,3 +1,5 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  class ParseError < StandardError
3
5
  end
@@ -1,13 +1,20 @@
1
+ # typed: false
2
+
1
3
  module Repeatable
2
4
  class Parser
5
+ extend T::Sig
6
+
7
+ sig { params(hash: T::Hash[T.any(String, Symbol), T.untyped]).void }
3
8
  def initialize(hash)
4
9
  @hash = hash
5
10
  end
6
11
 
12
+ sig { params(hash: T::Hash[T.any(String, Symbol), T.untyped]).returns(Expression::Base) }
7
13
  def self.call(hash)
8
14
  new(hash).call
9
15
  end
10
16
 
17
+ sig { returns(Expression::Base) }
11
18
  def call
12
19
  build_expression(hash)
13
20
  end
@@ -50,7 +57,7 @@ module Repeatable
50
57
  def expression_klass(string)
51
58
  camel_cased_string = string
52
59
  .capitalize
53
- .gsub(/(?:_)(?<word>[a-z\d]+)/i) { Regexp.last_match[:word].capitalize }
60
+ .gsub(/(?:_)(?<word>[a-z\d]+)/i) { T.must(Regexp.last_match)[:word]&.capitalize }
54
61
  Repeatable::Expression.const_get(camel_cased_string)
55
62
  rescue NameError => e
56
63
  raise if e.name && e.name.to_s != camel_cased_string
@@ -1,9 +1,14 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
4
  class Schedule
5
+ extend T::Sig
6
+
7
+ sig { params(arg: Object).void }
3
8
  def initialize(arg)
4
9
  case arg
5
10
  when Repeatable::Expression::Base
6
- @expression = arg
11
+ @expression = T.let(arg, Expression::Base)
7
12
  when Hash
8
13
  @expression = Parser.call(arg)
9
14
  else
@@ -11,6 +16,7 @@ module Repeatable
11
16
  end
12
17
  end
13
18
 
19
+ sig { params(start_date: Object, end_date: Object).returns(T::Array[::Date]) }
14
20
  def occurrences(start_date, end_date)
15
21
  start_date = Conversions::Date(start_date)
16
22
  end_date = Conversions::Date(end_date)
@@ -20,34 +26,48 @@ module Repeatable
20
26
  (start_date..end_date).select { |date| include?(date) }
21
27
  end
22
28
 
29
+ sig { params(start_date: Object, include_start: T::Boolean, limit: Integer).returns(T.nilable(::Date)) }
23
30
  def next_occurrence(start_date = Date.today, include_start: false, limit: 36525)
24
31
  date = Conversions::Date(start_date)
25
32
 
26
33
  return date if include_start && include?(date)
27
34
 
28
- 1.step do |i|
35
+ result = T.let(nil, T.nilable(Date))
36
+ 1.step(limit) do |i|
29
37
  date = date.next_day
30
38
 
31
- break date if include?(date)
32
- break if i == limit.to_i
39
+ if include?(date)
40
+ result = date
41
+ break
42
+ end
33
43
  end
44
+ result
34
45
  end
35
46
 
47
+ sig { params(date: Object).returns(T::Boolean) }
36
48
  def include?(date = Date.today)
37
49
  date = Conversions::Date(date)
38
50
  expression.include?(date)
39
51
  end
40
52
 
53
+ sig { returns(T::Hash[Symbol, T.any(Types::SymbolHash, T::Array[Types::SymbolHash])]) }
41
54
  def to_h
42
55
  expression.to_h
43
56
  end
44
57
 
58
+ sig { params(_keys: T.nilable(T::Array[Symbol])).returns(T::Hash[Symbol, T.any(Types::SymbolHash, T::Array[Types::SymbolHash])]) }
59
+ def deconstruct_keys(_keys)
60
+ to_h
61
+ end
62
+
63
+ sig { params(other: Object).returns(T::Boolean) }
45
64
  def ==(other)
46
65
  other.is_a?(self.class) && expression == other.expression
47
66
  end
48
67
 
49
68
  protected
50
69
 
70
+ sig { returns(Expression::Base) }
51
71
  attr_reader :expression
52
72
  end
53
73
  end
@@ -0,0 +1,7 @@
1
+ # typed: strict
2
+
3
+ module Repeatable
4
+ module Types
5
+ SymbolHash = T.type_alias { T::Hash[Symbol, T.untyped] }
6
+ end
7
+ end
@@ -1,3 +1,5 @@
1
+ # typed: strict
2
+
1
3
  module Repeatable
2
- VERSION = "1.0.0"
4
+ VERSION = "1.2.0"
3
5
  end
data/lib/repeatable.rb CHANGED
@@ -1,4 +1,7 @@
1
+ # typed: strict
2
+
1
3
  require "date"
4
+ require "sorbet-runtime"
2
5
 
3
6
  require "repeatable/version"
4
7
 
@@ -7,6 +10,8 @@ end
7
10
 
8
11
  require "repeatable/parse_error"
9
12
 
13
+ require "repeatable/types"
14
+
10
15
  require "repeatable/conversions"
11
16
  require "repeatable/last_date_of_month"
12
17