class Diecut::PluginLoader

Constants

NO_VALUE
PLUGIN_FILENAME

:nocov:

Attributes

issue_handler[W]
local_valise[RW]
plugins[R]

Public Class Methods

new() click to toggle source
# File lib/diecut/plugin-loader.rb, line 17
def initialize
  @sources = {}
  @local_sources = []
  @by_gem_name = Hash.new{|h,k| h[k] = []}
  @plugins = []
end

Public Instance Methods

add_plugin_desc(desc) click to toggle source
# File lib/diecut/plugin-loader.rb, line 183
def add_plugin_desc(desc)
  plugins << desc
end
choose_source(locations) click to toggle source
# File lib/diecut/plugin-loader.rb, line 171
def choose_source(locations)
  locations.each do |loc|
    path = loc.absolute_path
    if @sources.has_key?(path)
      return path
    end
  end
  fallback_location = locations.first.absolute_path
  issue_handler.unregistered_plugin_source(fallback_location)
  return fallback_location
end
component_sort() { |comp| ... } click to toggle source
# File lib/diecut/plugin-loader.rb, line 98
def component_sort
  unless block_given?
    return enum_for(:component_sort)
  end
  child_idxs = {}
  strongly_connected_components.each_with_index do |component, idx|
    component.sort_by{|node| child_idxs.fetch(node, -1) }.each do |comp|
      yield(comp)
    end

    component.each do |comp|
      tsort_each_child(comp) do |child|
        child_idxs[child] = idx
      end
    end
  end
end
dep_path?(from_gem, to_gem) click to toggle source
# File lib/diecut/plugin-loader.rb, line 150
def dep_path?(from_gem, to_gem)
  # potential to optimize this: build a map of reachablility and test
  # against that.
  closed = {}
  open = [from_gem]
  until open.empty?
    current = open.shift
    return true if current == to_gem
    closed[current] = true
    open += @by_gem_name[current.gem.name].select{|gem| !closed.has_key?(gem)}
  end
  return false
end
describe_plugin(name) { |desc| ... } click to toggle source
# File lib/diecut/plugin-loader.rb, line 187
def describe_plugin(name)
  source_path = choose_source(caller_locations)
  desc = PluginDescription.new(name, source_path)
  yield(desc)
  add_plugin_desc(desc)
  return desc
end
discover(prerelease) click to toggle source
# File lib/diecut/plugin-loader.rb, line 51
def discover(prerelease)
  latest_specs(prerelease).map do |spec|
    spec.matches_for_glob(PLUGIN_FILENAME).map do |match|
      from_gem(spec, match)
    end
  end
  local_valise.get(PLUGIN_FILENAME).present.map(&:full_path).each do |path|
    from_local(path)
  end
end
each_path() { |path| ... } click to toggle source
# File lib/diecut/plugin-loader.rb, line 116
def each_path
  component_sort.reverse_each do |source|
    yield source.path
  end
end
from_gem(spec, path) click to toggle source
# File lib/diecut/plugin-loader.rb, line 62
def from_gem(spec, path)
  plugin = GemPlugin.new(spec, path)

  @sources[path] = plugin
  spec.dependencies.map(&:name).each do |depname|
    @by_gem_name[depname] << plugin
  end
end
from_local(path) click to toggle source
# File lib/diecut/plugin-loader.rb, line 71
def from_local(path)
  source = GemPlugin.new(NO_VALUE, path)
  @sources[path] = source
  @local_sources << source
end
issue_handler() click to toggle source
# File lib/diecut/plugin-loader.rb, line 35
def issue_handler
  @issue_handler ||= Diecut.issue_handler
end
latest_specs(prerelease) click to toggle source

:nocov:

# File lib/diecut/plugin-loader.rb, line 41
def latest_specs(prerelease)
  Gem::Specification.latest_specs(prerelease)
end
load_plugins(prerelease = false) click to toggle source
# File lib/diecut/plugin-loader.rb, line 164
def load_plugins(prerelease = false)
  discover(prerelease)
  each_path do |path|
    require_plugin(path)
  end
end
require_plugin(path) click to toggle source
# File lib/diecut/plugin-loader.rb, line 45
def require_plugin(path)
  require path
end
strict_sequence?(to, from) click to toggle source

Can a chain of “is after” arrows be walked from ‘from’ to ‘to’. The rules are: A plugin defined by a gem that depends on another gem “is after” the plugin defined in the latter gem. A plugin defined in a local config file is after “more general” local files (project config is after personal is after system). All local plugins are after all gem plugins

The rationale for these rules is that decisions made later in time have more information and that decisions made closer to the problem know the problem domain better.

# File lib/diecut/plugin-loader.rb, line 134
def strict_sequence?(to, from)
  from_source = @sources[from.source_path]
  to_source = @sources[to.source_path]

  case [from_source.gem?, to_source.gem?]
  when [true, true]
    dep_path?(to_source, from_source)
  when [true, false]
    false
  when [false, true]
    true
  when [false, false]
    @local_sources.index_of(from.source_path) <= @local_sources.index_of(to.source_path)
  end
end
tsort_each_child(node) { |depplugin| ... } click to toggle source
# File lib/diecut/plugin-loader.rb, line 81
def tsort_each_child(node)
  if node.gem?
    @by_gem_name[node.gem.name].each do |depplugin|
      yield depplugin
    end
    @local_sources.each do |local|
      yield local
    end
  else
    @local_sources.drop_while do |src|
      src != node
    end.drop(1).each do |node|
      yield(node)
    end
  end
end
tsort_each_node(&block) click to toggle source
# File lib/diecut/plugin-loader.rb, line 77
def tsort_each_node(&block)
  @sources.each_value(&block)
end