url_shortener 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2009-11-08
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ lib/url_shortener.rb
5
+ lib/url_shortener/authorize.rb
6
+ lib/url_shortener/client.rb
7
+ lib/url_shortener/error.rb
8
+ lib/url_shortener/interface.rb
9
+ spec/spec_helper.rb
10
+ spec/url_shortener/authorize_spec.rb
11
+ spec/url_shortener/client_spec.rb
12
+ spec/url_shortener/interface_spec.rb
13
+ features/connect_to_bitly.feature
14
+ features/short_url.feature
15
+ features/support/env.rb
16
+ features/step_definitions/connection_error_steps.rb
17
+ features/step_definitions/short_url_steps.rb
data/README.rdoc ADDED
@@ -0,0 +1,54 @@
1
+ ==Description
2
+
3
+ Url Shortener is a Ruby library / gem and API wrapper for bit.ly to shorten the urls.
4
+
5
+ To use the url_shortener gem you need a bit.ly login and Api key.
6
+
7
+ * If you are registered at bit.ly then you already have it.
8
+ * If you are not registered then you can get it easily by registering at bit.ly as they give an api key to every registered user
9
+
10
+ ==USAGE
11
+
12
+ * authorize = UrlShortener::Authorize.new 'bitlyapidemo', 'R_0da49e0a9118ff35f52f629d2d71bf07'
13
+
14
+ * client = UrlShortener::Client.new authorize
15
+
16
+ * results = client.shorten('http://www.yahoo.com')
17
+
18
+ * results['shortUrl']
19
+
20
+ OR
21
+
22
+ * results = client.shorten('http://www.yahoo.com', 'http://www.google.com', 'http://github.com')
23
+
24
+ * results.each {|result| puts result['shortUrl']}
25
+
26
+
27
+ ==Tests
28
+
29
+ Tests are written using RSpec and Cucumber. Integration tests use bit.ly demo login and api key credentials.
30
+
31
+ == LICENSE:
32
+
33
+ (The MIT License)
34
+
35
+ Copyright (c) 2009 Nasir Jamal
36
+
37
+ Permission is hereby granted, free of charge, to any person obtaining
38
+ a copy of this software and associated documentation files (the
39
+ 'Software'), to deal in the Software without restriction, including
40
+ without limitation the rights to use, copy, modify, merge, publish,
41
+ distribute, sublicense, and/or sell copies of the Software, and to
42
+ permit persons to whom the Software is furnished to do so, subject to
43
+ the following conditions:
44
+
45
+ The above copyright notice and this permission notice shall be
46
+ included in all copies or substantial portions of the Software.
47
+
48
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
49
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
50
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
51
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
52
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
53
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
54
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ Feature: Get informative messages
2
+ In order to take appropriate measures
3
+ As a user
4
+ I want to be able to get meaningful and appropriate messages when I am not able to connect to bit.ly
5
+
6
+ Scenario: Return authorization failure when correct login is present and api key is wrong
7
+ Given I use "correct" "bit.ly" login name as "bitlyapidemo"
8
+ And I use "incorrect" "bit.ly" api key as "123123"
9
+ And I use "incorrect" credentials
10
+ When I submit a request to "bit.ly"
11
+ Then I should get the "UrlShortener::AuthorizationFailure" error
12
+
13
+ Scenario: Return authorization failure when correct api key is present with wrong login name
14
+ Given I use "incorrect" "bit.ly" login name as "123123"
15
+ And I use "correct" "bit.ly" api key as "R_0da49e0a9118ff35f52f629d2d71bf07"
16
+ And I use "incorrect" credentials
17
+ When I submit a request to "bit.ly"
18
+ Then I should get the "UrlShortener::AuthorizationFailure" error
@@ -0,0 +1,14 @@
1
+ Feature: Shorten the url
2
+ In order to write less characters
3
+ As a user
4
+ I want to shorten the long urls
5
+
6
+ Scenario: Create a short url when correct login and api key is present
7
+ Given I use "correct" "bit.ly" login name as "bitlyapidemo"
8
+ And I use "correct" "bit.ly" api key as "R_0da49e0a9118ff35f52f629d2d71bf07"
9
+ And I use "correct" credentials
10
+ And "bit.ly" is online
11
+ When I submit a request to shorten the url "http://www.github.com/nas"
12
+ Then I should get the response from "bit.ly"
13
+ And the shorten url should be "http://bit.ly/6NaDb"
14
+ And the hash should be "2oV4lu"
@@ -0,0 +1,41 @@
1
+ # ===============
2
+ # = Given Steps =
3
+ # ===============
4
+ Given /^I use "([^\"]*)" "([^\"]*)" login name as "([^\"]*)"$/ do |info_type, service, login|
5
+ @login = login
6
+ end
7
+
8
+ Given /^I use "([^\"]*)" "([^\"]*)" api key as "([^\"]*)"$/ do |info_type, service, api_key|
9
+ @api_key = api_key
10
+ end
11
+
12
+ Given /^I use "([^\"]*)" credentials$/ do |info_type|
13
+ @authorize = UrlShortener::Authorize.new(@login, @api_key)
14
+ end
15
+
16
+ Given /^"([^\"]*)" is online$/ do |site|
17
+ check_url=Net::HTTP.get_response(URI.parse('http://'+site))
18
+ check_url.code.should eql '200'
19
+ end
20
+
21
+ # ==============
22
+ # = When Steps =
23
+ # ==============
24
+
25
+ When /^I submit a request to "([^\"]*)"$/ do |arg1|
26
+ begin
27
+ @client = UrlShortener::Client.new(@authorize)
28
+ @client.shorten('http://cnn.com')
29
+ rescue => e
30
+ @error = e
31
+ end
32
+ end
33
+
34
+ # ==============
35
+ # = Then steps =
36
+ # ==============
37
+
38
+
39
+ Then /^I should get the "([^\"]*)" error$/ do |error_class|
40
+ @error.class.to_s.should eql(error_class)
41
+ end
@@ -0,0 +1,23 @@
1
+ # ==============
2
+ # = When Steps =
3
+ # ==============
4
+ When /^I submit a request to shorten the url "([^\"]*)"$/ do |url|
5
+ authorize = UrlShortener::Authorize.new('bitlyapidemo', 'R_0da49e0a9118ff35f52f629d2d71bf07')
6
+ client = UrlShortener::Client.new(authorize)
7
+ @result = client.shorten(url)
8
+ end
9
+
10
+ # ==============
11
+ # = Then Steps =
12
+ # ==============
13
+ Then /^I should get the response from "([^\"]*)"$/ do |arg1|
14
+ @result.should_not be_nil
15
+ end
16
+
17
+ Then /^the shorten url should be "([^\"]*)"$/ do |short_url|
18
+ @result['shortUrl'].should eql(short_url)
19
+ end
20
+
21
+ Then /^the hash should be "([^\"]*)"$/ do |hash|
22
+ @result['hash'].should eql(hash)
23
+ end
@@ -0,0 +1,3 @@
1
+ $: << File.join(File.dirname(__FILE__), "/../../lib")
2
+
3
+ require 'url_shortener'
@@ -0,0 +1,12 @@
1
+ module UrlShortener
2
+ class Authorize
3
+
4
+ attr_accessor :login, :api_key, :base_url
5
+
6
+ def initialize(login, api_key)
7
+ @login = login
8
+ @api_key = api_key
9
+ @base_url = 'http://api.bit.ly'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,47 @@
1
+ module UrlShortener
2
+ class Client
3
+
4
+ attr_accessor :authorize
5
+
6
+ def initialize(authorize)
7
+ @authorize = authorize
8
+ validated?
9
+ end
10
+
11
+ def shorten(*url)
12
+ # HTTParty accepts a hash for url parameters but if more than one parameters are passed
13
+ # to bitly then the url needs to have longUrl parameter multiple times but we cant have
14
+ # duplicate keys in a hash hence this solution
15
+ end_point_with_params = "#{end_point('shorten')}?longUrl=#{url.join('&longUrl=')}"
16
+ interface(end_point_with_params).get['nodeKeyVal']
17
+ end
18
+
19
+ def interface(end_point_with_params)
20
+ UrlShortener::Interface.new(end_point_with_params, :query => common_query_parameters)
21
+ end
22
+
23
+ def common_query_parameters
24
+ {:login => authorize.login,
25
+ :apiKey => authorize.api_key,
26
+ :version => '2.0.1',
27
+ :format => 'xml'
28
+ }
29
+ end
30
+
31
+ def end_point(resource)
32
+ "#{authorize.base_url}/#{resource}"
33
+ end
34
+
35
+ private
36
+
37
+ def validated?
38
+ valid_authorize_attribute?
39
+ end
40
+
41
+ def valid_authorize_attribute?
42
+ return true if authorize.is_a?(UrlShortener::Authorize)
43
+ raise UrlShortener::AuthorizationFailure, "Authorization type failure\n Received: #{authorize.class} \n Expected: UrlShortener::Authorize"
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,18 @@
1
+ module UrlShortener
2
+ class Error < StandardError
3
+
4
+ def initialize(data)
5
+ @data = data
6
+ super
7
+ end
8
+ end
9
+
10
+ class AuthorizationFailure < Error
11
+ end
12
+
13
+ class ResponseFailure < Error
14
+ end
15
+
16
+ class NoResult < Error
17
+ end
18
+ end
@@ -0,0 +1,50 @@
1
+ module UrlShortener
2
+ require 'timeout'
3
+
4
+ class Interface
5
+ include HTTParty
6
+
7
+ attr_reader :rest_url
8
+
9
+ def initialize(rest_url, options={})
10
+ @rest_url = rest_url
11
+ @options = options
12
+ @result = nil
13
+ validate?
14
+ end
15
+
16
+ def get
17
+ @result ||= UrlShortener::Interface.get(rest_url, @options)
18
+ timeout(10) do
19
+ unless result?(@result)
20
+ raise UrlShortener::NoResult, "No result returned from bit.ly"
21
+ end
22
+ if @result['bitly']['errorCode'] == '203'
23
+ raise UrlShortener::AuthorizationFailure, @result['bitly']['errorMessage']
24
+ end
25
+ if @result['bitly']['statusCode'] != 'OK' && @result['bitly']['errorCode'] != '0'
26
+ raise UrlShortener::ResponseFailure, @result['bitly']['errorMessage']
27
+ end
28
+ end
29
+ return @result['bitly']['results']
30
+ rescue Timeout::Error => e
31
+ raise UrlShortener::ResponseFailure, "Connection timed out"
32
+ end
33
+
34
+ def result?(result)
35
+ return false unless result
36
+ return false unless (result.is_a?(Hash) && result['bitly'])
37
+ return false if result['bitly'].empty?
38
+ true
39
+ end
40
+
41
+ private
42
+
43
+ # To prevent calling UrlShortener::Interface.new(nil)
44
+ def validate?
45
+ return true if rest_url
46
+ raise "Interface Url cannot be nil"
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'httparty'
6
+ require 'url_shortener/error.rb'
7
+ require 'url_shortener/authorize.rb'
8
+ require 'url_shortener/client.rb'
9
+ require 'url_shortener/interface.rb'
@@ -0,0 +1,3 @@
1
+ $: << File.join(File.dirname(__FILE__), "/../lib")
2
+ require 'spec'
3
+ require 'url_shortener'
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe UrlShortener::Authorize do
4
+
5
+ describe ".new" do
6
+ before(:each) do
7
+ @url_shortener = UrlShortener::Authorize.new('login', 'key')
8
+ end
9
+
10
+ it "should have the login attribute" do
11
+ @url_shortener.login.should eql('login')
12
+ end
13
+
14
+ it "should have the api key attribute" do
15
+ @url_shortener.api_key.should eql('key')
16
+ end
17
+
18
+ it "should have the base url attribute set to bitly api" do
19
+ @url_shortener.base_url.should eql('http://api.bit.ly')
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,129 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe UrlShortener::Client do
4
+ describe ".new" do
5
+ before(:each) do
6
+ @authorize = UrlShortener::Authorize.new 'login', 'key'
7
+ end
8
+
9
+ it "should recieve the authorize object" do
10
+ client = UrlShortener::Client.new(@authorize)
11
+ client.authorize.should eql(@authorize)
12
+ end
13
+
14
+ it "should raise an error if the authorize attribute is not a UrlShortener::Authorize object" do
15
+ lambda{ UrlShortener::Client.new(nil) }.should raise_error(UrlShortener::AuthorizationFailure)
16
+ end
17
+
18
+ end
19
+
20
+ describe "#end_point" do
21
+ before(:each) do
22
+ @authorize = UrlShortener::Authorize.new 'login', 'key'
23
+ @client = UrlShortener::Client.new(@authorize)
24
+ @resource = 'any'
25
+ end
26
+
27
+ it "should get the base url from authorization" do
28
+ @authorize.should_receive(:base_url)
29
+ @client.end_point(@resource)
30
+ end
31
+
32
+ it "should return the combination of base url and resource" do
33
+ @client.end_point(@resource).should eql('http://api.bit.ly/any')
34
+ end
35
+ end
36
+
37
+ describe "#common_query_parameters" do
38
+ before(:each) do
39
+ @authorize = UrlShortener::Authorize.new 'login', 'key'
40
+ @client = UrlShortener::Client.new(@authorize)
41
+ end
42
+
43
+ it "should return a hash of comman parameters" do
44
+ @client.common_query_parameters.should be_instance_of(Hash)
45
+ end
46
+
47
+ it "should include the login key" do
48
+ @client.common_query_parameters.keys.should include(:login)
49
+ end
50
+
51
+ it "should include the apiKey key" do
52
+ @client.common_query_parameters.keys.should include(:apiKey)
53
+ end
54
+
55
+ it "should include the version key" do
56
+ @client.common_query_parameters.keys.should include(:version)
57
+ end
58
+
59
+ it "should include the format key" do
60
+ @client.common_query_parameters.keys.should include(:format)
61
+ end
62
+
63
+ it "should get login attribute of authorize object" do
64
+ @authorize.should_receive(:login)
65
+ @client.common_query_parameters
66
+ end
67
+
68
+ it "should have the login key value from the login attribute of authorize object" do
69
+ @client.common_query_parameters[:login].should eql('login')
70
+ end
71
+
72
+ it "should get api key attribute of authorize object" do
73
+ @authorize.should_receive(:api_key)
74
+ @client.common_query_parameters
75
+ end
76
+
77
+ it "should have the apikey value from the api_key attribute of authorize object" do
78
+ @client.common_query_parameters[:apiKey].should eql('key')
79
+ end
80
+
81
+ it "should have the value of xml for the format key" do
82
+ @client.common_query_parameters[:format].should eql('xml')
83
+ end
84
+ end
85
+
86
+ describe "#shorten" do
87
+ before(:each) do
88
+ authorize = UrlShortener::Authorize.new 'login', 'key'
89
+ @client = UrlShortener::Client.new(authorize)
90
+ @interface = stub('UrlShortener::Interface', :get => {})
91
+ @client.stub!(:interface).and_return(@interface)
92
+ end
93
+
94
+ it "should get the end point" do
95
+ @client.should_receive(:end_point)
96
+ @client.shorten('a url')
97
+ end
98
+
99
+ it "should use the interface to connect to bitly" do
100
+ @client.should_receive(:interface).and_return(@interface)
101
+ @client.shorten('a url')
102
+ end
103
+
104
+ it "should get the data using interface" do
105
+ @interface.should_receive(:get)
106
+ @client.shorten('a url')
107
+ end
108
+
109
+ end
110
+
111
+ describe "#interface" do
112
+ before(:each) do
113
+ authorize = UrlShortener::Authorize.new 'login', 'key'
114
+ @client = UrlShortener::Client.new(authorize)
115
+ @client.stub!(:common_query_parameters).and_return({})
116
+ end
117
+
118
+ it "should initialize the interface object" do
119
+ UrlShortener::Interface.should_receive(:new).with('/some/uri', :query => {})
120
+ @client.interface('/some/uri')
121
+ end
122
+
123
+ it "should get the common query parameters" do
124
+ @client.should_receive(:common_query_parameters)
125
+ @client.interface('/some/uri')
126
+ end
127
+ end
128
+
129
+ end
@@ -0,0 +1,86 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe UrlShortener::Interface do
4
+
5
+ describe ".new" do
6
+ it "should have the rest url" do
7
+ @interface = UrlShortener::Interface.new('some/url')
8
+ @interface.rest_url.should eql('some/url')
9
+ end
10
+
11
+ it "should raise error when nil parameter is provided" do
12
+ lambda { UrlShortener::Interface.new(nil) }.should raise_error('Interface Url cannot be nil')
13
+ end
14
+ end
15
+
16
+ describe "#get" do
17
+ before(:each) do
18
+ @rest_url = 'http://some/url'
19
+ @interface = UrlShortener::Interface.new(@rest_url)
20
+ @interface.stub!(:result?).and_return(true)
21
+ @result = {'bitly' => {'errorCode' => '0', 'statusCode' => 'OK', 'results' => 'return result'}}
22
+ UrlShortener::Interface.stub!(:get).and_return(@result)
23
+ end
24
+
25
+ it "should call the get class method provided by httparty" do
26
+ UrlShortener::Interface.should_receive(:get).with(@rest_url,{}).and_return(@result)
27
+ @interface.get
28
+ end
29
+
30
+ it "should have a 10 second timeout set" do
31
+ @interface.should_receive(:timeout).with(10)
32
+ @interface.get
33
+ end
34
+
35
+ it "should raise NoResult error whern there is no result" do
36
+ @interface.stub!(:result?)
37
+ lambda { @interface.get }.should raise_error(UrlShortener::NoResult, "No result returned from bit.ly")
38
+ end
39
+
40
+ it "should raise AuthorizationFailure error when not authorised and error code in 203" do
41
+ result = {'bitly' => {'errorCode' => '203', 'errorMessage' => 'Any message returned'}}
42
+ UrlShortener::Interface.stub!(:get).and_return(result)
43
+ lambda { @interface.get }.should raise_error(UrlShortener::AuthorizationFailure, "Any message returned")
44
+ end
45
+
46
+ it "should raise response failure when returned status code is not OK and error code is not 0" do
47
+ result = {'bitly' => {'errorCode' => 'not 0', 'statusCode' => 'not OK', 'errorMessage' => 'Any message returned'}}
48
+ UrlShortener::Interface.stub!(:get).and_return(result)
49
+ lambda { @interface.get }.should raise_error(UrlShortener::ResponseFailure, "Any message returned")
50
+ end
51
+
52
+ it "should return the results hash from the returned results if status code is OK and errorCode is 0" do
53
+ @interface.get.should eql('return result')
54
+ end
55
+ end
56
+
57
+ describe "#result?" do
58
+ before(:each) do
59
+ @rest_url = 'http://some/url'
60
+ @interface = UrlShortener::Interface.new(@rest_url)
61
+ end
62
+ it "should return false if result is not present" do
63
+ @interface.result?(nil).should eql(false)
64
+ end
65
+
66
+ it "should return false if result is not a hash" do
67
+ @interface.result?('d').should eql(false)
68
+ end
69
+
70
+ it "should return false if there is no 'bitly' key in the result" do
71
+ @interface.result?({}).should eql(false)
72
+ end
73
+
74
+ it "should return nil if the value for 'bitly' key is nil" do
75
+ @interface.result?({'bitly' => nil}).should eql(false)
76
+ end
77
+
78
+ it "should return false if the value for 'bitly' key is an empty hash" do
79
+ @interface.result?({'bitly' => {}}).should eql(false)
80
+ end
81
+
82
+ it "should return true if the value for 'bitly' key is a hash with some key values" do
83
+ @interface.result?({'bitly' => {'otherkeys' => 'othervalues'}}).should eql(true)
84
+ end
85
+ end
86
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: url_shortener
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nasir Jamal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-08 00:00:00 +00: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.5
24
+ version:
25
+ description: Url Shortener is a Ruby library /gem and API wrapper for bit.ly
26
+ email: nas35_in@yahoo.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - History.txt
35
+ - Manifest.txt
36
+ - README.rdoc
37
+ - lib/url_shortener.rb
38
+ - lib/url_shortener/authorize.rb
39
+ - lib/url_shortener/client.rb
40
+ - lib/url_shortener/error.rb
41
+ - lib/url_shortener/interface.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/nas/url_shortener
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "1.8"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.4
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: Url Shortener is a Ruby library /gem and API wrapper for bit.ly
70
+ test_files:
71
+ - spec/spec_helper.rb
72
+ - spec/url_shortener/authorize_spec.rb
73
+ - spec/url_shortener/client_spec.rb
74
+ - spec/url_shortener/interface_spec.rb
75
+ - features/connect_to_bitly.feature
76
+ - features/short_url.feature
77
+ - features/support/env.rb
78
+ - features/step_definitions/connection_error_steps.rb
79
+ - features/step_definitions/short_url_steps.rb