Class: Puppet::Pops::Visitor

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/pops/visitor.rb

Overview

A Visitor performs delegation to a given receiver based on the configuration of the Visitor. A new visitor is created with a given receiver, a method prefix, min, and max argument counts. e.g.

visitor = Visitor.new(self, "visit_from", 1, 1)

will make the visitor call “self.visit_from_CLASS(x)” where CLASS is resolved to the given objects class, or one of is ancestors, the first class for which there is an implementation of a method will be selected.

Raises RuntimeError if there are too few or too many arguments, or if the receiver is not configured to handle a given visiting object.

Constant Summary collapse

NO_ARGS =
EMPTY_ARRAY

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(receiver, message, min_args = 0, max_args = nil) ⇒ Visitor

Returns a new instance of Visitor

Raises:

  • (ArgumentError)

15
16
17
18
19
20
21
22
23
24
# File 'lib/puppet/pops/visitor.rb', line 15

def initialize(receiver, message, min_args=0, max_args=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 = message
  @min_args = min_args
  @max_args = max_args
  @cache = Hash.new
end

Instance Attribute Details

#cacheObject (readonly)

Returns the value of attribute cache


14
15
16
# File 'lib/puppet/pops/visitor.rb', line 14

def cache
  @cache
end

#max_argsObject (readonly)

Returns the value of attribute max_args


14
15
16
# File 'lib/puppet/pops/visitor.rb', line 14

def max_args
  @max_args
end

#messageObject (readonly)

Returns the value of attribute message


14
15
16
# File 'lib/puppet/pops/visitor.rb', line 14

def message
  @message
end

#min_argsObject (readonly)

Returns the value of attribute min_args


14
15
16
# File 'lib/puppet/pops/visitor.rb', line 14

def min_args
  @min_args
end

#receiverObject (readonly)

Returns the value of attribute receiver


14
15
16
# File 'lib/puppet/pops/visitor.rb', line 14

def receiver
  @receiver
end

Instance Method Details

#visit(thing, *args) ⇒ Object

Visit the configured receiver


27
28
29
# File 'lib/puppet/pops/visitor.rb', line 27

def visit(thing, *args)
  visit_this(@receiver, thing, args)
end

#visit_this(receiver, thing, args) ⇒ Object

Visit an explicit receiver


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/puppet/pops/visitor.rb', line 34

def visit_this(receiver, thing, args)
  raise "Visitor Error: Too few arguments passed. min = #{@min_args}" unless args.length >= @min_args
  if @max_args
    raise "Visitor Error: Too many arguments passed. max = #{@max_args}" unless args.length <= @max_args
  end
  method_name = @cache[thing.class]
  if method_name
    return receiver.send(method_name, thing, *args)
  else
    thing.class.ancestors().each do |ancestor|
      name = ancestor.name
      next if name.nil?
      method_name = :"#{@message}_#{name.split(DOUBLE_COLON).last}"
      next unless receiver.respond_to?(method_name, true)
      @cache[thing.class] = method_name
      return receiver.send(method_name, thing, *args)
    end
  end
  raise "Visitor Error: the configured receiver (#{receiver.class}) can't handle instance of: #{thing.class}"
end

#visit_this_0(receiver, thing) ⇒ Object

Visit an explicit receiver with 0 args (This is ~30% faster than calling the general method)


80
81
82
83
84
85
86
# File 'lib/puppet/pops/visitor.rb', line 80

def visit_this_0(receiver, thing)
  method_name = @cache[thing.class]
  if method_name
    return receiver.send(method_name, thing)
  end
  visit_this(receiver, thing, NO_ARGS)
end

#visit_this_1(receiver, thing, arg) ⇒ Object

Visit an explicit receiver with 1 args (This is ~30% faster than calling the general method)


91
92
93
94
95
96
97
# File 'lib/puppet/pops/visitor.rb', line 91

def visit_this_1(receiver, thing, arg)
  method_name = @cache[thing.class]
  if method_name
    return receiver.send(method_name, thing, arg)
  end
  visit_this(receiver, thing, [arg])
end

#visit_this_2(receiver, thing, arg1, arg2) ⇒ Object

Visit an explicit receiver with 2 args (This is ~30% faster than calling the general method)


102
103
104
105
106
107
108
# File 'lib/puppet/pops/visitor.rb', line 102

def visit_this_2(receiver, thing, arg1, arg2)
  method_name = @cache[thing.class]
  if method_name
    return receiver.send(method_name, thing, arg1, arg2)
  end
  visit_this(receiver, thing, [arg1, arg2])
end

#visit_this_3(receiver, thing, arg1, arg2, arg3) ⇒ Object

Visit an explicit receiver with 3 args (This is ~30% faster than calling the general method)


113
114
115
116
117
118
119
# File 'lib/puppet/pops/visitor.rb', line 113

def visit_this_3(receiver, thing, arg1, arg2, arg3)
  method_name = @cache[thing.class]
  if method_name
    return receiver.send(method_name, thing, arg1, arg2, arg3)
  end
  visit_this(receiver, thing, [arg1, arg2, arg3])
end

#visit_this_class(receiver, clazz, args) ⇒ Object

Visit an explicit receiver


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/puppet/pops/visitor.rb', line 56

def visit_this_class(receiver, clazz, args)
  raise "Visitor Error: Too few arguments passed. min = #{@min_args}" unless args.length >= @min_args
  if @max_args
    raise "Visitor Error: Too many arguments passed. max = #{@max_args}" unless args.length <= @max_args
  end
  method_name = @cache[clazz]
  if method_name
    return receiver.send(method_name, clazz, *args)
  else
    clazz.ancestors().each do |ancestor|
      name = ancestor.name
      next if name.nil?
      method_name = :"#{@message}_#{name.split(DOUBLE_COLON).last}"
      next unless receiver.respond_to?(method_name, true)
      @cache[clazz] = method_name
      return receiver.send(method_name, clazz, *args)
    end
  end
  raise "Visitor Error: the configured receiver (#{receiver.class}) can't handle instance of: #{clazz}"
end