rewritten 0.13.1 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ec0125862e538037c12d709768eda65cf08e3cb6
4
- data.tar.gz: d02def0f2df7280603224f60e4c709844c1b56fe
3
+ metadata.gz: 183b54cd40ae90c9d26c6a4a2c804535003746a6
4
+ data.tar.gz: da104eb558ac511ef8ac843b9d25fd62ba8830db
5
5
  SHA512:
6
- metadata.gz: c02e89f98798a7e84e2bab137f3ef0d54c99376928adaac861c398434df0c18704155ca4b7bd4a9860df4bd169443b08a9b585d6ccef682148c6ed8306a84012
7
- data.tar.gz: a4d30fd8357c5ff63cac5de1592d52c3cc0bf95450d1da298ed68b12a602de080cb36206f6dbd7577f04975d0cb233966825dc6387454f3dcb53b55dd1f1c6d4
6
+ metadata.gz: e65d6785aadee1b61335933615ae6bdd3d702e47164103703a755f7aa5ad0da9cfce84ed2e66777b865db879d762a9e27208fdd0fd857f0bd723ec25335d55a8
7
+ data.tar.gz: 63a5a104a68963b837ddc220bd7c98776ef01676eb04d4bd886c527a07feb7ebe78652ac12bd00a638f99b4504bae66170e4c57cd60e38d3704794e0abd00876
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
4
+ services:
5
+ - redis-server
6
+
data/HISTORY.rdoc CHANGED
@@ -1,3 +1,6 @@
1
+ == 0.14.0
2
+ * Extract canonical to own rack app
3
+
1
4
  == 0.13.0
2
5
  * Find translations even for absolute urls and urls with query parameters
3
6
 
@@ -0,0 +1,45 @@
1
+ require 'rack'
2
+
3
+ module Rack
4
+
5
+ module Rewritten
6
+
7
+ class Canonical
8
+
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def call(env)
14
+ req = Rack::Request.new(env)
15
+
16
+ status, headers, response = @app.call(req.env)
17
+
18
+ if status == 200 && headers["Content-Type"] =~ /text\/html|application\/xhtml\+xml/
19
+ body = ""
20
+ response.each { |part| body << part }
21
+ index = body.rindex("</head>")
22
+ if index
23
+ # go with a request duplicate since infinitive works on translations
24
+ target_req = req.dup
25
+ target_req.path_info = ::Rewritten.infinitive( ::Rewritten.get_current_translation(req.path) )
26
+ target_req.env['QUERY_STRING'] = ''
27
+ #target = ::Rewritten.get_current_translation(target_req.url)
28
+ target = target_req.url
29
+
30
+ body.insert(index, %Q|<link rel="canonical" href="#{target}"/>| )
31
+ headers["Content-Length"] = body.length.to_s
32
+ response = [body]
33
+ end
34
+
35
+ [status, headers, response]
36
+ end
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+
data/lib/rack/url.rb CHANGED
@@ -11,11 +11,10 @@ module Rack
11
11
  @translate_backwards = false
12
12
  @downcase_before_lookup = false
13
13
  @translate_partial = false
14
-
15
14
  instance_eval(&block) if block_given?
16
15
  end
17
16
 
18
- def call(env, tail=nil)
17
+ def call(env)
19
18
  req = Rack::Request.new(env)
20
19
 
21
20
  subdomain = env["SUBDOMAIN"] ? "#{env["SUBDOMAIN"]}:" : ""
@@ -23,7 +22,7 @@ module Rack
23
22
  path = "#{subdomain}#{req.path_info}"
24
23
  path.downcase! if downcase_before_lookup?
25
24
 
26
- if ::Rewritten.includes?(path.chomp("/")) or translate_backwards? && ::Rewritten.exist_translation_for?(path)
25
+ if ::Rewritten.includes?(path.chomp("/")) or backwards=( translate_backwards? && ::Rewritten.exist_translation_for?(path) )
27
26
 
28
27
  to = ::Rewritten.includes?(path.chomp("/")) || path
29
28
 
@@ -31,30 +30,13 @@ module Rack
31
30
  current_path = current_path.split(":").last
32
31
  current_path = current_path.split('?')[0]
33
32
 
