rewritten 0.13.1 → 0.14.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.
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