usher 0.5.10 → 0.5.11

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  ---
2
- :patch: 10
2
+ :build:
3
+ :patch: 11
3
4
  :major: 0
4
5
  :minor: 5
data/lib/usher.rb CHANGED
@@ -5,10 +5,12 @@ require File.join(File.dirname(__FILE__), 'usher', 'interface')
5
5
  require File.join(File.dirname(__FILE__), 'usher', 'splitter')
6
6
  require File.join(File.dirname(__FILE__), 'usher', 'exceptions')
7
7
  require File.join(File.dirname(__FILE__), 'usher', 'util')
8
+ require File.join(File.dirname(__FILE__), 'usher', 'spinoffs', 'strscan_additions')
9
+ require File.join(File.dirname(__FILE__), 'usher', 'delimiters')
8
10
 
9
11
  class Usher
10
12
  attr_reader :root, :named_routes, :routes, :splitter,
11
- :delimiters, :delimiter_chars, :delimiters_regex,
13
+ :delimiters, :delimiters_regex,
12
14
  :parent_route, :generator, :grapher
13
15
 
14
16
  # Returns whether the route set is empty
@@ -50,9 +52,10 @@ class Usher
50
52
  # <tt>:request_methods</tt>: Array of Symbols. (default <tt>[:protocol, :domain, :port, :query_string, :remote_ip, :user_agent, :referer, :method, :subdomains]</tt>)
51
53
  # Array of methods called against the request object for the purposes of matching route requirements.
52
54
  def initialize(options = nil)
53
- self.generator = options && options.delete(:generator)
54
- self.delimiters = options && options.delete(:delimiters) || ['/', '.']
55
- self.valid_regex = options && options.delete(:valid_regex) || '[0-9A-Za-z\$\-_\+!\*\',]+'
55
+ self.generator = options && options.delete(:generator)
56
+ delimiters_array = options && options.delete(:delimiters) || ['/', '.']
57
+ self.delimiters = Delimiters.new(delimiters_array)
58
+ self.valid_regex = options && options.delete(:valid_regex) || '[0-9A-Za-z\$\-_\+!\*\',]+'
56
59
  self.request_methods = options && options.delete(:request_methods)
57
60
  reset!
58
61
  end
@@ -258,14 +261,13 @@ class Usher
258
261
 
259
262
  def delimiters=(delimiters)
260
263
  @delimiters = delimiters
261
- @delimiter_chars = @delimiters.collect{|d| d[0]}
262
264
  @delimiters_regex = @delimiters.collect{|d| Regexp.quote(d)} * '|'
263
265
  @delimiters
264
266
  end
265
267
 
266
268
  def valid_regex=(valid_regex)
267
269
  @valid_regex = valid_regex
268
- @splitter = Splitter.for_delimiters(self, @valid_regex)
270
+ @splitter = Splitter.for_delimiters(self.delimiters)
269
271
  @valid_regex
270
272
  end
271
273
 
@@ -0,0 +1,22 @@
1
+ class Delimiters < Array
2
+ # TODO: caching
3
+
4
+ def unescaped
5
+ self.map do |delimiter|
6
+ (delimiter[0] == ?\\) ?
7
+ delimiter[1..-1] :
8
+ delimiter
9
+ end
10
+ end
11
+
12
+ def first_in(array)
13
+ # TODO: should we optimize this O(n*m)? hash or modified or KNP or at leaset sort + b-search. But they are so short
14
+
15
+ array.each do |element|
16
+ return element if self.unescaped.any? { |delimiter| delimiter == element }
17
+ end
18
+ nil
19
+ end
20
+
21
+ # TODO: Delimiters#regex and so on
22
+ end
@@ -71,16 +71,19 @@ class Usher
71
71
  "#{request.path_parameters[:controller].camelize}Controller".constantize
72
72
  end
73
73
 