34
- if current_path == req.path_info or ::Rewritten.has_flag?(path, 'L')
33
+ if (current_path == req.path_info) or (::Rewritten.base_from(req.path_info) == current_path) or ::Rewritten.has_flag?(path, 'L')
35
34
  # if this is the current path, rewrite path and parameters
36
35
  tpath, tparams = split_to_path_params(to)
37
36
 
38
37
  env['QUERY_STRING'] = Rack::Utils.build_query(tparams.merge(req.params))
39
- req.path_info = tpath + (tail ? "/"+tail : "")
40
- #@app.call(req.env)
41
-
42
- # add the canonical tag to the body
43
- status, headers, response = @app.call(req.env)
44
-
45
- if status == 200 && headers["Content-Type"] =~ /text\/html|application\/xhtml\+xml/
46
- body = ""
47
- response.each { |part| body << part }
48
- index = body.rindex("</head>")
49
- if index
50
- body.insert(index, %Q|<link rel="canonical" href="#{path}"/>| )
51
- headers["Content-Length"] = body.length.to_s
52
- response = [body]
53
- end
54
- end
55
-
56
- [status, headers, response]
57
-
38
+ req.path_info = tpath + ::Rewritten.appendix(req.path_info)
39
+ @app.call(req.env)
58
40
  else
59
41
  # if this is not the current path, redirect to current path
60
42
  # NOTE: assuming redirection is always to non-subdomain-path
@@ -64,23 +46,15 @@ module Rack
64
46
  new_path = env["rack.url_scheme"].dup
65
47
  new_path << "://"
