Class: Squeel::Visitors::AttributeVisitor
- Defined in:
- lib/squeel/visitors/attribute_visitor.rb
Overview
A visitor that tries to convert visited nodes into Arel::Attributes or other nodes that can be used for grouping, ordering, and the like.
Constant Summary
Constants inherited from Base
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
-
#implies_context_change?(v) ⇒ Boolean
private
Whether the given value implies a context change.
-
#visit_Array(o, parent) ⇒ Array
private
Visit elements of an array that it’s possible to visit – leave other elements untouched.
-
#visit_Hash(o, parent) ⇒ Array
private
Visit a Hash.
-
#visit_Squeel_Nodes_Function(o, parent) ⇒ Object
private
Visit a Function node.
-
#visit_Squeel_Nodes_KeyPath(o, parent) ⇒ Object
private
Visit a keypath.
-
#visit_Squeel_Nodes_Operation(o, parent) ⇒ Object
private
Visit an Operation node.
-
#visit_Squeel_Nodes_Order(o, parent) ⇒ Arel::Nodes::Ordering
private
Visit an Order node.
-
#visit_Squeel_Nodes_Stub(o, parent) ⇒ Arel::Attribute
private
Visit a stub.
-
#visit_Symbol(o, parent) ⇒ Arel::Attribute
private
Visit a symbol.
-
#visit_with_context_change(k, v, parent) ⇒ Object
private
Change context (by setting the new parent to the result of a #find or #traverse on the key), then accept the given value.
-
#visit_without_context_change(k, v, parent) ⇒ Object
private
If there is no context change, we’ll just return the value unchanged, currently.
Methods inherited from Base
#accept, #can_accept?, can_accept?, #initialize, #quote, #quoted?, #visit
Constructor Details
This class inherits a constructor from Squeel::Visitors::Base
Instance Method Details
#implies_context_change?(v) ⇒ Boolean (private)
Returns Whether the given value implies a context change.
29 30 31 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 29 def implies_context_change?(v) can_accept?(v) end |
#visit_Array(o, parent) ⇒ Array (private)
Visit elements of an array that it’s possible to visit – leave other elements untouched.
74 75 76 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 74 def visit_Array(o, parent) o.map { |v| can_accept?(v) ? accept(v, parent) : v }.flatten end |
#visit_Hash(o, parent) ⇒ Array (private)
Visit a Hash. This entails iterating through each key and value and visiting each value in turn.
17 18 19 20 21 22 23 24 25 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 17 def visit_Hash(o, parent) o.map do |k, v| if implies_context_change?(v) visit_with_context_change(k, v, parent) else visit_without_context_change(k, v, parent) end end.flatten end |
#visit_Squeel_Nodes_Function(o, parent) ⇒ Object (private)
Visit a Function node. Each function argument will be accepted or contextualized if appropriate. Keep in mind that this occurs with the current parent within the context.
133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 133 def visit_Squeel_Nodes_Function(o, parent) args = o.args.map do |arg| case arg when Nodes::Function, Nodes::KeyPath accept(arg, parent) when Symbol, Nodes::Stub Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym]) else quote arg end end Arel::Nodes::NamedFunction.new(o.name, args, o.alias) end |
#visit_Squeel_Nodes_KeyPath(o, parent) ⇒ Object (private)
Visit a keypath. This will traverse the keypath’s “path”, setting a new parent as though the keypath’s endpoint was in a deeply-nested hash, then visit the endpoint with the new parent.
105 106 107 108 109 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 105 def visit_Squeel_Nodes_KeyPath(o, parent) parent = traverse(o, parent) accept(o.endpoint, parent) end |
#visit_Squeel_Nodes_Operation(o, parent) ⇒ Object (private)
Visit an Operation node. Each operand will be accepted or contextualized if appropriate. Keep in mind that this occurs with the current parent within the context.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 153 def visit_Squeel_Nodes_Operation(o, parent) args = o.args.map do |arg| case arg when Nodes::Function accept(arg, parent) when Symbol, Nodes::Stub Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym]) else quote arg end end op = case o.operator when :+ Arel::Nodes::Addition.new(args[0], args[1]) when :- Arel::Nodes::Subtraction.new(args[0], args[1]) when :* Arel::Nodes::Multiplication.new(args[0], args[1]) when :/ Arel::Nodes::Division.new(args[0], args[1]) else Arel.sql("#{arel_visitor.accept(args[0])} #{o.operator} #{arel_visitor.accept(args[1])}") end o.alias ? op.as(o.alias) : op end |
#visit_Squeel_Nodes_Order(o, parent) ⇒ Arel::Nodes::Ordering (private)
Visit an Order node.
116 117 118 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 116 def visit_Squeel_Nodes_Order(o, parent) accept(o.expr, parent).send(o.descending? ? :desc : :asc) end |
#visit_Squeel_Nodes_Stub(o, parent) ⇒ Arel::Attribute (private)
Visit a stub. This will return an attribute named after the stub against the current parent’s contextualized table.
94 95 96 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 94 def visit_Squeel_Nodes_Stub(o, parent) contextualize(parent)[o.symbol] end |
#visit_Symbol(o, parent) ⇒ Arel::Attribute (private)
Visit a symbol. This will return an attribute named after the symbol against the current parent’s contextualized table.
84 85 86 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 84 def visit_Symbol(o, parent) contextualize(parent)[o] end |
#visit_with_context_change(k, v, parent) ⇒ Object (private)
Change context (by setting the new parent to the result of a #find or #traverse on the key), then accept the given value.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 40 def visit_with_context_change(k, v, parent) parent = case k when Nodes::KeyPath traverse(k, parent, true) else find(k, parent) end if Array === v v.map {|val| accept(val, parent || k)} else can_accept?(v) ? accept(v, parent || k) : v end end |
#visit_without_context_change(k, v, parent) ⇒ Object (private)
If there is no context change, we’ll just return the value unchanged, currently. Is this really the right behavior? I don’t think so, but it works in this case.
64 65 66 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 64 def visit_without_context_change(k, v, parent) v end |