Mercurial > hg > soundsoftware-site
comparison vendor/gems/coderay-1.0.0/lib/coderay/helpers/plugin.rb @ 909:cbb26bc654de redmine-1.3
Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author | Chris Cannam |
---|---|
date | Fri, 24 Feb 2012 19:09:32 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
908:c6c2cbd0afee | 909:cbb26bc654de |
---|---|
1 module CodeRay | |
2 | |
3 # = PluginHost | |
4 # | |
5 # A simple subclass/subfolder plugin system. | |
6 # | |
7 # Example: | |
8 # class Generators | |
9 # extend PluginHost | |
10 # plugin_path 'app/generators' | |
11 # end | |
12 # | |
13 # class Generator | |
14 # extend Plugin | |
15 # PLUGIN_HOST = Generators | |
16 # end | |
17 # | |
18 # class FancyGenerator < Generator | |
19 # register_for :fancy | |
20 # end | |
21 # | |
22 # Generators[:fancy] #-> FancyGenerator | |
23 # # or | |
24 # CodeRay.require_plugin 'Generators/fancy' | |
25 # # or | |
26 # Generators::Fancy | |
27 module PluginHost | |
28 | |
29 # Raised if Encoders::[] fails because: | |
30 # * a file could not be found | |
31 # * the requested Plugin is not registered | |
32 PluginNotFound = Class.new LoadError | |
33 HostNotFound = Class.new LoadError | |
34 | |
35 PLUGIN_HOSTS = [] | |
36 PLUGIN_HOSTS_BY_ID = {} # dummy hash | |
37 | |
38 # Loads all plugins using list and load. | |
39 def load_all | |
40 for plugin in list | |
41 load plugin | |
42 end | |
43 end | |
44 | |
45 # Returns the Plugin for +id+. | |
46 # | |
47 # Example: | |
48 # yaml_plugin = MyPluginHost[:yaml] | |
49 def [] id, *args, &blk | |
50 plugin = validate_id(id) | |
51 begin | |
52 plugin = plugin_hash.[] plugin, *args, &blk | |
53 end while plugin.is_a? Symbol | |
54 plugin | |
55 end | |
56 | |
57 alias load [] | |
58 | |
59 # Tries to +load+ the missing plugin by translating +const+ to the | |
60 # underscore form (eg. LinesOfCode becomes lines_of_code). | |
61 def const_missing const | |
62 id = const.to_s. | |
63 gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). | |
64 gsub(/([a-z\d])([A-Z])/,'\1_\2'). | |
65 downcase | |
66 load id | |
67 end | |
68 | |
69 class << self | |
70 | |
71 # Adds the module/class to the PLUGIN_HOSTS list. | |
72 def extended mod | |
73 PLUGIN_HOSTS << mod | |
74 end | |
75 | |
76 end | |
77 | |
78 # The path where the plugins can be found. | |
79 def plugin_path *args | |
80 unless args.empty? | |
81 @plugin_path = File.expand_path File.join(*args) | |
82 end | |
83 @plugin_path ||= '' | |
84 end | |
85 | |
86 # Map a plugin_id to another. | |
87 # | |
88 # Usage: Put this in a file plugin_path/_map.rb. | |
89 # | |
90 # class MyColorHost < PluginHost | |
91 # map :navy => :dark_blue, | |
92 # :maroon => :brown, | |
93 # :luna => :moon | |
94 # end | |
95 def map hash | |
96 for from, to in hash | |
97 from = validate_id from | |
98 to = validate_id to | |
99 plugin_hash[from] = to unless plugin_hash.has_key? from | |
100 end | |
101 end | |
102 | |
103 # Define the default plugin to use when no plugin is found | |
104 # for a given id, or return the default plugin. | |
105 # | |
106 # See also map. | |
107 # | |
108 # class MyColorHost < PluginHost | |
109 # map :navy => :dark_blue | |
110 # default :gray | |
111 # end | |
112 # | |
113 # MyColorHost.default # loads and returns the Gray plugin | |
114 def default id = nil | |
115 if id | |
116 id = validate_id id | |
117 raise "The default plugin can't be named \"default\"." if id == :default | |
118 plugin_hash[:default] = id | |
119 else | |
120 load :default | |
121 end | |
122 end | |
123 | |
124 # Every plugin must register itself for +id+ by calling register_for, | |
125 # which calls this method. | |
126 # | |
127 # See Plugin#register_for. | |
128 def register plugin, id | |
129 plugin_hash[validate_id(id)] = plugin | |
130 end | |
131 | |
132 # A Hash of plugion_id => Plugin pairs. | |
133 def plugin_hash | |
134 @plugin_hash ||= make_plugin_hash | |
135 end | |
136 | |
137 # Returns an array of all .rb files in the plugin path. | |
138 # | |
139 # The extension .rb is not included. | |
140 def list | |
141 Dir[path_to('*')].select do |file| | |
142 File.basename(file)[/^(?!_)\w+\.rb$/] | |
143 end.map do |file| | |
144 File.basename(file, '.rb').to_sym | |
145 end | |
146 end | |
147 | |
148 # Returns an array of all Plugins. | |
149 # | |
150 # Note: This loads all plugins using load_all. | |
151 def all_plugins | |
152 load_all | |
153 plugin_hash.values.grep(Class) | |
154 end | |
155 | |
156 # Loads the map file (see map). | |
157 # | |
158 # This is done automatically when plugin_path is called. | |
159 def load_plugin_map | |
160 mapfile = path_to '_map' | |
161 @plugin_map_loaded = true | |
162 if File.exist? mapfile | |
163 require mapfile | |
164 true | |
165 else | |
166 false | |
167 end | |
168 end | |
169 | |
170 protected | |
171 | |
172 # Return a plugin hash that automatically loads plugins. | |
173 def make_plugin_hash | |
174 @plugin_map_loaded ||= false | |
175 Hash.new do |h, plugin_id| | |
176 id = validate_id(plugin_id) | |
177 path = path_to id | |
178 begin | |
179 raise LoadError, "#{path} not found" unless File.exist? path | |
180 require path | |
181 rescue LoadError => boom | |
182 if @plugin_map_loaded | |
183 if h.has_key?(:default) | |
184 warn '%p could not load plugin %p; falling back to %p' % [self, id, h[:default]] | |
185 h[:default] | |
186 else | |
187 raise PluginNotFound, '%p could not load plugin %p: %s' % [self, id, boom] | |
188 end | |
189 else | |
190 load_plugin_map | |
191 h[plugin_id] | |
192 end | |
193 else | |
194 # Plugin should have registered by now | |
195 if h.has_key? id | |
196 h[id] | |
197 else | |
198 raise PluginNotFound, "No #{self.name} plugin for #{id.inspect} found in #{path}." | |
199 end | |
200 end | |
201 end | |
202 end | |
203 | |
204 # Returns the expected path to the plugin file for the given id. | |
205 def path_to plugin_id | |
206 File.join plugin_path, "#{plugin_id}.rb" | |
207 end | |
208 | |
209 # Converts +id+ to a Symbol if it is a String, | |
210 # or returns +id+ if it already is a Symbol. | |
211 # | |
212 # Raises +ArgumentError+ for all other objects, or if the | |
213 # given String includes non-alphanumeric characters (\W). | |
214 def validate_id id | |
215 if id.is_a? Symbol or id.nil? | |
216 id | |
217 elsif id.is_a? String | |
218 if id[/\w+/] == id | |
219 id.downcase.to_sym | |
220 else | |
221 raise ArgumentError, "Invalid id given: #{id}" | |
222 end | |
223 else | |
224 raise ArgumentError, "String or Symbol expected, but #{id.class} given." | |
225 end | |
226 end | |
227 | |
228 end | |
229 | |
230 | |
231 # = Plugin | |
232 # | |
233 # Plugins have to include this module. | |
234 # | |
235 # IMPORTANT: Use extend for this module. | |
236 # | |
237 # See CodeRay::PluginHost for examples. | |
238 module Plugin | |
239 | |
240 attr_reader :plugin_id | |
241 | |
242 # Register this class for the given +id+. | |
243 # | |
244 # Example: | |
245 # class MyPlugin < PluginHost::BaseClass | |
246 # register_for :my_id | |
247 # ... | |
248 # end | |
249 # | |
250 # See PluginHost.register. | |
251 def register_for id | |
252 @plugin_id = id | |
253 plugin_host.register self, id | |
254 end | |
255 | |
256 # Returns the title of the plugin, or sets it to the | |
257 # optional argument +title+. | |
258 def title title = nil | |
259 if title | |
260 @title = title.to_s | |
261 else | |
262 @title ||= name[/([^:]+)$/, 1] | |
263 end | |
264 end | |
265 | |
266 # The PluginHost for this Plugin class. | |
267 def plugin_host host = nil | |
268 if host.is_a? PluginHost | |
269 const_set :PLUGIN_HOST, host | |
270 end | |
271 self::PLUGIN_HOST | |
272 end | |
273 | |
274 def aliases | |
275 plugin_host.load_plugin_map | |
276 plugin_host.plugin_hash.inject [] do |aliases, (key, _)| | |
277 aliases << key if plugin_host[key] == self | |
278 aliases | |
279 end | |
280 end | |
281 | |
282 end | |
283 | |
284 end |