more doc
[duncan/yastx-core.git] / lib / plugin.rb
1
2 # Based on 
3 # http://majakari.net/2006/11/23/adding-plugins-to-your-ruby-application
4 # http://eigenclass.org/hiki.rb?ruby+plugins
5
6 require 'tsort'
7
8 class Hash
9   include TSort
10   alias tsort_each_node each_key
11   
12   # hash values contain dependencies
13   def tsort_each_child(node, &block)
14     fetch(node, []).each(&block)
15   end
16 end
17
18 module PluginSugar
19   # allow accessing attributes using def_field
20   def def_field(*names)
21     class_eval do
22       names.each do |name|
23         define_method(name) do |*args|
24           case args.size
25           when 0: instance_variable_get("@#{name}")
26           else    instance_variable_set("@#{name}", *args)
27           end
28         end
29       end
30     end
31   end
32 end
33
34 class Plugin
35   @registered_plugins = {}
36   class << self
37     attr_reader :registered_plugins
38     private :new
39   end
40
41   def self.extensions(ext_point)
42     plugins = Plugin.registered_plugins.select do |n,o|
43       o.extends == ext_point
44     end
45     
46     deps = Hash.new([])
47     plugins.each do |name,obj|
48       if obj.run_after
49         deps[name] = obj.run_after.to_s
50       elsif obj.run_before
51         if obj.run_before.respond_to?(:pop) 
52           obj.run_before.each {|d| deps[d.to_s] = name}
53         else
54           deps[obj.run_before.to_s] = name
55         end
56       end
57     end
58     deps.tsort.map {|name| Plugin.registered_plugins[name]}
59   end
60
61   def self.define(name, &block)
62     p = new
63     p.instance_eval(&block)
64     Plugin.registered_plugins[name] = p
65   end
66
67   extend PluginSugar
68   def_field :author, :version, :extends, :run_before, :run_after
69 end