Class: Squeel::Nodes::KeyPath
- Inherits:
-
Object
- Object
- 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
-
#endpoint ⇒ Object
readonly
The endpoint, either another key as in the path, or a predicate, function, etc.
-
#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.
-
#eql?(other) ⇒ Boolean
Object comparison.
-
#hash ⇒ Object
For use with equality tests.
-
#initialize(path, endpoint, absolute = false) ⇒ KeyPath
constructor
Create a new KeyPath.
-
#method_missing(method_id, *args) ⇒ 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_with_endpoint ⇒ Array
The KeyPath’s path, including 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 (and alias to :to_str) to play nicely with ActiveRecord 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
#initialize(path, endpoint, absolute = false) ⇒ KeyPath
Create a new KeyPath.
29 30 31 32 33 34 |
# File 'lib/squeel/nodes/key_path.rb', line 29 def initialize(path, endpoint, absolute = false) @path, @endpoint = path, endpoint @path = [@path] unless Array === @path @endpoint = Stub.new(@endpoint) if Symbol === @endpoint @absolute = absolute end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_id, *args) ⇒ KeyPath
Appends to the KeyPath or delegates to the endpoint, as appropriate
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/squeel/nodes/key_path.rb', line 176 def method_missing(method_id, *args) super if method_id == :to_ary if endpoint.respond_to? method_id @endpoint = @endpoint.send(method_id, *args) self elsif Stub === endpoint || Join === endpoint @path << endpoint if args.empty? @endpoint = Stub.new(method_id) elsif (args.size == 1) && (Class === args[0]) @endpoint = Join.new(method_id, Arel::InnerJoin, args[0]) else @endpoint = Nodes::Function.new method_id, args end self else super end end |
Instance Attribute Details
#endpoint ⇒ Object (readonly)
22 23 24 |
# File 'lib/squeel/nodes/key_path.rb', line 22 def endpoint @endpoint end |
Instance Method Details
#%(val) ⇒ KeyPath
Delegate % to the KeyPath’s endpoint, with a bit of special logic for stubs or functions.
152 153 154 155 156 157 158 159 160 161 |
# File 'lib/squeel/nodes/key_path.rb', line 152 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 &
63 64 65 |
# File 'lib/squeel/nodes/key_path.rb', line 63 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 *
94 95 96 |
# File 'lib/squeel/nodes/key_path.rb', line 94 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 +
78 79 80 |
# File 'lib/squeel/nodes/key_path.rb', line 78 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 -
86 87 88 |
# File 'lib/squeel/nodes/key_path.rb', line 86 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 -@
70 71 72 |
# File 'lib/squeel/nodes/key_path.rb', line 70 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 /
102 103 104 |
# File 'lib/squeel/nodes/key_path.rb', line 102 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.
39 40 41 |
# File 'lib/squeel/nodes/key_path.rb', line 39 def absolute? @absolute end |
#eql?(other) ⇒ Boolean
Object comparison
44 45 46 47 48 49 |
# File 'lib/squeel/nodes/key_path.rb', line 44 def eql?(other) self.class.eql?(other.class) && self.path.eql?(other.path) && self.endpoint.eql?(other.endpoint) && self.absolute?.eql?(other.absolute?) end |
#hash ⇒ Object
For use with equality tests
137 138 139 |
# File 'lib/squeel/nodes/key_path.rb', line 137 def hash [self.class, endpoint, *path].hash end |
#no_method_error(method_id) ⇒ Object (private)
Raises a NoMethodError manually, bypassing #method_missing. Used by special-case operator overrides.
201 202 203 |
# File 'lib/squeel/nodes/key_path.rb', line 201 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
111 112 113 |
# File 'lib/squeel/nodes/key_path.rb', line 111 def op(operator, other) endpoint.respond_to?(:op) ? super : no_method_error(:op) end |
#path_with_endpoint ⇒ Array
164 165 166 |
# File 'lib/squeel/nodes/key_path.rb', line 164 def path_with_endpoint path + [endpoint] end |
#sift(name, *args) ⇒ KeyPath
Allow KeyPath to have a sifter as its endpoint, if the endpoint is a chainable node (Stub or Join)
119 120 121 122 123 124 125 126 127 |
# File 'lib/squeel/nodes/key_path.rb', line 119 def sift(name, *args) if Stub === endpoint || Join === endpoint @path << endpoint @endpoint = Sifter.new(name, args) self else no_method_error :sift end end |
#to_s ⇒ Object Also known as: to_str
Implement (and alias to :to_str) to play nicely with ActiveRecord grouped calculations
169 170 171 |
# File 'lib/squeel/nodes/key_path.rb', line 169 def to_s path.map(&:to_s).join('.') << ".#{endpoint}" 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.
145 146 147 |
# File 'lib/squeel/nodes/key_path.rb', line 145 def to_sym nil end |
#|(other) ⇒ Or
Allow KeyPath to function like its endpoint, in the case where its endpoint responds to |
55 56 57 |
# File 'lib/squeel/nodes/key_path.rb', line 55 def |(other) endpoint.respond_to?(:|) ? super : no_method_error(:|) end |
#~ ⇒ KeyPath
Set the absolute flag on this KeyPath
131 132 133 134 |
# File 'lib/squeel/nodes/key_path.rb', line 131 def ~ @absolute = true self end |