joshbuddy-usher 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -74,7 +74,6 @@ For instance, the path, <tt>/path/something(.xml|.html)</tt> would only match <t
74
74
  <tt>/path/something.html</tt>. Generally its more efficent to use one and only sections over using regex.
75
75
 
76
76
  === +options+
77
- * +transformers+ - Transforms a variable before it gets to the requirements. Takes either a +proc+ or a +symbol+. If its a +symbol+, calls the method on the incoming parameter. If its a +proc+, its called with the variable.
78
77
  * +requirements+ - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
79
78
  * +conditions+ - Accepts any of the +request_methods+ specificied in the construction of Usher. This can be either a <tt>string</tt> or a regular expression.
80
79
  * Any other key is interpreted as a requirement for the variable of its name.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 4
4
- :patch: 2
4
+ :patch: 3
data/lib/usher.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
3
  require 'cgi'
4
+ require 'uri'
4
5
  require 'usher/node'
5
6
  require 'usher/route'
6
7
  require 'usher/grapher'
@@ -135,12 +136,10 @@ class Usher
135
136
  # <tt>/path/something.html</tt>. Generally its more efficent to use one and only sections over using regex.
136
137
  #
137
138
  # === +options+
138
- # * +transformers+ - Transforms a variable before it gets to the requirements. Takes either a +proc+ or a +symbol+. If its a +symbol+, calls the method on the incoming parameter. If its a +proc+, its called with the variable.
139
139
  # * +requirements+ - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
140
140
  # * +conditions+ - Accepts any of the +request_methods+ specificied in the construction of Usher. This can be either a <tt>string</tt> or a regular expression.
141
141
  # * Any other key is interpreted as a requirement for the variable of its name.
142
142
  def add_route(path, options = nil)
143
- transformers = options && options.delete(:transformers) || {}
144
143
  conditions = options && options.delete(:conditions) || {}
145
144
  requirements = options && options.delete(:requirements) || {}
146
145
  if options
@@ -151,7 +150,7 @@ class Usher
151
150
  end
152
151
  end
153
152
  end
154
- route = Route.new(path, self, {:transformers => transformers, :conditions => conditions, :requirements => requirements})
153
+ route = Route.new(path, self, {:conditions => conditions, :requirements => requirements})
155
154
  route.to(options) if options && !options.empty?
156
155
 
157
156
  @tree.add(route)
@@ -224,15 +223,18 @@ class Usher
224
223
  case p.type
225
224
  when :*
226
225
  param_list.first.each {|dp| p.valid!(dp.to_s) } if check_variables
227
- generated_path << param_list.shift.collect{|dp| dp.to_s} * delimiter
226
+ generated_path << param_list.shift.collect{|dp| URI.escape(dp.to_s)} * delimiter
228
227
  else
229
228
  p.valid!(param_list.first.to_s) if check_variables
230
- (dp = param_list.shift) && generated_path << dp.to_s
229
+ if dp = param_list.shift
230
+ generated_path << URI.escape(dp.to_s)
231
+ end
231
232
  end
232
233
  else
233
234
  generated_path << p.to_s
234
235
  end
235
236
  end
237
+
236
238
  unless params_hash.empty?
237
239
  has_query = generated_path[??]
238
240
  params_hash.each do |k,v|
@@ -9,6 +9,8 @@ class Usher
9
9
  RequestMethods = [:method, :host, :port, :scheme]
10
10
  Request = Struct.new(:path, *RequestMethods)
11
11
 
12
+ attr_accessor :routes
13
+
12
14
  def initialize(&blk)
13
15
  @routes = Usher.new(:request_methods => RequestMethods)
14
16
  instance_eval(&blk) if blk
data/lib/usher/node.rb CHANGED
@@ -90,37 +90,27 @@ class Usher
90
90
  end
91
91
 
92
92
  def find(request, path, params = [])
93
- part = path.shift unless path.size.zero?
94
-
95
- if @exclusive_type
96
- path.unshift part
97
- [@lookup[request.send(@exclusive_type)], @lookup[nil]].each do |n|
98
- ret = n.find(request, path.dup, params.dup) if n
99
- ret and return ret
100
- end
101
- elsif path.size.zero? && !part
102
- if terminates?
103
- Response.new(terminates, params)
104
- elsif params.last.is_a?(Array) && @lookup[nil]
105
- if @lookup[nil].exclusive_type
106
- @lookup[nil].find(request, path, params)
107
- else
108
- Response.new(@lookup[nil].terminates, params)
93
+ if exclusive_type
94
+ [lookup[request.send(exclusive_type)], lookup[nil]].each do |n|
95
+ if n && (ret = n.find(request, path.dup, params.dup))
96
+ return ret
109
97
  end
