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