Class: Dio::Forwarders::BaseForwarder
- Inherits:
-
Delegator
- Object
- Delegator
- Dio::Forwarders::BaseForwarder
- Defined in:
- lib/dio/forwarders/base_forwarder.rb
Overview
Allows for Pattern Matching against arbitrary objects by wrapping them in an interface that understands methods of deconstructing objects.
**Approximating Deconstruction**
As Ruby does not, by default, define ‘deconstruct` and `deconstruct_keys` on objects this class attempts to approximate them.
This class does, however, do something unique in treating ‘deconstruct_keys` as a series of calls to sent to the class and its “nested” values.
**Demonstrating Nested Values**
Consider an integer:
“‘ruby Dio in { succ: { succ: { succ: 4 } } } # => true “`
It has no concept of deconstruction, except in that its ‘succ` method returns a “nested” value we can match against, allowing us to “dive into” the object, diving us our namesake Dio, or “Dive Into Object”
Delegation
As with most monadic-like design patterns that add additional behavior by wrapping objects we need to extract the value at the end to do anything particularly useful.
By adding delegation to this class we have a cheat around this in that any method called on the nested DiveForwarder instances will call through to the associated base object instead.
I am not 100% sold on this approach, and will consider it more in the future.
Direct Known Subclasses
Constant Summary collapse
- NEW_DIVE =
Wrapper for creating a new Forwarder
-> v { new(v) }
Instance Method Summary collapse
-
#deconstruct ⇒ Array[DiveForwarder]
Approximation of an Array deconstruction:.
-
#deconstruct_keys(keys) ⇒ Hash
Approximates ‘deconstruct_keys` for Hashes, except in adding `Qo`-like behavior that allows to treat objects as “nested values” through their method calls.
-
#initialize(base_object) ⇒ DiveForwarder
constructor
Creates a new delegator that understands the pattern matching interface.
-
#value ⇒ Any
(also: #__getobj__)
Unwrapped context, aliased afterwards to use Ruby’s delegator interface.
Constructor Details
#initialize(base_object) ⇒ DiveForwarder
Creates a new delegator that understands the pattern matching interface
54 55 56 |
# File 'lib/dio/forwarders/base_forwarder.rb', line 54 def initialize(base_object) @base_object = base_object end |
Instance Method Details
#deconstruct ⇒ Array[DiveForwarder]
Approximation of an Array deconstruction:
“‘ruby
- 1, 2, 3
-
in [*, 2, *]
“‘
Attempts to find a reasonable interface by which to extract values to be matched. If an object that knows how to match already is sent through wrap its child values for deeper matching.
Current interface will work with ‘to_a`, `to_ary`, `map`, and values that can already `deconstruct`. If others are desired please submit a PR to add them
78 79 80 81 82 83 84 85 86 |
# File 'lib/dio/forwarders/base_forwarder.rb', line 78 def deconstruct return @base_object.deconstruct.map!(&NEW_DIVE) if @base_object.respond_to?(:deconstruct) return @base_object.to_a.map!(&NEW_DIVE) if @base_object.respond_to?(:to_a) return @base_object.to_ary.map!(&NEW_DIVE) if @base_object.respond_to?(:to_ary) return @base_object.map(&NEW_DIVE) if @base_object.respond_to?(:map) raise Dio::Errors::NoDeconstructionMethod end |
#deconstruct_keys(keys) ⇒ Hash
Approximates ‘deconstruct_keys` for Hashes, except in adding `Qo`-like behavior that allows to treat objects as “nested values” through their method calls.
**Deconstructing an Object**
In ‘Qo` one could match against an object by calling to its methods using `public_send`. This allowed one to “dive into” an object through a series of method calls, approximating a Hash pattern match.
**Native Behavior**
If the object already responds to ‘deconstruct_keys` this method will behave similarly to `deconstruct` and wrap its values as new `DiveForwarder` contexts.
110 111 112 113 114 115 116 117 118 |
# File 'lib/dio/forwarders/base_forwarder.rb', line 110 def deconstruct_keys(keys) if @base_object.respond_to?(:deconstruct_keys) @base_object .deconstruct_keys(keys) .transform_values!(&NEW_DIVE) else keys.to_h { |k| @base_object.public_send(k).then { |v| [k, NEW_DIVE[v]] } } end end |
#value ⇒ Any Also known as: __getobj__
Unwrapped context, aliased afterwards to use Ruby’s delegator interface
124 125 126 |
# File 'lib/dio/forwarders/base_forwarder.rb', line 124 def value @base_object end |