74
- def reset!
75
- @router = Usher.new(:generator => Usher::Util::Generators::URL.new, :request_methods => [:protocol, :domain, :port, :query_string, :remote_ip, :user_agent, :referer, :method, :subdomains])
74
+ def reset!(options={})
75
+ options[:generator] = options[:generator] || Usher::Util::Generators::URL.new
76
+ options[:request_methods] = options[:request_methods] || [:protocol, :domain, :port, :query_string, :remote_ip, :user_agent, :referer, :method, :subdomains]
77
+
78
+ @router = Usher.new(options)
76
79
  @configuration_files = []
77
80
  @module ||= Module.new
78
81
  @controller_route_added = false
79
82
  @controller_action_route_added = false
80
83
  end
81
84
 
82
- def draw
83
- reset!
85
+ def draw(options={})
86
+ reset!(options)
84
87
  yield ActionController::Routing::RouteSet::Mapper.new(self)
85
88
  install_helpers
86
89
  end
data/lib/usher/node.rb CHANGED
@@ -61,7 +61,7 @@ class Usher
61
61
  end
62
62
 
63
63
  def terminates?
64
- @terminates
64
+ @terminates && @terminates.route.recognizable?
65
65
  end
66
66
 
67
67
  def pp
@@ -128,15 +128,15 @@ class Usher
128
128
  when Route::Variable::Glob
129
129
  params << [next_part.value.name, []] unless params.last && params.last.first == next_part.value.name
130
130
  while true
131
- if (next_part.value.look_ahead === part || (!usher.delimiter_chars.include?(part[0]) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part)))
131
+ if (next_part.value.look_ahead === part || (!usher.delimiters.unescaped.include?(part) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part)))
132
132
  path.unshift(part)
133
133
  position -= part.size
134
- if usher.delimiter_chars.include?(next_part.parent.value[0])
134
+ if usher.delimiters.unescaped.include?(next_part.parent.value)
135
135
  path.unshift(next_part.parent.value)
136
136
  position -= next_part.parent.value.size
137
137
  end
138
138
  break
139
- elsif !usher.delimiter_chars.include?(part[0])
139
+ elsif !usher.delimiters.unescaped.include?(part)
140
140
  next_part.value.valid!(part)
141
141
  params.last.last << part
142
142
  end
@@ -154,7 +154,7 @@ class Usher
154
154
  next_path_part = path.shift
155
155
  position += next_path_part.size
156
156
  params.last.last << next_path_part
157
- end if var.look_ahead && usher.delimiter_chars.size > 1
157
+ end if var.look_ahead && usher.delimiters.size > 1
158
158
  end
159
159
  next_part.find(usher, request_object, original_path, path, params, position)
160
160
  elsif request_method_type
data/lib/usher/route.rb CHANGED
@@ -5,16 +5,15 @@ require File.join(File.dirname(__FILE__), 'route', 'request_method')
5
5
 
6
6
  class Usher
7
7
  class Route
8
- attr_reader :paths, :requirements, :conditions,
9
- :destination, :named, :generate_with,
10
- :default_values, :match_partially
11
- attr_accessor :parent_route, :router
8
+ attr_reader :paths, :requirements, :conditions, :named, :generate_with, :default_values, :match_partially, :destination
9
+ attr_accessor :parent_route, :router, :recognizable
12
10
 
13
11
  GenerateWith = Struct.new(:scheme, :port, :host)
14
12
 
15
13
  def initialize(parsed_paths, router, conditions, requirements, default_values, generate_with, match_partially)
16
- @paths = parsed_paths.collect {|path| Path.new(self, path)}
17
14
  @router, @requirements, @conditions, @default_values, @match_partially = router, requirements, conditions, default_values, match_partially
15
+ @recognizable = true
16
+ @paths = parsed_paths.collect {|path| Path.new(self, path)}
18
17
  @generate_with = GenerateWith.new(generate_with[:scheme], generate_with[:port], generate_with[:host]) if generate_with
19
18
  end
20
19
 
@@ -25,7 +24,21 @@ class Usher
25
24
  end
26
25
  @grapher
27
26
  end
