repeatable 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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