rack_warden 0.0.9 → 0.0.10
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.
- checksums.yaml +8 -8
- data/.gitignore +2 -0
- data/Gemfile +13 -10
- data/README.md +115 -53
- data/config.ru +1 -0
- data/lib/rack_warden.rb +33 -5
- data/lib/rack_warden/app.rb +73 -58
- data/lib/rack_warden/core_patches.rb +20 -0
- data/lib/rack_warden/env.rb +27 -0
- data/lib/rack_warden/frameworks.rb +34 -36
- data/lib/rack_warden/frameworks/rack.rb +36 -0
- data/lib/rack_warden/frameworks/rails.rb +29 -9
- data/lib/rack_warden/frameworks/sinatra.rb +15 -11
- data/lib/rack_warden/helpers.rb +197 -29
- data/lib/rack_warden/mail.rb +26 -0
- data/lib/rack_warden/models.rb +79 -40
- data/lib/rack_warden/models/user.rb +180 -22
- data/lib/rack_warden/routes.rb +159 -83
- data/lib/rack_warden/sinatra/decompile.rb +127 -0
- data/lib/rack_warden/sinatra/json.rb +131 -0
- data/lib/rack_warden/sinatra/namespace.rb +285 -0
- data/lib/rack_warden/sinatra/respond_with.rb +277 -0
- data/lib/rack_warden/version.rb +1 -1
- data/lib/rack_warden/views/rw_account_widget.html.erb +8 -0
- data/lib/rack_warden/views/rw_activation.email.erb +3 -0
- data/lib/rack_warden/views/rw_admin.html.erb +7 -5
- data/lib/rack_warden/views/rw_dbinfo.html.erb +5 -4
- data/lib/rack_warden/views/rw_error.html.erb +1 -0
- data/lib/rack_warden/views/rw_flash_widget.html.erb +12 -0
- data/lib/rack_warden/views/rw_index.html.erb +1 -1
- data/lib/rack_warden/views/rw_layout.html.erb +13 -19
- data/lib/rack_warden/views/rw_layout_admin.html.erb +6 -6
- data/lib/rack_warden/views/rw_login.html.erb +18 -5
- data/lib/rack_warden/views/rw_new_user.html.erb +22 -6
- data/lib/rack_warden/views/rw_protected.xml.erb +10 -0
- data/lib/rack_warden/views/rw_session.html.erb +34 -0
- data/lib/rack_warden/warden.rb +161 -30
- data/rack_warden.gemspec +16 -13
- metadata +84 -29
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'backports'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Sinatra
|
6
|
+
|
7
|
+
# = Sinatra::Decompile
|
8
|
+
#
|
9
|
+
# <tt>Sinatra::Decompile</tt> is an extension that provides a method,
|
10
|
+
# conveniently called +decompile+, that will generate a String pattern for a
|
11
|
+
# given route.
|
12
|
+
#
|
13
|
+
# == Usage
|
14
|
+
#
|
15
|
+
# === Classic Application
|
16
|
+
#
|
17
|
+
# To use the extension in a classic application all you need to do is require
|
18
|
+
# it:
|
19
|
+
#
|
20
|
+
# require "sinatra"
|
21
|
+
# require "sinatra/decompile"
|
22
|
+
#
|
23
|
+
# # Your classic application code goes here...
|
24
|
+
#
|
25
|
+
# This will add the +decompile+ method to the application/class scope, but
|
26
|
+
# you can also call it as <tt>Sinatra::Decompile.decompile</tt>.
|
27
|
+
#
|
28
|
+
# === Modular Application
|
29
|
+
#
|
30
|
+
# To use the extension in a modular application you need to require it, and
|
31
|
+
# then, tell the application you will use it:
|
32
|
+
#
|
33
|
+
# require "sinatra/base"
|
34
|
+
# require "sinatra/decompile"
|
35
|
+
#
|
36
|
+
# class MyApp < Sinatra::Base
|
37
|
+
# register Sinatra::Decompile
|
38
|
+
#
|
39
|
+
# # The rest of your modular application code goes here...
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# This will add the +decompile+ method to the application/class scope. You
|
43
|
+
# can choose not to register the extension, but instead of calling
|
44
|
+
# +decompile+, you will need to call <tt>Sinatra::Decompile.decompile</tt>.
|
45
|
+
#
|
46
|
+
module Decompile
|
47
|
+
extend self
|
48
|
+
|
49
|
+
##
|
50
|
+
# Regenerates a string pattern for a given route
|
51
|
+
#
|
52
|
+
# Example:
|
53
|
+
#
|
54
|
+
# class Sinatra::Application
|
55
|
+
# routes.each do |verb, list|
|
56
|
+
# puts "#{verb}:"
|
57
|
+
# list.each do |data|
|
58
|
+
# puts "\t" << decompile(data)
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# Will return the internal Regexp if it's unable to reconstruct the pattern,
|
64
|
+
# which likely indicates that a Regexp was used in the first place.
|
65
|
+
#
|
66
|
+
# You can also use this to check whether you could actually use a string
|
67
|
+
# pattern instead of your regexp:
|
68
|
+
#
|
69
|
+
# decompile /^/foo$/ # => '/foo'
|
70
|
+
def decompile(pattern, keys = nil, *)
|
71
|
+
# Everything in here is basically just the reverse of
|
72
|
+
# Sinatra::Base#compile
|
73
|
+
#
|
74
|
+
# Sinatra 2.0 will come with a mechanism for this, making this obsolete.
|
75
|
+
pattern, keys = pattern if pattern.respond_to? :to_ary
|
76
|
+
keys, str = keys.try(:dup), pattern.inspect
|
77
|
+
return pattern unless str.start_with? '/' and str.end_with? '/'
|
78
|
+
str.gsub! /^\/(\^|\\A)?|(\$|\\z)?\/$/, ''
|
79
|
+
str.gsub! encoded(' '), ' '
|
80
|
+
return pattern if str =~ /^[\.\+]/
|
81
|
+
str.gsub! '((?:[^\.\/?#%]|(?:%[^2].|%[2][^Ee]))+)', '([^\/?#]+)'
|
82
|
+
str.gsub! '((?:[^\/?#%]|(?:%[^2].|%[2][^Ee]))+)', '([^\/?#]+)'
|
83
|
+
str.gsub! /\([^\(\)]*\)|\([^\(\)]*\([^\(\)]*\)[^\(\)]*\)/ do |part|
|
84
|
+
case part
|
85
|
+
when '(.*?)'
|
86
|
+
return pattern if keys.shift != 'splat'
|
87
|
+
'*'
|
88
|
+
when /^\(\?\:(\\*.)\|%[\w\[\]]+\)$/
|
89
|
+
$1
|
90
|
+
when /^\(\?\:(%\d+)\|([^\)]+|\([^\)]+\))\)$/
|
91
|
+
URI.unescape($1)
|
92
|
+
when '([^\/?#]+)'
|
93
|
+
return pattern if keys.empty?
|
94
|
+
":" << keys.shift
|
95
|
+
when /^\(\?\:\\?(.)\|/
|
96
|
+
char = $1
|
97
|
+
return pattern unless encoded(char) == part
|
98
|
+
Regexp.escape(char)
|
99
|
+
else
|
100
|
+
return pattern
|
101
|
+
end
|
102
|
+
end
|
103
|
+
str.gsub /(.)([\.\+\(\)\/])/ do
|
104
|
+
return pattern if $1 != "\\"
|
105
|
+
$2
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def encoded(char)
|
112
|
+
return super if defined? super
|
113
|
+
enc = uri_parser.escape(char)
|
114
|
+
enc = "(?:#{escaped(char, enc).join('|')})" if enc == char
|
115
|
+
enc = "(?:#{enc}|#{encoded('+')})" if char == " "
|
116
|
+
enc
|
117
|
+
end
|
118
|
+
|
119
|
+
def uri_parser
|
120
|
+
#TODO: Remove check after dropping support for 1.8.7
|
121
|
+
@_uri_parser ||= defined?(URI::Parser) ? URI::Parser.new : URI
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
#register Decompile
|
127
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'multi_json'
|
3
|
+
module Sinatra
|
4
|
+
|
5
|
+
# = Sinatra::JSON
|
6
|
+
#
|
7
|
+
# <tt>Sinatra::JSON</tt> adds a helper method, called +json+, for (obviously)
|
8
|
+
# json generation.
|
9
|
+
#
|
10
|
+
# == Usage
|
11
|
+
#
|
12
|
+
# === Classic Application
|
13
|
+
#
|
14
|
+
# In a classic application simply require the helper, and start using it:
|
15
|
+
#
|
16
|
+
# require "sinatra"
|
17
|
+
# require "sinatra/json"
|
18
|
+
#
|
19
|
+
# # define a route that uses the helper
|
20
|
+
# get '/' do
|
21
|
+
# json :foo => 'bar'
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # The rest of your classic application code goes here...
|
25
|
+
#
|
26
|
+
# === Modular Application
|
27
|
+
#
|
28
|
+
# In a modular application you need to require the helper, and then tell the
|
29
|
+
# application you will use it:
|
30
|
+
#
|
31
|
+
# require "sinatra/base"
|
32
|
+
# require "sinatra/json"
|
33
|
+
#
|
34
|
+
# class MyApp < Sinatra::Base
|
35
|
+
#
|
36
|
+
# # define a route that uses the helper
|
37
|
+
# get '/' do
|
38
|
+
# json :foo => 'bar'
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# # The rest of your modular application code goes here...
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# === Encoders
|
45
|
+
#
|
46
|
+
# By default it will try to call +to_json+ on the object, but if it doesn't
|
47
|
+
# respond to that message, it will use its own rather simple encoder. You can
|
48
|
+
# easily change that anyways. To use +JSON+, simply require it:
|
49
|
+
#
|
50
|
+
# require 'json'
|
51
|
+
#
|
52
|
+
# The same goes for <tt>Yajl::Encoder</tt>:
|
53
|
+
#
|
54
|
+
# require 'yajl'
|
55
|
+
#
|
56
|
+
# For other encoders, besides requiring them, you need to define the
|
57
|
+
# <tt>:json_encoder</tt> setting. For instance, for the +Whatever+ encoder:
|
58
|
+
#
|
59
|
+
# require 'whatever'
|
60
|
+
# set :json_encoder, Whatever
|
61
|
+
#
|
62
|
+
# To force +json+ to simply call +to_json+ on the object:
|
63
|
+
#
|
64
|
+
# set :json_encoder, :to_json
|
65
|
+
#
|
66
|
+
# Actually, it can call any method:
|
67
|
+
#
|
68
|
+
# set :json_encoder, :my_fancy_json_method
|
69
|
+
#
|
70
|
+
# === Content-Type
|
71
|
+
#
|
72
|
+
# It will automatically set the content type to "application/json". As
|
73
|
+
# usual, you can easily change that, with the <tt>:json_content_type</tt>
|
74
|
+
# setting:
|
75
|
+
#
|
76
|
+
# set :json_content_type, :js
|
77
|
+
#
|
78
|
+
# === Overriding the Encoder and the Content-Type
|
79
|
+
#
|
80
|
+
# The +json+ helper will also take two options <tt>:encoder</tt> and
|
81
|
+
# <tt>:content_type</tt>. The values of this options are the same as the
|
82
|
+
# <tt>:json_encoder</tt> and <tt>:json_content_type</tt> settings,
|
83
|
+
# respectively. You can also pass those to the json method:
|
84
|
+
#
|
85
|
+
# get '/' do
|
86
|
+
# json({:foo => 'bar'}, :encoder => :to_json, :content_type => :js)
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
module JSON
|
90
|
+
class << self
|
91
|
+
def encode(object)
|
92
|
+
::MultiJson.dump(object)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def json(object, options = {})
|
97
|
+
content_type resolve_content_type(options)
|
98
|
+
resolve_encoder_action object, resolve_encoder(options)
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def resolve_content_type(options = {})
|
104
|
+
options[:content_type] || settings.json_content_type
|
105
|
+
end
|
106
|
+
|
107
|
+
def resolve_encoder(options = {})
|
108
|
+
options[:json_encoder] || settings.json_encoder
|
109
|
+
end
|
110
|
+
|
111
|
+
def resolve_encoder_action(object, encoder)
|
112
|
+
[:encode, :generate].each do |method|
|
113
|
+
return encoder.send(method, object) if encoder.respond_to? method
|
114
|
+
end
|
115
|
+
if encoder.is_a? Symbol
|
116
|
+
object.__send__(encoder)
|
117
|
+
else
|
118
|
+
fail "#{encoder} does not respond to #generate nor #encode"
|
119
|
+
end #if
|
120
|
+
end #resolve_encoder_action
|
121
|
+
end #JSON
|
122
|
+
|
123
|
+
Base.set :json_encoder do
|
124
|
+
::MultiJson
|
125
|
+
end
|
126
|
+
|
127
|
+
Base.set :json_content_type, :json
|
128
|
+
|
129
|
+
# Load the JSON helpers in modular style automatically
|
130
|
+
Base.helpers JSON
|
131
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
require 'backports'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'rack_warden/sinatra/decompile'
|
4
|
+
|
5
|
+
module RackWarden
|
6
|
+
App.logger.debug "RW loading Namespace"
|
7
|
+
|
8
|
+
# = Sinatra::Namespace
|
9
|
+
#
|
10
|
+
# <tt>Sinatra::Namespace</tt> is an extension that adds namespaces to an
|
11
|
+
# application. This namespaces will allow you to share a path prefix for the
|
12
|
+
# routes within the namespace, and define filters, conditions and error
|
13
|
+
# handlers exclusively for them. Besides that, you can also register helpers
|
14
|
+
# and extensions that will be used only within the namespace.
|
15
|
+
#
|
16
|
+
# == Usage
|
17
|
+
#
|
18
|
+
# Once you have loaded the extension (see below), you can use the +namespace+
|
19
|
+
# method to define namespaces in your application.
|
20
|
+
#
|
21
|
+
# You can define a namespace by a path prefix:
|
22
|
+
#
|
23
|
+
# namespace '/blog' do
|
24
|
+
# get { haml :blog }
|
25
|
+
# get '/:entry_permalink' do
|
26
|
+
# @entry = Entry.find_by_permalink!(params[:entry_permalink])
|
27
|
+
# haml :entry
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # More blog routes...
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# by a condition:
|
34
|
+
#
|
35
|
+
# namespace :host_name => 'localhost' do
|
36
|
+
# get('/admin/dashboard') { haml :dashboard }
|
37
|
+
# get('/admin/login') { haml :login }
|
38
|
+
#
|
39
|
+
# # More admin routes...
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# or both:
|
43
|
+
#
|
44
|
+
# namespace '/admin', :host_name => 'localhost' do
|
45
|
+
# get('/dashboard') { haml :dashboard }
|
46
|
+
# get('/login') { haml :login }
|
47
|
+
# post('/login') { login_user }
|
48
|
+
#
|
49
|
+
# # More admin routes...
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# When you define a filter or an error handler, or register an extension or a
|
53
|
+
# set of helpers within a namespace, they only affect the routes defined in
|
54
|
+
# it. For instance, lets define a before filter to prevent the access of
|
55
|
+
# unauthorized users to the admin section of the application:
|
56
|
+
#
|
57
|
+
# namespace '/admin' do
|
58
|
+
# helpers AdminHelpers
|
59
|
+
# before { authenticate unless request.path_info == '/admin/login' }
|
60
|
+
#
|
61
|
+
# get '/dashboard' do
|
62
|
+
# # Only authenticated users can access here...
|
63
|
+
# haml :dashboard
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# # More admin routes...
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# get '/' do
|
70
|
+
# # Any user can access here...
|
71
|
+
# haml :index
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# Well, they actually also affect the nested namespaces:
|
75
|
+
#
|
76
|
+
# namespace '/admin' do
|
77
|
+
# helpers AdminHelpers
|
78
|
+
# before { authenticate unless request.path_info == '/admin/login' }
|
79
|
+
#
|
80
|
+
# namespace '/users' do
|
81
|
+
# get do
|
82
|
+
# # Only authenticated users can access here...
|
83
|
+
# @users = User.all
|
84
|
+
# haml :users
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# # More user admin routes...
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# # More admin routes...
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# === Classic Application Setup
|
94
|
+
#
|
95
|
+
# To be able to use namespaces in a classic application all you need to do is
|
96
|
+
# require the extension:
|
97
|
+
#
|
98
|
+
# require "sinatra"
|
99
|
+
# require "sinatra/namespace"
|
100
|
+
#
|
101
|
+
# # The rest of your classic application code goes here...
|
102
|
+
#
|
103
|
+
# === Modular Application Setup
|
104
|
+
#
|
105
|
+
# To be able to use namespaces in a modular application all you need to do is
|
106
|
+
# require the extension, and then, register it:
|
107
|
+
#
|
108
|
+
# require "sinatra/base"
|
109
|
+
# require "sinatra/namespace"
|
110
|
+
#
|
111
|
+
# class MyApp < Sinatra::Base
|
112
|
+
# register Sinatra::Namespace
|
113
|
+
#
|
114
|
+
# # The rest of your modular application code goes here...
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
module Namespace
|
118
|
+
def self.new(base, pattern, conditions = {}, &block)
|
119
|
+
Module.new do
|
120
|
+
extend NamespacedMethods
|
121
|
+
include InstanceMethods
|
122
|
+
@base, @extensions, @errors = base, [], {}
|
123
|
+
@pattern, @conditions = compile(pattern, conditions)
|
124
|
+
@templates = Hash.new { |h,k| @base.templates[k] }
|
125
|
+
namespace = self
|
126
|
+
before { extend(@namespace = namespace) }
|
127
|
+
class_eval(&block)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
module InstanceMethods
|
132
|
+
def settings
|
133
|
+
@namespace
|
134
|
+
end
|
135
|
+
|
136
|
+
def template_cache
|
137
|
+
super.fetch(:nested, @namespace) { Tilt::Cache.new }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
module SharedMethods
|
142
|
+
def namespace(pattern, conditions = {}, &block)
|
143
|
+
Namespace.new(self, pattern, conditions, &block)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
module NamespacedMethods
|
148
|
+
include SharedMethods
|
149
|
+
include Sinatra::Decompile
|
150
|
+
attr_reader :base, :templates
|
151
|
+
|
152
|
+
def self.prefixed(*names)
|
153
|
+
names.each { |n| define_method(n) { |*a, &b| prefixed(n, *a, &b) }}
|
154
|
+
end
|
155
|
+
|
156
|
+
prefixed :before, :after, :delete, :get, :head, :options, :patch, :post, :put
|
157
|
+
|
158
|
+
def helpers(*extensions, &block)
|
159
|
+
class_eval(&block) if block_given?
|
160
|
+
include(*extensions) if extensions.any?
|
161
|
+
end
|
162
|
+
|
163
|
+
def register(*extensions, &block)
|
164
|
+
extensions << Module.new(&block) if block_given?
|
165
|
+
@extensions += extensions
|
166
|
+
extensions.each do |extension|
|
167
|
+
extend extension
|
168
|
+
extension.registered(self) if extension.respond_to?(:registered)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def invoke_hook(name, *args)
|
173
|
+
@extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
|
174
|
+
end
|
175
|
+
|
176
|
+
def not_found(&block)
|
177
|
+
error(404, &block)
|
178
|
+
end
|
179
|
+
|
180
|
+
def errors
|
181
|
+
base.errors.merge(namespace_errors)
|
182
|
+
end
|
183
|
+
|
184
|
+
def namespace_errors
|
185
|
+
@errors
|
186
|
+
end
|
187
|
+
|
188
|
+
def error(*codes, &block)
|
189
|
+
args = Sinatra::Base.send(:compile!, "ERROR", /^#{@pattern}/, block)
|
190
|
+
codes = codes.map { |c| Array(c) }.flatten
|
191
|
+
codes << Exception if codes.empty?
|
192
|
+
codes.each do |c|
|
193
|
+
errors = @errors[c] ||= []
|
194
|
+
errors << args
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def respond_to(*args)
|
199
|
+
return @conditions[:provides] || base.respond_to if args.empty?
|
200
|
+
@conditions[:provides] = args
|
201
|
+
end
|
202
|
+
|
203
|
+
def set(key, value = self, &block)
|
204
|
+
raise ArgumentError, "may not set #{key}" if key != :views
|
205
|
+
return key.each { |k,v| set(k, v) } if block.nil? and value == self
|
206
|
+
block ||= proc { value }
|
207
|
+
singleton_class.send(:define_method, key, &block)
|
208
|
+
end
|
209
|
+
|
210
|
+
def enable(*opts)
|
211
|
+
opts.each { |key| set(key, true) }
|
212
|
+
end
|
213
|
+
|
214
|
+
def disable(*opts)
|
215
|
+
opts.each { |key| set(key, false) }
|
216
|
+
end
|
217
|
+
|
218
|
+
def template(name, &block)
|
219
|
+
filename, line = caller_locations.first
|
220
|
+
templates[name] = [block, filename, line.to_i]
|
221
|
+
end
|
222
|
+
|
223
|
+
def layout(name=:layout, &block)
|
224
|
+
template name, &block
|
225
|
+
end
|
226
|
+
|
227
|
+
private
|
228
|
+
|
229
|
+
def app
|
230
|
+
base.respond_to?(:base) ? base.base : base
|
231
|
+
end
|
232
|
+
|
233
|
+
def compile(pattern, conditions, default_pattern = nil)
|
234
|
+
if pattern.respond_to? :to_hash
|
235
|
+
conditions = conditions.merge pattern.to_hash
|
236
|
+
pattern = nil
|
237
|
+
end
|
238
|
+
base_pattern, base_conditions = @pattern, @conditions
|
239
|
+
pattern ||= default_pattern
|
240
|
+
base_pattern ||= base.pattern if base.respond_to? :pattern
|
241
|
+
base_conditions ||= base.conditions if base.respond_to? :conditions
|
242
|
+
[ prefixed_path(base_pattern, pattern),
|
243
|
+
(base_conditions || {}).merge(conditions) ]
|
244
|
+
end
|
245
|
+
|
246
|
+
def prefixed_path(a, b)
|
247
|
+
return a || b || // unless a and b
|
248
|
+
a, b = decompile(a), decompile(b) unless a.class == b.class
|
249
|
+
a, b = regexpify(a), regexpify(b) unless a.class == b.class
|
250
|
+
path = a.class.new "#{a}#{b}"
|
251
|
+
path = /^#{path}$/ if path.is_a? Regexp and base == app
|
252
|
+
path
|
253
|
+
end
|
254
|
+
|
255
|
+
def regexpify(pattern)
|
256
|
+
pattern = Sinatra::Base.send(:compile, pattern).first.inspect
|
257
|
+
pattern.gsub! /^\/(\^|\\A)?|(\$|\\Z)?\/$/, ''
|
258
|
+
Regexp.new pattern
|
259
|
+
end
|
260
|
+
|
261
|
+
def prefixed(method, pattern = nil, conditions = {}, &block)
|
262
|
+
default = '*' if method == :before or method == :after
|
263
|
+
pattern, conditions = compile pattern, conditions, default
|
264
|
+
result = base.send(method, pattern, conditions, &block)
|
265
|
+
invoke_hook :route_added, method.to_s.upcase, pattern, block
|
266
|
+
result
|
267
|
+
end
|
268
|
+
|
269
|
+
def method_missing(method, *args, &block)
|
270
|
+
base.send(method, *args, &block)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
module BaseMethods
|
275
|
+
include SharedMethods
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.extend_object(base)
|
279
|
+
base.extend BaseMethods
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
#register Sinatra::Namespace
|
284
|
+
#Delegator.delegate :namespace
|
285
|
+
end
|