shrinker 0.1.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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +83 -0
- data/Rakefile +1 -0
- data/lib/shrinker/backend/abstract.rb +25 -0
- data/lib/shrinker/backend/redis.rb +56 -0
- data/lib/shrinker/config.rb +83 -0
- data/lib/shrinker/easy_url.rb +36 -0
- data/lib/shrinker/extractor.rb +24 -0
- data/lib/shrinker/parser/abstract.rb +58 -0
- data/lib/shrinker/parser/mime.rb +44 -0
- data/lib/shrinker/parser/text.rb +21 -0
- data/lib/shrinker/parser/url.rb +41 -0
- data/lib/shrinker/serializer.rb +20 -0
- data/lib/shrinker/token.rb +23 -0
- data/lib/shrinker/version.rb +13 -0
- data/lib/shrinker.rb +48 -0
- data/shrinker.gemspec +20 -0
- data/spec/lib/backend/redis_spec.rb +77 -0
- data/spec/lib/config_spec.rb +66 -0
- data/spec/lib/easy_url_spec.rb +26 -0
- data/spec/lib/extractor_spec.rb +37 -0
- data/spec/lib/parser/mime_spec.rb +114 -0
- data/spec/lib/parser/text_spec.rb +110 -0
- data/spec/lib/parser/url_spec.rb +118 -0
- data/spec/lib/serializer_spec.rb +23 -0
- data/spec/lib/shrinker_spec.rb +11 -0
- data/spec/lib/token_spec.rb +24 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/fixtures/mime.txt +41 -0
- data/spec/support/fixtures/multipart_mime.txt +88 -0
- metadata +108 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shrinker::Backend::Redis do
|
4
|
+
subject { Shrinker::Backend::Redis.new }
|
5
|
+
|
6
|
+
describe "with options" do
|
7
|
+
let(:options) do
|
8
|
+
{
|
9
|
+
:client => {
|
10
|
+
:login => 'login',
|
11
|
+
:password => 'somepassword',
|
12
|
+
:port => '2331',
|
13
|
+
:host => 'localhost'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
subject { Shrinker::Backend::Redis.new(options) }
|
19
|
+
|
20
|
+
it "uses the options" do
|
21
|
+
Redis.should_receive(:new).with(options[:client])
|
22
|
+
|
23
|
+
subject.send(:client)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with a default client setup" do
|
28
|
+
let(:client) { Redis.new }
|
29
|
+
before { subject.stub(:client) { client} }
|
30
|
+
|
31
|
+
describe "#store" do
|
32
|
+
it "stores the raw_url with the token key" do
|
33
|
+
Shrinker::Serializer.should_receive(:to_json).with('someurl', {}).and_return("tobestored")
|
34
|
+
|
35
|
+
subject.store('someurl', 'token')
|
36
|
+
|
37
|
+
client.get("_shrinker::token").should == 'tobestored'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "stores the raw_url with the attributes" do
|
41
|
+
Shrinker::Serializer.should_receive(:to_json).with('someurl', {:user_id => 123}).and_return("tobestored")
|
42
|
+
|
43
|
+
subject.store('someurl', 'token', :user_id => 123)
|
44
|
+
client.get("_shrinker::token").should == 'tobestored'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "sets the ttl when present" do
|
48
|
+
Shrinker::Serializer.should_receive(:to_json).with('someurl', {}).and_return("tobestored")
|
49
|
+
subject.stub(:ttl) { 32 }
|
50
|
+
client.should_receive(:setex).with("_shrinker::token", 32, "tobestored")
|
51
|
+
|
52
|
+
subject.store('someurl', 'token')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#fetch" do
|
57
|
+
it "fetches using the token key" do
|
58
|
+
client.set("_shrinker::token", '{"url": "someurl", "attributes": {}}')
|
59
|
+
subject.fetch("token").should == {'url' => "someurl", 'attributes' => {}}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#used_token?" do
|
64
|
+
before { subject.send(:delete, 'token') }
|
65
|
+
|
66
|
+
it "returns true when the token is used" do
|
67
|
+
client.set("_shrinker::token", '{"url": "someurl", "attributes": {}}')
|
68
|
+
|
69
|
+
subject.used_token?('token').should be_true
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns false" do
|
73
|
+
subject.used_token?('token').should be_false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shrinker::Config do
|
4
|
+
|
5
|
+
module Shrinker
|
6
|
+
module Backend
|
7
|
+
class FakeBackend < ::Shrinker::Backend::Abstract
|
8
|
+
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:config) { Shrinker.config }
|
14
|
+
|
15
|
+
before do
|
16
|
+
config.reset!
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
config.reset!
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return the config object for manipulation' do
|
24
|
+
config.is_a?(Shrinker::Config).should be_true
|
25
|
+
Shrinker.configure.is_a?(Shrinker::Config).should be_true
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should yield to the config if a block is present' do
|
29
|
+
lambda{
|
30
|
+
Shrinker.configure do
|
31
|
+
raise self.class.name
|
32
|
+
end
|
33
|
+
}.should raise_error('Shrinker::Config')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'allows passing the backend' do
|
37
|
+
Shrinker.configure do
|
38
|
+
backend 'FakeBackend'
|
39
|
+
backend_options({:key => 'value'})
|
40
|
+
end
|
41
|
+
|
42
|
+
Shrinker::Backend::FakeBackend.should_receive(:new).with({:key => 'value'})
|
43
|
+
Shrinker.send(:backend)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#merge!" do
|
47
|
+
it "merges a hash" do
|
48
|
+
config.merge!(backend_options: {something: true})
|
49
|
+
config.backend_options.should == {something: true}
|
50
|
+
end
|
51
|
+
|
52
|
+
it "merges an instance of Config" do
|
53
|
+
config.instance_eval do
|
54
|
+
expanded_pattern 'first_pattern'
|
55
|
+
shrinked_pattern 'shrinked_pattern'
|
56
|
+
end
|
57
|
+
other_config = Shrinker::Config.new
|
58
|
+
other_config.instance_eval do
|
59
|
+
expanded_pattern 'second_pattern'
|
60
|
+
end
|
61
|
+
config.merge!(other_config)
|
62
|
+
config.expanded_pattern.should == 'second_pattern'
|
63
|
+
config.shrinked_pattern.should == 'shrinked_pattern'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shrinker::EasyUrl do
|
4
|
+
describe "#to_s" do
|
5
|
+
it "returns itself with no params" do
|
6
|
+
Shrinker::EasyUrl.new("test").to_s.should == 'test'
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns itself with params" do
|
10
|
+
Shrinker::EasyUrl.new("test?something=2").to_s.should == 'test?something=2'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns itself without the params when deleting it" do
|
14
|
+
easy_url = Shrinker::EasyUrl.new("test?something=2")
|
15
|
+
easy_url.params.delete(:something)
|
16
|
+
easy_url.to_s.should == 'test'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "keeps the other params when deleting some" do
|
20
|
+
easy_url = Shrinker::EasyUrl.new("test?something=2&else=3")
|
21
|
+
easy_url.params.delete(:something)
|
22
|
+
easy_url.params[:else].should == '3'
|
23
|
+
easy_url.to_s.should == 'test?else=3'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'redis'
|
3
|
+
|
4
|
+
describe Shrinker::Extractor do
|
5
|
+
describe "#url" do
|
6
|
+
let(:config) do
|
7
|
+
config = Shrinker::Config.new
|
8
|
+
config.instance_eval do
|
9
|
+
backend 'Redis'
|
10
|
+
end
|
11
|
+
config
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:client) { Redis.new }
|
15
|
+
|
16
|
+
before { client.set("_shrinker::token", '{"url": "someurl", "attributes": {"test": "ab"}}') }
|
17
|
+
|
18
|
+
it "returns an EasyUrl instance" do
|
19
|
+
easy_url = Shrinker::Extractor.unshrink("token", config)
|
20
|
+
easy_url.should be_instance_of(Shrinker::EasyUrl)
|
21
|
+
easy_url.to_s.should == "someurl"
|
22
|
+
easy_url.attributes.should == {"test" => 'ab'}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raise UrlNotFound when not existing" do
|
26
|
+
expect {
|
27
|
+
Shrinker::Extractor.unshrink("not-exiting", config)
|
28
|
+
}.to raise_error(Shrinker::UrlNotFound)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#config" do
|
33
|
+
it "returns the default config by default" do
|
34
|
+
Shrinker::Extractor.new.send(:config).should == Shrinker.config
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shrinker::Parser::Mime do
|
4
|
+
let(:mime) do
|
5
|
+
<<-MYMIME
|
6
|
+
Date: Fri, 23 Nov 2012 16:19:10 -0800
|
7
|
+
To: someone@example.com
|
8
|
+
From: else@example.com
|
9
|
+
Subject: Email test
|
10
|
+
Content-type: multipart/mixed; boundary="theBoundaryString"
|
11
|
+
|
12
|
+
--theBoundaryString
|
13
|
+
|
14
|
+
Plain text message goes in this part. Notice that it
|
15
|
+
has a blank line before it starts, meaning that this
|
16
|
+
part has no additional headers.
|
17
|
+
Here is a link to http://my-example.com/test?params=1
|
18
|
+
|
19
|
+
--theBoundaryString
|
20
|
+
Content-Type: text/html
|
21
|
+
Content-Transfer-Encoding: 7bit
|
22
|
+
Content-Disposition: inline
|
23
|
+
Content-Base: "http://somewebsite.com/"
|
24
|
+
|
25
|
+
<body><font size=4>This</font> is a
|
26
|
+
<i>test</i>.
|
27
|
+
--theBoundaryString--
|
28
|
+
MYMIME
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#replace" do
|
32
|
+
let(:config) do
|
33
|
+
config = Shrinker::Config.new
|
34
|
+
config.instance_eval do
|
35
|
+
expanded_pattern /(www\.)?my-example.com/
|
36
|
+
shrinked_pattern 'goo.ln'
|
37
|
+
end
|
38
|
+
config
|
39
|
+
end
|
40
|
+
|
41
|
+
it "replace the content in the mime" do
|
42
|
+
Shrinker::Parser::Url.should_receive(:replace).with('my-example.com/test?params=1', {}, config).and_return("replace1")
|
43
|
+
Shrinker::Parser::Url.should_receive(:replace).with('somewebsite.com', {}, config).never
|
44
|
+
|
45
|
+
replaced_mime = Shrinker::Parser::Mime::replace(mime, {}, config)
|
46
|
+
replaced_mime.should include("Here is a link to http://replace1")
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when mime is multipart" do
|
50
|
+
let(:mime) { File.read(File.join(FIXTURES_PATH, 'mime.txt')) }
|
51
|
+
|
52
|
+
it "replace only anchor tags when setting anchors_only_in_html to true" do
|
53
|
+
config.anchors_only_in_html true
|
54
|
+
|
55
|
+
Shrinker::Parser::Url.should_receive(:replace).with("my-example.com/a?something=true", {}, instance_of(Shrinker::Config)).and_return('replace1')
|
56
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.my-example.com/donec-lobortis-lacus-vel-urna-variuo--4?clicked=abcdef", {}, instance_of(Shrinker::Config)).and_return('replace2')
|
57
|
+
Shrinker::Parser::Url.should_receive(:replace).with('www.my-example.com/class-aptent-taciti-sociosqu-ad-litader.jpg', {}, instance_of(Shrinker::Config)).never
|
58
|
+
Shrinker::Parser::Url.should_receive(:replace).with('www.my-example.com/safe', {}, instance_of(Shrinker::Config)).never
|
59
|
+
Shrinker::Parser::Url.should_receive(:replace).with('my-example.com/none', {}, instance_of(Shrinker::Config)).never
|
60
|
+
|
61
|
+
replaced_mime = Shrinker::Parser::Mime::replace(mime, {}, config)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "replace every urls when not setting anchors_only_in_html" do
|
65
|
+
Shrinker::Parser::Url.should_receive(:replace).with("my-example.com/a?something=true", {}, instance_of(Shrinker::Config)).and_return('replace1')
|
66
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.my-example.com/donec-lobortis-lacus-vel-urna-variuo--4?clicked=abcdef", {}, instance_of(Shrinker::Config)).and_return('replace2')
|
67
|
+
Shrinker::Parser::Url.should_receive(:replace).with('www.my-example.com/class-aptent-taciti-sociosqu-ad-litader.jpg', {}, instance_of(Shrinker::Config)).and_return('replace3')
|
68
|
+
Shrinker::Parser::Url.should_receive(:replace).with('www.my-example.com/safe', {}, instance_of(Shrinker::Config)).and_return('replace4')
|
69
|
+
Shrinker::Parser::Url.should_receive(:replace).with('my-example.com/none', {}, instance_of(Shrinker::Config)).and_return('replace5')
|
70
|
+
|
71
|
+
replaced_mime = Shrinker::Parser::Mime::replace(mime, {}, config)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "for longer multipart mimes" do
|
77
|
+
|
78
|
+
let(:multipart_mime) { File.read(File.join(FIXTURES_PATH, 'multipart_mime.txt')) }
|
79
|
+
let(:config) do
|
80
|
+
config = Shrinker::Config.new
|
81
|
+
config.instance_eval do
|
82
|
+
backend 'Redis'
|
83
|
+
expanded_pattern /www.somwebsite.com/
|
84
|
+
exclude_path /core|assets/
|
85
|
+
shrinked_pattern 'goo.ln'
|
86
|
+
end
|
87
|
+
config
|
88
|
+
end
|
89
|
+
|
90
|
+
it "replace only anchor tags when setting anchors_only_in_html to true" do
|
91
|
+
config.anchors_only_in_html true
|
92
|
+
|
93
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.somwebsite.com/glencoe-il/t/office-help--0000", {}, instance_of(Shrinker::Config)).and_return('replace1')
|
94
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.somwebsite.com/notifications", {}, instance_of(Shrinker::Config)).and_return('replace2')
|
95
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.somwebsite.com/go/defdbf1191f17112776a6adb4c201b277af845278971e81b532089d1b96926300347343b15580afba7a7cc41567b9608161d", {}, instance_of(Shrinker::Config)).and_return('replace3')
|
96
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.somwebsite.com/go/5f25b2b15ec6b450c3c5af71102616e07413381a718f1b5d21e7ff9e26d6fc216e9c05ab2b8a40195a16c8603be5860170eb", {}, instance_of(Shrinker::Config)).and_return('replace4')
|
97
|
+
Shrinker::Parser::Url.should_receive(:replace).with('www.somwebsite.com/core/assets/email/somwebsite-sky-header.jpg', {}, instance_of(Shrinker::Config)).never
|
98
|
+
|
99
|
+
replaced_mime = Shrinker::Parser::Mime::replace(multipart_mime, {}, config)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "replace every urls when not setting anchors_only_in_html" do
|
103
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.somwebsite.com/glencoe-il/t/office-help--0000", {}, instance_of(Shrinker::Config)).and_return('replace1')
|
104
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.somwebsite.com/notifications", {}, instance_of(Shrinker::Config)).and_return('replace2')
|
105
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.somwebsite.com/go/defdbf1191f17112776a6adb4c201b277af845278971e81b532089d1b96926300347343b15580afba7a7cc41567b9608161d", {}, instance_of(Shrinker::Config)).and_return('replace3')
|
106
|
+
Shrinker::Parser::Url.should_receive(:replace).with("www.somwebsite.com/go/5f25b2b15ec6b450c3c5af71102616e07413381a718f1b5d21e7ff9e26d6fc216e9c05ab2b8a40195a16c8603be5860170eb", {}, instance_of(Shrinker::Config)).and_return('replace4')
|
107
|
+
Shrinker::Parser::Url.should_receive(:replace).with('www.somwebsite.com/core/assets/email/somwebsite-sky-header.jpg', {}, instance_of(Shrinker::Config)).never
|
108
|
+
|
109
|
+
replaced_mime = Shrinker::Parser::Mime::replace(multipart_mime, {}, config)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shrinker::Parser::Text do
|
4
|
+
describe "#replace" do
|
5
|
+
|
6
|
+
context "without protocol" do
|
7
|
+
let(:config) do
|
8
|
+
config = Shrinker::Config.new
|
9
|
+
config.instance_eval do
|
10
|
+
expanded_pattern /(www\.)?google.com/
|
11
|
+
shrinked_pattern 'goo.ln'
|
12
|
+
around_pattern /href="(?:https?:\/\/)?($url)"/
|
13
|
+
end
|
14
|
+
config
|
15
|
+
end
|
16
|
+
|
17
|
+
it "replaces proper occurences" do
|
18
|
+
content = <<-EV
|
19
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
20
|
+
Nunc quis rutrum <a href="http://www.google.com?something=true&else=false">dolor</a>.
|
21
|
+
<a href="www.google.com?params=abcdef" style="text-align:center;">http://google.com/safe</a>
|
22
|
+
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
23
|
+
Curabitur ullamcorper nisl non dolor <a href="http://google.fr?something=true">venenatis</a> consequat.
|
24
|
+
Morbi odio libero, tincidunt quis tempus a, fringilla vitae augue.
|
25
|
+
<a href="http://google.com/somepath?something=true"></a>
|
26
|
+
Aenean placerat ullamcorper lorem vel feugiat.
|
27
|
+
EV
|
28
|
+
|
29
|
+
Shrinker::Parser::Url.should_receive(:replace).with('www.google.com?something=true&else=false', {}, config).and_return("replace1")
|
30
|
+
Shrinker::Parser::Url.should_receive(:replace).with('www.google.com?params=abcdef', {}, config).and_return("replace2")
|
31
|
+
Shrinker::Parser::Url.should_receive(:replace).with('google.com/safe', {}, config).never
|
32
|
+
Shrinker::Parser::Url.should_receive(:replace).with('google.fr?something=true', {}, config).never
|
33
|
+
Shrinker::Parser::Url.should_receive(:replace).with('google.com/somepath?something=true', {}, config).and_return("replace3")
|
34
|
+
|
35
|
+
replaced_text = Shrinker::Parser::Text::replace(content, {}, config)
|
36
|
+
|
37
|
+
expected_replaced_text = <<-EV
|
38
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
39
|
+
Nunc quis rutrum <a href="http://replace1">dolor</a>.
|
40
|
+
<a href="replace2" style="text-align:center;">http://google.com/safe</a>
|
41
|
+
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
42
|
+
Curabitur ullamcorper nisl non dolor <a href="http://google.fr?something=true">venenatis</a> consequat.
|
43
|
+
Morbi odio libero, tincidunt quis tempus a, fringilla vitae augue.
|
44
|
+
<a href="http://replace3"></a>
|
45
|
+
Aenean placerat ullamcorper lorem vel feugiat.
|
46
|
+
EV
|
47
|
+
|
48
|
+
replaced_text.should == expected_replaced_text
|
49
|
+
end
|
50
|
+
|
51
|
+
it "does not do anything when there is no occurence" do
|
52
|
+
content = <<-EV
|
53
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
54
|
+
Curabitur ullamcorper nisl non dolor http://google.fr?something=true venenatis consequat.
|
55
|
+
Aenean placerat ullamcorper lorem vel feugiat.
|
56
|
+
EV
|
57
|
+
|
58
|
+
replaced_text = Shrinker::Parser::Text::replace(content, {}, config)
|
59
|
+
replaced_text.should == content
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "with protocol" do
|
64
|
+
let(:config) do
|
65
|
+
config = Shrinker::Config.new
|
66
|
+
config.instance_eval do
|
67
|
+
expanded_pattern /http:\/\/(www\.)?google.com/
|
68
|
+
shrinked_pattern 'https://goo.ln'
|
69
|
+
end
|
70
|
+
config
|
71
|
+
end
|
72
|
+
|
73
|
+
it "replaces proper occurences" do
|
74
|
+
content = <<-EV
|
75
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
76
|
+
Nunc quis rutrum http://www.google.com?something=true&else=false dolor.
|
77
|
+
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
78
|
+
Curabitur ullamcorper nisl non dolor http://google.fr?something=true venenatis consequat.
|
79
|
+
Morbi odio libero, tincidunt quis tempus a, fringilla vitae augue.
|
80
|
+
https://google.com/somepath?something=true
|
81
|
+
Aenean placerat ullamcorper lorem vel feugiat.
|
82
|
+
EV
|
83
|
+
|
84
|
+
Shrinker::Parser::Url.should_receive(:replace).with('http://www.google.com?something=true&else=false', {}, config).and_return("https://replace1")
|
85
|
+
Shrinker::Parser::Url.should_receive(:replace).with('google.fr?something=true', {}, config).never
|
86
|
+
Shrinker::Parser::Url.should_receive(:replace).with('http://google.com/somepath?something=true', {}, config).never
|
87
|
+
|
88
|
+
replaced_text = Shrinker::Parser::Text::replace(content, {}, config)
|
89
|
+
|
90
|
+
expected_replaced_text = <<-EV
|
91
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
92
|
+
Nunc quis rutrum https://replace1 dolor.
|
93
|
+
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
94
|
+
Curabitur ullamcorper nisl non dolor http://google.fr?something=true venenatis consequat.
|
95
|
+
Morbi odio libero, tincidunt quis tempus a, fringilla vitae augue.
|
96
|
+
https://google.com/somepath?something=true
|
97
|
+
Aenean placerat ullamcorper lorem vel feugiat.
|
98
|
+
EV
|
99
|
+
|
100
|
+
replaced_text.should == expected_replaced_text
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#config" do
|
106
|
+
it "returns the default config by default" do
|
107
|
+
Shrinker::Parser::Text.new.send(:config).should == Shrinker.config
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shrinker::Parser::Url do
|
4
|
+
describe "#replace" do
|
5
|
+
before { Shrinker::Token.stub(:fetch_unique_token).and_return("thetoken") }
|
6
|
+
|
7
|
+
context "without protocol" do
|
8
|
+
let(:config) do
|
9
|
+
config = Shrinker::Config.new
|
10
|
+
config.instance_eval do
|
11
|
+
backend 'Redis'
|
12
|
+
expanded_pattern /(www\.)?google.com/
|
13
|
+
exclude_path /images|assets/
|
14
|
+
shrinked_pattern 'goo.ln'
|
15
|
+
end
|
16
|
+
config
|
17
|
+
end
|
18
|
+
|
19
|
+
it "replace the link" do
|
20
|
+
Shrinker::Parser::Url::replace("www.google.com?something=else", {:user_id => 10}, config).should == "goo.ln/thetoken"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "store the old link" do
|
24
|
+
Shrinker::Backend::Redis.any_instance.should_receive(:store).with("www.google.com?something=else", 'thetoken', {:user_id => 10})
|
25
|
+
|
26
|
+
Shrinker::Parser::Url::replace("www.google.com?something=else", {:user_id => 10}, config)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "does not do anything" do
|
30
|
+
before do
|
31
|
+
Shrinker::Backend::Redis.any_instance.should_receive(:store).never
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns the text if it does not match an url" do
|
35
|
+
Shrinker::Parser::Url::replace("sometext", {}, config).should == "sometext"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns the text if it does not match the domain" do
|
39
|
+
Shrinker::Parser::Url::replace("www.google.fr", {}, config).should == "www.google.fr"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "does not replace the link if there is a shrinker=false" do
|
43
|
+
Shrinker::Parser::Url::replace("www.google.com?shrinker=false&something=else", {}, config).should == "www.google.com?something=else"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not replace the link if its excluded" do
|
47
|
+
Shrinker::Parser::Url::replace("www.google.com/assets/logo.png?something=else", {}, config).should == "www.google.com/assets/logo.png?something=else"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with full url dynamic pattern" do
|
53
|
+
let(:config) do
|
54
|
+
config = Shrinker::Config.new
|
55
|
+
config.instance_eval do
|
56
|
+
backend 'Redis'
|
57
|
+
expanded_pattern /(www\.)?google.com/
|
58
|
+
shrinked_pattern lambda{ |m| "#{m[0]}/x"}
|
59
|
+
end
|
60
|
+
config
|
61
|
+
end
|
62
|
+
|
63
|
+
it "replace the link" do
|
64
|
+
Shrinker::Parser::Url::replace("www.google.com?something=else", {:user_id => 10}, config).should == "www.google.com/x/thetoken"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "store the old link" do
|
68
|
+
Shrinker::Backend::Redis.any_instance.should_receive(:store).with("www.google.com?something=else", 'thetoken', {:user_id => 10})
|
69
|
+
|
70
|
+
Shrinker::Parser::Url::replace("www.google.com?something=else", {:user_id => 10}, config)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "with partial url dynamic pattern" do
|
75
|
+
let(:config) do
|
76
|
+
config = Shrinker::Config.new
|
77
|
+
config.instance_eval do
|
78
|
+
backend 'Redis'
|
79
|
+
expanded_pattern /(.+)\.google\.com/
|
80
|
+
shrinked_pattern lambda{ |m| "#{m[1]}.other.com"}
|
81
|
+
end
|
82
|
+
config
|
83
|
+
end
|
84
|
+
|
85
|
+
it "replace the link" do
|
86
|
+
Shrinker::Parser::Url::replace("xyz.google.com?something=else", {:user_id => 10}, config).should == "xyz.other.com/thetoken"
|
87
|
+
end
|
88
|
+
|
89
|
+
it "store the old link" do
|
90
|
+
Shrinker::Backend::Redis.any_instance.should_receive(:store).with("www.google.com?something=else", 'thetoken', {:user_id => 10})
|
91
|
+
|
92
|
+
Shrinker::Parser::Url::replace("www.google.com?something=else", {:user_id => 10}, config)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with protocol" do
|
97
|
+
let(:config) do
|
98
|
+
config = Shrinker::Config.new
|
99
|
+
config.instance_eval do
|
100
|
+
backend 'Redis'
|
101
|
+
expanded_pattern /http:\/\/(www\.)?google.com/
|
102
|
+
shrinked_pattern 'https://goo.ln'
|
103
|
+
end
|
104
|
+
config
|
105
|
+
end
|
106
|
+
|
107
|
+
it "replace the link" do
|
108
|
+
Shrinker::Parser::Url::replace("http://www.google.com?something=else", {:user_id => 10}, config).should == "https://goo.ln/thetoken"
|
109
|
+
end
|
110
|
+
|
111
|
+
it "store the old link" do
|
112
|
+
Shrinker::Backend::Redis.any_instance.should_receive(:store).with("http://www.google.com?something=else", 'thetoken', {:user_id => 10})
|
113
|
+
|
114
|
+
Shrinker::Parser::Url::replace("http://www.google.com?something=else", {:user_id => 10}, config)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shrinker::Serializer do
|
4
|
+
describe "#hash" do
|
5
|
+
it "returns a hash containing the url" do
|
6
|
+
Shrinker::Serializer::to_hash('someurl').should == {:url => 'someurl', :attributes => {}}
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns a hash containing the attributes" do
|
10
|
+
Shrinker::Serializer::to_hash('someurl', {:user_id => 12}).should == {:url => 'someurl', :attributes => {:user_id => 12}}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#json" do
|
15
|
+
it "returns a json containing the url" do
|
16
|
+
Shrinker::Serializer::to_json('someurl').should == {:url => 'someurl', :attributes => {}}.to_json
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns a json containing the attributes" do
|
20
|
+
Shrinker::Serializer::to_json('someurl', {:user_id => 12}).should == {:url => 'someurl', :attributes => {:user_id => 12}}.to_json
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shrinker::Token do
|
4
|
+
describe "#generate" do
|
5
|
+
it "allows passing a prefix" do
|
6
|
+
Shrinker::Token.stub(:rand).and_return('random')
|
7
|
+
Digest::MD5.should_receive(:hexdigest).with("something__random").and_return("abcdefghijklmnopqrstuvwxyz")
|
8
|
+
|
9
|
+
Shrinker::Token.generate(prefix: 'something').should == "opqrstuvwxyz"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#fetch_uniq_token" do
|
14
|
+
let(:backend) { stub }
|
15
|
+
|
16
|
+
it "returns an unique token" do
|
17
|
+
backend.stub(:used_token?).and_return(true, false)
|
18
|
+
|
19
|
+
Shrinker::Token.should_receive(:generate).twice.and_return('abcdef')
|
20
|
+
|
21
|
+
Shrinker::Token.fetch_unique_token(backend).should == 'abcdef'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
Date: Tue, 27 Nov 2012 21:23:03 +0000
|
2
|
+
From: Someone <someone@example.com>
|
3
|
+
To: someone@example.com
|
4
|
+
Message-ID: <50b52f37d9dfb_805540b019a86752@example.mail>
|
5
|
+
Subject: The subject
|
6
|
+
Mime-Version: 1.0
|
7
|
+
Content-Type: text/html;
|
8
|
+
charset=UTF-8
|
9
|
+
Content-Transfer-Encoding: quoted-printable
|
10
|
+
|
11
|
+
<!DOCTYPE html>
|
12
|
+
<html>
|
13
|
+
=C2=A0=C2=A0<head>
|
14
|
+
\ <meta content=3D"text/html; charset=3DUTF-8" http-equiv=3D"Content-Ty=
|
15
|
+
pe" />
|
16
|
+
=C2=A0=C2=A0</head>
|
17
|
+
=C2=A0=C2=A0<body>
|
18
|
+
|
19
|
+
<div style=3D"font-family: 'Helvetica Neue', Arial, Helvetica, sans-ser=
|
20
|
+
if; color: #462815; margin: 10px auto; position: relative; width: 600px; =
|
21
|
+
background-color: white;">
|
22
|
+
<img alt=3D"Quisque tincidunt mattis risus" border=
|
23
|
+
"0" src=3D"https://www.my-example.com/class-aptent-taciti-sociosqu-ad-lit=
|
24
|
+
ader.jpg" />
|
25
|
+
<a href=3D"my-example.com/a?something=3Dtrue">my-example.com/none</a>
|
26
|
+
<br/>
|
27
|
+
|
28
|
+
<br/>
|
29
|
+
<a href=3D"https://www.my-example.com/donec-lobortis-lacus-vel-urna-variu=
|
30
|
+
o--4?clicked=3Dabcdef">https://www.my-example.com/safe</a>
|
31
|
+
|
32
|
+
<br/><br/>
|
33
|
+
Khufu hidden vcjjxnb. Cnvxjcmcjahrajcb zings
|
34
|
+
non magna imperdiet aliquam.<br/><br/>
|
35
|
+
<br/>
|
36
|
+
<br/>
|
37
|
+
|
38
|
+
</div>
|
39
|
+
|
40
|
+
=C2=A0=C2=A0</body>
|
41
|
+
</html>=
|