mirror of
https://github.com/inspec/inspec
synced 2024-11-22 12:43:07 +00:00
Plugins Installer API (#3352)
* Sketch out in comments the unit and functional tests for the installer * Make a test fixture gem, v0.1.0 * Add a 0.2.0 version of the test fixture gem, this one with a dependency * Add a fixture with a pre-installed gem * Correct test-fixture 0.1.0 gem * Moockup of installed inspec-test-fixture gems * Uggh add gemspec files to mock installs * Update gem fixtures, and add a script that does it for me * Able to load from and list privately managed gems # Conflicts: # lib/inspec/plugin/v2/loader.rb * Expanded tests, starting on implementation of installer # Conflicts: # test/unit/plugin/v2/loader_test.rb * Install plugin from local gem file works * Writes the plugins.json file; needs refactor * Gem install works; no version pinning * Install with pinned version works * Install from path works * update works * Validation for uninstall * Uninstall from path works * Uninstaller works on gems * Add search to installer API. Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
This commit is contained in:
parent
1ba3174cbd
commit
7963131670
78 changed files with 2581 additions and 62 deletions
|
@ -6,13 +6,24 @@ module Inspec
|
|||
class Exception < Inspec::Error; end
|
||||
class ConfigError < Inspec::Plugin::V2::Exception; end
|
||||
class LoadError < Inspec::Plugin::V2::Exception; end
|
||||
class GemActionError < Inspec::Plugin::V2::Exception
|
||||
attr_accessor :plugin_name
|
||||
attr_accessor :version
|
||||
end
|
||||
class InstallError < Inspec::Plugin::V2::GemActionError; end
|
||||
class UpdateError < Inspec::Plugin::V2::GemActionError
|
||||
attr_accessor :from_version, :to_version
|
||||
end
|
||||
class UnInstallError < Inspec::Plugin::V2::GemActionError; end
|
||||
class SearchError < Inspec::Plugin::V2::GemActionError; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require_relative 'v2/registry'
|
||||
require_relative 'v2/loader'
|
||||
require_relative 'v2/plugin_base'
|
||||
require 'inspec/globals'
|
||||
require 'inspec/plugin/v2/registry'
|
||||
require 'inspec/plugin/v2/loader'
|
||||
require 'inspec/plugin/v2/plugin_base'
|
||||
|
||||
# Load all plugin type base classes
|
||||
Dir.glob(File.join(__dir__, 'v2', 'plugin_types', '*.rb')).each { |file| require file }
|
||||
|
|
|
@ -3,14 +3,19 @@ module Inspec::Plugin::V2
|
|||
:plugin_name,
|
||||
:plugin_type,
|
||||
:activator_name,
|
||||
:activated,
|
||||
:'activated?',
|
||||
:exception,
|
||||
:activation_proc,
|
||||
:implementation_class,
|
||||
) do
|
||||
def initialize(*)
|
||||
super
|
||||
self[:activated] = false
|
||||
self[:'activated?'] = false
|
||||
end
|
||||
|
||||
def activated?(new_value = nil)
|
||||
return self[:'activated?'] if new_value.nil?
|
||||
self[:'activated?'] = new_value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
406
lib/inspec/plugin/v2/installer.rb
Normal file
406
lib/inspec/plugin/v2/installer.rb
Normal file
|
@ -0,0 +1,406 @@
|
|||
# This file is not required by default.
|
||||
|
||||
require 'singleton'
|
||||
require 'forwardable'
|
||||
|
||||
# Gem extensions for doing unusual things - not loaded by Gem default
|
||||
require 'rubygems/package'
|
||||
require 'rubygems/name_tuple'
|
||||
require 'rubygems/uninstaller'
|
||||
|
||||
module Inspec::Plugin::V2
|
||||
# Handles all actions modifying the user's plugin set:
|
||||
# * Modifying the plugins.json file
|
||||
# * Installing, updating, and removing gem-based plugins
|
||||
# Loading plugins is handled by Loader.
|
||||
# Listing plugins is handled by Loader.
|
||||
# Searching for plugins is handled by ???
|
||||
class Installer
|
||||
include Singleton
|
||||
extend Forwardable
|
||||
|
||||
Gem.configuration['verbose'] = false
|
||||
|
||||
attr_reader :loader, :registry
|
||||
def_delegator :loader, :plugin_gem_path, :gem_path
|
||||
def_delegator :loader, :plugin_conf_file_path
|
||||
def_delegator :loader, :list_managed_gems
|
||||
def_delegator :loader, :list_installed_plugin_gems
|
||||
|
||||
def initialize
|
||||
@loader = Inspec::Plugin::V2::Loader.new
|
||||
@registry = Inspec::Plugin::V2::Registry.instance
|
||||
end
|
||||
|
||||
def plugin_installed?(name)
|
||||
list_installed_plugin_gems.detect { |spec| spec.name == name }
|
||||
end
|
||||
|
||||
def plugin_version_installed?(name, version)
|
||||
list_installed_plugin_gems.detect { |spec| spec.name == name && spec.version == Gem::Version.new(version) }
|
||||
end
|
||||
|
||||
# Installs a plugin. Defaults to assuming the plugin provided is a gem, and will try to install
|
||||
# from whatever gemsources `rubygems` thinks it should use.
|
||||
# If it's a gem, installs it and its dependencies to the `gem_path`. The gem is not activated.
|
||||
# If it's a path, leaves it in place.
|
||||
# Finally, updates the plugins.json file with the new information.
|
||||
# No attempt is made to load the plugin.
|
||||
#
|
||||
# @param [String] plugin_name
|
||||
# @param [Hash] opts The installation options
|
||||
# @option opts [String] :gem_file Path to a local gem file to install from
|
||||
# @option opts [String] :path Path to a file to be used as the entry point for a path-based plugin
|
||||
# @option opts [String] :version Version constraint for remote gem installs
|
||||
def install(plugin_name, opts = {})
|
||||
# TODO: - check plugins.json for validity before trying anything that needs to modify it.
|
||||
validate_installation_opts(plugin_name, opts)
|
||||
|
||||
if opts[:path]
|
||||
install_from_path(plugin_name, opts)
|
||||
elsif opts[:gem_file]
|
||||
install_from_gem_file(plugin_name, opts)
|
||||
else
|
||||
install_from_remote_gems(plugin_name, opts)
|
||||
end
|
||||
|
||||
update_plugin_config_file(plugin_name, opts.merge({ action: :install }))
|
||||
end
|
||||
|
||||
# Updates a plugin. Most options same as install, but will not handle path installs.
|
||||
# If no :version is provided, updates to the latest.
|
||||
# If a version is provided, the plugin becomes pinned at that specified version.
|
||||
#
|
||||
# @param [String] plugin_name
|
||||
# @param [Hash] opts The installation options
|
||||
# @option opts [String] :gem_file Reserved for future use. No effect.
|
||||
# @option opts [String] :version Version constraint for remote gem updates
|
||||
def update(plugin_name, opts = {})
|
||||
# TODO: - check plugins.json for validity before trying anything that needs to modify it.
|
||||
validate_update_opts(plugin_name, opts)
|
||||
opts[:update_mode] = true
|
||||
|
||||
# TODO: Handle installing from a local file
|
||||
# TODO: Perform dependency checks to make sure the new solution is valid
|
||||
install_from_remote_gems(plugin_name, opts)
|
||||
|
||||
update_plugin_config_file(plugin_name, opts.merge({ action: :update }))
|
||||
end
|
||||
|
||||
# Uninstalls (removes) a plugin. Refers to plugin.json to determine if it
|
||||
# was a gem-based or path-based install.
|
||||
# If it's a gem, uninstalls it, and all other unused plugins.
|
||||
# If it's a path, removes the reference from the plugins.json, but does not
|
||||
# tamper with the plugin source tree.
|
||||
# Either way, the plugins.json file is updated with the new information.
|
||||
#
|
||||
# @param [String] plugin_name
|
||||
# @param [Hash] opts The uninstallation options. Currently unused.
|
||||
def uninstall(plugin_name, opts = {})
|
||||
# TODO: - check plugins.json for validity before trying anything that needs to modify it.
|
||||
validate_uninstall_opts(plugin_name, opts)
|
||||
|
||||
if registry.path_based_plugin?(plugin_name)
|
||||
uninstall_via_path(plugin_name, opts)
|
||||
else
|
||||
uninstall_via_gem(plugin_name, opts)
|
||||
end
|
||||
|
||||
update_plugin_config_file(plugin_name, opts.merge({ action: :uninstall }))
|
||||
end
|
||||
|
||||
# Search rubygems.org for a plugin gem.
|
||||
#
|
||||
# @param [String] plugin_seach_term
|
||||
# @param [Hash] opts Search options
|
||||
# @option opts [TrueClass, FalseClass] :exact If true, use plugin_search_term exactly. If false (default), append a wildcard.
|
||||
# @return [Hash of Arrays] - Keys are String names of gems, arrays contain String versions.
|
||||
def search(plugin_query, opts = {})
|
||||
validate_search_opts(plugin_query, opts)
|
||||
|
||||
fetcher = Gem::SpecFetcher.fetcher
|
||||
matched_tuples = []
|
||||
if opts[:exact]
|
||||
matched_tuples = fetcher.detect(:released) { |tuple| tuple.name == plugin_query }
|
||||
else
|
||||
regex = Regexp.new('^' + plugin_query + '.*')
|
||||
matched_tuples = fetcher.detect(:released) do |tuple|
|
||||
tuple.name != 'inspec-core' && tuple.name =~ regex
|
||||
end
|
||||
end
|
||||
|
||||
gem_info = {}
|
||||
matched_tuples.each do |tuple|
|
||||
gem_info[tuple.first.name] ||= []
|
||||
gem_info[tuple.first.name] << tuple.first.version.to_s
|
||||
end
|
||||
gem_info
|
||||
end
|
||||
|
||||
# Testing API. Performs a hard reset on the installer and registry, and reloads the loader.
|
||||
# Not for public use.
|
||||
# TODO: bad timing coupling in tests
|
||||
def __reset
|
||||
registry.__reset
|
||||
end
|
||||
|
||||
def __reset_loader
|
||||
@loader = Loader.new
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
#===================================================================#
|
||||
# Validation Methods #
|
||||
#===================================================================#
|
||||
|
||||
# rubocop: disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
|
||||
# rationale for rubocop exemption: While there are many conditionals, they are all of the same form;
|
||||
# its goal is to check for several subtle combinations of params, and raise an error if needed. It's
|
||||
# straightforward to understand, but has to handle many cases.
|
||||
def validate_installation_opts(plugin_name, opts)
|
||||
unless plugin_name =~ /^(inspec|train)-/
|
||||
raise InstallError, "All inspec plugins must begin with either 'inspec-' or 'train-' - refusing to install #{plugin_name}"
|
||||
end
|
||||
|
||||
if opts.key?(:gem_file) && opts.key?(:path)
|
||||
raise InstallError, 'May not specify both gem_file and a path (for installing from source)'
|
||||
end
|
||||
|
||||
if opts.key?(:version) && (opts.key?(:gem_file) || opts.key?(:path))
|
||||
raise InstallError, 'May not specify a version when installing from a gem file or source path'
|
||||
end
|
||||
|
||||
if opts.key?(:gem_file)
|
||||
unless opts[:gem_file].end_with?('.gem')
|
||||
raise InstallError, "When installing from a local gem file, gem file must have '.gem' extension - saw #{opts[:gem_file]}"
|
||||
end
|
||||
unless File.exist?(opts[:gem_file])
|
||||
raise InstallError, "Could not find local gem file to install - #{opts[:gem_file]}"
|
||||
end
|
||||
elsif opts.key?(:path)
|
||||
unless Dir.exist?(opts[:path])
|
||||
raise InstallError, "Could not find directory for install from source path - #{opts[:path]}"
|
||||
end
|
||||
end
|
||||
|
||||
if plugin_installed?(plugin_name)
|
||||
if opts.key?(:version) && plugin_version_installed?(plugin_name, opts[:version])
|
||||
raise InstallError, "#{plugin_name} version #{opts[:version]} is already installed."
|
||||
else
|
||||
raise InstallError, "#{plugin_name} is already installed. Use 'inspec plugin update' to change version."
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop: enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
|
||||
|
||||
def validate_update_opts(plugin_name, opts)
|
||||
# Only update plugins we know about
|
||||
unless plugin_name =~ /^(inspec|train)-/
|
||||
raise UpdateError, "All inspec plugins must begin with either 'inspec-' or 'train-' - refusing to update #{plugin_name}"
|
||||
end
|
||||
unless registry.known_plugin?(plugin_name.to_sym)
|
||||
raise UpdateError, "'#{plugin_name}' is not installed - use 'inspec plugin install' to install it"
|
||||
end
|
||||
|
||||
# No local path support for update
|
||||
if registry[plugin_name.to_sym].installation_type == :path
|
||||
raise UpdateError, "'inspec plugin update' will not handle path-based plugins like '#{plugin_name}'. Use 'inspec plugin uninstall' to remove the reference, then install as a gem."
|
||||
end
|
||||
if opts.key?(:path)
|
||||
raise UpdateError, "'inspec plugin update' will not install from a path."
|
||||
end
|
||||
|
||||
if opts.key?(:version) && plugin_version_installed?(plugin_name, opts[:version])
|
||||
raise UpdateError, "#{plugin_name} version #{opts[:version]} is already installed."
|
||||
end
|
||||
end
|
||||
|
||||
def validate_uninstall_opts(plugin_name, _opts)
|
||||
# Only uninstall plugins we know about
|
||||
unless plugin_name =~ /^(inspec|train)-/
|
||||
raise UnInstallError, "All inspec plugins must begin with either 'inspec-' or 'train-' - refusing to uninstall #{plugin_name}"
|
||||
end
|
||||
unless registry.known_plugin?(plugin_name.to_sym)
|
||||
raise UnInstallError, "'#{plugin_name}' is not installed, refusing to uninstall."
|
||||
end
|
||||
end
|
||||
|
||||
def validate_search_opts(search_term, _opts)
|
||||
unless search_term =~ /^(inspec|train)-/
|
||||
raise SearchError, "All inspec plugins must begin with either 'inspec-' or 'train-'."
|
||||
end
|
||||
end
|
||||
|
||||
#===================================================================#
|
||||
# Install / Upgrade Methods #
|
||||
#===================================================================#
|
||||
|
||||
def install_from_path(requested_plugin_name, opts)
|
||||
# Nothing to do here; we will later update the plugins file with the path.
|
||||
end
|
||||
|
||||
def install_from_gem_file(requested_plugin_name, opts)
|
||||
plugin_dependency = Gem::Dependency.new(requested_plugin_name)
|
||||
|
||||
# Make Set that encompasses just the gemfile that was provided
|
||||
plugin_local_source = Gem::Source::SpecificFile.new(opts[:gem_file])
|
||||
requested_local_gem_set = Gem::Resolver::InstallerSet.new(:both) # :both means local and remote; allow satisfying our gemfile's deps from rubygems.org
|
||||
requested_local_gem_set.add_local(plugin_dependency.name, plugin_local_source.spec, plugin_local_source)
|
||||
|
||||
install_gem_to_plugins_dir(plugin_dependency, [requested_local_gem_set])
|
||||
end
|
||||
|
||||
def install_from_remote_gems(requested_plugin_name, opts)
|
||||
plugin_dependency = Gem::Dependency.new(requested_plugin_name, opts[:version] || '> 0')
|
||||
# BestSet is rubygems.org API + indexing
|
||||
install_gem_to_plugins_dir(plugin_dependency, [Gem::Resolver::BestSet.new], opts[:update_mode])
|
||||
end
|
||||
|
||||
def install_gem_to_plugins_dir(new_plugin_dependency, extra_request_sets = [], update_mode = false)
|
||||
# Get a list of all the gems available to us.
|
||||
gem_to_force_update = update_mode ? new_plugin_dependency.name : nil
|
||||
set_available_for_resolution = build_gem_request_universe(extra_request_sets, gem_to_force_update)
|
||||
|
||||
# Solve the dependency (that is, find a way to install the new plugin and anything it needs)
|
||||
request_set = Gem::RequestSet.new(new_plugin_dependency)
|
||||
begin
|
||||
request_set.resolve(set_available_for_resolution)
|
||||
rescue Gem::UnsatisfiableDependencyError => gem_ex
|
||||
# TODO: use search facility to determine if the requested gem exists at all, vs if the constraints are impossible
|
||||
ex = Inspec::Plugin::V2::InstallError.new(gem_ex.message)
|
||||
ex.plugin_name = new_plugin_dependency.name
|
||||
raise ex
|
||||
end
|
||||
|
||||
# OK, perform the installation.
|
||||
# Ignore deps here, because any needed deps should already be baked into new_plugin_dependency
|
||||
request_set.install_into(gem_path, true, ignore_dependencies: true)
|
||||
end
|
||||
|
||||
#===================================================================#
|
||||
# UnInstall Methods #
|
||||
#===================================================================#
|
||||
|
||||
def uninstall_via_path(requested_plugin_name, opts)
|
||||
# Nothing to do here; we will later update the plugins file to remove the plugin entry.
|
||||
end
|
||||
|
||||
def uninstall_via_gem(plugin_name_to_be_removed, _opts)
|
||||
# Strategy: excluding the plugin we want to uninstall, determine a gem install solution
|
||||
# based on gems we already have, then remove anything not needed. This removes 3 kinds
|
||||
# of cruft:
|
||||
# 1. All versions of the unwanted plugin gem
|
||||
# 2. All dependencies of the unwanted plugin gem (that aren't needed by something else)
|
||||
# 3. All other gems installed under the ~/.inspec/gems area that are not needed
|
||||
# by a plugin gem. TODO: ideally this would be a separate 'clean' operation.
|
||||
|
||||
# Create a list of plugins dependencies, including any version constraints,
|
||||
# excluding any that are path-or-core-based, excluding the gem to be removed
|
||||
plugin_deps_we_still_must_satisfy = registry.plugin_statuses
|
||||
plugin_deps_we_still_must_satisfy = plugin_deps_we_still_must_satisfy.select do |status|
|
||||
status.installation_type == :gem && status.name != plugin_name_to_be_removed.to_sym
|
||||
end
|
||||
plugin_deps_we_still_must_satisfy = plugin_deps_we_still_must_satisfy.map do |status|
|
||||
constraint = status.version || '> 0'
|
||||
Gem::Dependency.new(status.name.to_s, constraint)
|
||||
end
|
||||
|
||||
# Make a Request Set representing the still-needed deps
|
||||
request_set_we_still_must_satisfy = Gem::RequestSet.new(*plugin_deps_we_still_must_satisfy)
|
||||
request_set_we_still_must_satisfy.remote = false
|
||||
|
||||
# Find out which gems we still actually need...
|
||||
names_of_gems_we_actually_need = \
|
||||
request_set_we_still_must_satisfy.resolve(build_gem_request_universe)
|
||||
.map(&:full_spec).map(&:full_name)
|
||||
|
||||
# ... vs what we currently have, which should have some cruft
|
||||
cruft_gem_specs = loader.list_managed_gems.reject do |spec|
|
||||
names_of_gems_we_actually_need.include?(spec.full_name)
|
||||
end
|
||||
|
||||
# Ok, delete the unneeded gems
|
||||
cruft_gem_specs.each do |cruft_spec|
|
||||
Gem::Uninstaller.new(
|
||||
cruft_spec.name,
|
||||
version: cruft_spec.version,
|
||||
install_dir: gem_path,
|
||||
# Docs on this class are poor. Next 4 are reasonable, but cargo-culted.
|
||||
all: true,
|
||||
executables: true,
|
||||
force: true,
|
||||
ignore: true,
|
||||
).uninstall_gem(cruft_spec)
|
||||
end
|
||||
end
|
||||
|
||||
#===================================================================#
|
||||
# Utilities
|
||||
#===================================================================#
|
||||
|
||||
# Provides a RequestSet (a set of gems representing the gems that are available to
|
||||
# solve a dependency request) that represents a combination of:
|
||||
# * the gems included in the system
|
||||
# * the gems included in the inspec install
|
||||
# * the currently installed gems in the ~/.inspec/gems directory
|
||||
# * any other sets you provide
|
||||
def build_gem_request_universe(extra_request_sets = [], gem_to_force_update = nil)
|
||||
installed_plugins_gem_set = Gem::Resolver::VendorSet.new
|
||||
loader.list_managed_gems.each do |spec|
|
||||
next if spec.name == gem_to_force_update
|
||||
installed_plugins_gem_set.add_vendor_gem(spec.name, spec.gem_dir)
|
||||
end
|
||||
|
||||
# Combine the Sets, so the resolver has one composite place to look
|
||||
Gem::Resolver.compose_sets(
|
||||
installed_plugins_gem_set, # The gems that are in the plugin gem path directory tree
|
||||
Gem::Resolver::CurrentSet.new, # The gems that are already included either with Ruby or with the InSpec install
|
||||
*extra_request_sets, # Anything else our caller wanted to include
|
||||
)
|
||||
end
|
||||
|
||||
#===================================================================#
|
||||
# plugins.json Maintenance Methods #
|
||||
#===================================================================#
|
||||
|
||||
# TODO: refactor the plugin.json file to have its own class, which Installer consumes
|
||||
def update_plugin_config_file(plugin_name, opts)
|
||||
config = update_plugin_config_data(plugin_name, opts)
|
||||
File.write(plugin_conf_file_path, JSON.pretty_generate(config))
|
||||
end
|
||||
|
||||
# TODO: refactor the plugin.json file to have its own class, which Installer consumes
|
||||
def update_plugin_config_data(plugin_name, opts)
|
||||
config = read_or_init_config_data
|
||||
config['plugins'].delete_if { |entry| entry['name'] == plugin_name }
|
||||
return config if opts[:action] == :uninstall
|
||||
|
||||
entry = { 'name' => plugin_name }
|
||||
|
||||
# Parsing by Requirement handles lot of awkward formattoes
|
||||
entry['version'] = Gem::Requirement.new(opts[:version]).to_s if opts.key?(:version)
|
||||
|
||||
if opts.key?(:path)
|
||||
entry['installation_type'] = 'path'
|
||||
entry['installation_path'] = opts[:path]
|
||||
end
|
||||
|
||||
config['plugins'] << entry
|
||||
config
|
||||
end
|
||||
|
||||
# TODO: check for validity
|
||||
# TODO: refactor the plugin.json file to have its own class, which Installer consumes
|
||||
def read_or_init_config_data
|
||||
if File.exist?(plugin_conf_file_path)
|
||||
JSON.parse(File.read(plugin_conf_file_path))
|
||||
else
|
||||
{
|
||||
'plugins_config_version' => '1.0.0',
|
||||
'plugins' => [],
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,7 +14,6 @@ module Inspec::Plugin::V2
|
|||
def initialize(options = {})
|
||||
@options = options
|
||||
@registry = Inspec::Plugin::V2::Registry.instance
|
||||
determine_plugin_conf_file
|
||||
read_conf_file
|
||||
unpack_conf_file
|
||||
|
||||
|
@ -28,7 +27,10 @@ module Inspec::Plugin::V2
|
|||
end
|
||||
|
||||
def load_all
|
||||
registry.each do |plugin_name, plugin_details|
|
||||
# Be careful not to actually iterate directly over the registry here;
|
||||
# we want to allow "sidecar loading", in which case a plugin may add an entry to the registry.
|
||||
registry.plugin_names.dup.each do |plugin_name|
|
||||
plugin_details = registry[plugin_name]
|
||||
# We want to capture literally any possible exception here, since we are storing them.
|
||||
# rubocop: disable Lint/RescueException
|
||||
begin
|
||||
|
@ -69,13 +71,26 @@ module Inspec::Plugin::V2
|
|||
end
|
||||
end
|
||||
|
||||
def activate_mentioned_cli_plugins(cli_args = ARGV)
|
||||
# Get a list of CLI plugin activation hooks
|
||||
registry.find_activators(plugin_type: :cli_command).each do |act|
|
||||
next if act.activated?
|
||||
# If there is anything in the CLI args with the same name, activate it
|
||||
# If the word 'help' appears in the first position, load all CLI plugins
|
||||
if cli_args.include?(act.activator_name.to_s) || cli_args[0] == 'help'
|
||||
activate(:cli_command, act.activator_name)
|
||||
act.implementation_class.register_with_thor
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def activate(plugin_type, hook_name)
|
||||
activator = registry.find_activators(plugin_type: plugin_type, activator_name: hook_name).first
|
||||
# We want to capture literally any possible exception here, since we are storing them.
|
||||
# rubocop: disable Lint/RescueException
|
||||
begin
|
||||
impl_class = activator.activation_proc.call
|
||||
activator.activated = true
|
||||
activator.activated?(true)
|
||||
activator.implementation_class = impl_class
|
||||
rescue Exception => ex
|
||||
activator.exception = ex
|
||||
|
@ -84,21 +99,73 @@ module Inspec::Plugin::V2
|
|||
# rubocop: enable Lint/RescueException
|
||||
end
|
||||
|
||||
def activate_mentioned_cli_plugins(cli_args = ARGV)
|
||||
# Get a list of CLI plugin activation hooks
|
||||
registry.find_activators(plugin_type: :cli_command).each do |act|
|
||||
next if act.activated
|
||||
# If there is anything in the CLI args with the same name, activate it
|
||||
# If the word 'help' appears in the first position, load all CLI plugins
|
||||
if cli_args.include?(act.activator_name.to_s) || cli_args[0] == 'help' || cli_args.size.zero?
|
||||
activate(:cli_command, act.activator_name)
|
||||
act.implementation_class.register_with_thor
|
||||
end
|
||||
end
|
||||
def plugin_gem_path
|
||||
self.class.plugin_gem_path
|
||||
end
|
||||
|
||||
def self.plugin_gem_path
|
||||
# I can't believe there isn't a simpler way of getting this
|
||||
# 2.4.2.p123 => 2.4.0
|
||||
ruby_abi_version = (Gem.ruby_version.segments[0, 2] << 0).join('.')
|
||||
File.join(Inspec.config_dir, 'gems', ruby_abi_version)
|
||||
end
|
||||
|
||||
# Lists all gems found in the plugin_gem_path.
|
||||
# @return [Array[Gem::Specification]] Specs of all gems found.
|
||||
def list_managed_gems
|
||||
Dir.glob(File.join(plugin_gem_path, 'specifications', '*.gemspec')).map { |p| Gem::Specification.load(p) }
|
||||
end
|
||||
|
||||
# Lists all plugin gems found in the plugin_gem_path.
|
||||
# This is simply all gems that begin with train- or inspec-.
|
||||
# @return [Array[Gem::Specification]] Specs of all gems found.
|
||||
def list_installed_plugin_gems
|
||||
list_managed_gems.select { |spec| spec.name.match(/^(inspec|train)-/) }
|
||||
end
|
||||
|
||||
# TODO: refactor the plugin.json file to have its own class, which Loader consumes
|
||||
def plugin_conf_file_path
|
||||
self.class.plugin_conf_file_path
|
||||
end
|
||||
|
||||
# TODO: refactor the plugin.json file to have its own class, which Loader consumes
|
||||
def self.plugin_conf_file_path
|
||||
File.join(Inspec.config_dir, 'plugins.json')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# 'Activating' a gem adds it to the load path, so 'require "gemname"' will work.
|
||||
# Given a gem name, this activates the gem and all of its dependencies, respecting
|
||||
# version pinning needs.
|
||||
def activate_managed_gems_for_plugin(plugin_gem_name, version_constraint = '> 0')
|
||||
# TODO: enforce first-level version pinning
|
||||
plugin_deps = [Gem::Dependency.new(plugin_gem_name.to_s, version_constraint)]
|
||||
managed_gem_set = Gem::Resolver::VendorSet.new
|
||||
list_managed_gems.each { |spec| managed_gem_set.add_vendor_gem(spec.name, spec.gem_dir) }
|
||||
|
||||
# TODO: Next two lines merge our managed gems with the other gems available
|
||||
# in our "local universe" - which may be the system, or it could be in a Bundler microcosm,
|
||||
# or rbenv, etc. Do we want to merge that, though?
|
||||
distrib_gem_set = Gem::Resolver::CurrentSet.new
|
||||
installed_gem_set = Gem::Resolver.compose_sets(managed_gem_set, distrib_gem_set)
|
||||
|
||||
# So, given what we need, and what we have available, what activations are needed?
|
||||
resolver = Gem::Resolver.new(plugin_deps, installed_gem_set)
|
||||
begin
|
||||
solution = resolver.resolve
|
||||
rescue Gem::UnsatisfiableDependencyError => gem_ex
|
||||
# If you broke your install, or downgraded to a plugin with a bad gemspec, you could get here.
|
||||
ex = Inspec::Plugin::V2::LoadError.new(gem_ex.message)
|
||||
raise ex
|
||||
end
|
||||
solution.each do |activation_request|
|
||||
next if activation_request.full_spec.activated?
|
||||
activation_request.full_spec.activate
|
||||
# TODO: If we are under Bundler, inform it that we loaded a gem
|
||||
end
|
||||
end
|
||||
|
||||
def annotate_status_after_loading(plugin_name)
|
||||
status = registry[plugin_name]
|
||||
return if status.api_generation == 2 # Gen2 have self-annotating superclasses
|
||||
|
@ -116,7 +183,7 @@ module Inspec::Plugin::V2
|
|||
status = registry[plugin_name]
|
||||
status.api_generation = 0
|
||||
act = Activator.new
|
||||
act.activated = true
|
||||
act.activated?(true)
|
||||
act.plugin_type = :cli_command
|
||||
act.plugin_name = plugin_name
|
||||
act.activator_name = :default
|
||||
|
@ -143,11 +210,6 @@ module Inspec::Plugin::V2
|
|||
end
|
||||
end
|
||||
|
||||
def determine_plugin_conf_file
|
||||
@plugin_conf_file_path = ENV['INSPEC_CONFIG_DIR'] ? ENV['INSPEC_CONFIG_DIR'] : File.join(Dir.home, '.inspec')
|
||||
@plugin_conf_file_path = File.join(@plugin_conf_file_path, 'plugins.json')
|
||||
end
|
||||
|
||||
def detect_core_plugins
|
||||
core_plugins_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'plugins'))
|
||||
# These are expected to be organized as proper separate projects,
|
||||
|
@ -165,8 +227,8 @@ module Inspec::Plugin::V2
|
|||
# TODO: DRY up re: Installer read_or_init_config_file
|
||||
# TODO: refactor the plugin.json file to have its own class, which Loader consumes
|
||||
def read_conf_file
|
||||
if File.exist?(@plugin_conf_file_path)
|
||||
@plugin_file_contents = JSON.parse(File.read(@plugin_conf_file_path))
|
||||
if File.exist?(plugin_conf_file_path)
|
||||
@plugin_file_contents = JSON.parse(File.read(plugin_conf_file_path))
|
||||
else
|
||||
@plugin_file_contents = {
|
||||
'plugins_config_version' => '1.0.0',
|
||||
|
@ -174,19 +236,20 @@ module Inspec::Plugin::V2
|
|||
}
|
||||
end
|
||||
rescue JSON::ParserError => e
|
||||
raise Inspec::Plugin::V2::ConfigError, "Failed to load plugins JSON configuration from #{@plugin_conf_file_path}:\n#{e}"
|
||||
raise Inspec::Plugin::V2::ConfigError, "Failed to load plugins JSON configuration from #{plugin_conf_file_path}:\n#{e}"
|
||||
end
|
||||
|
||||
# TODO: refactor the plugin.json file to have its own class, which Loader consumes
|
||||
def unpack_conf_file
|
||||
validate_conf_file
|
||||
@plugin_file_contents['plugins'].each do |plugin_json|
|
||||
status = Inspec::Plugin::V2::Status.new
|
||||
status.name = plugin_json['name'].to_sym
|
||||
status.loaded = false
|
||||
status.installation_type = plugin_json['installation_type'].to_sym || :gem
|
||||
status.installation_type = (plugin_json['installation_type'] || :gem).to_sym
|
||||
case status.installation_type
|
||||
when :gem
|
||||
status.entry_point = status.name
|
||||
status.entry_point = status.name.to_s
|
||||
status.version = plugin_json['version']
|
||||
when :path
|
||||
status.entry_point = plugin_json['installation_path']
|
||||
|
@ -196,9 +259,10 @@ module Inspec::Plugin::V2
|
|||
end
|
||||
end
|
||||
|
||||
# TODO: refactor the plugin.json file to have its own class, which Loader consumes
|
||||
def validate_conf_file
|
||||
unless @plugin_file_contents['plugins_config_version'] == '1.0.0'
|
||||
raise Inspec::Plugin::V2::ConfigError, "Unsupported plugins.json file version #{@plugin_file_contents['plugins_config_version']} at #{@plugin_conf_file_path} - currently support versions: 1.0.0"
|
||||
raise Inspec::Plugin::V2::ConfigError, "Unsupported plugins.json file version #{@plugin_file_contents['plugins_config_version']} at #{plugin_conf_file_path} - currently support versions: 1.0.0"
|
||||
end
|
||||
|
||||
plugin_entries = @plugin_file_contents['plugins']
|
||||
|
|
|
@ -25,7 +25,7 @@ module Inspec::Plugin::V2
|
|||
end
|
||||
|
||||
def loaded_plugin?(name)
|
||||
registry.dig(name, :loaded)
|
||||
registry.dig(name.to_sym, :loaded)
|
||||
end
|
||||
|
||||
def loaded_count
|
||||
|
@ -40,6 +40,10 @@ module Inspec::Plugin::V2
|
|||
registry.values.select(&:loaded).map(&:name)
|
||||
end
|
||||
|
||||
def path_based_plugin?(name)
|
||||
known_plugin?(name.to_sym) && registry[name.to_sym].installation_type == :path
|
||||
end
|
||||
|
||||
def find_status_by_class(klass)
|
||||
registry.values.detect { |status| status.plugin_class == klass }
|
||||
end
|
||||
|
|
45
support/rebuild_inspec_test_fixture_plugin.sh
Executable file
45
support/rebuild_inspec_test_fixture_plugin.sh
Executable file
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Unportable assumptions:
|
||||
# 1. You use rbenv to manage ruby runtimes.
|
||||
# 2. You are running from project root
|
||||
eval "$(rbenv init -)"
|
||||
|
||||
PLUGIN_SRC_DIR=test/unit/mock/plugins/inspec-test-fixture
|
||||
FIXTURE_BASE=test/unit/mock/config_dirs
|
||||
FIXTURE_VERSIONS="1 2"
|
||||
RUBY_VERSIONS="2.3.1,2.3.0 2.4.2,2.4.0 2.5.1,2.5.0"
|
||||
|
||||
# Make two fresh gems
|
||||
cd $PLUGIN_SRC_DIR
|
||||
sed -i -e s/0\.2\.0/0.1.0/ lib/inspec-test-fixture/version.rb
|
||||
bundle exec rake build
|
||||
sed -i -e s/0\.1\.0/0.2.0/ lib/inspec-test-fixture/version.rb
|
||||
bundle exec rake build
|
||||
sed -i -e s/0\.2\.0/0.1.0/ lib/inspec-test-fixture/version.rb
|
||||
rm -f lib/inspec-test-fixture/version.rb-e
|
||||
cd ../../../../../
|
||||
|
||||
# Purge and re-install the existing gem installs
|
||||
for fver in $FIXTURE_VERSIONS; do
|
||||
for info in $RUBY_VERSIONS; do
|
||||
RUBY_VER=$(echo "$info" | cut -d, -f1)
|
||||
RUBY_ABI=$(echo "$info" | cut -d, -f2)
|
||||
GEM_DIR="$FIXTURE_BASE/test-fixture-${fver}-float/gems/$RUBY_ABI"
|
||||
echo "Reinstalling inspec-test-fixture-0.${fver}.0 for ABI $RUBY_ABI"
|
||||
rm -rf "$GEM_DIR"
|
||||
mkdir -p "$GEM_DIR"
|
||||
rbenv shell "$RUBY_VER"
|
||||
gem install -N -i "$GEM_DIR $PLUGIN_SRC_DIR/pkg/inspec-test-fixture-0.${fver}.0.gem"
|
||||
echo
|
||||
done
|
||||
done
|
||||
|
||||
# Fix ordinal array gemspec....
|
||||
for info in $RUBY_VERSIONS; do
|
||||
RUBY_ABI=$(echo $info | cut -d, -f2)
|
||||
GEM_DIR="$FIXTURE_BASE/test-fixture-${fver}-float/gems/$RUBY_ABI"
|
||||
cp -v "$GEM_DIR/specifications/ordinal_array-0.2.0.gemspec" "$GEM_DIR/gems/ordinal_array-0.2.0/ordinal_array.gemspec"
|
||||
done
|
||||
|
||||
rbenv shell 2.4.2
|
11
test/unit/mock/config_dirs/test-fixture-1-float/README.md
Normal file
11
test/unit/mock/config_dirs/test-fixture-1-float/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
This test fixture is a user config dir setup as though the inspec-test-fixture v1 was already installed, and it has no version constraint.
|
||||
|
||||
This was accomplished by executing (*without* bundler) the following commands:
|
||||
|
||||
```bash
|
||||
mkdir -p test/unit/mock/config_dirs/test-fixture-1-float/gems/{2.3.0,2.4.0,2.5.0}
|
||||
# Here I'm running a ruby 2.4.x binary with rbenv
|
||||
gem install -l -N -i test/unit/mock/config_dirs/test-fixture-1-float/gems/2.4.0 test/unit/mock/plugins/inspec-test-fixture/pkg/inspec-test-fixture-0.1.0.gem
|
||||
```
|
||||
|
||||
Note that we will need to add an installation tree each time we support a new minor or major version of the Ruby VM.
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
lib = File.expand_path("../lib", __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require "inspec-test-fixture/version"
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "inspec-test-fixture"
|
||||
spec.version = InspecPlugins::TestFixture::VERSION
|
||||
spec.authors = ["InSpec Engineering Team"]
|
||||
spec.email = ["hello@chef.io"]
|
||||
|
||||
spec.summary = %q{A simple test plugin gem for InSpec}
|
||||
spec.description = %q{This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.}
|
||||
spec.homepage = "https://github.com/inspec/inspec"
|
||||
|
||||
spec.files = [
|
||||
'inspec-test-fixture.gemspec',
|
||||
'lib/inspec-test-fixture.rb',
|
||||
'lib/inspec-test-fixture/plugin.rb',
|
||||
'lib/inspec-test-fixture/mock_plugin.rb',
|
||||
'lib/inspec-test-fixture/version.rb',
|
||||
]
|
||||
spec.executables = []
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
if InspecPlugins::TestFixture::VERSION == '0.2.0'
|
||||
spec.add_dependency "ordinal_array", "~> 0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
require 'inspec-test-fixture/plugin'
|
|
@ -0,0 +1,13 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
if InspecPlugins::TestFixture::VERSION == Gem::Version.new('0.2.0')
|
||||
require "ordinal_array"
|
||||
end
|
||||
|
||||
module InspecPlugins::TextFixture
|
||||
class MockPlugin < Inspec.plugin(2, :mock_plugin_type)
|
||||
def execute(opts = {})
|
||||
# Check to see if Array responds to 'third'
|
||||
Array.respond_to?(:third)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
|
||||
class Plugin < Inspec.plugin(2)
|
||||
plugin_name :'inspec-test-fixture'
|
||||
|
||||
mock_plugin_type :'inspec-test-fixture' do
|
||||
require 'mock_plugin'
|
||||
InspecPlugins::TestFixture
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
VERSION = "0.1.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: inspec-test-fixture 0.1.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "inspec-test-fixture"
|
||||
s.version = "0.1.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib"]
|
||||
s.authors = ["InSpec Engineering Team"]
|
||||
s.date = "2018-08-17"
|
||||
s.description = "This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development."
|
||||
s.email = ["hello@chef.io"]
|
||||
s.homepage = "https://github.com/inspec/inspec"
|
||||
s.rubygems_version = "2.5.1"
|
||||
s.summary = "A simple test plugin gem for InSpec"
|
||||
|
||||
s.installed_by_version = "2.5.1" if s.respond_to? :installed_by_version
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
s.specification_version = 4
|
||||
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_development_dependency(%q<rake>, ["~> 10.0"])
|
||||
else
|
||||
s.add_dependency(%q<rake>, ["~> 10.0"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<rake>, ["~> 10.0"])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
lib = File.expand_path("../lib", __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require "inspec-test-fixture/version"
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "inspec-test-fixture"
|
||||
spec.version = InspecPlugins::TestFixture::VERSION
|
||||
spec.authors = ["InSpec Engineering Team"]
|
||||
spec.email = ["hello@chef.io"]
|
||||
|
||||
spec.summary = %q{A simple test plugin gem for InSpec}
|
||||
spec.description = %q{This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.}
|
||||
spec.homepage = "https://github.com/inspec/inspec"
|
||||
|
||||
spec.files = [
|
||||
'inspec-test-fixture.gemspec',
|
||||
'lib/inspec-test-fixture.rb',
|
||||
'lib/inspec-test-fixture/plugin.rb',
|
||||
'lib/inspec-test-fixture/mock_plugin.rb',
|
||||
'lib/inspec-test-fixture/version.rb',
|
||||
]
|
||||
spec.executables = []
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
if InspecPlugins::TestFixture::VERSION == '0.2.0'
|
||||
spec.add_dependency "ordinal_array", "~> 0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
require 'inspec-test-fixture/plugin'
|
|
@ -0,0 +1,13 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
if InspecPlugins::TestFixture::VERSION == Gem::Version.new('0.2.0')
|
||||
require "ordinal_array"
|
||||
end
|
||||
|
||||
module InspecPlugins::TextFixture
|
||||
class MockPlugin < Inspec.plugin(2, :mock_plugin_type)
|
||||
def execute(opts = {})
|
||||
# Check to see if Array responds to 'third'
|
||||
Array.respond_to?(:third)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
|
||||
class Plugin < Inspec.plugin(2)
|
||||
plugin_name :'inspec-test-fixture'
|
||||
|
||||
mock_plugin_type :'inspec-test-fixture' do
|
||||
require 'mock_plugin'
|
||||
InspecPlugins::TestFixture
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
VERSION = "0.1.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: inspec-test-fixture 0.1.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "inspec-test-fixture".freeze
|
||||
s.version = "0.1.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["InSpec Engineering Team".freeze]
|
||||
s.date = "2018-08-17"
|
||||
s.description = "This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.".freeze
|
||||
s.email = ["hello@chef.io".freeze]
|
||||
s.homepage = "https://github.com/inspec/inspec".freeze
|
||||
s.rubygems_version = "2.6.13".freeze
|
||||
s.summary = "A simple test plugin gem for InSpec".freeze
|
||||
|
||||
s.installed_by_version = "2.6.13" if s.respond_to? :installed_by_version
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
s.specification_version = 4
|
||||
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_development_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
else
|
||||
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
lib = File.expand_path("../lib", __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require "inspec-test-fixture/version"
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "inspec-test-fixture"
|
||||
spec.version = InspecPlugins::TestFixture::VERSION
|
||||
spec.authors = ["InSpec Engineering Team"]
|
||||
spec.email = ["hello@chef.io"]
|
||||
|
||||
spec.summary = %q{A simple test plugin gem for InSpec}
|
||||
spec.description = %q{This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.}
|
||||
spec.homepage = "https://github.com/inspec/inspec"
|
||||
|
||||
spec.files = [
|
||||
'inspec-test-fixture.gemspec',
|
||||
'lib/inspec-test-fixture.rb',
|
||||
'lib/inspec-test-fixture/plugin.rb',
|
||||
'lib/inspec-test-fixture/mock_plugin.rb',
|
||||
'lib/inspec-test-fixture/version.rb',
|
||||
]
|
||||
spec.executables = []
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
if InspecPlugins::TestFixture::VERSION == '0.2.0'
|
||||
spec.add_dependency "ordinal_array", "~> 0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
require 'inspec-test-fixture/plugin'
|
|
@ -0,0 +1,13 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
if InspecPlugins::TestFixture::VERSION == Gem::Version.new('0.2.0')
|
||||
require "ordinal_array"
|
||||
end
|
||||
|
||||
module InspecPlugins::TextFixture
|
||||
class MockPlugin < Inspec.plugin(2, :mock_plugin_type)
|
||||
def execute(opts = {})
|
||||
# Check to see if Array responds to 'third'
|
||||
Array.respond_to?(:third)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
|
||||
class Plugin < Inspec.plugin(2)
|
||||
plugin_name :'inspec-test-fixture'
|
||||
|
||||
mock_plugin_type :'inspec-test-fixture' do
|
||||
require 'mock_plugin'
|
||||
InspecPlugins::TestFixture
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
VERSION = "0.1.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: inspec-test-fixture 0.1.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "inspec-test-fixture".freeze
|
||||
s.version = "0.1.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["InSpec Engineering Team".freeze]
|
||||
s.date = "2018-08-17"
|
||||
s.description = "This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.".freeze
|
||||
s.email = ["hello@chef.io".freeze]
|
||||
s.homepage = "https://github.com/inspec/inspec".freeze
|
||||
s.rubygems_version = "2.7.6".freeze
|
||||
s.summary = "A simple test plugin gem for InSpec".freeze
|
||||
|
||||
s.installed_by_version = "2.7.6" if s.respond_to? :installed_by_version
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
s.specification_version = 4
|
||||
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_development_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
else
|
||||
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"plugins_config_version" : "1.0.0",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "inspec-test-fixture"
|
||||
}
|
||||
]
|
||||
}
|
13
test/unit/mock/config_dirs/test-fixture-2-float/README.md
Normal file
13
test/unit/mock/config_dirs/test-fixture-2-float/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
This test fixture is a user config dir setup as though the inspec-test-fixture v0.2.0 was already installed, and it has no version constraint.
|
||||
|
||||
This is interesting because (unlike 0.1.0) v0.2.0 has a gem dependency.
|
||||
|
||||
This was accomplished by executing (*without* bundler) the following commands:
|
||||
|
||||
```bash
|
||||
mkdir -p test/unit/mock/config_dirs/test-fixture-2-float/gems/{2.3.0,2.4.0,2.5.0}
|
||||
# Here I'm running a ruby 2.4.x binary with rbenv
|
||||
gem install -N -i test/unit/mock/config_dirs/test-fixture-2-float/gems/2.4.0 test/unit/mock/plugins/inspec-test-fixture/pkg/inspec-test-fixture-0.2.0.gem
|
||||
```
|
||||
|
||||
Note that we will need to add an installation tree each time we support a new minor or major version of the Ruby VM.
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
lib = File.expand_path("../lib", __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require "inspec-test-fixture/version"
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "inspec-test-fixture"
|
||||
spec.version = InspecPlugins::TestFixture::VERSION
|
||||
spec.authors = ["InSpec Engineering Team"]
|
||||
spec.email = ["hello@chef.io"]
|
||||
|
||||
spec.summary = %q{A simple test plugin gem for InSpec}
|
||||
spec.description = %q{This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.}
|
||||
spec.homepage = "https://github.com/inspec/inspec"
|
||||
|
||||
spec.files = [
|
||||
'inspec-test-fixture.gemspec',
|
||||
'lib/inspec-test-fixture.rb',
|
||||
'lib/inspec-test-fixture/plugin.rb',
|
||||
'lib/inspec-test-fixture/mock_plugin.rb',
|
||||
'lib/inspec-test-fixture/version.rb',
|
||||
]
|
||||
spec.executables = []
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
if InspecPlugins::TestFixture::VERSION == '0.2.0'
|
||||
spec.add_dependency "ordinal_array", "~> 0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
require 'inspec-test-fixture/plugin'
|
|
@ -0,0 +1,13 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
if InspecPlugins::TestFixture::VERSION == Gem::Version.new('0.2.0')
|
||||
require "ordinal_array"
|
||||
end
|
||||
|
||||
module InspecPlugins::TextFixture
|
||||
class MockPlugin < Inspec.plugin(2, :mock_plugin_type)
|
||||
def execute(opts = {})
|
||||
# Check to see if Array responds to 'third'
|
||||
Array.respond_to?(:third)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
|
||||
class Plugin < Inspec.plugin(2)
|
||||
plugin_name :'inspec-test-fixture'
|
||||
|
||||
mock_plugin_type :'inspec-test-fixture' do
|
||||
require 'mock_plugin'
|
||||
InspecPlugins::TestFixture
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
VERSION = "0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
= Ordinal array
|
||||
|
||||
Ordinal array is a Gem which allows you to access to a value of an array by an ordinal value. You can access to the first element of an array by the "first" method. Now you can access to the second element by "second", the third by "third" and that until the 999th elements.
|
||||
|
||||
Works with Ruby 1.9
|
||||
|
||||
Improve ordinal array speed for multiple calls on the same method on the same array: (Benchmark results: https://gist.github.com/2337544)
|
||||
|
||||
Exemple:
|
||||
my_array = ["value1", "value2", "value3"]
|
||||
puts my_array.third # print: value 3
|
||||
puts my_array.third # print: value 3 (But... much faster!)
|
||||
|
||||
= How to use
|
||||
|
||||
Just add gem "ordinal_array" in your gemfile.
|
||||
It provides you some methods on the basic array class
|
||||
|
||||
Exemple of use:
|
||||
|
||||
my_array = ["value1", "value2", "value3"]
|
||||
puts my_array.third # print: value 3
|
||||
my_array[41] = "it works fine"
|
||||
puts my_array.fourty_second # print: it works fine
|
||||
|
||||
= Contributors
|
||||
|
||||
*Kevin Disneur
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
require_relative './ordinal_array/ordinal'
|
||||
require_relative './ordinal_array/ordinal_constants'
|
||||
|
||||
class Array
|
||||
|
||||
include OrdinalArray::Constant
|
||||
include OrdinalArray
|
||||
|
||||
def self.respond_to?(method_sym, include_private=false)
|
||||
return true if Array.number_in_letter? method_sym
|
||||
super
|
||||
end
|
||||
|
||||
def method_missing(name, *params)
|
||||
if Array.number_in_letter? name
|
||||
index = index_by_number_in_letter(name, params)
|
||||
|
||||
self.class.send(:define_method, name) do
|
||||
self[index]
|
||||
end
|
||||
|
||||
self.send(name)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.number_in_letter?(name)
|
||||
ordinal_figure = false
|
||||
possible_followers = [:hundred, :decade, :ordinal]
|
||||
|
||||
letter_numbers = name.to_s.split('_').drop_while do |letter_number|
|
||||
return false if ordinal_figure
|
||||
|
||||
figure = Numbers_in_letter.element_by_name(letter_number)
|
||||
return false unless figure
|
||||
return false unless possible_followers.include? figure.to_sym
|
||||
|
||||
possible_followers = figure.can_be_followed_by
|
||||
ordinal_figure = !figure.kind_of?(ComposedOrdinal)
|
||||
|
||||
true
|
||||
end
|
||||
letter_numbers.empty? && ordinal_figure
|
||||
end
|
||||
|
||||
def index_by_number_in_letter(name, *params)
|
||||
partial_sum = 1
|
||||
sum = name.to_s.split('_').inject(0) do |sum, letter_number|
|
||||
number = Numbers_in_letter.element_by_name(letter_number).number
|
||||
if partial_sum < number
|
||||
partial_sum = partial_sum * number
|
||||
else
|
||||
sum = sum + partial_sum
|
||||
partial_sum = number
|
||||
end
|
||||
sum
|
||||
end
|
||||
sum = sum + partial_sum
|
||||
index = sum - 1
|
||||
index > 0 ? index : nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1,71 @@
|
|||
module OrdinalArray
|
||||
|
||||
class Ordinal
|
||||
attr_accessor :number_in_letter, :number, :can_be_followed_by
|
||||
|
||||
def initialize(number_in_letter, number)
|
||||
@number_in_letter = number_in_letter
|
||||
@can_be_followed_by = nil
|
||||
@number = number
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:ordinal
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:hundred]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:ordinal
|
||||
end
|
||||
end
|
||||
|
||||
class DecadeOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = nil
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:decade
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedDecadeOrdinal < ComposedOrdinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:ordinal]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:decade
|
||||
end
|
||||
end
|
||||
|
||||
class HundredOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = nil
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:hundred
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedHundredOrdinal < ComposedDecadeOrdinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:decade, :ordinal]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:hundred
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,84 @@
|
|||
require_relative './ordinal'
|
||||
|
||||
module OrdinalArray
|
||||
module Constant
|
||||
|
||||
First = Ordinal.new("first", 1)
|
||||
One = ComposedOrdinal.new("one", 1)
|
||||
Second = Ordinal.new("second", 2)
|
||||
Two = ComposedOrdinal.new("two", 2)
|
||||
Third = Ordinal.new("third", 3)
|
||||
Three = ComposedOrdinal.new("three", 3)
|
||||
Fourth = Ordinal.new("fourth", 4)
|
||||
Four = ComposedOrdinal.new("four", 4)
|
||||
Fifth = Ordinal.new("fifth", 5)
|
||||
Five = ComposedOrdinal.new("five", 5)
|
||||
Sixth = Ordinal.new("sixth", 6)
|
||||
Six = ComposedOrdinal.new("six", 6)
|
||||
Seventh = Ordinal.new("seventh", 7)
|
||||
Seven = ComposedOrdinal.new("seven", 7)
|
||||
Eighth = Ordinal.new("eighth", 8)
|
||||
Eight = ComposedOrdinal.new("eight", 8)
|
||||
Ninth = Ordinal.new("ninth", 9)
|
||||
Nine = ComposedOrdinal.new("nine", 9)
|
||||
Tenth = DecadeOrdinal.new("tenth", 10)
|
||||
Ten = ComposedDecadeOrdinal.new("ten", 10)
|
||||
Eleventh = DecadeOrdinal.new("eleventh", 11)
|
||||
Eleven = ComposedDecadeOrdinal.new("eleven", 11)
|
||||
Twelfth = DecadeOrdinal.new("twelfth", 12)
|
||||
Twelve = ComposedDecadeOrdinal.new("twelve", 12)
|
||||
Thirteenth = DecadeOrdinal.new("thirteenth", 13)
|
||||
Thirteen = ComposedDecadeOrdinal.new("thirteen", 13)
|
||||
Fourteenth = DecadeOrdinal.new("fourteenth", 14)
|
||||
Fourteen = ComposedDecadeOrdinal.new("fourteen", 14)
|
||||
Fifteenth = DecadeOrdinal.new("fifteenth", 15)
|
||||
Fifteen = ComposedDecadeOrdinal.new("fifteen", 15)
|
||||
Sixteenth = DecadeOrdinal.new("sixteenth", 16)
|
||||
Sixteen = ComposedDecadeOrdinal.new("sixteen", 16)
|
||||
Seventeenth = DecadeOrdinal.new("seventeenth", 17)
|
||||
Seventeen = ComposedDecadeOrdinal.new("seventeen", 17)
|
||||
Eighteenth = DecadeOrdinal.new("eighteenth", 18)
|
||||
Eighteen = ComposedDecadeOrdinal.new("eighteen", 18)
|
||||
Nineteenth = DecadeOrdinal.new("nineteenth", 19)
|
||||
Nineteen = ComposedDecadeOrdinal.new("nineteen", 19)
|
||||
Twentieth = DecadeOrdinal.new("twentieth", 20)
|
||||
Twenty = ComposedDecadeOrdinal.new("twenty", 20)
|
||||
Thirtieth = DecadeOrdinal.new("thirtieth", 30)
|
||||
Thirty = ComposedDecadeOrdinal.new("thirty", 30)
|
||||
Fortieth = DecadeOrdinal.new("fortieth", 40)
|
||||
Fourty = ComposedDecadeOrdinal.new("fourty", 40)
|
||||
Fiftieth = DecadeOrdinal.new("fiftieth", 50)
|
||||
Fifty = ComposedDecadeOrdinal.new("fifty", 50)
|
||||
Sixtieth = DecadeOrdinal.new("sixtieth", 60)
|
||||
Sixty = ComposedDecadeOrdinal.new("sixty", 60)
|
||||
Seventieth = DecadeOrdinal.new("seventieth", 70)
|
||||
Seventy = ComposedDecadeOrdinal.new("seventy", 70)
|
||||
Eightieth = DecadeOrdinal.new("eightieth", 80)
|
||||
Eighty = ComposedDecadeOrdinal.new("eighty", 80)
|
||||
Ninetieth = DecadeOrdinal.new("ninetieth", 90)
|
||||
Ninety = ComposedDecadeOrdinal.new("ninety", 90)
|
||||
Hundredth = HundredOrdinal.new("hundredth", 100)
|
||||
Hundred = ComposedHundredOrdinal.new("hundred", 100)
|
||||
|
||||
Numbers_in_letter = [
|
||||
One, Two, Three, Four, Five, Six, Seven, Eight, Nine,
|
||||
Ten, Eleven, Twelve, Thirteen, Fourteen, Fifteen, Sixteen, Seventeen, Eighteen, Nineteen,
|
||||
Twenty, Thirty, Fourty, Fifty, Sixty, Seventy, Eighty, Ninety,
|
||||
Hundred,
|
||||
|
||||
First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth,
|
||||
Tenth, Eleventh, Twelfth, Thirteenth, Fourteenth, Fifteenth, Sixteenth, Seventeenth, Eighteenth, Nineteenth,
|
||||
Twentieth, Thirtieth, Fortieth, Fiftieth, Sixtieth, Seventieth, Eightieth, Ninetieth,
|
||||
Hundredth
|
||||
]
|
||||
|
||||
class << Numbers_in_letter
|
||||
def element_by_name(name)
|
||||
index = self.index {|n| n.number_in_letter == name }
|
||||
return nil unless index
|
||||
self.[](index)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: ordinal_array 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "ordinal_array"
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib"]
|
||||
s.authors = ["Kevin Disneur"]
|
||||
s.date = "2012-04-08"
|
||||
s.description = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements"
|
||||
s.email = ["kevin.disneur@gmail.com"]
|
||||
s.homepage = "https://github.com/kdisneur/ordinal_array"
|
||||
s.rubygems_version = "2.5.1"
|
||||
s.summary = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements"
|
||||
|
||||
s.installed_by_version = "2.5.1" if s.respond_to? :installed_by_version
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: inspec-test-fixture 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "inspec-test-fixture"
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib"]
|
||||
s.authors = ["InSpec Engineering Team"]
|
||||
s.date = "2018-08-17"
|
||||
s.description = "This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development."
|
||||
s.email = ["hello@chef.io"]
|
||||
s.homepage = "https://github.com/inspec/inspec"
|
||||
s.rubygems_version = "2.5.1"
|
||||
s.summary = "A simple test plugin gem for InSpec"
|
||||
|
||||
s.installed_by_version = "2.5.1" if s.respond_to? :installed_by_version
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
s.specification_version = 4
|
||||
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_development_dependency(%q<rake>, ["~> 10.0"])
|
||||
s.add_runtime_dependency(%q<ordinal_array>, ["~> 0.2.0"])
|
||||
else
|
||||
s.add_dependency(%q<rake>, ["~> 10.0"])
|
||||
s.add_dependency(%q<ordinal_array>, ["~> 0.2.0"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<rake>, ["~> 10.0"])
|
||||
s.add_dependency(%q<ordinal_array>, ["~> 0.2.0"])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: ordinal_array 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "ordinal_array"
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib"]
|
||||
s.authors = ["Kevin Disneur"]
|
||||
s.date = "2012-04-08"
|
||||
s.description = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements"
|
||||
s.email = ["kevin.disneur@gmail.com"]
|
||||
s.homepage = "https://github.com/kdisneur/ordinal_array"
|
||||
s.rubygems_version = "2.5.1"
|
||||
s.summary = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements"
|
||||
|
||||
s.installed_by_version = "2.5.1" if s.respond_to? :installed_by_version
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
lib = File.expand_path("../lib", __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require "inspec-test-fixture/version"
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "inspec-test-fixture"
|
||||
spec.version = InspecPlugins::TestFixture::VERSION
|
||||
spec.authors = ["InSpec Engineering Team"]
|
||||
spec.email = ["hello@chef.io"]
|
||||
|
||||
spec.summary = %q{A simple test plugin gem for InSpec}
|
||||
spec.description = %q{This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.}
|
||||
spec.homepage = "https://github.com/inspec/inspec"
|
||||
|
||||
spec.files = [
|
||||
'inspec-test-fixture.gemspec',
|
||||
'lib/inspec-test-fixture.rb',
|
||||
'lib/inspec-test-fixture/plugin.rb',
|
||||
'lib/inspec-test-fixture/mock_plugin.rb',
|
||||
'lib/inspec-test-fixture/version.rb',
|
||||
]
|
||||
spec.executables = []
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
if InspecPlugins::TestFixture::VERSION == '0.2.0'
|
||||
spec.add_dependency "ordinal_array", "~> 0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
require 'inspec-test-fixture/plugin'
|
|
@ -0,0 +1,13 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
if InspecPlugins::TestFixture::VERSION == Gem::Version.new('0.2.0')
|
||||
require "ordinal_array"
|
||||
end
|
||||
|
||||
module InspecPlugins::TextFixture
|
||||
class MockPlugin < Inspec.plugin(2, :mock_plugin_type)
|
||||
def execute(opts = {})
|
||||
# Check to see if Array responds to 'third'
|
||||
Array.respond_to?(:third)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
|
||||
class Plugin < Inspec.plugin(2)
|
||||
plugin_name :'inspec-test-fixture'
|
||||
|
||||
mock_plugin_type :'inspec-test-fixture' do
|
||||
require 'mock_plugin'
|
||||
InspecPlugins::TestFixture
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
VERSION = "0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
= Ordinal array
|
||||
|
||||
Ordinal array is a Gem which allows you to access to a value of an array by an ordinal value. You can access to the first element of an array by the "first" method. Now you can access to the second element by "second", the third by "third" and that until the 999th elements.
|
||||
|
||||
Works with Ruby 1.9
|
||||
|
||||
Improve ordinal array speed for multiple calls on the same method on the same array: (Benchmark results: https://gist.github.com/2337544)
|
||||
|
||||
Exemple:
|
||||
my_array = ["value1", "value2", "value3"]
|
||||
puts my_array.third # print: value 3
|
||||
puts my_array.third # print: value 3 (But... much faster!)
|
||||
|
||||
= How to use
|
||||
|
||||
Just add gem "ordinal_array" in your gemfile.
|
||||
It provides you some methods on the basic array class
|
||||
|
||||
Exemple of use:
|
||||
|
||||
my_array = ["value1", "value2", "value3"]
|
||||
puts my_array.third # print: value 3
|
||||
my_array[41] = "it works fine"
|
||||
puts my_array.fourty_second # print: it works fine
|
||||
|
||||
= Contributors
|
||||
|
||||
*Kevin Disneur
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
require_relative './ordinal_array/ordinal'
|
||||
require_relative './ordinal_array/ordinal_constants'
|
||||
|
||||
class Array
|
||||
|
||||
include OrdinalArray::Constant
|
||||
include OrdinalArray
|
||||
|
||||
def self.respond_to?(method_sym, include_private=false)
|
||||
return true if Array.number_in_letter? method_sym
|
||||
super
|
||||
end
|
||||
|
||||
def method_missing(name, *params)
|
||||
if Array.number_in_letter? name
|
||||
index = index_by_number_in_letter(name, params)
|
||||
|
||||
self.class.send(:define_method, name) do
|
||||
self[index]
|
||||
end
|
||||
|
||||
self.send(name)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.number_in_letter?(name)
|
||||
ordinal_figure = false
|
||||
possible_followers = [:hundred, :decade, :ordinal]
|
||||
|
||||
letter_numbers = name.to_s.split('_').drop_while do |letter_number|
|
||||
return false if ordinal_figure
|
||||
|
||||
figure = Numbers_in_letter.element_by_name(letter_number)
|
||||
return false unless figure
|
||||
return false unless possible_followers.include? figure.to_sym
|
||||
|
||||
possible_followers = figure.can_be_followed_by
|
||||
ordinal_figure = !figure.kind_of?(ComposedOrdinal)
|
||||
|
||||
true
|
||||
end
|
||||
letter_numbers.empty? && ordinal_figure
|
||||
end
|
||||
|
||||
def index_by_number_in_letter(name, *params)
|
||||
partial_sum = 1
|
||||
sum = name.to_s.split('_').inject(0) do |sum, letter_number|
|
||||
number = Numbers_in_letter.element_by_name(letter_number).number
|
||||
if partial_sum < number
|
||||
partial_sum = partial_sum * number
|
||||
else
|
||||
sum = sum + partial_sum
|
||||
partial_sum = number
|
||||
end
|
||||
sum
|
||||
end
|
||||
sum = sum + partial_sum
|
||||
index = sum - 1
|
||||
index > 0 ? index : nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1,71 @@
|
|||
module OrdinalArray
|
||||
|
||||
class Ordinal
|
||||
attr_accessor :number_in_letter, :number, :can_be_followed_by
|
||||
|
||||
def initialize(number_in_letter, number)
|
||||
@number_in_letter = number_in_letter
|
||||
@can_be_followed_by = nil
|
||||
@number = number
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:ordinal
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:hundred]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:ordinal
|
||||
end
|
||||
end
|
||||
|
||||
class DecadeOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = nil
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:decade
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedDecadeOrdinal < ComposedOrdinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:ordinal]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:decade
|
||||
end
|
||||
end
|
||||
|
||||
class HundredOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = nil
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:hundred
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedHundredOrdinal < ComposedDecadeOrdinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:decade, :ordinal]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:hundred
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,84 @@
|
|||
require_relative './ordinal'
|
||||
|
||||
module OrdinalArray
|
||||
module Constant
|
||||
|
||||
First = Ordinal.new("first", 1)
|
||||
One = ComposedOrdinal.new("one", 1)
|
||||
Second = Ordinal.new("second", 2)
|
||||
Two = ComposedOrdinal.new("two", 2)
|
||||
Third = Ordinal.new("third", 3)
|
||||
Three = ComposedOrdinal.new("three", 3)
|
||||
Fourth = Ordinal.new("fourth", 4)
|
||||
Four = ComposedOrdinal.new("four", 4)
|
||||
Fifth = Ordinal.new("fifth", 5)
|
||||
Five = ComposedOrdinal.new("five", 5)
|
||||
Sixth = Ordinal.new("sixth", 6)
|
||||
Six = ComposedOrdinal.new("six", 6)
|
||||
Seventh = Ordinal.new("seventh", 7)
|
||||
Seven = ComposedOrdinal.new("seven", 7)
|
||||
Eighth = Ordinal.new("eighth", 8)
|
||||
Eight = ComposedOrdinal.new("eight", 8)
|
||||
Ninth = Ordinal.new("ninth", 9)
|
||||
Nine = ComposedOrdinal.new("nine", 9)
|
||||
Tenth = DecadeOrdinal.new("tenth", 10)
|
||||
Ten = ComposedDecadeOrdinal.new("ten", 10)
|
||||
Eleventh = DecadeOrdinal.new("eleventh", 11)
|
||||
Eleven = ComposedDecadeOrdinal.new("eleven", 11)
|
||||
Twelfth = DecadeOrdinal.new("twelfth", 12)
|
||||
Twelve = ComposedDecadeOrdinal.new("twelve", 12)
|
||||
Thirteenth = DecadeOrdinal.new("thirteenth", 13)
|
||||
Thirteen = ComposedDecadeOrdinal.new("thirteen", 13)
|
||||
Fourteenth = DecadeOrdinal.new("fourteenth", 14)
|
||||
Fourteen = ComposedDecadeOrdinal.new("fourteen", 14)
|
||||
Fifteenth = DecadeOrdinal.new("fifteenth", 15)
|
||||
Fifteen = ComposedDecadeOrdinal.new("fifteen", 15)
|
||||
Sixteenth = DecadeOrdinal.new("sixteenth", 16)
|
||||
Sixteen = ComposedDecadeOrdinal.new("sixteen", 16)
|
||||
Seventeenth = DecadeOrdinal.new("seventeenth", 17)
|
||||
Seventeen = ComposedDecadeOrdinal.new("seventeen", 17)
|
||||
Eighteenth = DecadeOrdinal.new("eighteenth", 18)
|
||||
Eighteen = ComposedDecadeOrdinal.new("eighteen", 18)
|
||||
Nineteenth = DecadeOrdinal.new("nineteenth", 19)
|
||||
Nineteen = ComposedDecadeOrdinal.new("nineteen", 19)
|
||||
Twentieth = DecadeOrdinal.new("twentieth", 20)
|
||||
Twenty = ComposedDecadeOrdinal.new("twenty", 20)
|
||||
Thirtieth = DecadeOrdinal.new("thirtieth", 30)
|
||||
Thirty = ComposedDecadeOrdinal.new("thirty", 30)
|
||||
Fortieth = DecadeOrdinal.new("fortieth", 40)
|
||||
Fourty = ComposedDecadeOrdinal.new("fourty", 40)
|
||||
Fiftieth = DecadeOrdinal.new("fiftieth", 50)
|
||||
Fifty = ComposedDecadeOrdinal.new("fifty", 50)
|
||||
Sixtieth = DecadeOrdinal.new("sixtieth", 60)
|
||||
Sixty = ComposedDecadeOrdinal.new("sixty", 60)
|
||||
Seventieth = DecadeOrdinal.new("seventieth", 70)
|
||||
Seventy = ComposedDecadeOrdinal.new("seventy", 70)
|
||||
Eightieth = DecadeOrdinal.new("eightieth", 80)
|
||||
Eighty = ComposedDecadeOrdinal.new("eighty", 80)
|
||||
Ninetieth = DecadeOrdinal.new("ninetieth", 90)
|
||||
Ninety = ComposedDecadeOrdinal.new("ninety", 90)
|
||||
Hundredth = HundredOrdinal.new("hundredth", 100)
|
||||
Hundred = ComposedHundredOrdinal.new("hundred", 100)
|
||||
|
||||
Numbers_in_letter = [
|
||||
One, Two, Three, Four, Five, Six, Seven, Eight, Nine,
|
||||
Ten, Eleven, Twelve, Thirteen, Fourteen, Fifteen, Sixteen, Seventeen, Eighteen, Nineteen,
|
||||
Twenty, Thirty, Fourty, Fifty, Sixty, Seventy, Eighty, Ninety,
|
||||
Hundred,
|
||||
|
||||
First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth,
|
||||
Tenth, Eleventh, Twelfth, Thirteenth, Fourteenth, Fifteenth, Sixteenth, Seventeenth, Eighteenth, Nineteenth,
|
||||
Twentieth, Thirtieth, Fortieth, Fiftieth, Sixtieth, Seventieth, Eightieth, Ninetieth,
|
||||
Hundredth
|
||||
]
|
||||
|
||||
class << Numbers_in_letter
|
||||
def element_by_name(name)
|
||||
index = self.index {|n| n.number_in_letter == name }
|
||||
return nil unless index
|
||||
self.[](index)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: ordinal_array 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "ordinal_array".freeze
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["Kevin Disneur".freeze]
|
||||
s.date = "2012-04-08"
|
||||
s.description = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements".freeze
|
||||
s.email = ["kevin.disneur@gmail.com".freeze]
|
||||
s.homepage = "https://github.com/kdisneur/ordinal_array".freeze
|
||||
s.rubygems_version = "2.6.13".freeze
|
||||
s.summary = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements".freeze
|
||||
|
||||
s.installed_by_version = "2.6.13" if s.respond_to? :installed_by_version
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: inspec-test-fixture 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "inspec-test-fixture".freeze
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["InSpec Engineering Team".freeze]
|
||||
s.date = "2018-08-17"
|
||||
s.description = "This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.".freeze
|
||||
s.email = ["hello@chef.io".freeze]
|
||||
s.homepage = "https://github.com/inspec/inspec".freeze
|
||||
s.rubygems_version = "2.6.13".freeze
|
||||
s.summary = "A simple test plugin gem for InSpec".freeze
|
||||
|
||||
s.installed_by_version = "2.6.13" if s.respond_to? :installed_by_version
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
s.specification_version = 4
|
||||
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_development_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
s.add_runtime_dependency(%q<ordinal_array>.freeze, ["~> 0.2.0"])
|
||||
else
|
||||
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
s.add_dependency(%q<ordinal_array>.freeze, ["~> 0.2.0"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
s.add_dependency(%q<ordinal_array>.freeze, ["~> 0.2.0"])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: ordinal_array 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "ordinal_array".freeze
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["Kevin Disneur".freeze]
|
||||
s.date = "2012-04-08"
|
||||
s.description = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements".freeze
|
||||
s.email = ["kevin.disneur@gmail.com".freeze]
|
||||
s.homepage = "https://github.com/kdisneur/ordinal_array".freeze
|
||||
s.rubygems_version = "2.6.13".freeze
|
||||
s.summary = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements".freeze
|
||||
|
||||
s.installed_by_version = "2.6.13" if s.respond_to? :installed_by_version
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
lib = File.expand_path("../lib", __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require "inspec-test-fixture/version"
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "inspec-test-fixture"
|
||||
spec.version = InspecPlugins::TestFixture::VERSION
|
||||
spec.authors = ["InSpec Engineering Team"]
|
||||
spec.email = ["hello@chef.io"]
|
||||
|
||||
spec.summary = %q{A simple test plugin gem for InSpec}
|
||||
spec.description = %q{This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.}
|
||||
spec.homepage = "https://github.com/inspec/inspec"
|
||||
|
||||
spec.files = [
|
||||
'inspec-test-fixture.gemspec',
|
||||
'lib/inspec-test-fixture.rb',
|
||||
'lib/inspec-test-fixture/plugin.rb',
|
||||
'lib/inspec-test-fixture/mock_plugin.rb',
|
||||
'lib/inspec-test-fixture/version.rb',
|
||||
]
|
||||
spec.executables = []
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
if InspecPlugins::TestFixture::VERSION == '0.2.0'
|
||||
spec.add_dependency "ordinal_array", "~> 0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
require 'inspec-test-fixture/plugin'
|
|
@ -0,0 +1,13 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
if InspecPlugins::TestFixture::VERSION == Gem::Version.new('0.2.0')
|
||||
require "ordinal_array"
|
||||
end
|
||||
|
||||
module InspecPlugins::TextFixture
|
||||
class MockPlugin < Inspec.plugin(2, :mock_plugin_type)
|
||||
def execute(opts = {})
|
||||
# Check to see if Array responds to 'third'
|
||||
Array.respond_to?(:third)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
|
||||
class Plugin < Inspec.plugin(2)
|
||||
plugin_name :'inspec-test-fixture'
|
||||
|
||||
mock_plugin_type :'inspec-test-fixture' do
|
||||
require 'mock_plugin'
|
||||
InspecPlugins::TestFixture
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
VERSION = "0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
= Ordinal array
|
||||
|
||||
Ordinal array is a Gem which allows you to access to a value of an array by an ordinal value. You can access to the first element of an array by the "first" method. Now you can access to the second element by "second", the third by "third" and that until the 999th elements.
|
||||
|
||||
Works with Ruby 1.9
|
||||
|
||||
Improve ordinal array speed for multiple calls on the same method on the same array: (Benchmark results: https://gist.github.com/2337544)
|
||||
|
||||
Exemple:
|
||||
my_array = ["value1", "value2", "value3"]
|
||||
puts my_array.third # print: value 3
|
||||
puts my_array.third # print: value 3 (But... much faster!)
|
||||
|
||||
= How to use
|
||||
|
||||
Just add gem "ordinal_array" in your gemfile.
|
||||
It provides you some methods on the basic array class
|
||||
|
||||
Exemple of use:
|
||||
|
||||
my_array = ["value1", "value2", "value3"]
|
||||
puts my_array.third # print: value 3
|
||||
my_array[41] = "it works fine"
|
||||
puts my_array.fourty_second # print: it works fine
|
||||
|
||||
= Contributors
|
||||
|
||||
*Kevin Disneur
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
require_relative './ordinal_array/ordinal'
|
||||
require_relative './ordinal_array/ordinal_constants'
|
||||
|
||||
class Array
|
||||
|
||||
include OrdinalArray::Constant
|
||||
include OrdinalArray
|
||||
|
||||
def self.respond_to?(method_sym, include_private=false)
|
||||
return true if Array.number_in_letter? method_sym
|
||||
super
|
||||
end
|
||||
|
||||
def method_missing(name, *params)
|
||||
if Array.number_in_letter? name
|
||||
index = index_by_number_in_letter(name, params)
|
||||
|
||||
self.class.send(:define_method, name) do
|
||||
self[index]
|
||||
end
|
||||
|
||||
self.send(name)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.number_in_letter?(name)
|
||||
ordinal_figure = false
|
||||
possible_followers = [:hundred, :decade, :ordinal]
|
||||
|
||||
letter_numbers = name.to_s.split('_').drop_while do |letter_number|
|
||||
return false if ordinal_figure
|
||||
|
||||
figure = Numbers_in_letter.element_by_name(letter_number)
|
||||
return false unless figure
|
||||
return false unless possible_followers.include? figure.to_sym
|
||||
|
||||
possible_followers = figure.can_be_followed_by
|
||||
ordinal_figure = !figure.kind_of?(ComposedOrdinal)
|
||||
|
||||
true
|
||||
end
|
||||
letter_numbers.empty? && ordinal_figure
|
||||
end
|
||||
|
||||
def index_by_number_in_letter(name, *params)
|
||||
partial_sum = 1
|
||||
sum = name.to_s.split('_').inject(0) do |sum, letter_number|
|
||||
number = Numbers_in_letter.element_by_name(letter_number).number
|
||||
if partial_sum < number
|
||||
partial_sum = partial_sum * number
|
||||
else
|
||||
sum = sum + partial_sum
|
||||
partial_sum = number
|
||||
end
|
||||
sum
|
||||
end
|
||||
sum = sum + partial_sum
|
||||
index = sum - 1
|
||||
index > 0 ? index : nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1,71 @@
|
|||
module OrdinalArray
|
||||
|
||||
class Ordinal
|
||||
attr_accessor :number_in_letter, :number, :can_be_followed_by
|
||||
|
||||
def initialize(number_in_letter, number)
|
||||
@number_in_letter = number_in_letter
|
||||
@can_be_followed_by = nil
|
||||
@number = number
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:ordinal
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:hundred]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:ordinal
|
||||
end
|
||||
end
|
||||
|
||||
class DecadeOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = nil
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:decade
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedDecadeOrdinal < ComposedOrdinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:ordinal]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:decade
|
||||
end
|
||||
end
|
||||
|
||||
class HundredOrdinal < Ordinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = nil
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:hundred
|
||||
end
|
||||
end
|
||||
|
||||
class ComposedHundredOrdinal < ComposedDecadeOrdinal
|
||||
def initialize(number_in_letter, number)
|
||||
super(number_in_letter, number)
|
||||
@can_be_followed_by = [:decade, :ordinal]
|
||||
end
|
||||
|
||||
def to_sym
|
||||
:hundred
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,84 @@
|
|||
require_relative './ordinal'
|
||||
|
||||
module OrdinalArray
|
||||
module Constant
|
||||
|
||||
First = Ordinal.new("first", 1)
|
||||
One = ComposedOrdinal.new("one", 1)
|
||||
Second = Ordinal.new("second", 2)
|
||||
Two = ComposedOrdinal.new("two", 2)
|
||||
Third = Ordinal.new("third", 3)
|
||||
Three = ComposedOrdinal.new("three", 3)
|
||||
Fourth = Ordinal.new("fourth", 4)
|
||||
Four = ComposedOrdinal.new("four", 4)
|
||||
Fifth = Ordinal.new("fifth", 5)
|
||||
Five = ComposedOrdinal.new("five", 5)
|
||||
Sixth = Ordinal.new("sixth", 6)
|
||||
Six = ComposedOrdinal.new("six", 6)
|
||||
Seventh = Ordinal.new("seventh", 7)
|
||||
Seven = ComposedOrdinal.new("seven", 7)
|
||||
Eighth = Ordinal.new("eighth", 8)
|
||||
Eight = ComposedOrdinal.new("eight", 8)
|
||||
Ninth = Ordinal.new("ninth", 9)
|
||||
Nine = ComposedOrdinal.new("nine", 9)
|
||||
Tenth = DecadeOrdinal.new("tenth", 10)
|
||||
Ten = ComposedDecadeOrdinal.new("ten", 10)
|
||||
Eleventh = DecadeOrdinal.new("eleventh", 11)
|
||||
Eleven = ComposedDecadeOrdinal.new("eleven", 11)
|
||||
Twelfth = DecadeOrdinal.new("twelfth", 12)
|
||||
Twelve = ComposedDecadeOrdinal.new("twelve", 12)
|
||||
Thirteenth = DecadeOrdinal.new("thirteenth", 13)
|
||||
Thirteen = ComposedDecadeOrdinal.new("thirteen", 13)
|
||||
Fourteenth = DecadeOrdinal.new("fourteenth", 14)
|
||||
Fourteen = ComposedDecadeOrdinal.new("fourteen", 14)
|
||||
Fifteenth = DecadeOrdinal.new("fifteenth", 15)
|
||||
Fifteen = ComposedDecadeOrdinal.new("fifteen", 15)
|
||||
Sixteenth = DecadeOrdinal.new("sixteenth", 16)
|
||||
Sixteen = ComposedDecadeOrdinal.new("sixteen", 16)
|
||||
Seventeenth = DecadeOrdinal.new("seventeenth", 17)
|
||||
Seventeen = ComposedDecadeOrdinal.new("seventeen", 17)
|
||||
Eighteenth = DecadeOrdinal.new("eighteenth", 18)
|
||||
Eighteen = ComposedDecadeOrdinal.new("eighteen", 18)
|
||||
Nineteenth = DecadeOrdinal.new("nineteenth", 19)
|
||||
Nineteen = ComposedDecadeOrdinal.new("nineteen", 19)
|
||||
Twentieth = DecadeOrdinal.new("twentieth", 20)
|
||||
Twenty = ComposedDecadeOrdinal.new("twenty", 20)
|
||||
Thirtieth = DecadeOrdinal.new("thirtieth", 30)
|
||||
Thirty = ComposedDecadeOrdinal.new("thirty", 30)
|
||||
Fortieth = DecadeOrdinal.new("fortieth", 40)
|
||||
Fourty = ComposedDecadeOrdinal.new("fourty", 40)
|
||||
Fiftieth = DecadeOrdinal.new("fiftieth", 50)
|
||||
Fifty = ComposedDecadeOrdinal.new("fifty", 50)
|
||||
Sixtieth = DecadeOrdinal.new("sixtieth", 60)
|
||||
Sixty = ComposedDecadeOrdinal.new("sixty", 60)
|
||||
Seventieth = DecadeOrdinal.new("seventieth", 70)
|
||||
Seventy = ComposedDecadeOrdinal.new("seventy", 70)
|
||||
Eightieth = DecadeOrdinal.new("eightieth", 80)
|
||||
Eighty = ComposedDecadeOrdinal.new("eighty", 80)
|
||||
Ninetieth = DecadeOrdinal.new("ninetieth", 90)
|
||||
Ninety = ComposedDecadeOrdinal.new("ninety", 90)
|
||||
Hundredth = HundredOrdinal.new("hundredth", 100)
|
||||
Hundred = ComposedHundredOrdinal.new("hundred", 100)
|
||||
|
||||
Numbers_in_letter = [
|
||||
One, Two, Three, Four, Five, Six, Seven, Eight, Nine,
|
||||
Ten, Eleven, Twelve, Thirteen, Fourteen, Fifteen, Sixteen, Seventeen, Eighteen, Nineteen,
|
||||
Twenty, Thirty, Fourty, Fifty, Sixty, Seventy, Eighty, Ninety,
|
||||
Hundred,
|
||||
|
||||
First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth,
|
||||
Tenth, Eleventh, Twelfth, Thirteenth, Fourteenth, Fifteenth, Sixteenth, Seventeenth, Eighteenth, Nineteenth,
|
||||
Twentieth, Thirtieth, Fortieth, Fiftieth, Sixtieth, Seventieth, Eightieth, Ninetieth,
|
||||
Hundredth
|
||||
]
|
||||
|
||||
class << Numbers_in_letter
|
||||
def element_by_name(name)
|
||||
index = self.index {|n| n.number_in_letter == name }
|
||||
return nil unless index
|
||||
self.[](index)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: ordinal_array 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "ordinal_array".freeze
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["Kevin Disneur".freeze]
|
||||
s.date = "2012-04-08"
|
||||
s.description = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements".freeze
|
||||
s.email = ["kevin.disneur@gmail.com".freeze]
|
||||
s.homepage = "https://github.com/kdisneur/ordinal_array".freeze
|
||||
s.rubygems_version = "2.7.6".freeze
|
||||
s.summary = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements".freeze
|
||||
|
||||
s.installed_by_version = "2.7.6" if s.respond_to? :installed_by_version
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: inspec-test-fixture 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "inspec-test-fixture".freeze
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["InSpec Engineering Team".freeze]
|
||||
s.date = "2018-08-17"
|
||||
s.description = "This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.".freeze
|
||||
s.email = ["hello@chef.io".freeze]
|
||||
s.homepage = "https://github.com/inspec/inspec".freeze
|
||||
s.rubygems_version = "2.7.6".freeze
|
||||
s.summary = "A simple test plugin gem for InSpec".freeze
|
||||
|
||||
s.installed_by_version = "2.7.6" if s.respond_to? :installed_by_version
|
||||
|
||||
if s.respond_to? :specification_version then
|
||||
s.specification_version = 4
|
||||
|
||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||
s.add_development_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
s.add_runtime_dependency(%q<ordinal_array>.freeze, ["~> 0.2.0"])
|
||||
else
|
||||
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
s.add_dependency(%q<ordinal_array>.freeze, ["~> 0.2.0"])
|
||||
end
|
||||
else
|
||||
s.add_dependency(%q<rake>.freeze, ["~> 10.0"])
|
||||
s.add_dependency(%q<ordinal_array>.freeze, ["~> 0.2.0"])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
# stub: ordinal_array 0.2.0 ruby lib
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "ordinal_array".freeze
|
||||
s.version = "0.2.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
||||
s.require_paths = ["lib".freeze]
|
||||
s.authors = ["Kevin Disneur".freeze]
|
||||
s.date = "2012-04-08"
|
||||
s.description = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements".freeze
|
||||
s.email = ["kevin.disneur@gmail.com".freeze]
|
||||
s.homepage = "https://github.com/kdisneur/ordinal_array".freeze
|
||||
s.rubygems_version = "2.7.6".freeze
|
||||
s.summary = "You can access to the first element of an array by the 'first' method. Now you can access to the second element by 'second' and that until the 999th elements".freeze
|
||||
|
||||
s.installed_by_version = "2.7.6" if s.respond_to? :installed_by_version
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"plugins_config_version" : "1.0.0",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "inspec-test-fixture"
|
||||
}
|
||||
]
|
||||
}
|
6
test/unit/mock/plugins/inspec-test-fixture/README.md
Normal file
6
test/unit/mock/plugins/inspec-test-fixture/README.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
This directory is the source code for the RubyGem inspec-test-fixture, which is published on rubygems.org for testing.
|
||||
|
||||
In version 0.1.0, it has no dependencies.
|
||||
In version 0.2.0, it depends on ordinal_array.
|
||||
|
||||
In both versions, it implements a mock_plugin, whose execute() method checks to see if Array responds to :third.
|
1
test/unit/mock/plugins/inspec-test-fixture/Rakefile
Normal file
1
test/unit/mock/plugins/inspec-test-fixture/Rakefile
Normal file
|
@ -0,0 +1 @@
|
|||
require "bundler/gem_tasks"
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
lib = File.expand_path("../lib", __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require "inspec-test-fixture/version"
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "inspec-test-fixture"
|
||||
spec.version = InspecPlugins::TestFixture::VERSION
|
||||
spec.authors = ["InSpec Engineering Team"]
|
||||
spec.email = ["hello@chef.io"]
|
||||
|
||||
spec.summary = %q{A simple test plugin gem for InSpec}
|
||||
spec.description = %q{This gem is used to test the gem search and install capabilities of InSpec's plugin V2 system. It is not a good example or starting point for plugin development.}
|
||||
spec.homepage = "https://github.com/inspec/inspec"
|
||||
|
||||
spec.files = [
|
||||
'inspec-test-fixture.gemspec',
|
||||
'lib/inspec-test-fixture.rb',
|
||||
'lib/inspec-test-fixture/plugin.rb',
|
||||
'lib/inspec-test-fixture/mock_plugin.rb',
|
||||
'lib/inspec-test-fixture/version.rb',
|
||||
]
|
||||
spec.executables = []
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
if InspecPlugins::TestFixture::VERSION == '0.2.0'
|
||||
spec.add_dependency "ordinal_array", "~> 0.2.0"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
require 'inspec-test-fixture/plugin'
|
|
@ -0,0 +1,13 @@
|
|||
require 'inspec-test-fixture/version'
|
||||
if InspecPlugins::TestFixture::VERSION == Gem::Version.new('0.2.0')
|
||||
require "ordinal_array"
|
||||
end
|
||||
|
||||
module InspecPlugins::TextFixture
|
||||
class MockPlugin < Inspec.plugin(2, :mock_plugin_type)
|
||||
def execute(opts = {})
|
||||
# Check to see if Array responds to 'third'
|
||||
Array.respond_to?(:third)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
|
||||
class Plugin < Inspec.plugin(2)
|
||||
plugin_name :'inspec-test-fixture'
|
||||
|
||||
mock_plugin_type :'inspec-test-fixture' do
|
||||
require 'mock_plugin'
|
||||
InspecPlugins::TestFixture
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module InspecPlugins
|
||||
module TestFixture
|
||||
VERSION = "0.1.0"
|
||||
end
|
||||
end
|
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
require 'inspec-meaning-of-life-cli/plugin'
|
|
@ -1,13 +0,0 @@
|
|||
module InspecPlugins
|
||||
module MeaningOfLife
|
||||
class Cli < Inspec.plugin(2, :cli)
|
||||
|
||||
# Do cli-ish things
|
||||
def execute(opts)
|
||||
puts 'The answer to life, the universe, and everything:'
|
||||
puts '42'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
module InspecPlugins
|
||||
module MeaningOfLife
|
||||
|
||||
class Plugin < Inspec.plugin(2)
|
||||
plugin_name :meaning_of_life
|
||||
# cli 'meaning-of-life-the-universe-and-everything' do
|
||||
# require_relative './cli'
|
||||
# InspecPlugins::MeaningOfLife::Cli
|
||||
# end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
438
test/unit/plugin/v2/installer_test.rb
Normal file
438
test/unit/plugin/v2/installer_test.rb
Normal file
|
@ -0,0 +1,438 @@
|
|||
require 'minitest/autorun'
|
||||
require 'minitest/test'
|
||||
# Other unit tests include the webmock framework, which is process-wide.
|
||||
# We need to disable it, or else mock many, many rubygems API calls.
|
||||
require 'webmock/minitest'
|
||||
|
||||
require 'fileutils'
|
||||
require 'json'
|
||||
require_relative '../../../../lib/inspec/plugin/v2'
|
||||
require_relative '../../../../lib/inspec/plugin/v2/installer'
|
||||
|
||||
require 'byebug'
|
||||
|
||||
module InstallerTestHelpers
|
||||
def reset_globals
|
||||
ENV['HOME'] = @orig_home
|
||||
ENV['INSPEC_CONFIG_DIR'] = nil
|
||||
@installer.__reset
|
||||
end
|
||||
|
||||
def copy_in_config_dir(fixture_name)
|
||||
src = Dir.glob(File.join(@config_dir_path, fixture_name, '*'))
|
||||
dest = File.join(@config_dir_path, 'empty')
|
||||
src.each { |path| FileUtils.cp_r(path, dest) }
|
||||
end
|
||||
|
||||
def setup
|
||||
@orig_home = Dir.home
|
||||
|
||||
repo_path = File.expand_path(File.join( __FILE__, '..', '..', '..', '..', '..'))
|
||||
mock_path = File.join(repo_path, 'test', 'unit', 'mock')
|
||||
@config_dir_path = File.join(mock_path, 'config_dirs')
|
||||
@plugin_fixture_src_path = File.join(mock_path, 'plugins', 'inspec-test-fixture')
|
||||
@plugin_fixture_pkg_path = File.join(@plugin_fixture_src_path, 'pkg')
|
||||
|
||||
# This is unstable under CI; see https://github.com/inspec/inspec/issues/3355
|
||||
# @ruby_abi_version = (RUBY_VERSION.split('.')[0,2] << '0').join('.')
|
||||
@ruby_abi_version = (Gem.ruby_version.segments[0, 2] << 0).join('.')
|
||||
|
||||
@installer = Inspec::Plugin::V2::Installer.instance
|
||||
reset_globals
|
||||
WebMock.disable_net_connect!(allow: 'api.rubygems.org')
|
||||
end
|
||||
|
||||
def teardown
|
||||
reset_globals
|
||||
|
||||
# We use the 'empty' config dir for exercising a lot of installs.
|
||||
# Purge it after every test.
|
||||
unless ENV['INSPEC_TEST_PRESERVE_PLUGIN']
|
||||
Dir.glob(File.join(@config_dir_path, 'empty', '*')).each do |path|
|
||||
next if path.end_with? '.gitkeep'
|
||||
FileUtils.rm_rf(path)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: may need to edit the $LOAD_PATH, if it turns out that we need to "deactivate" gems after installation
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------#
|
||||
# basics
|
||||
#-----------------------------------------------------------------------#
|
||||
class PluginInstallerBasicTests < MiniTest::Test
|
||||
include InstallerTestHelpers
|
||||
|
||||
# it's a singleton
|
||||
def test_it_should_be_a_singleton
|
||||
klass = Inspec::Plugin::V2::Installer
|
||||
assert_equal klass.instance, klass.instance, "Calling instance on the Installer should always return the same object"
|
||||
assert_kind_of Inspec::Plugin::V2::Installer, klass.instance, 'Calling instance on the INstaller should return the right class'
|
||||
assert_raises(NoMethodError, 'Installer should have a private constructor') { klass.new }
|
||||
end
|
||||
|
||||
# it should know its gem path
|
||||
def test_it_should_know_its_gem_path_with_a_default_location
|
||||
ENV['HOME'] = File.join(@config_dir_path, 'fakehome')
|
||||
expected = File.join(ENV['HOME'], '.inspec', 'gems', @ruby_abi_version)
|
||||
assert_equal expected, @installer.gem_path
|
||||
end
|
||||
|
||||
def test_it_should_know_its_gem_path_with_a_custom_config_dir_from_env
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
expected = File.join(ENV['INSPEC_CONFIG_DIR'], 'gems', @ruby_abi_version)
|
||||
assert_equal expected, @installer.gem_path
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------#
|
||||
# Installing
|
||||
#-----------------------------------------------------------------------#
|
||||
class PluginInstallerInstallationTests < MiniTest::Test
|
||||
include InstallerTestHelpers
|
||||
|
||||
# While this is a negative test case on the prefix checking, there are
|
||||
# several positive test cases following.
|
||||
def test_refuse_to_install_gems_with_wrong_name_prefix
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
# Here, ordinal_array is the name of a simple, small gem available on rubygems.org
|
||||
# There is no significance in choosing that gem over any other.
|
||||
# Main point here is that its name does not begin with 'inspec-'.
|
||||
assert_raises(Inspec::Plugin::V2::InstallError) { @installer.install('ordinal_array')}
|
||||
end
|
||||
|
||||
def test_install_a_gem_from_local_file
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
gem_file = File.join(@plugin_fixture_pkg_path, 'inspec-test-fixture-0.1.0.gem')
|
||||
@installer.install('inspec-test-fixture', gem_file: gem_file)
|
||||
# Because no exception was thrown, this is a positive test case for prefix-checking.
|
||||
|
||||
# Installing a gem places it under the config dir gem area
|
||||
# Two things should happen: a copy of the gemspec should be left there...
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.1.0.gemspec')
|
||||
assert File.exist?(spec_path), 'After installation from a gem file, the gemspec should be installed to the gem path'
|
||||
# ... and the actual library code should be decompressed into a directory tree.
|
||||
installed_gem_base = File.join(@installer.gem_path, 'gems', 'inspec-test-fixture-0.1.0')
|
||||
assert Dir.exist?(installed_gem_base), 'After installation from a gem file, the gem tree should be installed to the gem path'
|
||||
|
||||
# Installation != gem activation
|
||||
spec = Gem::Specification.load(spec_path)
|
||||
refute spec.activated?, 'Installing a gem should not cause the gem to activate'
|
||||
end
|
||||
|
||||
def test_install_a_gem_from_missing_local_file
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
gem_file = File.join(@plugin_fixture_pkg_path, 'inspec-test-fixture-nonesuch-0.0.0.gem')
|
||||
refute File.exist?(gem_file), "The nonexistant gem should not exist prior to install attempt"
|
||||
ex = assert_raises(Inspec::Plugin::V2::InstallError) { @installer.install('inspec-test-fixture-nonesuch', gem_file: gem_file)}
|
||||
assert_includes ex.message, 'Could not find local gem file'
|
||||
end
|
||||
|
||||
def test_install_a_gem_from_local_file_creates_plugin_json
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
gem_file = File.join(@plugin_fixture_pkg_path, 'inspec-test-fixture-0.1.0.gem')
|
||||
@installer.install('inspec-test-fixture', gem_file: gem_file)
|
||||
|
||||
# Should now be present in plugin.json
|
||||
plugin_json_path = File.join(ENV['INSPEC_CONFIG_DIR'], 'plugins.json')
|
||||
assert File.exist?(plugin_json_path), 'plugins.json should now exist'
|
||||
plugin_json_data = JSON.parse(File.read(plugin_json_path))
|
||||
|
||||
assert_includes plugin_json_data.keys, 'plugins_config_version'
|
||||
assert_equal '1.0.0', plugin_json_data['plugins_config_version'], 'Plugin config version should ve initted to 1.0.0'
|
||||
assert_includes plugin_json_data.keys, 'plugins'
|
||||
assert_kind_of Array, plugin_json_data['plugins']
|
||||
assert_equal 1, plugin_json_data['plugins'].count, 'plugins.json should have one entry'
|
||||
entry = plugin_json_data['plugins'].first
|
||||
assert_kind_of Hash, entry
|
||||
assert_includes entry.keys, 'name'
|
||||
assert_equal 'inspec-test-fixture', entry['name']
|
||||
# TODO: any other fields to check? gem version?
|
||||
end
|
||||
|
||||
def test_install_a_gem_from_rubygems_org
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
@installer.install('inspec-test-fixture')
|
||||
# Because no exception was thrown, this is a positive test case for prefix-checking.
|
||||
|
||||
# Installing a gem places it under the config dir gem area
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.2.0.gemspec')
|
||||
assert File.exist?(spec_path), 'After installation from rubygems.org, the gemspec should be installed to the gem path'
|
||||
installed_gem_base = File.join(@installer.gem_path, 'gems', 'inspec-test-fixture-0.2.0')
|
||||
assert Dir.exist?(installed_gem_base), 'After installation from rubygems.org, the gem tree should be installed to the gem path'
|
||||
|
||||
# installing a gem with dependencies should result in the deps being installed under the config dir
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'ordinal_array-0.2.0.gemspec')
|
||||
assert File.exist?(spec_path), 'After installation from a gem file, the gemspec should be installed to the gem path'
|
||||
installed_gem_base = File.join(@installer.gem_path, 'gems', 'inspec-test-fixture-0.2.0')
|
||||
assert Dir.exist?(installed_gem_base), 'After installation from a gem file, the gem tree should be installed to the gem path'
|
||||
|
||||
# Installation != gem activation
|
||||
spec = Gem::Specification.load(spec_path)
|
||||
refute spec.activated?, 'Installing a gem should not cause the gem to activate'
|
||||
end
|
||||
|
||||
def test_handle_no_such_gem
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
assert_raises(Inspec::Plugin::V2::InstallError) { @installer.install('inspec-test-fixture-nonesuch') }
|
||||
end
|
||||
|
||||
# Should be able to install a plugin while pinning the version
|
||||
def test_install_a_pinned_gem_from_rubygems_org
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
@installer.install('inspec-test-fixture', version: '= 0.1.0')
|
||||
|
||||
# Installing a gem places it under the config dir gem area
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.1.0.gemspec')
|
||||
assert File.exist?(spec_path), 'After pinned installation from rubygems.org, the gemspec should be installed to the gem path'
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.2.0.gemspec')
|
||||
refute File.exist?(spec_path), 'After pinned installation from rubygems.org, the wrong gemspec version should be absent'
|
||||
|
||||
plugin_json_path = File.join(ENV['INSPEC_CONFIG_DIR'], 'plugins.json')
|
||||
plugin_json_data = JSON.parse(File.read(plugin_json_path))
|
||||
entry = plugin_json_data['plugins'].detect { |e| e["name"] == 'inspec-test-fixture'}
|
||||
assert_includes entry.keys, 'version', 'plugins.json should include version pinning key'
|
||||
assert_equal '= 0.1.0', entry['version'], 'plugins.json should include version pinning value'
|
||||
end
|
||||
|
||||
def test_install_a_plugin_from_a_path
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
@installer.install('inspec-test-fixture', path: @plugin_fixture_src_path)
|
||||
|
||||
# No gemspec should exist in the plugins area
|
||||
specs = Dir.glob(File.join(@installer.gem_path, 'specifications', '*.gemspec'))
|
||||
assert_empty specs, 'After install-from-path, no gemspecs should be installed'
|
||||
|
||||
plugin_json_path = File.join(ENV['INSPEC_CONFIG_DIR'], 'plugins.json')
|
||||
plugin_json_data = JSON.parse(File.read(plugin_json_path))
|
||||
entry = plugin_json_data['plugins'].detect { |e| e["name"] == 'inspec-test-fixture'}
|
||||
assert_includes entry.keys, 'installation_type', 'plugins.json should include installation_type key'
|
||||
assert_equal 'path', entry['installation_type'], 'plugins.json should include path installation_type'
|
||||
|
||||
assert_includes entry.keys, 'installation_path', 'plugins.json should include installation_path key'
|
||||
assert_equal @plugin_fixture_src_path, entry['installation_path'], 'plugins.json should include correct value for installation path'
|
||||
end
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------#
|
||||
# Updating
|
||||
#-----------------------------------------------------------------------#
|
||||
class PluginInstallerUpdaterTests < MiniTest::Test
|
||||
include InstallerTestHelpers
|
||||
|
||||
def test_update_using_path_not_allowed
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
assert_raises(Inspec::Plugin::V2::UpdateError) do
|
||||
@installer.update('inspec-test-fixture', path: @plugin_fixture_src_path)
|
||||
end
|
||||
end
|
||||
|
||||
def test_update_existing_plugin_at_same_version_not_allowed
|
||||
copy_in_config_dir('test-fixture-1-float')
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
assert_raises(Inspec::Plugin::V2::UpdateError) do
|
||||
@installer.update('inspec-test-fixture', version: '0.1.0')
|
||||
end
|
||||
end
|
||||
|
||||
def test_install_plugin_at_existing_version_not_allowed
|
||||
copy_in_config_dir('test-fixture-1-float')
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
assert_raises(Inspec::Plugin::V2::InstallError) do
|
||||
@installer.install('inspec-test-fixture', version: '0.1.0')
|
||||
end
|
||||
end
|
||||
|
||||
def test_install_existing_plugin_not_allowed
|
||||
copy_in_config_dir('test-fixture-1-float')
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
|
||||
ex = assert_raises(Inspec::Plugin::V2::InstallError) do
|
||||
@installer.install('inspec-test-fixture')
|
||||
end
|
||||
assert_includes ex.message, "Use 'inspec plugin update'"
|
||||
end
|
||||
|
||||
def test_update_to_latest_version
|
||||
copy_in_config_dir('test-fixture-1-float')
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
@installer.__reset_loader
|
||||
@installer.update('inspec-test-fixture')
|
||||
|
||||
# Verify presence of gemspecs
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.2.0.gemspec')
|
||||
assert File.exist?(spec_path), 'After update, the 0.2.0 gemspec should be installed to the gem path'
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.1.0.gemspec')
|
||||
assert File.exist?(spec_path), 'After update, the 0.1.0 gemspec should remain'
|
||||
|
||||
# Plugins file entry should not be version pinned
|
||||
plugin_json_path = File.join(ENV['INSPEC_CONFIG_DIR'], 'plugins.json')
|
||||
plugin_json_data = JSON.parse(File.read(plugin_json_path))
|
||||
entry = plugin_json_data['plugins'].detect { |e| e["name"] == 'inspec-test-fixture'}
|
||||
refute_includes entry.keys, 'version', 'plugins.json should NOT include version pinning key'
|
||||
end
|
||||
|
||||
def test_update_to_specified_later_version
|
||||
copy_in_config_dir('test-fixture-1-float')
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
@installer.__reset_loader
|
||||
|
||||
# Update to specific (but later) version
|
||||
@installer.update('inspec-test-fixture', version: '0.2.0')
|
||||
|
||||
# Verify presence of gemspecs
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.2.0.gemspec')
|
||||
assert File.exist?(spec_path), 'After update, the 0.2.0 gemspec should be installed to the gem path'
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.1.0.gemspec')
|
||||
assert File.exist?(spec_path), 'After update, the 0.1.0 gemspec should remain'
|
||||
|
||||
# Plugins file entry should be version pinned
|
||||
plugin_json_path = File.join(ENV['INSPEC_CONFIG_DIR'], 'plugins.json')
|
||||
plugin_json_data = JSON.parse(File.read(plugin_json_path))
|
||||
entry = plugin_json_data['plugins'].detect { |e| e["name"] == 'inspec-test-fixture'}
|
||||
assert_includes entry.keys, 'version', 'plugins.json should include version pinning key'
|
||||
assert_equal '= 0.2.0', entry['version'], 'plugins.json should include version pinning value'
|
||||
end
|
||||
|
||||
# TODO: Prevent updating a gem if it will lead to unsolveable dependencies
|
||||
# TODO: allow updating a gem that will lead to unsolveable dependencies if :force is provided
|
||||
# TODO: Prevent downgrading a gem if it will lead to unsolveable dependencies
|
||||
# TODO: allow downgrading a gem that will lead to unsolveable dependencies if :force is provided
|
||||
# TODO: update all
|
||||
# TODO: downgrade a plugin
|
||||
# TODO: Trying to do a gemfile install with an update is an error if the file version matches the installed version
|
||||
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------#
|
||||
# Uninstalling
|
||||
#-----------------------------------------------------------------------#
|
||||
class PluginInstallerUninstallTests < MiniTest::Test
|
||||
include InstallerTestHelpers
|
||||
|
||||
def test_uninstalling_a_nonexistant_plugin_is_an_error
|
||||
# Try a mythical one
|
||||
ex = assert_raises(Inspec::Plugin::V2::UnInstallError) do
|
||||
@installer.uninstall('inspec-test-fixture-nonesuch')
|
||||
end
|
||||
assert_includes ex.message, "'inspec-test-fixture-nonesuch' is not installed, refusing to uninstall."
|
||||
|
||||
# Try a real plugin that is not installed
|
||||
ex = assert_raises(Inspec::Plugin::V2::UnInstallError) do
|
||||
@installer.uninstall('inspec-test-fixture')
|
||||
end
|
||||
assert_includes ex.message, "'inspec-test-fixture' is not installed, refusing to uninstall."
|
||||
end
|
||||
|
||||
def test_uninstalling_a_path_based_plugin_works
|
||||
copy_in_config_dir('meaning_by_path')
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
@installer.__reset_loader
|
||||
|
||||
@installer.uninstall('inspec-meaning-of-life')
|
||||
|
||||
# Plugins file entry should be removed
|
||||
plugin_json_path = File.join(ENV['INSPEC_CONFIG_DIR'], 'plugins.json')
|
||||
plugin_json_data = JSON.parse(File.read(plugin_json_path))
|
||||
entries = plugin_json_data['plugins'].select { |e| e["name"] == 'inspec-meaning-of-life'}
|
||||
assert_empty entries, "After path-based uninstall, plugin name should be removed from plugins.json"
|
||||
|
||||
end
|
||||
|
||||
def test_uninstall_a_gem_plugin
|
||||
copy_in_config_dir('test-fixture-1-float')
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
@installer.__reset_loader
|
||||
|
||||
@installer.uninstall('inspec-test-fixture')
|
||||
|
||||
# UnInstalling a gem physically removes the gemspec and the gem library code
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.1.0.gemspec')
|
||||
refute File.exist?(spec_path), 'After uninstallation of a gem plugin, the gemspec should be removed.'
|
||||
installed_gem_base = File.join(@installer.gem_path, 'gems', 'inspec-test-fixture-0.1.0')
|
||||
refute Dir.exist?(installed_gem_base), 'After uninstallation of a gem plugin, the gem tree should be removed.'
|
||||
|
||||
# Rubygems' idea of what we have installed should be changed.
|
||||
# It should no longer be able to satisfy a request for the formerly installed gem.
|
||||
universe_set = @installer.send(:build_gem_request_universe) # private method
|
||||
request_set = Gem::RequestSet.new(Gem::Dependency.new('inspec-test-fixture'))
|
||||
assert_raises(Gem::UnsatisfiableDependencyError) { request_set.resolve(universe_set) }
|
||||
|
||||
# Plugins file entry should be removed
|
||||
plugin_json_path = File.join(ENV['INSPEC_CONFIG_DIR'], 'plugins.json')
|
||||
plugin_json_data = JSON.parse(File.read(plugin_json_path))
|
||||
entries = plugin_json_data['plugins'].select { |e| e["name"] == 'inspec-test-fixture'}
|
||||
assert_empty entries, "After gem-based uninstall, plugin name should be removed from plugins.json"
|
||||
end
|
||||
|
||||
def test_uninstall_a_gem_plugin_removes_deps
|
||||
copy_in_config_dir('test-fixture-2-float')
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'empty')
|
||||
@installer.__reset_loader
|
||||
|
||||
@installer.uninstall('inspec-test-fixture')
|
||||
|
||||
# UnInstalling a gem removes the gemspec and the gem library code
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'inspec-test-fixture-0.2.0.gemspec')
|
||||
refute File.exist?(spec_path), 'After uninstallation of a gem plugin with deps, the gemspec should be removed.'
|
||||
installed_gem_base = File.join(@installer.gem_path, 'gems', 'inspec-test-fixture-0.2.0')
|
||||
refute Dir.exist?(installed_gem_base), 'After uninstallation of a gem plugin with deps, the gem tree should be removed.'
|
||||
|
||||
# UnInstalling a gem with dependencies should result in the deps being removed
|
||||
spec_path = File.join(@installer.gem_path, 'specifications', 'ordinal_array-0.2.0.gemspec')
|
||||
refute File.exist?(spec_path), 'After uninstallation of a gem plugin with deps, the dep gemspec should be removed.'
|
||||
installed_gem_base = File.join(@installer.gem_path, 'gems', 'ordinal_array-0.2.0')
|
||||
refute Dir.exist?(installed_gem_base), 'After installation a gem plugin with deps, the gem tree should be removed.'
|
||||
|
||||
# Rubygems' idea of what we have installed should be changed.
|
||||
# It should no longer be able to satisfy a request for the formerly installed *dependency*
|
||||
universe_set = @installer.send(:build_gem_request_universe) # private method
|
||||
request_set = Gem::RequestSet.new(Gem::Dependency.new('ordinal_array'))
|
||||
assert_raises(Gem::UnsatisfiableDependencyError) { request_set.resolve(universe_set) }
|
||||
end
|
||||
|
||||
# TODO: Able to uninstall a specific version of a gem plugin
|
||||
# TODO: Prevent removing a gem if it will lead to unsolveable dependencies
|
||||
# TODO: Allow removing a gem that will lead to unsolveable dependencies if :force is provided
|
||||
end
|
||||
|
||||
#-----------------------------------------------------------------------#
|
||||
# Searching
|
||||
#-----------------------------------------------------------------------#
|
||||
class PluginInstallerSearchTests < MiniTest::Test
|
||||
include InstallerTestHelpers
|
||||
|
||||
def test_search_for_plugin_by_exact_name
|
||||
results = @installer.search('inspec-test-fixture', exact: true)
|
||||
assert_kind_of Hash, results, 'Results from searching should be a Hash'
|
||||
assert results.key?('inspec-test-fixture'), 'Search results should have a key for the sought plugin'
|
||||
assert_equal 1, results.count, 'There should be exactly one search result'
|
||||
version_list = results['inspec-test-fixture']
|
||||
assert_includes version_list, '0.1.0', 'Version list should contain 0.1.0'
|
||||
assert_includes version_list, '0.2.0', 'Version list should contain 0.2.0'
|
||||
end
|
||||
|
||||
def test_search_for_plugin_that_does_not_exist
|
||||
results = @installer.search('inspec-test-fixture-nonesuch', exact: true)
|
||||
assert_empty results
|
||||
end
|
||||
|
||||
def test_search_for_plugin_by_wildard
|
||||
results = @installer.search('inspec-test-')
|
||||
assert_kind_of Hash, results, 'Results from searching should be a Hash'
|
||||
assert results.key?('inspec-test-fixture'), 'Search results should have a key for at least one plugin'
|
||||
version_list = results['inspec-test-fixture']
|
||||
assert_includes version_list, '0.1.0', 'Version list should contain 0.1.0'
|
||||
assert_includes version_list, '0.2.0', 'Version list should contain 0.2.0'
|
||||
end
|
||||
end
|
||||
|
|
@ -152,6 +152,35 @@ class PluginLoaderTests < MiniTest::Test
|
|||
assert reg.loaded_plugin?(plugin_name), "\n#{plugin_name} should be loaded"
|
||||
end
|
||||
|
||||
def test_list_managed_gems
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'test-fixture-2-float')
|
||||
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true)
|
||||
gemspecs = loader.list_managed_gems
|
||||
gem = gemspecs.detect { |spec| spec.name == 'ordinal_array' }
|
||||
refute_nil gem, 'loader.list_managed_gems should find ordinal_array'
|
||||
assert_equal Gem::Version.new('0.2.0'), gem.version
|
||||
end
|
||||
|
||||
def test_list_installed_plugin_gems
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'test-fixture-1-float')
|
||||
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true)
|
||||
gemspecs = loader.list_installed_plugin_gems
|
||||
gem = gemspecs.detect { |spec| spec.name == 'inspec-test-fixture' }
|
||||
refute_nil gem, 'loader.list_installed_plugin_gems should find inspec-test-fixture'
|
||||
assert_equal Gem::Version.new('0.1.0'), gem.version
|
||||
end
|
||||
|
||||
def test_load_mock_plugin_by_gem
|
||||
ENV['INSPEC_CONFIG_DIR'] = File.join(@config_dir_path, 'test-fixture-1-float')
|
||||
reg = Inspec::Plugin::V2::Registry.instance
|
||||
plugin_name = :'inspec-test-fixture'
|
||||
loader = Inspec::Plugin::V2::Loader.new(omit_bundles: true)
|
||||
assert reg.known_plugin?(plugin_name), "\n#{plugin_name} should be a known plugin"
|
||||
refute reg.loaded_plugin?(plugin_name), "\n#{plugin_name} should not be loaded yet"
|
||||
loader.load_all
|
||||
assert reg.loaded_plugin?(plugin_name), "\n#{plugin_name} should be loaded"
|
||||
end
|
||||
|
||||
#====================================================================#
|
||||
# activation #
|
||||
#====================================================================#
|
||||
|
@ -174,12 +203,12 @@ class PluginLoaderTests < MiniTest::Test
|
|||
assert_equal 'Inspec::Plugin::V2::Activator', registry.find_activators()[0].class.name, 'find_activators should return an array of Activators'
|
||||
activator = registry.find_activators(plugin_type: :mock_plugin_type, name: :'meaning-of-life-the-universe-and-everything')[0]
|
||||
refute_nil activator, 'find_activators should find the test activator'
|
||||
[ :plugin_name, :plugin_type, :activator_name, :activated, :exception, :activation_proc, :implementation_class ].each do |method_name|
|
||||
[ :plugin_name, :plugin_type, :activator_name, :'activated?', :exception, :activation_proc, :implementation_class ].each do |method_name|
|
||||
assert_respond_to activator, method_name
|
||||
end
|
||||
|
||||
# Activation preconditions
|
||||
refute activator.activated, 'Test activator should start out unactivated'
|
||||
refute activator.activated?, 'Test activator should start out unactivated'
|
||||
assert_nil activator.exception, 'Test activator should have no exception prior to activation'
|
||||
assert_nil activator.implementation_class, 'Test activator should not know implementation class prior to activation'
|
||||
refute InspecPlugins::MeaningOfLife.const_defined?(:MockPlugin), 'impl_class should not be defined prior to activation'
|
||||
|
@ -187,7 +216,7 @@ class PluginLoaderTests < MiniTest::Test
|
|||
loader.activate(:mock_plugin_type, :'meaning-of-life-the-universe-and-everything')
|
||||
|
||||
# Activation postconditions
|
||||
assert activator.activated, 'Test activator should be activated after activate'
|
||||
assert activator.activated?, 'Test activator should be activated after activate'
|
||||
assert_nil activator.exception, 'Test activator should have no exception after activation'
|
||||
|
||||
# facts about the implementation class
|
||||
|
|
Loading…
Reference in a new issue