usher 0.5.13 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -42,8 +42,17 @@ class Usher
42
42
  @dynamic
43
43
  end
44
44
 
45
- def can_generate_from?(keys)
46
- (dynamic_required_keys - keys).size.zero?
45
+ def can_generate_from_keys?(keys)
46
+ if dynamic?
47
+ (dynamic_required_keys - keys).size.zero? ? keys : nil
48
+ end
49
+ end
50
+
51
+ def can_generate_from_params?(params)
52
+ if route.router.consider_destination_keys?
53
+ route.destination.to_a - params.to_a
54
+ (route.destination.to_a - params.to_a).size.zero?
55
+ end
47
56
  end
48
57
 
49
58
  # Merges paths for use in generation
@@ -1,7 +1,7 @@
1
1
  class Usher
2
2
  class Route
3
3
  class Static
4
- class Greedy < String
4
+ class Greedy < Regexp
5
5
 
6
6
  end
7
7
  end
@@ -117,9 +117,11 @@ class Usher
117
117
  params.merge!(extra_params) if extra_params
118
118
  end
119
119
 
120
-
121
120
  result = Rack::Utils.uri_escape(generate_path_for_base_params(path, params))
122
121
  unless !generate_extra || params.nil? || params.empty?
122
+ if usher.consider_destination_keys? && path.route.destination_keys
123
+ params.delete_if{|k, v| path.route.destination_keys.include?(k)}
124
+ end
123
125
  extra_params = generate_extra_params(params, result[??])
124
126
  result << extra_params
125
127
  end
@@ -144,8 +146,8 @@ class Usher
144
146
 
145
147
  @generation_module.module_eval <<-END_EVAL
146
148
  def respond_to?(method_name)
147
- if match = Regexp.new('^(.*?)_(path|url)$').match(method_name.to_s)
148
- @@generator.usher.named_routes.key?(match.group(1))
149
+ if method_name =~ /^(.*?)_(path|url)$/
150
+ @@generator.usher.named_routes.key?($1)
149
151
  else
150
152
  super
151
153
  end
@@ -184,7 +186,7 @@ class Usher
184
186
  (url[-1] == ?/) ? url[0..-2] : url
185
187
  end
186
188
 
187
- def path_for_routing_lookup(routing_lookup, params = {})
189
+ def path_for_routing_lookup(routing_lookup, params = {})
188
190
  path = case routing_lookup
189
191
  when Symbol
190
192
  route = @usher.named_routes[routing_lookup]
@@ -4,170 +4,161 @@ class Usher
4
4
  module Util
5
5
  class Parser
6
6
 
7
+ attr_reader :router
8
+
7
9
  def self.for_delimiters(router, valid_regex)
