cotweet-bitly 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ require 'cgi'
2
+
3
+ module Bitly
4
+ module Utils
5
+ def underscore(camel_cased_word) # stolen from rails
6
+ camel_cased_word.to_s.gsub(/::/, '/').
7
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
8
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
9
+ tr("-", "_").
10
+ downcase
11
+ end
12
+
13
+ def create_hash_from_url(url)
14
+ url.gsub(/^.*(bit\.ly|j\.mp)\//,'')
15
+ end
16
+
17
+ def attr_define(k,v)
18
+ instance_variable_set("@#{k}", v)
19
+ meta = class << self; self; end
20
+ meta.class_eval { attr_reader k.to_sym }
21
+ end
22
+
23
+ def instance_variablise(obj,variables)
24
+ if obj.is_a? Hash
25
+ obj.each do |k,v|
26
+ if v.is_a? Hash
27
+ instance_variablise(v,variables)
28
+ else
29
+ attr_define(underscore(k),v) if variables.include?(underscore(k))
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def create_url(resource="",args={})
36
+ args = args.merge({:login => @login, :apiKey => @api_key, :version => API_VERSION})
37
+ url = URI.join(API_URL,resource)
38
+ long_urls = args.delete(:long_urls)
39
+ url.query = args.map { |k,v| "%s=%s" % [CGI.escape(k.to_s), CGI.escape(v.to_s)] }.join("&")
40
+ url.query << "&" + long_urls.map { |long_url| "longUrl=#{CGI.escape(long_url)}" }.join("&") unless long_urls.nil?
41
+ url
42
+ end
43
+
44
+ def get_result(request)
45
+ begin
46
+ json = Net::HTTP.get(request)
47
+ # puts json.inspect
48
+ result = Crack::JSON.parse(json)
49
+ rescue
50
+ result = {'errorMessage' => 'JSON Parse Error(Bit.ly messed up)', 'errorCode' => 69, 'statusCode' => 'ERROR'}
51
+ end
52
+ if result['statusCode'] == "OK"
53
+ result = result['results']
54
+ else
55
+ raise BitlyError.new(result['errorMessage'],result['errorCode'])
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'httparty'
4
+ require 'cgi'
5
+
6
+ require 'v3/bitly'
7
+ require 'v3/client'
8
+ require 'v3/url'
9
+ require 'v3/missing_url'
@@ -0,0 +1,16 @@
1
+ module Bitly
2
+ module V3
3
+ def self.new(login, api_key)
4
+ Bitly::V3::Client.new(login, api_key)
5
+ end
6
+ end
7
+ end
8
+
9
+ class BitlyError < StandardError
10
+ attr_reader :code
11
+ alias :msg :message
12
+ def initialize(msg, code)
13
+ @code = code
14
+ super("#{msg} - '#{code}'")
15
+ end
16
+ end
@@ -0,0 +1,143 @@
1
+ module Bitly
2
+ module V3
3
+ # The client is the main part of this gem. You need to initialize the client with your
4
+ # username and API key and then you will be able to use the client to perform
5
+ # all the rest of the actions available through the API.
6
+ class Client
7
+ include HTTParty
8
+ base_uri 'http://api.bit.ly/v3/'
9
+
10
+ # Requires a login and api key. Get yours from your account page at http://bit.ly/a/account
11
+ def initialize(login, api_key)
12
+ @default_query_opts = { :login => login, :apiKey => api_key }
13
+ end
14
+
15
+ # Validates a login and api key
16
+ def validate(x_login, x_api_key)
17
+ response = get('/validate', :query => { :x_login => x_login, :x_apiKey => x_api_key })
18
+ return response['data']['valid'] == 1
19
+ end
20
+ alias :valid? :validate
21
+
22
+ # Checks whether a domain is a bitly.Pro domain
23
+ def bitly_pro_domain(domain)
24
+ response = get('/bitly_pro_domain', :query => { :domain => domain })
25
+ return response['data']['bitly_pro_domain']
26
+ end
27
+ alias :pro? :bitly_pro_domain
28
+
29
+ # Shortens a long url
30
+ #
31
+ # Options can be:
32
+ #
33
+ # [domain] choose bit.ly or j.mp (bit.ly is default)
34
+ #
35
+ # [x_login and x_apiKey] add this link to another user's history (both required)
36
+ #
37
+ def shorten(long_url, opts={})
38
+ query = { :longUrl => long_url }.merge(opts)
39
+ response = get('/shorten', :query => query)
40
+ return Bitly::V3::Url.new(self, response['data'])
41
+ end
42
+
43
+ # Expands either a hash, short url or array of either.
44
+ #
45
+ # Returns the results in the order they were entered
46
+ def expand(input)
47
+ get_method(:expand, input)
48
+ end
49
+
50
+ # Expands either a hash, short url or array of either and gets click data too.
51
+ #
52
+ # Returns the results in the order they were entered
53
+ def clicks(input)
54
+ get_method(:clicks, input)
55
+ end
56
+
57
+ # Like expand, but gets the title of the page and who created it
58
+ def info(input)
59
+ get_method(:info, input)
60
+ end
61
+
62
+ # Provides a list of referring sites for a specified bit.ly short link, and the number of clicks per referrer.
63
+ def referrers(input)
64
+ if is_a_short_url?(input)
65
+ query = { :shortUrl => CGI.escape(input) }
66
+ else
67
+ query = { :hash => CGI.escape(input) }
68
+ end
69
+ get("/referrers", :query => query)["data"]
70
+ end
71
+
72
+ # Looks up the short url and global hash of a url or array of urls
73
+ #
74
+ # Returns the results in the order they were entered
75
+ def lookup(input)
76
+ input = [input] if input.is_a?(String)
77
+ query = input.inject([]) { |query, i| query << "url=#{CGI.escape(i)}" }
78
+ query = "/lookup?" + query.join('&')
79
+ response = get(query)
80
+ results = response['data']['lookup'].inject([]) do |results, url|
81
+ url['long_url'] = url['url']
82
+ url['url'] = nil
83
+ if url['error'].nil?
84
+ # builds the results array in the same order as the input
85
+ results[input.index(url['long_url'])] = Bitly::V3::Url.new(self, url)
86
+ # remove the key from the original array, in case the same hash/url was entered twice
87
+ input[input.index(url['long_url'])] = nil
88
+ else
89
+ results[input.index(url['long_url'])] = Bitly::V3::MissingUrl.new(url)
90
+ input[input.index(url['long_url'])] = nil
91
+ end
92
+ results
93
+ end
94
+ return results.length > 1 ? results : results[0]
95
+ end
96
+
97
+ private
98
+
99
+ def get(method, opts={})
100
+ opts[:query] ||= {}
101
+ opts[:query].merge!(@default_query_opts)
102
+ response = self.class.get(method, opts)
103
+ if response['status_code'] == 200
104
+ return response
105
+ else
106
+ raise BitlyError.new(response['status_txt'], response['status_code'])
107
+ end
108
+ end
109
+
110
+ def is_a_short_url?(input)
111
+ input.match(/^http:\/\//)
112
+ end
113
+
114
+ def get_method(method, input)
115
+ input = [input] if input.is_a? String
116
+ query = input.inject([]) do |query,i|
117
+ if is_a_short_url?(i)
118
+ query << "shortUrl=#{CGI.escape(i)}"
119
+ else
120
+ query << "hash=#{CGI.escape(i)}"
121
+ end
122
+ end
123
+ query = "/#{method}?" + query.join('&')
124
+ response = get(query)
125
+ results = response['data'][method.to_s].inject([]) do |results, url|
126
+ result_index = input.index(url['short_url'] || url['hash']) || input.index(url['global_hash'])
127
+ if url['error'].nil?
128
+ # builds the results array in the same order as the input
129
+ results[result_index] = Bitly::V3::Url.new(self, url)
130
+ # remove the key from the original array, in case the same hash/url was entered twice
131
+ input[result_index] = nil
132
+ else
133
+ results[result_index] = Bitly::V3::MissingUrl.new(url)
134
+ input[result_index] = nil
135
+ end
136
+ results
137
+ end
138
+ return results.length > 1 ? results : results[0]
139
+ end
140
+
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,15 @@
1
+ module Bitly
2
+ module V3
3
+ class MissingUrl
4
+ attr_accessor :short_url, :user_hash, :long_url, :error
5
+ def initialize(opts={})
6
+ if opts
7
+ @short_url = opts['short_url']
8
+ @user_hash = opts['hash']
9
+ @long_url = opts['long_url']
10
+ @error = opts['error']
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,77 @@
1
+ module Bitly
2
+ module V3
3
+ # Url objects should only be created by the client object as it collects the correct information
4
+ # from the API.
5
+ class Url
6
+ attr_reader :short_url, :long_url, :user_hash, :global_hash
7
+
8
+ # Initialize with a bitly client and optional hash to fill in the details for the url.
9
+ def initialize(client, opts={})
10
+ @client = client
11
+ if opts
12
+ @short_url = opts['url'] || opts['short_url']
13
+ @long_url = opts['long_url']
14
+ @user_hash = opts['hash'] || opts['user_hash']
15
+ @global_hash = opts['global_hash']
16
+ @new_hash = (opts['new_hash'] == 1)
17
+ @user_clicks = opts['user_clicks']
18
+ @global_clicks = opts['global_clicks']
19
+ @title = opts['title']
20
+ @created_by = opts['created_by']
21
+ end
22
+ @short_url = "http://bit.ly/#{@user_hash}" unless @short_url
23
+ end
24
+
25
+ # Returns true if the user hash was created first for this call
26
+ def new_hash?
27
+ @new_hash
28
+ end
29
+
30
+ # If the url already has click statistics, returns the user clicks.
31
+ # IF there are no click statistics or <tt>:force => true</tt> is passed,
32
+ # updates the stats and returns the user clicks
33
+ def user_clicks(opts={})
34
+ update_clicks_data if @global_clicks.nil? || opts[:force]
35
+ @user_clicks
36
+ end
37
+
38
+ # If the url already has click statistics, returns the global clicks.
39
+ # IF there are no click statistics or <tt>:force => true</tt> is passed,
40
+ # updates the stats and returns the global clicks
41
+ def global_clicks(opts={})
42
+ update_clicks_data if @global_clicks.nil? || opts[:force]
43
+ @global_clicks
44
+ end
45
+
46
+ # If the url already has the title, return it.
47
+ # IF there is no title or <tt>:force => true</tt> is passed,
48
+ # updates the info and returns the title
49
+ def title(opts={})
50
+ update_info if @title.nil? || opts[:force]
51
+ @title
52
+ end
53
+
54
+ # If the url already has the creator, return it.
55
+ # IF there is no creator or <tt>:force => true</tt> is passed,
56
+ # updates the info and returns the creator
57
+ def created_by(opts={})
58
+ update_info if @created_by.nil? || opts[:force]
59
+ @created_by
60
+ end
61
+
62
+ private
63
+
64
+ def update_clicks_data
65
+ full_url = @client.clicks(@user_hash || @short_url)
66
+ @global_clicks = full_url.global_clicks
67
+ @user_clicks = full_url.user_clicks
68
+ end
69
+
70
+ def update_info
71
+ full_url = @client.info(@user_hash || @short_url)
72
+ @created_by = full_url.created_by
73
+ @title = full_url.title
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module Bitly
2
+ VERSION = '0.5.3'
3
+ end
@@ -0,0 +1,215 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper.rb')
2
+
3
+ class TestClient < Test::Unit::TestCase
4
+ context "bitly module" do
5
+ should "create a new bitly client" do
6
+ b = Bitly.new(login, api_key)
7
+ assert_equal Bitly::Client, b.class
8
+ end
9
+ end
10
+ context "using the bitly client" do
11
+ setup do
12
+ @bitly = Bitly.new(login, api_key)
13
+ end
14
+
15
+ context "shortening" do
16
+ context "a single link" do
17
+ setup do
18
+ stub_get(/^http:\/\/api.bit.ly\/shorten\?.*longUrl=.*cnn.com.*$/,"cnn.json")
19
+ @url = @bitly.shorten('http://cnn.com')
20
+ end
21
+ should "return a Bitly::Url" do
22
+ assert_kind_of Bitly::Url, @url
23
+ end
24
+ should "return a short bitly url" do
25
+ assert_equal "http://bit.ly/15DlK", @url.short_url
26
+ assert_equal "http://bit.ly/15DlK", @url.bitly_url
27
+ end
28
+ should "return a short jmp url" do
29
+ assert_equal "http://j.mp/15DlK", @url.jmp_url
30
+ end
31
+ should "save the long url" do
32
+ assert_equal "http://cnn.com", @url.long_url
33
+ end
34
+ end
35
+ context "multiple links" do
36
+ setup do
37
+ stub_get(/^http:\/\/api.bit.ly\/shorten\?.*longUrl=.*longUrl=.*$/,"cnn_and_google.json")
38
+ @urls = @bitly.shorten(['http://cnn.com', 'http://google.com'])
39
+ end
40
+ should "return an array of Bitly::Urls" do
41
+ assert_kind_of Array, @urls
42
+ assert_kind_of Bitly::Url, @urls[0]
43
+ end
44
+ should "shorten the urls in order" do
45
+ assert_equal "http://bit.ly/15DlK", @urls[0].short_url
46
+ assert_equal "http://bit.ly/11etr", @urls[1].short_url
47
+ end
48
+ should "save the long urls" do
49
+ assert_equal "http://cnn.com", @urls[0].long_url
50
+ assert_equal "http://google.com", @urls[1].long_url
51
+ end
52
+ end
53
+ context "no links" do
54
+ should "raise an ArgumentError" do
55
+ assert_raise ArgumentError do
56
+ @bitly.shorten
57
+ end
58
+ end
59
+ end
60
+ end
61
+ context "expanding" do
62
+ context "a hash" do
63
+ setup do
64
+ stub_get(/^http:\/\/api.bit.ly\/expand\?.*hash=31IqMl.*$/,"expand_cnn.json")
65
+ @url = @bitly.expand("31IqMl")
66
+ end
67
+ should "return a Bitly::Url" do
68
+ assert_kind_of Bitly::Url, @url
69
+ end
70
+ should "return the expanded url" do
71
+ assert_equal "http://cnn.com/", @url.long_url
72
+ end
73
+ should "save the hash" do
74
+ assert_equal "31IqMl", @url.hash
75
+ end
76
+ should "save the short url" do
77
+ assert_equal "http://bit.ly/31IqMl", @url.short_url
78
+ end
79
+ end
80
+ context "a short bitly url" do
81
+ setup do
82
+ stub_get(/^http:\/\/api.bit.ly\/expand\?.*hash=31IqMl.*$/,"expand_cnn.json")
83
+ @url = @bitly.expand("http://bit.ly/31IqMl")
84
+ end
85
+ should "return a Bitly::Url" do
86
+ assert_kind_of Bitly::Url, @url
87
+ end
88
+ should "return the expanded url" do
89
+ assert_equal "http://cnn.com/", @url.long_url
90
+ end
91
+ should "save the hash" do
92
+ assert_equal "31IqMl", @url.hash
93
+ end
94
+ should "save the bitly url" do
95
+ assert_equal "http://bit.ly/31IqMl", @url.bitly_url
96
+ end
97
+ should "save a jmp url" do
98
+ assert_equal "http://j.mp/31IqMl", @url.jmp_url
99
+ end
100
+ end
101
+ context "a short jmp url" do
102
+ setup do
103
+ stub_get(/^http:\/\/api.bit.ly\/expand\?.*hash=31IqMl.*$/,"expand_cnn.json")
104
+ @url = @bitly.expand("http://j.mp/31IqMl")
105
+ end
106
+ should "return a Bitly::Url" do
107
+ assert_kind_of Bitly::Url, @url
108
+ end
109
+ should "return the expanded url" do
110
+ assert_equal "http://cnn.com/", @url.long_url
111
+ end
112
+ should "save the hash" do
113
+ assert_equal "31IqMl", @url.hash
114
+ end
115
+ should "save the bitly url" do
116
+ assert_equal "http://bit.ly/31IqMl", @url.bitly_url
117
+ end
118
+ should "save a jmp url" do
119
+ assert_equal "http://j.mp/31IqMl", @url.jmp_url
120
+ end
121
+ end
122
+ context "multiple hashes" do
123
+ setup do
124
+ stub_get(/^http:\/\/api.bit.ly\/expand\?.*hash=15DlK.*3j4ir4.*$/,"expand_cnn_and_google.json")
125
+ @urls = @bitly.expand(["15DlK","3j4ir4"])
126
+ end
127
+ should "return an array of Bitly::Urls" do
128
+ assert_kind_of Array, @urls
129
+ assert_kind_of Bitly::Url, @urls[0]
130
+ assert_kind_of Bitly::Url, @urls[1]
131
+ end
132
+ should "expand the hashes in order" do
133
+ assert_equal "http://cnn.com/", @urls[0].long_url
134
+ assert_equal "http://google.com/", @urls[1].long_url
135
+ end
136
+ should "save the hash to each url" do
137
+ assert_equal "15DlK", @urls[0].hash
138
+ assert_equal "3j4ir4", @urls[1].hash
139
+ end
140
+ end
141
+ end
142
+ context "to get info on" do
143
+ context "a single link" do
144
+ setup do
145
+ stub_get(/^http:\/\/api.bit.ly\/info\?.*hash=3j4ir4.*$/,"google_info.json")
146
+ @url = @bitly.info('http://bit.ly/3j4ir4')
147
+ end
148
+ should "return a Bitly::Url" do
149
+ assert_kind_of Bitly::Url, @url
150
+ end
151
+ should "return an info object with the url" do
152
+ assert_not_nil @url.info
153
+ end
154
+ end
155
+ context "a single hash" do
156
+ setup do
157
+ stub_get(/^http:\/\/api.bit.ly\/info\?.*hash=3j4ir4.*$/,"google_info.json")
158
+ @url = @bitly.info('3j4ir4')
159
+ end
160
+ should "return a Bitly::Url" do
161
+ assert_kind_of Bitly::Url, @url
162
+ end
163
+ should "return an info object with the url" do
164
+ assert_not_nil @url.info
165
+ end
166
+ end
167
+ context "a list of hashes" do
168
+ setup do
169
+ stub_get(/^http:\/\/api.bit.ly\/info\?.*hash=3j4ir4.*31IqMl.*$/,"google_and_cnn_info.json")
170
+ @urls = @bitly.info(['3j4ir4','31IqMl'])
171
+ end
172
+ should "return a Bitly::Url" do
173
+ assert_kind_of Array, @urls
174
+ end
175
+ should "return an info object with the url" do
176
+ assert_not_nil @urls[0].info
177
+ assert_not_nil @urls[1].info
178
+ end
179
+ end
180
+ end
181
+ context "to get stats on" do
182
+ context "a single link" do
183
+ setup do
184
+ stub_get(/^http:\/\/api.bit.ly\/stats\?.*hash=3j4ir4.*$/,"google_stats.json")
185
+ @url = @bitly.stats('http://bit.ly/3j4ir4')
186
+ end
187
+ should "return a Bitly::Url" do
188
+ assert_kind_of Bitly::Url, @url
189
+ end
190
+ should "return an stats object" do
191
+ assert_not_nil @url.stats
192
+ end
193
+ end
194
+ context "a single hash" do
195
+ setup do
196
+ stub_get(/^http:\/\/api.bit.ly\/stats\?.*hash=3j4ir4.*$/,"google_stats.json")
197
+ @url = @bitly.stats('3j4ir4')
198
+ end
199
+ should "return a Bitly::Url" do
200
+ assert_kind_of Bitly::Url, @url
201
+ end
202
+ should "return an stats object" do
203
+ assert_not_nil @url.stats
204
+ end
205
+ end
206
+ context "a list of hashes" do
207
+ should "return an argument error" do
208
+ assert_raise ArgumentError do
209
+ @bitly.stats(['3j4ir4','31IqMl'])
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end