class CLAide::Command::PluginManager

Handles plugin related logic logic for the `Command` class.

Plugins are loaded the first time a command run and are identified by the prefix specified in the command class. Plugins must adopt the following conventions:

`lib/#{plugin_prefix}_plugin` relative path.

Public Class Methods

installed_specifications_for_prefix(plugin_prefix) click to toggle source

@return [Array<Specification>] The RubyGems specifications for the

installed plugins that match the given `plugin_prefix`.
# File lib/claide/command/plugin_manager.rb, line 45
def self.installed_specifications_for_prefix(plugin_prefix)
  loaded_plugins[plugin_prefix] ||
    plugin_gems_for_prefix(plugin_prefix).map(&:first)
end
load_plugins(plugin_prefix) click to toggle source

@return [Array<Gem::Specification>] Loads plugins via RubyGems looking

for files named after the `PLUGIN_PREFIX_plugin` and returns the
specifications of the gems loaded successfully.
Plugins are required safely.
# File lib/claide/command/plugin_manager.rb, line 28
def self.load_plugins(plugin_prefix)
  loaded_plugins[plugin_prefix] ||=
    plugin_gems_for_prefix(plugin_prefix).map do |spec, paths|
      spec if safe_activate_and_require(spec, paths)
    end.compact
end
loaded_plugins() click to toggle source

@return [Hash<String,Gem::Specification>] The loaded plugins,

grouped by plugin prefix.
# File lib/claide/command/plugin_manager.rb, line 19
def self.loaded_plugins
  @loaded_plugins ||= {}
end
plugin_gems_for_prefix(prefix) click to toggle source

@return [Array<[Gem::Specification, Array<String>]>]

Returns an array of tuples containing the specifications and
plugin files to require for a given plugin prefix.
# File lib/claide/command/plugin_manager.rb, line 72
def self.plugin_gems_for_prefix(prefix)
  glob = "#{prefix}_plugin#{Gem.suffix_pattern}"
  Gem::Specification.latest_specs(true).map do |spec|
    matches = spec.matches_for_glob(glob)
    [spec, matches] unless matches.empty?
  end.compact
end
plugins_involved_in_exception(exception) click to toggle source

@return [Array<String>] The list of the plugins whose root path appears

in the backtrace of an exception.

@param [Exception] exception

The exception to analyze.
# File lib/claide/command/plugin_manager.rb, line 56
def self.plugins_involved_in_exception(exception)
  specifications.select do |gemspec|
    exception.backtrace.any? do |line|
      full_require_paths_for(gemspec).any? do |plugin_path|
        line.include?(plugin_path)
      end
    end
  end.map(&:name)
end
safe_activate_and_require(spec, paths) click to toggle source

Activates the given spec and requires the given paths. If any exception occurs it is caught and an informative message is printed.

@param [Gem::Specification] spec

The spec to be activated.

@param [String] paths

The paths to require.

@return [Bool] Whether activation and requiring succeeded.

# File lib/claide/command/plugin_manager.rb, line 92
def self.safe_activate_and_require(spec, paths)
  spec.activate
  paths.each { |path| require(path) }
  true
rescue Exception => exception # rubocop:disable RescueException
  message = "\n---------------------------------------------"
  message << "\nError loading the plugin `#{spec.full_name}`.\n"
  message << "\n#{exception.class} - #{exception.message}"
  message << "\n#{exception.backtrace.join("\n")}"
  message << "\n---------------------------------------------\n"
  warn message.ansi.yellow
  false
end
specifications() click to toggle source

@return [Array<Specification>] The RubyGems specifications for the

loaded plugins.
# File lib/claide/command/plugin_manager.rb, line 38
def self.specifications
  loaded_plugins.values.flatten.uniq
end

Private Class Methods

full_require_paths_for(gemspec) click to toggle source
# File lib/claide/command/plugin_manager.rb, line 106
def self.full_require_paths_for(gemspec)
  if gemspec.respond_to?(:full_require_paths)
    return gemspec.full_require_paths
  end

  # RubyGems < 2.2
  gemspec.require_paths.map do |require_path|
    if require_path.include?(gemspec.full_gem_path)
      require_path
    else
      File.join(gemspec.full_gem_path, require_path)
    end
  end
end