Capcode 0.9.9 → 1.0.0

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 (36) hide show
  1. data/README.rdoc +3 -0
  2. data/examples/rest.log +15 -0
  3. data/examples/static.rb +12 -0
  4. data/examples/static/static-index.html +1 -0
  5. data/lib/capcode.rb +14 -344
  6. data/lib/capcode/filters.rb +1 -0
  7. data/lib/capcode/helpers.rb +246 -0
  8. data/lib/capcode/http_error.rb +49 -0
  9. data/lib/capcode/static_files.rb +68 -0
  10. data/lib/capcode/version.rb +1 -1
  11. metadata +46 -61
  12. data/doc/rdoc/classes/Capcode.html +0 -1076
  13. data/doc/rdoc/classes/Capcode/Base.html +0 -136
  14. data/doc/rdoc/classes/Capcode/Configuration.html +0 -290
  15. data/doc/rdoc/classes/Capcode/HTTPError.html +0 -148
  16. data/doc/rdoc/classes/Capcode/Helpers.html +0 -674
  17. data/doc/rdoc/classes/Capcode/Helpers/Authorization.html +0 -219
  18. data/doc/rdoc/classes/Capcode/Resource.html +0 -111
  19. data/doc/rdoc/classes/Capcode/StaticFiles.html +0 -199
  20. data/doc/rdoc/classes/Capcode/Views.html +0 -112
  21. data/doc/rdoc/created.rid +0 -1
  22. data/doc/rdoc/files/AUTHORS.html +0 -107
  23. data/doc/rdoc/files/COPYING.html +0 -531
  24. data/doc/rdoc/files/README_rdoc.html +0 -887
  25. data/doc/rdoc/files/lib/capcode/base/db_rb.html +0 -101
  26. data/doc/rdoc/files/lib/capcode/configuration_rb.html +0 -101
  27. data/doc/rdoc/files/lib/capcode/filters_rb.html +0 -101
  28. data/doc/rdoc/files/lib/capcode/helpers/auth_rb.html +0 -101
  29. data/doc/rdoc/files/lib/capcode/render/text_rb.html +0 -101
  30. data/doc/rdoc/files/lib/capcode_rb.html +0 -144
  31. data/doc/rdoc/fr_class_index.html +0 -35
  32. data/doc/rdoc/fr_file_index.html +0 -35
  33. data/doc/rdoc/fr_method_index.html +0 -56
  34. data/doc/rdoc/index.html +0 -24
  35. data/doc/rdoc/rdoc-style.css +0 -208
  36. data/lib/capcode.rbSAVE +0 -881
