joshbuddy-usher 0.4.2 → 0.4.3

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