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 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