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 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
@@ -2,4 +2,4 @@
2
2
  :build:
3
3
  :major: 0
4
4
  :minor: 6
5
- :patch: 6
5
+ :patch: 7
@@ -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 || lambda { |env| ::Rack::Response.new("No route found", 404).finish }
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
- self.add(path, options.merge!(:conditions => {:request_method => ["HEAD", "GET"]}))
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
- self.add(path, options.merge!(:conditions => {:request_method => "POST"}))
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
- self.add(path, options.merge!(:conditions => {:request_method => "PUT"}))
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
- self.add(path, options.merge!(:conditions => {:request_method => "DELETE"}))
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
- 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
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
@@ -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
- def parts=(parts)
70
- @parts = parts
71
- @dynamic = @parts.any?{|p| p.is_a?(Variable)}
72
- end
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
@@ -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("[#{delimiters.collect{|d| Regexp.quote(d)}.join}]|[^#{delimiters.collect{|d| Regexp.quote(d)}.join}]+")
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(@url_split_regex)
20
+ path.scan(url_split_regex)
19
21
  end
20
22
  end
21
23
 
data/lib/usher/util.rb CHANGED
@@ -2,7 +2,5 @@ class Usher
2
2
  module Util
3
3
  autoload :Generators, File.join('usher', 'util', 'generate')
4
4
  autoload :Parser, File.join('usher', 'util', 'parser')
5
- autoload :Graph, File.join('usher', 'util', 'graph')
6
- autoload :Mapper, File.join('usher', 'util', 'mapper')
7
5
  end
8
6
  end
@@ -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
- result = Rack::Utils.uri_escape(generate_path_for_base_params(path, params))
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
 
@@ -6,6 +6,12 @@ class Usher
6
6
  @router = router
7
7
  end
8
8
 
9
+ def with(prefix, options = nil)
10
+
11
+
12
+
13
+ end
14
+
9
15
  end
10
16
  end
11
17
  end
@@ -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.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-15 00:00:00 -05:00
17
+ date: 2010-01-24 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency