diff --git a/CHANGELOG.md b/CHANGELOG.md index 7599e5b..7daa83b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### Unreleased +Changes: + +* Support pattern matching for `Expression` and `Schedule` + [Commits](https://github.com/molawson/repeatable/compare/v1.1.0...main) ### 1.1.0 (2022-02-25) diff --git a/README.md b/README.md index b166ea0..79ff2fb 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,21 @@ schedule.to_h # can be used to recreate an identical Schedule object at a later time ``` +#### Pattern Matching + +Both `Repeatable::Schedule` and all `Repeatable::Expression` classes support Ruby 2.7+ [pattern matching][ruby-pattern-matching] which is particularly useful for parsing or presenting an existing schedule. + +```ruby +case schedule +in weekday: { weekday: } + "Weekly on #{Date::DAYNAMES[weekday]}" +in day_in_month: { day: } + "Every month on the #{day.ordinalize}" +in weekday_in_month: { weekday:, count: } + "Every month on the #{count.ordinalize} #{Date::DAYNAMES[weekday]}" +end +``` + #### Equivalence Both `Repeatable::Schedule` and all `Repeatable::Expression` classes have equivalence `#==` defined according to what's appropriate for each class, so regardless of the order of arguments passed to each, you can tell whether one object is equivalent to the other in terms of whether or not, when asked the same questions, you'd receive the same results from each. @@ -218,3 +233,5 @@ The gem is available as open source under the terms of the [MIT License](https:/ ## Code of Conduct Everyone interacting in the Repeatable project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/molawson/repeatable/blob/main/CODE_OF_CONDUCT.md). + +[ruby-pattern-matching]: https://docs.ruby-lang.org/en/3.0/syntax/pattern_matching_rdoc.html diff --git a/lib/repeatable/expression/base.rb b/lib/repeatable/expression/base.rb index 17e4cff..33f33ff 100644 --- a/lib/repeatable/expression/base.rb +++ b/lib/repeatable/expression/base.rb @@ -26,6 +26,11 @@ def to_h {hash_key => hash_value} end + sig { params(_keys: T.nilable(T::Array[Symbol])).returns(T::Hash[Symbol, T.any(Types::SymbolHash, T::Array[Types::SymbolHash])]) } + def deconstruct_keys(_keys) + to_h + end + sig { params(other: Expression::Base).returns(Expression::Union) } def union(other) Union.new(self, other) diff --git a/lib/repeatable/schedule.rb b/lib/repeatable/schedule.rb index c05d55c..b4a030d 100644 --- a/lib/repeatable/schedule.rb +++ b/lib/repeatable/schedule.rb @@ -54,6 +54,11 @@ def to_h expression.to_h end + sig { params(_keys: T.nilable(T::Array[Symbol])).returns(T::Hash[Symbol, T.any(Types::SymbolHash, T::Array[Types::SymbolHash])]) } + def deconstruct_keys(_keys) + to_h + end + sig { params(other: Object).returns(T::Boolean) } def ==(other) other.is_a?(self.class) && expression == other.expression diff --git a/spec/repeatable/schedule_spec.rb b/spec/repeatable/schedule_spec.rb index 095c80d..7b9e728 100644 --- a/spec/repeatable/schedule_spec.rb +++ b/spec/repeatable/schedule_spec.rb @@ -328,6 +328,14 @@ module Repeatable end end + describe "pattern matching" do + let(:arg) { nested_set_expression_hash } + + it "can #deconstruct_keys" do + expect(subject.deconstruct_keys(nil)).to eq subject.to_h + end + end + describe "#==" do it "returns true if the schedules have the same identity" do schedule = described_class.new(nested_set_expression_object) diff --git a/spec/support/expression_examples.rb b/spec/support/expression_examples.rb index 45858a2..c8b86d0 100644 --- a/spec/support/expression_examples.rb +++ b/spec/support/expression_examples.rb @@ -11,4 +11,10 @@ expect { subject.to_h }.not_to raise_error end end + + describe "pattern matching" do + it "can #deconstruct_keys" do + expect(subject.deconstruct_keys(nil)).to be_a(Hash) + end + end end