summaryrefslogtreecommitdiffstats
path: root/lib/puppet/parser/functions.rb
blob: a9f7ff1daa3c2a7fe16ed4027ae65cffcc0e2a9f (plain)
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$