class Qo::PatternMatchers::PatternMatch
Classic Pattern Match. This matcher uses `when` and `else` branches and is meant to be a more powerful variant of the case statement
@author baweaver @since 0.2.0
Public Class Methods
Allows for the creation of an anonymous PatternMatcher based on this parent class. To be used by people wishing to make their own pattern matchers with variant branches and other features not included in the defaultly provided ones
@param branches: [] [Array]
Branches to be used with this new pattern matcher
@return [Class]
Anonymous pattern matcher class to be bound to a constant or used anonymously.
# File lib/qo/pattern_matchers/pattern_match.rb, line 44 def self.create(branches: []) Class.new(Qo::PatternMatchers::PatternMatch) do branches.each { |branch| register_branch(branch.new) } end end
Allows for the injection of a pattern matching function into a type class for direct access, rather than yielding an instance of that class to a pattern matcher.
This is typically done for monadic types that need to `match`. When combined with extractor type branches it can be very handy for dealing with container types.
@example
```ruby # Technically Some and None don't exist yet, so we have to "cheat" instead # of just saying `Some` for the precondition SomeBranch = Qo.create_branch( name: 'some', precondition: -> v { v.is_a?(Some) }, extractor: :value ) NoneBranch = Qo.create_branch( name: 'none', precondition: -> v { v.is_a?(None) }, extractor: :value ) SomePatternMatch = Qo.create_pattern_match(branches: [SomeBranch, NoneBranch]) class Some include SomePatternMatch.mixin attr_reader :value def initialize(value) @value = value end def fmap(&fn) new_value = fn.call(value) new_value ? Some.new(new_value) : None(value) end end class None include SomePatternMatch.mixin attr_reader :value def initialize(value) @value = value end def fmap(&fn) None.new(value) end end Some.new(1) .fmap { |v| v * 2 } .match { |m| m.some { |v| v + 100 } m.none { "OHNO!" } } => 102 Some.new(1) .fmap { |v| nil } .match { |m| m.some { |v| v + 100 } m.none { "OHNO!" } } => "OHNO!" ```
@param destructure: false [Boolean]
Whether or not to destructure values before yielding to a block
@param as: :match [Symbol]
Name to use as a method name bound to the including class
@return [Module]
Module to be mixed into a class
# File lib/qo/pattern_matchers/pattern_match.rb, line 124 def self.mixin(destructure: false, as: :match) create_self = -> &function { new(destructure: destructure, &function) } Module.new do define_method(as) do |&function| create_self.call(&function).call(self) end end end
Creates a new instance of a pattern matcher
@param destructure: false [Boolean]
Whether or not to destructure values before yielding to a block
@param &fn [Proc]
Function to be used to construct the pattern matcher's branches
@return [Qo::PatternMatchers::PatternMatch]
# File lib/qo/pattern_matchers/pattern_match.rb, line 25 def initialize(destructure: false, &fn) @matchers = [] @default = nil @destructure = destructure yield(self) if block_given? end
Public Instance Methods
Calls the pattern matcher, yielding the target value to the first matching branch it encounters.
@param value [Any]
Value to match against
@return [Any]
Result of the called branch
@return [nil]
Returns nil if no branch is matched
# File lib/qo/pattern_matchers/pattern_match.rb, line 145 def call(value) @matchers.each do |matcher| status, return_value = matcher.call(value) return return_value if status end if @default _, return_value = @default.call(value) return_value else nil end end
Procified version of `call`
@return [Proc => Any]
# File lib/qo/pattern_matchers/pattern_match.rb, line 165 def to_proc -> target { self.call(target) } end