budurl 0.0.1

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.
@@ -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