class Puppet::Pops::Loader::PuppetResourceTypeImplInstantiator

The PuppetResourceTypeImplInstantiator instantiates a Puppet::Pops::ResourceTypeImpl object. given a Puppet Programming language source that when called evaluates the Puppet logic it contains.

Public Class Methods

create(loader, typed_name, source_ref, pp_code_string) click to toggle source

Produces an instance of Puppet::Pops::ResourceTypeImpl, or fails with an error if the given puppet source does not produce such an instance when evaluated.

@param loader [Loader] The loader the function is associated with @param typed_name [TypedName] the type / name of the resource type impl to load @param source_ref [URI, String] a reference to the source / origin of the puppet code to evaluate @param pp_code_string [String] puppet code in a string

@return [Puppet::Pops::ResourceTypeImpl] - an instantiated ResourceTypeImpl

   # File lib/puppet/pops/loader/puppet_resource_type_impl_instantiator.rb
17 def self.create(loader, typed_name, source_ref, pp_code_string)
18   parser = Parser::EvaluatingParser.new()
19 
20   # parse and validate
21   model = parser.parse_string(pp_code_string, source_ref)
22   statements = if model.is_a?(Model::Program)
23                  if model.body.is_a?(Model::BlockExpression)
24                    model.body.statements
25                  else
26                    [model.body]
27                  end
28                else
29                  EMPTY_ARRAY
30                end
31   statements = statements.reject { |s| s.is_a?(Model::Nop) }
32   if statements.empty?
33     raise ArgumentError, _("The code loaded from %{source_ref} does not create the resource type '%{type_name}' - it is empty") % { source_ref: source_ref, type_name: typed_name.name }
34   end
35 
36   rname = Resource::ResourceTypeImpl._pcore_type.name
37   unless statements.find do |s|
38     if s.is_a?(Model::CallMethodExpression)
39       functor_expr = s.functor_expr
40       functor_expr.is_a?(Model::NamedAccessExpression) &&
41         functor_expr.left_expr.is_a?(Model::QualifiedReference) &&
42         functor_expr.left_expr.cased_value == rname &&
43         functor_expr.right_expr.is_a?(Model::QualifiedName) &&
44         functor_expr.right_expr.value == 'new'
45     else
46       false
47     end
48   end
49     raise ArgumentError, _("The code loaded from %{source_ref} does not create the resource type '%{type_name}' - no call to %{rname}.new found.") % { source_ref: source_ref, type_name: typed_name.name, rname: rname }
50   end
51 
52   unless statements.size == 1
53     raise ArgumentError, _("The code loaded from %{source_ref} must contain only the creation of resource type '%{type_name}' - it has additional logic.") % { source_ref: source_ref, type_name: typed_name.name }
54   end
55 
56   closure_scope = Puppet.lookup(:global_scope) { {} }
57   resource_type_impl = parser.evaluate(closure_scope, model)
58 
59   unless resource_type_impl.is_a?(Puppet::Pops::Resource::ResourceTypeImpl)
60     got = resource_type.class
61     raise ArgumentError, _("The code loaded from %{source_ref} does not define the resource type '%{type_name}' - got '%{got}'.") % { source_ref: source_ref, type_name: typed_name.name, got: got }
62   end
63 
64   unless resource_type_impl.name == typed_name.name
65     expected = typed_name.name
66     actual = resource_type_impl.name
67     raise ArgumentError, _("The code loaded from %{source_ref} produced resource type with the wrong name, expected '%{expected}', actual '%{actual}'") % { source_ref: source_ref, expected: expected, actual: actual }
68   end
69 
70   # Adapt the resource type definition with loader - this is used from logic contained in it body to find the
71   # loader to use when making calls to the new function API. Such logic have a hard time finding the closure (where
72   # the loader is known - hence this mechanism
73   Adapters::LoaderAdapter.adapt(resource_type_impl).loader_name = loader.loader_name
74   resource_type_impl
75 end