@@ -1,881 +0,0 @@
1
- # Please read the README.rdoc file !
2
-
3
- require 'rubygems'
4
- require 'rack'
5
- require 'rack/mime'
6
- require 'logger'
7
- Logger.class_eval { alias :write :<< } unless Logger.instance_methods.include? "write"
8
- require 'optparse'
9
- require 'irb'
10
- require 'capcode/version'
11
- require 'capcode/core_ext'
12
- require 'capcode/helpers/auth'
13
- require 'capcode/render/text'
14
- require 'capcode/configuration'
15
- require 'capcode/filters'
16
- require 'capcode/ext/rack/urlmap'
17
-
18
- module Capcode
19
- class ParameterError < ArgumentError #:nodoc: all
20
- end
21
-
22
- class RouteError < ArgumentError #:nodoc: all
23
- end
24
-
25
- class RenderError < ArgumentError #:nodoc: all
26
- end
27
-
28
- class MissingLibrary < Exception #:nodoc: all
29
- end
30
-
31
- # Views is an empty module in which you can store your markaby or xml views.
32
- module Views; end
33
-
34
- # Helpers contains methods available in your controllers
35
- module Helpers
36
- def self.args
37
- @args ||= nil
38
- end
39
- def self.args=(x)
40
- @args = x
41
- end
42
-
43
- # Render a view
44
- #
45
- # render's parameter can be a Hash or a string. Passing a string is equivalent to do
46
- # render( :text => string )
47
- #
48
- # If you want to use a specific renderer, use one of this options :
49
- #
50
- # * :markaby => :my_func : :my_func must be defined in Capcode::Views
51
- # * :erb => :my_erb_file : this suppose that's my_erb_file.rhtml exist in erb_path
52
- # * :haml => :my_haml_file : this suppose that's my_haml_file.haml exist in haml_path
53
- # * :sass => :my_sass_file : this suppose that's my_sass_file.sass exist in sass_path
54
- # * :text => "my text"
55
- # * :json => MyObject : this suppose that's MyObject respond to .to_json
56
- # * :static => "my_file.xxx" : this suppose that's my_file.xxx exist in the static directory
57
- # * :xml => :my_func : :my_func must be defined in Capcode::Views
58
- # * :webdav => /path/to/root
59
- #
60
- # Or you can use a "HTTP code" renderer :
61
- #
62
- # render 200 => "Ok", :server => "Capcode #{Capcode::CAPCOD_VERION}", ...
63
- #
64
- # If you want to use a specific layout, you can specify it with option
65
- # :layout
66
- #
67
- # If you want to change the Content-Type, you can specify it with option
68
- # :content_type
69
- # Note that this will not work with the JSON renderer
70
- #
71
- # If you use the WebDav renderer, you can use the option
72
- # :resource_class (see http://github.com/georgi/rack_dav for more informations)
73
- def render( hash )
74
- if hash.class == Hash
75
- render_type = nil
76
- possible_code_renderer = nil
77
-
78
- hash.keys.each do |key|
79
- begin
80
- gem "capcode-render-#{key.to_s}"
81
- require "capcode/render/#{key.to_s}"
82
- rescue Gem::LoadError
83
- nil
84
- rescue LoadError
85
- raise Capcode::RenderError, "Hum... The #{key} renderer is malformated! Please try to install a new version or use an other renderer!", caller
86
- end
87
-
88
- if self.respond_to?("render_#{key.to_s}")
89
- unless render_type.nil?
90
- raise Capcode::RenderError, "Can't use multiple renderer (`#{render_type}' and `#{key}') !", caller
91
- end
92
- render_type = key
93
- end
94
-
95
- if key.class == Fixnum
96
- possible_code_renderer = key
97
- end
98
- end
99
-
100
- if render_type.nil? and possible_code_renderer.nil?
101
- raise Capcode::RenderError, "Renderer type not specified!", caller
102
- end
103
-
104
- unless self.respond_to?("render_#{render_type.to_s}")
105
- if possible_code_renderer.nil?
106
- raise Capcode::RenderError, "#{render_type} renderer not present ! please require 'capcode/render/#{render_type}'", caller
107
- else
108
- code = possible_code_renderer
109
- body = hash.delete(possible_code_renderer)
110
- header = {}
111
- hash.each do |k, v|
112
- k = k.to_s.split(/_/).map{|e| e.capitalize}.join("-")
113
- header[k] = v
114
- end
115
-
116
- [code, header, body]
117
- end
118
- else
119
- render_name = hash.delete(render_type)
120
- content_type = hash.delete(:content_type)
121
- unless content_type.nil?
122
- @response['Content-Type'] = content_type
123
- end
124
-
125
- begin
126
- self.send( "render_#{render_type.to_s}", render_name, hash )
127
- rescue => e
128
- raise Capcode::RenderError, "Error rendering `#{render_type.to_s}' : #{e.message}", caller
129
- end
130
- end
131
- else
132
- render( :text => hash )
133
- end
134
- end
135
-
136
- # Help you to return a JSON response
137
- #
138
- # module Capcode
139
- # class JsonResponse < Route '/json/([^\/]*)/(.*)'
140
- # def get( arg1, arg2 )
141
- # json( { :1 => arg1, :2 => arg2 })
142
- # end
143
- # end
144
- # end
145
- #
146
- # <b>DEPRECATED</b>, please use <tt>render( :json => o )</tt>
147
- def json( d ) ## DELETE THIS IN 1.0.0
148
- warn( "json is deprecated and will be removed in version 1.0, please use `render( :json => ... )'" )
149
- render :json => d
150
- end
151
-
152
- # Send a redirect response
153
- #
154
- # module Capcode
155
- # class Hello < Route '/hello/(.*)'
156
- # def get( you )
157
- # if you.nil?
158
- # redirect( WhoAreYou )
159
- # else
160
- # ...
161
- # end
162
- # end
163
- # end
164
- # end
165
- #
166
- # The first parameter can be a controller class name
167
- #
168
- # redirect( MyController )
169
- #
170
- # it can be a string path
171
- #
172
- # redirect( "/path/to/my/resource" )
173
- #
174
- # it can be an http status code (by default <tt>redirect</tt> use the http status code 302)
175
- #
176
- # redirect( 304, MyController )
177
- #
178
- # For more informations about HTTP status, see http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection
179
- def redirect( klass, *a )
180
- httpCode = 302
181
-
182
- if( klass.class == Fixnum )
183
- httpCode = klass
184
- klass = a.shift
185
- end
186
-
187
- [httpCode, {'Location' => URL(klass, *a)}, '']
188
- end
189
-
190
- # Builds an URL route to a controller or a path
191
- #
192
- # if you declare the controller Hello :
193
- #
194
- # module Capcode
195
- # class Hello < Route '/hello/(.*)'
196
- # ...
197
- # end
198
- # end
199
- #
200
- # then
201
- #
202
- # URL( Capcode::Hello, "you" ) # => /hello/you
203
- def URL( klass, *a )
204
- path = nil
205
- result = {}
206
-
207
- a = a.delete_if{ |x| x.nil? }
208
-
209
- if klass.class == Class
210
- klass.__urls__[0].each do |cpath, regexp|
211
- data = a.clone
212
-
213
- n = Regexp.new( regexp ).number_of_captures
214
- equart = (a.size - n).abs
215
-
216
- rtable = regexp.dup.gsub( /\\\(/, "" ).gsub( /\\\)/, "" ).split( /\([^\)]*\)/ )
217
- rtable.each do |r|
218
- if r == ""
219
- cpath = cpath + "/#{data.shift}"
220
- else
221
- cpath = cpath + "/#{r}"
222
- end
223
- end
224
-
225
- cpath = (cpath + "/" + data.join( "/" )) if data.size > 0
226
- cpath = cpath.gsub( /(\/){2,}/, "/" )
227
- result[equart] = cpath
228
- end
229
-
230
- path = result[result.keys.min]
231
- else
232
- path = klass
233
- end
234
-
235
- (ENV['RACK_BASE_URI']||'')+path
236
- end
237
-
238
- # Calling content_for stores a block of markup in an identifier.
239
- #
240
- # module Capcode
241
- # class ContentFor < Route '/'
242
- # def get
243
- # render( :markaby => :page, :layout => :layout )
244
- # end
245
- # end
246
- # end
247
- #
248
- # module Capcode::Views
249
- # def layout
250
- # html do
251
- # head do
252
- # yield :header
253
- # end
254
- # body do
255
- # yield :content
256
- # end
257
- # end
258
- # end
259
- #
260
- # def page
261
- # content_for :header do
262
- # title "This is the title!"
263
- # end
264
- #
265
- # content_for :content do
266
- # p "this is the content!"
267
- # end
268
- # end
269
- # end
270
- def content_for( x )
271
- if Capcode::Helpers.args.map{|_| _.to_s }.include?(x.to_s)
272
- yield
273
- end
274
- end
275
-
276
- # Return information about the static directory
277
- #
278
- # * <tt>static[:uri]</tt> give the static URI
279
- # * <tt>static[:path]</tt> give the path to the static directory on the server
280
- def static
281
- {
282
- :uri => Capcode.static,
283
- :path => File.expand_path( File.join(Capcode::Configuration.get(:root), Capcode::Configuration.get(:static) ) )
284
- }
285
- end
286
-
287
- # Use the Rack logger
288
- #
289
- # log.write( "This is a log !" )
290
- def log
291
- Capcode.logger || env['rack.errors']
292
- end
293
-
294
- include Authorization
295
- end
296
-
297
- include Rack
298
-
299
- # HTTPError help you to create your own 404, 500 and/or 501 response
300
- #
301
- # To create a custom 404 reponse, create a fonction HTTPError.r404 in
302
- # your application :
303
- #
304
- # module Capcode
305
- # class HTTPError
306
- # def r404(f)
307
- # "#{f} not found :("
308
- # end
309
- # end
310
- # end
311
- #
312
- # the rXXX method can also receive a second optional parameter corresponding
313
- # of the header's Hash :
314
- #
315
- # module Capcode
316
- # class HTTPError
317
- # def r404(f, h)
318
- # h['Content-Type'] = 'text/plain'
319
- # "You are here ---> X (#{f} point)"
320
- # end
321
- # end
322
- # end
323
- #
324
- # Do the same (r500, r501, r403) to customize 500, 501, 403 errors
325
- class HTTPError
326
- def initialize(app) #:nodoc:
327
- @app = app
328
- end
329
-
330
- def call(env) #:nodoc:
331
- status, headers, body = @app.call(env)
332
- if self.methods.include? "r#{status}"
333
- headers.delete('Content-Type') if headers.keys.include?('Content-Type')
334
- body = begin
335
- self.send( "r#{status}", env['REQUEST_PATH'], headers )
336
- rescue
337
- self.send( "r#{status}", env['REQUEST_PATH'] )
338
- end
339
- headers['Content-Length'] = body.length.to_s
340
- headers['Content-Type'] = "text/html" unless headers.keys.include?('Content-Type')
341
- end
342
-
343
- [status, headers, body]
344
- end
345
- end
346
-
347
- class StaticFiles
348
- def initialize(app)
349
- @app = app
350
- end
351
-
352
- def call(env)
353
- static = File.expand_path( File.join(Capcode::Configuration.get(:root), Capcode::Configuration.get(:static) ) )
354
- file = File.join(static, env['REQUEST_PATH'].split("/") )
355
- file = File.join(file, "index.html" ) if File.directory?(file)
356
- if File.exist?(file)
357
- body = [::File.read(file)]
358
- header = {
359
- "Last-Modified" => ::File.mtime(file).httpdate,
360
- "Content-Type" => ::Rack::Mime.mime_type(::File.extname(file), 'text/plain'),
361
- "Content-Length" => body.first.size.to_s
362
- }
363
- return [200, header, body]
364
- else
365
- return @app.call(env)
366
- end
367
-
368
- return @app.call(env)
369
- end
370
- end
371
-
372
- class << self
373
- attr :__auth__, true #:nodoc:
374
-
375
- # Add routes to a controller class
376
- #
377
- # module Capcode
378
- # class Hello < Route '/hello/(.*)', '/hello/([^#]*)#(.*)'
379
- # def get( arg1, arg2 )
380
- # ...
381
- # end
382
- # end
383
- # end
384
- #
385
- # In the <tt>get</tt> method, you will receive the maximum of parameters declared
386
- # by the routes. In this example, you will receive 2 parameters. So if you
387
- # go to <tt>/hello/world#friend</tt> then <tt>arg1</tt> will be set to <tt>world</tt> and <tt>arg2</tt>
388
- # will be set to <tt>friend</tt>. Now if you go to <tt>/hello/you</tt>, then <tt>arg1</tt> will
389
- # be set to <tt>you</tt> and <tt>arg2</tt> will be set to <tt>nil</tt>
390
- #
391
- # If the regexp in the route does not match, all arguments will be <tt>nil</tt>
392
- def Route *routes_paths
393
- create_path = routes_paths[0].nil?
394
- Class.new {
395
- meta_def(:__urls__) {
396
- routes_paths = ['/'+self.to_s.gsub( /^Capcode::/, "" ).underscore] if create_path == true
397
- # < Route '/hello/world/([^\/]*)/id(\d*)', '/hello/(.*)', :agent => /Songbird (\d\.\d)[\d\/]*?/
398
- # # => [ {'/hello/world' => '([^\/]*)/id(\d*)', '/hello' => '(.*)'},
399
- # 2,
400
- # <Capcode::Klass>,
401
- # {:agent => /Songbird (\d\.\d)[\d\/]*?/} ]
402
- hash_of_routes = {}
403
- max_captures_for_routes = 0
404
- routes_paths.each do |current_route_path|
405
- if current_route_path.class == String
406
- m = /\/([^\/]*\(.*)/.match( current_route_path )
407
- if m.nil?
408
- raise Capcode::RouteError, "Route `#{current_route_path}' already defined with regexp `#{hash_of_routes[current_route_path]}' !", caller if hash_of_routes.keys.include?(current_route_path)
409
- hash_of_routes[current_route_path] = ''
410
- else
411
- _pre = m.pre_match
412
- _pre = "/" if _pre.size == 0
413
- raise Capcode::RouteError, "Route `#{_pre}' already defined with regexp `#{hash_of_routes[_pre]}' !", caller if hash_of_routes.keys.include?(_pre)
414
- hash_of_routes[_pre] = m.captures[0]
415
- max_captures_for_routes = Regexp.new(m.captures[0]).number_of_captures if max_captures_for_routes < Regexp.new(m.captures[0]).number_of_captures
416
- end
417
- else
418
- raise Capcode::ParameterError, "Bad route declaration !", caller
419
- end
420
- end
421
- [hash_of_routes, max_captures_for_routes, self]
422
- }
423
-
424
- # Hash containing all the request parameters (GET or POST)
425
- def params
426
- @request.params
427
- end
428
-
429
- # Hash containing all the environment variables
430
- def env
431
- @env
432
- end
433
-
434
- # Session hash
435
- def session
436
- @env['rack.session']
437
- end
438
-
439
- # Return the Rack::Request object
440
- def request
441
- @request
442
- end
443
-
444
- # Return the Rack::Response object
445
- def response
446
- @response
447
- end
448
-
449
- def call( e ) #:nodoc:
450
- @env = e
451
- @response = Rack::Response.new
452
- @request = Rack::Request.new(@env)
453
-
454
- # Check authz
455
- authz_options = nil
456
- if Capcode.__auth__ and Capcode.__auth__.size > 0
457
- authz_options = Capcode.__auth__[@request.path]||nil
458
- if authz_options.nil?
459
- route = nil
460
-
461
- Capcode.__auth__.each do |r, o|
462
- regexp = "^#{r.gsub(/\/$/, "")}([/]{1}.*)?$"
463
- if Regexp.new(regexp).match( @request.path )
464
- if route.nil? or r.size > route.size
465
- route = r
466
- authz_options = o
467
- end
468
- end
469
- end
470
- end
471
- end
472
-
473
- r = catch(:halt) {
474
- unless authz_options.nil?
475
- http_authentication( :type => authz_options[:type], :realm => authz_options[:realm], :opaque => authz_options[:realm] ) {
476
- authz_options[:autz]
477
- }
478
- end
479
-
480
- finalPath = nil
481
- finalArgs = nil
482
- finalNArgs = nil
483
-
484
- aPath = @request.path.gsub( /^\//, "" ).split( "/" )
485
- print "aPath = "; p aPath
486
- self.class.__urls__[0].each do |p, r|
487
- puts "p = #{p}, r = #{r}"
488
- xPath = p.gsub( /^\//, "" ).split( "/" )
489
- puts "xPath = "; p xPath
490
- if (xPath - aPath).size == 0
491
- diffArgs = aPath - xPath
492
- diffNArgs = diffArgs.size # -1 ##################################### Why ?
493
- if finalNArgs.nil? or finalNArgs > diffNArgs
494
- finalPath = p
495
- finalNArgs = diffNArgs
496
- finalArgs = diffArgs
497
- end
498
- end
499
- end
500
-
501
- puts "finalPath = #{finalPath}"
502
- puts "finalNArgs = #{finalNArgs}"
503
- require 'pp'
504
- pp self.class.__urls__
505
- puts "self.class.__urls__[1] = #{self.class.__urls__[1]}"
506
- puts "finalArgs = "; pp finalArgs
507
-
508
- if finalNArgs > self.class.__urls__[1]
509
- return [404, {'Content-Type' => 'text/plain'}, "Not Found: #{@request.path}"]
510
- end
511
-
512
- nargs = self.class.__urls__[1]
513
- regexp = Regexp.new( self.class.__urls__[0][finalPath] )
514
- args = regexp.match( Rack::Utils.unescape(@request.path).gsub( Regexp.new( "^#{finalPath}" ), "" ).gsub( /^\//, "" ) )
515
- if args.nil?
516
- raise Capcode::ParameterError, "Path info `#{@request.path_info}' does not match route regexp `#{regexp.source}'"
517
- else
518
- args = args.captures.map { |x| (x.size == 0)?nil:x }
519
- end
520
-
521
- while args.size < nargs
522
- args << nil
523
- end
524
-
525
- filter_output = Capcode::Filter.execute( self )
526
-
527
- if( filter_output.nil? )
528
- # case @env["REQUEST_METHOD"]
529
- # when "GET"
530
- # get( *args )
531
- # when "POST"
532
- # _method = params.delete( "_method" ) { |_| "post" }
533
- # send( _method.downcase.to_sym, *args )
534
- # else
535
- # _method = @env["REQUEST_METHOD"]
536
- # send( _method.downcase.to_sym, *args )
537
- # end
538
- begin
539
- _method = params.delete( "_method" ) { |_| @env["REQUEST_METHOD"] }
540
- if self.class.method_defined?( _method.downcase.to_sym )
541
- send( _method.downcase.to_sym, *args )
542
- else
543
- any( *args )
544
- end
545
- rescue => e
546
- raise e.class, e.to_s
547
- end
548
- else
549
- filter_output
550
- end
551
- }
552
-
553
- if r.respond_to?(:to_ary)
554
- @response.status = r.shift #r[0]
555
- #r[1].each do |k,v|
556
- r.shift.each do |k,v|
557
- @response[k] = v
558
- end
559
- @response.write r.shift #r[2]
560
- else
561
- @response.write r
562
- end
563
-
564
- @response.finish
565
- end
566
-
567
- include Capcode::Helpers
568
- include Capcode::Views
569
- }
570
- end
571
- Capcode::Route = Capcode::Route(nil)
572
-
573
- # This method help you to map and URL to a Rack or What you want Helper
574
- #
575
- # Capcode.map( "/file" ) do
576
- # Rack::File.new( "." )
577
- # end
578
- def map( route, &b )
579
- Capcode.routes[route] = yield
580
- end
581
-
582
- # This method allow you to use a Rack middleware
583
- #
584
- # Example :
585
- #
586
- # module Capcode
587
- # ...
588
- # use Rack::Codehighlighter, :coderay, :element => "pre",
589
- # :pattern => /\A:::(\w+)\s*\n/, :logging => false
590
- # ...
591
- # end
592
- def use(middleware, *args, &block)
593
- middlewares << [middleware, args, block]
594
- end
595
- def middlewares #:nodoc:
596
- @middlewares ||= []
597
- end
598
-
599
- # Allow you to add and HTTP Authentication (Basic or Digest) to controllers for or specific route
600
- #
601
- # Options :
602
- # * <tt>:type</tt> : Authentication type (<tt>:basic</tt> or <tt>:digest</tt>) - default : <tt>:basic</tt>
603
- # * <tt>:realm</tt> : realm ;) - default : "Capcode.app"
604
- # * <tt>:opaque</tt> : Your secret passphrase. You MUST set it if you use Digest Auth - default : "opaque"
605
- # * <tt>:routes</tt> : Routes - default : "/"
606
- #
607
- # The block must return a Hash of username => password like that :
608
- # {
609
- # "user1" => "pass1",
610
- # "user2" => "pass2",
611
- # # ...
612
- # }
613
- def http_authentication( opts = {}, &b )
614
- options = {
615
- :type => :basic,
616
- :realm => "Capcode.app",
617
- :opaque => "opaque",
618
- :routes => "/"
619
- }.merge( opts )
620
-
621
- options[:autz] = b.call()
622
-
623
- @__auth__ ||= {}
624
-
625
- if options[:routes].class == Array
626
- options[:routes].each do |r|
627
- @__auth__[r] = options
628
- end
629
- else
630
- @__auth__[options[:routes]] = options
631
- end
632
- end
633
-
634
- # Return the Rack App.
635
- #
636
- # Options : see Capcode::Configuration.set
637
- #
638
- # Options set here replace the ones set globally
639
- def application( args = {} )
640
- Capcode::Configuration.configuration(args)
641
- Capcode::Configuration.print_debug if Capcode::Configuration.get(:verbose)
642
-
643
- Capcode.constants.clone.delete_if {|k|
644
- not( Capcode.const_get(k).to_s =~ /Capcode/ ) or [
645
- "Filter",
646
- "Helpers",
647
- "RouteError",
648
- "Views",
649
- "ParameterError",
650
- "HTTPError",
651
- "StaticFiles",
652
- "Configuration",
653
- "MissingLibrary",
654
- "Route",
655
- "RenderError"
656
- ].include?(k)
657
- }.each do |k|
658
- begin
659
- if eval "Capcode::#{k}.public_methods(true).include?( '__urls__' )"
660
- hash_of_routes, max_captures_for_routes, klass = eval "Capcode::#{k}.__urls__"
661
- hash_of_routes.keys.each do |current_route_path|
662
- #raise Capcode::RouteError, "Route `#{current_route_path}' already define !", caller if @@__ROUTES.keys.include?(current_route_path)
663
- raise Capcode::RouteError, "Route `#{current_route_path}' already define !", caller if Capcode.routes.keys.include?(current_route_path)
664
- # Capcode.routes[current_route_path] = klass.new
665
- Capcode.routes[current_route_path] = klass
666
- end
667
- end
668
- rescue => e
669
- raise e.message
670
- end
671
- end
672
-
673
- # Set Static directory
674
- Capcode.static = (Capcode::Configuration.get(:static)[0].chr == "/")?Capcode::Configuration.get(:static):"/"+Capcode::Configuration.get(:static) unless Capcode::Configuration.get(:static).nil?
675
-
676
- # Initialize Rack App
677
- puts "** Map routes." if Capcode::Configuration.get(:verbose)
678
- # app = Rack::URLMap.new(Capcode.routes)
679
- app = Capcode::Ext::Rack::URLMap.new(Capcode.routes)
680
- puts "** Initialize static directory (#{Capcode.static}) in #{File.expand_path(Capcode::Configuration.get(:root))}" if Capcode::Configuration.get(:verbose)
681
- app = Rack::Static.new(
682
- app,
683
- #:urls => [@@__STATIC_DIR],
684
- :urls => [Capcode.static],
685
- :root => File.expand_path(Capcode::Configuration.get(:root))
686
- ) unless Capcode::Configuration.get(:static).nil?
687
- puts "** Initialize session" if Capcode::Configuration.get(:verbose)
688
- app = Rack::Session::Cookie.new( app, Capcode::Configuration.get(:session) )
689
- app = Capcode::StaticFiles.new(app)
690
- app = Capcode::HTTPError.new(app)
691
- app = Rack::ContentLength.new(app)
692
- app = Rack::Lint.new(app)
693
- app = Rack::ShowExceptions.new(app)
694
- #app = Rack::Reloader.new(app) ## -- NE RELOAD QUE capcode.rb -- So !!!
695
- app = Rack::CommonLogger.new( app, @cclogger = Logger.new(Capcode::Configuration.get(:log)) )
696
-
697
- middlewares.each do |mw|
698
- middleware, args, block = mw
699
- puts "** Load middleware #{middleware}" if Capcode::Configuration.get(:verbose)
700
- if block
701
- app = middleware.new( app, *args, &block )
702
- else
703
- app = middleware.new( app, *args )
704
- end
705
- end
706
-
707
- # Start database
708
- if self.methods.include? "db_connect"
709
- db_connect( Capcode::Configuration.get(:db_config), Capcode::Configuration.get(:log) )
710
- end
711
-
712
- if block_given?
713
- puts "** Execute block" if Capcode::Configuration.get(:verbose)
714
- yield( self )
715
- end
716
-
717
- return app
718
- end
719
-
720
- # Start your application.
721
- #
722
- # Options : see Capcode::Configuration.set
723
- #
724
- # Options set here replace the ones set globally
725
- def run( args = {} )
726
- Capcode::Configuration.configuration(args)
727
-
728
- # Parse options
729
- opts = OptionParser.new do |opts|
730
- opts.banner = "Usage: #{File.basename($0)} [options]"
731
- opts.separator ""
732
- opts.separator "Specific options:"
733
-
734
- opts.on( "-C", "--console", "Run in console mode with IRB (default: false)" ) {
735
- Capcode::Configuration.set :console, true
736
- }
737
- opts.on( "-h", "--host HOSTNAME", "Host for web server to bind to (default: #{Capcode::Configuration.get(:host)})" ) { |h|
738
- Capcode::Configuration.set :host, h
739
- }
740
- opts.on( "-p", "--port NUM", "Port for web server (default: #{Capcode::Configuration.get(:port)})" ) { |p|
741
- Capcode::Configuration.set :port, p
742
- }
743
- opts.on( "-d", "--daemonize [true|false]", "Daemonize (default: #{Capcode::Configuration.get(:daemonize)})" ) { |d|
744
- Capcode::Configuration.set :daemonize, d
745
- }
746
- opts.on( "-r", "--root PATH", "Working directory (default: #{Capcode::Configuration.get(:root)})" ) { |w|
747
- Capcode::Configuration.set :root, w
748
- }
749
- opts.on( "-s", "--static PATH", "Static directory -- relative to the root directory (default: #{Capcode::Configuration.get(:static)})" ) { |r|
750
- Capcode::Configuration.set :static, r
751
- }
752
- opts.on( "-S", "--server SERVER", "Server to use (default: #{Capcode::Configuration.get(:server)})" ) { |r|
753
- Capcode::Configuration.set :server, r
754
- }
755
-
756
- opts.separator ""
757
- opts.separator "Common options:"
758
-
759
- opts.on("-?", "--help", "Show this message") do
760
- puts opts
761
- exit
762
- end
763
- opts.on("-v", "--version", "Show versions") do
764
- puts "Capcode version #{Capcode::CAPCOD_VERION} (ruby v#{RUBY_VERSION})"
765
- exit
766
- end
767
- opts.on_tail( "-V", "--verbose", "Run in verbose mode" ) do
768
- Capcode::Configuration.set :verbose, true
769
- end
770
- end
771
-
772
- begin
773
- opts.parse! ARGV
774
- rescue OptionParser::ParseError => ex
775
- puts "!! #{ex.message}"
776
- puts "** use `#{File.basename($0)} --help` for more details..."
777
- exit 1
778
- end
779
-
780
- # Run in the Working directory
781
- puts "** Go on root directory (#{File.expand_path(Capcode::Configuration.get(:root))})" if Capcode::Configuration.get(:verbose)
782
- Dir.chdir( Capcode::Configuration.get(:root) ) do
783
-
784
- # Check that mongrel exists
785
- if Capcode::Configuration.get(:server).nil? || Capcode::Configuration.get(:server) == "mongrel"
786
- begin
787
- require 'mongrel'
788
- Capcode::Configuration.set :server, :mongrel
789
- rescue LoadError
790
- puts "!! could not load mongrel. Falling back to webrick."
791
- Capcode::Configuration.set :server, :webrick
792
- end
793
- end
794
-
795
- # From rackup !!!
796
- if Capcode::Configuration.get(:daemonize)
797
- if /java/.match(RUBY_PLATFORM).nil?
798
- if RUBY_VERSION < "1.9"
799
- exit if fork
800
- Process.setsid
801
- exit if fork
802
- # Dir.chdir "/"
803
- File.umask 0000
804
- STDIN.reopen "/dev/null"
805
- STDOUT.reopen "/dev/null", "a"
806
- STDERR.reopen "/dev/null", "a"
807
- else
808
- Process.daemon
809
- end
810
- else
811
- puts "!! daemonize option unavailable on #{RUBY_PLATFORM} platform."
812
- end
813
-
814
- File.open(Capcode::Configuration.get(:pid), 'w'){ |f| f.write("#{Process.pid}") }
815
- at_exit { File.delete(Capcode::Configuration.get(:pid)) if File.exist?(Capcode::Configuration.get(:pid)) }
816
- end
817
-
818
- app = nil
819
- if block_given?
820
- app = application(Capcode::Configuration.get) { yield( self ) }
821
- else
822
- app = application(Capcode::Configuration.get)
823
- end
824
-
825
- if Capcode::Configuration.get(:console)
826
- puts "Run console..."
827
- IRB.start
828
- exit
829
- end
830
-
831
- # Start server
832
- case Capcode::Configuration.get(:server).to_s
833
- when "mongrel"
834
- puts "** Starting Mongrel on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
835
- Rack::Handler::Mongrel.run( app, {:Port => Capcode::Configuration.get(:port), :Host => Capcode::Configuration.get(:host)} ) { |server|
836
- trap "SIGINT", proc { server.stop }
837
- }
838
- when "webrick"
839
- puts "** Starting WEBrick on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
840
- Rack::Handler::WEBrick.run( app, {:Port => Capcode::Configuration.get(:port), :BindAddress => Capcode::Configuration.get(:host)} ) { |server|
841
- trap "SIGINT", proc { server.shutdown }
842
- }
843
- when "thin"
844
- puts "** Starting Thin on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
845
- Rack::Handler::Thin.run( app, {:Port => Capcode::Configuration.get(:port), :Host => Capcode::Configuration.get(:host)} ) { |server|
846
- trap "SIGINT", proc { server.stop }
847
- }
848
- when "unicorn"
849
- require 'unicorn/launcher'
850
- puts "** Starting Unicorn on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
851
- Unicorn.run( app, {:listeners => ["#{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"]} )
852
- when "rainbows"
853
- require 'unicorn/launcher'
854
- require 'rainbows'
855
- puts "** Starting Rainbow on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
856
- Rainbows.run( app, {:listeners => ["#{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"]} )
857
- when "control_tower"
858
- require 'control_tower'
859
- puts "** Starting ControlTower on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
860
- ControlTower::Server.new( app, {:host => Capcode::Configuration.get(:host), :port => Capcode::Configuration.get(:port)} ).start
861
- end
862
- end
863
- end
864
-
865
- def routes #:nodoc:
866
- @routes ||= {}
867
- end
868
-
869
- def logger
870
- @cclogger
871
- end
872
-
873
- def static #:nodoc:
874
- @static_dir ||= nil
875
- end
876
- def static=(x) #:nodoc:
877
- @static_dir = x
878
- end
879
-
880
- end
881
- end