usher 0.6.6 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.rdoc +6 -0
- data/README.rdoc +12 -13
- data/VERSION.yml +1 -1
- data/lib/usher/interface/rack.rb +50 -11
- data/lib/usher/interface/rails23.rb +42 -42
- data/lib/usher/route/path.rb +4 -5
- data/lib/usher/splitter.rb +4 -2
- data/lib/usher/util.rb +0 -2
- data/lib/usher/util/generate.rb +2 -2
- data/lib/usher/util/mapper.rb +6 -0
- data/lib/usher/util/rack-mixins.rb +7 -0
- metadata +2 -2
data/CHANGES.rdoc
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
= Changelog
|
2
2
|
|
3
|
+
== From 0.6.6 to 0.6.7
|
4
|
+
|
5
|
+
* Added Usher::Interfaces::Rack#only_get. Convenience method for adding routes which respond to only get and not both head and get.
|
6
|
+
* Made Usher::Interfaces::Rack take lots of configuration options and updated docs to reflect that. (As well as numerous other improved bits of docs.)
|
7
|
+
* When route goes through Rack interface, insert Router into env. (right now its usher.router by default)
|
8
|
+
|
3
9
|
== From 0.6.5 to 0.6.6
|
4
10
|
|
5
11
|
* Faster recognition (~10%)
|
data/README.rdoc
CHANGED
@@ -14,6 +14,18 @@ Tree-based router library. Useful for (specifically) for Rails and Rack, but pro
|
|
14
14
|
* Interface and implementation are separate, encouraging cross-pollination
|
15
15
|
* Works in 1.9!
|
16
16
|
|
17
|
+
== Projects using or other references to Usher
|
18
|
+
|
19
|
+
* http://github.com/Tass/CRUDtree - RESTful resource mapper
|
20
|
+
* http://github.com/padrino/padrino-framework - Web framework
|
21
|
+
* http://github.com/botanicus/rango - Web framework
|
22
|
+
* http://github.com/hassox/pancake - Web framework
|
23
|
+
* http://github.com/eddanger/junior - Web framework
|
24
|
+
* http://github.com/lifo/cramp - Web framework
|
25
|
+
* http://yehudakatz.com/2009/08/26/how-to-build-sinatra-on-rails-3/ - How to Build Sinatra on Rails 3
|
26
|
+
|
27
|
+
Any probably more!
|
28
|
+
|
17
29
|
== Route format
|
18
30
|
|
19
31
|
From the rdoc:
|
@@ -139,17 +151,4 @@ In Sinatra, you get the extra method, +generate+, which lets you generate a url.
|
|
139
151
|
"Hello World! #{generate(:hi)}"
|
140
152
|
end
|
141
153
|
|
142
|
-
== DONE
|
143
|
-
|
144
|
-
* add support for () optional parts
|
145
|
-
* Add support for arbitrary HTTP header checks
|
146
|
-
* Emit exceptions inline with relevant interfaces
|
147
|
-
* More RDoc! (optionally cowbell)
|
148
|
-
|
149
|
-
== TODO
|
150
|
-
|
151
|
-
* Make it integrate with merb
|
152
|
-
* Make it integrate with rails3
|
153
|
-
* Create decent DSL for use with rack
|
154
|
-
|
155
154
|
(Let me show you to your request)
|
data/VERSION.yml
CHANGED
data/lib/usher/interface/rack.rb
CHANGED
@@ -7,7 +7,12 @@ class Usher
|
|
7
7
|
|
8
8
|
ENV_KEY_RESPONSE = 'usher.response'
|
9
9
|
ENV_KEY_PARAMS = 'usher.params'
|
10
|
-
|
10
|
+
ENV_KEY_DEFAULT_ROUTER = 'usher.router'
|
11
|
+
|
12
|
+
|
13
|
+
# Middleware for using Usher's rack interface to recognize the request, then, pass on to the next application.
|
14
|
+
# Values are stored in <tt>env</tt> normally.
|
15
|
+
#
|
11
16
|
class Middleware
|
12
17
|
|
13
18
|
def initialize(app, router)
|
@@ -21,7 +26,10 @@ class Usher
|
|
21
26
|
end
|
22
27
|
|
23
28
|
end
|
24
|
-
|
29
|
+
|
30
|
+
# Replacement for <tt>Rack::Builder</tt> which using Usher to map requests instead of a simple Hash.
|
31
|
+
# As well, add convenience methods for the request methods.
|
32
|
+
#
|
25
33
|
class Builder < ::Rack::Builder
|
26
34
|
def initialize(&block)
|
27
35
|
@usher = Usher::Interface::Rack.new
|
@@ -53,19 +61,33 @@ class Usher
|
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
56
|
-
attr_reader :router
|
64
|
+
attr_reader :router, :router_key
|
57
65
|
|
66
|
+
# Constructor for Rack interface for Usher.
|
67
|
+
# <tt>app</tt> - the default application to route to if no matching route is found. The default is a 404 response.
|
68
|
+
# <tt>options</tt> - options to configure the router
|
69
|
+
# * <tt>use_destinations</tt> - option to disable using the destinations passed into routes. (Default <tt>true</tt>)
|
70
|
+
# * <tt>router_key</tt> - Key in which to put router into env. (Default <tt>usher.router</tt>)
|
71
|
+
# * <tt>request_methods</tt> - Request methods on <tt>Rack::Request</tt> to use in determining recognition. (Default <tt>[:request_method, :host, :port, :scheme]</tt>)
|
72
|
+
# * <tt>generator</tt> - Route generator to use. (Default <tt>Usher::Util::Generators::URL.new</tt>)
|
73
|
+
# * <tt>allow_identical_variable_names</tt> - Option to prevent routes with identical variable names to be added. eg, /:variable/:variable would raise an exception if this option is not enabled. (Default <tt>false</tt>)
|
58
74
|
def initialize(app = nil, options = nil, &blk)
|
59
|
-
@_app = app ||
|
60
|
-
@router = Usher.new(:request_methods => [:request_method, :host, :port, :scheme], :generator => Usher::Util::Generators::URL.new, :allow_identical_variable_names => false)
|
75
|
+
@_app = app || proc{|env| ::Rack::Response.new("No route found", 404).finish }
|
61
76
|
@use_destinations = options && options.key?(:use_destinations) ? options[:use_destinations] : true
|
77
|
+
@router_key = options && options[:router_key] || ENV_KEY_DEFAULT_ROUTER
|
78
|
+
request_methods = options && options[:request_methods] || [:request_method, :host, :port, :scheme]
|
79
|
+
generator = options && options[:generator] || Usher::Util::Generators::URL.new
|
80
|
+
allow_identical_variable_names = options && options.key(:allow_identical_variable_names) ? options[:allow_identical_variable_names] : false
|
81
|
+
@router = Usher.new(:request_methods => request_methods, :generator => generator, :allow_identical_variable_names => allow_identical_variable_names)
|
62
82
|
instance_eval(&blk) if blk
|
63
83
|
end
|
64
|
-
|
84
|
+
|
85
|
+
# Returns whether the route set has use_destinations? enabled.
|
65
86
|
def use_destinations?
|
66
87
|
@use_destinations
|
67
88
|
end
|
68
89
|
|
90
|
+
# Creates a deep copy of the current route set.
|
69
91
|
def dup
|
70
92
|
new_one = super
|
71
93
|
original = self
|
@@ -74,12 +96,16 @@ class Usher
|
|
74
96
|
end
|
75
97
|
new_one
|
76
98
|
end
|
77
|
-
|
99
|
+
|
100
|
+
# Adds a route to the route set with a +path+ and optional +options+.
|
101
|
+
# See <tt>Usher#add_route</tt> for more details about the format of the route and options accepted here.
|
78
102
|
def add(path, options = nil)
|
79
103
|
@router.add_route(path, options)
|
80
104
|
end
|
81
105
|
alias_method :path, :add
|
82
106
|
|
107
|
+
# Sets the default application when route matching is unsuccessful. Accepts either an application +app+ or a block to call.
|
108
|
+
#
|
83
109
|
# default { |env| ... }
|
84
110
|
# default DefaultApp
|
85
111
|
def default(app = nil, &block)
|
@@ -93,20 +119,30 @@ class Usher
|
|
93
119
|
|
94
120
|
# it returns route, and because you may want to work with the route,
|
95
121
|
# for example give it a name, we returns the route with GET request
|
122
|
+
|
123
|
+
# Convenience method for adding a route that only matches request method +GET+.
|
124
|
+
def only_get(path, options = {})
|
125
|
+
add(path, options.merge!(:conditions => {:request_method => ["GET"]}))
|
126
|
+
end
|
127
|
+
|
128
|
+
# Convenience method for adding a route that only matches request methods +GET+ and +HEAD+.
|
96
129
|
def get(path, options = {})
|
97
|
-
|
130
|
+
add(path, options.merge!(:conditions => {:request_method => ["HEAD", "GET"]}))
|
98
131
|
end
|
99
132
|
|
133
|
+
# Convenience method for adding a route that only matches request method +POST+.
|
100
134
|
def post(path, options = {})
|
101
|
-
|
135
|
+
add(path, options.merge!(:conditions => {:request_method => "POST"}))
|
102
136
|
end
|
103
137
|
|
138
|
+
# Convenience method for adding a route that only matches request method +PUT+.
|
104
139
|
def put(path, options = {})
|
105
|
-
|
140
|
+
add(path, options.merge!(:conditions => {:request_method => "PUT"}))
|
106
141
|
end
|
107
142
|
|
143
|
+
# Convenience method for adding a route that only matches request method +DELETE+.
|
108
144
|
def delete(path, options = {})
|
109
|
-
|
145
|
+
add(path, options.merge!(:conditions => {:request_method => "DELETE"}))
|
110
146
|
end
|
111
147
|
|
112
148
|
def parent_route=(route)
|
@@ -122,6 +158,7 @@ class Usher
|
|
122
158
|
end
|
123
159
|
|
124
160
|
def call(env)
|
161
|
+
env[router_key] = self
|
125
162
|
request = ::Rack::Request.new(env)
|
126
163
|
response = @router.recognize(request, request.path_info)
|
127
164
|
after_match(request, response) if response
|
@@ -161,6 +198,8 @@ class Usher
|
|
161
198
|
def determine_respondant(response)
|
162
199
|
if use_destinations? && response && response.destination && response.destination.respond_to?(:call)
|
163
200
|
response.destination
|
201
|
+
elsif use_destinations? && response && response.destination && response.destination.respond_to?(:args) && response.destination.args.first.respond_to?(:call)
|
202
|
+
response.args.first
|
164
203
|
else
|
165
204
|
_app
|
166
205
|
end
|
@@ -92,45 +92,45 @@ class Usher
|
|
92
92
|
Array(destinations).each do |d| d.module_eval { include Helpers }
|
93
93
|
@router.named_routes.keys.each do |name|
|
94
94
|
@module.module_eval <<-end_eval # We use module_eval to avoid leaks
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
95
|
+
def #{name}_url(options = {})
|
96
|
+
ActionController::Routing::UsherRoutes.generate(options, {}, :generate, :#{name})
|
97
|
+
end
|
98
|
+
end_eval
|
99
|
+
end
|
100
|
+
d.__send__(:include, @module)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate(options, recall = {}, method = :generate, route_name = nil)
|
105
|
+
route = if(route_name)
|
106
|
+
@router.named_routes[route_name]
|
107
|
+
else
|
108
|
+
merged_options = options
|
109
|
+
merged_options[:controller] = recall[:controller] unless options.key?(:controller)
|
110
|
+
unless options.key?(:action)
|
111
|
+
options[:action] = ''
|
112
|
+
end
|
113
|
+
path_for_options(merged_options)
|
114
|
+
end
|
115
|
+
case method
|
116
|
+
when :generate
|
117
|
+
merged_options ||= recall.merge(options)
|
118
|
+
url = generate_url(route, merged_options)
|
119
|
+
url.slice!(-1) if url[-1] == ?/
|
120
|
+
url
|
121
|
+
else
|
122
|
+
raise "method #{method} not recognized"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def generate_url(route, params)
|
127
|
+
@router.generator.generate(route, params)
|
128
|
+
end
|
129
|
+
|
130
|
+
def path_for_options(options)
|
131
|
+
@router.path_for_options(options)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/usher/route/path.rb
CHANGED
@@ -54,7 +54,6 @@ class Usher
|
|
54
54
|
|
55
55
|
def can_generate_from_params?(params)
|
56
56
|
if route.router.consider_destination_keys?
|
57
|
-
route.destination.to_a - params.to_a
|
58
57
|
(route.destination.to_a - params.to_a).size.zero?
|
59
58
|
end
|
60
59
|
end
|
@@ -66,10 +65,10 @@ class Usher
|
|
66
65
|
end
|
67
66
|
|
68
67
|
private
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
68
|
+
def parts=(parts)
|
69
|
+
@parts = parts
|
70
|
+
@dynamic = @parts.any?{|p| p.is_a?(Variable)}
|
71
|
+
end
|
73
72
|
|
74
73
|
end
|
75
74
|
end
|
data/lib/usher/splitter.rb
CHANGED
@@ -10,12 +10,14 @@ class Usher
|
|
10
10
|
|
11
11
|
class SingleCharacterSplitterInstance
|
12
12
|
|
13
|
+
attr_reader :url_split_regex
|
14
|
+
|
13
15
|
def initialize(delimiters)
|
14
|
-
@url_split_regex = Regexp.new("[
|
16
|
+
@url_split_regex = Regexp.new("[^#{delimiters.collect{|d| Regexp.quote(d)}.join}]+|[#{delimiters.collect{|d| Regexp.quote(d)}.join}]")
|
15
17
|
end
|
16
18
|
|
17
19
|
def split(path)
|
18
|
-
path.scan(
|
20
|
+
path.scan(url_split_regex)
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
data/lib/usher/util.rb
CHANGED
data/lib/usher/util/generate.rb
CHANGED
@@ -137,8 +137,8 @@ class Usher
|
|
137
137
|
extra_params = params.last.is_a?(Hash) ? params.pop : nil
|
138
138
|
raise MissingParameterException.new("got #{params.size}, expected #{path.dynamic_parts.size} parameters") unless path.dynamic_parts.size == params.size
|
139
139
|
end
|
140
|
-
|
141
|
-
|
140
|
+
result = generate_path_for_base_params(path, params)
|
141
|
+
Rack::Utils.uri_escape!(result)
|
142
142
|
|
143
143
|
params = extra_params if extra_params
|
144
144
|
|
data/lib/usher/util/mapper.rb
CHANGED
@@ -12,6 +12,13 @@ unless Rack::Utils.respond_to?(:uri_escape)
|
|
12
12
|
end
|
13
13
|
module_function :uri_escape
|
14
14
|
|
15
|
+
def uri_escape!(s)
|
16
|
+
s.to_s.gsub!(/([^:\/?\[\]\-_~\.!\$&'\(\)\*\+,;=@a-zA-Z0-9]+)/n) {
|
17
|
+
'%'<<$1.unpack('H2'*$1.size).join('%').upcase
|
18
|
+
}
|
19
|
+
end
|
20
|
+
module_function :uri_escape!
|
21
|
+
|
15
22
|
def uri_unescape(s)
|
16
23
|
gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
17
24
|
[$1.delete('%')].pack('H*')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: usher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Neighman
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-01-
|
17
|
+
date: 2010-01-24 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|