usher 0.6.6 → 0.6.7
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/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
|