usher 0.6.5 → 0.6.6

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 ADDED
@@ -0,0 +1,9 @@
1
+ = Changelog
2
+
3
+ == From 0.6.5 to 0.6.6
4
+
5
+ * Faster recognition (~10%)
6
+ * Nicer exception message when generating a route and raising a MissingParameterException
7
+ * Nodes now support #ancestors and #root methods.
8
+ * Cache responses on non-dynamic paths.
9
+ * Started a changelog.
data/VERSION.yml CHANGED
@@ -2,4 +2,4 @@
2
2
  :build:
3
3
  :major: 0
4
4
  :minor: 6
5
- :patch: 5
5
+ :patch: 6
@@ -3,7 +3,7 @@ class Usher
3
3
  class Response < Struct.new(:path, :params_as_array, :remaining_path, :matched_path)
4
4
 
5
5
  def params
6
- @params ||= params_as_array.nil? ? [] : path.convert_params_array(params_as_array)
6
+ @params ||= path.convert_params_array(params_as_array)
7
7
  end
8
8
 
9
9
  def partial_match?
@@ -11,7 +11,7 @@ class Usher
11
11
  end
12
12
 
13
13
  def params_as_hash
14
- @params_as_hash ||= params_as_array.nil? ? {} : params_as_array.inject({}){|hash, val| hash[path.dynamic_keys[hash.size]] = val; hash}
14
+ @params_as_hash ||= params_as_array.inject({}){|hash, val| hash[path.dynamic_keys[hash.size]] = val; hash}
15
15
  end
16
16
 
17
17
  def destination
@@ -7,6 +7,10 @@ class Usher
7
7
  self.request_methods = request_methods
8
8
  end
9
9
 
10
+ def route_set
11
+ parent
12
+ end
13
+
10
14
  def add(route)
11
15
  route.paths.each do |path|
12
16
  set_path_with_destination(path)
data/lib/usher/node.rb CHANGED
@@ -52,6 +52,26 @@ class Usher
52
52
  @terminates && @terminates.route.recognizable?
53
53
  end
54
54
 
55
+ def ancestors
56
+ unless @ancestors
57
+ @ancestors = []
58
+ node = self
59
+ while (node.respond_to?(:parent))
60
+ @ancestors << node
61
+ node = node.parent
62
+ end
63
+ end
64
+ @ancestors
65
+ end
66
+
67
+ def root
68
+ @root ||= ancestors.last
69
+ end
70
+
71
+ def route_set
72
+ @route_set ||= root.route_set
73
+ end
74
+
55
75
  def pp
56
76
  $stdout << " " * depth
57
77
  $stdout << "#{terminates? ? '* ' : ''}#{depth}: #{value.inspect}\n"
@@ -72,68 +92,71 @@ class Usher
72
92
  end if request
73
93
  end
74
94
 
75
- def find(usher, request_object, original_path, path, params = nil, position = 0)
76
- if terminates? && (path.empty? || terminates.route.partial_match? || (usher.ignore_trailing_delimiters? && path.all?{|p| usher.delimiters.include?(p)}))
77
- terminates.route.partial_match? ?
78
- Response.new(terminates, params, original_path[position, original_path.size], original_path[0, position]) :
79
- Response.new(terminates, params, nil, original_path)
80
- elsif !path.empty? and greedy and match_with_result_output = greedy.match_with_result(whole_path = original_path[position, original_path.size])
95
+ def find(request_object, original_path, path, params = [])
96
+ # terminates or is partial
97
+ if terminates? && (path.empty? || terminates.route.partial_match? || (route_set.ignore_trailing_delimiters? && path.all?{|p| route_set.delimiters.include?(p)}))
98
+ if terminates.cached_response
99
+ terminates.cached_response
100
+ else
101
+ terminates.route.partial_match? ?
102
+ Response.new(terminates, params, path.join, original_path[0, original_path.size - path.join.size]) :
103
+ Response.new(terminates, params, nil, original_path)
104
+ end
105
+ # terminates or is partial
106
+ elsif !path.empty? and greedy and match_with_result_output = greedy.match_with_result(whole_path = path.join)
81
107
  next_path, matched_part = match_with_result_output
82
- position += matched_part.size
83
108
  whole_path.slice!(0, matched_part.size)
84
- (params ||= []) << matched_part if next_path.value.is_a?(Route::Variable)
85
- next_path.find(usher, request_object, original_path, whole_path.empty? ? whole_path : usher.splitter.split(whole_path), params, position)
109
+ params << matched_part if next_path.value.is_a?(Route::Variable)
110
+ next_path.find(request_object, original_path, whole_path.empty? ? whole_path : route_set.splitter.split(whole_path), params)
86
111
  elsif !path.empty? and normal and next_part = normal[path.first] || normal[nil]
87
112
  part = path.shift
88
- position += part.size
89
113
  case next_part.value
90
- when String
91
- # do nothing
92
- when Route::Variable::Single
93
- # get the variable
94
- var = next_part.value
95
- # do a validity check
96
- var.valid!(part)
97
- # because its a variable, we need to add it to the params array
98
- (params ||= []) << part
99
- until path.empty? || (var.look_ahead === path.first) # variables have a look ahead notion,
114
+ when String
115
+ when Route::Variable::Single
116
+ # get the variable
117
+ variable = next_part.value
118
+ # do a validity check
119
+ variable.valid!(part)
120
+ # because its a variable, we need to add it to the params array
121
+ parameter_value = part
122
+ if variable.look_ahead
123
+ until path.empty? || (variable.look_ahead === path.first) # variables have a look ahead notion,
100
124
  next_path_part = path.shift # and until they are satified,