110
98
  end
111
- elsif next_part = @lookup[part]
112
- if next_part.value.is_a?(Route::Variable)
99
+ elsif path.size.zero? && terminates?
100
+ Response.new(terminates, params)
101
+ elsif next_part = lookup[part = path.shift] || lookup[nil]
102
+ case next_part.value
103
+ when Route::Variable
113
104
  case next_part.value.type
114
105
  when :*
115
106
  params << [next_part.value.name, []] unless params.last && params.last.first == next_part.value.name
116
107
  loop do
117
- if (next_part.value.look_ahead === part || (!part.is_a?(Symbol) && !next_part.value.regex_matcher.match(part)))
108
+ if (next_part.value.look_ahead === part || (!part.is_a?(Symbol) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part)))
118
109
  path.unshift(part)
119
110
  path.unshift(next_part.parent.value) if next_part.parent.value.is_a?(Symbol)
120
111
  break
121
112
  else
122
113
  unless part.is_a?(Symbol) && !next_part.value.globs_capture_separators
123
- part = next_part.value.transform!(part)
124
114
  next_part.value.valid!(part)
125
115
  params.last.last << part
126
116
  end
@@ -131,48 +121,16 @@ class Usher
131
121
  part = path.shift
132
122
  end
133
123
  end
134
- next_part.find(request, path, params)
135
- when :':'
136
- part = next_part.value.transform!(part)
137
- next_part.value.valid!(part)
138
- var = next_part.value
139
- params << [next_part.value.name, part]
140
- until (path.first == var.look_ahead) || path.empty?
141
- params.last.last << path.shift.to_s
142
- end
143
- next_part.find(request, path, params)
144
- end
145
- else
146
- next_part.find(request, path, params)
147
- end
148
- elsif next_part = @lookup[nil]
149
- if next_part.value.is_a?(Route::Variable)
150
- case next_part.value.type
151
- when :*
152
- params << [next_part.value.name, []] unless params.last && params.last.first == next_part.value.name
153
- if next_part.value.look_ahead === part
154
- path.unshift(part)
155
- path.unshift(next_part.parent.value) if next_part.parent.value.is_a?(Symbol)
156
- next_part.find(request, path, params)
157
- else
158
- unless part.is_a?(Symbol) && !next_part.value.globs_capture_separators
159
- part = next_part.value.transform!(part)
160
- next_part.value.valid!(part)
161
- params.last.last << part
162
- end
163
- find(request, path, params)
164
- end
165
124
  when :':'
166
- part = next_part.value.transform!(part)
167
125
  next_part.value.valid!(part)
168
126
  var = next_part.value
169
127
  params << [next_part.value.name, part]
170
128
  until (path.first == var.look_ahead) || path.empty?
171
129
  params.last.last << path.shift.to_s
172
130
  end
173
- next_part.find(request, path, params)
174
131
  end
175
132
  end
133
+ next_part.find(request, path, params)
176
134
  else
177
135
  nil
178
136
  end
data/lib/usher/route.rb CHANGED
@@ -13,8 +13,7 @@ class Usher
13
13
  @router = router
14
14
  @requirements = options && options.delete(:requirements)
15
15
  @conditions = options && options.delete(:conditions)
16
- @transformers = options && options.delete(:transformers)
17
- @paths = @router.splitter.split(@original_path, @requirements, @transformers).collect {|path| Path.new(self, path)}
16
+ @paths = @router.splitter.split(@original_path, @requirements).collect {|path| Path.new(self, path)}
18
17
  @primary_path = @paths.first
19
18
  #FIXME params is poorly named. this shouldn't be an array
20
19
  @params = []
@@ -1,14 +1,13 @@
1
1
  class Usher
2
2
  class Route
3
3
  class Variable
4
- attr_reader :type, :name, :validator, :transformer, :regex_matcher
4
+ attr_reader :type, :name, :validator, :regex_matcher
5
5
  attr_accessor :look_ahead, :globs_capture_separators
6
6
 
7
- def initialize(type, name, validator = nil, transformer = nil, regex_matcher = nil, globs_capture_separators = false)
7
+ def initialize(type, name, validator = nil, regex_matcher = nil, globs_capture_separators = false)
8
8
  @type = type
9
9
  @name = :"#{name}"
10
10
  @validator = validator
11
- @transformer = transformer
12
11
  @regex_matcher = regex_matcher
13
12
  @globs_capture_separators = globs_capture_separators
14
13
  end
