Class: Plumb::Key
- Inherits:
-
Object
- Object
- Plumb::Key
- Defined in:
- lib/plumb/key.rb
Overview
A hash-schema key. Two flavours:
* a LITERAL key — a Symbol or String name (`name:`, `'name' =>`). It is
matched by exact lookup and carries `#to_key`/`#to_sym`. A trailing `?`
(`name?:`) marks it optional. This is the common case and behaves exactly
as before.
* a MATCHER key — any Plumb type / `#===` object used as a key
(`Types::String[/^id_/] => ...`, or the `_` catch-all which wraps
`Types::Any`). It matches other keys via `matcher === other_key`, has no
single `#to_key`, and is inherently optional (it imposes no specific
required key).
Constant Summary collapse
- OPTIONAL_EXP =
OPTIONAL_EXP = /(\w+)(?)?$/
/(?<word>[A-Za-z0-9_$]+)(?<qmark>\?)?/
Instance Attribute Summary collapse
-
#matcher ⇒ Object
readonly
Returns the value of attribute matcher.
-
#node_name ⇒ Object
readonly
Returns the value of attribute node_name.
-
#to_key ⇒ Object
readonly
Returns the value of attribute to_key.
-
#to_sym ⇒ Object
readonly
Returns the value of attribute to_sym.
Class Method Summary collapse
Instance Method Summary collapse
-
#catch_all? ⇒ Boolean
The
_catch-all: a matcher key over the Any top, so it matches every key. - #eql?(other) ⇒ Boolean
-
#hash ⇒ Object
Dedupe/lookup identity.
-
#initialize(key, optional: false, symbolize: false) ⇒ Key
constructor
A new instance of Key.
- #inspect ⇒ Object
-
#literal? ⇒ Boolean
A concrete Symbol/String key (exact lookup) vs a type/matcher key.
-
#match?(other) ⇒ Boolean
Does this key match
other(a raw hash key)? Literal keys match by==(Symbol#===/String#===); matcher keys bymatcher === other. - #optional? ⇒ Boolean
- #to_s ⇒ Object
Constructor Details
#initialize(key, optional: false, symbolize: false) ⇒ Key
Returns a new instance of Key.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/plumb/key.rb', line 27 def initialize(key, optional: false, symbolize: false) @node_name = :key if key.is_a?(::Symbol) || key.is_a?(::String) key_type = symbolize ? Symbol : key.class match = OPTIONAL_EXP.match(key.to_s) name = match[:word] @to_key = key_type == Symbol ? name.to_sym : name @to_sym = @to_key.to_sym @optional = !match[:qmark].nil? ? true : optional @matcher = @to_key @literal = true else # A type/matcher key. It matches other keys structurally, so it has no # concrete #to_key and never imposes a required key. @matcher = Composable.wrap(key) @to_key = nil @to_sym = nil @optional = true @literal = false end freeze end |
Instance Attribute Details
#matcher ⇒ Object (readonly)
Returns the value of attribute matcher.
25 26 27 |
# File 'lib/plumb/key.rb', line 25 def matcher @matcher end |
#node_name ⇒ Object (readonly)
Returns the value of attribute node_name.
25 26 27 |
# File 'lib/plumb/key.rb', line 25 def node_name @node_name end |
#to_key ⇒ Object (readonly)
Returns the value of attribute to_key.
25 26 27 |
# File 'lib/plumb/key.rb', line 25 def to_key @to_key end |
#to_sym ⇒ Object (readonly)
Returns the value of attribute to_sym.
25 26 27 |
# File 'lib/plumb/key.rb', line 25 def to_sym @to_sym end |
Class Method Details
.wrap(key, symbolize: false) ⇒ Object
21 22 23 |
# File 'lib/plumb/key.rb', line 21 def self.wrap(key, symbolize: false) key.is_a?(Key) ? key : new(key, symbolize:) end |
Instance Method Details
#catch_all? ⇒ Boolean
The _ catch-all: a matcher key over the Any top, so it matches every key.
54 |
# File 'lib/plumb/key.rb', line 54 def catch_all? = !@literal && @matcher.is_a?(AnyClass) |
#eql?(other) ⇒ Boolean
69 70 71 72 73 74 75 76 77 |
# File 'lib/plumb/key.rb', line 69 def eql?(other) return false unless other.is_a?(Key) if @literal other.literal? && @to_key == other.to_key else !other.literal? && @matcher == other.matcher end end |
#hash ⇒ Object
Dedupe/lookup identity. Literal keys hash by name (unchanged); matcher keys
hash by matcher class (structural equality disambiguates via #eql?), so two
_ catch-alls collapse. Two keys are eql? when both literal with the same
name, or both matchers with equal matchers — optionality is deliberately
ignored (so name?/name collapse), and HashClass#== compares it separately.
67 |
# File 'lib/plumb/key.rb', line 67 def hash = @literal ? @to_key.hash : @matcher.class.hash |
#inspect ⇒ Object
83 84 85 86 87 88 89 90 91 |
# File 'lib/plumb/key.rb', line 83 def inspect if @literal "#{@to_key}#{'?' if @optional}" elsif catch_all? '_' else @matcher.inspect end end |
#literal? ⇒ Boolean
A concrete Symbol/String key (exact lookup) vs a type/matcher key.
51 |
# File 'lib/plumb/key.rb', line 51 def literal? = @literal |
#match?(other) ⇒ Boolean
Does this key match other (a raw hash key)? Literal keys match by ==
(Symbol#===/String#===); matcher keys by matcher === other.
58 |
# File 'lib/plumb/key.rb', line 58 def match?(other) = @matcher === other |
#optional? ⇒ Boolean
79 80 81 |
# File 'lib/plumb/key.rb', line 79 def optional? @optional end |
#to_s ⇒ Object
60 |
# File 'lib/plumb/key.rb', line 60 def to_s = (@to_key || @matcher).to_s |