Class: Puppet::Pops::Loader::ModuleLoaders::AbstractPathBasedModuleLoader Private

Inherits:
BaseLoader show all
Defined in:
lib/puppet/pops/loader/module_loaders.rb

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Direct Known Subclasses

FileBased

Constant Summary

Constants inherited from Loader

Loader::LOADABLE_KINDS

Instance Attribute Summary collapse

Attributes inherited from BaseLoader

#parent

Attributes inherited from Loader

#loader_name

Instance Method Summary collapse

Methods inherited from BaseLoader

#add_entry, #get_entry, #load_typed, #loaded_entry, #promote_entry, #remove_entry, #set_entry

Methods inherited from Loader

#[], #get_entry, #inspect, #load, #load_typed, #loaded_entry, #parent, #set_entry, #to_s

Constructor Details

#initialize(parent_loader, loaders, module_name, path, loader_name, loadables) ⇒ AbstractPathBasedModuleLoader

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize a kind of ModuleLoader for one module

Parameters:

  • parent_loader (Loader)

    loader with higher priority

  • loaders (Loaders)

    the container for this loader

  • module_name (String)

    the name of the module (non qualified name), may be nil for a global “component”

  • path (String)

    the path to the root of the module (semantics defined by subclass)

  • loader_name (String)

    a name that is used for human identification (useful when module_name is nil)



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/puppet/pops/loader/module_loaders.rb', line 92

def initialize(parent_loader, loaders, module_name, path, loader_name, loadables)
  super parent_loader, loader_name

  @module_name = module_name
  @path = path
  @smart_paths = LoaderPaths::SmartPaths.new(self)
  @loaders = loaders
  @loadables = loadables
  unless (loadables - LOADABLE_KINDS).empty?
    raise ArgumentError, 'given loadables are not of supported loadable kind'
  end
  loaders.add_loader_by_name(self)
end

Instance Attribute Details

#module_nameObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The name of the module, or nil, if this is a global “component”



70
71
72
# File 'lib/puppet/pops/loader/module_loaders.rb', line 70

def module_name
  @module_name
end

#pathObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The path to the location of the module/component - semantics determined by subclass



73
74
75
# File 'lib/puppet/pops/loader/module_loaders.rb', line 73

def path
  @path
end

#private_loaderObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Produces the private loader for the module. If this module is not already resolved, this will trigger resolution



83
84
85
# File 'lib/puppet/pops/loader/module_loaders.rb', line 83

def private_loader
  @private_loader
end

#smart_pathsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

A map of type to smart-paths that help with minimizing the number of paths to scan



76
77
78
# File 'lib/puppet/pops/loader/module_loaders.rb', line 76

def smart_paths
  @smart_paths
end

Instance Method Details

#existing_path(resolved_path) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Abstract method that subclasses override to answer if the given relative path exists, and if so returns that path

Parameters:

  • resolved_path (String)

    a path resolved by a smart path against the loader’s root (if it has one)

Returns:

  • (Boolean)

    true if the file exists

Raises:

  • (NotImplementedError)


212
213
214
# File 'lib/puppet/pops/loader/module_loaders.rb', line 212

def existing_path(resolved_path)
  raise NotImplementedError.new
end

#find(typed_name) ⇒ Loader::NamedEntry, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Finds typed/named entity in this module

Parameters:

  • typed_name (TypedName)

    the type/name to find

Returns:

  • (Loader::NamedEntry, nil found/created entry, or nil if not found)

    Loader::NamedEntry, nil found/created entry, or nil if not found



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/puppet/pops/loader/module_loaders.rb', line 114