27
+
28
+ def unrecognizable!
29
+ self.recognizable = false
30
+ self
31
+ end
28
32
 
33
+ def recognizable!
34
+ self.recognizable = true
35
+ self
36
+ end
37
+
38
+ def recognizable?
39
+ self.recognizable
40
+ end
41
+
29
42
  def dup
30
43
  result = super
31
44
  result.instance_eval do
@@ -0,0 +1,31 @@
1
+ require 'strscan'
2
+
3
+ #TODO: rewrite this in C and commit this addition back to community
4
+ class StringScanner
5
+ # scan_before(pattern)
6
+ #
7
+ #
8
+ # Scans the string until the +pattern+ is matched. As opposed to #scan_until,
9
+ # it does not include a matching pattern into a returning value and sets
10
+ # pointer just _before_ the pattern position.
11
+ # If there is no match, +nil+ is returned.
12
+ #
13
+ # s = StringScanner.new("Fri Dec 12 1975 14:39")
14
+ # s.scan_until(/1/) # -> "Fri Dec "
15
+ # s.scan(/1/) # -> "1"
16
+ # s.scan_until(/1/) # -> nil
17
+ #
18
+ def scan_before(pattern)
19
+ return nil unless self.exist?(pattern)
20
+
21
+ pattern_size = self.matched_size
22
+ result = self.scan_until(pattern)
23
+
24
+ self.pos = self.pos - pattern_size
25
+ (result.length == pattern_size) ?
26
+ (result = '') :
27
+ (result = result[0..(result.length - pattern_size - 1)])
28
+
29
+ result
30
+ end
31
+ end
@@ -1,22 +1,44 @@
1
- require 'strscan'
2
-
3
1
  class Usher
4
2
  class Splitter
5
-
6
- def self.for_delimiters(router, valid_regex)
7
- SplitterInstance.new(Regexp.new("[#{router.delimiters.collect{|d| Regexp.quote(d)}.join}]|[^#{router.delimiters.collect{|d| Regexp.quote(d)}.join}]+"))
3
+
4
+ def self.for_delimiters(delimiters_array)
5
+ delimiters = Delimiters.new(delimiters_array)
6
+ delimiters_array.any?{|d| d.size > 1} ?
7
+ MultiCharacterSplitterInstance.new(delimiters) :
8
+ SingleCharacterSplitterInstance.new(delimiters)
8
9
  end
9
10
 
10
- class SplitterInstance
11
+ class SingleCharacterSplitterInstance
11
12
 
12
- def initialize(url_split_regex)
13
- @url_split_regex = url_split_regex
13
+ def initialize(delimiters)
14
+ @url_split_regex = Regexp.new("[#{delimiters.collect{|d| Regexp.quote(d)}.join}]|[^#{delimiters.collect{|d| Regexp.quote(d)}.join}]+")
14
15
  end
15
16
 
16
17
  def url_split(path)
17
18
  path.scan(@url_split_regex)
18
19
  end
20
+ alias split url_split
19
21
  end
20
22
 
23
+ class MultiCharacterSplitterInstance
24
+
25
+ def initialize(delimiters)
26
+ @delimiters = delimiters
27
+ end
28
+
29
+ def url_split(path)
30
+ split_path = path.split(delimiters_regexp)
31
+ split_path.reject!{|s| s.size.zero? }
32
+ split_path
33
+ end
34
+ alias split url_split
35
+
36
+ protected
37
+
38
+ def delimiters_regexp
39
+ Regexp.new("(#{@delimiters.unescaped.collect{|d| Regexp.quote(d)}.join('|')})")
40
+ end
41
+
42
+ end
21
43
  end
22
44
  end
@@ -59,7 +59,7 @@ class Usher
59
59
  generate_path(path_for_routing_lookup(routing_lookup, params), params)
60
60
  end
61
61
 
62
- def generate_path(path, params = nil)
62
+ def generate_path(path, params = nil, generate_extra = true)
63
63
  params = Array(params) if params.is_a?(String)
64
64
  if params.is_a?(Array)
65
65
  given_size = params.size