66
48
  new_path << env["HTTP_HOST"].dup.sub(/^#{subdomain.chomp(':')}\./, '')
67
- new_path << current_path + (tail ? "/"+tail : "")
49
+ new_path << current_path
50
+ new_path << ::Rewritten.appendix(path) unless backwards
68
51
  new_path << '?' << env["QUERY_STRING"] unless (env["QUERY_STRING"]||'').empty?
69
52
 
70
53
  r.redirect(new_path, 301)
71
54
  a = r.finish
72
55
  end
73
56
  else
74
- # Translation of partials (e.g. /some/path/tail -> /translated/path/tail)
75
- if(path).count('/') > 1 && translate_partial?
76
- parts = path.split('/')
77
- req.path_info = parts.slice(0, parts.size-1).join('/')
78
- self.call(req.env, parts.last + (tail ? "/" + tail : ""))
79
- else
80
- req.path_info = (tail ? req.path_info+"/"+tail : req.path_info)
81
- @app.call(req.env)
82
-
83
- end
57
+ @app.call(req.env)
84
58
  end
85
59
  end
86
60
 
@@ -89,7 +63,6 @@ module Rack
89
63
  [path, Rack::Utils.parse_query(query_string)]
90
64
  end
91
65
 
92
-
93
66
  private
94
67
 
95
68
  def translate_backwards?
@@ -113,7 +86,8 @@ module Rack
113
86
  end
114
87
 
115
88
  def translate_partial=(yes_or_no)
116
- @translate_partial = yes_or_no
89
+ $stderr.puts "DEPRECATED. Please use Rewritten.translate_partial"
90
+ Rewritten.translate_partial = yes_or_no
117
91
  end
118
92
  end
119
93
  end
@@ -1,4 +1,4 @@
1
1
  module Rewritten
2
- VERSION = "0.13.1"
2
+ VERSION = "0.14.0"
3
3
  end
4
4
 
data/lib/rewritten.rb CHANGED
@@ -6,6 +6,7 @@ require 'rack/url'
6
6
  require 'rack/record'
7
7
  require 'rack/html'
8
8
  require 'rack/subdomain'
9
+ require 'rack/canonical'
9
10
  require 'rewritten/document'
10
11
 
11
12
  module Rewritten
@@ -40,6 +41,14 @@ module Rewritten
40
41
  end
41
42
  end
42
43
 
44
+ def translate_partial=(yes_or_no)
45
+ @translate_partial = yes_or_no
46
+ end
47
+
48
+ def translate_partial?
49
+ @translate_partial
50
+ end
51
+
43
52
  # Returns the current Redis connection. If none has been created, will
44
53
  # create a new one.
45
54
  def redis
@@ -186,26 +195,75 @@ module Rewritten
186
195
  Rewritten.redis.zrange("to:#{to}", 0, -1)
187
196
  end
188
197
 
189
- def get_current_translation(path)
198
+ def get_current_translation(path, tail=nil)
190
199
 
191
200
  uri = URI.parse(path)
192
201
 
202
+ # find directly
193
203
  translation = Rewritten.z_range("to:#{path}", -1)
194
-
204
+
195
205
  unless translation
196
206
  translation = Rewritten.z_range("to:#{uri.path}", -1)
197
207
  end
198
208
 
199
- # return path as is if no translation found
200
- return path unless translation
209
+ if translation.nil?
210
+ if translate_partial? && path.count('/') > 1
211
+ parts = path.split('/')
212
+ shorter_path = parts.slice(0, parts.size-1).join('/')
213
+ appendix = parts.last + (tail ? "/" + tail : "")
214
+ return get_current_translation(shorter_path, appendix)
215
+ else
216
+ return path
217
+ end
218
+ end
201
219
 
202
- translated_uri = URI.parse(translation)
220
+ complete_path = (tail ? translation+"/"+tail : translation)
221
+ translated_uri = URI.parse(complete_path)
203
222
  uri.path = translated_uri.path
204
223
  uri.query = [translated_uri.query, uri.query].compact.join('&')
205
224
  uri.query = nil if uri.query == ''
206
225
  uri.to_s
207
226
  end
208
227
 
228
+
229
+ # infinitive for translations only!
230
+ def infinitive(some_from)
231
+
232
+ conjugated = some_from.chomp('/')
233
+
234
+ to = translate(conjugated)
235
+ to = translate(conjugated.split('?')[0]) unless to
236
+
237
+ if to.nil? && translate_partial? && conjugated.count('/') > 1
238
+ parts = conjugated.split('/')
239
+ shorter_path = parts.slice(0, parts.size-1).join('/')
240
+ infinitive(shorter_path)
241
+ else
242
+ conjugated = get_current_translation(to) if to
243
+ conjugated.split('?')[0].chomp('/')
244
+ end
245
+ end
246
+
247
+ def base_from(some_from)
248
+ base_from = some_from.split('?')[0].chomp('/')
249
+ if translate(some_from)
250
+ some_from
251
+ elsif translate(base_from)
252
+ base_from
253
+ elsif translate_partial? && base_from.count('/') > 1
254
+ parts = base_from.split('/')
255
+ base_from(parts.slice(0,parts.size-1).join('/'))
256
+ else
257
+ nil
258
+ end
259
+ end
260
+
261
+ def appendix(some_from)
262
+ base = base_from(some_from) || ''
263
+ result = some_from.partition( base ).last
264
+ result.chomp('/')
265
+ end
266
+
209
267
  def get_flag_string(from)
210
268
  Rewritten.redis.hget("from:#{from}", :flags)||""
211
269
  end
@@ -240,7 +298,17 @@ module Rewritten
240
298
  end
241
299
 
242
300
  def includes?(path)
243
- Rewritten.redis.hget("from:#{path}", :to)
301
+
302
+ result = Rewritten.redis.hget("from:#{path.chomp('/')}", :to)
303
+ result = Rewritten.redis.hget("from:#{path.split('?')[0]}", :to) unless result
304
+
305
+ if result.nil? && translate_partial? && path.count('/') > 1
306
+ parts = path.split('/')
307
+ includes?( parts.slice(0,parts.size-1).join('/') )
308
+ else
309
+ result
310
+ end
311
+
244
312
  end
245
313
 
246
314
  # return the number of froms
@@ -0,0 +1,65 @@
1
+ require 'test_helper'
2
+
3
+ describe Rack::Rewritten::Canonical do
4
+
5
+ def call_args(overrides={})
6
+ {'HTTP_HOST' => 'www.example.org',
7
+ 'REQUEST_URI' => '/foo/with/params',
8
+ 'SCRIPT_INFO'=> '',
9
+ 'PATH_INFO' => '/foo/with/params',
10
+ 'QUERY_STRING' => '',
11
+ 'SERVER_PORT' => 80,
12
+ 'rack.input' => '',
13
+ 'rack.url_scheme' => 'http'}.merge(overrides)
14
+ end
15
+
16
+ def request_url(url, params={})
17
+ call_args.merge({'REQUEST_URI' => url, 'PATH_INFO' => url}.merge(params) )
18
+ end
19
+
20
+
21
+ before do
22
+ Rewritten.add_translation '/foo/bar', '/products/1'
23
+ Rewritten.add_translation '/foo/baz', '/products/1'
24
+ Rewritten.add_translation '/foo/with/params', '/products/2?w=1'
25
+
26
+ @html_body = <<-HTML
27
+ <html>
28
+ <head></head>
29
+ <body>Hello</body>
30
+ </html>
31
+ HTML
32
+ @rack = Rack::Rewritten::Canonical.new(lambda{|env| [200, {'Content-Type' => 'text/html'}, [@html_body]]})
33
+
34
+ end
35
+
36
+ describe 'canonical tag' do
37
+
38
+ it "must add the canonical tag to current translation if on non-translated page" do
39
+ res,env,body = @rack.call request_url('/products/1')
40
+ html = body.join("")
41
+ html.must_include '<link rel="canonical" href="http://www.example.org/foo/baz"/>'
42
+ end
43
+
44
+ it "the target of the canonical tag must have no params" do
45
+ res,env,body = @rack.call request_url('/products/1').merge('QUERY_STRING' => 'some=param' )
46
+ html = body.join("")
47
+ html.must_include '<link rel="canonical" href="http://www.example.org/foo/baz"/>'
48
+ end
49
+
50
+ describe 'context partial' do
51
+ before{ Rewritten.translate_partial = true }
52
+ after{ Rewritten.translate_partial = false }
53
+
54
+ it "must add the canonical tag to pages with tail" do
55
+ res,env,body = @rack.call request_url('/products/1/with/tail')
56
+ html = body.join("")
57
+ html.must_include '<link rel="canonical" href="http://www.example.org/foo/baz"/>'
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
@@ -8,6 +8,7 @@ describe Rack::Rewritten::Url do
8
8
  'SCRIPT_INFO'=> '',
9
9
  'PATH_INFO' => '/foo/with/params',
10
10
  'QUERY_STRING' => '',
11
+ 'SERVER_PORT' => 80,
11
12
  'rack.input' => '',
12
13
  'rack.url_scheme' => 'http'}.merge(overrides)
