1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
require 'puppet/indirector'
require 'puppet/indirector/indirection'
require 'puppet/util/instance_loader'
# A simple class that can function as the base class for indirected types.
class Puppet::Indirector::Terminus
require 'puppet/util/docs'
extend Puppet::Util::Docs
class << self
include Puppet::Util::InstanceLoader
attr_accessor :name, :terminus_type
attr_reader :abstract_terminus, :indirection
# Are we an abstract terminus type, rather than an instance with an
# associated indirection?
def abstract_terminus?
abstract_terminus
end
# Convert a constant to a short name.
def const2name(const)
const.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_" + i.downcase }.intern
end
# Look up the indirection if we were only provided a name.
def indirection=(name)
if name.is_a?(Puppet::Indirector::Indirection)
@indirection = name
elsif ind = Puppet::Indirector::Indirection.instance(name)
@indirection = ind
else
raise ArgumentError, "Could not find indirection instance %s for %s" % [name, self.name]
end
end
def indirection_name
@indirection.name
end
# Register our subclass with the appropriate indirection.
# This follows the convention that our terminus is named after the
# indirection.
def inherited(subclass)
longname = subclass.to_s
if longname =~ /#<Class/
raise Puppet::DevError, "Terminus subclasses must have associated constants"
end
names = longname.split("::")
# Convert everything to a lower-case symbol, converting camelcase to underscore word separation.
name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_" + i.downcase }.intern
subclass.name = name
# Short-circuit the abstract types, which are those that directly subclass
# the Terminus class.
if self == Puppet::Indirector::Terminus
subclass.mark_as_abstract_terminus
return
end
# Set the terminus type to be the name of the abstract terminus type.
# Yay, class/instance confusion.
subclass.terminus_type = self.name
# Our subclass is specifically associated with an indirection.
raise("Invalid name %s" % longname) unless names.length > 0
indirection_name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_" + i.downcase }.intern
if indirection_name == "" or indirection_name.nil?
raise Puppet::DevError, "Could not discern indirection model from class constant"
end
# This will throw an exception if the indirection instance cannot be found.
# Do this last, because it also registers the terminus type with the indirection,
# which needs the above information.
subclass.indirection = indirection_name
# And add this instance to the instance hash.
Puppet::Indirector::Terminus.register_terminus_class(subclass)
end
# Mark that this instance is abstract.
def mark_as_abstract_terminus
@abstract_terminus = true
end
def model
indirection.model
end
# Convert a short name to a constant.
def name2const(name)
name.to_s.capitalize.sub(/_(.)/) { |i| $1.upcase }
end
# Register a class, probably autoloaded.
def register_terminus_class(klass)
setup_instance_loading klass.indirection_name
instance_hash(klass.indirection_name)[klass.name] = klass
end
# Return a terminus by name, using the autoloader.
def terminus_class(indirection_name, terminus_type)
setup_instance_loading indirection_name
loaded_instance(indirection_name, terminus_type)
end
# Return all terminus classes for a given indirection.
def terminus_classes(indirection_name)
setup_instance_loading indirection_name
# Load them all.
instance_loader(indirection_name).loadall
# And return the list of names.
loaded_instances(indirection_name)
end
private
def setup_instance_loading(type)
unless instance_loading?(type)
instance_load type, "puppet/indirector/%s" % type
end
end
end
def indirection
self.class.indirection
end
def initialize
if self.class.abstract_terminus?
raise Puppet::DevError, "Cannot create instances of abstract terminus types"
end
end
def model
self.class.model
end
def name
self.class.name
end
def terminus_type
self.class.terminus_type
end
end
|