googl 0.4.3 → 0.5.0
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.
- data/README.rdoc +59 -2
- data/VERSION +1 -1
- data/googl.gemspec +25 -11
- data/lib/googl.rb +44 -3
- data/lib/googl/base.rb +0 -6
- data/lib/googl/client_login.rb +11 -11
- data/lib/googl/expand.rb +9 -8
- data/lib/googl/oauth2/native.rb +25 -0
- data/lib/googl/oauth2/server.rb +28 -0
- data/lib/googl/oauth2/utils.rb +58 -0
- data/lib/googl/shorten.rb +5 -5
- data/lib/googl/utils.rb +30 -0
- data/spec/fixtures/oauth2/native.json +12 -0
- data/spec/fixtures/oauth2/native_invalid.json +12 -0
- data/spec/fixtures/oauth2/native_token_expires.json +27 -0
- data/spec/fixtures/oauth2/server.json +12 -0
- data/spec/fixtures/oauth2/server_invalid.json +12 -0
- data/spec/fixtures/oauth2/server_token_expires.json +27 -0
- data/spec/{client_spec.rb → googl/client_spec.rb} +0 -0
- data/spec/{expand_spec.rb → googl/expand_spec.rb} +10 -1
- data/spec/googl/oauth2/native_spec.rb +152 -0
- data/spec/googl/oauth2/server_spec.rb +156 -0
- data/spec/{request_spec.rb → googl/request_spec.rb} +0 -0
- data/spec/{shorten_spec.rb → googl/shorten_spec.rb} +0 -0
- data/spec/spec_helper.rb +48 -1
- metadata +56 -42
    
        data/README.rdoc
    CHANGED
    
    | @@ -1,7 +1,11 @@ | |
| 1 | 
            -
            = googl
         | 
| 1 | 
            +
            = googl 
         | 
| 2 2 |  | 
| 3 3 | 
             
            Google URL Shortener API in Ruby
         | 
| 4 4 |  | 
| 5 | 
            +
            == Continuous Integration
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            http://travis-ci.org/zigotto/googl.png Travis[http://travis-ci.org/zigotto/googl]
         | 
| 8 | 
            +
             | 
| 5 9 | 
             
            == Basic Usage
         | 
| 6 10 |  | 
| 7 11 | 
             
            === Shorten a long URL
         | 
| @@ -45,7 +49,60 @@ Go to http://goo.gl to see URL statistics. | |
| 45 49 |  | 
| 46 50 | 
             
            === OAuth
         | 
| 47 51 |  | 
| 48 | 
            -
             | 
| 52 | 
            +
            Google supports three flows of OAuth 2.0
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            * The <b>client-side</b> flow for JavaScript applications running in a browser. (TODO)
         | 
| 55 | 
            +
            * The <b>server-side</b> flow for web applications with servers that can securely store persistent information.
         | 
| 56 | 
            +
            * The <b>native application</b> flow for desktop and mobile applications.
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            Today, gem googl support only <b>server-side</b> and <b>native application</b>.
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            ==== Server-side web applications
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            You'll need to register your application with Google to get a <em>client_id</em> and record the <em>redirect_uri</em> you'd like to use. 
         | 
