mongrel 0.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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