# encoding: utf-8 require 'fedux_org_stdlib/require_files' require 'fedux_org_stdlib/gem_plugins/no_plugin' require 'fedux_org_stdlib/gem_plugins/plugin' require 'fedux_org_stdlib/gem_plugins/exceptions' require 'fedux_org_stdlib/list' require_library %w( active_support/core_ext/string/inflections active_support/core_ext/object/blank hirb/console ) module FeduxOrgStdlib module GemPlugins # Plugin Manager # # To use the plugin manager you should build the plugins for your # application as rubygems. How you name the plugins is up to you, but it is # recommended to use something like `your-application-`. For # the plugin to be found, it needs to include the so called plugin file # `your-application-extension.rb`. # # @example PluginManager-class # # module YourApplication # class PluginManager < FeduxOrgStdlib::GemPlugins::PluginManager # end # end # # @example Default prefix # # Please make sure you create a class for your plugin manager to make it # work. Otherwise give the prefix via parameter - see below. # # # -- main.rb -- # # main module # module YourApplication # # The manager uses "#{self.name.underscore.gsub(/\//, '-')}-plugin.rb" as plugin-file # @plugin_manager = PluginManager.new # # class << self # attr_reader :plugin_manager # # def load_plugins # self.plugin_manager.load_plugins # end # end # end # # # @example Use different plugin file # # -- main.rb -- # # main module # module YourApplication # # The manager uses 'asdf-plugin1.rb' to find plugins # @plugin_manager = PluginManager.new(plugin_file: 'asdf-plugin1.rb') # # [...] # end # # At some place you need to load your plugins. # # @example Load plugins in your application # # # -- runner.rb -- # # YourApplication.load_plugins # class PluginManager private attr_reader :plugins, :creator, :plugin_file public def initialize(creator: Plugin, plugin_file: File.join('lib', __plugin_prefix + 'plugin.rb')) @creator = creator @plugin_file = plugin_file # needs variables above @plugins = plugins_in_rubygems_path end # Enable a plugin def activate_plugin(*names) names.flatten.each do |n| plugin = plugins.find(NoPlugin.new(n)) { |p| p.name == n } return if plugin.blank? plugin.activate end end # String representation def to_s data = plugins.sort.reduce([]) do |a, e| a << { name: e.name, version: e.version, author: e.author, homepage: e.homepage, activated: e.active?, require_file: e.require_file } end List.new(data).to_s( fields: [:name, :version, :author, :homepage, :activated, :require_file] ) end private # Find all installed plugins and store them in an internal array. def plugins_in_rubygems_path require 'rubygems' Gem.refresh specs = rubygems_latest_specs.select { |s| spec_has_file?(s) } specs.map do |s| creator.new(spec: s) end end # Where a given Gem::Specification has a specific file. Used # to discover plugins. # # @private # @param [Gem::Specification] spec # @param [String] path Path to look for # @return [Boolean] Whether the file exists def spec_has_file?(spec) File.exist? File.join(spec.full_gem_path, plugin_file) end # Backwards compatible means of finding all the latest gemspecs # available on the system # # @private # @return [Array] Array of latest Gem::Specification def rubygems_latest_specs # If newer Rubygems if ::Gem::Specification.respond_to? :latest_specs ::Gem::Specification.latest_specs(true) else ::Gem.source_index.latest_specs end end def __plugin_prefix name = if self.class.name.deconstantize.blank? self.class.name else self.class.name.deconstantize end "#{name.underscore.gsub(/\//, '-')}-" end end end end