101
- position += next_path_part.size # keep appending to the value in params
102
- params.last << next_path_part
103
- end if var.look_ahead && usher.delimiters.size > 1
104
- when Route::Variable::Glob
105
- (params ||= []) << []
106
- while true
107
- if (next_part.value.look_ahead === part || (!usher.delimiters.unescaped.include?(part) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part)))
108
- path.unshift(part)
109
- position -= part.size
110
- if usher.delimiters.unescaped.include?(next_part.parent.value)
111
- path.unshift(next_part.parent.value)
112
- position -= next_part.parent.value.size
113
- end
114
- break
115
- elsif !usher.delimiters.unescaped.include?(part)
116
- next_part.value.valid!(part)
117
- params.last << part
118
- end
119
- if path.empty?
120
- break
121
- else
122
- part = path.shift
125
+ parameter_value << next_path_part
126
+ end
127
+ end
128
+ params << parameter_value
129
+ when Route::Variable::Glob
130
+ params << []
131
+ loop do
132
+ if (next_part.value.look_ahead === part || (!route_set.delimiters.unescaped.include?(part) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part)))
133
+ path.unshift(part)
134
+ if route_set.delimiters.unescaped.include?(next_part.parent.value)
135
+ path.unshift(next_part.parent.value)
123
136
  end
137
+ break
138
+ elsif !route_set.delimiters.unescaped.include?(part)
139
+ next_part.value.valid!(part)
140
+ params.last << part
141
+ end
142
+ if path.empty?
143
+ break
144
+ else
145
+ part = path.shift
124
146
  end
147
+ end
125
148
  end
126
- next_part.find(usher, request_object, original_path, path, params, position)
149
+ next_part.find(request_object, original_path, path, params)
127
150
  elsif request_method_type
128
- return_value = if (specific_node = request[request_object.send(request_method_type)] and ret = specific_node.find(usher, request_object, original_path, path.dup, params && params.dup, position))
129
- usher.priority_lookups? ? [ret] : ret
151
+ return_value = if (specific_node = request[request_object.send(request_method_type)] and ret = specific_node.find(request_object, original_path, path.dup, params && params.dup))
152
+ route_set.priority_lookups? ? [ret] : ret
130
153
  end
131
154
 
132
- if usher.priority_lookups? || return_value.nil? and general_node = request[nil] and ret = general_node.find(usher, request_object, original_path, path.dup, params && params.dup, position)
133
- return_value = usher.priority_lookups? && return_value ? [return_value, ret] : ret
155
+ if route_set.priority_lookups? || return_value.nil? and general_node = request[nil] and ret = general_node.find(request_object, original_path, path.dup, params && params.dup)
156
+ return_value = route_set.priority_lookups? && return_value ? [return_value, ret] : ret
134
157
  end
135
158
 
136
- unless usher.priority_lookups?
159
+ unless route_set.priority_lookups?
137
160
  return_value
138
161
  else
139
162
  return_value = Array(return_value).flatten.compact
@@ -2,7 +2,7 @@ class Usher
2
2
  class Route
3
3
  class Path
4
4
 
5
- attr_accessor :route
5
+ attr_accessor :route, :cached_response
6
6
  attr_reader :parts
7
7
 
8
8
  def initialize(route, parts)
@@ -21,14 +21,14 @@ class Usher
21
21
  when String
22
22
  result << part
23
23
  when Route::Variable::Glob
24
- value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new)
24
+ value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new("expected a value for #{part.name}"))
25
25
  value.each_with_index do |current_value, index|
26
26
  part.valid!(current_value)
27
27
  result << current_value.to_s
28
28
  result << usher.delimiters.first if index != value.size - 1
29
29
  end
30
30
  when Route::Variable
31
- value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new)
31
+ value = (params && params.delete(part.name)) || part.default_value || raise(MissingParameterException.new("expected a value for #{part.name}"))
32
32
  part.valid!(value)
33
33
  result << value.to_s
34
34
  end
@@ -123,9 +123,9 @@ class Usher
123
123
  if variable
124
124
  variable_type = variable.slice!(0).chr.to_sym
125
125
  variable_class = case variable_type
126
- when :'!' : Usher::Route::Variable::Greedy
127
- when :* : Usher::Route::Variable::Glob
128
- when :':' : Usher::Route::Variable::Single
126
+ when :'!' then Usher::Route::Variable::Greedy
127
+ when :* then Usher::Route::Variable::Glob
128
+ when :':' then Usher::Route::Variable::Single
129
129
  end
130
130
  variable_name = variable[0, variable.size - 1].to_sym
131
131
  current_group << variable_class.new(variable_name, regex, requirements && requirements[variable_name])
data/lib/usher.rb CHANGED
@@ -232,7 +232,11 @@ class Usher
232
232
  # route = set.add_route('/test')
233
233
  # set.recognize(Request.new('/test')).path.route == route => true
234
234
  def recognize(request, path = request.path)
235
- @root.find(self, request, path, @splitter.split(path))
235
+ response = @root.find(request, path, @splitter.split(path))
236
+ if response && !response.path.dynamic?
237
+ response.path.cached_response = response
238
+ end
239
+ response
236
240
  end
237
241
 
238
242
  # Recognizes a +path+ and returns +nil+ or an Usher::Node::Response, which is a struct containing a Usher::Route::Path and an array of arrays containing the extracted parameters. Convenience method for when recognizing on the request object is unneeded.
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.5
4
+ version: 0.6.6
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-13 00:00:00 -05:00
17
+ date: 2010-01-15 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -36,6 +36,7 @@ extensions: []
36
36
  extra_rdoc_files:
37
37
  - README.rdoc
38
38
  files:
39
+ - CHANGES.rdoc
39
40
  - History.txt
40
41
  - Manifest.txt
41
42
  - README.rdoc