lib/qo/public_api.rb in qo-0.4.0 vs lib/qo/public_api.rb in qo-0.5.0
- old
+ new
@@ -13,13 +13,16 @@
# Creates an `and` type query matcher. All conditions in this type of matcher
# must pass to be considered a "match". It will short-circuit in the case of
# a false match.
#
- # @param *array_matchers [Array] Array-like conditionals
- # @param **keyword_matchers [Hash] Keyword style conditionals
+ # @param *array_matchers [Array]
+ # Array-like conditionals
#
+ # @param **keyword_matchers [Hash]
+ # Keyword style conditionals
+ #
# @return [Proc[Any]]
# Any -> Bool # Given a target, will return if it "matches"
def and(*array_matchers, **keyword_matchers)
create_matcher('and', array_matchers, keyword_matchers)
end
@@ -29,114 +32,104 @@
# Creates an `or` type query matcher. Any conditions in this type of matcher
# must pass to be considered a "match". It will short-circuit in the case of
# a true match.
#
- # @param *array_matchers [Array] Array-like conditionals
- # @param **keyword_matchers [Hash] Keyword style conditionals
+ # @param *array_matchers [Array]
+ # Array-like conditionals
#
+ # @param **keyword_matchers [Hash]
+ # Keyword style conditionals
+ #
# @return [Proc[Any]]
# Any -> Bool # Given a target, will return if it "matches"
def or(*array_matchers, **keyword_matchers)
create_matcher('or', array_matchers, keyword_matchers)
end
# Creates a `not` type query matcher. No conditions in this type of matcher
# should pass to be considered a "match". It will short-circuit in the case of
# a true match.
#
- # @param *array_matchers [Array] Array-like conditionals
- # @param **keyword_matchers [Hash] Keyword style conditionals
+ # @param *array_matchers [Array]
+ # Array-like conditionals
#
+ # @param **keyword_matchers [Hash]
+ # Keyword style conditionals
+ #
# @return [Proc[Any]]
# Any -> Bool # Given a target, will return if it "matches"
def not(*array_matchers, **keyword_matchers)
create_matcher('not', array_matchers, keyword_matchers)
end
- # Creates a Guard Block matcher.
+ # A pattern match will try and run all guard block style matchers in sequence
+ # until it finds one that "matches". Once found, it will pass the target
+ # into the associated matcher's block function.
#
- # A guard block matcher is used to guard a function from running unless
- # the left-hand matcher passes. Once called with a value, it will either
- # return `[false, false]` or `[true, Any]`.
+ # @example
+ # [1,2,3].map(&Qo.match { |m|
+ # m.when(:even?) { |v| v * 3 }
+ # m.else { |v| v - 1 }
+ # })
+ # => [0, 6, 2]
#
- # This wrapping is done to preserve intended false or nil responses,
- # and is unwrapped with match below.
+ # @param fn [Proc]
+ # Body of the matcher, as shown in examples
#
- # @param *array_matchers [Array] varargs matchers
- # @param **keyword_matchers [Hash] kwargs matchers
- # @param &fn [Proc] Guarded function
- #
- # @return [Proc[Any]]
- # Any -> Proc[Any]
- def matcher(*array_matchers, **keyword_matchers, &fn)
- Qo::Matchers::GuardBlockMatcher.new(*array_matchers, **keyword_matchers, &fn)
+ # @return [Qo::PatternMatch]
+ # A function awaiting a value to match against
+ def match(&fn)
+ return proc { false } unless block_given?
+
+ Qo::Matchers::PatternMatch.new(&fn)
end
- # Might be a tinge fond of shorthand
- alias_method :m, :matcher
-
- # "Curried" function that waits for a target, or evaluates immediately if given
- # one.
+ # Similar to the common case statement of Ruby, except in that it behaves
+ # as if `Array#===` and `Hash#===` exist in the form of Qo matchers.
#
- # A PatternMatch will try and run all GuardBlock matchers in sequence until
- # it finds one that "matches". Once found, it will pass the target into the
- # associated matcher's block function.
+ # @note
+ # I refer to the potential 2.6+ features currently being discussed here:
#
- # @param fn [Proc]
- # If provided, the pattern match will become block-style, utilizing
- # PatternMatchBlock instead. If any args are provided, the first
- # will be treated as the target.
+ # * `Hash#===` - https://bugs.ruby-lang.org/issues/14869
+ # * `Array#===` - https://bugs.ruby-lang.org/issues/14916
#
- # @param *args [Array[Any, *GuardBlockMatcher]]
- # Collection of matchers to run, potentially prefixed by a target object
+ # @see Qo#match
#
- # @return [Qo::PatternMatchBlock]
- # If a value is not provided, a block style pattern match will be returned
- # that responds to proc coercion. It can be used for functions like `map`.
+ # @example
+ # Qo.case([1, 1]) { |m|
+ # m.when(Any, Any) { |a, b| a + b }
+ # m.else { |v| v }
+ # }
+ # => 2
#
- # @return [Qo::PatternMatch]
- # If a value is not provided and no function is present, a PatternMatch
- # will be returned, awaiting a value to match against.
+ # @param value [Any]
+ # Value to match against
#
+ # @param &fn [Proc]
+ # Body of the matcher, as shown above
+ #
# @return [Any]
- # If a value is provided, matchers will attempt to call through on it,
- # returning the result of the function.
- def match(*args, &fn)
- if block_given?
- return args.empty? ?
- Qo::Matchers::PatternMatchBlock.new(&fn) :
- Qo::Matchers::PatternMatchBlock.new(&fn).call(args.first)
- end
-
- if args.first.is_a?(Qo::Matchers::GuardBlockMatcher)
- Qo::Matchers::PatternMatch.new(*args)
- else
- match_target, *qo_matchers = args
- Qo::Matchers::PatternMatch.new(*qo_matchers).call(match_target)
- end
+ # The result of calling a pattern match with a provided value
+ def case(value, &fn)
+ Qo::Matchers::PatternMatch.new(&fn).call(value)
end
# Abstraction for creating a matcher, allowing for common error handling scenarios.
#
- # @param type [String] Type of matcher
- # @param *array_matchers [Array] Array-like conditionals
- # @param **keyword_matchers [Hash] Keyword style conditionals
+ # @param type [String]
+ # Type of matcher
#
- # @raises Qo::Exceptions::NoMatchersProvided
- # @raises Qo::Exceptions::MultipleMatchersProvided
+ # @param array_matchers [Array[Any]]
+ # Array-like conditionals
#
+ # @param keyword_matchers [Hash[Any, Any]]
+ # Keyword style conditionals
+ #
# @return [Qo::Matcher]
private def create_matcher(type, array_matchers, keyword_matchers)
- array_empty, hash_empty = array_matchers.empty?, keyword_matchers.empty?
+ raise MultipleMatchersProvided if !array_matchers.empty? && !keyword_matchers.empty?
- raise Qo::NoMatchersProvided if array_empty && hash_empty
- raise Qo::MultipleMatchersProvided if !(array_empty || hash_empty)
-
- if hash_empty
- Qo::Matchers::ArrayMatcher.new(type, *array_matchers)
- else
- Qo::Matchers::HashMatcher.new(type, **keyword_matchers)
- end
+ Qo::Matchers::BaseMatcher.new(type, array_matchers, keyword_matchers)
end
end
end