usher 0.5.10 → 0.5.11
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/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
|