budurl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source :rubygems
2
+
3
+ group :development do
4
+ gem "rake"
5
+ end
6
+
7
+ gemspec
@@ -0,0 +1,14 @@
1
+ # BudURL
2
+
3
+ ### About
4
+
5
+ This gem provides a simple interface to the BudURL.Pro API, documented [here](http://budurl.com/page/budurlpro-api). BudURL provides URL shortening services as well as analytics, some of which is available externally. In particular, the API allows:
6
+ * **Shortening URLs** along with adding notes, setting redirect types, and checking for duplicates,
7
+ * **Expanding URLs** which have been shortened using the service,
8
+ * **Gathering analytics** such as click counts either since link creation or on a day-by-day basis, filterable by time period.
9
+
10
+ ### Usage
11
+
12
+ The BudURL API requires an API key for any usage other than URL expansion. More details at their website, [BudURL.Pro](http://budurl.pro).
13
+
14
+ Initialise a client using `Budurl.new(<API_KEY>)`. It provides `shorten(url, opts)` and `expand(short_url)` functionality; the resulting `Budurl::Url` objects can be used to acquire additional information such as click counts. Options not exposed in code can be passed in as options; generally speaking, any option available through the API should be accessible.
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.pattern = "./test/unit/*.rb"
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :spec
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.push("lib")
4
+
5
+ require 'budurl'
6
+
7
+ budurl = Budurl.new(ARGV[0])
8
+
9
+ puts budurl.expand(ARGV[1]).long_url
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.push("lib")
4
+
5
+ require 'budurl'
6
+
7
+ budurl = Budurl.new(ARGV[0])
8
+
9
+ puts budurl.shorten(ARGV[1]).link
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ require 'date'
3
+
4
+ $:.push("lib")
5
+
6
+ require 'budurl'
7
+
8
+ budurl = Budurl.new(ARGV[0])
9
+
10
+ url = budurl.expand(ARGV[1])
11
+
12
+ date_from = ARGV[2] ? Date.parse(ARGV[2]) : nil
13
+ date_to = ARGV[3] ? Date.parse(ARGV[3]) : nil
14
+
15
+ count = url.clicks(false, date_from, date_to)
16
+ dates = url.clicks(true, date_from, date_to)
17
+
18
+ puts "URL: #{url.long_url}"
19
+ puts "Total clicks: #{count}"
20
+ puts "Per date:"
21
+ dates.each {|date,clicks| puts "#{date}: #{clicks}"}
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "budurl/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "budurl"
7
+ s.version = Budurl::VERSION
8
+ s.authors = ["Anuj Das"]
9
+ s.email = ["anuj.das@mylookout.com"]
10
+ s.homepage = "https://github.com/lookout/budurl-gem"
11
+ s.summary = %q{A gem for interfacing with the BudURL.Pro url shortener API}
12
+ s.description = %q{Supported operations include shrinking, expanding, and counting clicks.}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency 'httparty'
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency 'ruby-debug'
23
+ s.add_development_dependency 'rspec'
24
+ s.add_development_dependency 'mimic'
25
+ s.add_development_dependency 'json'
26
+ end
@@ -0,0 +1,9 @@
1
+ require 'httparty'
2
+ require 'budurl/url'
3
+ require 'budurl/client'
4
+ require 'budurl/version'
5
+
6
+ module Budurl
7
+ # default BudURL.Pro API url
8
+ BUDURL_PRO_BASE_URI = 'http://BudURL.Pro/api/v2'
9
+ end
@@ -0,0 +1,67 @@
1
+ module Budurl
2
+ def self.new(api_key, uri = BUDURL_PRO_BASE_URI)
3
+ Budurl::Client.new(api_key, uri)
4
+ end
5
+
6
+ class Client
7
+ include HTTParty
8
+
9
+ format :json
10
+
11
+ # Returns a Budurl client which can be used to query API services.
12
+ # uri is the base uri for the BudURL API.
13
+ def initialize(api_key, uri)
14
+ self.class.base_uri uri
15
+ @default_query_opts = { :api_key => api_key }
16
+ end
17
+
18
+ # Returns a Budurl::Url object containing a shorturl.
19
+ # opts allow duplicate checking, notes, etc. For all options,
20
+ # see the BudURL API: http://budurl.com/page/budurlpro-api
21
+ def shorten(url, opts = {})
22
+ query_opts = {:long_url => url}.merge(opts)
23
+ response = get('/links/shrink', :query => query_opts)
24
+ Budurl::Url.new(self, response)
25
+ end
26
+
27
+ # Returns a Budurl::Url object containing a longurl.
28
+ def expand(short_url)
29
+ query_opts = {:link => short_url}
30
+ response = get('/links/expand', :query => query_opts)
31
+ Budurl::Url.new(self, response)
32
+ end
33
+
34
+ # Returns a hash containing click counts since creation.
35
+ # opts allow daily click counts and date filters. For all options,
36
+ # see the BudURL API: http://budurl.com/page/budurlpro-api
37
+ def clicks(short_url, opts = {})
38
+ query_opts = {:link => short_url}.merge(opts)
39
+ response = get('/clicks/count', :query => query_opts)
40
+ end
41
+
42
+ def get(uri, opts = {})
43
+ opts[:query] ||= {}
44
+ opts[:query].merge!(@default_query_opts)
45
+ response = self.class.get(uri, opts).parsed_response
46
+ if response.nil?
47
+ raise Error.new('No response from server.', 0)
48
+ elsif response['success'] == 1
49
+ response
50
+ else
51
+ raise Error.new(response['error_message'], response['error_code'])
52
+ end
53
+ end
54
+ private :get
55
+ end
56
+
57
+ # This class encapsulates BudURL API errors into a usable form.
58
+ class Error < StandardError
59
+ attr_reader :code
60
+
61
+ def initialize(message, code)
62
+ @code = code
63
+ super("#{code} - #{message}")
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,31 @@
1
+ require 'date'
2
+
3
+ module Budurl
4
+ class Url
5
+
6
+ attr_accessor :link, :long_url, :hash
7
+
8
+ # Create a Url with values filled in from a Client response.
9
+ def initialize(client, response = nil)
10
+ @client = client
11
+
12
+ if response && response.is_a?(Hash)
13
+ @link = response['link']
14
+ @long_url = response['long_url']
15
+ @hash = response['hash']
16
+ end
17
+ end
18
+
19
+ # Retrieve click counts for this shorturl.
20
+ # daily flag allows day-by-day breakdowns.
21
+ # date_from and date_to are Date objects which allow filtering.
22
+ def clicks(daily=false, date_from=nil, date_to=nil)
23
+ opts = { :daily => daily ? 1 : 0 }
24
+ opts.merge!(:date_from => date_from.to_s) if date_from
25
+ opts.merge!(:date_to => date_to.to_s) if date_to
26
+
27
+ response = @client.clicks(@link, opts)
28
+ daily ? response['dates'] : response['count']
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Budurl
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,112 @@
1
+ require 'rubygems'
2
+ require 'mimic'
3
+ require 'json'
4
+
5
+ class BudurlMock
6
+
7
+ API_KEY_ERROR = 100
8
+ LONG_URL_ERROR = 200
9
+ SHORT_URL_ERROR = 400
10
+
11
+ def initialize
12
+ self.clear
13
+ end
14
+
15
+ [:api_keys, :short_to_long_urls].each do |var|
16
+ class_eval %{
17
+ def self.#{var.to_s}
18
+ @@#{var}
19
+ end
20
+ }
21
+ end
22
+
23
+ def self.clear
24
+ # valid api keys
25
+ @@api_keys = []
26
+
27
+ # url mappings: short_url => {link, api_key, count, dates => {date => count, ...}}
28
+ @@short_to_long_urls = {}
29
+
30
+ # next unused short_url
31
+ @@next_hash = 0
32
+ end
33
+
34
+ def self.hash_from_short_url(url)
35
+ url.match(/^http:\/\/Ez\.com\/(\d{4})$/)[1]
36
+ end
37
+
38
+ def self.short_url_from_hash(hash)
39
+ "http://Ez.com/#{hash}"
40
+ end
41
+
42
+ def self.find_by_long_url(long_url)
43
+ short_url = @@short_to_long_urls.select{|k,v| v[:link] == long_url}.last
44
+ short_url ? short_url[0] : nil
45
+ end
46
+
47
+ def self.error_response(code)
48
+ {:success => 0, :error_code => code, :error_message => "Error"}
49
+ end
50
+
51
+ Mimic.mimic do
52
+ get '/links/shrink' do
53
+ if !@@api_keys.include?(params[:api_key])
54
+ response = BudurlMock.error_response(API_KEY_ERROR)
55
+ elsif params[:long_url].empty?
56
+ response = BudurlMock.error_response(LONG_URL_ERROR)
57
+ else
58
+ if params[:dupe_check] != '1' || !(short_url = BudurlMock.find_by_long_url(params[:long_url]))
59
+ short_url = BudurlMock.short_url_from_hash("%04d" % @@next_hash += 1)
60
+ @@short_to_long_urls[short_url] = {:link => params[:long_url],
61
+ :api_key => params[:api_key],
62
+ :count => 0,
63
+ :date => {}}
64
+ end
65
+ response = {:success => 1,
66
+ :link => short_url,
67
+ :hash => BudurlMock.hash_from_short_url(short_url),
68
+ :link_preview => short_url + '?'}
69
+ end
70
+
71
+ return [200, response.to_json]
72
+ end
73
+
74
+ get '/links/expand' do
75
+ if !@@api_keys.include?(params[:api_key])
76
+ response = BudurlMock.error_response(API_KEY_ERROR)
77
+ elsif params[:link].nil?
78
+ return [200, nil]
79
+ else
80
+ url = @@short_to_long_urls[params[:link]]
81
+ if url.nil?
82
+ response = BudurlMock.error_response(SHORT_URL_ERROR)
83
+ else
84
+ response = {:success => 1,
85
+ :long_url => url[:link]}
86
+ end
87
+ end
88
+
89
+ return [200, response.to_json]
90
+ end
91
+
92
+ get '/clicks/count' do
93
+ if !@@api_keys.include?(params[:api_key])
94
+ response = BudurlMock.error_response(API_KEY_ERROR)
95
+ elsif params[:link].nil?
96
+ return [200, nil]
97
+ elsif !(url = @@short_to_long_urls[params[:link]])
98
+ response = BudurlMock.error_response(SHORT_URL_ERROR)
99
+ elsif params[:api_key] != url[:api_key]
100
+ response = BudurlMock.error_response(API_KEY_ERROR)
101
+ else
102
+ response = {:success => 1,
103
+ :link => params[:link],
104
+ :hash => BudurlMock.hash_from_short_url(params[:link]),
105
+ :count => url[:count]}
106
+ response.merge!(:dates => url[:dates]) if params[:daily] == '1'
107
+ end
108
+
109
+ return [200, response.to_json]
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,141 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'budurl'
4
+ require 'budurl/client'
5
+ require File.dirname(__FILE__) + '/../helpers/budurl_mock'
6
+
7
+ require 'ruby-debug'
8
+
9
+ describe Budurl::Client do
10
+
11
+ MIMIC_BASE_URI = 'http://127.0.0.1:11988'
12
+ API_KEY = '12345'
13
+
14
+ SHORT_URL = 'http://Ez.com/1234'
15
+ LONG_URL = 'http://www.example.com'
16
+
17
+ def create_short_url(long_url, short_url, opts={})
18
+ data = {:link => long_url,
19
+ :api_key => API_KEY,
20
+ :count => 0,
21
+ :dates => {}}.merge(opts)
22
+ BudurlMock.short_to_long_urls[short_url] = data
23
+ end
24
+
25
+ before :all do
26
+ @budurl = Budurl.new(API_KEY, MIMIC_BASE_URI)
27
+ end
28
+
29
+ before :each do
30
+ BudurlMock.clear
31
+ BudurlMock.api_keys << API_KEY
32
+ end
33
+
34
+ it 'initialises with the correct API key' do
35
+ @budurl.instance_variable_get(:@default_query_opts).should == {:api_key => API_KEY}
36
+ end
37
+
38
+ it 'returns a Budurl::Client object' do
39
+ @budurl.should be_an_instance_of(Budurl::Client)
40
+ end
41
+
42
+ describe '#shorten' do
43
+ it 'successfully shortens a URL' do
44
+ url = @budurl.shorten(LONG_URL)
45
+
46
+ url.link.should == BudurlMock.find_by_long_url(LONG_URL)
47
+ url.hash.should == BudurlMock.hash_from_short_url(url.link)
48
+ url.long_url.should be_nil
49
+ end
50
+
51
+ it 'creates unique short URLs if dupe_check is off' do
52
+ create_short_url(LONG_URL, SHORT_URL)
53
+ url = @budurl.shorten(LONG_URL)
54
+
55
+ url.link.should_not == SHORT_URL
56
+ url.hash.should_not == BudurlMock.hash_from_short_url(SHORT_URL)
57
+ url.long_url.should be_nil
58
+ end
59
+
60
+ it 'returns the last address if dupe_check is on' do
61
+ create_short_url(LONG_URL, SHORT_URL)
62
+ url = @budurl.shorten(LONG_URL, :dupe_check => 1)
63
+
64
+ url.link.should == SHORT_URL
65
+ url.hash.should == BudurlMock.hash_from_short_url(SHORT_URL)
66
+ url.long_url.should be_nil
67
+ end
68
+
69
+ it 'creates a new short URL if dupe_check is on but no duplicates exist' do
70
+ url = @budurl.shorten(LONG_URL, :dupe_check => 1)
71
+
72
+ url.link.should == BudurlMock.find_by_long_url(LONG_URL)
73
+ url.hash.should == BudurlMock.hash_from_short_url(url.link)
74
+ url.long_url.should be_nil
75
+ end
76
+
77
+ it 'reports Error 200 when called without a URL' do
78
+ lambda { @budurl.shorten(nil) }.should raise_error(Budurl::Error, /200/)
79
+ end
80
+
81
+ it 'reports Error 100 when called with an invalid API key' do
82
+ BudurlMock.api_keys.delete(API_KEY)
83
+ lambda { @budurl.shorten(LONG_URL) }.should raise_error(Budurl::Error, /100/)
84
+ end
85
+ end
86
+
87
+ describe '#expand' do
88
+ it 'successfully expands an extant short URL' do
89
+ create_short_url(LONG_URL, SHORT_URL)
90
+ url = @budurl.expand(SHORT_URL)
91
+
92
+ url.long_url.should == LONG_URL
93
+ url.link.should be_nil
94
+ url.hash.should be_nil
95
+ end
96
+
97
+ it 'reports Error 400 when passed an invalid short URL' do
98
+ lambda { @budurl.expand(SHORT_URL) }.should raise_error(Budurl::Error, /400/)
99
+ end
100
+ end
101
+
102
+ describe '#clicks' do
103
+ it 'produces a total click count' do
104
+ create_short_url(LONG_URL, SHORT_URL, :count => 10)
105
+ count = @budurl.clicks(SHORT_URL)
106
+
107
+ count.should be_an_instance_of(Hash)
108
+ count['link'].should == SHORT_URL
109
+ count['hash'].should == BudurlMock.hash_from_short_url(SHORT_URL)
110
+ count['count'].should == 10
111
+ count['dates'].should be_nil
112
+ end
113
+
114
+ it 'produces a day-to-day click count hash with the correct options' do
115
+ dates = {'2012-01-01' => 3, '2012-01-02' => 4, '2012-01-03' => 3}
116
+ create_short_url(LONG_URL, SHORT_URL, :count => 10, :dates => dates)
117
+ count = @budurl.clicks(SHORT_URL, :daily => 1)
118
+
119
+ count.should be_an_instance_of(Hash)
120
+ count['link'].should == SHORT_URL
121
+ count['hash'].should == BudurlMock.hash_from_short_url(SHORT_URL)
122
+ count['count'].should == 10
123
+ count['dates'].should be_an_instance_of(Hash)
124
+ count['dates'].should == dates
125
+ end
126
+
127
+ it 'reports Error 400 when passed an invalid short URL' do
128
+ lambda { @budurl.clicks(SHORT_URL) }.should raise_error(Budurl::Error, /400/)
129
+ end
130
+
131
+ it 'reports Error 100 when passed a short URL not belonging to us' do
132
+ create_short_url(LONG_URL, SHORT_URL, :api_key => '00000')
133
+ lambda { @budurl.clicks(SHORT_URL) }.should raise_error(Budurl::Error, /100/)
134
+ end
135
+
136
+ it 'reports Error 100 when called with an invalid API key' do
137
+ BudurlMock.api_keys.delete(API_KEY)
138
+ lambda { @budurl.clicks(SHORT_URL) }.should raise_error(Budurl::Error, /100/)
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,87 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'budurl'
4
+ require 'budurl/url'
5
+ require File.dirname(__FILE__) + '/../helpers/budurl_mock'
6
+
7
+ require 'ruby-debug'
8
+
9
+ describe Budurl::Url do
10
+
11
+ MIMIC_BASE_URI = 'http://127.0.0.1:11988'
12
+ API_KEY = '12345'
13
+
14
+ SHORT_URL = 'http://Ez.com/1234'
15
+ LONG_URL = 'http://www.example.com'
16
+
17
+ def create_short_url(long_url, short_url, opts={})
18
+ data = {:link => long_url,
19
+ :api_key => API_KEY,
20
+ :count => 0,
21
+ :dates => {}}.merge(opts)
22
+ BudurlMock.short_to_long_urls[short_url] = data
23
+ end
24
+
25
+ before :all do
26
+ @budurl = Budurl.new(API_KEY, MIMIC_BASE_URI)
27
+ end
28
+
29
+ before :each do
30
+ BudurlMock.clear
31
+ BudurlMock.api_keys << API_KEY
32
+ end
33
+
34
+ it 'saves the calling Budurl client internally' do
35
+ url = Budurl::Url.new(@budurl)
36
+ url.instance_variable_get(:@client).should be_an_instance_of(Budurl::Client)
37
+ end
38
+
39
+ it 'internalizes relevant information from a hash' do
40
+ data = {'success' => '1',
41
+ 'link' => SHORT_URL,
42
+ 'long_url' => LONG_URL,
43
+ 'hash' => BudurlMock.hash_from_short_url(SHORT_URL)}
44
+ url = Budurl::Url.new(@budurl, data)
45
+
46
+ url.link.should == SHORT_URL
47
+ url.long_url.should == LONG_URL
48
+ url.hash.should == BudurlMock.hash_from_short_url(SHORT_URL)
49
+ end
50
+
51
+ describe '#clicks' do
52
+ it 'returns the click count for a short URL' do
53
+ create_short_url(LONG_URL, SHORT_URL, :count => 10, :dates => {'2012-01-01' => 10})
54
+
55
+ data = {'success' => '1',
56
+ 'link' => SHORT_URL,
57
+ 'long_url' => LONG_URL,
58
+ 'hash' => BudurlMock.hash_from_short_url(SHORT_URL)}
59
+ url = Budurl::Url.new(@budurl, data)
60
+
61
+ url.clicks.should == 10
62
+ end
63
+
64
+ it 'returns the daily click counts for a URL with daily = true' do
65
+ create_short_url(LONG_URL, SHORT_URL, :count => 10, :dates => {'2012-01-01' => 10})
66
+
67
+ data = {'success' => '1',
68
+ 'link' => SHORT_URL,
69
+ 'long_url' => LONG_URL,
70
+ 'hash' => BudurlMock.hash_from_short_url(SHORT_URL)}
71
+ url = Budurl::Url.new(@budurl, data)
72
+
73
+ url.clicks(true).should == {'2012-01-01' => 10}
74
+ end
75
+
76
+ it 'raises Error 0 for a long URL with no short URL associated' do
77
+ data = {'success' => '1',
78
+ 'link' => SHORT_URL,
79
+ 'long_url' => LONG_URL,
80
+ 'hash' => BudurlMock.hash_from_short_url(SHORT_URL)}
81
+ url = Budurl::Url.new(@budurl)
82
+
83
+ lambda { url.clicks }.should raise_error(Budurl::Error, /0/)
84
+ lambda { url.clicks(true) }.should raise_error(Budurl::Error, /0/)
85
+ end
86
+ end
87
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: budurl
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Anuj Das
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-04-25 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: httparty
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: ruby-debug
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: mimic
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :development
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: json
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ type: :development
89
+ version_requirements: *id005
90
+ description: Supported operations include shrinking, expanding, and counting clicks.
91
+ email:
92
+ - anuj.das@mylookout.com
93
+ executables:
94
+ - expand
95
+ - shorten
96
+ - stats
97
+ extensions: []
98
+
99
+ extra_rdoc_files: []
100
+
101
+ files:
102
+ - .gitignore
103
+ - Gemfile
104
+ - README.md
105
+ - Rakefile
106
+ - bin/expand
107
+ - bin/shorten
108
+ - bin/stats
109
+ - budurl.gemspec
110
+ - lib/budurl.rb
111
+ - lib/budurl/client.rb
112
+ - lib/budurl/url.rb
113
+ - lib/budurl/version.rb
114
+ - test/helpers/budurl_mock.rb
115
+ - test/unit/client_spec.rb
116
+ - test/unit/url_spec.rb
117
+ homepage: https://github.com/lookout/budurl-gem
118
+ licenses: []
119
+
120
+ post_install_message:
121
+ rdoc_options: []
122
+
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ none: false
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ hash: 3
131
+ segments:
132
+ - 0
133
+ version: "0"
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ hash: 3
140
+ segments:
141
+ - 0
142
+ version: "0"
143
+ requirements: []
144
+
145
+ rubyforge_project:
146
+ rubygems_version: 1.8.23
147
+ signing_key:
148
+ specification_version: 3
149
+ summary: A gem for interfacing with the BudURL.Pro url shortener API
150
+ test_files:
151
+ - test/helpers/budurl_mock.rb
152
+ - test/unit/client_spec.rb
153
+ - test/unit/url_spec.rb