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