gem_plugin 0.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/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ Ruby is copyrighted free software by Zed A. Shaw <zedshaw at zedshaw dot com>
2
+ You can redistribute it and/or modify it under either the terms of the GPL
3
+ or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) rename any non-standard executables so the names do not conflict
21
+ with standard executables, which must also be provided.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or executable
26
+ form, provided that you do at least ONE of the following:
27
+
28
+ a) distribute the executables and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard executables non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under this terms.
43
+
44
+ They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
45
+ files under the ./missing directory. See each file for the copying
46
+ condition.
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
58
+
data/README ADDED
@@ -0,0 +1,115 @@
1
+ = GemPlugin: Gem Based Plugin System
2
+
3
+ GemPlugin is a system that lets your users install gems and lets you load
4
+ them as additional features to use in your software. It originated from the
5
+ Mongrel (http://mongrel.rubyforge.org) project but proved useful enough to
6
+ break out into a separate project.
7
+
8
+ GemPlugin works by listing the gems installed, and doing a require_gem on
9
+ any that have the right dependencies. For example, if a gem depends on
10
+ "gem_plugin" and "mongrel" then it'll load as a Mongrel plugin. This
11
+ makes it so that users of the plugins only need to gem install (and maybe
12
+ config a bit), and plugin authors only need to make gems.
13
+
14
+
15
+ == Implementers
16
+
17
+ To use GemPlugin in your system you only have to require 'gem_plugin' and
18
+ then use the GemPlugin::Manager.create, GemPlugin::Manager.load, and
19
+ GemPlugin::Manager.available methods to work with them.
20
+
21
+ * GemPlugin::Manager.load -- Takes a "depend include/exclude map" and loads plugins based on it.
22
+ * GemPlugin::Manager.create -- Takes a URI style name and some options then creates one for you.
23
+ * GemPlugin::Manager.available -- Lets you inspect and mess with the internal plugin registry.
24
+
25
+ === Loading Plugins
26
+
27
+ As an example from Mongrel it's necessary to load plugins that depend on rails after
28
+ the Rails system is configured, but load other plugins right when Mongrel is ready.
29
+ To do this we very first do:
30
+
31
+ GemPlugin::Manager.instance.load "mongrel" => GemPlugin::INCLUDE, "rails" => GemPlugin::EXCLUDE
32
+
33
+ Later, when it's ready to load Rails plugins as well we do this:
34
+
35
+ GemPlugin::Manager.instance.load "mongrel" => GemPlugin::INCLUDE
36
+
37
+ This simply loads any plugins that remain and are ready for use in Rails.
38
+
39
+ === Creating Plugins
40
+
41
+ Creating a plugin is cake:
42
+
43
+ plug = GemPlugin::Manager.instance.create("/commands/snazzy", "something" => "yeah")
44
+
45
+ In this case we're making the snazzy command and passing a couple fake options.
46
+
47
+ === Finding Available Plugins
48
+
49
+ Finding plugins is also very easy, you just call GemPlugin::Manager.instance.available
50
+ and you get a Hash that maps categories to name => class. For example, if I had
51
+ the "/commands/snazzy" plugin registered above, then I'd get the following:
52
+
53
+ puts GemPlugin::Manager.instance.available["/commands"].inspect
54
+ -> { "/snazzy" => Snazzy}
55
+
56
+
57
+ === Plugins Inside Modules
58
+
59
+ Plugins that are placed in modules are also lowercased when registered but
60
+ still retain their module. So, if Snazzy was actually MyModule::Snazzy, then
61
+ it'd be registered as "/commands/mymodule::snazzy".
62
+
63
+
64
+ == Plugin Authors
65
+
66
+ People who wish to write gem plugins have a faily easy time of it, but need
67
+ to know the particular rules for the target system. To keep this example
68
+ concrete we'll assume you want to write a Mongrel command plugin.
69
+
70
+ First thing is create your project like normal and setup Rake to make
71
+ your gem. Your plugin then needs to be created like so:
72
+
73
+ class Snazzy < GemPlugin::Plugin "/commands"
74
+ ...
75
+ end
76
+
77
+ And place this code in a file you will have RubyGems autorequire (I use lib/init.rb).
78
+
79
+ Next you need to add the following to whatever Rakefile code you use to create
80
+ your gem:
81
+
82
+ spec.add_dependency('gem_plugin', '>= 0.1')
83
+ spec.add_dependency('mongrel', '>= 0.3.9')
84
+ spec.autorequire = 'init.rb'
85
+
86
+ This does three things:
87
+
88
+ * Tells GemPlugins::Manager.load that this is a GemPlugin.
89
+ * Tells Mongrel that this is a Mongrel specific GemPlugin.
90
+ * Tells RubyGems to run init.rb when the gem is required, just hooking up your plugin.
91
+
92
+ Now, all the users of your plugin have to do is gem install it and then
93
+ they get the plugin automagically.
94
+
95
+ People writing GemPlugins for other systems would have to check the
96
+ documentation from that project to get an idea of what extra
97
+ requirements might be needed. For example, you'd probably have to
98
+ depend on another project other that *mongrel* and most likely have
99
+ a few more things to configure in your init.rb.
100
+
101
+ == Plugin Users
102
+
103
+ Plugin users have it the easiest of all. They simply do:
104
+
105
+ gem install mongrel_command_snazzy
106
+
107
+ And that's it. When they run mongrel_rails (given the above example)
108
+ this snazzy command get loaded automatically without any intervention.
109
+
110
+ The only thing missing in this release is a way for end users to configure
111
+ such a plugin. I really think this is the job of the implementers to define.
112
+
113
+ == Contact
114
+
115
+ E-mail zedshaw at zedshaw.com and I'll help. Comments about the API are welcome.
@@ -0,0 +1,35 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/clean'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'tools/rakehelp'
7
+ require 'fileutils'
8
+ include FileUtils
9
+
10
+ setup_tests
11
+ setup_clean ["pkg", "lib/*.bundle", "*.gem", ".config"]
12
+
13
+ setup_rdoc ['README', 'LICENSE', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc']
14
+
15
+ desc "Does a full compile, test run"
16
+ task :default => [:test, :package]
17
+
18
+ version="0.1"
19
+ summary = "A plugin system based only on rubygems"
20
+ test_file = "test/test_plugins.rb"
21
+ author="Zed A. Shaw"
22
+ name="gem_plugin"
23
+ scripts=[]
24
+
25
+ setup_gem(name, version, author, summary, scripts, test_file) do |spec|
26
+ spec.autorequire = "gem_plugin"
27
+ end
28
+
29
+ task :gem_test => [:package] do
30
+ sh %{sudo gem install pkg/gem_plugin-#{version}}
31
+ end
32
+
33
+ task :site => [:rerdoc] do
34
+ sh %{ scp -r doc/rdoc/* #{ENV['SSH_USER']}@rubyforge.org:/var/www/gforge-projects/mongrel/gem_plugin_rdoc/ }
35
+ end
@@ -0,0 +1,247 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>Module: GemPlugin</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="classHeader">
50
+ <table class="header-table">
51
+ <tr class="top-aligned-row">
52
+ <td><strong>Module</strong></td>
53
+ <td class="class-name-in-header">GemPlugin</td>
54
+ </tr>
55
+ <tr class="top-aligned-row">
56
+ <td><strong>In:</strong></td>
57
+ <td>
58
+ <a href="../files/lib/gem_plugin_rb.html">
59
+ lib/gem_plugin.rb
60
+ </a>
61
+ <br />
62
+ </td>
63
+ </tr>
64
+
65
+ </table>
66
+ </div>
67
+ <!-- banner header -->
68
+
69
+ <div id="bodyContent">
70
+
71
+
72
+
73
+ <div id="contextContent">
74
+
75
+ <div id="description">
76
+ <p>
77
+ Implements a dynamic plugin loading, configuration, and discovery system
78
+ based on RubyGems and a simple additional name space that looks like a URI.
79
+ </p>
80
+ <p>
81
+ A plugin is created and put into a category with the following code:
82
+ </p>
83
+ <pre>
84
+ class MyThing &lt; GemPlugin::Plugin &quot;/things&quot;
85
+ ...
86
+ end
87
+ </pre>
88
+ <p>
89
+ What this does is sets up your MyThing in the plugin registry via <a
90
+ href="GemPlugin/Manager.html">GemPlugin::Manager</a>. You can then later
91
+ get this plugin with <a
92
+ href="GemPlugin/Manager.html#M000008">GemPlugin::Manager.create</a>(&quot;/things/mything&quot;)
93
+ and can also pass in options as a second parameter.
94
+ </p>
95
+ <p>
96
+ This isn&#8217;t such a big deal, but the power is really from the <a
97
+ href="GemPlugin/Manager.html#M000006">GemPlugin::Manager.load</a> method.
98
+ This method will go through the installed gems and require_gem any that
99
+ depend on the gem_plugin RubyGem. You can arbitrarily include or exclude
100
+ gems based on what they also depend on, thus letting you load these gems
101
+ when appropriate.
102
+ </p>
103
+ <p>
104
+ Since this system was written originally for the Mongrel project
105
+ that&#8217;ll be the best examle of using it.
106
+ </p>
107
+ <p>
108
+ Imagine you have a neat plugin for Mongrel called snazzy_command that give
109
+ the mongrel_rails a new command snazzy (like: mongrel_rails snazzy).
110
+ You&#8216;d like people to be able to grab this plugin if they want and use
111
+ it, because it&#8217;s snazzy.
112
+ </p>
113
+ <p>
114
+ First thing you do is create a gem of your project and make sure that it
115
+ depends on &quot;mongrel&quot; AND &quot;gem_plugin&quot;. This signals to
116
+ the <a href="GemPlugin.html">GemPlugin</a> system that this is a plugin for
117
+ mongrel.
118
+ </p>
119
+ <p>
120
+ Next you put this code into a file like lib/init.rb (can be anything
121
+ really):
122
+ </p>
123
+ <pre>
124
+ class Snazzy &lt; GemPlugin::Plugin &quot;/commands&quot;
125
+ ...
126
+ end
127
+ </pre>
128
+ <p>
129
+ Then when you create your gem you have the following bits in your Rakefile:
130
+ </p>
131
+ <pre>
132
+ spec.add_dependency('mongrel', '&gt;= 0.3.9')
133
+ spec.add_dependency('gem_plugin', '&gt;= 0.1')
134
+ spec.autorequire = 'init.rb'
135
+ </pre>
136
+ <p>
137
+ Finally, you just have to now publish this gem for people to install and
138
+ Mongrel will &quot;magically&quot; be able to install it.
139
+ </p>
140
+ <p>
141
+ The &quot;magic&quot; part though is pretty simple and done via the <a
142
+ href="GemPlugin/Manager.html#M000006">GemPlugin::Manager.load</a> method.
143
+ Read that to see how it is really done.
144
+ </p>
145
+
146
+ </div>
147
+
148
+
149
+ </div>
150
+
151
+ <div id="method-list">
152
+ <h3 class="section-bar">Methods</h3>
153
+
154
+ <div class="name-list">
155
+ <a href="#M000001">Plugin</a>&nbsp;&nbsp;
156
+ </div>
157
+ </div>
158
+
159
+ </div>
160
+
161
+
162
+ <!-- if includes -->
163
+
164
+ <div id="section">
165
+
166
+ <div id="class-list">
167
+ <h3 class="section-bar">Classes and Modules</h3>
168
+
169
+ Class <a href="GemPlugin/Base.html" class="link">GemPlugin::Base</a><br />
170
+ Class <a href="GemPlugin/Manager.html" class="link">GemPlugin::Manager</a><br />
171
+
172
+ </div>
173
+
174
+ <div id="constants-list">
175
+ <h3 class="section-bar">Constants</h3>
176
+
177
+ <div class="name-list">
178
+ <table summary="Constants">
179
+ <tr class="top-aligned-row context-row">
180
+ <td class="context-item-name">EXCLUDE</td>
181
+ <td>=</td>
182
+ <td class="context-item-value">true</td>
183
+ </tr>
184
+ <tr class="top-aligned-row context-row">
185
+ <td class="context-item-name">INCLUDE</td>
186
+ <td>=</td>
187
+ <td class="context-item-value">false</td>
188
+ </tr>
189
+ </table>
190
+ </div>
191
+ </div>
192
+
193
+
194
+
195
+
196
+
197
+
198
+ <!-- if method_list -->
199
+ <div id="methods">
200
+ <h3 class="section-bar">Public Class methods</h3>
201
+
202
+ <div id="method-M000001" class="method-detail">
203
+ <a name="M000001"></a>
204
+
205
+ <div class="method-heading">
206
+ <a href="GemPlugin.src/M000001.html" target="Code" class="method-signature"
207
+ onclick="popupCode('GemPlugin.src/M000001.html');return false;">
208
+ <span class="method-name">Plugin</span><span class="method-args">(c)</span>
209
+ </a>
210
+ </div>
211
+
212
+ <div class="method-description">
213
+ <p>
214
+ This nifty function works with the <a
215
+ href="GemPlugin/Base.html">GemPlugin::Base</a> to give you the syntax:
216
+ </p>
217
+ <pre>
218
+ class MyThing &lt; GemPlugin::Plugin &quot;/things&quot;
219
+ ...
220
+ end
221
+ </pre>
222
+ <p>
223
+ What it does is temporarily sets the GemPlugin::Base.category, and then
224
+ returns <a href="GemPlugin/Base.html">GemPlugin::Base</a>. Since the next
225
+ immediate thing Ruby does is use this returned class to create the new
226
+ class, <a href="GemPlugin/Base.html#M000002">GemPlugin::Base.inherited</a>
227
+ gets called. <a
228
+ href="GemPlugin/Base.html#M000002">GemPlugin::Base.inherited</a> then uses
229
+ the set category, class name, and class to register the plugin in the right
230
+ way.
231
+ </p>
232
+ </div>
233
+ </div>
234
+
235
+
236
+ </div>
237
+
238
+
239
+ </div>
240
+
241
+
242
+ <div id="validator-badges">
243
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
244
+ </div>
245
+
246
+ </body>
247
+ </html>