# = Plugin Handler
#
# Find plugins across various library managers.
#
# All plugins are expected to be within a libraries designated
# loadpath(s) under a plugin/ subdirectory. By using
# this assigned space, ie. plugin/, plugins are kept
# isolated from normal libary scripts. This helps prevent
# inadvertent name clashes.
#
# == How To Use
#
# Usage is very simple. Just supply a glob to the +Plugin.find+
# function.
#
# Plugin.find('syckle/*')
#
# A shortcut is provided with [].
#
# Plugin['syckle/*']
#
# == A Note on RubyGems
#
# A way has not yet been devised to isolate the actived version
# of a gem from the latest inactive version. Therefore some
# overlap can occur if an older version of a plugin-containing
# gem has been activated prior to calling Plugin.find(). Such an
# occurance will be rare (considering the use cases of plugins),
# so it is nothing to be overly concerned about. Moreover, it is
# a long-way from the offical Gems plugin policy which is to find
# all matching files from *all* versions using Gem.find_files().
# I quote Eric Hodel, "It's an encouragement to make your plugin
# files as light as possible, such as requiring an additional file
# or calling some very stable API." While an understandable
# encouragment, ultimately it is not a robust solution.
module Plugin
extend self
DIRECTORY = 'plugin'
# Find plugins, searching through standard $LOAD_PATH,
# Roll Libraries and RubyGems.
#
# Provide a +match+ file glob to find plugins.
#
# Plugins.find('syckle/*')
#
def find(match)
plugins = []
plugins.concat find_roll(match)
plugins.concat find_loadpath(match)
plugins.concat find_gems(match)
plugins.uniq
end
# Shortcut for #find.
#
# Plugin['syckle/*']
#
alias_method :[], :find
# Search roll for current or latest libraries.
def find_roll(match)
plugins = []
if defined?(::Roll)
::Roll::Library.ledger.each do |name, lib|
lib = lib.sort.first if Array===lib
lib.loadpath.each do |path|
find = File.join(lib.location, path, DIRECTORY, match)
list = Dir.glob(find)
list = list.map{ |d| d.chomp('/') }
plugins.concat(list)
end
end
end
plugins
end
# Search standard $LOAD_PATH.
#
# Activated gem versions are in here too.
def find_loadpath(match)
plugins = []
$LOAD_PATH.uniq.each do |path|
list = Dir.glob(File.join(path, DIRECTORY, match))
#dirs = dirs.select{ |d| File.directory?(d) }
list = list.map{ |d| d.chomp('/') }
plugins.concat(list)
end
plugins
end
# Search latest gem versions.
#
# TODO: Is there anyway to skip active gems?
def find_gems(match)
plugins = []
if defined?(::Gem)
::Gem.latest_load_paths do |path|
list = Dir.glob(File.join(path, DIRECTORY, match))
list = list.map{ |d| d.chomp('/') }
plugins.concat(list)
end
end
plugins
end
end