Class: Ruber::ComponentManager::PluginSorter
- Inherits:
-
Object
- Object
- Ruber::ComponentManager::PluginSorter
- Defined in:
- lib/ruber/component_manager.rb
Overview
Helper class used to resolve dependencies among plugins. Most likely you don’t need to use it, but simply call Ruber::ComponentManager.sort_plugins.
Instance Method Summary (collapse)
-
- (Object) find_dep(plug, stack = [])
private
Finds the dependencies of the plugin plug.
-
- (Object) find_unknown_deps
private
Checks whether all the dependencies among the plugins are satisifed either by.
-
- (PluginSorter) initialize(pdfs, ignored = [])
constructor
Creates a new PluginSorter.
-
- (Object) sort_plugins
Sorts the plugins associated with the object, according with their dependencies and returns an array containing the plugin descriptions sorted in dependence order, from the dependence to the dependent.
Constructor Details
- (PluginSorter) initialize(pdfs, ignored = [])
Creates a new PluginSorter. pdfs is an array of the plugin descriptions to sort. ignored is an array containing dependencies to be ignored(maybe because they’re already loaded). ignored can be either an array of symbols, where each symbol is the name of a feature, or an array of +PluginSpecification+s.
Note: pdfs should contain dependencies in terms of actual plugins, not of features.
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/ruber/component_manager.rb', line 67 def initialize pdfs, ignored = [] @pdfs = {} @plugins = {} pdfs.each do |i| @pdfs[i.name] = i @plugins[i.name] = i.deps end @ignored = ignored.map{|i| i.is_a?(OpenStruct) ? i.name : i} @ready = [] @deps = {} end |
Instance Method Details
- (Object) find_dep(plug, stack = []) (private)
Finds the dependencies of the plugin plug. To do this, it calls itself recursively for each of the direct dependencies of the plugin. The dependencies found are stored in the @deps hash.
To avoid an endless loop or a SystemStackError in case of circular dependencies, each time the method is called, it is also passed a second argument, an array containing the names of the plugins whose dependencies have lead to that call. If circular dependencies are found, the entry in @deps corresponding to the plugin is set to nil, and an array containing the pairs of plugins with circular dependencies is returned. If no circular dependencies exist, the returned array is empty.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/ruber/component_manager.rb', line 148 def find_dep plug, stack = [] direct_deps = @plugins[plug] || [] circ = [] deps = [] circ << plug if stack.include? plug direct_deps.each{|d| circ << plug << d if stack.include? d} if circ.empty? deps = [] res = direct_deps.each do |d| circ += find_dep d, stack + [plug] unless @deps.has_key? d deps += @deps[d] + [d] if @deps[d] end end @deps[plug] = circ.empty? ? deps : nil circ end |
- (Object) find_unknown_deps (private)
Checks whether all the dependencies among the plugins are satisifed either by another plugin or by a plugin in the ignore list. Returns a hash which is empty if all the dependencies were satisifed and otherwise has for keys the names of plugins whose dependencies couldn’t be found and for values arrays containing the names of the missing dependencies for that plugin.
124 125 126 127 128 129 130 131 132 |
# File 'lib/ruber/component_manager.rb', line 124 def find_unknown_deps known = @plugins.keys res = Hash.new{|h, k| h[k] = []} known.each do |i| missing_deps = @plugins[i] - known missing_deps.each{|d| res[d] << i} end res end |
- (Object) sort_plugins
Sorts the plugins associated with the object, according with their dependencies and returns an array containing the plugin descriptions sorted in dependence order, from the dependence to the dependent.
If some of the plugins have dependency which doesn’t correspond neither to another plugin nor to one of the plugins to ignore, Ruber::ComponentManager::UnresolvedDep will be raised.
If there’s a circular dependency among the plugins, Ruber::ComponentManager::CircularDep will be raised.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/ruber/component_manager.rb', line 91 def sort_plugins @plugins.each_value do |v| v.reject!{|d| @ignored.include? d} end unknown = find_unknown_deps raise ComponentManager::UnresolvedDep.new unknown unless unknown.empty? circular = @plugins.keys.inject([]){ |res, plug| res + find_dep( plug ) } raise ComponentManager::CircularDep.new(circular.uniq) unless circular.empty? deps = @deps.reject{|k, v| v.nil? } res = [] old_size = deps.size until deps.empty? ready = deps.select{|k, v| v.empty?}.map{|i| i[0]}.sort_by{|i| i.to_s} res += ready ready.each do |i| deps.each{|d| d[1].delete i} deps.delete i end raise "Circular deps (this shouldn't happen)" unless old_size > deps.size old_size = deps.size end res.map{|i| @pdfs[i]} end |