summaryrefslogtreecommitdiffstats
path: root/lib/puppet/parser/functions.rb
blob: 6ba3669c023f338b87e64aa53389de3a81eae7ce (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
require 'puppet/util/autoload'
require 'puppet/parser/scope'

# A module for managing parser functions.  Each specified function
# is added to a central module that then gets included into the Scope
# class.
module Puppet::Parser::Functions

    @functions = {}
    @modules = {}

    class << self
        include Puppet::Util
    end

    def self.autoloader
        unless defined? @autoloader
            @autoloader = Puppet::Util::Autoload.new(self,
                "puppet/parser/functions",
                :wrap => false
            )
        end

        @autoloader
    end

    def self.environment_module(env = nil)
        @module ||= Module.new
    end

    # Create a new function type.
    def self.newfunction(name, options = {}, &block)
        name = symbolize(name)

        if @functions.include? name
            raise Puppet::DevError, "Function %s already defined" % name
        end

        ftype = options[:type] || :statement

        unless ftype == :statement or ftype == :rvalue
            raise Puppet::DevError, "Invalid statement type %s" % ftype.inspect
        end

        fname = "function_" + name.to_s
        environment_module.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}
        if options[:doc]
            @functions[name][:doc] = options[:doc]
        end
    end

    # Remove a function added by newfunction
    def self.rmfunction(name)
        name = symbolize(name)

        unless @functions.include? name
            raise Puppet::DevError, "Function %s is not defined" % name
        end

        @functions.delete(name)

        fname = "function_" + name.to_s
        environment_module.send(:remove_method, fname)
    end

    # Determine if a given name is a function
    def self.function(name)
        name = symbolize(name)

        unless @functions.include? name
            autoloader.load(name)
        end

        if @functions.include? name
            return @functions[name][:name]
        else
            return false
        end
    end

    def self.functiondocs
        autoloader.loadall

        ret = ""

        @functions.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash|
            #ret += "%s\n%s\n" % [name, hash[:type]]
            ret += "%s\n%s\n" % [name, "-" * name.to_s.length]
            if hash[:doc]
                ret += Puppet::Util::Docs.scrub(hash[:doc])
            else
                ret += "Undocumented.\n"
            end

            ret += "\n\n- **Type**: %s\n\n" % hash[:type]
        end

        return ret
    end

    def self.functions
        @functions.keys
    end

    # Determine if a given function returns a value or not.
    def self.rvalue?(name)
        name = symbolize(name)

        if @functions.include? name
            case @functions[name][:type]
            when :statement; return false
            when :rvalue; return true
            end
        else
            return false
        end
    end

    # Runs a newfunction to create a function for each of the log levels

    Puppet::Util::Log.levels.each do |level|
        newfunction(level, :doc => "Log a message on the server at level #{level.to_s}.") do |vals|
            send(level, vals.join(" "))
        end
    end

end