plugin_manager 1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+
2
+ Plugin Manager
3
+ ==============
4
+
5
+ This is a plugin loader for Ruby. Features:
6
+
7
+ * dependencies
8
+ * versioning
9
+ * multiple plugin sources
10
+ * safe against plugins with broken code
11
+ * plugin code reloading
12
+
13
+ It is not tied to Rubygems or Rails. A plugin is any directory with a plugin.rb file
14
+ inside that looks like this:
15
+
16
+ Plugin.define do
17
+ name "Extras"
18
+ version "1.0"
19
+
20
+ # the file to load to load the plugin. It is expected to be an .rb
21
+ # file relative to this definition
22
+ file "extras"
23
+
24
+ # this is an object that is defined by the plugin code
25
+ object "App::Extras"
26
+
27
+ # Dependencies of the plugin
28
+ dependencies "core", ">=1.0",
29
+ "fonts", ">=0.5, <1.9",
30
+ "debug", ">0, !=0.95, < 2"
31
+ end
32
+
33
+ See the spec/fixtures/example/ directory for an example of a set of plugins.
34
+
35
+ This
36
+ directory of plugins can be loaded with:
37
+
38
+ manager = PluginManager.new
39
+ manager.add_plugin_source("spec/fixtures/example")
40
+ manager.load
41
+
42
+ The code in the appropriate plugins will be loaded and you will then have available:
43
+
44
+ # plugins that were loaded successfully
45
+ manager.loaded_plugins
46
+
47
+ # plugins that could not be loaded because of unmet dependencies,
48
+ # or because a more recent version was available.
49
+ manager.unloaded_plugins
50
+
51
+ # plugin.rb files that could not be read
52
+ manager.unreadable_definitions
53
+
54
+ # plugins that raised exceptions while being loaded
55
+ manager.plugins_with_errors
56
+
57
+
58
+ License
59
+ =======
60
+
61
+ MIT
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), "..", "lib", "plugin_manager")
4
+
@@ -0,0 +1,37 @@
1
+
2
+ class PluginManager
3
+ class DefinitionBuilder
4
+ def initialize(&block)
5
+ @block = block
6
+ @definition = PluginDefinition.new
7
+ end
8
+
9
+ def build
10
+ instance_eval(&@block)
11
+ @definition
12
+ end
13
+
14
+ def name(value)
15
+ @definition.name = value
16
+ end
17
+
18
+ def version(value)
19
+ @definition.version = value
20
+ end
21
+
22
+ def object(value)
23
+ @definition.object = value
24
+ end
25
+
26
+ def file(value)
27
+ @definition.file = value
28
+ end
29
+
30
+ def dependencies(*deps)
31
+ @definition.dependencies ||= []
32
+ deps.each_slice(2) do |name, ver|
33
+ @definition.dependencies << [name, ver]
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+
2
+ class PluginManager
3
+ class Plugin
4
+ def self.define(&block)
5
+ builder = DefinitionBuilder.new(&block)
6
+ builder.build
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+
2
+ class PluginManager
3
+ class PluginDefinition
4
+ attr_accessor :name,
5
+ :version,
6
+ :object,
7
+ :file,
8
+ :dependencies,
9
+ :definition_file
10
+
11
+ def inspect
12
+ "<Plugin #{name} #{version} depends:[#{(dependencies||[]).map{|dep| dep.join("")}.join(", ")}] #{required_files.length} files>"
13
+ end
14
+
15
+ def required_files
16
+ @required_files ||= []
17
+ end
18
+
19
+ def load
20
+ required_files.each {|file| $".delete(file) }
21
+ new_files = log_requires do
22
+ require File.expand_path(File.join(File.dirname(definition_file), file))
23
+ end
24
+ required_files.unshift(*new_files)
25
+ end
26
+
27
+ private
28
+
29
+ def log_requires
30
+ before = $".dup
31
+ yield
32
+ after = $".dup
33
+ result = after - before
34
+ result
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,104 @@
1
+
2
+ $:.unshift(File.dirname(__FILE__))
3
+
4
+ require 'plugin_manager/plugin'
5
+ require 'plugin_manager/plugin_definition'
6
+ require 'plugin_manager/definition_builder'
7
+
8
+ class PluginManager
9
+ attr_reader :unreadable_definitions, :plugins_with_errors, :loaded_plugins
10
+
11
+ def initialize
12
+ @unloaded_plugins = []
13
+ @loaded_plugins = []
14
+ @unreadable_definitions = []
15
+ @plugins_with_errors = []
16
+ end
17
+
18
+ def plugins
19
+ @unloaded_plugins + @loaded_plugins
20
+ end
21
+
22
+ def add_plugin_source(directory)
23
+ definition_files = Dir[File.join(File.expand_path(directory), "*", "plugin.rb")]
24
+ definition_files.reject! {|f| plugins.any? {|pl| pl.definition_file == File.expand_path(f) } }
25
+ new_definitions =
26
+ definition_files.map do |file|
27
+ begin
28
+ definition = instance_eval(File.read(file))
29
+ definition.definition_file = File.expand_path(file)
30
+ definition
31
+ rescue Object
32
+ puts "Unreadable plugin definition: #{file}"
33
+ @unreadable_definitions << file
34
+ nil
35
+ end
36
+ end.compact.sort_by {|p| p.name.downcase }
37
+ @unloaded_plugins += new_definitions
38
+ end
39
+
40
+ def load
41
+ previous_length = @unloaded_plugins.length + 1
42
+ while previous_length > @unloaded_plugins.length
43
+ previous_length = @unloaded_plugins.length
44
+ if plugin = next_to_load
45
+ begin
46
+ plugin.load
47
+ rescue Object => e
48
+ puts "Error loading plugin: #{plugin}"
49
+ puts " " + e.message
50
+ puts e.backtrace.map {|l| " " + l }
51
+ @plugins_with_errors << plugin
52
+ end
53
+ @loaded_plugins << plugin
54
+ @unloaded_plugins.delete(plugin)
55
+ end
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def next_to_load
62
+ # this ordering ensures we try the most recent version of a plugin first
63
+ remaining_plugins = @unloaded_plugins.sort_by {|pl| pl.version }.reverse
64
+
65
+ remaining_plugins.detect do |d|
66
+ next if @loaded_plugins.map {|pl| pl.name }.include?(d.name)
67
+ (d.dependencies||[]).all? do |dep|
68
+ req_name, req_ver = *dep
69
+ @loaded_plugins.detect do |d1|
70
+ d1.name == req_name and
71
+ PluginManager.compare_version(req_ver, d1.version)
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ def self.compare_version(required, got)
78
+ got = got.gsub(/(\.0)+$/, "")
79
+ required.split(",").all? do |req|
80
+ req = req.strip
81
+ req = req.gsub(/(\.0)+$/, "")
82
+ if md = req.match(/^(=|>|>=|<|<=|!=)?([\d\.]*)$/)
83
+ case md[1]
84
+ when ">"
85
+ got > md[2]
86
+ when ">="
87
+ got >= md[2]
88
+ when "<"
89
+ got < md[2]
90
+ when "<="
91
+ got <= md[2]
92
+ when "="
93
+ md[2] == got
94
+ when "!="
95
+ md[2] != got
96
+ end
97
+ else
98
+ puts "don't recognize version string: #{required.inspect}"
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: plugin_manager
3
+ version: !ruby/object:Gem::Version
4
+ version: "1"
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Lucraft
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-16 00:00:00 +00:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: dan@fluentradical.com
27
+ executables:
28
+ - plugin_manager
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.md
33
+ files:
34
+ - README.md
35
+ - lib/plugin_manager/definition_builder.rb
36
+ - lib/plugin_manager/plugin.rb
37
+ - lib/plugin_manager/plugin_definition.rb
38
+ - lib/plugin_manager.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/danlucraft/plugin_manager
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --main
46
+ - README.md
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.5
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: A Ruby plugin loader
68
+ test_files: []
69
+