drcapulet-shorty 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 +3 -0
- data/README.rdoc +66 -0
- data/Rakefile +67 -0
- data/VERSION +1 -0
- data/features/bitly.feature +4 -0
- data/features/step_definitions/api.rb +18 -0
- data/features/step_definitions/common_steps.rb +163 -0
- data/features/support/common.rb +29 -0
- data/features/support/env.rb +14 -0
- data/features/support/matchers.rb +11 -0
- data/features/trim.feature +8 -0
- data/lib/shorty/bitly.rb +101 -0
- data/lib/shorty/cligs.rb +56 -0
- data/lib/shorty/isgd.rb +14 -0
- data/lib/shorty/supr.rb +100 -0
- data/lib/shorty/tinyurl.rb +14 -0
- data/lib/shorty/trim.rb +110 -0
- data/lib/shorty/twurl.rb +32 -0
- data/lib/shorty.rb +17 -0
- data/test/bitly_test.rb +32 -0
- data/test/cligs_test.rb +18 -0
- data/test/fixtures/bitly-expand-cnn.json +10 -0
- data/test/fixtures/bitly-shorten-cnn.json +1 -0
- data/test/fixtures/bitly-stats-cnn.json +1 -0
- data/test/fixtures/cligs-shorten-google.txt +1 -0
- data/test/fixtures/isgd-shorten-google.txt +1 -0
- data/test/fixtures/supr-expand-cnn-error.json +1 -0
- data/test/fixtures/supr-expand-cnn.json +1 -0
- data/test/fixtures/supr-shorten-cnn.json +1 -0
- data/test/fixtures/tinyurl-shorten-google.txt +1 -0
- data/test/fixtures/trim-trim-simple.txt +1 -0
- data/test/fixtures/trim-trim-url.xml +7 -0
- data/test/fixtures/twurl-shorten-google.txt +1 -0
- data/test/isgd_test.rb +18 -0
- data/test/shory_test.rb +7 -0
- data/test/supr_test.rb +69 -0
- data/test/test_helper.rb +9 -0
- data/test/tinyurl_test.rb +18 -0
- data/test/trim_test.rb +24 -0
- data/test/twurl_test.rb +18 -0
- metadata +120 -0
data/.gitignore
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
= Shorty
|
2
|
+
|
3
|
+
shorty makes interfacing with url shortening services easy, so far the following are supported:
|
4
|
+
- http://bit.ly
|
5
|
+
- http://tr.im - only URL API implemented, not media ones
|
6
|
+
- http://is.gd
|
7
|
+
- http://tinyurl.com
|
8
|
+
- http://cli.gs - only shorten implemented, expand not
|
9
|
+
- http://twurl.nl
|
10
|
+
- http://su.pr
|
11
|
+
|
12
|
+
== Install
|
13
|
+
|
14
|
+
sudo gem install drcapulet-shorty
|
15
|
+
|
16
|
+
== Usage
|
17
|
+
|
18
|
+
Yeah just read the rdocs.
|
19
|
+
|
20
|
+
== Possible Additions
|
21
|
+
|
22
|
+
- http://ow.ly - currently no API, says it is coming soon
|
23
|
+
|
24
|
+
== Other Possible Gems
|
25
|
+
|
26
|
+
- http://post.ly - Not really a shortener
|
27
|
+
- http://ping.fm - Not really a shortener
|
28
|
+
- http://ff.im - Not a shortener either
|
29
|
+
- http://yfrog.com - Not a shortener, maybe expand this gem or a media gem. API docs: http://code.google.com/p/imageshackapi
|
30
|
+
- http://twitpic.com - Same as yfrog. API docs: http://twitpic.com/api.do
|
31
|
+
|
32
|
+
== Other Ideas
|
33
|
+
|
34
|
+
* Possibly use OpenStruct to make data access easier
|
35
|
+
* Possibly set a user agent using
|
36
|
+
|
37
|
+
class Foo
|
38
|
+
include HTTParty
|
39
|
+
headers 'Accept' => 'text/html'
|
40
|
+
end
|
41
|
+
|
42
|
+
* Also possibly create a command line app
|
43
|
+
|
44
|
+
|
45
|
+
== License
|
46
|
+
|
47
|
+
Copyright (c) 2009 Alex Coomans
|
48
|
+
|
49
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
50
|
+
a copy of this software and associated documentation files (the
|
51
|
+
"Software"), to deal in the Software without restriction, including
|
52
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
53
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
54
|
+
permit persons to whom the Software is furnished to do so, subject to
|
55
|
+
the following conditions:
|
56
|
+
|
57
|
+
The above copyright notice and this permission notice shall be
|
58
|
+
included in all copies or substantial portions of the Software.
|
59
|
+
|
60
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
61
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
62
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
63
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
64
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
65
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
66
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# begin
|
4
|
+
# require 'cucumber/rake/task'
|
5
|
+
#
|
6
|
+
# Cucumber::Rake::Task.new(:features) do |t|
|
7
|
+
# t.fork = true
|
8
|
+
# t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]
|
9
|
+
# end
|
10
|
+
# rescue LoadError
|
11
|
+
# desc 'Cucumber rake task not available'
|
12
|
+
# task :features do
|
13
|
+
# abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'jeweler'
|
19
|
+
Jeweler::Tasks.new do |gemspec|
|
20
|
+
gemspec.name = "shorty"
|
21
|
+
gemspec.summary = "Gem that talks to APIs for shortening urls"
|
22
|
+
gemspec.description = "Makes it easy to shorten URLs"
|
23
|
+
gemspec.email = "alex@alexcoomans.com"
|
24
|
+
gemspec.homepage = "http://github.com/drcapulet/shorty"
|
25
|
+
gemspec.authors = ["Alex Coomans"]
|
26
|
+
gemspec.add_dependency('httparty', '>= 0.4.4')
|
27
|
+
gemspec.add_dependency('crack', '>= 0.1.4')
|
28
|
+
end
|
29
|
+
rescue LoadError
|
30
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'rake/testtask'
|
34
|
+
Rake::TestTask.new(:test) do |test|
|
35
|
+
test.libs << 'lib' << 'test'
|
36
|
+
test.pattern = 'test/**/*_test.rb'
|
37
|
+
test.verbose = true
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
require 'rcov/rcovtask'
|
42
|
+
Rcov::RcovTask.new do |test|
|
43
|
+
test.libs << 'test'
|
44
|
+
test.pattern = 'test/**/*_test.rb'
|
45
|
+
test.verbose = true
|
46
|
+
end
|
47
|
+
rescue LoadError
|
48
|
+
task :rcov do
|
49
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
task :default => :test
|
54
|
+
|
55
|
+
require 'rake/rdoctask'
|
56
|
+
Rake::RDocTask.new do |rdoc|
|
57
|
+
if File.exist?('VERSION')
|
58
|
+
version = File.read('VERSION')
|
59
|
+
else
|
60
|
+
version = ""
|
61
|
+
end
|
62
|
+
|
63
|
+
rdoc.rdoc_dir = 'doc'
|
64
|
+
rdoc.title = "shorty #{version}"
|
65
|
+
rdoc.rdoc_files.include('README*')
|
66
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
67
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Given /I have created a new (.*) instance/ do |n|
|
2
|
+
@instance = Shorty::Trim.new()
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /I want to shorten (.*)/ do |n|
|
6
|
+
@url = @instance.shorten(n)
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^I should see "([^\"]*)"$/ do |text|
|
10
|
+
actual_output = File.read(@stdout)
|
11
|
+
actual_output.should contain(text)
|
12
|
+
end
|
13
|
+
|
14
|
+
Then /the URL should look like "([^\"]*)"$/ do |text|
|
15
|
+
@url.should contain(text)
|
16
|
+
end
|
17
|
+
|
18
|
+
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# Given /^this project is active project folder/ do
|
2
|
+
# @active_project_folder = File.expand_path(File.dirname(__FILE__) + "/../..")
|
3
|
+
# end
|
4
|
+
#
|
5
|
+
# Given /^env variable \$([\w_]+) set to "(.*)"/ do |env_var, value|
|
6
|
+
# ENV[env_var] = value
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# Given /"(.*)" folder is deleted/ do |folder|
|
10
|
+
# in_project_folder { FileUtils.rm_rf folder }
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# When /^I invoke "(.*)" generator with arguments "(.*)"$/ do |generator, arguments|
|
14
|
+
# @stdout = StringIO.new
|
15
|
+
# in_project_folder do
|
16
|
+
# if Object.const_defined?("APP_ROOT")
|
17
|
+
# APP_ROOT.replace(FileUtils.pwd)
|
18
|
+
# else
|
19
|
+
# APP_ROOT = FileUtils.pwd
|
20
|
+
# end
|
21
|
+
# run_generator(generator, arguments.split(' '), SOURCES, :stdout => @stdout)
|
22
|
+
# end
|
23
|
+
# File.open(File.join(@tmp_root, "generator.out"), "w") do |f|
|
24
|
+
# @stdout.rewind
|
25
|
+
# f << @stdout.read
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# When /^I run executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
30
|
+
# @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
31
|
+
# in_project_folder do
|
32
|
+
# system "#{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# When /^I run project executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
37
|
+
# @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
38
|
+
# in_project_folder do
|
39
|
+
# system "ruby #{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# When /^I run local executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
44
|
+
# @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
45
|
+
# executable = File.expand_path(File.join(File.dirname(__FILE__), "/../../bin", executable))
|
46
|
+
# in_project_folder do
|
47
|
+
# system "ruby #{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# When /^I invoke task "rake (.*)"/ do |task|
|
52
|
+
# @stdout = File.expand_path(File.join(@tmp_root, "tests.out"))
|
53
|
+
# in_project_folder do
|
54
|
+
# system "rake #{task} --trace > #{@stdout} 2> #{@stdout}"
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# Then /^folder "(.*)" (is|is not) created/ do |folder, is|
|
59
|
+
# in_project_folder do
|
60
|
+
# File.exists?(folder).should(is == 'is' ? be_true : be_false)
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# Then /^file "(.*)" (is|is not) created/ do |file, is|
|
65
|
+
# in_project_folder do
|
66
|
+
# File.exists?(file).should(is == 'is' ? be_true : be_false)
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# Then /^file with name matching "(.*)" is created/ do |pattern|
|
71
|
+
# in_project_folder do
|
72
|
+
# Dir[pattern].should_not be_empty
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# Then /^file "(.*)" contents (does|does not) match \/(.*)\// do |file, does, regex|
|
77
|
+
# in_project_folder do
|
78
|
+
# actual_output = File.read(file)
|
79
|
+
# (does == 'does') ?
|
80
|
+
# actual_output.should(match(/#{regex}/)) :
|
81
|
+
# actual_output.should_not(match(/#{regex}/))
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# Then /gem file "(.*)" and generated file "(.*)" should be the same/ do |gem_file, project_file|
|
86
|
+
# File.exists?(gem_file).should be_true
|
87
|
+
# File.exists?(project_file).should be_true
|
88
|
+
# gem_file_contents = File.read(File.dirname(__FILE__) + "/../../#{gem_file}")
|
89
|
+
# project_file_contents = File.read(File.join(@active_project_folder, project_file))
|
90
|
+
# project_file_contents.should == gem_file_contents
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# Then /^(does|does not) invoke generator "(.*)"$/ do |does_invoke, generator|
|
94
|
+
# actual_output = File.read(@stdout)
|
95
|
+
# does_invoke == "does" ?
|
96
|
+
# actual_output.should(match(/dependency\s+#{generator}/)) :
|
97
|
+
# actual_output.should_not(match(/dependency\s+#{generator}/))
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# Then /help options "(.*)" and "(.*)" are displayed/ do |opt1, opt2|
|
101
|
+
# actual_output = File.read(@stdout)
|
102
|
+
# actual_output.should match(/#{opt1}/)
|
103
|
+
# actual_output.should match(/#{opt2}/)
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# Then /^I should see$/ do |text|
|
107
|
+
# actual_output = File.read(@stdout)
|
108
|
+
# actual_output.should contain(text)
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# Then /^I should not see$/ do |text|
|
112
|
+
# actual_output = File.read(@stdout)
|
113
|
+
# actual_output.should_not contain(text)
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# Then /^I should see exactly$/ do |text|
|
117
|
+
# actual_output = File.read(@stdout)
|
118
|
+
# actual_output.should == text
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# Then /^I should see all (\d+) tests pass/ do |expected_test_count|
|
122
|
+
# expected = %r{^#{expected_test_count} tests, \d+ assertions, 0 failures, 0 errors}
|
123
|
+
# actual_output = File.read(@stdout)
|
124
|
+
# actual_output.should match(expected)
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
# Then /^I should see all (\d+) examples pass/ do |expected_test_count|
|
128
|
+
# expected = %r{^#{expected_test_count} examples?, 0 failures}
|
129
|
+
# actual_output = File.read(@stdout)
|
130
|
+
# actual_output.should match(expected)
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# Then /^yaml file "(.*)" contains (\{.*\})/ do |file, yaml|
|
134
|
+
# in_project_folder do
|
135
|
+
# yaml = eval yaml
|
136
|
+
# YAML.load(File.read(file)).should == yaml
|
137
|
+
# end
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# Then /^Rakefile can display tasks successfully/ do
|
141
|
+
# @stdout = File.expand_path(File.join(@tmp_root, "rakefile.out"))
|
142
|
+
# in_project_folder do
|
143
|
+
# system "rake -T > #{@stdout} 2> #{@stdout}"
|
144
|
+
# end
|
145
|
+
# actual_output = File.read(@stdout)
|
146
|
+
# actual_output.should match(/^rake\s+\w+\s+#\s.*/)
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# Then /^task "rake (.*)" is executed successfully/ do |task|
|
150
|
+
# @stdout.should_not be_nil
|
151
|
+
# actual_output = File.read(@stdout)
|
152
|
+
# actual_output.should_not match(/^Don't know how to build task '#{task}'/)
|
153
|
+
# actual_output.should_not match(/Error/i)
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# Then /^gem spec key "(.*)" contains \/(.*)\// do |key, regex|
|
157
|
+
# in_project_folder do
|
158
|
+
# gem_file = Dir["pkg/*.gem"].first
|
159
|
+
# gem_spec = Gem::Specification.from_yaml(`gem spec #{gem_file}`)
|
160
|
+
# spec_value = gem_spec.send(key.to_sym)
|
161
|
+
# spec_value.to_s.should match(/#{regex}/)
|
162
|
+
# end
|
163
|
+
# end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module CommonHelpers
|
2
|
+
def in_tmp_folder(&block)
|
3
|
+
FileUtils.chdir(@tmp_root, &block)
|
4
|
+
end
|
5
|
+
|
6
|
+
def in_project_folder(&block)
|
7
|
+
project_folder = @active_project_folder || @tmp_root
|
8
|
+
FileUtils.chdir(project_folder, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def in_home_folder(&block)
|
12
|
+
FileUtils.chdir(@home_path, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def force_local_lib_override(project_name = @project_name)
|
16
|
+
rakefile = File.read(File.join(project_name, 'Rakefile'))
|
17
|
+
File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
|
18
|
+
f << "$:.unshift('#{@lib_path}')\n"
|
19
|
+
f << rakefile
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup_active_project_folder project_name
|
24
|
+
@active_project_folder = File.join(@tmp_root, project_name)
|
25
|
+
@project_name = project_name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
World(CommonHelpers)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../lib/shorty"
|
2
|
+
|
3
|
+
gem 'cucumber'
|
4
|
+
require 'cucumber'
|
5
|
+
gem 'rspec'
|
6
|
+
require 'spec'
|
7
|
+
|
8
|
+
Before do
|
9
|
+
@tmp_root = File.dirname(__FILE__) + "/../../tmp"
|
10
|
+
@home_path = File.expand_path(File.join(@tmp_root, "home"))
|
11
|
+
FileUtils.rm_rf @tmp_root
|
12
|
+
FileUtils.mkdir_p @home_path
|
13
|
+
ENV['HOME'] = @home_path
|
14
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Matchers
|
2
|
+
def contain(expected)
|
3
|
+
simple_matcher("contain #{expected.inspect}") do |given, matcher|
|
4
|
+
matcher.failure_message = "expected #{given.inspect} to contain #{expected.inspect}"
|
5
|
+
matcher.negative_failure_message = "expected #{given.inspect} not to contain #{expected.inspect}"
|
6
|
+
given.index expected
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
World(Matchers)
|
data/lib/shorty/bitly.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
module Shorty
|
2
|
+
# The bit.ly API class. API documentation: http://code.google.com/p/bitly-api/wiki/ApiDocumentation
|
3
|
+
# For testing, use:
|
4
|
+
# require 'lib/shorty'
|
5
|
+
# bitly = Shorty::Bitly.new('bitlyapidemo', 'R_0da49e0a9118ff35f52f629d2d71bf07')
|
6
|
+
class Bitly
|
7
|
+
attr_reader :options
|
8
|
+
include HTTParty
|
9
|
+
|
10
|
+
# Standard Error Class
|
11
|
+
class Error < StandardError; end
|
12
|
+
|
13
|
+
API_URL = 'api.bit.ly'
|
14
|
+
API_VERSION = '2.0.1'
|
15
|
+
base_uri API_URL
|
16
|
+
|
17
|
+
# Options to pass:
|
18
|
+
#
|
19
|
+
# - login
|
20
|
+
# - apikey
|
21
|
+
def initialize(login, apikey)
|
22
|
+
@options = {
|
23
|
+
:login => login,
|
24
|
+
:apiKey => apikey,
|
25
|
+
:version => API_VERSION
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
# shorten, pass:
|
30
|
+
#
|
31
|
+
# - longurl: the URL to be shortened
|
32
|
+
def shorten( longurl )
|
33
|
+
query = {:longUrl => longurl}
|
34
|
+
query.merge!(@options)
|
35
|
+
short = self.class.get('/shorten', :query => query)
|
36
|
+
short = Crack::JSON.parse(short)
|
37
|
+
short["errorCode"].zero? ? short["results"][longurl]["shortUrl"] : raise_error(short["errorCode"], short["errorMessage"])
|
38
|
+
end
|
39
|
+
|
40
|
+
# expand- given a bit.ly url, returns long source url, takes:
|
41
|
+
#
|
42
|
+
# - shorturl: the bit.ly url, can either be the full url or missing http://bit.ly
|
43
|
+
def expand(shorturl)
|
44
|
+
shorturl = gsub_url(shorturl)
|
45
|
+
query = {:hash => shorturl}
|
46
|
+
query.merge!(@options)
|
47
|
+
expand = self.class.get('/expand', :query => query)
|
48
|
+
expand = Crack::JSON.parse(expand)
|
49
|
+
expand["errorCode"].zero? ? expand["results"][shorturl]["longUrl"] : raise_error(expand["errorCode"], expand["errorMessage"])
|
50
|
+
end
|
51
|
+
|
52
|
+
# info - Given a bit.ly url or hash, return information about that page, such as the long source url, ...
|
53
|
+
def info(urlorhash, keys = [])
|
54
|
+
urlhash = gsub_url(urlorhash)
|
55
|
+
if keys != []
|
56
|
+
query = {:hash => urlhash, :keys => keys.join(',')}
|
57
|
+
else
|
58
|
+
query = {:hash => urlhash}
|
59
|
+
end
|
60
|
+
query.merge!(@options)
|
61
|
+
stats = self.class.get('/info', :query => query)
|
62
|
+
stats = Crack::JSON.parse(stats)
|
63
|
+
stats["errorCode"].zero? ? stats["results"][urlhash] : raise_error(stats["errorCode"], stats["errorMessage"])
|
64
|
+
end
|
65
|
+
|
66
|
+
# stats - get stats on clicks and reffers, pass either:
|
67
|
+
#
|
68
|
+
# - shortURL: A single bitly url, eg: http://bit.ly/1RmnUT
|
69
|
+
# - hash: A single hash, eg: 1RmnUT
|
70
|
+
#
|
71
|
+
# Example:
|
72
|
+
# bitly = Shorty::Bitly.new('login', 'apikey')
|
73
|
+
# bitly.expand('1RmnUT')
|
74
|
+
# Or:
|
75
|
+
# bitly = Shorty::Bitly.new('login', 'apikey')
|
76
|
+
# bitly.expand('http://bit.ly/1RmnUT')
|
77
|
+
def stats(urlorhash)
|
78
|
+
urlhash = gsub_url(urlorhash)
|
79
|
+
query = {:hash => urlhash}
|
80
|
+
query.merge!(@options)
|
81
|
+
stats = self.class.get('/stats', :query => query)
|
82
|
+
stats = Crack::JSON.parse(stats)
|
83
|
+
stats["errorCode"].zero? ? stats["results"] : raise_error(stats["errorCode"], stats["errorMessage"])
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
def gsub_url(shorturl)
|
90
|
+
shorturl.split('/').last
|
91
|
+
# shorturl = shorturl.gsub(/http:\/\//, '') if shorturl.include?('http://')
|
92
|
+
# shorturl = shorturl.gsub(/bit.ly\//, '') if shorturl.include?('bit.ly/')
|
93
|
+
end
|
94
|
+
|
95
|
+
def raise_error(code, message = '(no error message)')
|
96
|
+
error = message + " (error code: #{code})"
|
97
|
+
raise Shorty::Bitly::Error, error
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
data/lib/shorty/cligs.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Shorty
|
2
|
+
# The cli.gs API class. API documentation: http://blog.cli.gs/api
|
3
|
+
# For testing, use:
|
4
|
+
# require 'lib/shorty'
|
5
|
+
# cligs = Shorty::Cligs.new
|
6
|
+
class Cligs
|
7
|
+
attr_reader :options
|
8
|
+
include HTTParty
|
9
|
+
|
10
|
+
# Standard Error Class
|
11
|
+
class Error < StandardError; end
|
12
|
+
|
13
|
+
API_URL = 'http://cli.gs/api/v1/cligs'
|
14
|
+
API_VERSION = '1'
|
15
|
+
base_uri API_URL
|
16
|
+
|
17
|
+
# Options to pass:
|
18
|
+
#
|
19
|
+
# - API key: f given it associates the new clig with a user account so that they can view the traffic statistics. If not given, then a Public clig is created.
|
20
|
+
# - AppId: a simple string, HTML allowed, that identifies your App when the API usage is listed in the user’s control panel. Keep it short and simple please.
|
21
|
+
#
|
22
|
+
# cligs = Shorty::Cligs.new(:apikey => 'apikey', :appid => 'appid')
|
23
|
+
def initialize(options = {})
|
24
|
+
@options = {}
|
25
|
+
@options[:key] = options[:apikey] if options[:apikey]
|
26
|
+
@options[:appid] = options[:appid] if options[:appid]
|
27
|
+
end
|
28
|
+
|
29
|
+
# shorten. pass:
|
30
|
+
#
|
31
|
+
# - url: the url to shorten
|
32
|
+
def shorten(url)
|
33
|
+
query = {:url => url}
|
34
|
+
query.merge!(@options)
|
35
|
+
self.class.get('/create', :query => query)
|
36
|
+
end
|
37
|
+
|
38
|
+
# expand. pass either:
|
39
|
+
#
|
40
|
+
# - A valid clig ID, like Ts8p6Y
|
41
|
+
# - A clig URL, like http://cli.gs/Ts8p6Y
|
42
|
+
#
|
43
|
+
# Currently not implemented due to the fact this method wont work for demo.
|
44
|
+
def expand(urlorhash)
|
45
|
+
raise StandardError, 'Method not implemented'
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def raise_error(code, message = '(no error message)')
|
51
|
+
error = message + " (error code: #{code})"
|
52
|
+
raise Shorty::Bitly::Error, error
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/shorty/isgd.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Shorty
|
2
|
+
# is.gd API as defined http://is.gd/api_info.php
|
3
|
+
class Isgd
|
4
|
+
include HTTParty
|
5
|
+
|
6
|
+
def shorten(url)
|
7
|
+
self.class.get('http://is.gd/api.php', :query => {:longurl => url})
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.shorten(url)
|
11
|
+
get('http://is.gd/api.php', :query => {:longurl => url})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/shorty/supr.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
module Shorty
|
2
|
+
# The su.pr API class. API documentation: http://www.stumbleupon.com/developers/Supr:API_documentation/
|
3
|
+
class Supr
|
4
|
+
attr_reader :options
|
5
|
+
include HTTParty
|
6
|
+
|
7
|
+
# Standard Error Class
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
API_URL = 'http://su.pr/api'
|
11
|
+
API_VERSION = '1.0'
|
12
|
+
base_uri API_URL
|
13
|
+
|
14
|
+
# Options to pass, optional, but both must be passed when used
|
15
|
+
# - login: Your Su.pr username (also your StumbleUpon username)
|
16
|
+
# - apikey: Your private API key. This can be generated on your Su.pr settings page.
|
17
|
+
def initialize(login = nil, apikey = nil)
|
18
|
+
@options = {
|
19
|
+
:version => API_VERSION
|
20
|
+
}
|
21
|
+
if login && apikey
|
22
|
+
@options.merge({:login => login, :apiKey => apikey})
|
23
|
+
elsif (login || apikey)
|
24
|
+
raise Shorty::Supr::Error, 'Both the API key and login values must be passed when you want to use authentication'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# shorten. pass:
|
29
|
+
# - url: The long URL you wish to shorten
|
30
|
+
# Will return the full url unless you pass false for the second parameter, then it only returns the hash
|
31
|
+
def shorten(url, full = true)
|
32
|
+
query = {:longUrl => url}
|
33
|
+
query.merge!(@options)
|
34
|
+
short = self.class.get('/shorten', :query => query)
|
35
|
+
short = Crack::JSON.parse(short)
|
36
|
+
if full
|
37
|
+
short["errorCode"].zero? ? short["results"][url]["shortUrl"] : raise_error(short["errorCode"], short["errorMessage"])
|
38
|
+
else
|
39
|
+
short["errorCode"].zero? ? short["results"][url]["hash"] : raise_error(short["errorCode"], short["errorMessage"])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# self.shorten. see shorten
|
44
|
+
def self.shorten(url, full = true)
|
45
|
+
query = {:longUrl => url}
|
46
|
+
query.merge!(@options) if @options
|
47
|
+
short = get('/shorten', :query => query)
|
48
|
+
short = Crack::JSON.parse(short)
|
49
|
+
if full
|
50
|
+
short["errorCode"].zero? ? short["results"][url]["shortUrl"] : raise_error(short["errorCode"], short["errorMessage"])
|
51
|
+
else
|
52
|
+
short["errorCode"].zero? ? short["results"][url]["hash"] : raise_error(short["errorCode"], short["errorMessage"])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# expand. pass either:
|
57
|
+
# - shortUrl: he Su.pr URL you wish to expand
|
58
|
+
# - hash: The six character hash you wish to expand
|
59
|
+
def expand(urlorhash)
|
60
|
+
hash = gsub_url(urlorhash)
|
61
|
+
query = {:hash => hash}
|
62
|
+
query.merge!(@options)
|
63
|
+
expand = self.class.get('/expand', :query => query)
|
64
|
+
expand = Crack::JSON.parse(expand)
|
65
|
+
expand["errorCode"].zero? ? expand["results"][hash]["longUrl"] : raise_error(expand["errorCode"], expand["errorMessage"])
|
66
|
+
end
|
67
|
+
|
68
|
+
# self.expand. see expand
|
69
|
+
def self.expand(urlorhash)
|
70
|
+
hash = gsub_url(urlorhash)
|
71
|
+
query = {:hash => hash}
|
72
|
+
query.merge!(@options) if @options
|
73
|
+
expand = get('/expand', :query => query)
|
74
|
+
expand = Crack::JSON.parse(expand)
|
75
|
+
expand["errorCode"].zero? ? expand["results"][hash]["longUrl"] : raise_error(expand["errorCode"], expand["errorMessage"])
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def gsub_url(shorturl)
|
82
|
+
shorturl.split('/').last
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.gsub_url(shorturl)
|
86
|
+
shorturl.split('/').last
|
87
|
+
end
|
88
|
+
|
89
|
+
def raise_error(code, message = '(no error message)')
|
90
|
+
error = message + " (error code: #{code})"
|
91
|
+
raise Shorty::Supr::Error, error
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.raise_error(code, message = '(no error message)')
|
95
|
+
error = message + " (error code: #{code})"
|
96
|
+
raise Shorty::Supr::Error, error
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Shorty
|
2
|
+
# The tinyurl.com API. Not much here, undocumented API
|
3
|
+
class Tinyurl
|
4
|
+
include HTTParty
|
5
|
+
|
6
|
+
def shorten(url)
|
7
|
+
self.class.get('http://tinyurl.com/api-create.php', :query => {:url => url})
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.shorten(url)
|
11
|
+
get('http://tinyurl.com/api-create.php', :query => {:url => url})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/shorty/trim.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
|
2
|
+
module Shorty
|
3
|
+
# The tr.im API class. API documentation: http://tr.im/website/api
|
4
|
+
class Trim
|
5
|
+
include HTTParty
|
6
|
+
attr_reader :options
|
7
|
+
# API Error
|
8
|
+
class APIError < StandardError; end
|
9
|
+
class APIKeyInvalid < StandardError; end
|
10
|
+
class APIKeyRequired < StandardError; end
|
11
|
+
# Submitted URL Invalid.
|
12
|
+
class URLInvalid < StandardError; end
|
13
|
+
# Submitted URL is Already a Shortened URL.
|
14
|
+
class AlreadyShortened < StandardError; end
|
15
|
+
class URLMissing < StandardError; end
|
16
|
+
class URLDoesntExist < StandardError; end
|
17
|
+
class URLAlreadyClaimed < StandardError; end
|
18
|
+
# The URL has been Flagged as Spam and Rejected.
|
19
|
+
class FlaggedSpam < StandardError; end
|
20
|
+
# The Custom tr.im URL Requested is Already in Us.
|
21
|
+
class AlreadyInUse < StandardError; end
|
22
|
+
class AuthenticationInvalid < StandardError; end
|
23
|
+
class ReferenceCodeNonExistent< StandardError; end
|
24
|
+
# Media
|
25
|
+
class MediaTypeUnsupported < StandardError; end
|
26
|
+
class MediaTooLarge < StandardError; end
|
27
|
+
class MediaInvalidDimensions < StandardError; end
|
28
|
+
# Invalid Errors
|
29
|
+
class InvalidCharacters < StandardError; end
|
30
|
+
class InvalidParameter < StandardError; end
|
31
|
+
class UnknownError < StandardError; end
|
32
|
+
# Required Parameter URL Not Submitted.
|
33
|
+
class MissingParameter < StandardError; end
|
34
|
+
|
35
|
+
|
36
|
+
base_uri 'api.tr.im/api'
|
37
|
+
|
38
|
+
# TODO: We should take the api_key, username and or password here and authenticate them if needed (need to look into that)
|
39
|
+
def initialize(api_key = nil)
|
40
|
+
@options = {}
|
41
|
+
@options << {:api_key => api_key} if api_key
|
42
|
+
end
|
43
|
+
|
44
|
+
# The trim_simple API method as defined: http://tr.im/website/api#trim_simple
|
45
|
+
# Can only be passed a site URL, only returns a URL, and no error handling occurs
|
46
|
+
# api = Shorty::Trim.new
|
47
|
+
# api.shorten('http://google.com') => http://tr.im/szMj
|
48
|
+
def shorten( website_url )
|
49
|
+
self.class.get( '/trim_simple', :query => { :url => website_url } )
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# The trim_url API method as defined: http://tr.im/website/api#trim_url
|
54
|
+
# The following options can be passed:
|
55
|
+
#
|
56
|
+
# - url: the URL you want to shorten
|
57
|
+
# - custom: A custom URL that is preferred to an auto-generated URL.
|
58
|
+
# - searchtags: A search string value to attach to a tr.im URL.
|
59
|
+
# - privacycode: A string value that must be appended after the URL.
|
60
|
+
# - newtrim: If present with any value, it will force the creation of a new tr.im URL.
|
61
|
+
# - sandbox: If present with any value a test data set will be returned, and no URL created. This is intended for testing so that you do not consume API calls or insert pointless data while in development.
|
62
|
+
#
|
63
|
+
# require 'shorty'
|
64
|
+
# api = Shorty::Trim.new
|
65
|
+
# api.trim_url(:url => 'http://google.com', :custom => 'thisismygoogle', :sandbox => 'true') # => http://tr.im/szMj
|
66
|
+
|
67
|
+
def trim_url( options = {} )
|
68
|
+
options.merge!(@options)
|
69
|
+
response = self.class.get( '/trim_url.xml', :query => options )
|
70
|
+
response = Crack::XML.parse(response)
|
71
|
+
raise_error(response['trim']['status']['code'], response['trim']['status']['message']) if response['trim']['status']['code'] >= '205'
|
72
|
+
return response['trim']['url']
|
73
|
+
end
|
74
|
+
|
75
|
+
TRIM_ERRORS = {
|
76
|
+
400 => Shorty::Trim::MissingParameter, # Required Parameter URL Not Submitted.
|
77
|
+
401 => Shorty::Trim::URLInvalid, # Submitted URL Invalid.
|
78
|
+
402 => Shorty::Trim::AlreadyShortened, # Submitted URL is Already a Shortened URL.
|
79
|
+
403 => Shorty::Trim::FlaggedSpam, # The URL has been Flagged as Spam and Rejected.
|
80
|
+
404 => Shorty::Trim::AlreadyInUse, # The Custom tr.im URL Requested is Already in Us.
|
81
|
+
405 => Shorty::Trim::InvalidCharacters, # Requested Custom URL Contains Invalid Characters.
|
82
|
+
406 => Shorty::Trim::InvalidCharacters, # Requested Privacy Code Contains Invalid Characters.
|
83
|
+
407 => Shorty::Trim::InvalidCharacters, # Requested Search Tags Contains Invalid Characters.
|
84
|
+
410 => Shorty::Trim::AuthenticationInvalid, # Required Authentication Not Submitted or Invalid.
|
85
|
+
411 => Shorty::Trim::MissingParameter, # URL Reference Code Not Submitted.
|
86
|
+
412 => Shorty::Trim::ReferenceCodeNonExistent, # URL Reference Code Not Does Not Exist.
|
87
|
+
413 => Shorty::Trim::URLMissing, # tr.im URL Path Not Submitted.
|
88
|
+
414 => Shorty::Trim::URLDoesntExist, # tr.im URL Does Not Exist.
|
89
|
+
415 => Shorty::Trim::URLAlreadyClaimed, # tr.im URL Referenced Already Claimed.
|
90
|
+
420 => Shorty::Trim::MediaTypeUnsupported, # Media Type Uploaded Not Supported.
|
91
|
+
421 => Shorty::Trim::MediaTooLarge, # Media Uploaded too Large.
|
92
|
+
422 => Shorty::Trim::MediaInvalidDimensions, # Media Uploaded XY Dimensions too Small.
|
93
|
+
425 => Shorty::Trim::APIError, # API Rate Limit Exceeded.
|
94
|
+
426 => Shorty::Trim::APIKeyInvalid, # API Key Submitted Does Not Exist or is Invalid.
|
95
|
+
427 => Shorty::Trim::APIKeyRequired, # API Key Required.
|
96
|
+
445 => Shorty::Trim::InvalidParameter, # Parameter Data Within the Request is Invalid.
|
97
|
+
446 => Shorty::Trim::MissingParameter, # "Required Parameter Missing within the Request."
|
98
|
+
450 => Shorty::Trim::UnknownError # "An Unknown Error Occurred. Please email api@tr.im."
|
99
|
+
}
|
100
|
+
|
101
|
+
private
|
102
|
+
# Raise an error depending on the problem
|
103
|
+
def raise_error(code, message = '(no error message)')
|
104
|
+
# raise Shorty::Trim::APIError.new(TRIM_ERRORS[code])
|
105
|
+
raise TRIM_ERRORS[code], message
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
|
data/lib/shorty/twurl.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Shorty
|
2
|
+
# The twurl.nl API class. API documentation: http://tweetburner.com/api
|
3
|
+
class Twurl
|
4
|
+
attr_reader :options
|
5
|
+
include HTTParty
|
6
|
+
|
7
|
+
# Standard Error Class
|
8
|
+
class Error < StandardError; end
|
9
|
+
|
10
|
+
API_URL = 'http://tweetburner.com'
|
11
|
+
base_uri API_URL
|
12
|
+
|
13
|
+
# shorten. pass:
|
14
|
+
# - url: the url to be shortened
|
15
|
+
# So to use:
|
16
|
+
# twurl = Shorty::Truwl.new
|
17
|
+
# twurl.shorten('http://google.com')
|
18
|
+
def shorten(url)
|
19
|
+
query = { :'link[url]' => url }
|
20
|
+
self.class.post("/links", :query => query)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Same as the shorten method, you can just call the following instead:
|
24
|
+
#
|
25
|
+
# Shorty::Truwl.shorten('http://google.com')
|
26
|
+
def self.shorten(url)
|
27
|
+
query = { :'link[url]' => url }
|
28
|
+
post("/links", :query => query)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/lib/shorty.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'crack'
|
3
|
+
|
4
|
+
module Shorty
|
5
|
+
class API
|
6
|
+
include HTTParty
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'shorty/trim'
|
10
|
+
require 'shorty/bitly'
|
11
|
+
require 'shorty/tinyurl'
|
12
|
+
require 'shorty/isgd'
|
13
|
+
require 'shorty/cligs'
|
14
|
+
require 'shorty/twurl'
|
15
|
+
require 'shorty/supr'
|
16
|
+
end
|
17
|
+
|
data/test/bitly_test.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BitlyTest < Test::Unit::TestCase
|
4
|
+
context "A bit.ly instance" do
|
5
|
+
setup do
|
6
|
+
FakeWeb.register_uri(:get, "http://api.bit.ly/shorten?apiKey=R_0da49e0a9118ff35f52f629d2d71bf07&version=2.0.1&longUrl=http%3A%2F%2Fcnn.com&login=bitlyapidemo", :body => File.join(File.dirname(__FILE__), 'fixtures', 'bitly-shorten-cnn.json'))
|
7
|
+
FakeWeb.register_uri(:get, "http://api.bit.ly/expand?apiKey=R_0da49e0a9118ff35f52f629d2d71bf07&version=2.0.1&login=bitlyapidemo&hash=15DlK", :body => File.join(File.dirname(__FILE__), 'fixtures', 'bitly-expand-cnn.json'))
|
8
|
+
FakeWeb.register_uri(:get, "http://api.bit.ly/stats?hash=15DlK&apiKey=R_0da49e0a9118ff35f52f629d2d71bf07&version=2.0.1&login=bitlyapidemo", :body => File.join(File.dirname(__FILE__), 'fixtures', 'bitly-stats-cnn.json'))
|
9
|
+
@bitly = Shorty::Bitly.new('bitlyapidemo', 'R_0da49e0a9118ff35f52f629d2d71bf07')
|
10
|
+
end
|
11
|
+
|
12
|
+
should "exist" do
|
13
|
+
assert @bitly
|
14
|
+
end
|
15
|
+
|
16
|
+
should "return a shortened url" do
|
17
|
+
assert_equal 'http://bit.ly/15DlK', @bitly.shorten('http://cnn.com')
|
18
|
+
end
|
19
|
+
|
20
|
+
should "return an expanded url when passed a hash" do
|
21
|
+
assert_equal 'http://cnn.com/', @bitly.expand('15DlK')
|
22
|
+
end
|
23
|
+
|
24
|
+
should "return an expanded url when passed a full url" do
|
25
|
+
assert_equal 'http://cnn.com/', @bitly.expand('http://bit.ly/15DlK')
|
26
|
+
end
|
27
|
+
|
28
|
+
should "return the stats for a url" do
|
29
|
+
assert_equal 3046, @bitly.stats('http://bit.ly/15DlK')["clicks"]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/test/cligs_test.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CligsTest < Test::Unit::TestCase
|
4
|
+
context "A cli.gs instance" do
|
5
|
+
setup do
|
6
|
+
FakeWeb.register_uri(:get, "http://cli.gs/api/v1/cligs/create?url=http%3A%2F%2Fgoogle.com", :body => File.join(File.dirname(__FILE__), 'fixtures', 'cligs-shorten-google.txt'))
|
7
|
+
@cligs = Shorty::Cligs.new
|
8
|
+
end
|
9
|
+
|
10
|
+
should "exist" do
|
11
|
+
assert @cligs
|
12
|
+
end
|
13
|
+
|
14
|
+
should "return a shortened url" do
|
15
|
+
assert_equal 'http://cli.gs/g5nmE', @cligs.shorten('http://google.com')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{ "errorCode": 0, "errorMessage": "", "results": { "http://cnn.com": { "hash": "31IqMl", "shortKeywordUrl": "", "shortUrl": "http://bit.ly/15DlK", "userHash": "15DlK" } }, "statusCode": "OK" }
|
@@ -0,0 +1 @@
|
|
1
|
+
{ "errorCode": 0, "errorMessage": "", "results": { "clicks": 3046, "hash": "31IqMl", "referrers": { "": { "/index.html": 1, "None": 5, "direct": 2255 }, "api.bit.ly": { "/shorten": 2 }, "benny-web": { "/jseitel/bitly/install.html": 1 }, "bit.ly": { "/": 3, "/app/demos/info.html": 102, "/app/demos/stats.html": 402, "/app/demos/statsModule.html": 2, "/info/14tP6": 1, "/info/15DlK": 1, "/info/27I9Ll": 1, "/info/31IqMl": 4, "/info/J066u": 1, "/info/SiNn6": 1, "/info/hic4E": 1 }, "code.google.com": { "/p/bitly-api/wiki/ApiDocumentation": 1 }, "dev.chartbeat.com": { "/static/bitly.html": 1 }, "dev.unhub.com": { "/pnG8/": 1 }, "klout.net": { "/profiledetail.php": 1 }, "localhost": { "/New Folder/test1.php": 1, "/index2.html": 1 }, "mail.google.com": { "/mail/": 1 }, "partners.bit.ly": { "/td": 9 }, "powertwitter.me": { "/": 1 }, "quietube.com": { "/getbitly.php": 1 }, "search.twitter.com": { "/search": 3 }, "sfbay.craigslist.org": { "/sfc/rnr/891043787.html": 8 }, "spreadsheets.google.com": { "/ccc": 27, "/ccc2": 1 }, "strat.corp.advertising.com": { "/brandmaker/bitly.php": 4 }, "taggytext.com": { "/ganja": 1 }, "twitter.com": { "/": 11, "/SuperTestAcct": 2, "/TattoosOn": 1, "/WilliamWoods": 1, "/home": 6, "/ibiboisms": 2, "/kshanns": 1, "/matraji": 1, "/nathanfolkman": 1, "/pantaleonescu": 1, "/rubyisbeautiful": 1, "/williamwoods": 1 }, "twitter.mattz.dev.buddymedia.com": { "/twitter/": 1 }, "twitturls.com": { "/": 21 }, "twitturly.com": { "": 17, "/urlinfo/url/2168a5e81280538cdbf6ad4c4ab019db/": 1 }, "uploaddownloadperform.net": { "/Test/TestPage2": 1 }, "url.ly": { "/": 19, "/info/27I9Ll": 1, "/info/31IqMl": 3 }, "urly.local:3600": { "/": 7 }, "v2.blogg.no": { "/test.cfm": 1 }, "www.facebook.com": { "/home.php": 1 }, "www.longurlplease.com": { "/": 3 }, "www.microblogbuzz.com": { "": 5 } }, "userClicks": 373, "userHash": "15DlK", "userReferrers": { "": { "None": 1, "direct": 366 }, "api.bit.ly": { "/shorten": 2 }, "code.google.com": { "/p/bitly-api/wiki/ApiDocumentation": 1 }, "twitter.com": { "/TattoosOn": 1, "/rubyisbeautiful": 1 }, "www.longurlplease.com": { "/": 1 } } }, "statusCode": "OK" }
|
@@ -0,0 +1 @@
|
|
1
|
+
http://cli.gs/g5nmE
|
@@ -0,0 +1 @@
|
|
1
|
+
http://is.gd/2iE2G
|
@@ -0,0 +1 @@
|
|
1
|
+
{"errorCode":1204,"errorMessage":"Invalid Su.pr hash","statusCode":"ERROR"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"errorCode":0,"errorMessage":"","results":{"2yw2PP":{"longUrl":"http:\/\/cnn.com\/"}},"statusCode":"OK"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"errorCode":0,"errorMessage":"","results":{"http:\/\/cnn.com":{"hash":"2yw2PP","shortUrl":"http:\/\/su.pr\/2yw2PP"}},"statusCode":"OK"}
|
@@ -0,0 +1 @@
|
|
1
|
+
http://tinyurl.com/2x6rgl
|
@@ -0,0 +1 @@
|
|
1
|
+
http://tr.im/w5Pm
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<trim>
|
3
|
+
<status result="OK" code="200" message="tr.im URL Added."/>
|
4
|
+
<url>http://tr.im/thisismygoogletesting</url>
|
5
|
+
<reference>CRzMDvkYP7VYKrpBWsUAU4fAbT7MUg</reference>
|
6
|
+
<trimpath>thisismygoogletesting</trimpath>
|
7
|
+
</trim>
|
@@ -0,0 +1 @@
|
|
1
|
+
http://twurl.nl/jnlwyb
|
data/test/isgd_test.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class IsgdTest < Test::Unit::TestCase
|
4
|
+
context "Using is.gd" do
|
5
|
+
setup do
|
6
|
+
FakeWeb.register_uri(:get, "http://is.gd/api.php?longurl=http%3A%2F%2Fgoogle.com", :body => File.join(File.dirname(__FILE__), 'fixtures', 'isgd-shorten-google.txt'))
|
7
|
+
end
|
8
|
+
|
9
|
+
should "return a shortened url (class method)" do
|
10
|
+
assert_equal 'http://is.gd/2iE2G', Shorty::Isgd.shorten('http://google.com')
|
11
|
+
end
|
12
|
+
|
13
|
+
should "return a shortened url (instance method)" do
|
14
|
+
@isgd = Shorty::Isgd.new
|
15
|
+
assert_equal 'http://is.gd/2iE2G', @isgd.shorten('http://google.com')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/test/shory_test.rb
ADDED
data/test/supr_test.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SuprTest < Test::Unit::TestCase
|
4
|
+
context "A su.pr instance" do
|
5
|
+
setup do
|
6
|
+
FakeWeb.register_uri(:get, "http://su.pr/api/shorten?version=1.0&longUrl=http%3A%2F%2Fcnn.com", :body => File.join(File.dirname(__FILE__), 'fixtures', 'supr-shorten-cnn.json'))
|
7
|
+
FakeWeb.register_uri(:get, "http://su.pr/api/shorten?longUrl=http%3A%2F%2Fcnn.com", :body => File.join(File.dirname(__FILE__), 'fixtures', 'supr-shorten-cnn.json'))
|
8
|
+
FakeWeb.register_uri(:get, "http://su.pr/api/expand?hash=2yw2PP&version=1.0", :body => File.join(File.dirname(__FILE__), 'fixtures', 'supr-expand-cnn.json'))
|
9
|
+
FakeWeb.register_uri(:get, "http://su.pr/api/expand?hash=2yw2PP", :body => File.join(File.dirname(__FILE__), 'fixtures', 'supr-expand-cnn.json'))
|
10
|
+
FakeWeb.register_uri(:get, "http://su.pr/api/expand?hash=15DlK&version=1.0", :body => File.join(File.dirname(__FILE__), 'fixtures', 'supr-expand-cnn-error.json'))
|
11
|
+
FakeWeb.register_uri(:get, "http://su.pr/api/expand?hash=15DlK", :body => File.join(File.dirname(__FILE__), 'fixtures', 'supr-expand-cnn-error.json'))
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when using instance methods" do
|
15
|
+
setup do
|
16
|
+
@supr = Shorty::Supr.new
|
17
|
+
end
|
18
|
+
|
19
|
+
should "exist" do
|
20
|
+
assert @supr
|
21
|
+
end
|
22
|
+
|
23
|
+
should "return a shortened url" do
|
24
|
+
assert_equal 'http://su.pr/2yw2PP', @supr.shorten('http://cnn.com')
|
25
|
+
end
|
26
|
+
|
27
|
+
should "return an expanded url when passed a hash" do
|
28
|
+
assert_equal 'http://cnn.com/', @supr.expand('2yw2PP')
|
29
|
+
end
|
30
|
+
|
31
|
+
should "return an expanded url when passed a full url" do
|
32
|
+
assert_equal 'http://cnn.com/', @supr.expand('http://su.pr/2yw2PP')
|
33
|
+
end
|
34
|
+
|
35
|
+
should "raise an error when passed an invalid hash to expand" do
|
36
|
+
assert_raise Shorty::Supr::Error do
|
37
|
+
@supr.expand('15DlK')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
should "raise an error when an instance is being created and is missing a paramter" do
|
42
|
+
assert_raise Shorty::Supr::Error do
|
43
|
+
Shorty::Supr.new('dummyapi')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when using class methods" do
|
49
|
+
should "return a shortened url" do
|
50
|
+
assert_equal 'http://su.pr/2yw2PP', Shorty::Supr.shorten('http://cnn.com')
|
51
|
+
end
|
52
|
+
|
53
|
+
should "return an expanded url when passed a hash" do
|
54
|
+
assert_equal 'http://cnn.com/', Shorty::Supr.expand('2yw2PP')
|
55
|
+
end
|
56
|
+
|
57
|
+
should "return an expanded url when passed a full url" do
|
58
|
+
assert_equal 'http://cnn.com/', Shorty::Supr.expand('http://su.pr/2yw2PP')
|
59
|
+
end
|
60
|
+
|
61
|
+
should "return an error when passed an invalid hash to expand" do
|
62
|
+
assert_raise Shorty::Supr::Error do
|
63
|
+
Shorty::Supr.expand('15DlK')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TinyurlTest < Test::Unit::TestCase
|
4
|
+
context "Using tinyurl.com" do
|
5
|
+
setup do
|
6
|
+
FakeWeb.register_uri(:get, "http://tinyurl.com/api-create.php?url=http%3A%2F%2Fgoogle.com", :body => File.join(File.dirname(__FILE__), 'fixtures', 'tinyurl-shorten-google.txt'))
|
7
|
+
end
|
8
|
+
|
9
|
+
should "return a shortened url (class method)" do
|
10
|
+
assert_equal 'http://tinyurl.com/2x6rgl', Shorty::Tinyurl.shorten('http://google.com')
|
11
|
+
end
|
12
|
+
|
13
|
+
should "return a shortened url (instance method)" do
|
14
|
+
@tinyurl = Shorty::Tinyurl.new
|
15
|
+
assert_equal 'http://tinyurl.com/2x6rgl', @tinyurl.shorten('http://google.com')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/test/trim_test.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TrimTest < Test::Unit::TestCase
|
4
|
+
context "A tr.im instance" do
|
5
|
+
setup do
|
6
|
+
FakeWeb.register_uri(:get, "http://api.tr.im/api/trim_simple?url=http%3A%2F%2Fgoogle.com", :body => File.join(File.dirname(__FILE__), 'fixtures', 'trim-trim-simple.txt'))
|
7
|
+
FakeWeb.register_uri(:get, "http://api.tr.im/api/trim_url.xml?url=http%3A%2F%2Fgoogle.com&custom=thisismygoogletesting", :body => File.join(File.dirname(__FILE__), 'fixtures', 'trim-trim-url.xml'))
|
8
|
+
# FakeWeb.register_uri(:get, "http://api.bit.ly/stats?hash=15DlK&apiKey=R_0da49e0a9118ff35f52f629d2d71bf07&version=2.0.1&login=bitlyapidemo", :body => File.join(File.dirname(__FILE__), 'fixtures', 'bitly-stats-cnn.json'))
|
9
|
+
@trim = Shorty::Trim.new
|
10
|
+
end
|
11
|
+
|
12
|
+
should "exist" do
|
13
|
+
assert @trim
|
14
|
+
end
|
15
|
+
|
16
|
+
should "return a shortened url using trim_simple" do
|
17
|
+
assert_equal 'http://tr.im/w5Pm', @trim.shorten('http://google.com')
|
18
|
+
end
|
19
|
+
|
20
|
+
should "return a shortened url using trim_url" do
|
21
|
+
assert_equal 'http://tr.im/thisismygoogletesting', @trim.trim_url(:url => 'http://google.com', :custom => 'thisismygoogletesting')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/test/twurl_test.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TwurlTest < Test::Unit::TestCase
|
4
|
+
context "Using twurl.nl" do
|
5
|
+
setup do
|
6
|
+
FakeWeb.register_uri(:post, "http://tweetburner.com/links?link[url]=http%3A%2F%2Fgoogle.com", :body => File.join(File.dirname(__FILE__), 'fixtures', 'twurl-shorten-google.txt'))
|
7
|
+
end
|
8
|
+
|
9
|
+
should "return a shortened url (class method)" do
|
10
|
+
assert_equal 'http://twurl.nl/jnlwyb', Shorty::Twurl.shorten('http://google.com')
|
11
|
+
end
|
12
|
+
|
13
|
+
should "return a shortened url (instance method)" do
|
14
|
+
@twurl = Shorty::Twurl.new
|
15
|
+
assert_equal 'http://twurl.nl/jnlwyb', @twurl.shorten('http://google.com')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: drcapulet-shorty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alex Coomans
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: httparty
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.4.4
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: crack
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.4
|
34
|
+
version:
|
35
|
+
description: Makes it easy to shorten URLs
|
36
|
+
email: alex@alexcoomans.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.rdoc
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- README.rdoc
|
46
|
+
- Rakefile
|
47
|
+
- VERSION
|
48
|
+
- features/bitly.feature
|
49
|
+
- features/step_definitions/api.rb
|
50
|
+
- features/step_definitions/common_steps.rb
|
51
|
+
- features/support/common.rb
|
52
|
+
- features/support/env.rb
|
53
|
+
- features/support/matchers.rb
|
54
|
+
- features/trim.feature
|
55
|
+
- lib/shorty.rb
|
56
|
+
- lib/shorty/bitly.rb
|
57
|
+
- lib/shorty/cligs.rb
|
58
|
+
- lib/shorty/isgd.rb
|
59
|
+
- lib/shorty/supr.rb
|
60
|
+
- lib/shorty/tinyurl.rb
|
61
|
+
- lib/shorty/trim.rb
|
62
|
+
- lib/shorty/twurl.rb
|
63
|
+
- test/bitly_test.rb
|
64
|
+
- test/cligs_test.rb
|
65
|
+
- test/fixtures/bitly-expand-cnn.json
|
66
|
+
- test/fixtures/bitly-shorten-cnn.json
|
67
|
+
- test/fixtures/bitly-stats-cnn.json
|
68
|
+
- test/fixtures/cligs-shorten-google.txt
|
69
|
+
- test/fixtures/isgd-shorten-google.txt
|
70
|
+
- test/fixtures/supr-expand-cnn-error.json
|
71
|
+
- test/fixtures/supr-expand-cnn.json
|
72
|
+
- test/fixtures/supr-shorten-cnn.json
|
73
|
+
- test/fixtures/tinyurl-shorten-google.txt
|
74
|
+
- test/fixtures/trim-trim-simple.txt
|
75
|
+
- test/fixtures/trim-trim-url.xml
|
76
|
+
- test/fixtures/twurl-shorten-google.txt
|
77
|
+
- test/isgd_test.rb
|
78
|
+
- test/shory_test.rb
|
79
|
+
- test/supr_test.rb
|
80
|
+
- test/test_helper.rb
|
81
|
+
- test/tinyurl_test.rb
|
82
|
+
- test/trim_test.rb
|
83
|
+
- test/twurl_test.rb
|
84
|
+
has_rdoc: false
|
85
|
+
homepage: http://github.com/drcapulet/shorty
|
86
|
+
licenses:
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options:
|
89
|
+
- --charset=UTF-8
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: "0"
|
97
|
+
version:
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: "0"
|
103
|
+
version:
|
104
|
+
requirements: []
|
105
|
+
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.3.5
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Gem that talks to APIs for shortening urls
|
111
|
+
test_files:
|
112
|
+
- test/bitly_test.rb
|
113
|
+
- test/cligs_test.rb
|
114
|
+
- test/isgd_test.rb
|
115
|
+
- test/shory_test.rb
|
116
|
+
- test/supr_test.rb
|
117
|
+
- test/test_helper.rb
|
118
|
+
- test/tinyurl_test.rb
|
119
|
+
- test/trim_test.rb
|
120
|
+
- test/twurl_test.rb
|