Class: Puppet::Parser::AST::Lambda

Inherits:
BlockExpression show all
Defined in:
lib/puppet/parser/ast/lambda.rb

Overview

A block of statements/expressions with additional parameters Requires scope to contain the values for the defined parameters when evaluated If evaluated without a prepared scope, the lambda will behave like its super class.

Instance Attribute Summary collapse

Attributes inherited from Branch

#children, #pin

Instance Method Summary collapse

Methods inherited from BlockExpression

#[], #push, #sequence_with

Methods inherited from Branch

#each

Constructor Details

#initialize(options) ⇒ Lambda

Returns a new instance of Lambda.



112
113
114
115
116
117
# File 'lib/puppet/parser/ast/lambda.rb', line 112

def initialize(options)
  super(options)
  # ensure there is an empty parameters structure if not given by creator
  @parameters = [] unless options[:parameters]
  validate
end

Instance Attribute Details

#parametersArray<Array<String,String>>

The lambda parameters. These are encoded as an array where each entry is an array of one or two object. The first is the parameter name, and the optional second object is the value expression (that will be evaluated when bound to a scope). The value expression is the default value for the parameter. All default values must be at the end of the parameter list.

Returns:



18
19
20
# File 'lib/puppet/parser/ast/lambda.rb', line 18

def parameters
  @parameters
end

Instance Method Details

#call(scope, *args) ⇒ Object

Calls the lambda. Assigns argument values in a nested local scope that should be used to evaluate the lambda and then evaluates the lambda.

Parameters:

  • scope (Puppet::Scope)

    the calling scope

Returns:

  • (Object)

    the result of evaluating the expression(s) in the lambda

Raises:



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
# File 'lib/puppet/parser/ast/lambda.rb', line 37

def call(scope, *args)
  raise Puppet::ParseError, "Too many arguments: #{args.size} for #{parameters.size}" unless args.size <= parameters.size

  # associate values with parameters
  merged = parameters.zip(args)
  # calculate missing arguments
  missing = parameters.slice(args.size, parameters.size - args.size).select {|e| e.size == 1}
  unless missing.empty?
    optional = parameters.count { |p| p.size == 2 }
    raise Puppet::ParseError, "Too few arguments; #{args.size} for #{optional > 0 ? ' min ' : ''}#{parameters.size - optional}"
  end

  evaluated = merged.collect do |m|
    # m can be one of
    # m = [["name"], "given"]
    #   | [["name", default_expr], "given"]
    #
    # "given" is always an optional entry. If a parameter was provided then
    # the entry will be in the array, otherwise the m array will be a
    # single element.
    given_argument = m[1]
    argument_name = m[0][0]
    default_expression = m[0][1]

    value = if m.size == 1
      default_expression.safeevaluate(scope)
    else
      given_argument
    end
    [argument_name, value]
  end

  # Store the evaluated name => value associations in a new inner/local/ephemeral scope
  # (This is made complicated due to the fact that the implementation of scope is overloaded with
  # functionality and an inner ephemeral scope must be used (as opposed to just pushing a local scope
  # on a scope "stack").

  # Ensure variable exists with nil value if error occurs. 
  # Some ruby implementations does not like creating variable on return
  result = nil
  begin
    elevel = scope.ephemeral_level
    scope.ephemeral_from(Hash[evaluated], file, line)
    result = safeevaluate(scope)
  ensure
    scope.unset_ephemeral_var(elevel)
  end
  result
end

#evaluate(scope) ⇒ Object

Evaluates each expression/statement and produce the last expression evaluation result

Returns:

  • (Object)

    what the last expression evaluated to



21
22
23
24
25
26
27
28
29
# File 'lib/puppet/parser/ast/lambda.rb', line 21

def evaluate(scope)
  if @children.is_a? Puppet::Parser::AST::ASTArray
    result = nil
    @children.each {|expr| result = expr.evaluate(scope) }
    result
  else
    @children.evaluate(scope)
  end
end

#optional_parameter_countInteger

Returns the number of optional parameters.

Returns:

  • (Integer)

    the number of optional accepted parameters



108
109
110
# File 'lib/puppet/parser/ast/lambda.rb', line 108

def optional_parameter_count
  @parameters.count {|p| p.size == 2 }
end

#parameter_countInteger

Returns the number of parameters (required and optional)

Returns:

  • (Integer)

    the total number of accepted parameters



102
103
104
# File 'lib/puppet/parser/ast/lambda.rb', line 102

def parameter_count
  @parameters.size
end

#parameter_namesObject



131
132
133
# File 'lib/puppet/parser/ast/lambda.rb', line 131

def parameter_names
  @parameters.collect {|p| p[0] }
end

#puppet_lambdaObject

marker method checked with respond_to :puppet_lambda



127
128
129
# File 'lib/puppet/parser/ast/lambda.rb', line 127

def puppet_lambda()
  true
end

#to_sObject



119
120
121
122
123
124
# File 'lib/puppet/parser/ast/lambda.rb', line 119

def to_s
  result = ["{|"]
  result += @parameters.collect {|p| "#{p[0]}" + (p.size == 2 && p[1]) ? p[1].to_s() : '' }.join(', ')
  result << "| ... }"
  result.join('')
end

#validateObject

Validates the lambda. Validation checks if parameters with default values are at the end of the list. (It is illegal to have a parameter with default value followed by one without).

Raises:

  • (Puppet::ParseError)

    if a parameter with a default comes before a parameter without default value



93
94
95
96
97
98
# File 'lib/puppet/parser/ast/lambda.rb', line 93

def validate
  params = parameters || []
  defaults = params.drop_while {|p| p.size < 2 }
  trailing = defaults.drop_while {|p| p.size == 2 }
  raise Puppet::ParseError, "Lambda parameters with default values must be placed last" unless trailing.empty?
end