rails/arel — pull request #204 by trptcolin (2013-08-14 22:16:04+00:00)
Title: Cache visitor dispatch on a per-visitor basis

Currently, visitor dispatch (via the `DISPATCH`) constant is cached on a global basis. This means that, for instance, `Arel::Nodes::Union` will work fine when you use visitors implementing `visit_Arel_Nodes_Union` directly, like `Visitors::ToSql`.

But if a visitor needs to go up the class hierarchy looking for the method, the dispatch table gets mutated. This is fine as a cache for a specific visitor class, assuming methods don't get added dynamically to the visitor classes (anybody doing that should probably expect problems anyway). But for this mutation to ruin other visitors' dispatch cache seems bad.

So this patch turns `DISPATCH` into a 2-level hash, first for the visitor class, then for the node class.

The alternatives I see are:
- depend on clients to avoid calling methods implemented in ancestor classes (not awesome; they'd have to depend on implementation details)
- get rid of this cache entirely (bad; presumably the cache is there for perf reasons)
- depend on clients to call `Arel::Visitors::Visitor::DISPATCH.clear` (bad; they'd lose the perf benefits and have ugly code)

Thoughts?