13
14
  end
@@ -62,18 +63,20 @@ describe Rack::Rewritten::Url do
62
63
 
63
64
  describe "partial translation" do
64
65
 
65
- before {
66
+ before do
66
67
  @request_str = '/foo/baz/with_tail'
67
68
  @env = request_url(@request_str)
68
- @html_body = <<-HTML
69
- <html>
70
- <head></head>
71
- <body>Hello</body>
72
- </html>
73
- HTML
74
- }
69
+ Rewritten.translate_partial = true
70
+ end
71
+
72
+ after do
73
+ Rewritten.translate_partial = false
74
+ end
75
+
76
+ after{ Rewritten.translate_partial = false }
75
77
 
76
78
  it "must not translate partials by default" do
79
+ Rewritten.translate_partial = false
77
80
  @app.expect :call, [200, {'Content-Type' => 'text/plain'},[""]], [Hash]
78
81
  ret = @rack.call @env
79
82
  @app.verify
@@ -81,21 +84,14 @@ describe Rack::Rewritten::Url do
81
84
  end
82
85
 
83
86
  it "must translate partials if enabled" do
84
- @rack = Rack::Rewritten::Url.new(@app) do
85
- self.translate_partial = true
86
- end
87
-
87
+ Rewritten.translate_partial = true
88
88
  @app.expect :call, [200, {'Content-Type' => 'text/html'},[]], [Hash]
89
-
90
89
  ret = @rack.call @env
91
90
  @app.verify
92
91
  @env['PATH_INFO'].must_equal '/products/1/with_tail'
93
92
  end
94
93
 
95
94
  it "must work on long, non-translated urls with partial translation enabled" do
96
- @rack = Rack::Rewritten::Url.new(@app) do
97
- self.translate_partial = true
98
- end
99
95
 
100
96
  @app.expect :call, [200, {'Content-Type' => 'text/html'},[]], [Hash]
101
97
 
@@ -107,21 +103,8 @@ describe Rack::Rewritten::Url do
107
103
  @env['PATH_INFO'].must_equal url
108
104
  end
109
105
 
