Created
February 17, 2017 19:10
-
-
Save film42/6e43ce2f27d2f91ee4daf011a20e1c0d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Arel | |
module Visitors | |
class Visitor | |
def initialize | |
@dispatch = get_dispatch_cache | |
@random = [0.1, 0.5, 1, 2, 4] | |
end | |
def accept object | |
visit object | |
end | |
private | |
def self.dispatch_cache | |
Hash.new do |hash, klass| | |
hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" | |
end | |
end | |
def get_dispatch_cache | |
self.class.dispatch_cache | |
end | |
def dispatch | |
@dispatch | |
end | |
def visit object | |
sleep @random.sample | |
dispatch_method = dispatch[object.class] | |
send dispatch_method, object | |
rescue NoMethodError => e | |
puts "HERE" | |
sleep @random.sample | |
raise e if respond_to?(dispatch_method, 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 | |
end | |
end | |
end | |
# frozen_string_literal: true | |
require 'helper' | |
module Arel | |
module Visitors | |
describe 'avoiding contamination between visitor dispatch tables' do | |
before do | |
@connection = Table.engine.connection | |
@table = Table.new(:users) | |
end | |
it 'dispatches properly after failing upwards' do | |
node = Nodes::Union.new(Nodes::True.new, Nodes::False.new) | |
assert_equal "( TRUE UNION FALSE )", node.to_sql | |
node.first # from Nodes::Node's Enumerable mixin | |
assert_equal "( TRUE UNION FALSE )", node.to_sql | |
end | |
it 'does not throw NoMethodError when multi-threaded defining "visit"' do | |
::Thread.abort_on_exception = true | |
threads = [] | |
20.times do | |
threads << ::Thread.new do | |
puts "thread opened" | |
10.times do | |
node = Nodes::Union.new(Nodes::True.new, Nodes::False.new) | |
assert_equal "( TRUE UNION FALSE )", node.to_sql | |
node.first # from Nodes::Node's Enumerable mixin | |
assert_equal "( TRUE UNION FALSE )", node.to_sql | |
end | |
puts "thread done" | |
end | |
end | |
threads.map(&:join) | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment