shorty 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/LICENSE +7 -0
- data/README.rdoc +76 -0
- data/Rakefile +68 -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/shorty.gemspec +95 -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 +124 -0
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2009 Alex Coomans
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,76 @@
|
|
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. But to get started, make sure the gem is installed. Require:
|
19
|
+
|
20
|
+
require 'shorty'
|
21
|
+
|
22
|
+
or with Rails:
|
23
|
+
|
24
|
+
config.gem 'drcapulet-shorty', :lib => 'shorty'
|
25
|
+
|
26
|
+
== Possible Additions
|
27
|
+
|
28
|
+
- http://ow.ly - currently no API, says it is coming soon
|
29
|
+
|
30
|
+
== Other Possible Gems
|
31
|
+
|
32
|
+
- http://post.ly - Not really a shortener
|
33
|
+
- http://ping.fm - Not really a shortener
|
34
|
+
- http://ff.im - Not a shortener either
|
35
|
+
- http://yfrog.com - Not a shortener, maybe expand this gem or a media gem. API docs: http://code.google.com/p/imageshackapi
|
36
|
+
- http://twitpic.com - Same as yfrog. API docs: http://twitpic.com/api.do
|
37
|
+
|
38
|
+
== Other Ideas
|
39
|
+
|
40
|
+
* Possibly use OpenStruct to make data access easier
|
41
|
+
* Possibly set a user agent using
|
42
|
+
|
43
|
+
class Foo
|
44
|
+
include HTTParty
|
45
|
+
headers 'Accept' => 'text/html'
|
46
|
+
end
|
47
|
+
|
48
|
+
* Also possibly create a command line app
|
49
|
+
* Any other ideas create an issue and start the title with [feature]
|
50
|
+
|
51
|
+
== Contributing
|
52
|
+
|
53
|
+
I invite anyone who wants to help to fork and then when you've made your changes, send me a pull request. I'd love to keep everything central.
|
54
|
+
|
55
|
+
== License
|
56
|
+
|
57
|
+
Copyright (c) 2009 Alex Coomans
|
58
|
+
|
59
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
60
|
+
a copy of this software and associated documentation files (the
|
61
|
+
"Software"), to deal in the Software without restriction, including
|
62
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
63
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
64
|
+
permit persons to whom the Software is furnished to do so, subject to
|
65
|
+
the following conditions:
|
66
|
+
|
67
|
+
The above copyright notice and this permission notice shall be
|
68
|
+
included in all copies or substantial portions of the Software.
|
69
|
+
|
70
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
71
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
72
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
73
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
74
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
75
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
76
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
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
|
+
Jeweler::GemcutterTasks.new
|
30
|
+
rescue LoadError
|
31
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'rake/testtask'
|
35
|
+
Rake::TestTask.new(:test) do |test|
|
36
|
+
test.libs << 'lib' << 'test'
|
37
|
+
test.pattern = 'test/**/*_test.rb'
|
38
|
+
test.verbose = true
|
39
|
+
end
|
40
|
+
|
41
|
+
begin
|
42
|
+
require 'rcov/rcovtask'
|
43
|
+
Rcov::RcovTask.new do |test|
|
44
|
+
test.libs << 'test'
|
45
|
+
test.pattern = 'test/**/*_test.rb'
|
46
|
+
test.verbose = true
|
47
|
+
end
|
48
|
+
rescue LoadError
|
49
|
+
task :rcov do
|
50
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
task :default => :test
|
55
|
+
|
56
|
+
require 'rake/rdoctask'
|
57
|
+
Rake::RDocTask.new do |rdoc|
|
58
|
+
if File.exist?('VERSION')
|
59
|
+
version = File.read('VERSION')
|
60
|
+
else
|
61
|
+
version = ""
|
62
|
+
end
|
63
|
+
|
64
|
+
rdoc.rdoc_dir = 'doc'
|
65
|
+
rdoc.title = "shorty #{version}"
|
66
|
+
rdoc.rdoc_files.include('README*')
|
67
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
68
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -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
|