Class: Qo::Branches::Branch
- Inherits:
-
Object
- Object
- Qo::Branches::Branch
- Defined in:
- lib/qo/branches/branch.rb
Overview
Branches
A branch is a particular branch of a pattern match. The default branches
emulate a case
statement. Consider a case
statement like this:
case value
when condition then first_return
else second_return
end
With a Qo branch you would see something like this:
Qo.match { |m|
m.when(condition) { first_return }
m.else { second_return }
}
The when
and else
are the names the branch was "registered" with in
Qo::PatternMatchers::Branching
. The name becomes the method name that
the associated matcher uses.
Order of Execution
A branch will execute in the following order:
value -> precondition ? -> extractor -> condition ? -> destructurer
Preconditions allow for things like type checks or any static condition that will remain constant across all matches. Think of them as abstracting a single condition to guard before the branch continues.
Conditions are typical Qo matchers, as documented in the README. Upon a match, the branch will be considered matched and continue on to calling the associated block function.
Extractors are used to pull a value out of a container type, such as
value
for monadic types or last
for response array tuples.
Lastly, if given, Destructurers will destructure an object. That means that the associated function now places great significance on the names of the arguments as they'll be used to extract values from the object that would have normally been returned.
Destructuring can be a complicated topic, see the following article to find out more on how this works or see the README for examples:
https://medium.com/rubyinside/destructuring-in-ruby-9e9bd2be0360
Match Tuples
Branches will respond with a tuple of (status, value). A status of false
indicates a non-match, and a status or true indicates a match. This is done
to ensure that truly false
or nil
returns are not swallowed by a
match.
A Pattern Match will use these statuses to find the first matching branch.
Direct Known Subclasses
ElseBranch, ErrorBranch, FailureBranch, MonadicElseBranch, MonadicWhenBranch, SuccessBranch, WhenBranch
Constant Summary
- UNMATCHED =
Representation of an unmatched value. These values are wrapped in array tuples to preserve legitimate
false
andnil
values by indicating the status of the match in the first position and the returned value in the second. [false, nil]
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Name of the branch, see the initializer for more information.
Class Method Summary collapse
-
.create(name:, precondition: Any, extractor: IDENTITY, destructure: false, default: false) ⇒ Class
A dynamic creator for new branch types to be made on the fly in programs.
Instance Method Summary collapse
-
#create_matcher(conditions, destructure: @destructure, &function) ⇒ Proc[Any]
Uses the current configuration of the branch to create a matcher to be used in a pattern match.
-
#default? ⇒ Boolean
Whether or not this is a default branch.
-
#initialize(name:, precondition: Any, extractor: IDENTITY, destructure: false, default: false) ⇒ Qo::Branches::Branch
constructor
Creates an instance of a Branch.
Constructor Details
#initialize(name:, precondition: Any, extractor: IDENTITY, destructure: false, default: false) ⇒ Qo::Branches::Branch
Creates an instance of a Branch
113 114 115 116 117 118 119 |
# File 'lib/qo/branches/branch.rb', line 113 def initialize(name:, precondition: Any, extractor: IDENTITY, destructure: false, default: false) @name = name @precondition = precondition.is_a?(Symbol) ? precondition.to_proc : precondition @extractor = extractor.is_a?(Symbol) ? extractor.to_proc : extractor @destructure = destructure @default = default end |
Instance Attribute Details
#name ⇒ Object (readonly)
Name of the branch, see the initializer for more information
76 77 78 |
# File 'lib/qo/branches/branch.rb', line 76 def name @name end |
Class Method Details
.create(name:, precondition: Any, extractor: IDENTITY, destructure: false, default: false) ⇒ Class
A dynamic creator for new branch types to be made on the fly in programs. This exists to make new types of pattern matches to suit your own needs.
Prefer the public API to using this method directly, Qo.create_branch
,
mostly because it's less typing.
131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/qo/branches/branch.rb', line 131 def self.create(name:, precondition: Any, extractor: IDENTITY, destructure: false, default: false) attributes = { name: name, precondition: precondition, extractor: extractor, destructure: destructure, default: default } Class.new(Qo::Branches::Branch) do define_method(:initialize) { super(**attributes) } end end |
Instance Method Details
#create_matcher(conditions, destructure: @destructure, &function) ⇒ Proc[Any]
Uses the current configuration of the branch to create a matcher to
be used in a pattern match. The returned proc can be passed a value
that will return back a tuple of (status, value)
to indicate whether
or not a match was made with this branch.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/qo/branches/branch.rb', line 169 def create_matcher(conditions, destructure: @destructure, &function) function ||= IDENTITY destructurer = Destructurers::Destructurer.new( destructure: destructure, &function ) Proc.new { |value| # If it's a default branch, return true, as conditions are redundant if @default extracted_value = @extractor.call(value) next [true, destructurer.call(extracted_value)] end # Otherwise we check the precondition first before extracting the # value from whatever container it might be in. next UNMATCHED unless @precondition === value extracted_value = @extractor.call(value) # If that extracted value matches our conditions, destructure the value # and return it, or return unmatched otherwise. conditions === extracted_value ? [true, destructurer.call(extracted_value)] : UNMATCHED } end |
#default? ⇒ Boolean
Whether or not this is a default branch
148 149 150 |
# File 'lib/qo/branches/branch.rb', line 148 def default? @default end |