@@ -69,7 +69,7 @@ class Usher
69
69
  end
70
70
 
71
71
  result = Rack::Utils.uri_escape(generate_path_for_base_params(path, params))
72
- unless params.nil? || params.empty?
72
+ unless !generate_extra || params.nil? || params.empty?
73
73
  extra_params = generate_extra_params(params, result[??])
74
74
  result << extra_params
75
75
  end
@@ -117,6 +117,16 @@ class Usher
117
117
  end
118
118
  end
119
119
 
120
+ def generate_base_url(params = nil)
121
+ if usher.parent_route
122
+ usher.parent_route.router.generator.generate_path(usher.parent_route.paths.first, params, false)
123
+ elsif params && params.key?(:default)
124
+ params[:default].to_s
125
+ else
126
+ '/'
127
+ end
128
+ end
129
+
120
130
  def generate_start(path, request)
121
131
  result = (path.route.generate_with && path.route.generate_with.scheme || request.scheme).dup
122
132
  result << '://'
@@ -12,10 +12,10 @@ class Usher
12
12
  end
13
13
 
14
14
  class ParserInstance
15
-
16
15
  def initialize(router, split_regex)
17
16
  @router = router
18
17
  @split_regex = split_regex
18
+ @delimiters_regex = Regexp.new(router.delimiters_regex)
19
19
  end
20
20
 
21
21
  def generate_route(unprocessed_path, conditions, requirements, default_values, generate_with)
@@ -48,14 +48,14 @@ class Usher
48
48
  part.look_ahead = nil
49
49
  part.look_ahead_priority = true
50
50
  else
51
- part.look_ahead = path[index + 1, path.size].find{|p| !p.is_a?(Usher::Route::Variable) && !router.delimiter_chars.include?(p[0])} || nil
51
+ part.look_ahead = path[index + 1, path.size].find{|p| !p.is_a?(Usher::Route::Variable) && !router.delimiters.unescaped.include?(p)} || nil
52
52
  end
53
53
  when Usher::Route::Variable
54
54
  if part.look_ahead && !part.look_ahead_priority
55
55
  part.look_ahead = nil
56
56
  part.look_ahead_priority = true
57
57
  else
58
- part.look_ahead = path[index + 1, path.size].find{|p| router.delimiter_chars.include?(p[0])} || router.delimiters.first
58
+ part.look_ahead = router.delimiters.first_in(path[index + 1, path.size]) || router.delimiters.unescaped.first
59
59
  end
60
60
  end
61
61
  end
@@ -73,17 +73,27 @@ class Usher
73
73
 
74
74
  end
75
75
 
76
-
77
76
  def parse_and_expand(path, requirements = nil, default_values = nil)
78
77
  Usher::Route::Util.expand_path(parse(path, requirements, default_values))
79
78
  end
80
79
 
81
80
  def parse(path, requirements = nil, default_values = nil)
82
81
  parts = Usher::Route::Util::Group.new(:all, nil)
83
- ss = StringScanner.new(path)
82
+ scanner = StringScanner.new(path)
83
+
84
84
  current_group = parts
85
- while !ss.eos?
86
- part = ss.scan(@split_regex)
85
+ part = nil
86
+ while !scanner.eos?
87
+ part ?
88
+ (part << scanner.scan(@split_regex)) :
89
+ (part = scanner.scan(@split_regex))
90
+
91
+ if scanner.match?(/\\/) and !scanner.match?(@delimiters_regex)
92
+ scanner.skip(/\\/)
93
+ part << scanner.getch
94
+ next
95
+ end
96
+
87
97
  case part[0]
88
98
  when ?*
89
99
  var_name = part[1, part.size - 1].to_sym
