mongrel 0.3 → 0.3.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.
Files changed (78) hide show
  1. data/README +24 -28
  2. data/Rakefile +11 -4
  3. data/bin/mongrel_rails +82 -25
  4. data/doc/rdoc/classes/FactoryError.html +144 -0
  5. data/doc/rdoc/classes/FactoryError.src/M000001.html +23 -0
  6. data/doc/rdoc/classes/Mongrel.html +5 -5
  7. data/doc/rdoc/classes/Mongrel.src/{M000001.html → M000015.html} +4 -4
  8. data/doc/rdoc/classes/Mongrel/Const.html +2 -2
  9. data/doc/rdoc/classes/Mongrel/DirHandler.html +26 -26
  10. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000009.html → M000023.html} +0 -0
  11. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000010.html → M000024.html} +5 -2
  12. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000011.html → M000025.html} +26 -26
  13. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000012.html → M000026.html} +17 -17
  14. data/doc/rdoc/classes/Mongrel/DirHandler.src/{M000013.html → M000027.html} +24 -24
  15. data/doc/rdoc/classes/Mongrel/Error404Handler.html +10 -10
  16. data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000033.html → M000047.html} +0 -0
  17. data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000034.html → M000048.html} +0 -0
  18. data/doc/rdoc/classes/Mongrel/HeaderOut.html +10 -10
  19. data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000019.html → M000033.html} +0 -0
  20. data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000020.html → M000034.html} +0 -0
  21. data/doc/rdoc/classes/Mongrel/HttpHandler.html +5 -5
  22. data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000025.html → M000039.html} +0 -0
  23. data/doc/rdoc/classes/Mongrel/HttpParser.html +35 -35
  24. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000002.html → M000016.html} +0 -0
  25. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000003.html → M000017.html} +0 -0
  26. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000004.html → M000018.html} +0 -0
  27. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000005.html → M000019.html} +0 -0
  28. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000006.html → M000020.html} +0 -0
  29. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000007.html → M000021.html} +0 -0
  30. data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000008.html → M000022.html} +0 -0
  31. data/doc/rdoc/classes/Mongrel/HttpRequest.html +5 -5
  32. data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000035.html → M000049.html} +0 -0
  33. data/doc/rdoc/classes/Mongrel/HttpResponse.html +36 -36
  34. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000026.html → M000040.html} +0 -0
  35. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000027.html → M000041.html} +1 -1
  36. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000028.html → M000042.html} +0 -0
  37. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000029.html → M000043.html} +1 -1
  38. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000030.html → M000044.html} +0 -0
  39. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000031.html → M000045.html} +0 -0
  40. data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000032.html → M000046.html} +0 -0
  41. data/doc/rdoc/classes/Mongrel/HttpServer.html +28 -28
  42. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000014.html → M000028.html} +0 -0
  43. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000015.html → M000029.html} +0 -0
  44. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000016.html → M000030.html} +0 -0
  45. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000017.html → M000031.html} +0 -0
  46. data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000018.html → M000032.html} +0 -0
  47. data/doc/rdoc/classes/Mongrel/URIClassifier.html +20 -20
  48. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000021.html → M000035.html} +0 -0
  49. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000022.html → M000036.html} +0 -0
  50. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000023.html → M000037.html} +0 -0
  51. data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000024.html → M000038.html} +0 -0
  52. data/doc/rdoc/classes/PluginFactory.html +409 -0
  53. data/doc/rdoc/classes/PluginFactory.src/M000002.html +18 -0
  54. data/doc/rdoc/classes/PluginFactory.src/M000003.html +18 -0
  55. data/doc/rdoc/classes/PluginFactory.src/M000004.html +22 -0
  56. data/doc/rdoc/classes/PluginFactory.src/M000005.html +22 -0
  57. data/doc/rdoc/classes/PluginFactory.src/M000006.html +33 -0
  58. data/doc/rdoc/classes/PluginFactory.src/M000007.html +32 -0
  59. data/doc/rdoc/classes/PluginFactory.src/M000008.html +18 -0
  60. data/doc/rdoc/classes/PluginFactory.src/M000009.html +24 -0
  61. data/doc/rdoc/classes/PluginFactory.src/M000010.html +40 -0
  62. data/doc/rdoc/classes/PluginFactory.src/M000011.html +39 -0
  63. data/doc/rdoc/classes/PluginFactory.src/M000012.html +24 -0
  64. data/doc/rdoc/classes/PluginFactory.src/M000013.html +70 -0
  65. data/doc/rdoc/classes/PluginFactory.src/M000014.html +34 -0
  66. data/doc/rdoc/created.rid +1 -1
  67. data/doc/rdoc/files/README.html +29 -37
  68. data/doc/rdoc/files/lib/mongrel_rb.html +1 -1
  69. data/doc/rdoc/files/lib/pluginfactory_rb.html +132 -0
  70. data/doc/rdoc/fr_class_index.html +2 -0
  71. data/doc/rdoc/fr_file_index.html +1 -0
  72. data/doc/rdoc/fr_method_index.html +49 -35
  73. data/examples/simpletest.rb +10 -3
  74. data/lib/mongrel.rb +6 -3
  75. data/lib/mongrel/command.rb +192 -0
  76. data/lib/pluginfactory.rb +384 -0
  77. data/tools/rakehelp.rb +33 -29
  78. metadata +71 -41
