svenfuchs-routing-filter 0.0.1
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/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +123 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/routing_filter.rb +94 -0
- data/lib/routing_filter/base.rb +31 -0
- data/lib/routing_filter/force_extension.rb +57 -0
- data/lib/routing_filter/locale.rb +70 -0
- data/lib/routing_filter/pagination.rb +33 -0
- data/spec/force_extension_spec.rb +65 -0
- data/spec/generation_spec.rb +367 -0
- data/spec/pagination_extension_spec.rb +19 -0
- data/spec/recognition_spec.rb +76 -0
- data/spec/routing_filter_spec.rb +114 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +108 -0
- metadata +75 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
vendor
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Sven Fuchs
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
## Routing Filter
|
2
|
+
|
3
|
+
This plugin is a wild hack that wraps around the complex beast that the Rails
|
4
|
+
routing system is to allow for unseen flexibility and power in Rails URL
|
5
|
+
recognition and generation.
|
6
|
+
|
7
|
+
As powerful and awesome the Rails' routes are, when you need to design your
|
8
|
+
URLs in a manner that only slightly leaves the paved cowpaths of Rails
|
9
|
+
conventions, you're usually unable to use all the goodness of helpers and
|
10
|
+
convenience that Rails ships with.
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
This plugin comes with a locale routing filter that demonstrates the
|
15
|
+
implementation of a custom filter.
|
16
|
+
|
17
|
+
The following would be a sceleton of an empty filter:
|
18
|
+
|
19
|
+
module RoutingFilter
|
20
|
+
class Awesomeness < Base
|
21
|
+
def around_recognize(route, path, env)
|
22
|
+
# Alter the path here before it gets recognized.
|
23
|
+
# Make sure to yield (calls the next around filter if present and
|
24
|
+
# eventually `recognize_path` on the routeset):
|
25
|
+
returning yield do |params|
|
26
|
+
# You can additionally modify the params here before they get passed
|
27
|
+
# to the controller.
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def around_generate(controller, *args, &block)
|
32
|
+
# Alter arguments here before they are passed to `url_for`.
|
33
|
+
# Make sure to yield (calls the next around filter if present and
|
34
|
+
# eventually `url_for` on the controller):
|
35
|
+
returning yield do |result|
|
36
|
+
# You can change the generated url_or_path here. Make sure to use
|
37
|
+
# one of the "in-place" modifying String methods though (like sub!
|
38
|
+
# and friends).
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
You then have to specify the filter explicitely in your routes.rb:
|
45
|
+
|
46
|
+
ActionController::Routing::Routes.draw do |map|
|
47
|
+
map.filter 'awesomeness'
|
48
|
+
end
|
49
|
+
|
50
|
+
(I am not sure if it makes sense to provide more technical information than
|
51
|
+
this because the usage of this plugin definitely requires some advanced
|
52
|
+
knowledge about Rails internals and especially its routing system. So, I
|
53
|
+
figure, anyone who could use this should also be able to read the code and
|
54
|
+
figure out what it's doing much better then from any lengthy documentation.
|
55
|
+
|
56
|
+
If I'm mistaken on this please drop me an email with your suggestions.)
|
57
|
+
|
58
|
+
|
59
|
+
## Rationale: Two example usecases
|
60
|
+
|
61
|
+
An early usecase from which this originated was the need to define a locale
|
62
|
+
at the beginning of an URL in a way so that
|
63
|
+
|
64
|
+
* the locale can be omitted when it is the default locale
|
65
|
+
* all the url\_helpers that are generated by named routes continue to work in
|
66
|
+
a concise manner (i.e. without specifying all parameters again and again)
|
67
|
+
* ideally also plays nicely with default route helpers in tests/specs
|
68
|
+
|
69
|
+
You can read about this struggle and two possible, yet unsatisfying solutions
|
70
|
+
[here](http://www.artweb-design.de/2007/5/13/concise-localized-rails-url-helpers-solved-twice).
|
71
|
+
The conclusion so far is that Rails itself does not provide the tools to solve
|
72
|
+
this problem in a clean and dry way.
|
73
|
+
|
74
|
+
Another usecase that eventually spawned the manifestation of this plugin was
|
75
|
+
the need to map an arbitrary count of path segments to a certain model
|
76
|
+
instance. In an application that I've been working on recently I needed to
|
77
|
+
map URL paths to a nested tree of models like so:
|
78
|
+
|
79
|
+
root
|
80
|
+
+ docs
|
81
|
+
+ api
|
82
|
+
+ wiki
|
83
|
+
|
84
|
+
E.g. the docs section should map to the path `/docs`, the api section to
|
85
|
+
the path `/docs/api` and so on. Furthermore, after these paths there need to be
|
86
|
+
more things to be specified. E.g. the wiki needs to define a whole Rails
|
87
|
+
resource with URLs like `/docs/wiki/pages/1/edit`.
|
88
|
+
|
89
|
+
The only way to solve this problem with Rails' routing toolkit is to map
|
90
|
+
a big, bold `/*everything` catch-all ("globbing") route and process the whole
|
91
|
+
path in a custom dispatcher.
|
92
|
+
|
93
|
+
This, of course, is a really unsatisfying solution because one has to
|
94
|
+
reimplement everything that Rails routes are here to help with: regarding both
|
95
|
+
URL recognition (like parameter mappings, resources, ...) and generation
|
96
|
+
(url\_helpers).
|
97
|
+
|
98
|
+
## Solution
|
99
|
+
|
100
|
+
This plugin offers a solution that takes exactly the opposite route.
|
101
|
+
|
102
|
+
Instead of trying to change things *between* the URL recognition and
|
103
|
+
generation stages to achieve the desired result it *wraps around* the whole
|
104
|
+
routing system and allows to pre- and post-filter both what goes into it
|
105
|
+
(URL recognition) and what comes out of it (URL generation).
|
106
|
+
|
107
|
+
This way we can leave *everything* else completely untouched.
|
108
|
+
|
109
|
+
* We can tinker with the URLs that we receive from the server and feed URLs to
|
110
|
+
Rails that perfectly match the best breed of Rails' conventions.
|
111
|
+
* Inside of the application we can use all the nice helper goodness and
|
112
|
+
conveniences that rely on these conventions being followed.
|
113
|
+
* Finally we can accept URLs that have been generated by the url\_helpers and,
|
114
|
+
again, mutate them in the way that matches our requirements.
|
115
|
+
|
116
|
+
So, even though the plugin itself is a blatant monkey-patch to one of the
|
117
|
+
most complex area of Rails internals, this solution seems to be effectively
|
118
|
+
less intrusive and pricey than others are.
|
119
|
+
|
120
|
+
## Etc
|
121
|
+
|
122
|
+
Authors: [Sven Fuchs](http://www.artweb-design.de) <svenfuchs at artweb-design dot de>
|
123
|
+
License: MIT
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.2
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'routing_filter'
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module RoutingFilter
|
2
|
+
mattr_accessor :active
|
3
|
+
@@active = true
|
4
|
+
|
5
|
+
class Chain < Array
|
6
|
+
def << (filter)
|
7
|
+
filter.chain = self
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(method, *args, &final)
|
12
|
+
RoutingFilter.active && !first.nil? ? first.run(method, *args, &final) : final.call
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_reverse(method, *args, &final)
|
16
|
+
RoutingFilter.active && !last.nil? ? last.run_reverse(method, *args, &final) : final.call
|
17
|
+
end
|
18
|
+
|
19
|
+
def predecessor(filter)
|
20
|
+
ix = index(filter)
|
21
|
+
ix > 0 ? self[ix - 1] : nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def successor(filter)
|
25
|
+
ix = index(filter)
|
26
|
+
ix < length - 1 ? self[ix + 1] : nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# allows to install a filter to the route set by calling: map.filter 'locale'
|
32
|
+
ActionController::Routing::RouteSet::Mapper.class_eval do
|
33
|
+
def filter(name, options = {})
|
34
|
+
require options.delete(:file) || "routing_filter/#{name}"
|
35
|
+
klass = RoutingFilter.const_get(name.to_s.camelize)
|
36
|
+
@set.filters << klass.new(options)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# same here for the optimized url generation in named routes
|
41
|
+
ActionController::Routing::RouteSet::NamedRouteCollection.class_eval do
|
42
|
+
# gosh. monkey engineering optimization code
|
43
|
+
def generate_optimisation_block_with_filtering(*args)
|
44
|
+
code = generate_optimisation_block_without_filtering(*args)
|
45
|
+
if match = code.match(%r(^return (.*) if (.*)))
|
46
|
+
# returned string must not contain newlines, or we'll spill out of inline code comments in
|
47
|
+
# ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper
|
48
|
+
"returning(#{match[1]}) { |result|" +
|
49
|
+
" ActionController::Routing::Routes.filters.run_reverse(:around_generate, *args, &lambda{ result }) " +
|
50
|
+
"} if #{match[2]}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
alias_method_chain :generate_optimisation_block, :filtering
|
54
|
+
end
|
55
|
+
|
56
|
+
ActionController::Routing::RouteSet.class_eval do
|
57
|
+
def clear_with_filtering!
|
58
|
+
@filters.clear if @filters
|
59
|
+
clear_without_filtering!
|
60
|
+
end
|
61
|
+
alias_method_chain :clear!, :filtering
|
62
|
+
|
63
|
+
attr_writer :filters
|
64
|
+
|
65
|
+
def filters
|
66
|
+
@filters ||= RoutingFilter::Chain.new
|
67
|
+
end
|
68
|
+
|
69
|
+
def recognize_path_with_filtering(path, env = {})
|
70
|
+
path = ::URI.unescape(path.dup) # string is frozen due to memoize
|
71
|
+
filters.run(:around_recognize, path, env, &lambda{ recognize_path_without_filtering(path, env) })
|
72
|
+
end
|
73
|
+
alias_method_chain :recognize_path, :filtering
|
74
|
+
|
75
|
+
def generate_with_filtering(*args)
|
76
|
+
filters.run_reverse(:around_generate, args.first, &lambda{ generate_without_filtering(*args) })
|
77
|
+
end
|
78
|
+
alias_method_chain :generate, :filtering
|
79
|
+
|
80
|
+
# add some useful information to the request environment
|
81
|
+
# right, this is from jamis buck's excellent article about routes internals
|
82
|
+
# http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2
|
83
|
+
# TODO move this ... where?
|
84
|
+
alias_method :extract_request_environment_without_host, :extract_request_environment unless method_defined? :extract_request_environment_without_host
|
85
|
+
def extract_request_environment(request)
|
86
|
+
returning extract_request_environment_without_host(request) do |env|
|
87
|
+
env.merge! :host => request.host,
|
88
|
+
:port => request.port,
|
89
|
+
:host_with_port => request.host_with_port,
|
90
|
+
:domain => request.domain,
|
91
|
+
:subdomain => request.subdomains.first
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RoutingFilter
|
2
|
+
class Base
|
3
|
+
class_inheritable_accessor :active
|
4
|
+
self.active = true
|
5
|
+
|
6
|
+
attr_accessor :chain, :options
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = options
|
10
|
+
options.each { |name, value| instance_variable_set :"@#{name}", value }
|
11
|
+
end
|
12
|
+
|
13
|
+
def run(method, *args, &block)
|
14
|
+
_next = successor ? lambda { successor.run(method, *args, &block) } : block
|
15
|
+
active ? send(method, *args, &_next) : _next.call(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_reverse(method, *args, &block)
|
19
|
+
_prev = predecessor ? lambda { predecessor.run(method, *args, &block) } : block
|
20
|
+
active ? send(method, *args, &_prev) : _prev.call(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def predecessor
|
24
|
+
@chain.predecessor(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
def successor
|
28
|
+
@chain.successor(self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'routing_filter/base'
|
2
|
+
|
3
|
+
module RoutingFilter
|
4
|
+
class ForceExtension < Base
|
5
|
+
attr_reader :extension, :exclude
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
@extension ||= 'html'
|
10
|
+
@exclude = %r(^(http.?://[^/]+)?\/?$) if @exclude.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
def around_recognize(path, env, &block)
|
14
|
+
extract_extension!(path) unless excluded?(path)
|
15
|
+
yield(path, env)
|
16
|
+
end
|
17
|
+
|
18
|
+
def around_generate(*args, &block)
|
19
|
+
returning yield do |result|
|
20
|
+
url = result.is_a?(Array) ? result.first : result
|
21
|
+
append_extension!(url) if append_extension?(url)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def extract_extension!(path)
|
28
|
+
path.sub! /\.#{extension}$/, ''
|
29
|
+
$1
|
30
|
+
end
|
31
|
+
|
32
|
+
def append_extension?(url)
|
33
|
+
!(url.blank? || excluded?(url) || mime_extension?(url))
|
34
|
+
end
|
35
|
+
|
36
|
+
def excluded?(url)
|
37
|
+
case exclude
|
38
|
+
when Regexp
|
39
|
+
url =~ exclude
|
40
|
+
when Proc
|
41
|
+
exclude.call(url)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def mime_extension?(url)
|
46
|
+
url =~ /\.#{Mime::EXTENSION_LOOKUP.keys.join('|')}(\?|$)/
|
47
|
+
end
|
48
|
+
|
49
|
+
def append_extension!(url)
|
50
|
+
url.replace url.sub(/(\?|$)/, ".#{extension}\\1")
|
51
|
+
end
|
52
|
+
|
53
|
+
def append_page!(url, page)
|
54
|
+
url.replace "#{url}/pages/#{page}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
require 'routing_filter/base'
|
3
|
+
|
4
|
+
module RoutingFilter
|
5
|
+
class Locale < Base
|
6
|
+
@@include_default_locale = true
|
7
|
+
cattr_writer :include_default_locale
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def include_default_locale?
|
11
|
+
@@include_default_locale
|
12
|
+
end
|
13
|
+
|
14
|
+
def locales
|
15
|
+
@@locales ||= I18n.available_locales.map(&:to_sym)
|
16
|
+
end
|
17
|
+
|
18
|
+
def locales=(locales)
|
19
|
+
@@locales = locales.map(&:to_sym)
|
20
|
+
end
|
21
|
+
|
22
|
+
def locales_pattern
|
23
|
+
@@locales_pattern ||= %r(^/(#{self.locales.map { |l| Regexp.escape(l.to_s) }.join('|')})(?=/|$))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def around_recognize(path, env, &block)
|
28
|
+
locale = extract_locale!(path) # remove the locale from the beginning of the path
|
29
|
+
returning yield do |params| # invoke the given block (calls more filters and finally routing)
|
30
|
+
params[:locale] = locale if locale # set recognized locale to the resulting params hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def around_generate(*args, &block)
|
35
|
+
locale = args.extract_options!.delete(:locale) # extract the passed :locale option
|
36
|
+
locale = I18n.locale if locale.nil? # default to I18n.locale when locale is nil (could also be false)
|
37
|
+
locale = nil unless valid_locale?(locale) # reset to no locale when locale is not valid
|
38
|
+
|
39
|
+
returning yield do |result|
|
40
|
+
if locale && prepend_locale?(locale)
|
41
|
+
url = result.is_a?(Array) ? result.first : result
|
42
|
+
prepend_locale!(url, locale)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def extract_locale!(path)
|
50
|
+
path.sub! self.class.locales_pattern, ''
|
51
|
+
$1
|
52
|
+
end
|
53
|
+
|
54
|
+
def prepend_locale?(locale)
|
55
|
+
self.class.include_default_locale? || !default_locale?(locale)
|
56
|
+
end
|
57
|
+
|
58
|
+
def valid_locale?(locale)
|
59
|
+
locale && self.class.locales.include?(locale.to_sym)
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_locale?(locale)
|
63
|
+
locale && locale.to_sym == I18n.default_locale.to_sym
|
64
|
+
end
|
65
|
+
|
66
|
+
def prepend_locale!(url, locale)
|
67
|
+
url.sub!(%r(^(http.?://[^/]*)?(.*))) { "#{$1}/#{locale}#{$2}" }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'routing_filter/base'
|
2
|
+
|
3
|
+
module RoutingFilter
|
4
|
+
class Pagination < Base
|
5
|
+
def around_recognize(path, env, &block)
|
6
|
+
page = extract_page!(path)
|
7
|
+
returning yield(path, env) do |params|
|
8
|
+
params[:page] = page.to_i if page
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def around_generate(*args, &block)
|
13
|
+
page = args.extract_options!.delete(:page)
|
14
|
+
returning yield do |result|
|
15
|
+
if page && page != 1
|
16
|
+
url = result.is_a?(Array) ? result.first : result
|
17
|
+
append_page!(url, page)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def extract_page!(path)
|
25
|
+
path.sub! %r(/pages/([\d]+)/?$), ''
|
26
|
+
$1
|
27
|
+
end
|
28
|
+
|
29
|
+
def append_page!(url, page)
|
30
|
+
url.sub!(/($|\?)/) { "/pages/#{page}#{$1}" }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'RoutingFilter::ForceExtension' do
|
4
|
+
include RoutingFilterHelpers
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
setup_environment(:force_extension)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'url recognition' do
|
11
|
+
it 'recognizes the path /sections/1.html' do
|
12
|
+
should_recognize_path '/sections/1.html', @section_params
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'recognizes the path /sections/1/articles/1.html' do
|
16
|
+
should_recognize_path '/sections/1/articles/1.html', @article_params
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'does not recognize the path /sections/1/articles/1.foobar' do
|
20
|
+
lambda { @set.recognize_path('/sections/1/articles/1.foobar', {}) }.should raise_error(ActionController::RoutingError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'url generation' do
|
25
|
+
it 'appends the .html extension to generated paths (section_path)' do
|
26
|
+
section_path(:id => 1).should == '/sections/1.html'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'appends the .html extension to generated paths (section_article_path)' do
|
30
|
+
section_article_path(:section_id => 1, :id => 1).should == '/sections/1/articles/1.html'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'appends the .html extension to generated paths (admin_articles_path)' do
|
34
|
+
admin_articles_path.should == '/admin/articles.html'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not replace or add on an existing extension' do
|
38
|
+
section_path(:id => 1, :format => 'xml').should == '/sections/1.xml'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'works with url query params' do
|
42
|
+
section_path(:id => 1, :foo => 'bar').should == '/sections/1.html?foo=bar'
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'excludes / by default' do
|
46
|
+
home_path.should == '/'
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'excludes http://test.host/ by default' do
|
50
|
+
home_url.should == 'http://test.host/'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'excludes with custom regexp' do
|
54
|
+
setup_environment { |map| map.filter :force_extension, :exclude => %r(^/(admin|$)) }
|
55
|
+
home_path.should == '/'
|
56
|
+
admin_articles_path.should == '/admin/articles'
|
57
|
+
section_path(:id => 1).should == '/sections/1.html'
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'does not exclude / when :exclude => false was passed' do
|
61
|
+
setup_environment { |map| map.filter :force_extension, :exclude => false }
|
62
|
+
home_path.should == '/.html'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,367 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'RoutingFilter', 'url generation' do
|
4
|
+
include RoutingFilterHelpers
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
setup_environment :locale, :pagination
|
8
|
+
|
9
|
+
@site = Site.new
|
10
|
+
@section = Section.new
|
11
|
+
@article = Article.new
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "named route url_helpers" do
|
15
|
+
describe "a not nested resource" do
|
16
|
+
it 'does not change the section_path when given page option equals 1' do
|
17
|
+
section_path(:id => 1, :page => 1).should == '/en/sections/1'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'appends the pages segments to section_path when given page option does not equal 1' do
|
21
|
+
section_path(:id => 1, :page => 2).should == '/en/sections/1/pages/2'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'prepends the current locale to section_path' do
|
25
|
+
I18n.locale = :de
|
26
|
+
section_path(:id => 1).should == '/de/sections/1'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'prepends a given locale param to section_path' do
|
30
|
+
I18n.locale = :de
|
31
|
+
section_path(:id => 1, :locale => :fi).should == '/fi/sections/1'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'does not prepend a locale to section_path if given locale is false' do
|
35
|
+
section_path(:id => 1, :locale => false).should == '/sections/1'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'works on section_path with both a locale and page option' do
|
39
|
+
section_path(:id => 1, :locale => :fi, :page => 2).should == '/fi/sections/1/pages/2'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should not prepend an invalid locale to section_path' do
|
43
|
+
section_path(:id => 1, :locale => :aa).should == '/sections/1'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should prepend a longer locale to section_path' do
|
47
|
+
section_path(:id => 1, :locale => 'en-US').should == '/en-US/sections/1'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not prepend the default locale when configured not to' do
|
51
|
+
RoutingFilter::Locale.include_default_locale = false
|
52
|
+
section_path(:id => 1, :locale => :en).should == '/sections/1'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "a nested resource" do
|
57
|
+
it 'does not change the section_article_path when given page option equals 1' do
|
58
|
+
section_article_path(:section_id => 1, :id => 1, :page => 1).should == '/en/sections/1/articles/1'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'appends the pages segments to section_article_path when given page option does not equal 1' do
|
62
|
+
section_article_path(:section_id => 1, :id => 1, :page => 2).should == '/en/sections/1/articles/1/pages/2'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'prepends the current locale to section_article_path' do
|
66
|
+
I18n.locale = :de
|
67
|
+
section_article_path(:section_id => 1, :id => 1).should == '/de/sections/1/articles/1'
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'prepends a given locale param to section_article_path' do
|
71
|
+
I18n.locale = :de
|
72
|
+
section_article_path(:section_id => 1, :id => 1, :locale => :fi).should == '/fi/sections/1/articles/1'
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'does not prepend a locale to section_article_path if given locale is false' do
|
76
|
+
section_article_path(:section_id => 1, :id => 1, :locale => false).should == '/sections/1/articles/1'
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'works on section_article_path with both a locale and page option' do
|
80
|
+
section_article_path(:section_id => 1, :id => 1, :locale => :fi, :page => 2).should == '/fi/sections/1/articles/1/pages/2'
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should not prepend an invalid locale to section_article_path' do
|
84
|
+
section_article_path(:section_id => 1, :id => 1, :locale => :aa).should == '/sections/1/articles/1'
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should prepend a longer locale to section_article_path' do
|
88
|
+
section_article_path(:section_id => 1, :id => 1, :locale => 'en-US').should == '/en-US/sections/1/articles/1'
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should not prepend the default locale when configured not to' do
|
92
|
+
RoutingFilter::Locale.include_default_locale = false
|
93
|
+
section_article_path(:section_id => 1, :id => 1, :locale => :en).should == '/sections/1/articles/1'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'when used with named route url_helper with "optimized" generation blocks' do
|
99
|
+
describe "a not nested resource" do
|
100
|
+
it 'does not change the section_path when given page option equals 1' do
|
101
|
+
section_path(1, :page => 1).should == '/en/sections/1'
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'appends the pages segments to section_path when given page option does not equal 1' do
|
105
|
+
section_path(1, :page => 2).should == '/en/sections/1/pages/2'
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'prepends the current locale to section_path' do
|
109
|
+
I18n.locale = :de
|
110
|
+
section_path(1).should == '/de/sections/1'
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'prepends a given locale param to section_path' do
|
114
|
+
I18n.locale = :de
|
115
|
+
section_path(1, :locale => :fi).should == '/fi/sections/1'
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'does not prepend a locale to section_path if given locale is false' do
|
119
|
+
section_path(1, :locale => false).should == '/sections/1'
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'works for section_path with both a locale and page option' do
|
123
|
+
section_path(1, :locale => :fi, :page => 2).should == '/fi/sections/1/pages/2'
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should not prepend an invalid locale to section_path' do
|
127
|
+
section_path(1, :locale => :aa).should == '/sections/1'
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should prepend a longer locale to section_path' do
|
131
|
+
section_path(1, :locale => 'en-US').should == '/en-US/sections/1'
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should not prepend the default locale when configured not to' do
|
135
|
+
RoutingFilter::Locale.include_default_locale = false
|
136
|
+
section_path(1, :locale => :en).should == '/sections/1'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "a nested resource" do
|
141
|
+
it 'does not change the section_article_path when given page option equals 1' do
|
142
|
+
section_article_path(1, 1, :page => 1).should == '/en/sections/1/articles/1'
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'appends the pages segments to section_article_path when given page option does not equal 1' do
|
146
|
+
section_article_path(1, 1, :page => 2).should == '/en/sections/1/articles/1/pages/2'
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'prepends the current locale to section_article_path' do
|
150
|
+
I18n.locale = :de
|
151
|
+
section_article_path(1, 1).should == '/de/sections/1/articles/1'
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'prepends a given locale param to section_article_path' do
|
155
|
+
I18n.locale = :de
|
156
|
+
section_article_path(1, 1, :locale => :fi).should == '/fi/sections/1/articles/1'
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'does not prepend a locale to section_article_path if given locale is false' do
|
160
|
+
section_article_path(1, 1, :locale => false).should == '/sections/1/articles/1'
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'works for section_article_path with both a locale and page option' do
|
164
|
+
section_article_path(1, 1, :locale => :fi, :page => 2).should == '/fi/sections/1/articles/1/pages/2'
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should not prepend an invalid locale to section_article_path' do
|
168
|
+
section_article_path(1, 1, :locale => :aa).should == '/sections/1/articles/1'
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should prepend a longer locale to section_article_path' do
|
172
|
+
section_article_path(1, 1, :locale => 'en-US').should == '/en-US/sections/1/articles/1'
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'should not prepend the default locale when configured not to' do
|
176
|
+
RoutingFilter::Locale.include_default_locale = false
|
177
|
+
section_article_path(1, 1, :locale => :en).should == '/sections/1/articles/1'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe 'when used with a polymorphic_path' do
|
183
|
+
describe "a not nested resource" do
|
184
|
+
it 'does not change the section_path when given page option equals 1' do
|
185
|
+
section_path(@section, :page => 1).should == '/en/sections/1'
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'appends the pages segments to section_path when given page option does not equal 1' do
|
189
|
+
section_path(@section, :page => 2).should == '/en/sections/1/pages/2'
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'prepends the current locale to section_path' do
|
193
|
+
I18n.locale = :de
|
194
|
+
section_path(@section).should == '/de/sections/1'
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'prepends a given locale param to section_path' do
|
198
|
+
I18n.locale = :de
|
199
|
+
section_path(@section, :locale => :fi).should == '/fi/sections/1'
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'does not prepend a locale to section_path if given locale is false' do
|
203
|
+
section_path(@section, :locale => false).should == '/sections/1'
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'works for section_path with both a locale and page option' do
|
207
|
+
section_path(@section, :locale => :fi, :page => 2).should == '/fi/sections/1/pages/2'
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'should not prepend an invalid locale to section_path' do
|
211
|
+
section_path(@section, :locale => :aa).should == '/sections/1'
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should prepend a longer locale to section_path' do
|
215
|
+
section_path(@section, :locale => 'en-US').should == '/en-US/sections/1'
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'should not prepend the default locale when configured not to' do
|
219
|
+
RoutingFilter::Locale.include_default_locale = false
|
220
|
+
section_path(@section, :locale => :en).should == '/sections/1'
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe "a nested resource" do
|
225
|
+
it 'does not change the section_article_path when given page option equals 1' do
|
226
|
+
section_article_path(@section, @article, :page => 1).should == '/en/sections/1/articles/1'
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'appends the pages segments to section_article_path when given page option does not equal 1' do
|
230
|
+
section_article_path(@section, @article, :page => 2).should == '/en/sections/1/articles/1/pages/2'
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'prepends the current locale to section_article_path' do
|
234
|
+
I18n.locale = :de
|
235
|
+
section_article_path(@section, @article).should == '/de/sections/1/articles/1'
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'prepends a given locale param to section_article_path' do
|
239
|
+
I18n.locale = :de
|
240
|
+
section_article_path(@section, @article, :locale => :fi).should == '/fi/sections/1/articles/1'
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'does not prepend a locale to section_article_path if given locale is false' do
|
244
|
+
section_article_path(@section, @article, :locale => false).should == '/sections/1/articles/1'
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'works for section_article_path with both a locale and page option' do
|
248
|
+
section_article_path(@section, @article, :locale => :fi, :page => 2).should == '/fi/sections/1/articles/1/pages/2'
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should not prepend an invalid locale to section_article_path' do
|
252
|
+
section_article_path(@section, @article, :locale => :aa).should == '/sections/1/articles/1'
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'should prepend a longer locale to section_article_path' do
|
256
|
+
section_article_path(@section, @article, :locale => 'en-US').should == '/en-US/sections/1/articles/1'
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'should not prepend the default locale when configured not to' do
|
260
|
+
RoutingFilter::Locale.include_default_locale = false
|
261
|
+
section_article_path(@section, @article, :locale => :en).should == '/sections/1/articles/1'
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe 'when used with url_for and an ActivRecord instance' do
|
267
|
+
describe "a not nested resource" do
|
268
|
+
it 'does not change the url_for result when given page option equals 1' do
|
269
|
+
params = @section_params.update :id => @section, :page => 1
|
270
|
+
url_for(params).should == 'http://test.host/en/sections/1'
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'appends the pages segments to url_for result when given page option does not equal 1' do
|
274
|
+
params = @section_params.update :id => @section, :page => 2
|
275
|
+
url_for(params).should == 'http://test.host/en/sections/1/pages/2'
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'prepends the current locale to url_for result' do
|
279
|
+
I18n.locale = :de
|
280
|
+
params = @section_params.update :id => @section
|
281
|
+
url_for(params).should == 'http://test.host/de/sections/1'
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'prepends a given locale param url_for result' do
|
285
|
+
I18n.locale = :de
|
286
|
+
params = @section_params.update :id => @section, :locale => :fi
|
287
|
+
url_for(params).should == 'http://test.host/fi/sections/1'
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'does not prepend a locale to url_for result if given locale is false' do
|
291
|
+
params = @section_params.update :id => @section, :locale => false
|
292
|
+
url_for(params).should == 'http://test.host/sections/1'
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'works for url_for result with both a locale and page option' do
|
296
|
+
params = @section_params.update :id => @section, :locale => :fi, :page => 2
|
297
|
+
url_for(params).should == 'http://test.host/fi/sections/1/pages/2'
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'should not prepend an invalid locale to section_path' do
|
301
|
+
params = @section_params.update :id => @section, :locale => :aa
|
302
|
+
url_for(params).should == 'http://test.host/sections/1'
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'should prepend a longer locale to section_path' do
|
306
|
+
params = @section_params.update :id => @section, :locale => 'en-US'
|
307
|
+
url_for(params).should == 'http://test.host/en-US/sections/1'
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'should not prepend the default locale when configured not to' do
|
311
|
+
RoutingFilter::Locale.include_default_locale = false
|
312
|
+
params = @section_params.update :id => @section, :locale => :en
|
313
|
+
url_for(params).should == 'http://test.host/sections/1'
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
describe "a nested resource" do
|
318
|
+
it 'does not change the url_for result when given page option equals 1' do
|
319
|
+
params = @article_params.update :section_id => @section, :id => @article, :page => 1
|
320
|
+
url_for(params).should == 'http://test.host/en/sections/1/articles/1'
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'appends the pages segments to url_for result when given page option does not equal 1' do
|
324
|
+
params = @article_params.update :section_id => @section, :id => @article, :page => 2
|
325
|
+
url_for(params).should == 'http://test.host/en/sections/1/articles/1/pages/2'
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'prepends the current locale to url_for result' do
|
329
|
+
I18n.locale = :de
|
330
|
+
params = @article_params.update :section_id => @section, :id => @article
|
331
|
+
url_for(params).should == 'http://test.host/de/sections/1/articles/1'
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'prepends a given locale param to url_for result' do
|
335
|
+
I18n.locale = :de
|
336
|
+
params = @article_params.update :section_id => @section, :id => @article, :locale => :fi
|
337
|
+
url_for(params).should == 'http://test.host/fi/sections/1/articles/1'
|
338
|
+
end
|
339
|
+
|
340
|
+
it 'does not prepend a locale to url_for result if given locale is false' do
|
341
|
+
params = @article_params.update :section_id => @section, :id => @article, :locale => false
|
342
|
+
url_for(params).should == 'http://test.host/sections/1/articles/1'
|
343
|
+
end
|
344
|
+
|
345
|
+
it 'works for url_for result with both a locale and page option' do
|
346
|
+
params = @article_params.update :section_id => @section, :id => @article, :locale => :fi, :page => 2
|
347
|
+
url_for(params).should == 'http://test.host/fi/sections/1/articles/1/pages/2'
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'should not prepend an invalid locale to url_for result' do
|
351
|
+
params = @article_params.update :section_id => @section, :id => @article, :locale => :aa
|
352
|
+
url_for(params).should == 'http://test.host/sections/1/articles/1'
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'should prepend a longer locale to section_article_path' do
|
356
|
+
params = @article_params.update :section_id => @section, :id => @article, :locale => 'en-US'
|
357
|
+
url_for(params).should == 'http://test.host/en-US/sections/1/articles/1'
|
358
|
+
end
|
359
|
+
|
360
|
+
it 'should not prepend the default locale when configured not to' do
|
361
|
+
RoutingFilter::Locale.include_default_locale = false
|
362
|
+
params = @article_params.update :section_id => @section, :id => @article, :locale => :en
|
363
|
+
url_for(params).should == 'http://test.host/sections/1/articles/1'
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'RoutingFilter::Pagination' do
|
4
|
+
include RoutingFilterHelpers
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
setup_environment(:pagination)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'url generation' do
|
11
|
+
it 'appends the segments /pages/:page to the generated path' do
|
12
|
+
section_path(1, :page => 2).should == '/sections/1/pages/2'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'appends the segments /pages/:page to the generated path excluding http get params' do
|
16
|
+
section_path(1, :page => 2, :foo => 'bar').should == '/sections/1/pages/2?foo=bar'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'RoutingFilter', 'url recognition' do
|
4
|
+
include RoutingFilterHelpers
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
setup_environment :locale, :pagination
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'recognizes the path /de/sections/1 and sets the :locale param' do
|
11
|
+
should_recognize_path '/de/sections/1', @section_params.update(:locale => 'de')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'recognizes the path /sections/1/pages/1 and sets the :page param' do
|
15
|
+
should_recognize_path '/sections/1/pages/1', @section_params.update(:page => 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'recognizes the path /de/sections/1/pages/1 and sets the :locale param' do
|
19
|
+
should_recognize_path '/de/sections/1/pages/1', @section_params.update(:locale => 'de', :page => 1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'recognizes the path /sections/1/articles/1 and sets the :locale param' do
|
23
|
+
should_recognize_path '/sections/1/articles/1', @article_params
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'recognizes the path /de/sections/1/articles/1 and sets the :locale param' do
|
27
|
+
should_recognize_path '/de/sections/1/articles/1', @article_params.update(:locale => 'de')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'recognizes the path /de/sections/1/articles/1/pages/1 and sets the :locale param' do
|
31
|
+
should_recognize_path '/de/sections/1/articles/1/pages/1', @article_params.update(:locale => 'de', :page => 1)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'recognizes the path /sections/1 and does not set a :locale param' do
|
35
|
+
should_recognize_path '/sections/1', @section_params
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'recognizes the path /sections/1 and does not set a :page param' do
|
39
|
+
should_recognize_path '/sections/1', @section_params
|
40
|
+
end
|
41
|
+
|
42
|
+
# Test that routing errors are thrown for invalid locales
|
43
|
+
it 'does not recognizes the path /aa/sections/1 and does not set a :locale param' do
|
44
|
+
begin
|
45
|
+
should_recognize_path '/aa/sections/1', @section_params.update(:locale => 'aa')
|
46
|
+
false
|
47
|
+
rescue ActionController::RoutingError
|
48
|
+
true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'recognizes the path /en-US/sections/1 and sets a :locale param' do
|
53
|
+
should_recognize_path '/en-US/sections/1', @section_params.update(:locale => 'en-US')
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'recognizes the path /sections/1/articles/1 and does not set a :locale param' do
|
57
|
+
should_recognize_path '/sections/1/articles/1', @article_params
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'recognizes the path /sections/1/articles/1 and does not set a :page param' do
|
61
|
+
should_recognize_path '/sections/1/articles/1', @article_params
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'invalid locale: does not recognize the path /aa/sections/1/articles/1 and does not set a :locale param' do
|
65
|
+
lambda { @set.recognize_path('/aa/sections/1/articles/1', {}) }.should raise_error(ActionController::RoutingError)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'recognizes the path /en-US/sections/1/articles/1 and sets a :locale param' do
|
69
|
+
should_recognize_path '/en-US/sections/1/articles/1', @article_params.update(:locale => 'en-US')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'unescapes the path for the filters' do
|
73
|
+
@set.should_receive(:recognize_path_without_filtering).with('/sections/motörhead', 'test')
|
74
|
+
@set.recognize_path('/sections/mot%C3%B6rhead', 'test')
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'RoutingFilter' do
|
4
|
+
include RoutingFilterHelpers
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
setup_environment :locale, :pagination
|
8
|
+
end
|
9
|
+
|
10
|
+
def recognize_path(path = '/de/sections/1', options = {})
|
11
|
+
@set.recognize_path(path, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'installs filters to the route set' do
|
15
|
+
@locale_filter.should be_instance_of(RoutingFilter::Locale)
|
16
|
+
@pagination_filter.should be_instance_of(RoutingFilter::Pagination)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'calls the first filter for route recognition' do
|
20
|
+
@locale_filter.should_receive(:around_recognize).and_return :foo => :bar
|
21
|
+
recognize_path.should == { :foo => :bar }
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'calls the second filter for route recognition' do
|
25
|
+
@pagination_filter.should_receive(:around_recognize).and_return :foo => :bar
|
26
|
+
recognize_path.should == { :foo => :bar, :locale => 'de' }
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'calls the first filter for url generation' do
|
30
|
+
@locale_filter.should_receive(:around_generate).and_return '/en/sections/1?page=2'
|
31
|
+
url_for(:controller => 'sections', :action => 'show', :section_id => 1)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'calls the second filter for url generation' do
|
35
|
+
@pagination_filter.should_receive(:around_generate).and_return '/sections/1?page=2'
|
36
|
+
url_for(:controller => 'sections', :action => 'show', :section_id => 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'calls the first filter for named route url_helper' do
|
40
|
+
@locale_filter.should_receive(:around_generate).and_return '/en/sections/1'
|
41
|
+
section_path(:section_id => 1)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'calls the filter for named route url_helper with "optimized" generation blocks' do
|
45
|
+
# at_least(1) since the inline code comments in ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper also call us (as of http://github.com/rails/rails/commit/a2270ef2594b97891994848138614657363f2806)
|
46
|
+
@locale_filter.should_receive(:around_generate).at_least(1).and_return '/en/sections/1'
|
47
|
+
section_path(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'calls the filter for named route polymorphic_path' do
|
51
|
+
# at_least(1) since the inline code comments in ActionController::Routing::RouteSet::NamedRouteCollection#define_url_helper also call us (as of http://github.com/rails/rails/commit/a2270ef2594b97891994848138614657363f2806)
|
52
|
+
@locale_filter.should_receive(:around_generate).at_least(1).and_return '/en/sections/1'
|
53
|
+
section_path(Section.new)
|
54
|
+
end
|
55
|
+
|
56
|
+
# When filters are set up in the order:
|
57
|
+
#
|
58
|
+
# map.filter :locale
|
59
|
+
# map.filter :pagination
|
60
|
+
#
|
61
|
+
# Then #around_recognize should be first called on the locale filter and then
|
62
|
+
# on the pagination filter. Whereas #around_generate should be first called
|
63
|
+
# on the pagination filter and then on the locale filter. Right?
|
64
|
+
|
65
|
+
it 'calls #around_recognize in the expected order' do
|
66
|
+
params = { :id => "1", :page => 2, :controller => "sections", :action => "show" }
|
67
|
+
@pagination_filter.stub!(:around_recognize).and_return({ :page => 2, :controller => "sections", :action => "show" })
|
68
|
+
|
69
|
+
recognize_path('/de/sections/1/pages/2')[:locale].should == "de"
|
70
|
+
recognize_path('/de/sections/1/pages/2')[:page].should == 2
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'calls #around_generate in the expected order' do
|
74
|
+
@locale_filter.stub!(:around_generate).and_return('de/sections/1')
|
75
|
+
section_path(1, :page => 2).should == "de/sections/1/pages/2"
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'does not call deactivated filters' do
|
79
|
+
with_deactivated_filters(RoutingFilter::Locale) do
|
80
|
+
@locale_filter.should_not_receive(:around_generate)
|
81
|
+
section_path(Section.new)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'still calls successors of deactivated filters' do
|
86
|
+
with_deactivated_filters(RoutingFilter::Locale) do
|
87
|
+
@pagination_filter.should_receive(:around_recognize).and_return :foo => :bar
|
88
|
+
recognize_path('/sections/1').should == { :foo => :bar }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# chain
|
93
|
+
|
94
|
+
it 'adds filters in the order they are registered' do
|
95
|
+
@set.filters[0].should == @locale_filter
|
96
|
+
@set.filters[1].should == @pagination_filter
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns the previous filter as a predecessor of a filter' do
|
100
|
+
@set.filters.predecessor(@pagination_filter).should == @locale_filter
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'returns the nil as a predecessor of the first filter' do
|
104
|
+
@set.filters.successor(@pagination_filter).should be_nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns the next filter as a successor of a filter' do
|
108
|
+
@set.filters.successor(@locale_filter).should == @pagination_filter
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'returns the nil as a successor of the last filter' do
|
112
|
+
@set.filters.successor(@pagination_filter).should be_nil
|
113
|
+
end
|
114
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
$: << File.dirname(__FILE__) + '/../lib/'
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'actionpack'
|
6
|
+
require 'activesupport'
|
7
|
+
require 'action_controller'
|
8
|
+
require 'action_controller/test_process'
|
9
|
+
require 'active_support/vendor'
|
10
|
+
require 'spec'
|
11
|
+
|
12
|
+
require 'routing_filter'
|
13
|
+
require 'routing_filter/locale'
|
14
|
+
require 'routing_filter/pagination'
|
15
|
+
|
16
|
+
class Site
|
17
|
+
end
|
18
|
+
|
19
|
+
class Section
|
20
|
+
def id; 1 end
|
21
|
+
alias :to_param :id
|
22
|
+
def type; 'Section' end
|
23
|
+
def path; 'section' end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Article
|
27
|
+
def to_param; 1 end
|
28
|
+
end
|
29
|
+
|
30
|
+
module RoutingFilterHelpers
|
31
|
+
def draw_routes(&block)
|
32
|
+
set = returning ActionController::Routing::RouteSet.new do |set|
|
33
|
+
class << set; def clear!; end; end
|
34
|
+
set.draw &block
|
35
|
+
silence_warnings{ ActionController::Routing.const_set 'Routes', set }
|
36
|
+
end
|
37
|
+
set
|
38
|
+
end
|
39
|
+
|
40
|
+
def instantiate_controller(params)
|
41
|
+
returning ActionController::Base.new do |controller|
|
42
|
+
request = ActionController::TestRequest.new
|
43
|
+
url = ActionController::UrlRewriter.new(request, params)
|
44
|
+
controller.stub!(:request).and_return request
|
45
|
+
controller.instance_variable_set :@url, url
|
46
|
+
controller
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def should_recognize_path(path, params)
|
51
|
+
@set.recognize_path(path, {}).should == params
|
52
|
+
end
|
53
|
+
|
54
|
+
def home_path(*args)
|
55
|
+
@controller.send :home_path, *args
|
56
|
+
end
|
57
|
+
|
58
|
+
def home_url(*args)
|
59
|
+
@controller.send :home_url, *args
|
60
|
+
end
|
61
|
+
|
62
|
+
def section_path(*args)
|
63
|
+
@controller.send :section_path, *args
|
64
|
+
end
|
65
|
+
|
66
|
+
def section_article_path(*args)
|
67
|
+
@controller.send :section_article_path, *args
|
68
|
+
end
|
69
|
+
|
70
|
+
def admin_articles_path(*args)
|
71
|
+
@controller.send :admin_articles_path, *args
|
72
|
+
end
|
73
|
+
|
74
|
+
def url_for(*args)
|
75
|
+
@controller.send :url_for, *args
|
76
|
+
end
|
77
|
+
|
78
|
+
def setup_environment(*filters)
|
79
|
+
RoutingFilter::Locale.locales = [:en, 'en-US', :de, :fi, 'en-UK']
|
80
|
+
RoutingFilter::Locale.include_default_locale = true
|
81
|
+
I18n.default_locale = :en
|
82
|
+
I18n.locale = :en
|
83
|
+
|
84
|
+
@controller = instantiate_controller :locale => 'de', :id => 1
|
85
|
+
@set = draw_routes do |map|
|
86
|
+
yield map if block_given?
|
87
|
+
filters.each { |filter| map.filter filter }
|
88
|
+
map.section 'sections/:id.:format', :controller => 'sections', :action => "show"
|
89
|
+
map.section_article 'sections/:section_id/articles/:id', :controller => 'articles', :action => "show"
|
90
|
+
map.admin_articles 'admin/articles/:id', :controller => 'admin/articles', :action => "index"
|
91
|
+
map.home '/', :controller => 'home', :action => 'index'
|
92
|
+
end
|
93
|
+
|
94
|
+
@section_params = {:controller => 'sections', :action => "show", :id => "1"}
|
95
|
+
@article_params = {:controller => 'articles', :action => "show", :section_id => "1", :id => "1"}
|
96
|
+
@locale_filter = @set.filters.first
|
97
|
+
@pagination_filter = @set.filters.last
|
98
|
+
end
|
99
|
+
|
100
|
+
def with_deactivated_filters(*filters, &block)
|
101
|
+
states = filters.inject({}) do |states, filter|
|
102
|
+
states[filter], filter.active = filter.active, false
|
103
|
+
states
|
104
|
+
end
|
105
|
+
yield
|
106
|
+
states.each { |filter, state| filter.active = state }
|
107
|
+
end
|
108
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: svenfuchs-routing-filter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sven Fuchs
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-26 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: routing-filter wraps around the complex beast that the Rails routing system is, allowing for unseen flexibility and power in Rails URL recognition and generation.
|
17
|
+
email: svenfuchs@artweb-design.de
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.markdown
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.markdown
|
28
|
+
- VERSION
|
29
|
+
- init.rb
|
30
|
+
- lib/routing_filter.rb
|
31
|
+
- lib/routing_filter/base.rb
|
32
|
+
- lib/routing_filter/force_extension.rb
|
33
|
+
- lib/routing_filter/locale.rb
|
34
|
+
- lib/routing_filter/pagination.rb
|
35
|
+
- spec/force_extension_spec.rb
|
36
|
+
- spec/generation_spec.rb
|
37
|
+
- spec/pagination_extension_spec.rb
|
38
|
+
- spec/recognition_spec.rb
|
39
|
+
- spec/routing_filter_spec.rb
|
40
|
+
- spec/spec.opts
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
has_rdoc: false
|
43
|
+
homepage: http://github.com/svenfuchs/routing-filter
|
44
|
+
licenses:
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options:
|
47
|
+
- --charset=UTF-8
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.3.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: routing-filter wraps around the complex beast that the Rails routing system is, allowing for unseen flexibility and power in Rails URL recognition and generation.
|
69
|
+
test_files:
|
70
|
+
- spec/force_extension_spec.rb
|
71
|
+
- spec/generation_spec.rb
|
72
|
+
- spec/pagination_extension_spec.rb
|
73
|
+
- spec/recognition_spec.rb
|
74
|
+
- spec/routing_filter_spec.rb
|
75
|
+
- spec/spec_helper.rb
|