@@ -17,19 +16,6 @@ class Usher
17
16
  "#{type}#{name}"
18
17
  end
19
18
 
20
- def transform!(val)
21
- return val unless @transformer
22
-
23
- case @transformer
24
- when Proc
25
- @transformer.call(val)
26
- when Symbol
27
- val.send(@transformer)
28
- end
29
- rescue Exception => e
30
- raise ValidationException.new("#{val} could not be successfully transformed by #{@transformer}, root cause #{e.inspect}")
31
- end
32
-
33
19
  def valid!(val)
34
20
  case @validator
35
21
  when Proc
@@ -19,27 +19,18 @@ class Usher
19
19
  def initialize(delimiters, split_regex, url_split_regex)
20
20
  @delimiters = delimiters
21
21
  @delimiter_chars = delimiters.collect{|d| d[0]}
22
+ @delimiter_chars_map = Hash[*@delimiter_chars.map{|c| [c, c.chr.to_sym]}.flatten]
22
23
  @split_regex = split_regex
23
24
  @url_split_regex = url_split_regex
24
25
  end
25
26
 
26
27
  def url_split(path)
27
- parts = []
28
- ss = StringScanner.new(path)
29
- while !ss.eos?
30
- if part = ss.scan(@url_split_regex)
31
- parts << case part[0]
32
- when *@delimiter_chars
33
- part.to_sym
34
- else
35
- part
36
- end
37
- end
38
- end if path && !path.empty?
28
+ parts = path.scan(@url_split_regex)
29
+ parts.map!{ |part| @delimiter_chars_map[part[0]] || part}
39
30
  parts
40
31
  end
41
32
 
42
- def split(path, requirements = nil, transformers = nil)
33
+ def split(path, requirements = nil)
43
34
  parts = Group.new(:all, nil)
44
35
  ss = StringScanner.new(path)
45
36
  current_group = parts
@@ -48,9 +39,9 @@ class Usher
48
39
  case part[0]
49
40
  when ?*, ?:
50
41
  type = part.slice!(0).chr.to_sym
