Mercurial > hg > soundsoftware-site
comparison vendor/plugins/coderay-0.9.2/lib/coderay/helpers/.svn/text-base/plugin.rb.svn-base @ 0:513646585e45
* Import Redmine trunk SVN rev 3859
author | Chris Cannam |
---|---|
date | Fri, 23 Jul 2010 15:52:44 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:513646585e45 |
---|---|
1 module CodeRay | |
2 | |
3 # = PluginHost | |
4 # | |
5 # A simple subclass plugin system. | |
6 # | |
7 # Example: | |
8 # class Generators < PluginHost | |
9 # plugin_path 'app/generators' | |
10 # end | |
11 # | |
12 # class Generator | |
13 # extend Plugin | |
14 # PLUGIN_HOST = Generators | |
15 # end | |
16 # | |
17 # class FancyGenerator < Generator | |
18 # register_for :fancy | |
19 # end | |
20 # | |
21 # Generators[:fancy] #-> FancyGenerator | |
22 # # or | |
23 # CodeRay.require_plugin 'Generators/fancy' | |
24 module PluginHost | |
25 | |
26 # Raised if Encoders::[] fails because: | |
27 # * a file could not be found | |
28 # * the requested Encoder is not registered | |
29 PluginNotFound = Class.new Exception | |
30 HostNotFound = Class.new Exception | |
31 | |
32 PLUGIN_HOSTS = [] | |
33 PLUGIN_HOSTS_BY_ID = {} # dummy hash | |
34 | |
35 # Loads all plugins using list and load. | |
36 def load_all | |
37 for plugin in list | |
38 load plugin | |
39 end | |
40 end | |
41 | |
42 # Returns the Plugin for +id+. | |
43 # | |
44 # Example: | |
45 # yaml_plugin = MyPluginHost[:yaml] | |
46 def [] id, *args, &blk | |
47 plugin = validate_id(id) | |
48 begin | |
49 plugin = plugin_hash.[] plugin, *args, &blk | |
50 end while plugin.is_a? Symbol | |
51 plugin | |
52 end | |
53 | |
54 # Alias for +[]+. | |
55 alias load [] | |
56 | |
57 def require_helper plugin_id, helper_name | |
58 path = path_to File.join(plugin_id, helper_name) | |
59 require path | |
60 end | |
61 | |
62 class << self | |
63 | |
64 # Adds the module/class to the PLUGIN_HOSTS list. | |
65 def extended mod | |
66 PLUGIN_HOSTS << mod | |
67 end | |
68 | |
69 # Warns you that you should not #include this module. | |
70 def included mod | |
71 warn "#{name} should not be included. Use extend." | |
72 end | |
73 | |
74 # Find the PluginHost for host_id. | |
75 def host_by_id host_id | |
76 unless PLUGIN_HOSTS_BY_ID.default_proc | |
77 ph = Hash.new do |h, a_host_id| | |
78 for host in PLUGIN_HOSTS | |
79 h[host.host_id] = host | |
80 end | |
81 h.fetch a_host_id, nil | |
82 end | |
83 PLUGIN_HOSTS_BY_ID.replace ph | |
84 end | |
85 PLUGIN_HOSTS_BY_ID[host_id] | |
86 end | |
87 | |
88 end | |
89 | |
90 # The path where the plugins can be found. | |
91 def plugin_path *args | |
92 unless args.empty? | |
93 @plugin_path = File.expand_path File.join(*args) | |
94 load_map | |
95 end | |
96 @plugin_path | |
97 end | |
98 | |
99 # The host's ID. | |
100 # | |
101 # If PLUGIN_HOST_ID is not set, it is simply the class name. | |
102 def host_id | |
103 if self.const_defined? :PLUGIN_HOST_ID | |
104 self::PLUGIN_HOST_ID | |
105 else | |
106 name | |
107 end | |
108 end | |
109 | |
110 # Map a plugin_id to another. | |
111 # | |
112 # Usage: Put this in a file plugin_path/_map.rb. | |
113 # | |
114 # class MyColorHost < PluginHost | |
115 # map :navy => :dark_blue, | |
116 # :maroon => :brown, | |
117 # :luna => :moon | |
118 # end | |
119 def map hash | |
120 for from, to in hash | |
121 from = validate_id from | |
122 to = validate_id to | |
123 plugin_hash[from] = to unless plugin_hash.has_key? from | |
124 end | |
125 end | |
126 | |
127 # Define the default plugin to use when no plugin is found | |
128 # for a given id. | |
129 # | |
130 # See also map. | |
131 # | |
132 # class MyColorHost < PluginHost | |
133 # map :navy => :dark_blue | |
134 # default :gray | |
135 # end | |
136 def default id = nil | |
137 if id | |
138 id = validate_id id | |
139 plugin_hash[nil] = id | |
140 else | |
141 plugin_hash[nil] | |
142 end | |
143 end | |
144 | |
145 # Every plugin must register itself for one or more | |
146 # +ids+ by calling register_for, which calls this method. | |
147 # | |
148 # See Plugin#register_for. | |
149 def register plugin, *ids | |
150 for id in ids | |
151 unless id.is_a? Symbol | |
152 raise ArgumentError, | |
153 "id must be a Symbol, but it was a #{id.class}" | |
154 end | |
155 plugin_hash[validate_id(id)] = plugin | |
156 end | |
157 end | |
158 | |
159 # A Hash of plugion_id => Plugin pairs. | |
160 def plugin_hash | |
161 @plugin_hash ||= create_plugin_hash | |
162 end | |
163 | |
164 # Returns an array of all .rb files in the plugin path. | |
165 # | |
166 # The extension .rb is not included. | |
167 def list | |
168 Dir[path_to('*')].select do |file| | |
169 File.basename(file)[/^(?!_)\w+\.rb$/] | |
170 end.map do |file| | |
171 File.basename file, '.rb' | |
172 end | |
173 end | |
174 | |
175 # Makes a map of all loaded plugins. | |
176 def inspect | |
177 map = plugin_hash.dup | |
178 map.each do |id, plugin| | |
179 map[id] = plugin.to_s[/(?>\w+)$/] | |
180 end | |
181 "#{name}[#{host_id}]#{map.inspect}" | |
182 end | |
183 | |
184 protected | |
185 # Created a new plugin list and stores it to @plugin_hash. | |
186 def create_plugin_hash | |
187 @plugin_hash = | |
188 Hash.new do |h, plugin_id| | |
189 id = validate_id(plugin_id) | |
190 path = path_to id | |
191 begin | |
192 require path | |
193 rescue LoadError => boom | |
194 if h.has_key? nil # default plugin | |
195 h[id] = h[nil] | |
196 else | |
197 raise PluginNotFound, 'Could not load plugin %p: %s' % [id, boom] | |
198 end | |
199 else | |
200 # Plugin should have registered by now | |
201 unless h.has_key? id | |
202 raise PluginNotFound, | |
203 "No #{self.name} plugin for #{id.inspect} found in #{path}." | |
204 end | |
205 end | |
206 h[id] | |
207 end | |
208 end | |
209 | |
210 # Loads the map file (see map). | |
211 # | |
212 # This is done automatically when plugin_path is called. | |
213 def load_map | |
214 mapfile = path_to '_map' | |
215 if File.exist? mapfile | |
216 require mapfile | |
217 elsif $VERBOSE | |
218 warn 'no _map.rb found for %s' % name | |
219 end | |
220 end | |
221 | |
222 # Returns the Plugin for +id+. | |
223 # Use it like Hash#fetch. | |
224 # | |
225 # Example: | |
226 # yaml_plugin = MyPluginHost[:yaml, :default] | |
227 def fetch id, *args, &blk | |
228 plugin_hash.fetch validate_id(id), *args, &blk | |
229 end | |
230 | |
231 # Returns the expected path to the plugin file for the given id. | |
232 def path_to plugin_id | |
233 File.join plugin_path, "#{plugin_id}.rb" | |
234 end | |
235 | |
236 # Converts +id+ to a Symbol if it is a String, | |
237 # or returns +id+ if it already is a Symbol. | |
238 # | |
239 # Raises +ArgumentError+ for all other objects, or if the | |
240 # given String includes non-alphanumeric characters (\W). | |
241 def validate_id id | |
242 if id.is_a? Symbol or id.nil? | |
243 id | |
244 elsif id.is_a? String | |
245 if id[/\w+/] == id | |
246 id.downcase.to_sym | |
247 else | |
248 raise ArgumentError, "Invalid id: '#{id}' given." | |
249 end | |
250 else | |
251 raise ArgumentError, | |
252 "String or Symbol expected, but #{id.class} given." | |
253 end | |
254 end | |
255 | |
256 end | |
257 | |
258 | |
259 # = Plugin | |
260 # | |
261 # Plugins have to include this module. | |
262 # | |
263 # IMPORTANT: use extend for this module. | |
264 # | |
265 # Example: see PluginHost. | |
266 module Plugin | |
267 | |
268 def included mod | |
269 warn "#{name} should not be included. Use extend." | |
270 end | |
271 | |
272 # Register this class for the given langs. | |
273 # Example: | |
274 # class MyPlugin < PluginHost::BaseClass | |
275 # register_for :my_id | |
276 # ... | |
277 # end | |
278 # | |
279 # See PluginHost.register. | |
280 def register_for *ids | |
281 plugin_host.register self, *ids | |
282 end | |
283 | |
284 # Returns the title of the plugin, or sets it to the | |
285 # optional argument +title+. | |
286 def title title = nil | |
287 if title | |
288 @title = title.to_s | |
289 else | |
290 @title ||= name[/([^:]+)$/, 1] | |
291 end | |
292 end | |
293 | |
294 # The host for this Plugin class. | |
295 def plugin_host host = nil | |
296 if host and not host.is_a? PluginHost | |
297 raise ArgumentError, | |
298 "PluginHost expected, but #{host.class} given." | |
299 end | |
300 self.const_set :PLUGIN_HOST, host if host | |
301 self::PLUGIN_HOST | |
302 end | |
303 | |
304 # Require some helper files. | |
305 # | |
306 # Example: | |
307 # | |
308 # class MyPlugin < PluginHost::BaseClass | |
309 # register_for :my_id | |
310 # helper :my_helper | |
311 # | |
312 # The above example loads the file myplugin/my_helper.rb relative to the | |
313 # file in which MyPlugin was defined. | |
314 # | |
315 # You can also load a helper from a different plugin: | |
316 # | |
317 # helper 'other_plugin/helper_name' | |
318 def helper *helpers | |
319 for helper in helpers | |
320 if helper.is_a?(String) && helper[/\//] | |
321 self::PLUGIN_HOST.require_helper $`, $' | |
322 else | |
323 self::PLUGIN_HOST.require_helper plugin_id, helper.to_s | |
324 end | |
325 end | |
326 end | |
327 | |
328 # Returns the pulgin id used by the engine. | |
329 def plugin_id | |
330 name[/\w+$/].downcase | |
331 end | |
332 | |
333 end | |
334 | |
335 # Convenience method for plugin loading. | |
336 # The syntax used is: | |
337 # | |
338 # CodeRay.require_plugin '<Host ID>/<Plugin ID>' | |
339 # | |
340 # Returns the loaded plugin. | |
341 def self.require_plugin path | |
342 host_id, plugin_id = path.split '/', 2 | |
343 host = PluginHost.host_by_id(host_id) | |
344 raise PluginHost::HostNotFound, | |
345 "No host for #{host_id.inspect} found." unless host | |
346 host.load plugin_id | |
347 end | |
348 | |
349 end |