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

Private Class Methods

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