diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2014-09-22 11:01:03 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2014-09-22 11:01:03 -0700 |
commit | b57a11cb8abfca345f63084ce841c6f412c1156e (patch) | |
tree | c58702c92ba90e121a4556bc4053a0e6b790873f /lib/arel/visitors/visitor.rb | |
parent | c903c6b28933a041d42d943c6c83f98aaa81f42a (diff) | |
download | rails-b57a11cb8abfca345f63084ce841c6f412c1156e.tar.gz rails-b57a11cb8abfca345f63084ce841c6f412c1156e.tar.bz2 rails-b57a11cb8abfca345f63084ce841c6f412c1156e.zip |
move the dispatch table to be per-instance
visitors are not shared among threads, so any mutations to the cache
should be OK. The cache is also pre-populated on construction, but we
should pull that out so we can share the cache among visitors in the
future.
Diffstat (limited to 'lib/arel/visitors/visitor.rb')
-rw-r--r-- | lib/arel/visitors/visitor.rb | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 0730c15794..2317d0c95f 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -1,32 +1,39 @@ module Arel module Visitors class Visitor + def initialize + @dispatch = Hash.new do |hash, class_name| + raise if class_name == 'Arel::Nodes::Union' + hash[class_name] = "visit_#{(class_name || '').gsub('::', '_')}" + end + + # pre-populate cache. FIXME: this should be passed in to each + # instance, but we can do that later. + self.class.private_instance_methods.sort.each do |name| + next unless name =~ /^visit_(.*)$/ + @dispatch[$1.gsub('_', '::')] = name + end + end + def accept object visit object end private - DISPATCH = Hash.new do |hash, visitor_class| - hash[visitor_class] = - Hash.new do |method_hash, node_class| - method_hash[node_class] = "visit_#{(node_class.name || '').gsub('::', '_')}" - end - end - def dispatch - DISPATCH[self.class] + @dispatch end def visit object - send dispatch[object.class], object + send dispatch[object.class.name], object rescue NoMethodError => e - raise e if respond_to?(dispatch[object.class], true) + raise e if respond_to?(dispatch[object.class.name], true) superklass = object.class.ancestors.find { |klass| - respond_to?(dispatch[klass], true) + respond_to?(dispatch[klass.name], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass - dispatch[object.class] = dispatch[superklass] + dispatch[object.class.name] = dispatch[superklass.name] retry end end |