Class: Squeel::Visitors::Visitor
- Inherits:
-
Object
- Object
- Squeel::Visitors::Visitor
- Defined in:
- lib/squeel/visitors/visitor.rb
Overview
The Base visitor class, containing the default behavior common to subclasses.
Direct Known Subclasses
Constant Summary collapse
- DISPATCH =
A hash that caches the method name to use for a visitor for a given class
Hash.new do |hash, klass| hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" end
Instance Attribute Summary collapse
-
#context ⇒ Object
Returns the value of attribute context.
Class Method Summary collapse
-
.can_visit?(object) ⇒ Boolean
Whether or not visitors of this class can visit the given object.
Instance Method Summary collapse
-
#accept(object, parent = context.base) ⇒ Object
Accept an object.
-
#can_visit?(object) ⇒ Boolean
Whether or not the visitor can visit the given object.
-
#hash_context_shifted? ⇒ Boolean
private
If we’re visiting stuff in a hash, it’s good to check whether or not we’ve shifted context already.
-
#initialize(context = nil) ⇒ Visitor
constructor
Create a new Visitor that uses the supplied context object to contextualize visited nodes.
-
#quote(value) ⇒ Arel::Nodes::SqlLiteral
private
Quote a value based on its type, not on the last column used by the ARel visitor.
-
#quoted?(object) ⇒ Boolean
private
Important to avoid accidentally allowing the default ARel visitor’s last_column quoting behavior (where a value is quoted as though it is of the type of the last visited column).
-
#visit(object, parent) ⇒ Object
private
Visit the object.
-
#visit_Array(o, parent) ⇒ Array
private
Visit an array, which involves accepting any values we know how to accept, and skipping the rest.
-
#visit_passthrough(object, parent) ⇒ Object
(also: #visit_Fixnum, #visit_Bignum)
private
Pass an object through the visitor unmodified.
Constructor Details
#initialize(context = nil) ⇒ Visitor
Create a new Visitor that uses the supplied context object to contextualize visited nodes.
15 16 17 18 |
# File 'lib/squeel/visitors/visitor.rb', line 15 def initialize(context = nil) @context = context @hash_context_depth = 0 end |
Instance Attribute Details
#context ⇒ Object
Returns the value of attribute context.
8 9 10 |
# File 'lib/squeel/visitors/visitor.rb', line 8 def context @context end |
Class Method Details
.can_visit?(object) ⇒ Boolean
Returns Whether or not visitors of this class can visit the given object.
38 39 40 41 42 43 44 45 |
# File 'lib/squeel/visitors/visitor.rb', line 38 def self.can_visit?(object) @can_visit ||= Hash.new do |hash, klass| hash[klass] = klass.ancestors.detect { |ancestor| private_method_defined? DISPATCH[ancestor] } ? true : false end @can_visit[object.class] end |
Instance Method Details
#accept(object, parent = context.base) ⇒ Object
Accept an object.
26 27 28 |
# File 'lib/squeel/visitors/visitor.rb', line 26 def accept(object, parent = context.base) visit(object, parent) end |
#can_visit?(object) ⇒ Boolean
Returns Whether or not the visitor can visit the given object.
32 33 34 |
# File 'lib/squeel/visitors/visitor.rb', line 32 def can_visit?(object) self.class.can_visit? object end |
#hash_context_shifted? ⇒ Boolean (private)
If we’re visiting stuff in a hash, it’s good to check whether or not we’ve shifted context already. If we have, we may want to use caution as it pertains to certain input, in case it’s untrusted. See CVE-2012-2661 for info.
60 61 62 |
# File 'lib/squeel/visitors/visitor.rb', line 60 def hash_context_shifted? @hash_context_depth > 0 end |
#quote(value) ⇒ Arel::Nodes::SqlLiteral (private)
Quote a value based on its type, not on the last column used by the ARel visitor. This is occasionally necessary to avoid having ARel quote a value according to an integer column, converting ‘My String’ to 0.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/squeel/visitors/visitor.rb', line 88 def quote(value) if quoted? value case value when Array value.map {|v| quote(v)} when Range Range.new(quote(value.begin), quote(value.end), value.exclude_end?) else Arel.sql(arel_visitor.accept value) end else value end end |
#quoted?(object) ⇒ Boolean (private)
Important to avoid accidentally allowing the default ARel visitor’s last_column quoting behavior (where a value is quoted as though it is of the type of the last visited column). This can wreak havoc with Functions and Operations.
72 73 74 75 76 77 78 79 |
# File 'lib/squeel/visitors/visitor.rb', line 72 def quoted?(object) case object when Arel::Nodes::SqlLiteral, Bignum, Fixnum, Arel::SelectManager false else true end end |
#visit(object, parent) ⇒ Object (private)
Visit the object.
107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/squeel/visitors/visitor.rb', line 107 def visit(object, parent) send(DISPATCH[object.class], object, parent) rescue NoMethodError => e raise e if respond_to?(DISPATCH[object.class], true) superklass = object.class.ancestors.find { |klass| respond_to?(DISPATCH[klass], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass DISPATCH[object.class] = DISPATCH[superklass] retry end |
#visit_Array(o, parent) ⇒ Array (private)
Visit an array, which involves accepting any values we know how to accept, and skipping the rest.
126 127 128 |
# File 'lib/squeel/visitors/visitor.rb', line 126 def visit_Array(o, parent) o.map { |v| can_visit?(v) ? visit(v, parent) : v }.flatten end |
#visit_passthrough(object, parent) ⇒ Object (private) Also known as: visit_Fixnum, visit_Bignum
Pass an object through the visitor unmodified. This is in order to allow objects that don’t require modification to be handled by ARel directly.
137 138 139 |
# File 'lib/squeel/visitors/visitor.rb', line 137 def visit_passthrough(object, parent) object end |