51
- current_group << Usher::Route::Variable.new(type, part, requirements && requirements[part.to_sym], transformers && transformers[part.to_sym])
42
+ current_group << Usher::Route::Variable.new(type, part, requirements && requirements[part.to_sym])
52
43
  when ?{
53
- pattern = '^'
44
+ pattern = ''
54
45
  count = 1
55
46
  variable = ss.scan(/[:\*]([^,]+),/)
56
47
  until count.zero?
@@ -63,12 +54,12 @@ class Usher
63
54
  end
64
55
  pattern << regex_part
65
56
  end
66
- pattern[pattern.size - 1] = ?$
57
+ pattern.slice!(pattern.length - 1)
67
58
  regex = Regexp.new(pattern)
68
59
  if variable
69
60
  variable_type = variable.slice!(0).chr.to_sym
70
61
  variable_name = variable[0, variable.size - 1].to_sym
71
- current_group << Usher::Route::Variable.new(variable_type, variable_name, requirements && requirements[variable_name], transformers && transformers[variable_name], regex)
62
+ current_group << Usher::Route::Variable.new(variable_type, variable_name, requirements && requirements[variable_name], regex)
72
63
  else
73
64
  current_group << regex
74
65
  end
@@ -8,8 +8,6 @@ def build_email_mock(email)
8
8
  request
9
9
  end
10
10
 
11
- SampleController = Object.new
12
-
13
11
  describe "Usher (for email) route recognition" do
14
12
 
15
13
  before(:each) do
@@ -18,6 +18,11 @@ describe "Usher URL generation" do
18
18
  route_set.generate_url(:sample, {:action => 'action'}).should == '/sample/action'
19
19
  end
20
20
 
21
+ it "should generate a simple URL with a single variable (and escape)" do
22
+ route_set.add_named_route(:sample, '/sample/:action', :controller => 'sample')
23
+ route_set.generate_url(:sample, {:action => 'action time'}).should == '/sample/action%20time'
24
+ end
25
+
21
26
  it "should generate a simple URL with a single variable (thats not a string)" do
22
27
  route_set.add_named_route(:sample, '/sample/:action/:id', :controller => 'sample')
23
28
  route_set.generate_url(:sample, {:action => 'action', :id => 123}).should == '/sample/action/123'
@@ -18,8 +18,6 @@ def build_app_mock(params)
18
18
  request
19
19
  end
20
20
 
21
- SampleController = Object.new
22
-
23
21
  describe "Usher (for rack) route dispatching" do
24
22
 
25
23
  before(:each) do
@@ -10,8 +10,6 @@ def build_request(opts)
10
10
  request
11
11
  end
12
12
 
13
- SampleController = Object.new
14
-
15
13
  describe "Usher route recognition" do
16
14
 
17
15
  before(:each) do
@@ -83,6 +81,12 @@ describe "Usher route recognition" do
83
81
  route_set.recognize(build_request({:method => 'get', :path => '/test/part/hello/again/123/hello/again/onemore'})).params.should == [[:test, ['hello', 'again', '123', 'hello', 'again']]]
84
82
  end
85
83
 
84
+ it "should recgonize a regex glob variable terminated by a single regex variable" do
85
+ target_route = route_set.add_route('/test/part/{*test,^(hello|again|\d+)$}/{:party,onemore}')
86
+ route_set.recognize(build_request({:method => 'get', :path => '/test/part/hello/again/123/hello/again/onemore'})).path.route.should == target_route
87
+ route_set.recognize(build_request({:method => 'get', :path => '/test/part/hello/again/123/hello/again/onemore'})).params.should == [[:test, ['hello', 'again', '123', 'hello', 'again']], [:party, 'onemore']]
88
+ end
89
+
86
90
  it "should recgonize two glob-style variables separated by a static part" do
87
91
  target_route = route_set.add_route('/*format/innovate/*onemore')
88
92
  response = route_set.recognize(build_request({:method => 'get', :path => '/sample/html/innovate/apple'}))
@@ -143,11 +147,6 @@ describe "Usher route recognition" do
143
147
  www_product_show_route.should == route_set.recognize(build_request({:method => 'get', :path => '/products/show/123', :subdomains => ['www'], :user_agent => false})).path.route
144
148
  end
145
149
 
146
- it "should use a transformer (proc) on incoming variables" do
147
- route_set.add_route('/:controller/:action/:id', :transformers => {:id => proc{|v| v.to_i}})
148
- route_set.recognize(build_request({:method => 'get', :path => '/products/show/123asd', :domain => 'admin.host.com'})).params.rassoc(123).first.should == :id
149
- end
150
-
151
150
  it "should use a requirement (proc) on incoming variables" do
152
151
  route_set.add_route('/:controller/:action/:id', :id => proc{|v| Integer(v)})
153
152
  proc {route_set.recognize(build_request({:method => 'get', :path => '/products/show/123', :domain => 'admin.host.com'}))}.should_not raise_error Usher::ValidationException
@@ -164,19 +163,10 @@ describe "Usher route recognition" do
164
163
  route_set.recognize(build_request({:method => 'get', :path => '/testing/asd.qwe/testing2/poi.zxc/oiu.asd'})).params.should == [[:id, 'asd.qwe'], [:id2, 'poi.zxc'], [:id3, 'oiu.asd']]
165
164
  end
166
165
 
167
- it "should use a transformer (symbol) on incoming variables" do
168
- route_set.add_route('/:controller/:action/:id', :transformers => {:id => :to_i})
169
- route_set.recognize(build_request({:method => 'get', :path => '/products/show/123asd', :domain => 'admin.host.com'})).params.rassoc(123).first.should == :id
170
- end
171
-
172
166
  it "should should raise if malformed variables are used" do
173
167
  route_set.add_route('/products/show/:id', :id => /\d+/, :conditions => {:method => 'get'})
174
168
  proc {route_set.recognize(build_request({:method => 'get', :path => '/products/show/qweasd', :domain => 'admin.host.com'}))}.should raise_error
175
169
  end
176
170
 
177
- it "should should raise if transformer proc raises (anything)" do
178
- route_set.add_route('/products/show/:id', :transformers => {:id => proc{|v| Integer(v)}})
179
- proc {route_set.recognize(build_request({:method => 'get', :path => '/products/show/qweasd', :domain => 'admin.host.com'}))}.should raise_error(Usher::ValidationException)
180
- end
181
171
 
182
172
  end
@@ -9,7 +9,7 @@ describe "Usher route tokenizing" do
9
9
 
10
10
  it "should split / delimited routes with a regex in it" do
11
11
  Usher::Splitter.for_delimiters(['/', '.'], '[0-9A-Za-z\$\-_\+!\*\',]+').
12
- split('/test/{this}/split').should == [[:/, 'test', :/, /^this$/, :/, 'split']]
12
+ split('/test/{this}/split').should == [[:/, 'test', :/, /this/, :/, 'split']]
13
13
  end
14
14
 
15
15
  it "should split on ' ' delimited routes as well" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: joshbuddy-usher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Hull
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-11 00:00:00 -07:00
12
+ date: 2009-05-15 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency