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 +2 -1
- data/lib/usher.rb +8 -6
- data/lib/usher/delimiters.rb +22 -0
- data/lib/usher/interface/rails2_3_interface.rb +7 -4
- data/lib/usher/node.rb +5 -5
- data/lib/usher/route.rb +18 -5
- data/lib/usher/spinoffs/strscan_additions.rb +31 -0
- data/lib/usher/splitter.rb +30 -8
- data/lib/usher/util/generate.rb +12 -2
- data/lib/usher/util/parser.rb +24 -13
- data/lib/usher/util/rack-mixins.rb +1 -1
- data/spec/private/delimiters_spec.rb +48 -0
- data/spec/private/generate_spec.rb +27 -0
- data/spec/private/parser_spec.rb +28 -1
- data/spec/private/recognize_spec.rb +38 -4
- data/spec/private/splitter_spec.rb +40 -0
- data/spec/private/string_scanner_spec.rb +39 -0
- metadata +10 -2
data/VERSION.yml
CHANGED
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, :
|
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
|
54
|
-
|
55
|
-
self.
|
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
|
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
|
-
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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
|
data/lib/usher/splitter.rb
CHANGED
@@ -1,22 +1,44 @@
|
|
1
|
-
require 'strscan'
|
2
|
-
|
3
1
|
class Usher
|
4
2
|
class Splitter
|
5
|
-
|
6
|
-
def self.for_delimiters(
|
7
|
-
|
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
|
11
|
+
class SingleCharacterSplitterInstance
|
11
12
|
|
12
|
-
def initialize(
|
13
|
-
@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
|
data/lib/usher/util/generate.rb
CHANGED
@@ -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 << '://'
|
data/lib/usher/util/parser.rb
CHANGED
@@ -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.
|
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]
|
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
|
-
|
82
|
+
scanner = StringScanner.new(path)
|
83
|
+
|
84
84
|
current_group = parts
|
85
|
-
|
86
|
-
|
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 =
|
107
|
+
variable = scanner.scan(/[!:\*]([^,]+),/)
|
98
108
|
until count.zero?
|
99
|
-
regex_part =
|
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
|
-
|
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
|
@@ -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
|
data/spec/private/parser_spec.rb
CHANGED
@@ -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
|
-
|
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.
|
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-
|
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
|