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.
- data/README.rdoc +3 -0
- data/examples/rest.log +15 -0
- data/examples/static.rb +12 -0
- data/examples/static/static-index.html +1 -0
- data/lib/capcode.rb +14 -344
- data/lib/capcode/filters.rb +1 -0
- data/lib/capcode/helpers.rb +246 -0
- data/lib/capcode/http_error.rb +49 -0
- data/lib/capcode/static_files.rb +68 -0
- data/lib/capcode/version.rb +1 -1
- metadata +46 -61
- data/doc/rdoc/classes/Capcode.html +0 -1076
- data/doc/rdoc/classes/Capcode/Base.html +0 -136
- data/doc/rdoc/classes/Capcode/Configuration.html +0 -290
- data/doc/rdoc/classes/Capcode/HTTPError.html +0 -148
- data/doc/rdoc/classes/Capcode/Helpers.html +0 -674
- data/doc/rdoc/classes/Capcode/Helpers/Authorization.html +0 -219
- data/doc/rdoc/classes/Capcode/Resource.html +0 -111
- data/doc/rdoc/classes/Capcode/StaticFiles.html +0 -199
- data/doc/rdoc/classes/Capcode/Views.html +0 -112
- data/doc/rdoc/created.rid +0 -1
- data/doc/rdoc/files/AUTHORS.html +0 -107
- data/doc/rdoc/files/COPYING.html +0 -531
- data/doc/rdoc/files/README_rdoc.html +0 -887
- data/doc/rdoc/files/lib/capcode/base/db_rb.html +0 -101
- data/doc/rdoc/files/lib/capcode/configuration_rb.html +0 -101
- data/doc/rdoc/files/lib/capcode/filters_rb.html +0 -101
- data/doc/rdoc/files/lib/capcode/helpers/auth_rb.html +0 -101
- data/doc/rdoc/files/lib/capcode/render/text_rb.html +0 -101
- data/doc/rdoc/files/lib/capcode_rb.html +0 -144
- data/doc/rdoc/fr_class_index.html +0 -35
- data/doc/rdoc/fr_file_index.html +0 -35
- data/doc/rdoc/fr_method_index.html +0 -56
- data/doc/rdoc/index.html +0 -24
- data/doc/rdoc/rdoc-style.css +0 -208
- data/lib/capcode.rbSAVE +0 -881
data/lib/capcode.rbSAVE
DELETED
@@ -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
|