class Puppet::Pops::Types::ClassLoader

The ClassLoader provides a Class instance given a class name or a meta-type. If the class is not already loaded, it is loaded using the Puppet Autoloader. This means it can load a class from a gem, or from puppet modules.

Public Class Methods

provide(name) click to toggle source

Returns a Class given a fully qualified class name. Lookup of class is never relative to the calling namespace. @param name [String, Array<String>, Array<Symbol>, PAnyType] A fully qualified

class name String (e.g. '::Foo::Bar', 'Foo::Bar'), a PAnyType, or a fully qualified name in Array form where each part
is either a String or a Symbol, e.g. `%w{Puppetx Puppetlabs SomeExtension}`.

@return [Class, nil] the looked up class or nil if no such class is loaded @raise ArgumentError If the given argument has the wrong type @api public

   # File lib/puppet/pops/types/class_loader.rb
20 def self.provide(name)
21   case name
22   when String
23     provide_from_string(name)
24 
25   when Array
26     provide_from_name_path(name.join('::'), name)
27 
28   when PAnyType, PTypeType
29     provide_from_type(name)
30 
31   else
32     raise ArgumentError, "Cannot provide a class from a '#{name.class.name}'"
33   end
34 end
provide_from_name_path(name, name_path) click to toggle source
   # File lib/puppet/pops/types/class_loader.rb
83 def self.provide_from_name_path(name, name_path)
84   # If class is already loaded, try this first
85   result = find_class(name_path)
86 
87   unless result.is_a?(Module)
88     # Attempt to load it using the auto loader
89     loaded_path = nil
90     if paths_for_name(name_path).find {|path| loaded_path = path; @autoloader.load(path, Puppet.lookup(:current_environment)) }
91       result = find_class(name_path)
92       unless result.is_a?(Module)
93         raise RuntimeError, "Loading of #{name} using relative path: '#{loaded_path}' did not create expected class"
94       end
95     end
96   end
97   return nil unless result.is_a?(Module)
98   result
99 end

Private Class Methods

de_camel(fq_name) click to toggle source
    # File lib/puppet/pops/types/class_loader.rb
122 def self.de_camel(fq_name)
123   fq_name.to_s.gsub(/::/, '/').
124   gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
125   gsub(/([a-z\d])([A-Z])/,'\1_\2').
126   tr("-", "_").
127   downcase
128 end
find_class(name_path) click to toggle source
    # File lib/puppet/pops/types/class_loader.rb
102 def self.find_class(name_path)
103   name_path.reduce(Object) do |ns, name|
104     begin
105       ns.const_get(name, false) # don't search ancestors
106     rescue NameError
107       return nil
108     end
109   end
110 end
paths_for_name(fq_named_parts) click to toggle source
    # File lib/puppet/pops/types/class_loader.rb
113 def self.paths_for_name(fq_named_parts)
114   # search two entries, one where all parts are decamelized, and one with names just downcased
115   # TODO:this is not perfect - it will not produce the correct mix if a mix of styles are used
116   # The alternative is to test many additional paths.
117   #
118   [fq_named_parts.map {|part| de_camel(part)}.join('/'), fq_named_parts.join('/').downcase ]
119 end
provide_from_string(name) click to toggle source
   # File lib/puppet/pops/types/class_loader.rb
76 def self.provide_from_string(name)
77   name_path = name.split(TypeFormatter::NAME_SEGMENT_SEPARATOR)
78   # always from the root, so remove an empty first segment
79   name_path.shift if name_path[0].empty?
80   provide_from_name_path(name, name_path)
81 end
provide_from_type(type) click to toggle source
   # File lib/puppet/pops/types/class_loader.rb
36 def self.provide_from_type(type)
37   case type
38   when PRuntimeType
39     raise ArgumentError.new("Only Runtime type 'ruby' is supported, got #{type.runtime}") unless type.runtime == :ruby
40     provide_from_string(type.runtime_type_name)
41 
42   when PBooleanType
43     # There is no other thing to load except this Enum meta type
44     RGen::MetamodelBuilder::MMBase::Boolean
45 
46   when PTypeType
47     # TODO: PTypeType should have a type argument (a PAnyType) so the Class' class could be returned
48     #       (but this only matters in special circumstances when meta programming has been used).
49     Class
50 
51   when POptionalType
52     # cannot make a distinction between optional and its type
53     provide_from_type(type.optional_type)
54 
55   # Although not expected to be the first choice for getting a concrete class for these
56   # types, these are of value if the calling logic just has a reference to type.
57   #
58   when PArrayType    ; Array
59   when PTupleType    ; Array
60   when PHashType     ; Hash
61   when PStructType   ; Hash
62   when PRegexpType   ; Regexp
63   when PIntegerType  ; Integer
64   when PStringType   ; String
65   when PPatternType  ; String
66   when PEnumType     ; String
67   when PFloatType    ; Float
68   when PUndefType    ; NilClass
69   when PCallableType ; Proc
70   else
71     nil
72   end
73 end