Class: GemPlugin::Manager
- Inherits:
-
Object
- Object
- GemPlugin::Manager
- Includes:
- Singleton
- Defined in:
- lib/gem_plugin.rb
Overview
This class is used by people who use gem plugins (but don’t necessarily make them) to add plugins to their own systems. It provides a way to load plugins, list them, and create them as needed.
It is a singleton so you use like this: GemPlugins::Manager.instance.load
Instance Attribute Summary collapse
-
#gems ⇒ Object
readonly
Returns the value of attribute gems.
-
#plugins ⇒ Object
readonly
Returns the value of attribute plugins.
Instance Method Summary collapse
-
#config(gem_name, options = {}) ⇒ Object
While Manager.resource will find arbitrary resources, a special case is when you need to load a set of configuration defaults.
-
#create(name, options = {}) ⇒ Object
Resolves the given name (should include /category/name) to find the plugin class and create an instance.
-
#initialize ⇒ Manager
constructor
A new instance of Manager.
-
#load(needs = {}) ⇒ Object
Responsible for going through the list of available gems and loading any plugins requested.
-
#loaded?(gem_name) ⇒ Boolean
Simply says whether the given gem has been loaded yet or not.
-
#register(category, name, klass) ⇒ Object
Not necessary for you to call directly, but this is how GemPlugin::Base.inherited actually adds a plugin to a category.
-
#resource(gem_name, path) ⇒ Object
GemPlugins can have a ‘resources’ directory which is packaged with them and can hold any data resources the plugin may need.
Constructor Details
#initialize ⇒ Manager
Returns a new instance of Manager.
69 70 71 72 73 74 75 76 |
# File 'lib/gem_plugin.rb', line 69 def initialize # plugins that have been loaded @plugins = {} # keeps track of gems which have been loaded already by the manager *and* # where they came from so that they can be referenced later @gems = {} end |
Instance Attribute Details
#gems ⇒ Object (readonly)
Returns the value of attribute gems.
66 67 68 |
# File 'lib/gem_plugin.rb', line 66 def gems @gems end |
#plugins ⇒ Object (readonly)
Returns the value of attribute plugins.
65 66 67 |
# File 'lib/gem_plugin.rb', line 65 def plugins @plugins end |
Instance Method Details
#config(gem_name, options = {}) ⇒ Object
While Manager.resource will find arbitrary resources, a special case is when you need to load a set of configuration defaults. GemPlugin normalizes this to be if you have a file “resources/defaults.yaml” then you’ll be able to load them via Manager.config.
How you use the method is you get the options the user wants set, pass them to Manager.instance.config, and what you get back is a new Hash with the user’s settings overriding the defaults.
opts = Manager.instance.config "mygem", :age => 12, :max_load => .9
In the above case, if defaults had => 14 then it would be changed to 12.
This loads the .yaml file on the fly every time, so doing it a whole lot is very stupid. If you need to make frequent calls to this, call it once with no options (Manager.instance.config) then use the returned defaults directly from then on.
229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/gem_plugin.rb', line 229 def config(gem_name, ={}) config_file = Manager.instance.resource(gem_name, "/defaults.yaml") if config_file begin defaults = YAML.load_file(config_file) return defaults.merge() rescue raise "Error loading config #{config_file} for gem #{gem_name}" end else return end end |
#create(name, options = {}) ⇒ Object
Resolves the given name (should include /category/name) to find the plugin class and create an instance. You can pass a second hash option that is then given to the Plugin to configure it.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/gem_plugin.rb', line 156 def create(name, = {}) last_slash = name.rindex("/") category = name[0 ... last_slash] plugin = name[last_slash .. -1] map = @plugins[category] if not map raise "Plugin category #{category} does not exist" elsif not map.has_key? plugin raise "Plugin #{plugin} does not exist in category #{category}" else map[plugin].new() end end |
#load(needs = {}) ⇒ Object
Responsible for going through the list of available gems and loading any plugins requested. It keeps track of what it’s loaded already and won’t load them again.
It accepts one parameter which is a hash of gem depends that should include or exclude a gem from being loaded. A gem must depend on gem_plugin to be considered, but then each system has to add it’s own INCLUDE to make sure that only plugins related to it are loaded.
An example again comes from Mongrel. In order to load all Mongrel plugins:
GemPlugin::Manager.instance.load "mongrel" => GemPlugin::INCLUDE
Which will load all plugins that depend on mongrel AND gem_plugin. Now, one extra thing we do is we delay loading Rails Mongrel plugins until after rails is configured. Do do this the mongrel_rails script has:
GemPlugin::Manager.instance.load “mongrel” => GemPlugin::INCLUDE, “rails” => GemPlugin::EXCLUDE The only thing to remember is that this is saying “include a plugin if it depends on gem_plugin, mongrel, but NOT rails”. If a plugin also depends on other stuff then it’s loaded just fine. Only gem_plugin, mongrel, and rails are ever used to determine if it should be included.
NOTE: Currently RubyGems will run autorequire on gems that get required AND on their dependencies. This really messes with people running edge rails since activerecord or other stuff gets loaded for just touching a gem plugin. To prevent this load requires the full path to the “init.rb” file, which avoids the RubyGems autorequire magic.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/gem_plugin.rb', line 107 def load(needs = {}) sdir = File.join(Gem.dir, "specifications") gems = Gem::SourceIndex.from_installed_gems(sdir) needs = needs.merge({"gem_plugin" => INCLUDE}) gems.each do |path, gem| # don't load gems more than once next if @gems.has_key? gem.name check = needs.dup # rolls through the depends and inverts anything it finds gem.dependencies.each do |dep| # this will fail if a gem is depended more than once if check.has_key? dep.name check[dep.name] = !check[dep.name] end end # now since excluded gems start as true, inverting them # makes them false so we'll skip this gem if any excludes are found if (check.select {|name,test| !test}).length == 0 # looks like no needs were set to false, so it's good # Previously was set wrong, we already have the correct gem path! #gem_dir = File.join(Gem.dir, "gems", "#{gem.name}-#{gem.version}") gem_dir = File.join(Gem.dir, "gems", path) require File.join(gem_dir, "lib", gem.name, "init.rb") @gems[gem.name] = gem_dir end end return nil end |
#loaded?(gem_name) ⇒ Boolean
Simply says whether the given gem has been loaded yet or not.
173 174 175 |
# File 'lib/gem_plugin.rb', line 173 def loaded?(gem_name) @gems.has_key? gem_name end |
#register(category, name, klass) ⇒ Object
Not necessary for you to call directly, but this is how GemPlugin::Base.inherited actually adds a plugin to a category.
146 147 148 149 |
# File 'lib/gem_plugin.rb', line 146 def register(category, name, klass) @plugins[category] ||= {} @plugins[category][name.downcase] = klass end |
#resource(gem_name, path) ⇒ Object
GemPlugins can have a ‘resources’ directory which is packaged with them and can hold any data resources the plugin may need. The main problem is that it’s difficult to figure out where these resources are actually located on the file system. The resource method tries to locate the real path for a given resource path.
Let’s say you have a ‘resources/stylesheets/default.css’ file in your gem distribution, then finding where this file really is involves:
Manager.instance.resource("mygem", "/stylesheets/default.css")
You either get back the full path to the resource or you get a nil if it doesn’t exist.
If you request a path for a GemPlugin that hasn’t been loaded yet then it will throw an PluginNotLoaded exception. The gem may be present on your system in this case, but you just haven’t loaded it with Manager.instance.load properly.
196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/gem_plugin.rb', line 196 def resource(gem_name, path) if not loaded? gem_name raise PluginNotLoaded.new("Plugin #{gem_name} not loaded when getting resource #{path}") end file = File.join(@gems[gem_name], "resources", path) if File.exist? file return file else return nil end end |