8
- ParserInstance.new(
10
+ new(
9
11
  router,
10
12
  Regexp.new('((:|\*)?' + valid_regex + '|' + router.delimiters_regex + '|\(|\)|\||\{)')
11
13
  )
12
14
  end
13
15
 
14
- class ParserInstance
15
- def initialize(router, split_regex)
16
- @router = router
17
- @split_regex = split_regex
18
- @delimiters_regex = Regexp.new(router.delimiters_regex)
19
- end
16
+ def initialize(router, split_regex)
17
+ @router = router
18
+ @split_regex = split_regex
19
+ @delimiters_regex = Regexp.new(router.delimiters_regex)
20
+ end
20
21
 
21
- def generate_route(unprocessed_path, conditions, requirements, default_values, generate_with, priority)
22
- match_partially = if unprocessed_path.is_a?(String)
23
- unprocessed_path = parse(unprocessed_path, requirements, default_values)
24
- if unprocessed_path[-1] == ?*
25
- unprocessed_path.slice!(-1)
26
- true
27
- else
28
- false
29
- end
30
- else
31
- false
32
- end
33
-
34
- unless unprocessed_path.first.is_a?(Route::Util::Group)
35
- group = Usher::Route::Util::Group.new(:all, nil)
36
- unprocessed_path.each{|p| group << p}
37
- unprocessed_path = group
22
+ def generate_route(unprocessed_path, conditions, requirements, default_values, generate_with, priority)
23
+ match_partially = false
24
+ case unprocessed_path
25
+ when String
26
+ if unprocessed_path[-1] == ?*
27
+ unprocessed_path.slice!(-1)
28
+ match_partially = true
38
29
  end
30
+ unprocessed_path = parse(unprocessed_path, requirements, default_values)
31
+ when Regexp
32
+ unprocessed_path = [Route::Static::Greedy.new(unprocessed_path)]
33
+ else
34
+ match_partially = false
35
+ end
36
+
37
+ unless unprocessed_path.first.is_a?(Route::Util::Group)
38
+ group = Usher::Route::Util::Group.new(:all, nil)
39
+ unprocessed_path.each{|p| group << p}
40
+ unprocessed_path = group
41
+ end
42
+ paths = Route::Util.expand_path(unprocessed_path)
39
43
 
40
- paths = Route::Util.expand_path(unprocessed_path)
41
-
42
- paths.map! do |path|
43
- if path.all?{|part| String === part}
44
- path #parse "{~#{path.join}}"
45
- else
46
- path.each_with_index do |part, index|
47
- part.default_value = default_values[part.name] if part.is_a?(Usher::Route::Variable) && default_values && default_values[part.name]
48
- case part
49
- when Usher::Route::Variable::Glob
50
- if part.look_ahead && !part.look_ahead_priority
51
- part.look_ahead = nil
52
- part.look_ahead_priority = true
53
- else
54
- part.look_ahead = path[index + 1, path.size].find{|p| !p.is_a?(Usher::Route::Variable) && !router.delimiters.unescaped.include?(p)} || nil
55
- end
56
- when Usher::Route::Variable
57
- if part.look_ahead && !part.look_ahead_priority
58
- part.look_ahead = nil
59
- part.look_ahead_priority = true
60
- else
61
- part.look_ahead = router.delimiters.first_in(path[index + 1, path.size]) || router.delimiters.unescaped.first
62
- end
63
- end
44
+ paths.each do |path|
45
+ path.each_with_index do |part, index|
46
+ part.default_value = default_values[part.name] if part.is_a?(Usher::Route::Variable) && default_values && default_values[part.name]
47
+ case part
48
+ when Usher::Route::Variable::Glob
49
+ if part.look_ahead && !part.look_ahead_priority
50
+ part.look_ahead = nil
51
+ part.look_ahead_priority = true
52
+ else
53
+ part.look_ahead = path[index + 1, path.size].find{|p| !p.is_a?(Usher::Route::Variable) && !router.delimiters.unescaped.include?(p)} || nil
54
+ end
55
+ when Usher::Route::Variable
56
+ if part.look_ahead && !part.look_ahead_priority
57
+ part.look_ahead = nil
58
+ part.look_ahead_priority = true
59
+ else
60
+ part.look_ahead = router.delimiters.first_in(path[index + 1, path.size]) || router.delimiters.unescaped.first
64
61
  end
65
- path
66
62
  end
67
63
  end
68
-
69
- Route.new(
70
- paths,
71
- router,
72
- conditions,
73
- requirements,
74
- default_values,
75
- generate_with,
76
- match_partially,
77
- priority
78
- )
79
-
80
64
  end
81
65
 
82
- def parse_and_expand(path, requirements = nil, default_values = nil)
83
- Usher::Route::Util.expand_path(parse(path, requirements, default_values))
84
- end
66
+ Route.new(
67
+ paths,
68
+ router,
69
+ conditions,
70
+ requirements,
71
+ default_values,
72
+ generate_with,
73
+ match_partially,
74
+ priority
75
+ )
76
+ end
85
77
 
86
- def parse(path, requirements = nil, default_values = nil)
87
- parts = Usher::Route::Util::Group.new(:all, nil)
88
- scanner = StringScanner.new(path)
78
+ def parse_and_expand(path, requirements = nil, default_values = nil)
79
+ Usher::Route::Util.expand_path(parse(path, requirements, default_values))
80
+ end
89
81
 
90
- current_group = parts
91
- part = nil
92
- while !scanner.eos?
93
- part ?
94
- (part << scanner.scan(@split_regex)) :
95
- (part = scanner.scan(@split_regex))
82
+ def parse(path, requirements = nil, default_values = nil)
83
+ parts = Usher::Route::Util::Group.new(:all, nil)
84
+ scanner = StringScanner.new(path)
96
85
 
97
- if scanner.match?(/\\/) and !scanner.match?(@delimiters_regex)
98
- scanner.skip(/\\/)
99
- part << scanner.getch
100
- next
101
- end
86
+ current_group = parts
87
+ part = nil
88
+ while !scanner.eos?
89
+ part ?
90
+ (part << scanner.scan(@split_regex)) :
91
+ (part = scanner.scan(@split_regex))
102
92
 
103
- case part[0]
104
- when ?*
105
- var_name = part[1, part.size - 1].to_sym
106
- current_group << Usher::Route::Variable::Glob.new(part[1, part.size - 1], nil, requirements && requirements[var_name])
107
- when ?:
108
- var_name = part[1, part.size - 1].to_sym
109
- current_group << Usher::Route::Variable::Single.new(part[1, part.size - 1], nil, requirements && requirements[var_name])
110
- when ?{
111
- pattern = ''
112
- count = 1
113
- simple = scanner.scan(/~/)
114
- variable = scanner.scan(/[!:\*]([^,]+),/)
115
- until count.zero?
116
- regex_part = scanner.scan(/\{|\}|[^\{\}]+/)
117
- case regex_part[0]
118
- when ?{
119
- count += 1
120
- when ?}
121
- count -= 1
122
- end
123
- pattern << regex_part
124
- end
125
- pattern.slice!(pattern.length - 1)
126
- regex = Regexp.new(pattern)
127
- if variable
128
- variable_type = variable.slice!(0).chr.to_sym
129
- variable_class = case variable_type
130
- when :'!' then Usher::Route::Variable::Greedy
131
- when :* then Usher::Route::Variable::Glob
132
- when :':' then Usher::Route::Variable::Single
133
- end
134
- variable_name = variable[0, variable.size - 1].to_sym
135
- current_group << variable_class.new(variable_name, regex, requirements && requirements[variable_name])
136
- elsif simple
137
- current_group << Usher::Route::Static::Greedy.new(pattern)
138
- else
139
- current_group << regex
93
+ if scanner.match?(/\\/) and !scanner.match?(@delimiters_regex)
94
+ scanner.skip(/\\/)
95
+ part << scanner.getch
96
+ next
97
+ end
98
+
99
+ case part[0]
100
+ when ?*
101
+ var_name = part[1, part.size - 1].to_sym
102
+ current_group << Usher::Route::Variable::Glob.new(part[1, part.size - 1], nil, requirements && requirements[var_name])
103
+ when ?:
104
+ var_name = part[1, part.size - 1].to_sym
105
+ current_group << Usher::Route::Variable::Single.new(part[1, part.size - 1], nil, requirements && requirements[var_name])
106
+ when ?{
107
+ pattern = ''
108
+ count = 1
109
+ simple = scanner.scan(/~/)
110
+ variable = scanner.scan(/[!:\*]([^,]+),/)
111
+ until count.zero?
112
+ regex_part = scanner.scan(/\{|\}|[^\{\}]+/)
113
+ case regex_part[0]
114
+ when ?{
115
+ count += 1
116
+ when ?}
117
+ count -= 1
140
118
  end
141
- when ?(
142
- new_group = Usher::Route::Util::Group.new(:any, current_group)
143
- current_group << new_group
144
- current_group = new_group
145
- when ?)
146
- current_group = current_group.parent.group_type == :one ? current_group.parent.parent : current_group.parent
147
- when ?|
148
- unless current_group.parent.group_type == :one
149
- detached_group = current_group.parent.pop
150
- new_group = Usher::Route::Util::Group.new(:one, detached_group.parent)
151
- detached_group.parent = new_group
152
- detached_group.group_type = :all
153
- new_group << detached_group
154
- new_group.parent << new_group
119
+ pattern << regex_part
120
+ end
121
+ pattern.slice!(pattern.length - 1)
122
+ regex = Regexp.new(pattern)
123
+ if variable
124
+ variable_type = variable.slice!(0).chr.to_sym
125
+ variable_class = case variable_type
126
+ when :'!' then Usher::Route::Variable::Greedy
127
+ when :* then Usher::Route::Variable::Glob
128
+ when :':' then Usher::Route::Variable::Single
155
129
  end
156
- current_group.parent << Usher::Route::Util::Group.new(:all, current_group.parent)
157
- current_group = current_group.parent.last
158
- when ?\\
159
- current_group << part[1..-1]
130
+ variable_name = variable[0, variable.size - 1].to_sym
131
+ current_group << variable_class.new(variable_name, regex, requirements && requirements[variable_name])
132
+ elsif simple
133
+ current_group << Usher::Route::Static::Greedy.new(Regexp.new(pattern))
160
134
  else
161
- current_group << part
135
+ current_group << regex
162
136
  end
163
- part = nil
164
- end unless !path || path.empty?
165
- parts
166
- end
167
-
168
- private
169
-
170
- attr_reader :router
137
+ when ?(
138
+ new_group = Usher::Route::Util::Group.new(:any, current_group)
139
+ current_group << new_group
140
+ current_group = new_group
141
+ when ?)
142
+ current_group = current_group.parent.group_type == :one ? current_group.parent.parent : current_group.parent
143
+ when ?|
144
+ unless current_group.parent.group_type == :one
145
+ detached_group = current_group.parent.pop
146
+ new_group = Usher::Route::Util::Group.new(:one, detached_group.parent)
147
+ detached_group.parent = new_group
148
+ detached_group.group_type = :all
149
+ new_group << detached_group
150
+ new_group.parent << new_group
151
+ end
152
+ current_group.parent << Usher::Route::Util::Group.new(:all, current_group.parent)
153
+ current_group = current_group.parent.last
154
+ when ?\\
155
+ current_group << part[1..-1]
156
+ else
157
+ current_group << part
158
+ end
159
+ part = nil
160
+ end unless !path || path.empty?
161
+ parts
171
162
  end
172
163
  end
173
164
  end
@@ -1,17 +1,17 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
2
2
  require 'usher'
3
3
 
4
- describe Delimiters do
4
+ describe Usher::Delimiters do
5
5
  describe "#unescaped" do
6
6
  it "should unescape delimiters correctly" do
7
- Delimiters.new(['/', '\)', '\\\\']).unescaped.should == ['/', ')', '\\']
7
+ Usher::Delimiters.new(['/', '\)', '\\\\']).unescaped.should == ['/', ')', '\\']
8
8
  end
9
9
  end
10
10
 
11
11
  describe "#first_in" do
12
12
  describe "when there is a complex path with a lot of delimiters occurrences" do
13
13
  before :each do
14
- @delimiters = Delimiters.new ['@', '.', '/']
14
+ @delimiters = Usher::Delimiters.new ['@', '.', '/']
15
15
  @paths = ['var', '.', 'var', '/', 'var', '@']
16
16
  end
17
17
 
@@ -24,7 +24,7 @@ describe Delimiters do
24
24
 
25
25
  describe "when there are delimiters with escaped charaters" do
26
26
  before :each do
27
- @delimiters = Delimiters.new ['\\(', '\\)']
27
+ @delimiters = Usher::Delimiters.new ['\\(', '\\)']
28
28
  @paths = ['var', '(', 'var', ')']
29
29
  end
30
30
 
@@ -35,7 +35,7 @@ describe Delimiters do
35
35
 
36
36
  describe "when there is no occurence of delimiters in path" do
37
37
  before :each do
38
- @delimiters = Delimiters.new ['-', '/']
38
+ @delimiters = Usher::Delimiters.new ['-', '/']
39
39
  @paths = ['e', '@', 'ma', '.', 'il']
40
40
  end
41
41
 
@@ -0,0 +1,32 @@
1
+ describe "a route destination" do
2
+ before(:each) do
3
+ @u = Usher.new
4
+ end
5
+
6
+ it "should return a compound with given var args" do
7
+ r = @u.add_route('/testsauce').to(:one, :two, :three, :four)
8
+ r.destination.args.should == [:one, :two, :three, :four]
9
+ end
10
+
11
+ it "should return a compound with given var args and a hash on the end" do
12
+ r = @u.add_route('/testsauce').to(:one, :two, :three, :four, :five => 'six', :seven => 'heaven')
13
+ r.destination.args.should == [:one, :two, :three, :four]
14
+ r.destination.options.should == {:five => 'six', :seven => 'heaven'}
15
+ end
16
+
17
+ it "should never wrap it in a compound if its a simple hash" do
18
+ r = @u.add_route('/testsauce').to(:five => 'six', :seven => 'heaven')
19
+ r.destination.should == {:five => 'six', :seven => 'heaven'}
20
+ end
21
+
22
+ it "should never wrap it in a compound if its a simple object" do
23
+ r = @u.add_route('/testsauce').to(:eighteen)
24
+ r.destination.should == :eighteen
25
+ end
26
+
27
+ it "should never wrap it in a compound if its a simple block" do
28
+ p = proc{ puts 'lovetown' }
29
+ r = @u.add_route('/testsauce').to(&p)
30
+ r.destination.should == p
31
+ end
32
+ end
@@ -142,6 +142,21 @@ describe "Usher URL generation" do
142
142
  @route_set.generator.generate(:default_values_not_in_path, {:controller => "foo"}).should == '/foo?page=1'
143
143
  end
144
144
 
145
+ describe "with consider_destination_keys enabled" do
146
+
147
+ before(:each) do
148
+ @route_set = Usher.new(:generator => Usher::Util::Generators::URL.new, :consider_destination_keys => true)
149
+ @route_set.reset!
150
+ end
151
+
152
+ it "should generate direct unnamed paths" do
153
+ @route_set.add_route('/profiles', :controller => 'profiles', :action => 'edit')
154
+ @route_set.add_route('/users', :controller => 'users', :action => 'index')
155
+ @route_set.generator.generate(nil, :controller => 'profiles', :action => 'edit').should == '/profiles'
156
+ @route_set.generator.generate(nil, :controller => 'users', :action => 'index').should == '/users'
157
+ end
158
+ end
159
+
145
160
  describe "when named route was added with string key" do
146
161
  before :each do
147
162
  @route_set.add_named_route 'items', '/items', :controller => 'items', :action => 'index'
@@ -258,6 +273,19 @@ describe "Usher URL generation" do
258
273
  end
259
274
  end
260
275
 
276
+ describe "#path_for_routing_lookup" do
277
+ describe "when direct route exists" do
278
+ before :each do
279
+ @route_set = Usher.new(:generator => Usher::Util::Generators::URL.new, :consider_destination_keys => true)
280
+ @route = @route_set.add_named_route(:direct_path, '/some-neat-name', :controller => 'foo', :action => 'bar')
281
+ end
282
+
283
+ it "should return exactly this route" do
284
+ @route_set.generator.path_for_routing_lookup(nil, :controller => 'foo', :action => 'bar').should == @route.paths.first
285
+ end
286
+ end
287
+ end
288
+
261
289
  describe "nested generation" do
262
290
  before do
263
291
  @route_set2 = Usher.new(:generator => Usher::Util::Generators::URL.new)