uncoil 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/Manifest +9 -0
- data/README.md +39 -0
- data/Rakefile +12 -0
- data/lib/uncoil/version.rb +3 -0
- data/lib/uncoil.rb +81 -0
- data/spec/uncoil_spec.rb +130 -0
- data/uncoil.gemspec +26 -0
- metadata +92 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/Manifest
ADDED
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# uncoil
|
2
|
+
|
3
|
+
The uncoil gem is a one stop shop for un-shortening urls.
|
4
|
+
|
5
|
+
The idea is based off of my site http://uncoil.me and I built this as part of my UWE-Ruby fall project.
|
6
|
+
|
7
|
+
## Why the heck does this exist?
|
8
|
+
This gem is all about transparency and safety, and knowing where you are going on the internet.
|
9
|
+
|
10
|
+
There are a few instances where it may come in handy:
|
11
|
+
|
12
|
+
* You want to make sure you're not heading into an obviously sketchy site
|
13
|
+
* You're at work and want to keep out the NSFW
|
14
|
+
|
15
|
+
## Example
|
16
|
+
I have no idea where http://bit.ly/2EEjBl really goes.
|
17
|
+
|
18
|
+
But by expanding it with uncoil, I can see that it goes to http://www.cnn.com
|
19
|
+
|
20
|
+
## How the app works
|
21
|
+
|
22
|
+
1. Extract the domain from the url
|
23
|
+
2. See if it matches with any of the supported APIs
|
24
|
+
* If so, it calls the correct API method
|
25
|
+
* If no matching method is found, it runs through an HTTP loop until it receives a 200 response
|
26
|
+
3. It then returns a hash containing, among other items, the full url
|
27
|
+
|
28
|
+
## Current Issues
|
29
|
+
|
30
|
+
## Future Enhancements
|
31
|
+
Here are a few ideas I have for the future:
|
32
|
+
|
33
|
+
* Additional APIs as they become available
|
34
|
+
* These seem to be faster than a general HTTP request loop
|
35
|
+
* Modularized structure with each API's content in its own file
|
36
|
+
* Dynamic method assignment based on domain.
|
37
|
+
* This goes with the modularized structure above, because it allows you to just drop more API files into the folder and not have to modify the main method
|
38
|
+
* Better error handling (I'd appreciate any comments on what to catch and what to leave)
|
39
|
+
* Offer the code as a gem
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake'
|
4
|
+
require 'rspec'
|
5
|
+
|
6
|
+
desc "`rake` will default to running `rake:spec`"
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
desc "Run all the rspec examples"
|
10
|
+
task :spec do
|
11
|
+
system "bundle exec rspec -c spec"
|
12
|
+
end
|
data/lib/uncoil.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'bitly'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class Uncoil
|
7
|
+
ISGD_ROOT_URL = "http://is.gd/forward.php?format=json&shorturl="
|
8
|
+
BITLY_DOM_ARRAY = %w[bit.ly, j.mp, bitlypro.com, cs.pn, nyti.ms]
|
9
|
+
|
10
|
+
def initialize options = {}
|
11
|
+
Bitly.use_api_version_3
|
12
|
+
@bitly_access = false
|
13
|
+
|
14
|
+
if options.has_key?(:bitlyuser) && options.has_key?(:bitlykey)
|
15
|
+
@bitly_instance = Bitly.new("#{options[:bitlyuser]}", "#{options[:bitlykey]}")
|
16
|
+
@bitly_access = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def identify_domain short_url
|
21
|
+
clean_url(short_url).split("/")[2].to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def clean_url short_url
|
25
|
+
short_url = "http://" << short_url unless short_url =~ /^https?:\/\//
|
26
|
+
short_url.chop! if short_url[-1] == "/"
|
27
|
+
short_url
|
28
|
+
end
|
29
|
+
|
30
|
+
def expand url_arr
|
31
|
+
out_arr = Array(url_arr).flatten.map do |short_url|
|
32
|
+
short_url = clean_url(short_url)
|
33
|
+
domain = identify_domain(short_url)
|
34
|
+
|
35
|
+
@bitly_access.nil? ? error = "Not logged in to Bitly API" : error = nil
|
36
|
+
|
37
|
+
begin
|
38
|
+
if @bitly_access && BITLY_DOM_ARRAY.include?(domain)
|
39
|
+
long_url = uncoil_bitly(short_url)
|
40
|
+
elsif @bitly_access && check_bitly_pro(domain)
|
41
|
+
long_url = uncoil_bitly(short_url)
|
42
|
+
elsif domain == "is.gd"
|
43
|
+
long_url = uncoil_isgd(short_url)
|
44
|
+
else
|
45
|
+
long_url = uncoil_other(short_url)
|
46
|
+
end
|
47
|
+
rescue => exception
|
48
|
+
long_url = nil
|
49
|
+
error = exception.message
|
50
|
+
end
|
51
|
+
|
52
|
+
{ :short_url => short_url , :long_url => long_url, :error => error }
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
out_arr.length == 1 ? out_arr[0] : out_arr
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def check_bitly_pro url_domain
|
61
|
+
@bitly_instance.bitly_pro_domain(url_domain)
|
62
|
+
end
|
63
|
+
|
64
|
+
def uncoil_bitly short_url
|
65
|
+
@bitly_instance.expand(short_url).long_url
|
66
|
+
end
|
67
|
+
|
68
|
+
def uncoil_isgd short_url
|
69
|
+
JSON.parse(open(ISGD_ROOT_URL + "#{short_url}") { |file| file.read } )["url"]
|
70
|
+
end
|
71
|
+
|
72
|
+
def uncoil_other short_url, depth = 10
|
73
|
+
url = URI.encode(short_url)
|
74
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
75
|
+
|
76
|
+
case response
|
77
|
+
when Net::HTTPSuccess then url
|
78
|
+
when Net::HTTPRedirection then uncoil_other(response['location'], depth - 1)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/uncoil_spec.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'uncoil'
|
2
|
+
|
3
|
+
describe Uncoil do
|
4
|
+
|
5
|
+
subject { Uncoil.new(:bitlyuser => "stim371", :bitlykey => "R_7a6f6d845668a8a7bb3e0c80ee3c28d6")}
|
6
|
+
|
7
|
+
context "when cleaning up the url" do
|
8
|
+
|
9
|
+
it "should add the prefix if none exists" do
|
10
|
+
subject.clean_url("cnn.com").should eq "http://cnn.com"
|
11
|
+
subject.clean_url("cnn.com/").should eq "http://cnn.com"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not add the prefix if one exists" do
|
15
|
+
subject.clean_url("http://cnn.com").should eq "http://cnn.com"
|
16
|
+
subject.clean_url("http://cnn.com/").should eq "http://cnn.com"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not add the prefix if a secure one exists" do
|
20
|
+
subject.clean_url("https://cnn.com").should eq "https://cnn.com"
|
21
|
+
subject.clean_url("https://cnn.com/").should eq "https://cnn.com"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should remove the trailing slash" do
|
25
|
+
subject.clean_url("http://cnn.com/").should eq "http://cnn.com"
|
26
|
+
subject.clean_url("cnn.com/").should eq "http://cnn.com"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not remove characters on the end that aren't slashes" do
|
30
|
+
subject.clean_url("http://cnn.com").should eq "http://cnn.com"
|
31
|
+
subject.clean_url("cnn.com").should eq "http://cnn.com"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when extracting the domain" do
|
37
|
+
|
38
|
+
it "should correctly extract the domain from a normal url" do
|
39
|
+
subject.identify_domain("http://bit.ly/2EEjBl").should eq "bit.ly"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when checking a domain" do
|
45
|
+
|
46
|
+
it "should identify pro domains" do
|
47
|
+
subject.check_bitly_pro("cs.pn").should be_true
|
48
|
+
subject.check_bitly_pro("nyti.ms").should be_true
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should identify non-pro domains" do
|
52
|
+
subject.check_bitly_pro("bit.ly").should be_false #the bit.ly domain comes back false since its not a "pro" domain
|
53
|
+
subject.check_bitly_pro("tinyurl.com").should be_false
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "when using the submethods" do
|
59
|
+
|
60
|
+
context "when trying to undo a bit.ly link" do
|
61
|
+
|
62
|
+
it "should bring back the correct long link" do
|
63
|
+
expected_result = "http://www.cnn.com/"
|
64
|
+
subject.uncoil_bitly("http://bit.ly/2EEjBl").should eq expected_result
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when trying to undo a bit.ly pro link" do
|
70
|
+
|
71
|
+
it "should bring back the correct long link" do
|
72
|
+
expected_result = "http://www.c-spanvideo.org/program/CainNew"
|
73
|
+
subject.uncoil_bitly("http://cs.pn/vsZpra").should eq expected_result
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when trying to undo an is.gd link" do
|
79
|
+
|
80
|
+
it "should bring back the correct long link" do
|
81
|
+
subject.uncoil_isgd("http://is.gd/gbKNRq").should eq "http://www.google.com"
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when trying to undo from other services" do
|
87
|
+
|
88
|
+
it "should bring back the correct long link" do
|
89
|
+
subject.uncoil_other("http://tinyurl.com/736swvl").should eq "http://www.chinadaily.com.cn/usa/business/2011-11/08/content_14057648.htm"
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when using the main expand method" do
|
96
|
+
|
97
|
+
it "should expand bitly correctly" do
|
98
|
+
expected_result = Hash[:long_url => "http://www.cnn.com/", :short_url => "http://bit.ly/2EEjBl", :error => nil]
|
99
|
+
subject.expand("http://bit.ly/2EEjBl").should eq expected_result
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should expand bitlypro domains correctly" do
|
103
|
+
subject.expand("http://cs.pn/vsZpra").should eq Hash[:long_url => "http://www.c-spanvideo.org/program/CainNew", :short_url => "http://cs.pn/vsZpra", :error => nil]
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should expand isgd domains correctly" do
|
107
|
+
subject.expand("http://is.gd/gbKNRq").should eq Hash[:long_url => "http://www.google.com", :short_url => "http://is.gd/gbKNRq", :error => nil]
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should expand other shortened urls correctly" do
|
111
|
+
short_url = "http://tinyurl.com/736swvl"
|
112
|
+
results_array = Hash[:long_url => "http://www.chinadaily.com.cn/usa/business/2011-11/08/content_14057648.htm", :short_url => "http://tinyurl.com/736swvl", :error => nil]
|
113
|
+
|
114
|
+
subject.expand(short_url).should eq results_array
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should also take an array of quotes" do
|
118
|
+
arr_of_links = ["http://bit.ly/2EEjBl","http://is.gd/gbKNRq","http://cs.pn/vsZpra"]
|
119
|
+
results_array = [Hash[:long_url => "http://www.cnn.com/", :short_url => "http://bit.ly/2EEjBl", :error => nil], Hash[:long_url => "http://www.google.com", :short_url => "http://is.gd/gbKNRq", :error => nil],Hash[:long_url => "http://www.c-spanvideo.org/program/CainNew", :short_url => "http://cs.pn/vsZpra", :error => nil]]
|
120
|
+
|
121
|
+
subject.expand(arr_of_links).should eq results_array
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should raise an error for non-urls" do
|
125
|
+
subject.expand("a")[:error].should_not be_nil
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
data/uncoil.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "uncoil/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "uncoil"
|
7
|
+
s.version = Uncoil::VERSION
|
8
|
+
s.authors = ["Joel Stimson"]
|
9
|
+
s.email = ["contact@cleanroomstudios.com"]
|
10
|
+
s.homepage = "http://uncoil.me"
|
11
|
+
s.summary = %q{Uncoil is a gem to unshorten urls so you know where obscured links really go.}
|
12
|
+
s.description = %q{Uncoil is a gem to unshorten urls so you know where obscured links really go. If you have bitly login credentials, initialize an instance of Uncoil to use the bitly API.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "uncoil"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency "guard-rspec"
|
24
|
+
|
25
|
+
s.add_runtime_dependency "bitly"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: uncoil
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joel Stimson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &2154321340 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2154321340
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: guard-rspec
|
27
|
+
requirement: &2154320920 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2154320920
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: bitly
|
38
|
+
requirement: &2154320500 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2154320500
|
47
|
+
description: Uncoil is a gem to unshorten urls so you know where obscured links really
|
48
|
+
go. If you have bitly login credentials, initialize an instance of Uncoil to use
|
49
|
+
the bitly API.
|
50
|
+
email:
|
51
|
+
- contact@cleanroomstudios.com
|
52
|
+
executables: []
|
53
|
+
extensions: []
|
54
|
+
extra_rdoc_files: []
|
55
|
+
files:
|
56
|
+
- .gitignore
|
57
|
+
- Gemfile
|
58
|
+
- Guardfile
|
59
|
+
- Manifest
|
60
|
+
- README.md
|
61
|
+
- Rakefile
|
62
|
+
- lib/uncoil.rb
|
63
|
+
- lib/uncoil/version.rb
|
64
|
+
- spec/uncoil_spec.rb
|
65
|
+
- uncoil.gemspec
|
66
|
+
homepage: http://uncoil.me
|
67
|
+
licenses: []
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project: uncoil
|
86
|
+
rubygems_version: 1.8.10
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Uncoil is a gem to unshorten urls so you know where obscured links really
|
90
|
+
go.
|
91
|
+
test_files:
|
92
|
+
- spec/uncoil_spec.rb
|