sayso-routing-filter 0.2.2.001
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/Gemfile +8 -0
- data/Gemfile.lock +82 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +204 -0
- data/lib/routing-filter.rb +1 -0
- data/lib/routing_filter.rb +28 -0
- data/lib/routing_filter/adapters/rails_2.rb +69 -0
- data/lib/routing_filter/adapters/rails_3.rb +77 -0
- data/lib/routing_filter/chain.rb +22 -0
- data/lib/routing_filter/filter.rb +37 -0
- data/lib/routing_filter/filters/extension.rb +76 -0
- data/lib/routing_filter/filters/language.rb +88 -0
- data/lib/routing_filter/filters/locale.rb +83 -0
- data/lib/routing_filter/filters/pagination.rb +47 -0
- data/lib/routing_filter/filters/uuid.rb +40 -0
- data/lib/routing_filter/version.rb +3 -0
- data/test/all.rb +1 -0
- data/test/filters/all_filters/generation.rb +42 -0
- data/test/filters/all_filters/recognition.rb +92 -0
- data/test/filters/all_filters_test.rb +25 -0
- data/test/filters/extension_test.rb +54 -0
- data/test/filters/locale_test.rb +69 -0
- data/test/filters/pagination_test.rb +29 -0
- data/test/filters/uuid_test.rb +40 -0
- data/test/rails_test.rb +92 -0
- data/test/routes_test.rb +31 -0
- data/test/routing_filter_test.rb +47 -0
- data/test/test_adapters/rails_2.rb +17 -0
- data/test/test_adapters/rails_3.rb +28 -0
- data/test/test_helper.rb +41 -0
- metadata +139 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module RoutingFilter
|
2
|
+
class Chain < Array
|
3
|
+
def <<(filter)
|
4
|
+
filter.previous, last.next = last, filter if last
|
5
|
+
super
|
6
|
+
end
|
7
|
+
alias push <<
|
8
|
+
|
9
|
+
def unshift(filter)
|
10
|
+
filter.next, first.previous = first, filter if first
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(method, *args, &final)
|
15
|
+
active? ? first.run(method, *args, &final) : final.call
|
16
|
+
end
|
17
|
+
|
18
|
+
def active?
|
19
|
+
RoutingFilter.active? && !empty?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RoutingFilter
|
2
|
+
class Filter
|
3
|
+
attr_accessor :next, :previous, :options
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(method, *args, &block)
|
10
|
+
_next = self.next ? proc {|path, env| self.next.run(method, *args, &block) } : block
|
11
|
+
RoutingFilter.active? ? send(method, *args, &_next) : _next.call(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_reverse(method, *args, &block)
|
15
|
+
_prev = previous ? lambda { previous.run_reverse(method, *args, &block) } : block
|
16
|
+
RoutingFilter.active? ? send(method, *args, &_prev) : _prev.call(*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def extract_segment!(pattern, path)
|
22
|
+
path.sub!(pattern) { $2 || '' }
|
23
|
+
path.replace('/') if path.empty?
|
24
|
+
$1
|
25
|
+
end
|
26
|
+
|
27
|
+
def prepend_segment!(result, segment)
|
28
|
+
url = result.is_a?(Array) ? result.first : result
|
29
|
+
url.sub!(%r(^(http.?://[^/]*)?(.*))) { "#{$1}/#{segment}#{$2 == '/' ? '' : $2}" }
|
30
|
+
end
|
31
|
+
|
32
|
+
def append_segment!(result, segment)
|
33
|
+
url = result.is_a?(Array) ? result.first : result
|
34
|
+
url.sub!(%r(/?($|\?))) { "/#{segment}#{$1}" }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# The Extension filter chops a file extension off from the end of the
|
2
|
+
# recognized path. When a path is generated the filter re-adds the extension
|
3
|
+
# to the path accordingly.
|
4
|
+
#
|
5
|
+
# incoming url: /de/products/page/1
|
6
|
+
# filtered url: /de/products
|
7
|
+
# params: params[:locale] = 'de'
|
8
|
+
#
|
9
|
+
# You can install the filter like this:
|
10
|
+
#
|
11
|
+
# # in config/routes.rb
|
12
|
+
# Rails.application.routes.draw do
|
13
|
+
# filter :locale
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# To make your named_route helpers or url_for add the pagination segments you
|
17
|
+
# can use:
|
18
|
+
#
|
19
|
+
# products_path(:locale => 'de')
|
20
|
+
# url_for(:products, :locale => 'de'))
|
21
|
+
|
22
|
+
module RoutingFilter
|
23
|
+
class Extension < Filter
|
24
|
+
attr_reader :extension, :exclude
|
25
|
+
|
26
|
+
def initialize(*args)
|
27
|
+
super
|
28
|
+
@exclude = options[:exclude]
|
29
|
+
@extension = options[:extension] || 'html'
|
30
|
+
end
|
31
|
+
|
32
|
+
def around_recognize(path, env, &block)
|
33
|
+
extract_extension!(path) unless excluded?(path)
|
34
|
+
yield(path, env)
|
35
|
+
end
|
36
|
+
|
37
|
+
def around_generate(params, &block)
|
38
|
+
yield.tap do |result|
|
39
|
+
url = result.is_a?(Array) ? result.first : result
|
40
|
+
append_extension!(url) if append_extension?(url)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def extract_extension!(path)
|
47
|
+
path.sub!(/\.#{extension}$/, '')
|
48
|
+
$1
|
49
|
+
end
|
50
|
+
|
51
|
+
def append_extension?(url)
|
52
|
+
!(blank?(url) || excluded?(url) || mime_extension?(url))
|
53
|
+
end
|
54
|
+
|
55
|
+
def append_extension!(url)
|
56
|
+
url.replace url.sub(/(\?|$)/, ".#{extension}\\1")
|
57
|
+
end
|
58
|
+
|
59
|
+
def blank?(url)
|
60
|
+
url.blank? || !!url.match(%r(^/(\?|$)))
|
61
|
+
end
|
62
|
+
|
63
|
+
def excluded?(url)
|
64
|
+
case exclude
|
65
|
+
when Regexp
|
66
|
+
url =~ exclude
|
67
|
+
when Proc
|
68
|
+
exclude.call(url)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def mime_extension?(url)
|
73
|
+
url =~ /\.#{Mime::EXTENSION_LOOKUP.keys.join('|')}(\?|$)/
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# The language filter extracts segments matching /:language from the beginning of
|
2
|
+
# the recognized path and exposes the page parameter as params[:page]. When a
|
3
|
+
# path is generated the filter adds the segments to the path accordingly if
|
4
|
+
# the page parameter is passed to the url helper.
|
5
|
+
#
|
6
|
+
# incoming url: /de/products/page/1
|
7
|
+
# filtered url: /de/products
|
8
|
+
# params: params[:language] = 'de'
|
9
|
+
#
|
10
|
+
# You can install the filter like this:
|
11
|
+
#
|
12
|
+
# # in config/routes.rb
|
13
|
+
# Rails.application.routes.draw do
|
14
|
+
# filter :language
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# To make your named_route helpers or url_for add the pagination segments you
|
18
|
+
# can use:
|
19
|
+
#
|
20
|
+
# products_path(:language => 'de')
|
21
|
+
# url_for(:products, :language => 'de'))
|
22
|
+
|
23
|
+
require 'i18n'
|
24
|
+
|
25
|
+
module RoutingFilter
|
26
|
+
class Language < Filter
|
27
|
+
@@include_default_language = true
|
28
|
+
cattr_writer :include_default_language
|
29
|
+
|
30
|
+
class << self
|
31
|
+
def include_default_language?
|
32
|
+
@@include_default_language
|
33
|
+
end
|
34
|
+
|
35
|
+
def languages
|
36
|
+
@@languages ||= I18n.available_locales.map{|l| l.to_sym}
|
37
|
+
end
|
38
|
+
|
39
|
+
def languages=(languages)
|
40
|
+
@@languages = languages.map(&:to_sym)
|
41
|
+
end
|
42
|
+
|
43
|
+
#redefine original method to support locales like en-RU etc
|
44
|
+
def languages_pattern
|
45
|
+
@@languages_pattern ||= %r(^/(#{self.languages.map{|l| Regexp.escape(l.to_s).sub(/[A-Z]{2}$/,"[A-Z]{2}")}.join('|')})(?=/|$))
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def around_recognize(path, env, &block)
|
51
|
+
language = extract_segment!(self.class.languages_pattern, path) # remove the language from the beginning of the path
|
52
|
+
yield.tap do |params| # invoke the given block (calls more filters and finally routing)
|
53
|
+
params[:language] = language if language # set recognized language to the resulting params hash
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def around_generate(*args, &block)
|
58
|
+
params = args.extract_options! # this is because we might get a call like forum_topics_path(forum, topic, :language => :en)
|
59
|
+
|
60
|
+
language = params[:language] # extract the passed :language option
|
61
|
+
language = I18n.locale if language.nil? # default to I18n.locale when language is nil (could also be false)
|
62
|
+
language = I18n.lang_tag(language) if language
|
63
|
+
language = nil unless valid_language?(language) # reset to no language when language is not valid
|
64
|
+
|
65
|
+
params.delete(:language) unless configatron.prevent_deleting_language_param
|
66
|
+
|
67
|
+
args << params
|
68
|
+
|
69
|
+
yield.tap do |result|
|
70
|
+
prepend_segment!(result, language) if prepend_language?(language)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def valid_language?(language)
|
77
|
+
language && self.class.languages.include?(language.to_sym)
|
78
|
+
end
|
79
|
+
|
80
|
+
def default_language?(language)
|
81
|
+
language && language.to_sym == I18n.lang_tag(I18n.default_locale).to_sym
|
82
|
+
end
|
83
|
+
|
84
|
+
def prepend_language?(language)
|
85
|
+
language && (self.class.include_default_language? || !default_language?(language))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# The Locale filter extracts segments matching /:locale from the beginning of
|
2
|
+
# the recognized path and exposes the page parameter as params[:page]. When a
|
3
|
+
# path is generated the filter adds the segments to the path accordingly if
|
4
|
+
# the page parameter is passed to the url helper.
|
5
|
+
#
|
6
|
+
# incoming url: /de/products/page/1
|
7
|
+
# filtered url: /de/products
|
8
|
+
# params: params[:locale] = 'de'
|
9
|
+
#
|
10
|
+
# You can install the filter like this:
|
11
|
+
#
|
12
|
+
# # in config/routes.rb
|
13
|
+
# Rails.application.routes.draw do
|
14
|
+
# filter :locale
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# To make your named_route helpers or url_for add the pagination segments you
|
18
|
+
# can use:
|
19
|
+
#
|
20
|
+
# products_path(:locale => 'de')
|
21
|
+
# url_for(:products, :locale => 'de'))
|
22
|
+
|
23
|
+
require 'i18n'
|
24
|
+
|
25
|
+
module RoutingFilter
|
26
|
+
class Locale < Filter
|
27
|
+
@@include_default_locale = true
|
28
|
+
cattr_writer :include_default_locale
|
29
|
+
|
30
|
+
class << self
|
31
|
+
def include_default_locale?
|
32
|
+
@@include_default_locale
|
33
|
+
end
|
34
|
+
|
35
|
+
def locales
|
36
|
+
@@locales ||= I18n.available_locales.map(&:to_sym)
|
37
|
+
end
|
38
|
+
|
39
|
+
def locales=(locales)
|
40
|
+
@@locales = locales.map(&:to_sym)
|
41
|
+
end
|
42
|
+
|
43
|
+
def locales_pattern
|
44
|
+
@@locales_pattern ||= %r(^/(#{self.locales.map { |l| Regexp.escape(l.to_s) }.join('|')})(?=/|$))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def around_recognize(path, env, &block)
|
49
|
+
locale = extract_segment!(self.class.locales_pattern, path) # remove the locale from the beginning of the path
|
50
|
+
yield.tap do |params| # invoke the given block (calls more filters and finally routing)
|
51
|
+
params[:locale] = locale if locale # set recognized locale to the resulting params hash
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def around_generate(*args, &block)
|
56
|
+
params = args.extract_options! # this is because we might get a call like forum_topics_path(forum, topic, :locale => :en)
|
57
|
+
|
58
|
+
locale = params.delete(:locale) # extract the passed :locale option
|
59
|
+
locale = I18n.locale if locale.nil? # default to I18n.locale when locale is nil (could also be false)
|
60
|
+
locale = nil unless valid_locale?(locale) # reset to no locale when locale is not valid
|
61
|
+
|
62
|
+
args << params
|
63
|
+
|
64
|
+
yield.tap do |result|
|
65
|
+
prepend_segment!(result, locale) if prepend_locale?(locale)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
def valid_locale?(locale)
|
72
|
+
locale && self.class.locales.include?(locale.to_sym)
|
73
|
+
end
|
74
|
+
|
75
|
+
def default_locale?(locale)
|
76
|
+
locale && locale.to_sym == I18n.default_locale.to_sym
|
77
|
+
end
|
78
|
+
|
79
|
+
def prepend_locale?(locale)
|
80
|
+
locale && (self.class.include_default_locale? || !default_locale?(locale))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# The Pagination filter extracts segments matching /page/:page from the end of
|
2
|
+
# the recognized url and exposes the page parameter as params[:page]. When a
|
3
|
+
# url is generated the filter adds the segments to the url accordingly if the
|
4
|
+
# page parameter is passed to the url helper.
|
5
|
+
#
|
6
|
+
# incoming url: /products/page/1
|
7
|
+
# filtered url: /products
|
8
|
+
# params: params[:page] = 1
|
9
|
+
#
|
10
|
+
# You can install the filter like this:
|
11
|
+
#
|
12
|
+
# # in config/routes.rb
|
13
|
+
# Rails.application.routes.draw do
|
14
|
+
# filter :pagination
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# To make your named_route helpers or url_for add the pagination segments you
|
18
|
+
# can use:
|
19
|
+
#
|
20
|
+
# products_path(:page => 1)
|
21
|
+
# url_for(:products, :page => 1)
|
22
|
+
|
23
|
+
module RoutingFilter
|
24
|
+
class Pagination < Filter
|
25
|
+
PAGINATION_SEGMENT = %r(/page/([\d]+)/?$)
|
26
|
+
|
27
|
+
def around_recognize(path, env, &block)
|
28
|
+
page = extract_segment!(PAGINATION_SEGMENT, path)
|
29
|
+
yield(path, env).tap do |params|
|
30
|
+
params[:page] = page.to_i if page
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def around_generate(params, &block)
|
35
|
+
page = params.delete(:page)
|
36
|
+
yield.tap do |result|
|
37
|
+
append_segment!(result, "page/#{page}") if append_page?(page)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def append_page?(page)
|
44
|
+
page && page.to_i != 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# The Uuid filter extracts an UUID segment from the beginning of the recognized
|
2
|
+
# path and exposes the page parameter as params[:page]. When a path is generated
|
3
|
+
# the filter adds the segments to the path accordingly if the page parameter is
|
4
|
+
# passed to the url helper.
|
5
|
+
#
|
6
|
+
# incoming url: /d00fbbd1-82b6-4c1a-a57d-098d529d6854/product/1
|
7
|
+
# filtered url: /product/1
|
8
|
+
# params: params[:uuid] = 'd00fbbd1-82b6-4c1a-a57d-098d529d6854'
|
9
|
+
#
|
10
|
+
# You can install the filter like this:
|
11
|
+
#
|
12
|
+
# # in config/routes.rb
|
13
|
+
# Rails.application.routes.draw do
|
14
|
+
# filter :uuid
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# To make your named_route helpers or url_for add the uuid segment you can use:
|
18
|
+
#
|
19
|
+
# product_path(:uuid => uuid)
|
20
|
+
# url_for(product, :uuid => uuid)
|
21
|
+
|
22
|
+
module RoutingFilter
|
23
|
+
class Uuid < Filter
|
24
|
+
UUID_SEGMENT = %r(^/?([a-z\d]{8}\-[a-z\d]{4}\-[a-z\d]{4}\-[a-z\d]{4}\-[a-z\d]{12})(/)?)
|
25
|
+
|
26
|
+
def around_recognize(path, env, &block)
|
27
|
+
uuid = extract_segment!(UUID_SEGMENT, path)
|
28
|
+
yield.tap do |params|
|
29
|
+
params[:uuid] = uuid if uuid
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def around_generate(params, &block)
|
34
|
+
uuid = params.delete(:uuid)
|
35
|
+
yield.tap do |result|
|
36
|
+
prepend_segment!(result, uuid) if uuid
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/test/all.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.expand_path('../**/*_test.rb', __FILE__)].each { |file| require file }
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Generation
|
2
|
+
test 'generates the path /some.html (extension)' do
|
3
|
+
params = self.params
|
4
|
+
assert_equal '/some.html', routes.generate(params)
|
5
|
+
end
|
6
|
+
|
7
|
+
# extension with any
|
8
|
+
|
9
|
+
test 'generates the path /de/some (extension, locale)' do
|
10
|
+
params = self.params.merge(:locale => 'de')
|
11
|
+
assert_equal '/de/some.html', routes.generate(params)
|
12
|
+
end
|
13
|
+
|
14
|
+
test 'generates the path /some/page/2 (extension, pagination)' do
|
15
|
+
params = self.params.merge(:page => 2)
|
16
|
+
assert_equal '/some/page/2.html', routes.generate(params)
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'generates the path /:uuid/some (extension, uuid)' do
|
20
|
+
params = self.params.merge(:uuid => uuid)
|
21
|
+
assert_equal "/#{uuid}/some.html", routes.generate(params)
|
22
|
+
end
|
23
|
+
|
24
|
+
# extension, locale with any
|
25
|
+
|
26
|
+
test 'generates the path /de/some/page/2 (extension, locale, pagination)' do
|
27
|
+
params = self.params.merge(:locale => 'de', :page => 2)
|
28
|
+
assert_equal '/de/some/page/2.html', routes.generate(params)
|
29
|
+
end
|
30
|
+
|
31
|
+
test 'generates the path /de/:uuid/some (extension, locale, uuid)' do
|
32
|
+
params = self.params.merge(:locale => 'de', :uuid => uuid)
|
33
|
+
assert_equal "/de/#{uuid}/some.html", routes.generate(params)
|
34
|
+
end
|
35
|
+
|
36
|
+
# all
|
37
|
+
|
38
|
+
test 'generates the path /de/some/page/2 (extension, pagination, uuid)' do
|
39
|
+
params = self.params.merge(:locale => 'de', :page => 2, :uuid => uuid)
|
40
|
+
assert_equal "/de/#{uuid}/some/page/2.html", routes.generate(params)
|
41
|
+
end
|
42
|
+
end
|