@@ -94,9 +104,9 @@ class Usher
94
104
  when ?{
95
105
  pattern = ''
96
106
  count = 1
97
- variable = ss.scan(/[!:\*]([^,]+),/)
107
+ variable = scanner.scan(/[!:\*]([^,]+),/)
98
108
  until count.zero?
99
- regex_part = ss.scan(/\{|\}|[^\{\}]+/)
109
+ regex_part = scanner.scan(/\{|\}|[^\{\}]+/)
100
110
  case regex_part[0]
101
111
  when ?{
102
112
  count += 1
@@ -137,19 +147,20 @@ class Usher
137
147
  end
138
148
  current_group.parent << Usher::Route::Util::Group.new(:all, current_group.parent)
139
149
  current_group = current_group.parent.last
150
+ when ?\\
151
+ current_group << part[1..-1]
140
152
  else
141
153
  current_group << part
142
154
  end
155
+ part = nil
143
156
  end unless !path || path.empty?
144
157
  parts
145
158
  end
146
159
 
147
- private
148
- attr_reader :router
160
+ private
149
161
 
162
+ attr_reader :router
150
163
  end
151
-
152
-
153
164
  end
154
165
  end
155
166
  end
@@ -8,7 +8,7 @@ unless Rack::Utils.respond_to?(:uri_escape)
8
8
  def uri_escape(s)
9
9
  s.to_s.gsub(/([^:\/?\[\]\-_~\.!\$&'\(\)\*\+,;=@a-zA-Z0-9]+)/n) {
10
10
  '%'<<$1.unpack('H2'*$1.size).join('%').upcase
11
- }.tr(' ', '+')
11
+ }
12
12
  end
13
13
  module_function :uri_escape
14
14
 
@@ -0,0 +1,48 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+ require 'usher'
3
+
4
+ describe Delimiters do
5
+ describe "#unescaped" do
6
+ it "should unescape delimiters correctly" do
7
+ Delimiters.new(['/', '\)', '\\\\']).unescaped.should == ['/', ')', '\\']
8
+ end
9
+ end
10
+
11
+ describe "#first_in" do
12
+ describe "when there is a complex path with a lot of delimiters occurrences" do
13
+ before :each do
14
+ @delimiters = Delimiters.new ['@', '.', '/']
15
+ @paths = ['var', '.', 'var', '/', 'var', '@']
16
+ end
17
+
18
+ it "should find nearest delimiter correctly" do
19
+ @delimiters.first_in(@paths).should == '.'
20
+ @delimiters.first_in(@paths[2..-1]).should == '/'
21
+ @delimiters.first_in(@paths[4..-1]).should == '@'
22
+ end
23
+ end
24
+
25
+ describe "when there are delimiters with escaped charaters" do
26
+ before :each do
27
+ @delimiters = Delimiters.new ['\\(', '\\)']
28
+ @paths = ['var', '(', 'var', ')']
29
+ end
30
+
31
+ it "should find nearest delimiter in unescaped path" do
32
+ @delimiters.first_in(@paths).should == '('
33
+ end
34
+ end
35
+
36
+ describe "when there is no occurence of delimiters in path" do
37
+ before :each do
38
+ @delimiters = Delimiters.new ['-', '/']
39
+ @paths = ['e', '@', 'ma', '.', 'il']
40
+ end
41
+
42
+ it "should return nil" do
43
+ @delimiters.first_in(@paths).should be_nil
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -189,6 +189,33 @@ describe "Usher URL generation" do
189
189
  @route_set4.generator.generate(:nested_simple)
190
190
  end.should raise_error(Usher::MissingParameterException)
191
191
  end
192
+
193
+ describe "generate_base_url" do
194
+ it "should generate a base url for a non nested router" do
195
+ @route_set.generator.generate_base_url.should == "/"
196
+ end
197
+
198
+ it "should generate a base url for a nested router" do
199
+ @route_set2.generator.generate_base_url.should == "/mount_point"
200
+ end
201
+
202
+ it "should generate a base url with parameters" do
203
+ @route_set4.generator.generate_base_url(:bar => "the_bar").should == "/fourth/the_bar"
204
+ end
205
+
206
+ it "should generate a base url with a default route" do
207
+ @route_set.generator.generate_base_url(:default => "/foo").should == "/foo"
208
+ end
209
+
210
+ it "should generate a base url with a default that is not a /" do
211
+ @route_set.generator.generate_base_url(:default => ":").should == ":"
212
+ end
213
+
214
+ it "should generate a base url with a default of a blank string" do
215
+ @route_set.generator.generate_base_url(:default => "").should == ""
216
+ @route_set.generator.generate_base_url(:default => nil).should == ""
217
+ end
218
+ end
192
219
  end
193
220
 
194
221
  describe "dupped generation" do
@@ -23,6 +23,10 @@ describe "Usher route tokenizing" do
23
23
  it "should split on ' ' delimited routes for more complex routes as well" do
24
24
  Usher.new(:delimiters => [' '], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('(test|this) split').should == [['test', ' ', 'split'], ['this', ' ', 'split']]
25
25
  end
26
+
27
+ it "should correctly handle multichar delimiters as well" do
28
+ Usher.new(:delimiters => ['%28', '%29'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('cheese%28parmesan%29').should == [['cheese', '%28', 'parmesan', '%29']]
29
+ end
26
30
 
27
31
  it "should group optional parts with brackets" do
28
32
  Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/test/this(/split)').should == [
@@ -73,4 +77,27 @@ describe "Usher route tokenizing" do
73
77
  parts[1].should == parts[3]
74
78
  end
75
79
 
76
- end
80
+ it "should let me escape reserved characters" do
81
+ Usher.new.parser.parse_and_expand('/my\/thing/is\*lovingyou').should == [["/", "my/thing", "/", "is*lovingyou"]]
82
+ end
83
+
84
+ it "should let me use escaped characters as delimiters" do
85
+ Usher.new(:delimiters => ['/', '\(', '\)']).parser.parse_and_expand('/cheese\(:kind\)').should == [['/', 'cheese', '(', Usher::Route::Variable::Single.new(:kind), ')']]
86
+ end
87
+
88
+ describe "#generate_route" do
89
+ describe "when delimiters contain escaped characters" do
90
+ before :each do
91
+ @parser = Usher.new(:delimiters => ['/', '\(', '\)']).parser
92
+ end
93
+
94
+ it "should correctly generate route with a variable" do
95
+ route = @parser.generate_route('/cheese\(:kind\)', nil, nil, nil, nil)
96
+ variable = route.paths[0].parts[3]
97
+
98
+ variable.should be_kind_of(Usher::Route::Variable::Single)
99
+ variable.look_ahead.should == ')'
100
+ end
101
+ end
102
+ end
103
+ end
@@ -17,6 +17,11 @@ describe "Usher route recognition" do
17
17
 
18
18
  describe 'request conditions' do
19
19
 
20
+ it "should ignore an unrecognized route" do
21
+ target_route = @route_set.add_route('/sample', :controller => 'sample', :action => 'action', :conditions => {:protocol => 'http'}).unrecognizable!
22
+ @route_set.recognize(build_request({:method => 'get', :path => '/sample', :protocol => 'http'})).should be_nil
23
+ end
24
+
20
25
  it "should recognize a specific domain name" do
21
26
  target_route = @route_set.add_route('/sample', :controller => 'sample', :action => 'action', :conditions => {:protocol => 'http'})
22
27
  @route_set.add_route('/sample', :controller => 'sample', :action => 'action2', :conditions => {:protocol => 'https'})
@@ -79,6 +84,35 @@ describe "Usher route recognition" do
79
84
  @route_set.recognize(build_request({:method => 'get', :path => '/sample/html/json/apple'})).params.should == [[:format, ['html', 'json', 'apple']]]
80
85
  end
81
86
 
87
+ it "should recognize variables between multi-char delimiters" do
88
+ @route_set = Usher.new(:delimiters => ['%28', '%29', '/', '.'])
89
+ target_route = @route_set.add_route('/cheese%28:kind%29', :controller => 'sample', :action => 'action')
90
+
91
+ response = @route_set.recognize(build_request({:method => 'get', :path => '/cheese%28parmesan%29'}))
92
+ response.path.route.should == target_route
93
+ response.params.should == [[:kind , 'parmesan']]
94
+ end
95
+
96
+ it "should recognize route with escaped characters as delimiters" do
97
+ @route_set = Usher.new(:delimiters => ['/', '.', '\\(', '\\)'])
98
+
99
+ target_route = @route_set.add_route('/cheese\\(:kind\\)', :controller => 'sample', :action => 'action')
100
+
101
+ response = @route_set.recognize(build_request({:method => 'get', :path => '/cheese(parmesan)'}))
102
+ response.should_not be_nil
103
+ response.path.route.should == target_route
104
+ response.params.should == [[:kind , 'parmesan']]
105
+ end
106
+
107
+ it "should recognize route with consecutive delimiters" do
108
+ @route_set = Usher.new(:delimiters => ['!', '/'])
109
+ target_route = @route_set.add_route('/cheese/!:kind', :controller => 'sample', :action => 'action')
110
+
111
+ response = @route_set.recognize(build_request({:method => 'get', :path => '/cheese/!parmesan'}))
112
+ response.path.route.should == target_route
113
+ response.params.should == [[:kind , 'parmesan']]
114
+ end
115
+
82
116
  it "should recgonize only a glob-style variable" do
83
117
  target_route = @route_set.add_route('/*format')
84
118
  response = @route_set.recognize(build_request({:method => 'get', :path => '/sample/html/json/apple'}))
@@ -94,10 +128,10 @@ describe "Usher route recognition" do
94
128
  end
95
129
 
96
130
  it "should recgonize a two identical regex static parts distinguished by request methods" do
97
- get_route = @route_set.add_route('/{:val,test}', :conditions => {:method => 'get'})
98
- post_route = @route_set.add_route('/{:val,test}', :conditions => {:method => 'post'})
99
- @route_set.recognize(build_request({:method => 'get', :path => '/test'})).path.route.should == get_route
100
- @route_set.recognize(build_request({:method => 'post', :path => '/test'})).path.route.should == post_route
131
+ get_route = @route_set.add_route('/test1/{:val,test}', :conditions => {:method => 'get'})
132
+ post_route = @route_set.add_route('/test1/{:val,test}', :conditions => {:method => 'post'})
133
+ @route_set.recognize(build_request({:method => 'get', :path => '/test1/test'})).path.route.should == get_route
134
+ @route_set.recognize(build_request({:method => 'post', :path => '/test1/test'})).path.route.should == post_route
101
135
  end
102
136
 
103
137
  it "shouldn't accept a nil variable" do
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+ require "usher"
3
+
4
+ describe Usher::Splitter, "#split" do
5
+ describe "when there are single-character delimiters" do
6
+ it "should split correctly" do
7
+ Usher::Splitter.for_delimiters(['.', '/']).split('/one/two.three/').should == ['/', 'one', '/', 'two', '.', 'three', '/']
8
+ end
9
+ end
10
+
11
+ describe "when there are multi-character delimiters" do
12
+ it "should split correctly" do
13
+ Usher::Splitter.for_delimiters(['/', '%28', '%29']).split('/one%28two%29three/').should == ['/', 'one', '%28', 'two', '%29', 'three', '/']
14
+ end
15
+ end
16
+
17
+ describe "when there is no delimiter in the end" do
18
+ it "should split correctly" do
19
+ Usher::Splitter.for_delimiters(['.', '/']).split('/one/two.three').should == ['/', 'one', '/', 'two', '.', 'three']
20
+ end
21
+ end
22
+
23
+ describe "when there is no delimiter in the beginning" do
24
+ it "should split correctly" do
25
+ Usher::Splitter.for_delimiters(['.', '/']).split('one/two.three/').should == ['one', '/', 'two', '.', 'three', '/']
26
+ end
27
+ end
28
+
29
+ describe "when delimiters are consecutive" do
30
+ it "should split correctly" do
31
+ Usher::Splitter.for_delimiters(['/', '!']).split('/cheese/!parmesan').should == ['/', 'cheese', '/', '!', 'parmesan']
32
+ end
33
+ end
34
+
35
+ describe "when delimiters contain escaped characters" do
36
+ it "should split correctly" do
37
+ Usher::Splitter.for_delimiters(['/', '\(', '\)']).split('/cheese(parmesan)').should == ['/', 'cheese', '(', 'parmesan', ')']
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
+ require "usher"
3
+
4
+ describe StringScanner do
5
+ describe "#scan_before" do
6
+ before :each do
7
+ @scanner = StringScanner.new("/one/two..three")
8
+ end
9
+
10
+ describe "when there is a match" do
11
+ it "should return subsequent string without matching pattern in the end" do
12
+ @scanner.scan_before(/\.\./).should == "/one/two"
13
+ end
14
+
15
+ it "should set pointer right before the matching pattern" do
16
+ @scanner.scan_before(/\.\./)
17
+ @scanner.scan(/\.\./).should == '..'
18
+ end
19
+
20
+ describe "when matching pattern is right at the position" do
21
+ it "should return empty string" do
22
+ @scanner.scan_before(/\//).should == ''
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "when there is no match" do
28
+ it "should return nil" do
29
+ @scanner.scan_before(/bla-bla-bla/).should == nil
30
+ end
31
+
32
+ it "should not move the pointer" do
33
+ @scanner.scan_before(/bla-bla-bla/)
34
+ @scanner.pos.should == 0
35
+ end
36
+ end
37
+ end
38
+ end
39
+
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.5.10
4
+ version: 0.5.11
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-10-11 00:00:00 -04:00
12
+ date: 2009-11-20 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -37,6 +37,7 @@ files:
37
37
  - Rakefile
38
38
  - VERSION.yml
39
39
  - lib/usher.rb
40
+ - lib/usher/delimiters.rb
40
41
  - lib/usher/exceptions.rb
41
42
  - lib/usher/grapher.rb
42
43
  - lib/usher/interface.rb
@@ -56,6 +57,7 @@ files:
56
57
  - lib/usher/route/request_method.rb
57
58
  - lib/usher/route/util.rb
58
59
  - lib/usher/route/variable.rb
60
+ - lib/usher/spinoffs/strscan_additions.rb
59
61
  - lib/usher/splitter.rb
60
62
  - lib/usher/util.rb
61
63
  - lib/usher/util/generate.rb
@@ -63,6 +65,7 @@ files:
63
65
  - lib/usher/util/parser.rb
64
66
  - lib/usher/util/rack-mixins.rb
65
67
  - rails/init.rb
68
+ - spec/private/delimiters_spec.rb
66
69
  - spec/private/email/recognize_spec.rb
67
70
  - spec/private/generate_spec.rb
68
71
  - spec/private/grapher_spec.rb
@@ -80,6 +83,8 @@ files:
80
83
  - spec/private/rails2_3/recognize_spec.rb
81
84
  - spec/private/recognize_spec.rb
82
85
  - spec/private/request_method_spec.rb
86
+ - spec/private/splitter_spec.rb
87
+ - spec/private/string_scanner_spec.rb
83
88
  - spec/spec.opts
84
89
  - spec/spec_helper.rb
85
90
  has_rdoc: true
@@ -111,6 +116,7 @@ signing_key:
111
116
  specification_version: 3
112
117
  summary: A general purpose routing library
113
118
  test_files:
119
+ - spec/private/delimiters_spec.rb
114
120
  - spec/private/email/recognize_spec.rb
115
121
  - spec/private/generate_spec.rb
116
122
  - spec/private/grapher_spec.rb
@@ -128,4 +134,6 @@ test_files:
128
134
  - spec/private/rails2_3/recognize_spec.rb
129
135
  - spec/private/recognize_spec.rb
130
136
  - spec/private/request_method_spec.rb
137
+ - spec/private/splitter_spec.rb
138
+ - spec/private/string_scanner_spec.rb
131
139
  - spec/spec_helper.rb