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
|
# Grr
require 'puppet/parser/scope'
module Puppet::Parser
module Functions
# A module for managing parser functions. Each specified function
# becomes an instance method on the Scope class.
# Create a new function type.
def self.newfunction(name, ftype = :statement, &block)
@functions ||= {}
name = name.intern if name.is_a? String
if @functions.include? name
raise Puppet::DevError, "Function %s already defined" % name
end
# We want to use a separate, hidden module, because we don't want
# people to be able to call them directly.
unless defined? FCollection
eval("module FCollection; end")
end
unless ftype == :statement or ftype == :rvalue
raise Puppet::DevError, "Invalid statement type %s" % ftype.inspect
end
fname = "function_" + name.to_s
Puppet::Parser::Scope.send(:define_method, fname, &block)
# Someday we'll support specifying an arity, but for now, nope
#@functions[name] = {:arity => arity, :type => ftype}
@functions[name] = {:type => ftype, :name => fname}
end
# Determine if a given name is a function
def self.function(name)
name = name.intern if name.is_a? String
if @functions.include? name
return @functions[name][:name]
else
return false
end
end
# Determine if a given function returns a value or not.
def self.rvalue?(name)
name = name.intern if name.is_a? String
if @functions.include? name
case @functions[name][:type]
when :statement: return false
when :rvalue: return true
end
else
return false
end
end
# Include the specified classes
newfunction(:include) do |vals|
vals.each do |val|
if objecttype = lookuptype(val)
# It's a defined type, so set it into the scope so it can
# be evaluated.
setobject(
:type => val,
:arguments => {}
)
else
raise Puppet::ParseError, "Unknown class %s" % val
end
end
end
# Tag the current scope with each passed name
newfunction(:tag) do |vals|
vals.each do |val|
# Some hackery, because the tags are stored by object id
# for singletonness.
self.setclass(val.object_id, val)
end
# Also add them as tags
self.tag(*vals)
end
# Test whether a given tag is set. This functions as a big OR -- if any of the
# specified tags are unset, we return false.
newfunction(:tagged, :rvalue) do |vals|
classlist = self.classlist
retval = true
vals.each do |val|
unless classlist.include?(val) or self.tags.include?(val)
retval = false
break
end
end
return retval
end
# Test whether a given class or definition is defined
newfunction(:defined, :rvalue) do |vals|
retval = true
vals.each do |val|
unless builtintype?(val) or lookuptype(val)
retval = false
break
end
end
return retval
end
newfunction(:fail, :statement) do |vals|
vals = vals.collect { |s| s.to_s }.join(" ") if vals.is_a? Array
raise Puppet::ParseError, vals.to_s
end
newfunction(:template, :rvalue) do |vals|
require 'erb'
vals.collect do |file|
# Use a wrapper, so the template can't get access to the full
# Scope object.
debug "Retrieving template %s" % file
wrapper = Puppet::Parser::Scope::TemplateWrapper.new(self, file)
begin
wrapper.result()
rescue => detail
raise Puppet::ParseError,
"Failed to parse template %s: %s" %
[file, detail]
end
end.join("")
end
end
end
# $Id$
|