Class: Squeel::Nodes::KeyPath
- Includes:
- Operators, PredicateOperators
- Defined in:
- lib/squeel/nodes/key_path.rb
Overview
A node that stores a path of keys (of Symbol, Stub, or Join values) and an endpoint. Used similarly to a nested hash.
Instance Attribute Summary collapse
-
#path ⇒ Array<Symbol, Stub, Join>
readonly
The path.
Instance Method Summary collapse
-
#%(val) ⇒ KeyPath
Delegate % to the KeyPath’s endpoint, with a bit of special logic for stubs or functions.
-
#&(other) ⇒ And
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to &.
-
#*(other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to *.
-
#+(other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to +.
-
#-(other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to -.
-
#-@ ⇒ Not
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to -@.
-
#/(other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to /.
-
#absolute? ⇒ Boolean
Whether or not the KeyPath should be interpreted relative to its current location (if nested in a Hash, for instance) or as though it’s at the base.
-
#endpoint ⇒ Object
The endpoint, either another key as in the path, or a predicate, function, etc.
-
#endpoint=(val) ⇒ Object
Set the new value of the KeyPath’s endpoint.
-
#eql?(other) ⇒ Boolean
Object comparison.
-
#hash ⇒ Object
For use with equality tests.
-
#initialize(path, absolute = false) ⇒ KeyPath
constructor
Create a new KeyPath.
-
#initialize_copy(orig) ⇒ Object
private
Prevent a cloned keypath from inadvertently modifying the path of its source.
-
#method_missing(method_id, *args, &block) ⇒ KeyPath
Appends to the KeyPath or delegates to the endpoint, as appropriate.
-
#no_method_error(method_id) ⇒ Object
private
Raises a NoMethodError manually, bypassing #method_missing.
-
#op(operator, other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to #op.
-
#path_without_endpoint ⇒ Array
The KeyPath’s path, minus its endpoint, as a single array.
-
#sift(name, *args) ⇒ KeyPath
Allow KeyPath to have a sifter as its endpoint, if the endpoint is a chainable node (Stub or Join).
-
#to_s ⇒ Object
(also: #to_str)
Implement #to_s (and alias to #to_str) to play nicely with Active Record grouped calculations.
-
#to_sym ⇒ NilClass
expand_hash_conditions_for_aggregates assumes our hash keys can be converted to symbols, so this has to be implemented, but it doesn’t really have to do anything useful.
-
#|(other) ⇒ Or
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to |.
-
#~ ⇒ KeyPath
Set the absolute flag on this KeyPath.
Constructor Details
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_id, *args, &block) ⇒ KeyPath
Appends to the KeyPath or delegates to the endpoint, as appropriate
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/squeel/nodes/key_path.rb', line 182 def method_missing(method_id, *args, &block) super if method_id == :to_ary if endpoint.respond_to?(method_id) if Predicate === endpoint && method_id == :== false else # TODO: We really should not mutate here. self.endpoint = endpoint.send(method_id, *args) self end elsif Stub === endpoint || Join === endpoint if args.empty? @path << Stub.new(method_id) elsif (args.size == 1) && (Class === args[0]) @path << Join.new(method_id, Arel::InnerJoin, args[0]) else @path << Nodes::Function.new(method_id, args) end self else super end end |
Instance Attribute Details
Instance Method Details
#%(val) ⇒ KeyPath
Delegate % to the KeyPath’s endpoint, with a bit of special logic for stubs or functions.
157 158 159 160 161 162 163 164 165 166 |
# File 'lib/squeel/nodes/key_path.rb', line 157 def %(val) case endpoint when Stub, Function Array === val ? self.in(val) : self.eq(val) self else endpoint % val self end end |
#&(other) ⇒ And
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to &
69 70 71 |
# File 'lib/squeel/nodes/key_path.rb', line 69 def &(other) endpoint.respond_to?(:&) ? super : no_method_error(:&) end |
#*(other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to *
100 101 102 |
# File 'lib/squeel/nodes/key_path.rb', line 100 def *(other) endpoint.respond_to?(:*) ? super : no_method_error(:*) end |
#+(other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to +
84 85 86 |
# File 'lib/squeel/nodes/key_path.rb', line 84 def +(other) endpoint.respond_to?(:+) ? super : no_method_error(:+) end |
#-(other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to -
92 93 94 |
# File 'lib/squeel/nodes/key_path.rb', line 92 def -(other) endpoint.respond_to?(:-) ? super : no_method_error(:-) end |
#-@ ⇒ Not
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to -@
76 77 78 |
# File 'lib/squeel/nodes/key_path.rb', line 76 def -@ endpoint.respond_to?(:-@) ? super : no_method_error(:-@) end |
#/(other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to /
108 109 110 |
# File 'lib/squeel/nodes/key_path.rb', line 108 def /(other) endpoint.respond_to?(:/) ? super : no_method_error(:/) end |
#absolute? ⇒ Boolean
Whether or not the KeyPath should be interpreted relative to its current location
(if nested in a Hash, for instance) or as though it's at the base.
34 35 36 |
# File 'lib/squeel/nodes/key_path.rb', line 34 def absolute? @absolute end |
#endpoint ⇒ Object
Returns The endpoint, either another key as in the path, or a predicate, function, etc.
39 40 41 |
# File 'lib/squeel/nodes/key_path.rb', line 39 def endpoint @path[-1] end |
#endpoint=(val) ⇒ Object
Set the new value of the KeyPath’s endpoint.
46 47 48 |
# File 'lib/squeel/nodes/key_path.rb', line 46 def endpoint=(val) @path[-1] = val end |
#eql?(other) ⇒ Boolean
Object comparison
51 52 53 54 55 |
# File 'lib/squeel/nodes/key_path.rb', line 51 def eql?(other) self.class.eql?(other.class) && self.path.eql?(other.path) && self.absolute?.eql?(other.absolute?) end |
#hash ⇒ Object
For use with equality tests
142 143 144 |
# File 'lib/squeel/nodes/key_path.rb', line 142 def hash [self.class, *path].hash end |
#initialize_copy(orig) ⇒ Object (private)
Prevent a cloned keypath from inadvertently modifying the path of its source.
211 212 213 214 |
# File 'lib/squeel/nodes/key_path.rb', line 211 def initialize_copy(orig) super @path = @path.dup end |
#no_method_error(method_id) ⇒ Object (private)
Raises a NoMethodError manually, bypassing #method_missing. Used by special-case operator overrides.
218 219 220 |
# File 'lib/squeel/nodes/key_path.rb', line 218 def no_method_error(method_id) raise NoMethodError, "undefined method `#{method_id}' for #{self}:#{self.class}" end |
#op(operator, other) ⇒ Operation
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to #op
117 118 119 |
# File 'lib/squeel/nodes/key_path.rb', line 117 def op(operator, other) endpoint.respond_to?(:op) ? super : no_method_error(:op) end |
#path_without_endpoint ⇒ Array
Returns The KeyPath’s path, minus its endpoint, as a single array.
169 170 171 |
# File 'lib/squeel/nodes/key_path.rb', line 169 def path_without_endpoint path[0..-2] end |
#sift(name, *args) ⇒ KeyPath
Allow KeyPath to have a sifter as its endpoint, if the endpoint is a chainable node (Stub or Join)
125 126 127 128 129 130 131 132 |
# File 'lib/squeel/nodes/key_path.rb', line 125 def sift(name, *args) if Stub === endpoint || Join === endpoint @path << Sifter.new(name, args) self else no_method_error :sift end end |
#to_s ⇒ Object Also known as: to_str
Implement #to_s (and alias to #to_str) to play nicely with Active Record grouped calculations
175 176 177 |
# File 'lib/squeel/nodes/key_path.rb', line 175 def to_s path.map(&:to_s).join('.') end |
#to_sym ⇒ NilClass
expand_hash_conditions_for_aggregates assumes our hash keys can be converted to symbols, so this has to be implemented, but it doesn’t really have to do anything useful.
150 151 152 |
# File 'lib/squeel/nodes/key_path.rb', line 150 def to_sym nil end |
#|(other) ⇒ Or
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to |
61 62 63 |
# File 'lib/squeel/nodes/key_path.rb', line 61 def |(other) endpoint.respond_to?(:|) ? super : no_method_error(:|) end |
#~ ⇒ KeyPath
Set the absolute flag on this KeyPath
136 137 138 139 |
# File 'lib/squeel/nodes/key_path.rb', line 136 def ~ @absolute = true self end |