110
- it "must add the canonical tag to pages with trail" do
111
-
112
- @rack = Rack::Rewritten::Url.new(lambda{|env| [200, {'Content-Type' => 'text/html'}, [@html_body]]}) do
113
- self.translate_partial = true
114
- end
115
-
116
- res,env,body = @rack.call(@env)
117
- html = body.join("")
118
- html.must_include '<link rel="canonical" href="/foo/baz"/>'
119
- end
120
-
106
+
121
107
  it "won't translate segments not by separated by slashes" do
122
- @rack = Rack::Rewritten::Url.new(@app) do
123
- self.translate_partial = true
124
- end
125
108
  @app.expect :call, [200, {'Content-Type' => 'text/plain'},[""]], [Hash]
126
109
  ret = @rack.call @env=request_url('/foo/bazzling')
127
110
  @app.verify
@@ -129,15 +112,11 @@ describe Rack::Rewritten::Url do
129
112
  end
130
113
 
131
114
  it "must carry on trail when redirecting" do
132
- @rack = Rack::Rewritten::Url.new(@app) do
133
- self.translate_partial = true
134
- end
135
115
  ret = @rack.call request_url('/foo/bar/with_tail', 'QUERY_STRING' => 'w=1')
136
116
  @app.verify
137
117
  ret[0].must_equal 301
138
118
  ret[1]['Location'].must_equal "http://www.example.org/foo/baz/with_tail?w=1"
139
119
  end
140
-
141
120
  end
142
121
 
143
122
  describe "/ behavior" do
@@ -11,7 +11,7 @@ describe Rewritten do
11
11
  Rewritten.add_translation('/with/flags [L12]', '/to3')
12
12
  }
13
13
 
14
- describe 'Rewritten.get_current_translation' do
14
+ describe 'Rewritten.get_current_translation for to-target' do
15
15
 
16
16
  it "must give current_translation" do
17
17
  Rewritten.get_current_translation('/to').must_equal '/from2'
@@ -36,6 +36,31 @@ describe Rewritten do
36
36
 
37
37
  end
38
38
 
39
+ describe 'get_infinitive (always from conjugated for -> for)' do
40
+
41
+ it 'must remove query parameters from non translatable foreign path' do
42
+ Rewritten.infinitive('/no/translation').must_equal '/no/translation'
43
+ Rewritten.infinitive('/no/translation/').must_equal '/no/translation'
44
+ Rewritten.infinitive('/no/translation?some=param&another=2').must_equal '/no/translation'
45
+ end
46
+
47
+ it 'must remove query parameters from translatable foreign path' do
48
+ Rewritten.infinitive('/from').must_equal '/from2'
49
+ Rewritten.infinitive('/from/').must_equal '/from2'
50
+ Rewritten.infinitive('/from?some=param&another=2').must_equal '/from2'
51
+ end
52
+
53
+ describe 'context translate partial' do
54
+ before{ Rewritten.translate_partial = true }
55
+ after{ Rewritten.translate_partial = false }
56
+
57
+ it 'must remove trail if translpartial is enabled' do
58
+ Rewritten.infinitive('/from/with/trail?and=param').must_equal '/from2'
59
+ end
60
+ end
61
+
62
+ end
63
+
39
64
  describe "basic interface" do
40
65
 
41
66
  it "must translate froms" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rewritten
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.1
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kai Rubarth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-15 00:00:00.000000000 Z
11
+ date: 2014-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-namespace
@@ -149,6 +149,7 @@ extensions: []
149
149
  extra_rdoc_files: []
150
150
  files:
151
151
  - ".gitignore"
152
+ - ".travis.yml"
152
153
  - Gemfile
153
154
  - HISTORY.rdoc
154
155
  - README.md
@@ -158,6 +159,7 @@ files:
158
159
  - bin/rewritten-import.rb
159
160
  - bin/rewritten-web.rb
160
161
  - config.ru
162
+ - lib/rack/canonical.rb
161
163
  - lib/rack/dummy.rb
162
164
  - lib/rack/html.rb
163
165
  - lib/rack/record.rb
@@ -197,6 +199,7 @@ files:
197
199
  - lib/rewritten/server/views/translations.erb
198
200
  - lib/rewritten/version.rb
199
201
  - rewritten.gemspec
202
+ - test/rack/rewritten_canonical_test.rb
200
203
  - test/rack/rewritten_html_test.rb
201
204
  - test/rack/rewritten_url_test.rb
202
205
  - test/rewritten/document_test.rb