lib/pdk/generate/puppet_object.rb in pdk-2.3.0 vs lib/pdk/generate/puppet_object.rb in pdk-2.4.0
- old
+ new
@@ -1,232 +1,232 @@
-require 'pdk'
-
-module PDK
- module Generate
- class PuppetObject
- attr_reader :context
- attr_reader :object_name
- attr_reader :options
-
- # Initialises the PDK::Generate::PuppetObject object.
- #
- # In general, this object should never be instantiated directly. Instead,
- # one of the subclasses should be used e.g. PDK::Generate::Klass.
- #
- # New subclasses generally only need to inherit this class, set the
- # OBJECT_TYPE constant and implement the {#template_data},
- # {#target_object_path} and {#target_spec_path} methods.
- #
- # @param module_dir [String] The path to the root of module that the
- # will contain the object.
- # @param object_name [String] The name of the object.
- # @param options [Hash{Symbol => Object}]
- def initialize(context, object_name, options)
- raise ArgumentError, _('Expected PDK::Context::AbstractContext but got \'%{klass}\' for context') % { klass: context.class } unless context.is_a?(PDK::Context::AbstractContext)
- @context = context
- @options = options
- @object_name = object_name
- end
-
- # Whether the generator should only return test (spec) files
- # @return [Boolean]
- def spec_only?
- @options[:spec_only]
- end
-
- # Subclass and implement {#friendly_name} to provide a nice name to show users in CLI
- # @abstract
- # @return String
- def friendly_name
- raise NotImplementedError
- end
-
- # Subclass and implement {#template_files} to provide the template files to
- # render. Implementations of this method should return a Hash!{String => String}.
- # @abstract
- # @return Hash{String => String} Hash key is the source template file and the Hash value is
- # the relative destination path
- def template_files
- raise NotImplementedError
- end
-
- # Subclass and implement {#template_data} to provide data to the templates during rendering.
- # @abstract
- # @return Hash{Symbol => Object}
- def template_data
- raise NotImplementedError
- end
-
- # Raises an error if any pre-conditions are not met
- #
- # @return [void]
- # @abstract
- def check_preconditions
- raise ArgumentError, _('Expected a module context but got %{context_name}') % { context_name: context.display_name } unless context.is_a?(PDK::Context::Module)
- end
-
- # Check the preconditions of this template group, behaving as a predicate rather than raising an exception.
- #
- # @return [Boolean] true if the generator is safe to run, otherwise false.
- def can_run?
- check_preconditions
- true
- rescue StandardError
- false
- end
-
- # Creates an instance of an update manager
- # @api private
- def update_manager_instance
- require 'pdk/module/update_manager'
- PDK::Module::UpdateManager.new
- end
-
- # Stages and then executes the changes for the templates to be rendereed.
- # This is the main entry point for the class.
- #
- # @see #stage_changes
- # @return [PDK::Module::UpdateManager] The update manager which implemented the changes
- # @api public
- def run(update_manager = update_manager_instance)
- stage_changes(update_manager).sync_changes!
- update_manager
- end
-
- # Check that the templates can be rendered. Find an appropriate template
- # and stages the target files from the template. This is the main entry
- # point for the class.
- #
- # @raise [PDK::CLI::ExitWithError] if the target files already exist.
- # @raise [PDK::CLI::FatalError] (see #render_file)
- # @return [PDK::Module::UpdateManager] The update manager with the staged changes
- # @api public
- def stage_changes(update_manager)
- check_preconditions
-
- with_templates do |template_dir|
- template_files.each do |source_file, relative_dest_path|
- new_content = template_dir.render_single_item(source_file, template_data)
- next if new_content.nil?
-
- stage_change(relative_dest_path, new_content, update_manager)
- end
- end
- non_template_files.each { |relative_dest_path, content| stage_change(relative_dest_path, content, update_manager) }
-
- update_manager
- end
-
- # Stages a single file into the Update Manager.
- # @return [void]
- # @api private
- def stage_change(relative_dest_path, content, update_manager)
- absolute_file_path = File.join(context.root_path, relative_dest_path)
- if PDK::Util::Filesystem.exist?(absolute_file_path)
- raise PDK::CLI::ExitWithError, _("Unable to generate %{object_type}; '%{file}' already exists.") % {
- file: absolute_file_path,
- object_type: spec_only? ? 'unit test' : friendly_name,
- }
- end
- update_manager.add_file(absolute_file_path, content)
- end
-
- # A subclass may wish to stage files into the Update Manager, but the content is not templated. Subclasses
- # can override this method to stage arbitrary files
- #
- # @api private
- # @return [Hash{String => String}] A Hash with the relative file path as the key and the new file content as the value.
- # @abstract
- def non_template_files
- {}
- end
-
- # Search the possible template directories in order of preference to find
- # a template that can be used to render a new object of the specified
- # type.
- #
- # @yieldparam template_paths [Hash{Symbol => String}] :object contains
- # the path on disk to the template file for the object, :spec contains
- # the path on disk to the template file for the tests for the object
- # (if it exists).
- # @yieldparam config_hash [Hash{Object => Object}] the contents of the
- # :global key in the config_defaults.yml file.
- #
- # @raise [PDK::CLI::FatalError] if no suitable template could be found.
- #
- # @api private
- def with_templates
- require 'pdk/logger'
- require 'pdk/util/template_uri'
-
- templates.each do |template|
- if template[:uri].nil?
- PDK.logger.debug(_('No %{dir_type} template found; trying next template directory.') % { dir_type: template[:type] })
- next
- end
-
- PDK::Template.with(PDK::Util::TemplateURI.new(template[:uri]), context) do |template_dir|
- if template_files.any? { |source_file, _| template_dir.has_single_item?(source_file) }
- yield template_dir
- # TODO: refactor to a search-and-execute form instead
- return # work is done # rubocop:disable Lint/NonLocalExitFromIterator
- elsif template[:allow_fallback]
- PDK.logger.debug(_('Unable to find a %{type} template in %{url}; trying next template directory.') % { type: friendly_name, url: template[:uri] })
- else
- raise PDK::CLI::FatalError, _('Unable to find the %{type} template in %{url}.') % { type: friendly_name, url: template[:uri] }
- end
- end
- end
- rescue ArgumentError => e
- raise PDK::CLI::ExitWithError, e
- end
-
- # Provides the possible template directory locations in the order in
- # which they should be searched for a valid template.
- #
- # If a template-url has been specified on in the options hash (e.g. from
- # a CLI parameter), then this template directory will be checked first
- # and we do not fall back to the next possible template directory.
- #
- # If we have not been provided a specific template directory to use, we
- # try the template specified in the module metadata (as set during
- # PDK::Generate::Module) and fall back to the default template if
- # necessary.
- #
- # @return [Array<Hash{Symbol => Object}>] an array of hashes. Each hash
- # contains 3 keys: :type contains a String that describes the template
- # directory, :url contains a String with the URL to the template
- # directory, and :allow_fallback contains a Boolean that specifies if
- # the lookup process should proceed to the next template directory if
- # the template file is not in this template directory.
- #
- # @api private
- def templates
- require 'pdk/util/template_uri'
-
- @templates ||= PDK::Util::TemplateURI.templates(@options)
- end
-
- # Retrieves the name of the module (without the forge username) from the
- # module metadata.
- #
- # @return [String] The name of the module.
- #
- # @api private
- def module_name
- return nil unless context.is_a?(PDK::Context::Module)
-
- require 'pdk/util'
- @module_name ||= PDK::Util.module_metadata(context.root_path)['name'].rpartition('-').last
- rescue ArgumentError => e
- raise PDK::CLI::FatalError, e
- end
-
- private
-
- # Transform an object name into a ruby class name
- def class_name_from_object_name(object_name)
- object_name.to_s.split('_').map(&:capitalize).join
- end
- end
- end
-end
+require 'pdk'
+
+module PDK
+ module Generate
+ class PuppetObject
+ attr_reader :context
+ attr_reader :object_name
+ attr_reader :options
+
+ # Initialises the PDK::Generate::PuppetObject object.
+ #
+ # In general, this object should never be instantiated directly. Instead,
+ # one of the subclasses should be used e.g. PDK::Generate::Klass.
+ #
+ # New subclasses generally only need to inherit this class, set the
+ # OBJECT_TYPE constant and implement the {#template_data},
+ # {#target_object_path} and {#target_spec_path} methods.
+ #
+ # @param module_dir [String] The path to the root of module that the
+ # will contain the object.
+ # @param object_name [String] The name of the object.
+ # @param options [Hash{Symbol => Object}]
+ def initialize(context, object_name, options)
+ raise ArgumentError, _('Expected PDK::Context::AbstractContext but got \'%{klass}\' for context') % { klass: context.class } unless context.is_a?(PDK::Context::AbstractContext)
+ @context = context
+ @options = options
+ @object_name = object_name
+ end
+
+ # Whether the generator should only return test (spec) files
+ # @return [Boolean]
+ def spec_only?
+ @options[:spec_only]
+ end
+
+ # Subclass and implement {#friendly_name} to provide a nice name to show users in CLI
+ # @abstract
+ # @return String
+ def friendly_name
+ raise NotImplementedError
+ end
+
+ # Subclass and implement {#template_files} to provide the template files to
+ # render. Implementations of this method should return a Hash!{String => String}.
+ # @abstract
+ # @return Hash{String => String} Hash key is the source template file and the Hash value is
+ # the relative destination path
+ def template_files
+ raise NotImplementedError
+ end
+
+ # Subclass and implement {#template_data} to provide data to the templates during rendering.
+ # @abstract
+ # @return Hash{Symbol => Object}
+ def template_data
+ raise NotImplementedError
+ end
+
+ # Raises an error if any pre-conditions are not met
+ #
+ # @return [void]
+ # @abstract
+ def check_preconditions
+ raise ArgumentError, _('Expected a module context but got %{context_name}') % { context_name: context.display_name } unless context.is_a?(PDK::Context::Module)
+ end
+
+ # Check the preconditions of this template group, behaving as a predicate rather than raising an exception.
+ #
+ # @return [Boolean] true if the generator is safe to run, otherwise false.
+ def can_run?
+ check_preconditions
+ true
+ rescue StandardError
+ false
+ end
+
+ # Creates an instance of an update manager
+ # @api private
+ def update_manager_instance
+ require 'pdk/module/update_manager'
+ PDK::Module::UpdateManager.new
+ end
+
+ # Stages and then executes the changes for the templates to be rendereed.
+ # This is the main entry point for the class.
+ #
+ # @see #stage_changes
+ # @return [PDK::Module::UpdateManager] The update manager which implemented the changes
+ # @api public
+ def run(update_manager = update_manager_instance)
+ stage_changes(update_manager).sync_changes!
+ update_manager
+ end
+
+ # Check that the templates can be rendered. Find an appropriate template
+ # and stages the target files from the template. This is the main entry
+ # point for the class.
+ #
+ # @raise [PDK::CLI::ExitWithError] if the target files already exist.
+ # @raise [PDK::CLI::FatalError] (see #render_file)
+ # @return [PDK::Module::UpdateManager] The update manager with the staged changes
+ # @api public
+ def stage_changes(update_manager)
+ check_preconditions
+
+ with_templates do |template_dir|
+ template_files.each do |source_file, relative_dest_path|
+ new_content = template_dir.render_single_item(source_file, template_data)
+ next if new_content.nil?
+
+ stage_change(relative_dest_path, new_content, update_manager)
+ end
+ end
+ non_template_files.each { |relative_dest_path, content| stage_change(relative_dest_path, content, update_manager) }
+
+ update_manager
+ end
+
+ # Stages a single file into the Update Manager.
+ # @return [void]
+ # @api private
+ def stage_change(relative_dest_path, content, update_manager)
+ absolute_file_path = File.join(context.root_path, relative_dest_path)
+ if PDK::Util::Filesystem.exist?(absolute_file_path)
+ raise PDK::CLI::ExitWithError, _("Unable to generate %{object_type}; '%{file}' already exists.") % {
+ file: absolute_file_path,
+ object_type: spec_only? ? 'unit test' : friendly_name,
+ }
+ end
+ update_manager.add_file(absolute_file_path, content)
+ end
+
+ # A subclass may wish to stage files into the Update Manager, but the content is not templated. Subclasses
+ # can override this method to stage arbitrary files
+ #
+ # @api private
+ # @return [Hash{String => String}] A Hash with the relative file path as the key and the new file content as the value.
+ # @abstract
+ def non_template_files
+ {}
+ end
+
+ # Search the possible template directories in order of preference to find
+ # a template that can be used to render a new object of the specified
+ # type.
+ #
+ # @yieldparam template_paths [Hash{Symbol => String}] :object contains
+ # the path on disk to the template file for the object, :spec contains
+ # the path on disk to the template file for the tests for the object
+ # (if it exists).
+ # @yieldparam config_hash [Hash{Object => Object}] the contents of the
+ # :global key in the config_defaults.yml file.
+ #
+ # @raise [PDK::CLI::FatalError] if no suitable template could be found.
+ #
+ # @api private
+ def with_templates
+ require 'pdk/logger'
+ require 'pdk/util/template_uri'
+
+ templates.each do |template|
+ if template[:uri].nil?
+ PDK.logger.debug(_('No %{dir_type} template found; trying next template directory.') % { dir_type: template[:type] })
+ next
+ end
+
+ PDK::Template.with(PDK::Util::TemplateURI.new(template[:uri]), context) do |template_dir|
+ if template_files.any? { |source_file, _| template_dir.has_single_item?(source_file) }
+ yield template_dir
+ # TODO: refactor to a search-and-execute form instead
+ return # work is done # rubocop:disable Lint/NonLocalExitFromIterator
+ elsif template[:allow_fallback]
+ PDK.logger.debug(_('Unable to find a %{type} template in %{url}; trying next template directory.') % { type: friendly_name, url: template[:uri] })
+ else
+ raise PDK::CLI::FatalError, _('Unable to find the %{type} template in %{url}.') % { type: friendly_name, url: template[:uri] }
+ end
+ end
+ end
+ rescue ArgumentError => e
+ raise PDK::CLI::ExitWithError, e
+ end
+
+ # Provides the possible template directory locations in the order in
+ # which they should be searched for a valid template.
+ #
+ # If a template-url has been specified on in the options hash (e.g. from
+ # a CLI parameter), then this template directory will be checked first
+ # and we do not fall back to the next possible template directory.
+ #
+ # If we have not been provided a specific template directory to use, we
+ # try the template specified in the module metadata (as set during
+ # PDK::Generate::Module) and fall back to the default template if
+ # necessary.
+ #
+ # @return [Array<Hash{Symbol => Object}>] an array of hashes. Each hash
+ # contains 3 keys: :type contains a String that describes the template
+ # directory, :url contains a String with the URL to the template
+ # directory, and :allow_fallback contains a Boolean that specifies if
+ # the lookup process should proceed to the next template directory if
+ # the template file is not in this template directory.
+ #
+ # @api private
+ def templates
+ require 'pdk/util/template_uri'
+
+ @templates ||= PDK::Util::TemplateURI.templates(@options)
+ end
+
+ # Retrieves the name of the module (without the forge username) from the
+ # module metadata.
+ #
+ # @return [String] The name of the module.
+ #
+ # @api private
+ def module_name
+ return nil unless context.is_a?(PDK::Context::Module)
+
+ require 'pdk/util'
+ @module_name ||= PDK::Util.module_metadata(context.root_path)['name'].rpartition('-').last
+ rescue ArgumentError => e
+ raise PDK::CLI::FatalError, e
+ end
+
+ private
+
+ # Transform an object name into a ruby class name
+ def class_name_from_object_name(object_name)
+ object_name.to_s.split('_').map(&:capitalize).join
+ end
+ end
+ end
+end