embiggen 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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +57 -0
- data/lib/embiggen.rb +14 -0
- data/lib/embiggen/configuration.rb +68 -0
- data/lib/embiggen/uri.rb +81 -0
- data/spec/embiggen/configuration_spec.rb +52 -0
- data/spec/embiggen/uri_spec.rb +221 -0
- data/spec/embiggen_spec.rb +31 -0
- data/spec/spec_helper.rb +20 -0
- metadata +87 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6af561209a387ec502e579b6917f6bf3984fd7c3
|
4
|
+
data.tar.gz: 8a53fba0f9b2879df685ddfc8e82647b6c51411b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ae5a3f54a1c89cf969d8a0d292c23163becc1a31ab8c45bb218b7b93f998a9b838d0e457dd37bd03d05cd4954becbd7580d37ea95894e157d472c117e1ca9462
|
7
|
+
data.tar.gz: c858db7c641918040855a9ede16b3c3ccee88840f860667860172d50629e81324d0c2356be4f787ace159e129987cf6d8b7c12ccfd5c6c382b6794924ecc3d86
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Altmetric LLP
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Embiggen [](https://travis-ci.org/altmetric/embiggen)
|
2
|
+
|
3
|
+
A Ruby library to expand shortened URLs.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
```ruby
|
7
|
+
require 'embiggen'
|
8
|
+
|
9
|
+
# Basic usage
|
10
|
+
Embiggen::URI('https://youtu.be/dQw4w9WgXcQ').expand
|
11
|
+
#=> #<URI:HTTPS https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be>
|
12
|
+
|
13
|
+
# Longer-form usage
|
14
|
+
uri = Embiggen::URI.new(URI('https://youtu.be/dQw4w9WgXcQ'))
|
15
|
+
uri.shortened?
|
16
|
+
#=> true
|
17
|
+
uri.expand
|
18
|
+
#=> #<URI:HTTPS https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be>
|
19
|
+
|
20
|
+
# Gracefully deals with unshortened URIs
|
21
|
+
uri = Embiggen::URI('http://www.altmetric.com')
|
22
|
+
uri.shortened?
|
23
|
+
#=> false
|
24
|
+
uri.expand
|
25
|
+
#=> #<URI:HTTP http://www.altmetric.com>
|
26
|
+
|
27
|
+
# Noisier expand! for explicit error handling
|
28
|
+
Embiggen::URI('http://bit.ly/bad').expand!
|
29
|
+
#=> TooManyRedirects: http://bit.ly/bad redirected too many times
|
30
|
+
# or...
|
31
|
+
#=> BadShortenedURI: following http://bit.ly/bad did not redirect
|
32
|
+
|
33
|
+
# Optionally specify a timeout in seconds for expansion (default is 1)
|
34
|
+
Embiggen::URI('https://youtu.be/dQw4w9WgXcQ').expand(:timeout => 5)
|
35
|
+
|
36
|
+
# Optionally specify a number of redirects to follow (default is 5)
|
37
|
+
Embiggen::URI('https://youtu.be/dQw4w9WgXcQ').expand(:redirects => 2)
|
38
|
+
|
39
|
+
# Override the default configuration for all expansions and add your own
|
40
|
+
# shorteners
|
41
|
+
Embiggen.configure do |config|
|
42
|
+
config.timeout = 5
|
43
|
+
config.redirects = 2
|
44
|
+
config.shorteners += %w(myshorten.er anoth.er)
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
## Acknowledgements
|
49
|
+
|
50
|
+
* The list of shorteners comes from [LongURL.org's curated
|
51
|
+
list](http://longurl.org/services).
|
52
|
+
|
53
|
+
## License
|
54
|
+
|
55
|
+
Copyright © 2015 Altmetric LLP
|
56
|
+
|
57
|
+
Distributed under the MIT License.
|
data/lib/embiggen.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Embiggen
|
5
|
+
class Configuration
|
6
|
+
class << self
|
7
|
+
attr_writer :timeout, :redirects, :shorteners
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.timeout
|
11
|
+
@timeout ||= 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.redirects
|
15
|
+
@redirects ||= 5
|
16
|
+
end
|
17
|
+
|
18
|
+
# From http://longurl.org/services
|
19
|
+
def self.shorteners
|
20
|
+
@shorteners ||= Set.new(%w(
|
21
|
+
0rz.tw 1link.in 1url.com 2.gp 2big.at 2tu.us 3.ly 307.to 4ms.me
|
22
|
+
4sq.com 4url.cc 6url.com 7.ly a.gg a.nf aa.cx abcurl.net ad.vu adf.ly
|
23
|
+
adjix.com afx.cc all.fuseurl.com alturl.com amzn.to ar.gy arst.ch
|
24
|
+
atu.ca azc.cc b23.ru b2l.me bacn.me bcool.bz binged.it bit.ly bizj.us
|
25
|
+
bloat.me bravo.ly bsa.ly budurl.com canurl.com chilp.it chzb.gr cl.lk
|
26
|
+
cl.ly clck.ru cli.gs cliccami.info clickthru.ca clop.in conta.cc
|
27
|
+
cort.as cot.ag crks.me ctvr.us cutt.us dai.ly decenturl.com dfl8.me
|
28
|
+
digbig.com digg.com disq.us dld.bz dlvr.it do.my doiop.com dopen.us
|
29
|
+
easyuri.com easyurl.net eepurl.com eweri.com fa.by fav.me fb.me
|
30
|
+
fbshare.me ff.im fff.to fire.to firsturl.de firsturl.net flic.kr
|
31
|
+
flq.us fly2.ws fon.gs freak.to fuseurl.com fuzzy.to fwd4.me fwib.net
|
32
|
+
g.ro.lt gizmo.do gl.am go.9nl.com go.ign.com go.usa.gov goo.gl
|
33
|
+
goshrink.com gurl.es hex.io hiderefer.com hmm.ph href.in hsblinks.com
|
34
|
+
htxt.it huff.to hulu.com hurl.me hurl.ws icanhaz.com idek.net ilix.in
|
35
|
+
is.gd its.my ix.lt j.mp jijr.com kl.am klck.me korta.nu krunchd.com
|
36
|
+
l9k.net lat.ms liip.to liltext.com linkbee.com linkbun.ch liurl.cn
|
37
|
+
ln-s.net ln-s.ru lnk.gd lnk.ms lnkd.in lnkurl.com lru.jp lt.tl lurl.no
|
38
|
+
macte.ch mash.to merky.de migre.me miniurl.com minurl.fr mke.me
|
39
|
+
moby.to moourl.com mrte.ch myloc.me myurl.in n.pr nbc.co nblo.gs nn.nf
|
40
|
+
not.my notlong.com nsfw.in nutshellurl.com nxy.in nyti.ms o-x.fr
|
41
|
+
oc1.us om.ly omf.gd omoikane.net on.cnn.com on.mktw.net onforb.es
|
42
|
+
orz.se ow.ly ping.fm pli.gs pnt.me politi.co post.ly pp.gg profile.to
|
43
|
+
ptiturl.com pub.vitrue.com qlnk.net qte.me qu.tc qy.fi r.im rb6.me
|
44
|
+
read.bi readthis.ca reallytinyurl.com redir.ec stub_redirects.ca
|
45
|
+
redirx.com retwt.me ri.ms rickroll.it riz.gd rt.nu ru.ly rubyurl.com
|
46
|
+
rurl.org rww.tw s4c.in s7y.us safe.mn sameurl.com sdut.us shar.es
|
47
|
+
shink.de shorl.com short.ie short.to shortlinks.co.uk shorturl.com
|
48
|
+
shout.to show.my shrinkify.com shrinkr.com shrt.fr shrt.st shrten.com
|
49
|
+
shrunkin.com simurl.com slate.me smallr.com smsh.me smurl.name sn.im
|
50
|
+
snipr.com snipurl.com snurl.com sp2.ro spedr.com srnk.net srs.li
|
51
|
+
starturl.com su.pr surl.co.uk surl.hu t.cn t.co t.lh.com ta.gd tbd.ly
|
52
|
+
tcrn.ch tgr.me tgr.ph tighturl.com tiniuri.com tiny.cc tiny.ly tiny.pl
|
53
|
+
tinylink.in tinyuri.ca tinyurl.com tk tl.gd tmi.me tnij.org tnw.to
|
54
|
+
tny.com to to.ly togoto.us totc.us toysr.us tpm.ly tr.im tra.kz
|
55
|
+
trunc.it twhub.com twirl.at twitclicks.com twitterurl.net
|
56
|
+
twitterurl.org twiturl.de twurl.cc twurl.nl u.mavrev.com u.nu u76.org
|
57
|
+
ub0.cc ulu.lu updating.me ur1.ca url.az url.co.uk url.ie url360.me
|
58
|
+
url4.eu urlborg.com urlbrief.com urlcover.com urlcut.com urlenco.de
|
59
|
+
urli.nl urls.im urlshorteningservicefortwitter.com urlx.ie urlzen.com
|
60
|
+
usat.ly use.my vb.ly vgn.am vl.am vm.lc w55.de wapo.st wapurl.co.uk
|
61
|
+
wipi.es wp.me x.vu xr.com xrl.in xrl.us xurl.es xurl.jp y.ahoo.it
|
62
|
+
yatuc.com ye.pe yep.it yfrog.com yhoo.it yiyd.com youtu.be yuarel.com
|
63
|
+
z0p.de zi.ma zi.mu zipmyurl.com zud.me zurl.ws zz.gd zzang.kr ›.ws
|
64
|
+
✩.ws ✿.ws ❥.ws ➔.ws ➞.ws ➡.ws ➨.ws ➯.ws ➹.ws ➽.ws
|
65
|
+
))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/embiggen/uri.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'embiggen/configuration'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Embiggen
|
5
|
+
class URI
|
6
|
+
attr_reader :uri
|
7
|
+
|
8
|
+
def initialize(uri)
|
9
|
+
@uri = uri.is_a?(::URI::Generic) ? uri : URI(uri.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
def expand(request_options = {})
|
13
|
+
expand!(request_options)
|
14
|
+
rescue TooManyRedirects => error
|
15
|
+
error.uri
|
16
|
+
rescue Error, ::Timeout::Error, ::Errno::ECONNRESET
|
17
|
+
uri
|
18
|
+
end
|
19
|
+
|
20
|
+
def expand!(request_options = {})
|
21
|
+
return uri unless shortened?
|
22
|
+
|
23
|
+
redirects = request_options.fetch(:redirects) { Configuration.redirects }
|
24
|
+
check_redirects(redirects)
|
25
|
+
|
26
|
+
location = head_location(request_options)
|
27
|
+
check_location(location)
|
28
|
+
|
29
|
+
URI.new(location).
|
30
|
+
expand!(request_options.merge(:redirects => redirects - 1))
|
31
|
+
end
|
32
|
+
|
33
|
+
def shortened?
|
34
|
+
Configuration.shorteners.any? { |domain| uri.host =~ /\b#{domain}\z/i }
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def check_redirects(redirects)
|
40
|
+
return unless redirects.zero?
|
41
|
+
|
42
|
+
fail TooManyRedirects.new("#{uri} redirected too many times", uri)
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_location(location)
|
46
|
+
return if location
|
47
|
+
|
48
|
+
fail BadShortenedURI, "following #{uri} did not redirect"
|
49
|
+
end
|
50
|
+
|
51
|
+
def head_location(request_options = {})
|
52
|
+
timeout = request_options.fetch(:timeout) { Configuration.timeout }
|
53
|
+
|
54
|
+
http.open_timeout = timeout
|
55
|
+
http.read_timeout = timeout
|
56
|
+
|
57
|
+
response = http.head(uri.request_uri)
|
58
|
+
|
59
|
+
response.fetch('Location') if response.is_a?(::Net::HTTPRedirection)
|
60
|
+
end
|
61
|
+
|
62
|
+
def http
|
63
|
+
http = ::Net::HTTP.new(uri.host, uri.port)
|
64
|
+
http.use_ssl = true if uri.scheme == 'https'
|
65
|
+
|
66
|
+
http
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Error < ::StandardError; end
|
71
|
+
class BadShortenedURI < Error; end
|
72
|
+
|
73
|
+
class TooManyRedirects < Error
|
74
|
+
attr_reader :uri
|
75
|
+
|
76
|
+
def initialize(message, uri)
|
77
|
+
super(message)
|
78
|
+
@uri = uri
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'embiggen'
|
2
|
+
|
3
|
+
module Embiggen
|
4
|
+
RSpec.describe Configuration do
|
5
|
+
describe '#timeout' do
|
6
|
+
it 'defaults to 1 second' do
|
7
|
+
expect(described_class.timeout).to eq(1)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'can be overridden' do
|
11
|
+
described_class.timeout = 10
|
12
|
+
|
13
|
+
expect(described_class.timeout).to eq(10)
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
described_class.timeout = 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#redirects' do
|
22
|
+
it 'defaults to 5' do
|
23
|
+
expect(described_class.redirects).to eq(5)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'can be overridden' do
|
27
|
+
described_class.redirects = 2
|
28
|
+
|
29
|
+
expect(described_class.redirects).to eq(2)
|
30
|
+
end
|
31
|
+
|
32
|
+
after do
|
33
|
+
described_class.redirects = 5
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#shorteners' do
|
38
|
+
it 'defaults to a list of shorteners' do
|
39
|
+
expect(described_class.shorteners).to_not be_empty
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'can be overridden' do
|
43
|
+
expect { described_class.shorteners << 'foo.bar' }.
|
44
|
+
to change { described_class.shorteners.size }.by(1)
|
45
|
+
end
|
46
|
+
|
47
|
+
after do
|
48
|
+
described_class.shorteners.delete('foo.bar')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'embiggen'
|
2
|
+
|
3
|
+
module Embiggen
|
4
|
+
RSpec.describe URI do
|
5
|
+
describe '#expand' do
|
6
|
+
it 'expands HTTP URIs' do
|
7
|
+
stub_redirect('http://bit.ly/1ciyUPh',
|
8
|
+
'http://us.macmillan.com/books/9781466879980')
|
9
|
+
|
10
|
+
uri = described_class.new(URI('http://bit.ly/1ciyUPh'))
|
11
|
+
|
12
|
+
expect(uri.expand).to eq(URI('http://us.macmillan.com/books/9781466879980'))
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'expands HTTPS URIs' do
|
16
|
+
stub_redirect('https://youtu.be/dQw4w9WgXcQ',
|
17
|
+
'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be')
|
18
|
+
|
19
|
+
uri = described_class.new(URI('https://youtu.be/dQw4w9WgXcQ'))
|
20
|
+
|
21
|
+
expect(uri.expand).to eq(URI('https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be'))
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'expands URIs passed as strings' do
|
25
|
+
stub_redirect('http://bit.ly/1ciyUPh',
|
26
|
+
'http://us.macmillan.com/books/9781466879980')
|
27
|
+
|
28
|
+
uri = described_class.new('http://bit.ly/1ciyUPh')
|
29
|
+
|
30
|
+
expect(uri.expand).to eq(URI('http://us.macmillan.com/books/9781466879980'))
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'does not expand unshortened URIs' do
|
34
|
+
uri = described_class.new(URI('http://www.altmetric.com'))
|
35
|
+
|
36
|
+
expect(uri.expand).to eq(URI('http://www.altmetric.com'))
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'does not make requests for unshortened URIs' do
|
40
|
+
uri = described_class.new(URI('http://www.altmetric.com'))
|
41
|
+
|
42
|
+
expect { uri.expand }.to_not raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'does not expand erroring URIs' do
|
46
|
+
stub_request(:head, 'http://bit.ly/bad').to_return(:status => 500)
|
47
|
+
uri = described_class.new(URI('http://bit.ly/bad'))
|
48
|
+
|
49
|
+
expect(uri.expand).to eq(URI('http://bit.ly/bad'))
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'does not expand URIs that time out' do
|
53
|
+
stub_request(:head, 'http://bit.ly/bad').to_timeout
|
54
|
+
uri = described_class.new(URI('http://bit.ly/bad'))
|
55
|
+
|
56
|
+
expect(uri.expand).to eq(URI('http://bit.ly/bad'))
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'does not expand URIs whose connection resets' do
|
60
|
+
stub_request(:head, 'http://bit.ly/bad').to_raise(Errno::ECONNRESET)
|
61
|
+
uri = described_class.new(URI('http://bit.ly/bad'))
|
62
|
+
|
63
|
+
expect(uri.expand).to eq(URI('http://bit.ly/bad'))
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'takes an optional timeout' do
|
67
|
+
stub_request(:head, 'http://bit.ly/bad').to_timeout
|
68
|
+
uri = described_class.new(URI('http://bit.ly/bad'))
|
69
|
+
|
70
|
+
expect(uri.expand(:timeout => 5)).to eq(URI('http://bit.ly/bad'))
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'expands redirects to other shorteners' do
|
74
|
+
stub_redirect('http://bit.ly/98K8eH',
|
75
|
+
'https://youtu.be/dQw4w9WgXcQ')
|
76
|
+
stub_redirect('https://youtu.be/dQw4w9WgXcQ',
|
77
|
+
'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be')
|
78
|
+
uri = described_class.new(URI('http://bit.ly/98K8eH'))
|
79
|
+
|
80
|
+
expect(uri.expand).to eq(URI('https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be'))
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'stops expanding redirects after a default threshold of 5' do
|
84
|
+
stub_redirect('http://bit.ly/1', 'http://bit.ly/2')
|
85
|
+
stub_redirect('http://bit.ly/2', 'http://bit.ly/3')
|
86
|
+
stub_redirect('http://bit.ly/3', 'http://bit.ly/4')
|
87
|
+
stub_redirect('http://bit.ly/4', 'http://bit.ly/5')
|
88
|
+
stub_redirect('http://bit.ly/5', 'http://bit.ly/6')
|
89
|
+
stub_redirect('http://bit.ly/6', 'http://bit.ly/7')
|
90
|
+
uri = described_class.new(URI('http://bit.ly/1'))
|
91
|
+
|
92
|
+
expect(uri.expand).to eq(URI('http://bit.ly/6'))
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'takes an optional redirect threshold' do
|
96
|
+
stub_redirect('http://bit.ly/1', 'http://bit.ly/2')
|
97
|
+
stub_redirect('http://bit.ly/2', 'http://bit.ly/3')
|
98
|
+
stub_redirect('http://bit.ly/3', 'http://bit.ly/4')
|
99
|
+
uri = described_class.new(URI('http://bit.ly/1'))
|
100
|
+
|
101
|
+
expect(uri.expand(:redirects => 2)).to eq(URI('http://bit.ly/3'))
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'uses the threshold from the configuration' do
|
105
|
+
stub_redirect('http://bit.ly/1', 'http://bit.ly/2')
|
106
|
+
stub_redirect('http://bit.ly/2', 'http://bit.ly/3')
|
107
|
+
stub_redirect('http://bit.ly/3', 'http://bit.ly/4')
|
108
|
+
uri = described_class.new(URI('http://bit.ly/1'))
|
109
|
+
Configuration.redirects = 2
|
110
|
+
|
111
|
+
expect(uri.expand).to eq(URI('http://bit.ly/3'))
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'uses shorteners from the configuration' do
|
115
|
+
stub_redirect('http://altmetric.it', 'http://www.altmetric.com')
|
116
|
+
Configuration.shorteners << 'altmetric.it'
|
117
|
+
uri = described_class.new(URI('http://altmetric.it'))
|
118
|
+
|
119
|
+
expect(uri.expand).to eq(URI('http://www.altmetric.com'))
|
120
|
+
end
|
121
|
+
|
122
|
+
after do
|
123
|
+
Configuration.redirects = 5
|
124
|
+
Configuration.shorteners.delete('altmetric.it')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#expand!' do
|
129
|
+
it 'expands shortened URLs' do
|
130
|
+
stub_redirect('https://youtu.be/dQw4w9WgXcQ',
|
131
|
+
'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be')
|
132
|
+
uri = described_class.new(URI('https://youtu.be/dQw4w9WgXcQ'))
|
133
|
+
|
134
|
+
expect(uri.expand!).to eq(URI('https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=youtu.be'))
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'does not expand unshortened URIs' do
|
138
|
+
uri = described_class.new(URI('http://www.altmetric.com'))
|
139
|
+
|
140
|
+
expect(uri.expand!).to eq(URI('http://www.altmetric.com'))
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'raises an error if the URI redirects too many times' do
|
144
|
+
stub_redirect('http://bit.ly/1', 'http://bit.ly/2')
|
145
|
+
stub_redirect('http://bit.ly/2', 'http://bit.ly/3')
|
146
|
+
stub_redirect('http://bit.ly/3', 'http://bit.ly/4')
|
147
|
+
uri = described_class.new(URI('http://bit.ly/1'))
|
148
|
+
|
149
|
+
expect { uri.expand!(:redirects => 2) }.
|
150
|
+
to raise_error(TooManyRedirects)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'raises an error if a shortened URI does not redirect' do
|
154
|
+
stub_request(:head, 'http://bit.ly/bad').to_return(:status => 500)
|
155
|
+
uri = described_class.new(URI('http://bit.ly/bad'))
|
156
|
+
|
157
|
+
expect { uri.expand! }.to raise_error(BadShortenedURI)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'raises an error if the URI times out' do
|
161
|
+
stub_request(:head, 'http://bit.ly/bad').to_timeout
|
162
|
+
uri = described_class.new(URI('http://bit.ly/bad'))
|
163
|
+
|
164
|
+
expect { uri.expand! }.to raise_error(::Timeout::Error)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'raises an error if the URI errors' do
|
168
|
+
stub_request(:head, 'http://bit.ly/bad').to_raise(::Errno::ECONNRESET)
|
169
|
+
uri = described_class.new(URI('http://bit.ly/bad'))
|
170
|
+
|
171
|
+
expect { uri.expand! }.to raise_error(::Errno::ECONNRESET)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#uri' do
|
176
|
+
it 'returns the original URI' do
|
177
|
+
uri = described_class.new(URI('http://www.altmetric.com'))
|
178
|
+
|
179
|
+
expect(uri.uri).to eq(URI('http://www.altmetric.com'))
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'returns a URI even if a string was passed' do
|
183
|
+
uri = described_class.new('http://www.altmetric.com')
|
184
|
+
|
185
|
+
expect(uri.uri).to eq(URI('http://www.altmetric.com'))
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe '#shortened?' do
|
190
|
+
it 'returns true if the link has been shortened' do
|
191
|
+
uri = described_class.new('http://bit.ly/1ciyUPh')
|
192
|
+
|
193
|
+
expect(uri).to be_shortened
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'returns false if the link has not been shortened' do
|
197
|
+
uri = described_class.new('http://www.altmetric.com')
|
198
|
+
|
199
|
+
expect(uri).to_not be_shortened
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'returns true if the link has been shortened with the wrong case' do
|
203
|
+
uri = described_class.new('http://BIT.LY/1ciyUPh')
|
204
|
+
|
205
|
+
expect(uri).to be_shortened
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'returns false if the link is not shortened but uses a similar ' \
|
209
|
+
'domain' do
|
210
|
+
uri = described_class.new('http://notbit.ly/1ciyUPh')
|
211
|
+
|
212
|
+
expect(uri).to_not be_shortened
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def stub_redirect(short_url, expanded_url, status = 301)
|
217
|
+
stub_request(:head, short_url).
|
218
|
+
to_return(:status => status, :headers => { 'Location' => expanded_url })
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'embiggen'
|
2
|
+
|
3
|
+
RSpec.describe Embiggen do
|
4
|
+
describe '#URI' do
|
5
|
+
it 'returns an Embiggen::URI' do
|
6
|
+
uri = described_class::URI('http://www.altmetric.com')
|
7
|
+
|
8
|
+
expect(uri).to be_a(described_class::URI)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'accepts an existing Embiggen::URI' do
|
12
|
+
uri = described_class::URI.new('http://www.altmetric.com')
|
13
|
+
|
14
|
+
expect(described_class::URI(uri)).to be_a(described_class::URI)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#configure' do
|
19
|
+
it 'can be used to set global configuration' do
|
20
|
+
described_class.configure do |config|
|
21
|
+
config.timeout = 10
|
22
|
+
end
|
23
|
+
|
24
|
+
expect(described_class::Configuration.timeout).to eq(10)
|
25
|
+
end
|
26
|
+
|
27
|
+
after do
|
28
|
+
described_class::Configuration.timeout = 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'webmock/rspec'
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
config.filter_run :focus
|
5
|
+
config.run_all_when_everything_filtered = true
|
6
|
+
config.disable_monkey_patching!
|
7
|
+
config.warnings = true
|
8
|
+
config.order = :random
|
9
|
+
Kernel.srand config.seed
|
10
|
+
|
11
|
+
config.default_formatter = 'doc' if config.files_to_run.one?
|
12
|
+
|
13
|
+
config.expect_with :rspec do |expectations|
|
14
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
15
|
+
end
|
16
|
+
|
17
|
+
config.mock_with :rspec do |mocks|
|
18
|
+
mocks.verify_partial_doubles = true
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: embiggen
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Mucur
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: webmock
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.21'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.21'
|
41
|
+
description: |2
|
42
|
+
A library to expand shortened URIs, respecting timeouts, following
|
43
|
+
multiple redirects and leaving unshortened URIs intact.
|
44
|
+
email: support@altmetric.com
|
45
|
+
executables: []
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- LICENSE
|
50
|
+
- README.md
|
51
|
+
- lib/embiggen.rb
|
52
|
+
- lib/embiggen/configuration.rb
|
53
|
+
- lib/embiggen/uri.rb
|
54
|
+
- spec/embiggen/configuration_spec.rb
|
55
|
+
- spec/embiggen/uri_spec.rb
|
56
|
+
- spec/embiggen_spec.rb
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
homepage: https://github.com/altmetric/embiggen
|
59
|
+
licenses:
|
60
|
+
- MIT
|
61
|
+
metadata: {}
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 2.4.5
|
79
|
+
signing_key:
|
80
|
+
specification_version: 4
|
81
|
+
summary: A library to expand shortened URLs
|
82
|
+
test_files:
|
83
|
+
- spec/embiggen/configuration_spec.rb
|
84
|
+
- spec/embiggen/uri_spec.rb
|
85
|
+
- spec/embiggen_spec.rb
|
86
|
+
- spec/spec_helper.rb
|
87
|
+
has_rdoc:
|