Class: Puppet::Pops::Visitor::Visitor2
- Defined in:
- lib/puppet/pops/visitor.rb
Overview
This is an alternative implementation that separates the finding of method names (Cached in the Visitor2 class), and bound methods (in an inner Delegator class) that are cached for this receiver instance. This is based on micro benchmarks measuring that a send is slower that directly calling a bound method. Larger benchmark however show that the overhead is fractional. Additional (larger) tests may show otherwise. To use this class instead of the regular Visitor.
@@the_visitor_c = Visitor2.new(...)
@@the_visitor = @@the_visitor_c.instance(self)
then visit with one of the Delegator's visit methods.
Performance Note: there are still issues with this implementation (although cleaner) since it requires holding on to the first instance in order to compute respond_do?. This is required if the class is using method_missing? which cannot be computed by introspection of the class (which would be ideal). Another approach is to pre-scan all the available methods starting with the pattern for the visitor, scan the class, and just check if the class has this method. (This will not work for dispatch to methods that requires method missing. (Maybe that does not matter) Further experiments could try looking up unbound methods via the class, cloning and binding them instead of again looking them up with #method(name) Also note that this implementation does not check min/max args on each call - there was not much gain from skipping this. It is safe to skip, but produces less friendly errors if there is an error in the implementation.
Defined Under Namespace
Classes: Delegator
Instance Attribute Summary collapse
- #cache ⇒ Object readonly
- #max_args ⇒ Object readonly
- #message ⇒ Object readonly
- #min_args ⇒ Object readonly
- #receiver ⇒ Object readonly
Instance Method Summary collapse
-
#initialize(receiver, message, min_args = 0, max_args = nil) ⇒ Visitor2
constructor
A new instance of Visitor2.
- #instance(receiver) ⇒ Object
-
#method_name_for(thing) ⇒ Symbol?
Produce the name of the method to use.
Constructor Details
#initialize(receiver, message, min_args = 0, max_args = nil) ⇒ Visitor2
Returns a new instance of Visitor2.
115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/puppet/pops/visitor.rb', line 115 def initialize(receiver, , min_args=0, max_args=nil) raise ArgumentError.new("receiver can not be nil") if receiver.nil? raise ArgumentError.new("min_args must be >= 0") if min_args < 0 raise ArgumentError.new("max_args must be >= min_args or nil") if max_args && max_args < min_args @receiver = receiver @message = @min_args = min_args @max_args = max_args @cache = Hash.new end |
Instance Attribute Details
#cache ⇒ Object (readonly)
113 114 115 |
# File 'lib/puppet/pops/visitor.rb', line 113 def cache @cache end |
#max_args ⇒ Object (readonly)
113 114 115 |
# File 'lib/puppet/pops/visitor.rb', line 113 def max_args @max_args end |
#message ⇒ Object (readonly)
113 114 115 |
# File 'lib/puppet/pops/visitor.rb', line 113 def @message end |
#min_args ⇒ Object (readonly)
113 114 115 |
# File 'lib/puppet/pops/visitor.rb', line 113 def min_args @min_args end |
#receiver ⇒ Object (readonly)
113 114 115 |
# File 'lib/puppet/pops/visitor.rb', line 113 def receiver @receiver end |
Instance Method Details
#instance(receiver) ⇒ Object
127 128 129 130 |
# File 'lib/puppet/pops/visitor.rb', line 127 def instance(receiver) # Create a visitable instance for the receiver Delegator.new(receiver, self) end |
#method_name_for(thing) ⇒ Symbol?
Produce the name of the method to use
135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/puppet/pops/visitor.rb', line 135 def method_name_for(thing) if method_name = @cache[thing.class] return method_name else thing.class.ancestors().each do |ancestor| method_name = :"#{@message}_#{ancestor.name.split(/::/).last}" next unless receiver.respond_to?(method_name, true) @cache[thing.class] = method_name return method_name end end end |