| 63 | 
            +
            See the Registering[http://code.google.com/apis/accounts/docs/OAuth2.html#Registering] your app with Google section for details on how to register.
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              client = Googl::OAuth2.server("client_id", "client_secret", "redirect_uri")
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            Redirect your users to
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              client.authorize_url
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            After the user approves access or chooses not to, we'll redirect to the <em>redirect_uri</em> you passed us and append either an authorization code.
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              client.request_access_token(params["code"])
         | 
| 74 | 
            +
              client.authorized?
         | 
| 75 | 
            +
              => true
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            Now you can get a user's history, shorten url, etc...
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              history = client.history
         | 
| 80 | 
            +
              history.total_items
         | 
| 81 | 
            +
              => 19
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              url = Googl.shorten('https://github.com/zigotto/googl')
         | 
| 84 | 
            +
              url.short_url
         | 
| 85 | 
            +
              => http://goo.gl/DWDfi
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            ==== Native applications
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            You'll need to register your application with Google to get a <em>client_id</em> and record the special <em>redirect_uri: urn:ietf:wg:oauth:2.0:oob</em>. 
         | 
| 90 | 
            +
            See the Registering[http://code.google.com/apis/accounts/docs/OAuth2.html#Registering] your app with Google section for details on how to register.
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            When you use this redirect_uri, instead of redirecting the user's browser to a page on your site with an authorization code, Google will display the authorization code or error response in the title of the page and a text field with instructions for the user to copy and paste it in to your application. Your application can either monitor the window title of a web-view or browser window it launches and close it once the authorization code appears or prompt the user to copy and paste the code.
         | 
| 93 | 
            +
             | 
| 94 | 
            +
              client = Googl::OAuth2.native("client_id", "client_secret")
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            Open a browser or a webview to the OAuth dialog at
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              client.authorize_url
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            In the native app flow, after the user approves access, we'll display the authorization code in the title of the page and in a text input with instructions for the user to copy and paste the code to your application
         | 
| 101 | 
            +
             | 
| 102 | 
            +
              code = "copied code"
         | 
| 103 | 
            +
              client.request_access_token(code)
         | 
| 104 | 
            +
              client.authorized?
         | 
| 105 | 
            +
              => true
         | 
| 49 106 |  | 
| 50 107 | 
             
            == Analytics
         | 
| 51 108 |  | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0. | 
| 1 | 
            +
            0.5.0
         | 
    
        data/googl.gemspec
    CHANGED
    
    | @@ -5,11 +5,11 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name = %q{googl}
         | 
| 8 | 
            -
              s.version = "0. | 
| 8 | 
            +
              s.version = "0.5.0"
         | 
| 9 9 |  | 
| 10 10 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 11 | 
             
              s.authors = ["Jesus Lopes"]
         | 
| 12 | 
            -
              s.date = %q{2011- | 
| 12 | 
            +
              s.date = %q{2011-05-01}
         | 
| 13 13 | 
             
              s.description = %q{Small library for Google URL Shortener API}
         | 
| 14 14 | 
             
              s.email = %q{jlopes@zigotto.com.br}
         | 
| 15 15 | 
             
              s.extra_rdoc_files = [
         | 
| @@ -27,11 +27,13 @@ Gem::Specification.new do |s| | |
| 27 27 | 
             
                "lib/googl/base.rb",
         | 
| 28 28 | 
             
                "lib/googl/client_login.rb",
         | 
| 29 29 | 
             
                "lib/googl/expand.rb",
         | 
| 30 | 
            +
                "lib/googl/oauth2/native.rb",
         | 
| 31 | 
            +
                "lib/googl/oauth2/server.rb",
         | 
| 32 | 
            +
                "lib/googl/oauth2/utils.rb",
         | 
| 30 33 | 
             
                "lib/googl/request.rb",
         | 
| 31 34 | 
             
                "lib/googl/ruby_extensions.rb",
         | 
| 32 35 | 
             
                "lib/googl/shorten.rb",
         | 
| 33 | 
            -
                " | 
| 34 | 
            -
                "spec/expand_spec.rb",
         | 
| 36 | 
            +
                "lib/googl/utils.rb",
         | 
| 35 37 | 
             
                "spec/fixtures/client_login_invalid.json",
         | 
| 36 38 | 
             
                "spec/fixtures/client_login_valid.json",
         | 
| 37 39 | 
             
                "spec/fixtures/expand.json",
         | 
| @@ -42,25 +44,37 @@ Gem::Specification.new do |s| | |
| 42 44 | 
             
                "spec/fixtures/expand_removed.json",
         | 
| 43 45 | 
             
                "spec/fixtures/history.json",
         | 
| 44 46 | 
             
                "spec/fixtures/history_projection_clicks.json",
         | 
| 47 | 
            +
                "spec/fixtures/oauth2/native.json",
         | 
| 48 | 
            +
                "spec/fixtures/oauth2/native_invalid.json",
         | 
| 49 | 
            +
                "spec/fixtures/oauth2/native_token_expires.json",
         | 
| 50 | 
            +
                "spec/fixtures/oauth2/server.json",
         | 
| 51 | 
            +
                "spec/fixtures/oauth2/server_invalid.json",
         | 
| 52 | 
            +
                "spec/fixtures/oauth2/server_token_expires.json",
         | 
| 45 53 | 
             
                "spec/fixtures/shorten.json",
         | 
| 46 54 | 
             
                "spec/fixtures/shorten_authenticated.json",
         | 
| 47 55 | 
             
                "spec/fixtures/shorten_invalid_content_type.json",
         | 
| 48 | 
            -
                "spec/ | 
| 56 | 
            +
                "spec/googl/client_spec.rb",
         | 
| 57 | 
            +
                "spec/googl/expand_spec.rb",
         | 
| 58 | 
            +
                "spec/googl/oauth2/native_spec.rb",
         | 
| 59 | 
            +
                "spec/googl/oauth2/server_spec.rb",
         | 
| 60 | 
            +
                "spec/googl/request_spec.rb",
         | 
| 61 | 
            +
                "spec/googl/shorten_spec.rb",
         | 
| 49 62 | 
             
                "spec/shared_examples.rb",
         | 
| 50 | 
            -
                "spec/shorten_spec.rb",
         | 
| 51 63 | 
             
                "spec/spec_helper.rb"
         | 
| 52 64 | 
             
              ]
         | 
| 53 65 | 
             
              s.homepage = %q{http://github.com/zigotto/googl}
         | 
| 54 66 | 
             
              s.licenses = ["MIT"]
         | 
| 55 67 | 
             
              s.require_paths = ["lib"]
         | 
| 56 | 
            -
              s.rubygems_version = %q{1. | 
| 68 | 
            +
              s.rubygems_version = %q{1.4.2}
         | 
| 57 69 | 
             
              s.summary = %q{Wrapper for Google URL Shortener API}
         | 
| 58 70 | 
             
              s.test_files = [
         | 
| 59 | 
            -
                "spec/client_spec.rb",
         | 
| 60 | 
            -
                "spec/expand_spec.rb",
         | 
| 61 | 
            -
                "spec/ | 
| 71 | 
            +
                "spec/googl/client_spec.rb",
         | 
| 72 | 
            +
                "spec/googl/expand_spec.rb",
         | 
| 73 | 
            +
                "spec/googl/oauth2/native_spec.rb",
         | 
| 74 | 
            +
                "spec/googl/oauth2/server_spec.rb",
         | 
| 75 | 
            +
                "spec/googl/request_spec.rb",
         | 
| 76 | 
            +
                "spec/googl/shorten_spec.rb",
         | 
| 62 77 | 
             
                "spec/shared_examples.rb",
         | 
| 63 | 
            -
                "spec/shorten_spec.rb",
         | 
| 64 78 | 
             
                "spec/spec_helper.rb"
         | 
| 65 79 | 
             
              ]
         | 
| 66 80 |  | 
    
        data/lib/googl.rb
    CHANGED
    
    | @@ -2,6 +2,7 @@ require 'httparty' | |
| 2 2 | 
             
            require 'ostruct'
         | 
| 3 3 | 
             
            require 'json'
         | 
| 4 4 |  | 
| 5 | 
            +
            require 'googl/utils'
         | 
| 5 6 | 
             
            require 'googl/base'
         | 
| 6 7 | 
             
            require 'googl/request'
         | 
| 7 8 | 
             
            require 'googl/shorten'
         | 
| @@ -9,7 +10,12 @@ require 'googl/expand' | |
| 9 10 | 
             
            require 'googl/client_login'
         | 
| 10 11 | 
             
            require 'googl/ruby_extensions'
         | 
| 11 12 |  | 
| 13 | 
            +
            require 'googl/oauth2/utils'
         | 
| 14 | 
            +
            require 'googl/oauth2/native'
         | 
| 15 | 
            +
            require 'googl/oauth2/server'
         | 
| 16 | 
            +
             | 
| 12 17 | 
             
            module Googl
         | 
| 18 | 
            +
              extend self
         | 
| 13 19 |  | 
| 14 20 | 
             
              # Creates a new short URL
         | 
| 15 21 | 
             
              #
         | 
| @@ -17,7 +23,7 @@ module Googl | |
| 17 23 | 
             
              #   url.short_url
         | 
| 18 24 | 
             
              #   => "http://goo.gl/ump4S"
         | 
| 19 25 | 
             
              #
         | 
| 20 | 
            -
              def  | 
| 26 | 
            +
              def shorten(url=nil)
         | 
| 21 27 | 
             
                raise ArgumentError.new("URL to shorten is required") if url.blank?
         | 
| 22 28 | 
             
                Googl::Shorten.new(url)
         | 
| 23 29 | 
             
              end
         | 
| @@ -79,7 +85,7 @@ module Googl | |
| 79 85 | 
             
              #
         | 
| 80 86 | 
             
              # For mor details, see http://code.google.com/intl/pt-BR/apis/urlshortener/v1/reference.html#resource_url
         | 
| 81 87 | 
             
              #
         | 
| 82 | 
            -
              def  | 
| 88 | 
            +
              def expand(url=nil, options={})
         | 
| 83 89 | 
             
                raise ArgumentError.new("URL to expand is required") if url.blank?
         | 
| 84 90 | 
             
                options = {:shortUrl => url, :projection => nil}.merge!(options)
         | 
| 85 91 | 
             
                Googl::Expand.new(options)
         | 
| @@ -95,8 +101,43 @@ module Googl | |
| 95 101 | 
             
              #
         | 
| 96 102 | 
             
              # Go to http://goo.gl to see URL statistics.
         | 
| 97 103 | 
             
              #
         | 
| 98 | 
            -
              def  | 
| 104 | 
            +
              def client(email, passwd)
         | 
| 99 105 | 
             
                Googl::ClientLogin.new(email, passwd)
         | 
| 100 106 | 
             
              end
         | 
| 101 107 |  | 
| 108 | 
            +
              # OAuth 2.0
         | 
| 109 | 
            +
              #
         | 
| 110 | 
            +
              # Google supports three flows of OAuth 2.0
         | 
| 111 | 
            +
              #
         | 
| 112 | 
            +
              # * client-side
         | 
| 113 | 
            +
              # * server-side
         | 
| 114 | 
            +
              # * native application
         | 
| 115 | 
            +
              #
         | 
| 116 | 
            +
              # Now, gem googl support only client-side and native application.
         | 
| 117 | 
            +
              #
         | 
| 118 | 
            +
              module OAuth2
         | 
| 119 | 
            +
                extend self
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                # OAuth 2.0 for server-side web applications
         | 
| 122 | 
            +
                #
         | 
| 123 | 
            +
                # The server-side flow for web applications with servers that can securely store persistent information
         | 
| 124 | 
            +
                #
         | 
| 125 | 
            +
                #   client = Googl::OAuth2.server("client_id", "client_secret", "redirect_uri")
         | 
| 126 | 
            +
                #
         | 
| 127 | 
            +
                def server(client_id, client_secret, redirect_uri)
         | 
| 128 | 
            +
                  Googl::OAuth2::Server.new(client_id, client_secret, redirect_uri)
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                # OAuth 2.0 for native applications
         | 
| 132 | 
            +
                #
         | 
| 133 | 
            +
                # The native application flow for desktop and mobile applications
         | 
| 134 | 
            +
                #
         | 
| 135 | 
            +
                #   client = Googl::OAuth2.native("client_id", "client_secret")
         | 
| 136 | 
            +
                #
         | 
| 137 | 
            +
                def native(client_id, client_secret)
         | 
| 138 | 
            +
                  Googl::OAuth2::Native.new(client_id, client_secret)
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
              end
         | 
| 142 | 
            +
             | 
| 102 143 | 
             
            end
         | 
    
        data/lib/googl/base.rb
    CHANGED
    
    
    
        data/lib/googl/client_login.rb
    CHANGED
    
    | @@ -1,9 +1,8 @@ | |
| 1 1 | 
             
            module Googl
         | 
| 2 2 |  | 
| 3 | 
            -
              class ClientLogin | 
| 3 | 
            +
              class ClientLogin
         | 
| 4 4 |  | 
| 5 | 
            -
                 | 
| 6 | 
            -
                API_HISTORY_URL = "https://www.googleapis.com/urlshortener/v1/url/history"
         | 
| 5 | 
            +
                include Googl::Utils
         | 
| 7 6 |  | 
| 8 7 | 
             
                attr_accessor :code, :items
         | 
| 9 8 |  | 
| @@ -11,13 +10,13 @@ module Googl | |
| 11 10 | 
             
                #
         | 
| 12 11 | 
             
                def initialize(email, passwd)
         | 
| 13 12 | 
             
                  modify_headers('Content-Type' => 'application/x-www-form-urlencoded')
         | 
| 14 | 
            -
                  resp =  | 
| 15 | 
            -
                   | 
| 13 | 
            +
                  resp = post(API_CLIENT_LOGIN_URL, :body => params.merge!('Email' => email, 'Passwd' => passwd))
         | 
| 14 | 
            +
                  self.code = resp.code
         | 
| 16 15 | 
             
                  if resp.code == 200
         | 
| 17 16 | 
             
                    token = resp.split('=').last.gsub(/\n/, '')
         | 
| 18 17 | 
             
                    modify_headers("Authorization" => "GoogleLogin auth=#{token}")
         | 
| 19 18 | 
             
                  else
         | 
| 20 | 
            -
                    raise  | 
| 19 | 
            +
                    raise exception("#{resp.code} #{resp.parsed_response}")
         | 
| 21 20 | 
             
                  end
         | 
| 22 21 | 
             
                end
         | 
| 23 22 |  | 
| @@ -26,7 +25,7 @@ module Googl | |
| 26 25 | 
             
                # See Googl.client
         | 
| 27 26 | 
             
                #
         | 
| 28 27 | 
             
                def shorten(url)
         | 
| 29 | 
            -
                  Googl | 
| 28 | 
            +
                  Googl.shorten(url)
         | 
| 30 29 | 
             
                end
         | 
| 31 30 |  | 
| 32 31 | 
             
                # Gets a user's history of shortened URLs. (Authenticated)
         | 
| @@ -46,11 +45,12 @@ module Googl | |
| 46 45 | 
             
                #   history = client.history(:projection => :analytics_clicks)
         | 
| 47 46 | 
             
                #
         | 
| 48 47 | 
             
                def history(options={})
         | 
| 49 | 
            -
                  resp = options.blank? ? Googl:: | 
| 50 | 
            -
                   | 
| 51 | 
            -
             | 
| 48 | 
            +
                  resp = options.blank? ? get(Googl::Utils::API_HISTORY_URL) : get(Googl::Utils::API_HISTORY_URL, :query => options)
         | 
| 49 | 
            +
                  case resp.code
         | 
| 50 | 
            +
                  when 200
         | 
| 51 | 
            +
                    self.items = resp.parsed_response.to_openstruct
         | 
| 52 52 | 
             
                  else
         | 
| 53 | 
            -
                    raise  | 
| 53 | 
            +
                    raise exception("#{resp.code} #{resp.parsed_response}")
         | 
| 54 54 | 
             
                  end
         | 
| 55 55 | 
             
                end
         | 
| 56 56 |  | 
    
        data/lib/googl/expand.rb
    CHANGED
    
    | @@ -2,9 +2,9 @@ module Googl | |
| 2 2 |  | 
| 3 3 | 
             
              class Expand < Base
         | 
| 4 4 |  | 
| 5 | 
            -
                 | 
| 5 | 
            +
                include Googl::Utils
         | 
| 6 6 |  | 
| 7 | 
            -
                attr_accessor :long_url, :analytics, :status, :short_url
         | 
| 7 | 
            +
                attr_accessor :long_url, :analytics, :status, :short_url, :created
         | 
| 8 8 |  | 
| 9 9 | 
             
                # Expands a short URL or gets creation time and analytics. See Googl.expand
         | 
| 10 10 | 
             
                #
         | 
| @@ -12,14 +12,15 @@ module Googl | |
| 12 12 |  | 
| 13 13 | 
             
                  options.delete_if {|key, value| value.nil?}
         | 
| 14 14 |  | 
| 15 | 
            -
                  resp =  | 
| 15 | 
            +
                  resp = get(API_URL, :query => options)
         | 
| 16 16 | 
             
                  if resp.code == 200
         | 
| 17 | 
            -
                     | 
| 18 | 
            -
                     | 
| 19 | 
            -
                     | 
| 20 | 
            -
                     | 
| 17 | 
            +
                    self.created    = resp['created'] if resp.has_key?('created')
         | 
| 18 | 
            +
                    self.long_url   = resp['longUrl']
         | 
| 19 | 
            +
                    self.analytics  = resp['analytics'].to_openstruct if resp.has_key?('analytics')
         | 
| 20 | 
            +
                    self.status     = resp['status']
         | 
| 21 | 
            +
                    self.short_url  = resp['id']
         | 
| 21 22 | 
             
                  else
         | 
| 22 | 
            -
                    raise  | 
| 23 | 
            +
                    raise exception("#{resp.code} #{resp.message}")
         | 
| 23 24 | 
             
                  end
         | 
| 24 25 | 
             
                end
         | 
| 25 26 |  | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module Googl
         | 
| 2 | 
            +
              module OAuth2
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                class Native
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  include Googl::Utils
         | 
| 7 | 
            +
                  include Googl::OAuth2::Utils
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def initialize(client_id, client_secret)
         | 
| 10 | 
            +
                    self.client_id     = client_id
         | 
| 11 | 
            +
                    self.client_secret = client_secret
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def authorize_url
         | 
| 15 | 
            +
                    make_authorize_url("urn:ietf:wg:oauth:2.0:oob")
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def request_access_token(code)
         | 
| 19 | 
            +
                    request_token(code)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            module Googl
         | 
| 2 | 
            +
              module OAuth2
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                class Server
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  include Googl::Utils
         | 
| 7 | 
            +
                  include Googl::OAuth2::Utils
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  attr_accessor :redirect_uri
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def initialize(client_id, client_secret, redirect_uri)
         | 
| 12 | 
            +
                    self.client_id     = client_id
         | 
| 13 | 
            +
                    self.client_secret = client_secret
         | 
| 14 | 
            +
                    self.redirect_uri  = redirect_uri
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def authorize_url
         | 
| 18 | 
            +
                    make_authorize_url(redirect_uri)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def request_access_token(code)
         | 
| 22 | 
            +
                    request_token(code, redirect_uri)
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            module Googl
         | 
| 2 | 
            +
              module OAuth2
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                module Utils
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  attr_accessor :client_id, :client_secret, :access_token, :refresh_token, :expires_in, :expires_at
         | 
| 7 | 
            +
                  attr_accessor :items
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def expires?
         | 
| 10 | 
            +
                    expires_at < Time.now
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def authorized?
         | 
| 14 | 
            +
                    !access_token.nil? && !refresh_token.nil? && !expires_in.nil? && !expires_at.nil?
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # Gets a user's history of shortened URLs.
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  def history(options={})
         | 
| 20 | 
            +
                    return unless authorized?
         | 
| 21 | 
            +
                    resp = options.blank? ? get(Googl::Utils::API_HISTORY_URL) : get(Googl::Utils::API_HISTORY_URL, :query => options)
         | 
| 22 | 
            +
                    case resp.code
         | 
| 23 | 
            +
                    when 200
         | 
| 24 | 
            +
                      self.items = resp.parsed_response.to_openstruct
         | 
| 25 | 
            +
                    else
         | 
| 26 | 
            +
                      raise exception("#{resp.code} #{resp.parsed_response}")
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  private
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def request_token(code, request_uri="urn:ietf:wg:oauth:2.0:oob")
         | 
| 33 | 
            +
                    params = "code=#{code}&client_id=#{client_id}&client_secret=#{client_secret}&redirect_uri=#{request_uri}&grant_type=authorization_code"
         | 
| 34 | 
            +
                    modify_headers('Content-Type' => 'application/x-www-form-urlencoded')
         | 
| 35 | 
            +
                    resp = post("https://accounts.google.com/o/oauth2/token", :body => params)
         | 
| 36 | 
            +
                    case resp.code
         | 
| 37 | 
            +
                    when 200
         | 
| 38 | 
            +
                      modify_headers("Authorization" => "OAuth #{resp["access_token"]}")
         | 
| 39 | 
            +
                      self.access_token  = resp["access_token"]
         | 
| 40 | 
            +
                      self.refresh_token = resp["refresh_token"]
         | 
| 41 | 
            +
                      self.expires_in    = resp["expires_in"]
         | 
| 42 | 
            +
                      self.expires_at    = Time.now + expires_in if expires_in
         | 
| 43 | 
            +
                      self
         | 
| 44 | 
            +
                    when 401
         | 
| 45 | 
            +
                      raise exception("#{resp.code} #{resp.parsed_response["error"]["message"]}")
         | 
| 46 | 
            +
                    else
         | 
| 47 | 
            +
                      raise exception("#{resp.code} #{resp.parsed_response["error"]}")
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def make_authorize_url(redirect_uri)
         | 
| 52 | 
            +
                    "https://accounts.google.com/o/oauth2/auth?client_id=#{client_id}&redirect_uri=#{redirect_uri}&scope=#{Googl::Utils::SCOPE_URL}&response_type=code"
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
            end
         | 
    
        data/lib/googl/shorten.rb
    CHANGED
    
    | @@ -2,7 +2,7 @@ module Googl | |
| 2 2 |  | 
| 3 3 | 
             
              class Shorten < Base
         | 
| 4 4 |  | 
| 5 | 
            -
                 | 
| 5 | 
            +
                include Googl::Utils
         | 
| 6 6 |  | 
| 7 7 | 
             
                attr_accessor :short_url, :long_url
         | 
| 8 8 |  | 
| @@ -11,12 +11,12 @@ module Googl | |
| 11 11 | 
             
                def initialize(long_url)
         | 
| 12 12 | 
             
                  modify_headers('Content-Type' => 'application/json')
         | 
| 13 13 | 
             
                  options = {"longUrl" => long_url}.to_json
         | 
| 14 | 
            -
                  resp =  | 
| 14 | 
            +
                  resp = post(API_URL, :body => options)
         | 
| 15 15 | 
             
                  if resp.code == 200
         | 
| 16 | 
            -
                     | 
| 17 | 
            -
                     | 
| 16 | 
            +
                    self.short_url  = resp['id']
         | 
| 17 | 
            +
                    self.long_url   = resp['longUrl']
         | 
| 18 18 | 
             
                  else
         | 
| 19 | 
            -
                    raise  | 
| 19 | 
            +
                    raise exception(resp.parsed_response)
         | 
| 20 20 | 
             
                  end
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
    
        data/lib/googl/utils.rb
    ADDED
    
    | @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module Googl
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              module Utils # :nodoc:
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                API_URL              = 'https://www.googleapis.com/urlshortener/v1/url'
         | 
| 6 | 
            +
                API_HISTORY_URL      = "https://www.googleapis.com/urlshortener/v1/url/history"
         | 
| 7 | 
            +
                API_CLIENT_LOGIN_URL = "https://www.google.com/accounts/ClientLogin"
         | 
| 8 | 
            +
                SCOPE_URL            = "https://www.googleapis.com/auth/urlshortener"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                private
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def modify_headers(item)
         | 
| 13 | 
            +
                  Googl::Request.headers.merge!(item)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def post(url, params={})
         | 
| 17 | 
            +
                  Googl::Request.post(url, params)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def get(url, params={})
         | 
| 21 | 
            +
                  Googl::Request.get(url, params)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def exception(msg)
         | 
| 25 | 
            +
                  Exception.new(msg)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            HTTP/1.1 200 OK
         | 
| 2 | 
            +
            Content-Type: application/json
         | 
| 3 | 
            +
            Date: Thu, 17 Mar 2011 02:45:33 GMT
         | 
| 4 | 
            +
            Expires: Thu, 17 Mar 2011 02:45:33 GMT
         | 
| 5 | 
            +
            Cache-Control: private, max-age=0
         | 
| 6 | 
            +
            X-Content-Type-Options: nosniff
         | 
| 7 | 
            +
            X-Frame-Options: SAMEORIGIN
         | 
| 8 | 
            +
            X-XSS-Protection: 1; mode=block
         | 
| 9 | 
            +
            Server: GSE
         | 
| 10 | 
            +
            Transfer-Encoding: chunked
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            {"access_token":"1/YCzoGAYT8XUuOifjNh_KqA","expires_in":3600,"refresh_token":"1/x_31GvgzdgHDMkRep5i8YxFlq76w3yjFu9Dp72Op-pI"}
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            HTTP/1.1 400 Bad Request
         | 
| 2 | 
            +
            Content-Type: application/json
         | 
| 3 | 
            +
            Date: Thu, 17 Mar 2011 03:05:33 GMT
         | 
| 4 | 
            +
            Expires: Thu, 17 Mar 2011 03:05:33 GMT
         | 
| 5 | 
            +
            Cache-Control: private, max-age=0
         | 
| 6 | 
            +
            X-Content-Type-Options: nosniff
         | 
| 7 | 
            +
            X-Frame-Options: SAMEORIGIN
         | 
| 8 | 
            +
            X-XSS-Protection: 1; mode=block
         | 
| 9 | 
            +
            Server: GSE
         | 
| 10 | 
            +
            Transfer-Encoding: chunked
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            {"error":"invalid_token"}
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            HTTP/1.1 401 Unauthorized
         | 
| 2 | 
            +
            WWW-Authenticate: AuthSub realm="https://gaiastaging.corp.google.com/accounts/AuthSubRequest" allowed-scopes="https://www.googleapis.com/auth/urlshortener"
         | 
| 3 | 
            +
            Content-Type: application/json; charset=UTF-8
         | 
| 4 | 
            +
            Date: Fri, 18 Mar 2011 23:32:07 GMT
         | 
| 5 | 
            +
            Expires: Fri, 18 Mar 2011 23:32:07 GMT
         | 
| 6 | 
            +
            Cache-Control: private, max-age=0
         | 
| 7 | 
            +
            X-Content-Type-Options: nosniff
         | 
| 8 | 
            +
            X-Frame-Options: SAMEORIGIN
         | 
| 9 | 
            +
            X-XSS-Protection: 1; mode=block
         | 
| 10 | 
            +
            Server: GSE
         | 
| 11 | 
            +
            Transfer-Encoding: chunked
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            {
         | 
| 14 | 
            +
             "error": {
         | 
| 15 | 
            +
              "errors": [
         | 
| 16 | 
            +
               {
         | 
| 17 | 
            +
                "domain": "global",
         | 
| 18 | 
            +
                "reason": "invalid",
         | 
| 19 | 
            +
                "message": "Invalid Credentials",
         | 
| 20 | 
            +
                "locationType": "header",
         | 
| 21 | 
            +
                "location": "Authorization"
         | 
| 22 | 
            +
               }
         | 
| 23 | 
            +
              ],
         | 
| 24 | 
            +
              "code": 401,
         | 
| 25 | 
            +
              "message": "Invalid Credentials"
         | 
| 26 | 
            +
             }
         | 
| 27 | 
            +
            }
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            HTTP/1.1 200 OK
         | 
| 2 | 
            +
            Content-Type: application/json
         | 
| 3 | 
            +
            Date: Fri, 18 Mar 2011 02:11:50 GMT
         | 
| 4 | 
            +
            Expires: Fri, 18 Mar 2011 02:11:50 GMT
         | 
| 5 | 
            +
            Cache-Control: private, max-age=0
         | 
| 6 | 
            +
            X-Content-Type-Options: nosniff
         | 
| 7 | 
            +
            X-Frame-Options: SAMEORIGIN
         | 
| 8 | 
            +
            X-XSS-Protection: 1; mode=block
         | 
| 9 | 
            +
            Server: GSE
         | 
| 10 | 
            +
            Transfer-Encoding: chunked
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            {"access_token":"1/9eNgoHDXi-1u1fDzZ2wLLGATiaQZnWPB51nTvo8n9Sw","expires_in":3600,"refresh_token":"1/gvmLC5XlU0qRPIBR3mt7OBBfEoTKB6i2T-Gu4dBDupw"}
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            HTTP/1.1 400 Bad Request
         | 
| 2 | 
            +
            Content-Type: application/json
         | 
| 3 | 
            +
            Date: Fri, 18 Mar 2011 14:12:06 GMT
         | 
| 4 | 
            +
            Expires: Fri, 18 Mar 2011 14:12:06 GMT
         | 
| 5 | 
            +
            Cache-Control: private, max-age=0
         | 
| 6 | 
            +
            X-Content-Type-Options: nosniff
         | 
| 7 | 
            +
            X-Frame-Options: SAMEORIGIN
         | 
| 8 | 
            +
            X-XSS-Protection: 1; mode=block
         | 
| 9 | 
            +
            Server: GSE
         | 
| 10 | 
            +
            Transfer-Encoding: chunked
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            {"error":"invalid_token"}
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            HTTP/1.1 401 Unauthorized
         | 
| 2 | 
            +
            WWW-Authenticate: AuthSub realm="https://gaiastaging.corp.google.com/accounts/AuthSubRequest" allowed-scopes="https://www.googleapis.com/auth/urlshortener"
         | 
| 3 | 
            +
            Content-Type: application/json; charset=UTF-8
         | 
| 4 | 
            +
            Date: Sat, 19 Mar 2011 00:00:35 GMT
         | 
| 5 | 
            +
            Expires: Sat, 19 Mar 2011 00:00:35 GMT
         | 
| 6 | 
            +
            Cache-Control: private, max-age=0
         | 
| 7 | 
            +
            X-Content-Type-Options: nosniff
         | 
| 8 | 
            +
            X-Frame-Options: SAMEORIGIN
         | 
| 9 | 
            +
            X-XSS-Protection: 1; mode=block
         | 
| 10 | 
            +
            Server: GSE
         | 
| 11 | 
            +
            Transfer-Encoding: chunked
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            {
         | 
| 14 | 
            +
             "error": {
         | 
| 15 | 
            +
              "errors": [
         | 
| 16 | 
            +
               {
         | 
| 17 | 
            +
                "domain": "global",
         | 
| 18 | 
            +
                "reason": "invalid",
         | 
| 19 | 
            +
                "message": "Invalid Credentials",
         | 
| 20 | 
            +
                "locationType": "header",
         | 
| 21 | 
            +
                "location": "Authorization"
         | 
| 22 | 
            +
               }
         | 
| 23 | 
            +
              ],
         | 
| 24 | 
            +
              "code": 401,
         | 
| 25 | 
            +
              "message": "Invalid Credentials"
         | 
| 26 | 
            +
             }
         | 
| 27 | 
            +
            }
         | 
| 
            File without changes
         | 
| @@ -60,6 +60,15 @@ describe Googl::Expand do | |
| 60 60 |  | 
| 61 61 | 
             
                      subject { Googl.expand('http://goo.gl/DWDfi', :projection => :full) }
         | 
| 62 62 |  | 
| 63 | 
            +
                      describe "#created" do
         | 
| 64 | 
            +
                        let(:element) { subject.created }
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                        it "should be the time url was shortened" do
         | 
| 67 | 
            +
                          element.should == Time.iso8601("2011-01-13T03:48:10.309+00:00")
         | 
| 68 | 
            +
                        end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                      end
         | 
| 71 | 
            +
             | 
| 63 72 | 
             
                      describe "#all_time" do
         | 
| 64 73 | 
             
                        let(:element) { subject.analytics.all_time }
         | 
| 65 74 |  | 
| @@ -67,7 +76,7 @@ describe Googl::Expand do | |
| 67 76 | 
             
                        it_should_behave_like 'a period'
         | 
| 68 77 |  | 
| 69 78 | 
             
                        it "should rename id to label" do
         | 
| 70 | 
            -
                          element.countries.first.label.should == "BR" | 
| 79 | 
            +
                          element.countries.first.label.should == "BR"
         | 
| 71 80 | 
             
                        end
         | 
| 72 81 | 
             
                      end
         | 
| 73 82 |  | 
| @@ -0,0 +1,152 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Googl::OAuth2::Native do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              before :each do
         | 
| 6 | 
            +
                fake_urls? true
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              subject do
         | 
| 10 | 
            +
                Googl::OAuth2.native("185706845724.apps.googleusercontent.com", "DrBLCdCQ3gOybHrj7TPz/B0N")
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              describe "#initialize" do
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                it "should assign client_id" do
         | 
| 16 | 
            +
                  subject.client_id.should == "185706845724.apps.googleusercontent.com"
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                it "should assign client_secret" do
         | 
| 20 | 
            +
                  subject.client_secret.should == "DrBLCdCQ3gOybHrj7TPz/B0N"
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              describe "#authorize_url" do
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                it { subject.should respond_to(:authorize_url) }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                it "should return url for authorize" do
         | 
| 30 | 
            +
                  subject.authorize_url.should == "https://accounts.google.com/o/oauth2/auth?client_id=185706845724.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/urlshortener&response_type=code"
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                it "should include the client_id" do
         | 
| 34 | 
            +
                  subject.authorize_url.should be_include("client_id=185706845724.apps.googleusercontent.com")
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                it "should include the redirect_uri" do
         | 
| 38 | 
            +
                  subject.authorize_url.should be_include("redirect_uri=urn:ietf:wg:oauth:2.0:oob")
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it "should include the scope" do
         | 
| 42 | 
            +
                  subject.authorize_url.should be_include("scope=https://www.googleapis.com/auth/urlshortener")
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                it "should include the response_type" do
         | 
| 46 | 
            +
                  subject.authorize_url.should be_include("response_type=code")
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              describe "#request_access_token" do
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                it { subject.should respond_to(:request_access_token) }
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                context "with valid code" do
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  let(:native) { subject.request_access_token("4/SuSud6RqPojUXsPpeh-wSVCwnmTQ") }
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  it "should return a access_token" do
         | 
| 60 | 
            +
                    native.access_token.should == "1/YCzoGAYT8XUuOifjNh_KqA"
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  it "should return a refresh_token" do
         | 
| 64 | 
            +
                    native.refresh_token.should == "1/x_31GvgzdgHDMkRep5i8YxFlq76w3yjFu9Dp72Op-pI"
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  it "should return a expires_in" do
         | 
| 68 | 
            +
                    native.expires_in.should == 3600
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                context "with invalid code" do
         | 
| 74 | 
            +
                  it "should raise error" do
         | 
| 75 | 
            +
                    lambda {  subject.request_access_token("my_invalid_code")  }.should raise_error(/400 invalid_token/)
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
                  it "should raise Invalid Credentials on 401 response" do
         | 
| 78 | 
            +
                    lambda {  subject.request_access_token("4/JvkEhCtr7tv1A60ENmubQT-cosRl")  }.should raise_error(/401 Invalid Credentials/)
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              describe "#expires_at" do
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                before do
         | 
| 87 | 
            +
                  @now = Time.now
         | 
| 88 | 
            +
                  Time.stub!(:now).and_return(@now)
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                let(:native) { subject.request_access_token("4/SuSud6RqPojUXsPpeh-wSVCwnmTQ") }
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                it "should be a time representation of #expires_in" do
         | 
| 94 | 
            +
                  native.expires_at.should == (@now + 3600)
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              describe "#expires?" do
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                before :each do
         | 
| 102 | 
            +
                  Time.stub!(:now).and_return(Time.parse("2011-04-23 15:30:00"))
         | 
| 103 | 
            +
                  subject.request_access_token("4/SuSud6RqPojUXsPpeh-wSVCwnmTQ")
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                it "should be true if access token expires" do
         | 
| 107 | 
            +
                  Time.stub!(:now).and_return(Time.parse("2011-04-23 18:30:00"))
         | 
| 108 | 
            +
                  subject.expires?.should be_true
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                it "should be false if access token not expires" do
         | 
| 112 | 
            +
                  subject.expires?.should be_false
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
              end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              describe "#authorized?" do
         | 
| 118 | 
            +
                
         | 
| 119 | 
            +
                it "should return false if client is not authorized" do
         | 
| 120 | 
            +
                  subject.authorized?.should be_false
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                let(:native) { subject.request_access_token("4/SuSud6RqPojUXsPpeh-wSVCwnmTQ") }
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                it "should return true if client is authorized" do
         | 
| 126 | 
            +
                  native.authorized?.should be_true
         | 
| 127 | 
            +
                end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
              end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
              context "when gets a user history of shortened" do
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                it { subject.should respond_to(:history) }
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                it "should not return when client not authorized" do
         | 
| 136 | 
            +
                  subject.history.should be_nil
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                context "if authorized" do
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  let(:native) { subject.request_access_token("4/SuSud6RqPojUXsPpeh-wSVCwnmTQ") }
         | 
| 142 | 
            +
                  let(:history) { native.history }
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                  it { history.should respond_to(:total_items) }
         | 
| 145 | 
            +
                  it { history.should respond_to(:items_per_page) }
         | 
| 146 | 
            +
                  it { history.should respond_to(:items) }
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
              end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            end
         | 
| @@ -0,0 +1,156 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Googl::OAuth2::Server do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              before :each do
         | 
| 6 | 
            +
                fake_urls? true
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              subject do
         | 
| 10 | 
            +
                Googl::OAuth2.server("438834493660.apps.googleusercontent.com", "8i4iJJkFTukWhNpxTU1b2Zhi", "http://gooogl.heroku.com/back")
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              describe "#initialize" do
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                it "should assign client_id" do
         | 
| 16 | 
            +
                  subject.client_id.should == "438834493660.apps.googleusercontent.com"
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
                  
         | 
| 19 | 
            +
                it "should assign client_secret" do
         | 
| 20 | 
            +
                  subject.client_secret.should == "8i4iJJkFTukWhNpxTU1b2Zhi"
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                  
         | 
| 23 | 
            +
                it "should assign redirect_uri" do
         | 
| 24 | 
            +
                  subject.redirect_uri.should == "http://gooogl.heroku.com/back"
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              describe "#authorize_url" do
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                it { subject.should respond_to(:authorize_url) }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                it "should return url for authorize" do
         | 
| 34 | 
            +
                  subject.authorize_url.should == "https://accounts.google.com/o/oauth2/auth?client_id=438834493660.apps.googleusercontent.com&redirect_uri=http://gooogl.heroku.com/back&scope=https://www.googleapis.com/auth/urlshortener&response_type=code"
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                it "should include the client_id" do
         | 
| 38 | 
            +
                  subject.authorize_url.should be_include("client_id=438834493660.apps.googleusercontent.com")
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it "should include the redirect_uri" do
         | 
| 42 | 
            +
                  subject.authorize_url.should be_include("redirect_uri=http://gooogl.heroku.com/back")
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                it "should include the scope" do
         | 
| 46 | 
            +
                  subject.authorize_url.should be_include("scope=https://www.googleapis.com/auth/urlshortener")
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                it "should include the response_type" do
         | 
| 50 | 
            +
                  subject.authorize_url.should be_include("response_type=code")
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              describe "#request_access_token" do
         | 
| 56 | 
            +
                
         | 
| 57 | 
            +
                it { subject.should respond_to(:request_access_token) }
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                context "with valid code" do
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  let(:server) { subject.request_access_token("4/z43CZpNmqd0IO3dR1Y_ouase13CH") }
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  it "should return a access_token" do
         | 
| 64 | 
            +
                    server.access_token.should == "1/9eNgoHDXi-1u1fDzZ2wLLGATiaQZnWPB51nTvo8n9Sw"
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  it "should return a refresh_token" do
         | 
| 68 | 
            +
                    server.refresh_token.should == "1/gvmLC5XlU0qRPIBR3mt7OBBfEoTKB6i2T-Gu4dBDupw"
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  it "should return a expires_in" do
         | 
| 72 | 
            +
                    server.expires_in.should == 3600
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                context "with invalid code" do
         | 
| 78 | 
            +
                  it "should raise error" do
         | 
| 79 | 
            +
                    lambda {  subject.request_access_token("my_invalid_code")  }.should raise_error(/400 invalid_token/)
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                  it "should raise Invalid Credentials on 401 response" do
         | 
| 82 | 
            +
                    lambda {  subject.request_access_token("4/JvkEhCtr7tv1A60ENmubQT-cosRl")  }.should raise_error(/401 Invalid Credentials/)
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              describe "#expires_at" do
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                before do
         | 
| 91 | 
            +
                  @now = Time.now
         | 
| 92 | 
            +
                  Time.stub!(:now).and_return(@now)
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                let(:server) { subject.request_access_token("4/z43CZpNmqd0IO3dR1Y_ouase13CH") }
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                it "should be a time representation of #expires_in" do
         | 
| 98 | 
            +
                  server.expires_at.should == (@now + 3600)
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              describe "#expires?" do
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                before :each do
         | 
| 106 | 
            +
                  Time.stub!(:now).and_return(Time.parse("2011-04-23 15:30:00"))
         | 
| 107 | 
            +
                  subject.request_access_token("4/z43CZpNmqd0IO3dR1Y_ouase13CH")
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                it "should be true if access token expires" do
         | 
| 111 | 
            +
                  Time.stub!(:now).and_return(Time.parse("2011-04-23 18:30:00"))
         | 
| 112 | 
            +
                  subject.expires?.should be_true
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                it "should be false if access token not expires" do
         | 
| 116 | 
            +
                  subject.expires?.should be_false
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              describe "#authorized?" do
         | 
| 122 | 
            +
                
         | 
| 123 | 
            +
                it "should return false if client is not authorized" do
         | 
| 124 | 
            +
                  subject.authorized?.should be_false
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                let(:server) { subject.request_access_token("4/z43CZpNmqd0IO3dR1Y_ouase13CH") }
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                it "should return true if client is authorized" do
         | 
| 130 | 
            +
                  server.authorized?.should be_true
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
              end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
              context "when gets a user history of shortened" do
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                it { subject.should respond_to(:history) }
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                it "should not return when client not authorized" do
         | 
| 140 | 
            +
                  subject.history.should be_nil
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                context "if authorized" do
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                  let(:server) { subject.request_access_token("4/z43CZpNmqd0IO3dR1Y_ouase13CH") }
         | 
| 146 | 
            +
                  let(:history) { server.history }
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  it { history.should respond_to(:total_items) }
         | 
| 149 | 
            +
                  it { history.should respond_to(:items_per_page) }
         | 
| 150 | 
            +
                  it { history.should respond_to(:items) }
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
              end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            end
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -75,7 +75,7 @@ def fake_urls?(status) | |
| 75 75 | 
             
                       :headers => {'Authorization'=>'GoogleLogin auth=DQAAAK8AAAC9ahL-o7g', 'Content-Type'=>'application/json'}).
         | 
| 76 76 | 
             
                       to_return(load_fixture('shorten_authenticated.json'))
         | 
| 77 77 |  | 
| 78 | 
            -
                # History
         | 
| 78 | 
            +
                # History for ClientLogin
         | 
| 79 79 | 
             
                stub_request(:get, "https://www.googleapis.com/urlshortener/v1/url/history").
         | 
| 80 80 | 
             
                  with(:headers => {'Authorization'=>'GoogleLogin auth=DQAAAK8AAAC9ahL-o7g'}).
         | 
| 81 81 | 
             
                  to_return(load_fixture('history.json'))
         | 
| @@ -84,6 +84,53 @@ def fake_urls?(status) | |
| 84 84 | 
             
                stub_request(:get, "https://www.googleapis.com/urlshortener/v1/url/history?projection=analytics_clicks").
         | 
| 85 85 | 
             
                  with(:headers => {'Authorization'=>'GoogleLogin auth=DQAAAK8AAAC9ahL-o7g'}).
         | 
| 86 86 | 
             
                  to_return(load_fixture('history_projection_clicks.json'))
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                # OAuth 2.0 for native applications
         | 
| 89 | 
            +
                stub_request(:post, "https://accounts.google.com/o/oauth2/token").
         | 
| 90 | 
            +
                  with(:body => "code=4/SuSud6RqPojUXsPpeh-wSVCwnmTQ&client_id=185706845724.apps.googleusercontent.com&client_secret=DrBLCdCQ3gOybHrj7TPz/B0N&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code", 
         | 
| 91 | 
            +
                       :headers => {'Content-Type'=>'application/x-www-form-urlencoded'}).
         | 
| 92 | 
            +
                       to_return(load_fixture('oauth2/native.json'))    
         | 
| 93 | 
            +
                
         | 
| 94 | 
            +
                # OAuth 2.0 for native applications (invalid token)
         | 
| 95 | 
            +
                stub_request(:post, "https://accounts.google.com/o/oauth2/token").
         | 
| 96 | 
            +
                  with(:body => "code=my_invalid_code&client_id=185706845724.apps.googleusercontent.com&client_secret=DrBLCdCQ3gOybHrj7TPz/B0N&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code", 
         | 
| 97 | 
            +
                       :headers => {'Content-Type'=>'application/x-www-form-urlencoded'}).
         | 
| 98 | 
            +
                       to_return(load_fixture('oauth2/native_invalid.json'))
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                # OAuth 2.0 for native applications (expired token)
         | 
| 101 | 
            +
                stub_request(:post, "https://accounts.google.com/o/oauth2/token").
         | 
| 102 | 
            +
                  with(:body => "code=4/JvkEhCtr7tv1A60ENmubQT-cosRl&client_id=185706845724.apps.googleusercontent.com&client_secret=DrBLCdCQ3gOybHrj7TPz/B0N&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code", 
         | 
| 103 | 
            +
                       :headers => {'Content-Type'=>'application/x-www-form-urlencoded'}).
         | 
| 104 | 
            +
                       to_return(load_fixture('oauth2/native_token_expires.json'))
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                # OAuth 2.0 for native applications (history)
         | 
| 107 | 
            +
                stub_request(:get, "https://www.googleapis.com/urlshortener/v1/url/history").
         | 
| 108 | 
            +
                   with(:headers => {'Authorization'=>'OAuth 1/YCzoGAYT8XUuOifjNh_KqA', 'Content-Type'=>'application/x-www-form-urlencoded'}).
         | 
| 109 | 
            +
                  to_return(load_fixture('history.json'))
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                # OAuth 2.0 for server-side web applications
         | 
| 112 | 
            +
                stub_request(:post, "https://accounts.google.com/o/oauth2/token").
         | 
| 113 | 
            +
                  with(:body => "code=4/z43CZpNmqd0IO3dR1Y_ouase13CH&client_id=438834493660.apps.googleusercontent.com&client_secret=8i4iJJkFTukWhNpxTU1b2Zhi&redirect_uri=http://gooogl.heroku.com/back&grant_type=authorization_code", 
         | 
| 114 | 
            +
                       :headers => {'Content-Type'=>'application/x-www-form-urlencoded'}).
         | 
| 115 | 
            +
                       to_return(load_fixture('oauth2/server.json'))
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                # OAuth 2.0 for server-side web applications (invalid token)
         | 
| 118 | 
            +
                stub_request(:post, "https://accounts.google.com/o/oauth2/token").
         | 
| 119 | 
            +
                  with(:body => "code=my_invalid_code&client_id=438834493660.apps.googleusercontent.com&client_secret=8i4iJJkFTukWhNpxTU1b2Zhi&redirect_uri=http://gooogl.heroku.com/back&grant_type=authorization_code", 
         | 
| 120 | 
            +
                       :headers => {'Content-Type'=>'application/x-www-form-urlencoded'}).
         | 
| 121 | 
            +
                       to_return(load_fixture('oauth2/server_invalid.json'))
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                # OAuth 2.0 for server-side web applications (expired token)
         | 
| 124 | 
            +
                stub_request(:post, "https://accounts.google.com/o/oauth2/token").
         | 
| 125 | 
            +
                  with(:body => "code=4/JvkEhCtr7tv1A60ENmubQT-cosRl&client_id=438834493660.apps.googleusercontent.com&client_secret=8i4iJJkFTukWhNpxTU1b2Zhi&redirect_uri=http://gooogl.heroku.com/back&grant_type=authorization_code", 
         | 
| 126 | 
            +
                       :headers => {'Content-Type'=>'application/x-www-form-urlencoded'}).
         | 
| 127 | 
            +
                       to_return(load_fixture('oauth2/server_token_expires.json'))    
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                # OAuth 2.0 for server-side web applications (history)
         | 
| 130 | 
            +
                stub_request(:get, "https://www.googleapis.com/urlshortener/v1/url/history").
         | 
| 131 | 
            +
                  with(:headers => {'Authorization'=>'OAuth 1/9eNgoHDXi-1u1fDzZ2wLLGATiaQZnWPB51nTvo8n9Sw'}).
         | 
| 132 | 
            +
                  to_return(load_fixture('history.json'))
         | 
| 133 | 
            +
             | 
| 87 134 | 
             
              else
         | 
| 88 135 | 
             
                WebMock.allow_net_connect!
         | 
| 89 136 | 
             
              end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: googl
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 11
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 | 
            -
              -  | 
| 9 | 
            -
              -  | 
| 10 | 
            -
              version: 0. | 
| 8 | 
            +
              - 5
         | 
| 9 | 
            +
              - 0
         | 
| 10 | 
            +
              version: 0.5.0
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Jesus Lopes
         | 
| @@ -15,12 +15,14 @@ autorequire: | |
| 15 15 | 
             
            bindir: bin
         | 
| 16 16 | 
             
            cert_chain: []
         | 
| 17 17 |  | 
| 18 | 
            -
            date: 2011- | 
| 18 | 
            +
            date: 2011-05-01 00:00:00 -03:00
         | 
| 19 19 | 
             
            default_executable: 
         | 
| 20 20 | 
             
            dependencies: 
         | 
| 21 21 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 22 | 
            +
              prerelease: false
         | 
| 23 | 
            +
              name: httparty
         | 
| 22 24 | 
             
              type: :runtime
         | 
| 23 | 
            -
               | 
| 25 | 
            +
              version_requirements: &id001 !ruby/object:Gem::Requirement 
         | 
| 24 26 | 
             
                none: false
         | 
| 25 27 | 
             
                requirements: 
         | 
| 26 28 | 
             
                - - ">="
         | 
| @@ -31,12 +33,12 @@ dependencies: | |
| 31 33 | 
             
                    - 6
         | 
| 32 34 | 
             
                    - 1
         | 
| 33 35 | 
             
                    version: 0.6.1
         | 
| 34 | 
            -
               | 
| 35 | 
            -
              version_requirements: *id001
         | 
| 36 | 
            -
              prerelease: false
         | 
| 36 | 
            +
              requirement: *id001
         | 
| 37 37 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 38 | 
            +
              prerelease: false
         | 
| 39 | 
            +
              name: json
         | 
| 38 40 | 
             
              type: :runtime
         | 
| 39 | 
            -
               | 
| 41 | 
            +
              version_requirements: &id002 !ruby/object:Gem::Requirement 
         | 
| 40 42 | 
             
                none: false
         | 
| 41 43 | 
             
                requirements: 
         | 
| 42 44 | 
             
                - - ">="
         | 
| @@ -47,12 +49,12 @@ dependencies: | |
| 47 49 | 
             
                    - 4
         | 
| 48 50 | 
             
                    - 6
         | 
| 49 51 | 
             
                    version: 1.4.6
         | 
| 50 | 
            -
               | 
| 51 | 
            -
              version_requirements: *id002
         | 
| 52 | 
            -
              prerelease: false
         | 
| 52 | 
            +
              requirement: *id002
         | 
| 53 53 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 54 | 
            +
              prerelease: false
         | 
| 55 | 
            +
              name: rspec
         | 
| 54 56 | 
             
              type: :development
         | 
| 55 | 
            -
               | 
| 57 | 
            +
              version_requirements: &id003 !ruby/object:Gem::Requirement 
         | 
| 56 58 | 
             
                none: false
         | 
| 57 59 | 
             
                requirements: 
         | 
| 58 60 | 
             
                - - ~>
         | 
| @@ -63,12 +65,12 @@ dependencies: | |
| 63 65 | 
             
                    - 3
         | 
| 64 66 | 
             
                    - 0
         | 
| 65 67 | 
             
                    version: 2.3.0
         | 
| 66 | 
            -
               | 
| 67 | 
            -
              version_requirements: *id003
         | 
| 68 | 
            -
              prerelease: false
         | 
| 68 | 
            +
              requirement: *id003
         | 
| 69 69 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 70 | 
            +
              prerelease: false
         | 
| 71 | 
            +
              name: bundler
         | 
| 70 72 | 
             
              type: :development
         | 
| 71 | 
            -
               | 
| 73 | 
            +
              version_requirements: &id004 !ruby/object:Gem::Requirement 
         | 
| 72 74 | 
             
                none: false
         | 
| 73 75 | 
             
                requirements: 
         | 
| 74 76 | 
             
                - - ~>
         | 
| @@ -79,12 +81,12 @@ dependencies: | |
| 79 81 | 
             
                    - 0
         | 
| 80 82 | 
             
                    - 0
         | 
| 81 83 | 
             
                    version: 1.0.0
         | 
| 82 | 
            -
               | 
| 83 | 
            -
              version_requirements: *id004
         | 
| 84 | 
            -
              prerelease: false
         | 
| 84 | 
            +
              requirement: *id004
         | 
| 85 85 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 86 | 
            +
              prerelease: false
         | 
| 87 | 
            +
              name: jeweler
         | 
| 86 88 | 
             
              type: :development
         | 
| 87 | 
            -
               | 
| 89 | 
            +
              version_requirements: &id005 !ruby/object:Gem::Requirement 
         | 
| 88 90 | 
             
                none: false
         | 
| 89 91 | 
             
                requirements: 
         | 
| 90 92 | 
             
                - - ~>
         | 
| @@ -95,12 +97,12 @@ dependencies: | |
| 95 97 | 
             
                    - 5
         | 
| 96 98 | 
             
                    - 2
         | 
| 97 99 | 
             
                    version: 1.5.2
         | 
| 98 | 
            -
               | 
| 99 | 
            -
              version_requirements: *id005
         | 
| 100 | 
            -
              prerelease: false
         | 
| 100 | 
            +
              requirement: *id005
         | 
| 101 101 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 102 | 
            +
              prerelease: false
         | 
| 103 | 
            +
              name: rcov
         | 
| 102 104 | 
             
              type: :development
         | 
| 103 | 
            -
               | 
| 105 | 
            +
              version_requirements: &id006 !ruby/object:Gem::Requirement 
         | 
| 104 106 | 
             
                none: false
         | 
| 105 107 | 
             
                requirements: 
         | 
| 106 108 | 
             
                - - ">="
         | 
| @@ -109,12 +111,12 @@ dependencies: | |
| 109 111 | 
             
                    segments: 
         | 
| 110 112 | 
             
                    - 0
         | 
| 111 113 | 
             
                    version: "0"
         | 
| 112 | 
            -
               | 
| 113 | 
            -
              version_requirements: *id006
         | 
| 114 | 
            -
              prerelease: false
         | 
| 114 | 
            +
              requirement: *id006
         | 
| 115 115 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 116 | 
            +
              prerelease: false
         | 
| 117 | 
            +
              name: webmock
         | 
| 116 118 | 
             
              type: :development
         | 
| 117 | 
            -
               | 
| 119 | 
            +
              version_requirements: &id007 !ruby/object:Gem::Requirement 
         | 
| 118 120 | 
             
                none: false
         | 
| 119 121 | 
             
                requirements: 
         | 
| 120 122 | 
             
                - - ~>
         | 
| @@ -125,9 +127,7 @@ dependencies: | |
| 125 127 | 
             
                    - 6
         | 
| 126 128 | 
             
                    - 2
         | 
| 127 129 | 
             
                    version: 1.6.2
         | 
| 128 | 
            -
               | 
| 129 | 
            -
              version_requirements: *id007
         | 
| 130 | 
            -
              prerelease: false
         | 
| 130 | 
            +
              requirement: *id007
         | 
| 131 131 | 
             
            description: Small library for Google URL Shortener API
         | 
| 132 132 | 
             
            email: jlopes@zigotto.com.br
         | 
| 133 133 | 
             
            executables: []
         | 
| @@ -148,11 +148,13 @@ files: | |
| 148 148 | 
             
            - lib/googl/base.rb
         | 
| 149 149 | 
             
            - lib/googl/client_login.rb
         | 
| 150 150 | 
             
            - lib/googl/expand.rb
         | 
| 151 | 
            +
            - lib/googl/oauth2/native.rb
         | 
| 152 | 
            +
            - lib/googl/oauth2/server.rb
         | 
| 153 | 
            +
            - lib/googl/oauth2/utils.rb
         | 
| 151 154 | 
             
            - lib/googl/request.rb
         | 
| 152 155 | 
             
            - lib/googl/ruby_extensions.rb
         | 
| 153 156 | 
             
            - lib/googl/shorten.rb
         | 
| 154 | 
            -
            -  | 
| 155 | 
            -
            - spec/expand_spec.rb
         | 
| 157 | 
            +
            - lib/googl/utils.rb
         | 
| 156 158 | 
             
            - spec/fixtures/client_login_invalid.json
         | 
| 157 159 | 
             
            - spec/fixtures/client_login_valid.json
         | 
| 158 160 | 
             
            - spec/fixtures/expand.json
         | 
| @@ -163,12 +165,22 @@ files: | |
| 163 165 | 
             
            - spec/fixtures/expand_removed.json
         | 
| 164 166 | 
             
            - spec/fixtures/history.json
         | 
| 165 167 | 
             
            - spec/fixtures/history_projection_clicks.json
         | 
| 168 | 
            +
            - spec/fixtures/oauth2/native.json
         | 
| 169 | 
            +
            - spec/fixtures/oauth2/native_invalid.json
         | 
| 170 | 
            +
            - spec/fixtures/oauth2/native_token_expires.json
         | 
| 171 | 
            +
            - spec/fixtures/oauth2/server.json
         | 
| 172 | 
            +
            - spec/fixtures/oauth2/server_invalid.json
         | 
| 173 | 
            +
            - spec/fixtures/oauth2/server_token_expires.json
         | 
| 166 174 | 
             
            - spec/fixtures/shorten.json
         | 
| 167 175 | 
             
            - spec/fixtures/shorten_authenticated.json
         | 
| 168 176 | 
             
            - spec/fixtures/shorten_invalid_content_type.json
         | 
| 169 | 
            -
            - spec/ | 
| 177 | 
            +
            - spec/googl/client_spec.rb
         | 
| 178 | 
            +
            - spec/googl/expand_spec.rb
         | 
| 179 | 
            +
            - spec/googl/oauth2/native_spec.rb
         | 
| 180 | 
            +
            - spec/googl/oauth2/server_spec.rb
         | 
| 181 | 
            +
            - spec/googl/request_spec.rb
         | 
| 182 | 
            +
            - spec/googl/shorten_spec.rb
         | 
| 170 183 | 
             
            - spec/shared_examples.rb
         | 
| 171 | 
            -
            - spec/shorten_spec.rb
         | 
| 172 184 | 
             
            - spec/spec_helper.rb
         | 
| 173 185 | 
             
            has_rdoc: true
         | 
| 174 186 | 
             
            homepage: http://github.com/zigotto/googl
         | 
| @@ -200,14 +212,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 200 212 | 
             
            requirements: []
         | 
| 201 213 |  | 
| 202 214 | 
             
            rubyforge_project: 
         | 
| 203 | 
            -
            rubygems_version: 1. | 
| 215 | 
            +
            rubygems_version: 1.4.2
         | 
| 204 216 | 
             
            signing_key: 
         | 
| 205 217 | 
             
            specification_version: 3
         | 
| 206 218 | 
             
            summary: Wrapper for Google URL Shortener API
         | 
| 207 219 | 
             
            test_files: 
         | 
| 208 | 
            -
            - spec/client_spec.rb
         | 
| 209 | 
            -
            - spec/expand_spec.rb
         | 
| 210 | 
            -
            - spec/ | 
| 220 | 
            +
            - spec/googl/client_spec.rb
         | 
| 221 | 
            +
            - spec/googl/expand_spec.rb
         | 
| 222 | 
            +
            - spec/googl/oauth2/native_spec.rb
         | 
| 223 | 
            +
            - spec/googl/oauth2/server_spec.rb
         | 
| 224 | 
            +
            - spec/googl/request_spec.rb
         | 
| 225 | 
            +
            - spec/googl/shorten_spec.rb
         | 
| 211 226 | 
             
            - spec/shared_examples.rb
         | 
| 212 | 
            -
            - spec/shorten_spec.rb
         | 
| 213 227 | 
             
            - spec/spec_helper.rb
         |