def find(typed_name)
  # This loader is tailored to only find entries in the current runtime
  return nil unless typed_name.name_authority == Pcore::RUNTIME_NAME_AUTHORITY

  # Assume it is a global name, and that all parts of the name should be used when looking up
  name_parts = typed_name.name_parts

  # Certain types and names can be disqualified up front
  if name_parts.size > 1
    # The name is in a name space.

    # Then entity cannot possible be in this module unless the name starts with the module name.
    # Note: If "module" represents a "global component", the module_name is nil and cannot match which is
    # ok since such a "module" cannot have namespaced content).
    #
    return nil unless name_parts[0] == module_name
  else
    # The name is in the global name space.

    # The only globally name-spaced elements that may be loaded from modules are functions and resource types
    case typed_name.type
    when :function
    when :resource_type
    when :resource_type_pp
    when :type
      if !global?
        # Global name can only be the module typeset
        return nil unless name_parts[0] == module_name

        origin, smart_path = find_existing_path(init_typeset_name)
        return nil unless smart_path

        value = smart_path.instantiator.create(self, typed_name, origin, get_contents(origin))
        if value.is_a?(Types::PTypeSetType)
          # cache the entry and return it
          return set_entry(typed_name, value, origin)
        end

        raise ArgumentError,"The code loaded from #{origin} does not define the TypeSet '#{module_name.capitalize}'"
      end
    else
      # anything else cannot possibly be in this module
      # TODO: should not be allowed anyway... may have to revisit this decision
      return nil
    end
  end

  # Get the paths that actually exist in this module (they are lazily processed once and cached).
  # The result is an array (that may be empty).
  # Find the file to instantiate, and instantiate the entity if file is found
  origin, smart_path = find_existing_path(typed_name)
  if smart_path
    value = smart_path.instantiator.create(self, typed_name, origin, get_contents(origin))
    # cache the entry and return it
    return set_entry(typed_name, value, origin)
  end

  return nil unless typed_name.type == :type && typed_name.qualified?

  # Search for TypeSet using parent name
  ts_name = typed_name.parent
  while ts_name
    # Do not traverse parents here. This search must be confined to this loader
    tse = get_entry(ts_name)
    tse = find(ts_name) if tse.nil? || tse.value.nil?
    if tse && (ts = tse.value).is_a?(Types::PTypeSetType)
      # The TypeSet might be unresolved at this point. If so, it must be resolved using
      # this loader. That in turn, adds all contained types to this loader.
      ts.resolve(self)
      te = get_entry(typed_name)
      return te unless te.nil?
    end
    ts_name = ts_name.parent
  end
  nil
end

#get_contents(effective_path) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Abstract method that subclasses override to produce the content of the effective path. It should either succeed and return a String or fail with an exception.

Parameters:

  • effective_path (String)

    a path as resolved by a smart path

Returns:

  • (String)

    the content of the file

Raises:

  • (NotImplementedError)


222
223
224
# File 'lib/puppet/pops/loader/module_loaders.rb', line 222

def get_contents(effective_path)
  raise NotImplementedError.new
end

#get_source_ref(relative_path) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Abstract method that subclasses override to produce a source reference String used to identify the system resource (resource in the URI sense).

Parameters:

  • relative_path (String)

    a path relative to the module’s root

Returns:

  • (String)

    a reference to the source file (in file system, zip file, or elsewhere).

Raises:

  • (NotImplementedError)


232
233
234
# File 'lib/puppet/pops/loader/module_loaders.rb', line 232

def get_source_ref(relative_path)
  raise NotImplementedError.new
end

#global?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Answers the question if this loader represents a global component (true for resource type loader and environment loader)

Returns:

  • (Boolean)

    ‘true` if this loader represents a global component



240
241
242
# File 'lib/puppet/pops/loader/module_loaders.rb', line 240

def global?
  module_name.nil? || module_name == ENVIRONMENT
end

#loadablesObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



106
107
108
# File 'lib/puppet/pops/loader/module_loaders.rb', line 106

def loadables
  @loadables
end

#meaningful_to_search?(smart_path) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Abstract method that subclasses override that checks if it is meaningful to search using a generic smart path. This optimization is performed to not be tricked into searching an empty directory over and over again. The implementation may perform a deep search for file content other than directories and cache this in and index. It is guaranteed that a call to meaningful_to_search? takes place before checking any other path with relative_path_exists?.

This optimization exists because many modules have been created from a template and they have empty directories for functions, types, etc. (It is also the place to create a cached index of the content).

Parameters:

  • smart_path (String)

    a path relative to the module’s root

Returns:

  • (Boolean)

    true if there is content in the directory appointed by the relative path

Raises:

  • (NotImplementedError)


203
204
205
# File 'lib/puppet/pops/loader/module_loaders.rb', line 203

def meaningful_to_search?(smart_path)
  raise NotImplementedError.new
end