usher 0.5.13 → 0.6.0

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.
@@ -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)