@@ -0,0 +1,384 @@
1
+ #!/usr/bin/env ruby -w
2
+ #
3
+ # This module contains the PluginFactory mixin. Including PluginFactory in your
4
+ # class turns it into a factory for its derivatives, capable of searching for
5
+ # and loading them by name. This is useful when you have an abstract base class
6
+ # which defines an interface and basic functionality for a part of a larger
7
+ # system, and a collection of subclasses which implement the interface for
8
+ # different underlying functionality.
9
+ #
10
+ # An example of where this might be useful is in a program which talks to a
11
+ # database. To avoid coupling it to a specific database, you use a Driver class
12
+ # which encapsulates your program's interaction with the database behind a
13
+ # useful interface. Now you can create a concrete implementation of the Driver
14
+ # class for each kind of database you wish to talk to. If you make the base
15
+ # Driver class a PluginFactory, too, you can add new drivers simply by dropping
16
+ # them in a directory and using the Driver's <tt>create</tt> method to
17
+ # instantiate them:
18
+ #
19
+ # == Creation Argument Variants
20
+ #
21
+ # The +create+ class method added to your class by PluginFactory searches for your module using
22
+ #
23
+ # == Synopsis
24
+ #
25
+ #---##### in driver.rb #####---
26
+ #
27
+ # require "PluginFactory"
28
+ #
29
+ # class Driver
30
+ # include PluginFactory
31
+ # def self::derivativeDirs
32
+ # ["drivers"]
33
+ # end
34
+ # end
35
+ #
36
+ #---##########
37
+ #
38
+ #---##### in drivers/mysql.rb #####
39
+ #
40
+ # require 'driver'
41
+ #
42
+ # class MysqlDriver < Driver
43
+ # ...implementation...
44
+ # end
45
+ #
46
+ #---##########
47
+ #
48
+ #---##### in /usr/lib/ruby/1.8/PostgresDriver.rb #####
49
+ #
50
+ # require 'driver'
51
+ #
52
+ # class PostgresDriver < Driver
53
+ # ...implementation...
54
+ # end
55
+ #
56
+ #---##########
57
+ #
58
+ #---##### elsewhere #####
59
+ #
60
+ # require 'driver'
61
+ #
62
+ # config[:driver_type] #=> "mysql"
63
+ # driver = Driver::create( config[:driver_type] )
64
+ # driver.class #=> MysqlDriver
65
+ # pgdriver = Driver::create( "PostGresDriver" )
66
+ #
67
+ #---##########
68
+ #
69
+ # == Rcsid
70
+ #
71
+ # $Id: pluginfactory.rb 32 2005-03-05 00:21:05Z ged $
72
+ #
73
+ # == Authors
74
+ #
75
+ # * Martin Chase <stillflame@FaerieMUD.org>
76
+ # * Michael Granger <ged@FaerieMUD.org>
77
+ #
78
+ # modified temporarily by Zed A. Shaw until license attribution can be given.
79
+ #---
80
+ #
81
+ # Please see the file docs/COPYRIGHT for licensing details.
82
+ #
83
+
84
+
85
+ ### An exception class for PluginFactory specific errors.
86
+ class FactoryError < RuntimeError
87
+ def initialize( *args )
88
+ if ! args.empty?
89
+ msg = args.collect {|a| a.to_s}.join
90
+ super( msg )
91
+ else
92
+ super( message )
93
+ end
94
+ end
95
+ end # class FactoryError
96
+
97
+
98
+ ### A mixin that adds PluginFactory class methods to a base class, so that
99
+ ### subclasses may be instantiated by name.
100
+ module PluginFactory
101
+
102
+ ### A callback for logging the various debug and information this module
103
+ ### has to log. Should take two arguments, the log level, possibly as a
104
+ ### symbol, and the log message itself.
105
+ @logger_callback = nil
106
+ class << self
107
+ attr_accessor :logger_callback
108
+ end
109
+
110
+ ### If the logger callback is set, use it to pass on a log entry. First argument is
111
+ def self::log(level, *msg)
112
+ @logger_callback.call(level, msg.join) if @logger_callback
113
+ end
114
+
115
+
116
+ ### Inclusion callback -- extends the including class.
117
+ def self::included( klass )
118
+ klass.extend( self )
119
+ end
120
+
121
+
122
+ ### Raise an exception if the object being extended is anything but a
123
+ ### class.
124
+ def self::extend_object( obj )
125
+ unless obj.is_a?( Class )
126
+ raise TypeError, "Cannot extend a #{obj.class.name}", caller(1)
127
+ end
128
+ obj.instance_variable_set( :@derivatives, {} )
129
+ super
130
+ end
131
+
132
+
133
+ #############################################################
134
+ ### M I X I N M E T H O D S
135
+ #############################################################
136
+
137
+ ### Return the Hash of derivative classes, keyed by various versions of
138
+ ### the class name.
139
+ def derivatives
140
+ ancestors.each {|klass|
141
+ if klass.instance_variables.include?( "@derivatives" )
142
+ break klass.instance_variable_get( :@derivatives )
143
+ end
144
+ }
145
+ end
146
+
147
+
148
+ ### Returns the type name used when searching for a derivative.
149
+ def factoryType
150
+ base = nil
151
+ self.ancestors.each {|klass|
152
+ if klass.instance_variables.include?( "@derivatives" )
153
+ base = klass
154
+ break
155
+ end
156
+ }
157
+
158
+ raise FactoryError, "Couldn't find factory base for #{self.name}" if
159
+ base.nil?
160
+
161
+ if base.name =~ /^.*::(.*)/
162
+ return $1
163
+ else
164
+ return base.name
165
+ end
166
+ end
167
+
168
+
169
+ ### Inheritance callback -- Register subclasses in the derivatives hash
170
+ ### so that ::create knows about them.
171
+ def inherited( subclass )
172
+ keys = [ subclass.name, subclass.name.downcase, subclass ]
173
+
174
+ # Handle class names like 'FooBar' for 'Bar' factories.
175
+ if subclass.name.match( /(?:.*::)?(\w+)(?:#{self.factoryType})/i )
176
+ keys << Regexp.last_match[1].downcase
177
+ else
178
+ keys << subclass.name.sub( /.*::/, '' ).downcase
179
+ end
180
+
181
+ keys.uniq.each {|key|
182
+ #PluginFactory::log :info, "Registering %s derivative of %s as %p" %
183
+ # [ subclass.name, self.name, key ]
184
+ self.derivatives[ key ] = subclass
185
+ }
186
+ super
187
+ end
188
+
189
+
190
+ ### Returns an Array of registered derivatives
191
+ def derivativeClasses
192
+ self.derivatives.values.uniq
193
+ end
194
+
195
+
196
+ ### Given the <tt>className</tt> of the class to instantiate, and other
197
+ ### arguments bound for the constructor of the new object, this method
198
+ ### loads the derivative class if it is not loaded already (raising a
199
+ ### LoadError if an appropriately-named file cannot be found), and
200
+ ### instantiates it with the given <tt>args</tt>. The <tt>className</tt>
201
+ ### may be the the fully qualified name of the class, the class object
202
+ ### itself, or the unique part of the class name. The following examples
203
+ ### would all try to load and instantiate a class called "FooListener"
204
+ ### if Listener included Factory
205
+ ### obj = Listener::create( 'FooListener' )
206
+ ### obj = Listener::create( FooListener )
207
+ ### obj = Listener::create( 'Foo' )
208
+ def create( subType, *args, &block )
209
+ subclass = getSubclass( subType )
210
+
211
+ return subclass.new( *args, &block )
212
+ rescue => err
213
+ nicetrace = err.backtrace.reject {|frame| /#{__FILE__}/ =~ frame}
214
+ msg = "When creating '#{subType}': " + err.message
215
+ Kernel::raise( err.class, msg, nicetrace )
216
+ end
217
+
218
+
219
+ ### Given a <tt>className</tt> like that of the first argument to
220
+ ### #create, attempt to load the corresponding class if it is not
221
+ ### already loaded and return the class object.
222
+ def getSubclass( className )
223
+ return self if ( self.name == className || className == '' )
224
+ return className if className.is_a?( Class ) && className >= self
225
+
226
+ unless self.derivatives.has_key?( className.downcase )
227
+ self.loadDerivative( className )
228
+
229
+ unless self.derivatives.has_key?( className.downcase )
230
+ raise FactoryError,
231
+ "loadDerivative(%s) didn't add a '%s' key to the "\
232
+ "registry for %s" %
233
+ [ className, className.downcase, self.name ]
234
+ end
235
+
236
+ subclass = self.derivatives[ className.downcase ]
237
+ unless subclass.is_a?( Class )
238
+ raise FactoryError,
239
+ "loadDerivative(%s) added something other than a class "\
240
+ "to the registry for %s: %p" %
241
+ [ className, self.name, subclass ]
242
+ end
243
+ end
244
+
245
+ return self.derivatives[ className.downcase ]
246
+ end
247
+
248
+
249
+ ### Calculates an appropriate filename for the derived class using the
250
+ ### name of the base class and tries to load it via <tt>require</tt>. If
251
+ ### the including class responds to a method named
252
+ ### <tt>derivativeDirs</tt>, its return value (either a String, or an
253
+ ### array of Strings) is added to the list of prefix directories to try
254
+ ### when attempting to require a modules. Eg., if
255
+ ### <tt>class.derivativeDirs</tt> returns <tt>['foo','bar']</tt> the
256
+ ### require line is tried with both <tt>'foo/'</tt> and <tt>'bar/'</tt>
257
+ ### prepended to it.
258
+ def loadDerivative( className )
259
+ className = className.to_s
260
+
261
+ #PluginFactory::log :debug, "Loading derivative #{className}"
262
+
263
+ # Get the unique part of the derived class name and try to
264
+ # load it from one of the derivative subdirs, if there are
265
+ # any.
266
+ modName = self.getModuleName( className )
267
+ self.requireDerivative( modName )
268
+
269
+ # Check to see if the specified listener is now loaded. If it
270
+ # is not, raise an error to that effect.
271
+ unless self.derivatives[ className.downcase ]
272
+ raise FactoryError,
273
+ "Couldn't find a %s named '%s'. Loaded derivatives are: %p" % [
274
+ self.factoryType,
275
+ className.downcase,
276
+ self.derivatives.keys,
277
+ ], caller(3)
278
+ end
279
+
280
+ return true
281
+ end
282
+
283
+
284
+ ### Build and return the unique part of the given <tt>className</tt>
285
+ ### either by stripping leading namespaces if the name already has the
286
+ ### name of the factory type in it (eg., 'My::FooService' for Service,
287
+ ### or by appending the factory type if it doesn't.
288
+ def getModuleName( className )
289
+ if className =~ /\w+#{self.factoryType}/
290
+ modName = className.sub( /(?:.*::)?(\w+)(?:#{self.factoryType})/, "\\1" )
291
+ else
292
+ modName = className
293
+ end
294
+
295
+ return modName
296
+ end
297
+
298
+
299
+ ### If the factory responds to the #derivativeDirs method, call
300
+ ### it and use the returned array as a list of directories to
301
+ ### search for the module with the specified <tt>modName</tt>.
302
+ def requireDerivative( modName )
303
+
304
+ # See if we have a list of special subdirs that derivatives
305
+ # live in
306
+ if ( self.respond_to?(:derivativeDirs) )
307
+ subdirs = self.derivativeDirs
308
+ subdirs = [ subdirs ] unless subdirs.is_a?( Array )
309
+
310
+ # If not, just try requiring it from $LOAD_PATH
311
+ else
312
+ subdirs = ['']
313
+ end
314
+
315
+ fatals = []
316
+
317
+ # Iterate over the subdirs until we successfully require a
318
+ # module.
319
+ catch( :found ) {
320
+ subdirs.collect {|dir| dir.strip}.each do |subdir|
321
+ self.makeRequirePath( modName, subdir ).each {|path|
322
+ #PluginFactory::log :debug, "Trying #{path}..."
323
+
324
+ # Try to require the module, saving errors and jumping
325
+ # out of the catch block on success.
326
+ begin
327
+ require( path.untaint )
328
+ rescue LoadError => err
329
+ PluginFactory::log :debug,
330
+ "No module at '%s', trying the next alternative: '%s'" %
331
+ [ path, err.message ]
332
+ rescue ScriptError,StandardError => err
333
+ fatals << err
334
+ PluginFactory::log :error,
335
+ "Found '#{path}', but encountered an error: %s\n\t%s" %
336
+ [ err.message, err.backtrace.join("\n\t") ]
337
+ else
338
+ #PluginFactory::log :debug,
339
+ # "Found '#{path}'. Throwing :found"
340
+ throw :found
341
+ end
342
+ }
343
+ end
344
+
345
+ #PluginFactory::log :debug, "fatals = %p" % [ fatals ]
346
+
347
+ # Re-raise is there was a file found, but it didn't load for
348
+ # some reason.
349
+ if ! fatals.empty?
350
+ #PluginFactory::log :debug, "Re-raising first fatal error"
351
+ Kernel::raise( fatals.first )
352
+ end
353
+
354
+ nil
355
+ }
356
+ end
357
+
358
+
359
+ ### Make a list of permutations of the given +modname+ for the given
360
+ ### +subdir+. Called on a +DataDriver+ class with the arguments 'Socket' and
361
+ ### 'drivers', returns:
362
+ ### ["drivers/socketdatadriver", "drivers/socketDataDriver",
363
+ ### "drivers/SocketDataDriver", "drivers/socket", "drivers/Socket"]
364
+ def makeRequirePath( modname, subdir )
365
+ path = []
366
+ myname = self.factoryType
367
+
368
+ # Make permutations of the two parts
369
+ path << modname
370
+ path << modname.downcase
371
+ path << modname + myname
372
+ path << modname.downcase + myname
373
+ path << modname.downcase + myname.downcase
374
+
375
+ # If a non-empty subdir was given, prepend it to all the items in the
376
+ # path
377
+ unless subdir.nil? or subdir.empty?
378
+ path.collect! {|m| File::join(subdir, m)}
379
+ end
380
+
381
+ return path.uniq.reverse
382
+ end
383
+
384
+ end # module Factory
@@ -65,35 +65,39 @@ end
65
65
 
66
66
 
67
67
  def setup_gem(pkg_name, pkg_version, author, summary, executables, test_file)
68
- pkg_version = pkg_version
69
- pkg_name = pkg_name
70
- pkg_file_name = "#{pkg_name}-#{pkg_version}"
71
-
72
- spec = Gem::Specification.new do |s|
73
- s.name = pkg_name
74
- s.version = pkg_version
75
- s.platform = Gem::Platform::RUBY
76
- s.author = author
77
- s.summary = summary
78
- s.test_file = test_file
79
- s.has_rdoc = true
80
- s.extra_rdoc_files = [ "README" ]
81
-
82
- s.files = %w(COPYING LICENSE ext/http11/MANIFEST README Rakefile setup.rb) +
83
- Dir.glob("{bin,doc,test,lib}/**/*") +
84
- Dir.glob("ext/**/*.{h,c,rb}") +
85
- Dir.glob("examples/**/*.rb") +
86
- Dir.glob("tools/*.rb")
68
+ pkg_version = pkg_version
69
+ pkg_name = pkg_name
70
+ pkg_file_name = "#{pkg_name}-#{pkg_version}"
71
+
72
+ spec = Gem::Specification.new do |s|
73
+ s.name = pkg_name
74
+ s.version = pkg_version
75
+ s.platform = Gem::Platform::RUBY
76
+ s.author = author
77
+ s.summary = summary
78
+ s.test_file = test_file
79
+ s.has_rdoc = true
80
+ s.extra_rdoc_files = [ "README" ]
87
81
 
88
- s.require_path = "lib"
89
- s.extensions = FileList["ext/**/extconf.rb"].to_a
90
-
91
- s.executables = executables
92
- s.bindir = "bin"
93
- end
94
-
95
- Rake::GemPackageTask.new(spec) do |p|
96
- p.gem_spec = spec
97
- p.need_tar = true
82
+ s.files = %w(COPYING LICENSE ext/http11/MANIFEST README Rakefile setup.rb) +
83
+ Dir.glob("{bin,doc/rdoc,test,lib}/**/*") +
84
+ Dir.glob("ext/**/*.{h,c,rb}") +
85
+ Dir.glob("examples/**/*.rb") +
86
+ Dir.glob("tools/*.rb")
87
+
88
+ s.require_path = "lib"
89
+ s.extensions = FileList["ext/**/extconf.rb"].to_a
90
+
91
+ s.executables = executables
92
+ s.bindir = "bin"
93
+
94
+ if block_given?
95
+ yield s
98
96
  end
97
+ end
98
+
99
+ Rake::GemPackageTask.new(spec) do |p|
100
+ p.gem_spec = spec
101
+ p.need_tar = true
102
+ end
99
103
  end