Merge remote branch 'remotes/upstream/master'
This commit is contained in:
commit
f736ac4d97
|
@ -5,6 +5,8 @@
|
||||||
* added OAuth 2 support to the command line tool
|
* added OAuth 2 support to the command line tool
|
||||||
* renamed some switches in the command line tool
|
* renamed some switches in the command line tool
|
||||||
* added additional configuration capabilities
|
* added additional configuration capabilities
|
||||||
|
* fixed a few deprecation warnings from dependencies
|
||||||
|
* added gemspec to source control
|
||||||
|
|
||||||
== 0.2.0
|
== 0.2.0
|
||||||
|
|
||||||
|
|
4
Rakefile
4
Rakefile
|
@ -4,10 +4,6 @@ $LOAD_PATH.uniq!
|
||||||
|
|
||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
require 'rake'
|
require 'rake'
|
||||||
require 'rake/testtask'
|
|
||||||
require 'rake/rdoctask'
|
|
||||||
require 'rake/packagetask'
|
|
||||||
require 'rake/gempackagetask'
|
|
||||||
|
|
||||||
gem 'rspec', '~> 1.2.9'
|
gem 'rspec', '~> 1.2.9'
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -294,13 +294,12 @@ HTML
|
||||||
exit(0)
|
exit(0)
|
||||||
else
|
else
|
||||||
$verifier = nil
|
$verifier = nil
|
||||||
# TODO(bobaman): Cross-platform?
|
|
||||||
logger = WEBrick::Log.new('/dev/null')
|
|
||||||
server = WEBrick::HTTPServer.new(
|
server = WEBrick::HTTPServer.new(
|
||||||
:Port => OAUTH_SERVER_PORT,
|
:Port => OAUTH_SERVER_PORT,
|
||||||
:Logger => logger,
|
:Logger => WEBrick::Log.new,
|
||||||
:AccessLog => logger
|
:AccessLog => WEBrick::Log.new
|
||||||
)
|
)
|
||||||
|
server.logger.level = 0
|
||||||
trap("INT") { server.shutdown }
|
trap("INT") { server.shutdown }
|
||||||
|
|
||||||
server.mount("/", OAuthVerifierServlet)
|
server.mount("/", OAuthVerifierServlet)
|
||||||
|
@ -366,8 +365,8 @@ HTML
|
||||||
exit(0)
|
exit(0)
|
||||||
else
|
else
|
||||||
$verifier = nil
|
$verifier = nil
|
||||||
# TODO(bobaman): Cross-platform?
|
logger = WEBrick::Log.new
|
||||||
logger = WEBrick::Log.new('/dev/null')
|
logger.level = 0
|
||||||
server = WEBrick::HTTPServer.new(
|
server = WEBrick::HTTPServer.new(
|
||||||
:Port => OAUTH_SERVER_PORT,
|
:Port => OAUTH_SERVER_PORT,
|
||||||
:Logger => logger,
|
:Logger => logger,
|
||||||
|
@ -389,7 +388,7 @@ HTML
|
||||||
)
|
)
|
||||||
|
|
||||||
# Launch browser
|
# Launch browser
|
||||||
Launchy::Browser.run(oauth_client.authorization_uri.to_s)
|
Launchy.open(oauth_client.authorization_uri.to_s)
|
||||||
|
|
||||||
server.start
|
server.start
|
||||||
oauth_client.code = $verifier
|
oauth_client.code = $verifier
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
# Buzz Ruby Sample
|
|
||||||
This is a simple starter project written in Ruby which provides a minimal
|
|
||||||
example of Buzz integration within a Sinatra web application.
|
|
||||||
|
|
||||||
Once you've run the starter project and played with the features it provides,
|
|
||||||
this starter project provides a great place to start your experimentation into
|
|
||||||
the API.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
Please make sure that all of these are installed before you try to run the
|
|
||||||
sample.
|
|
||||||
|
|
||||||
- Ruby 1.8.7+
|
|
||||||
- Ruby Gems 1.3.7+
|
|
||||||
- Are you on a Mac? If so, be sure you have XCode 3.2+
|
|
||||||
- A few gems (run 'sudo gem install <gem name>' to install)
|
|
||||||
- sinatra
|
|
||||||
- httpadapter
|
|
||||||
- extlib
|
|
||||||
- dm-sqlite-adapter
|
|
||||||
- google-api-ruby-client
|
|
||||||
|
|
||||||
## Setup Authentication
|
|
||||||
|
|
||||||
This API uses OAuth 2.0. Learn more about Google APIs and OAuth 2.0 here:
|
|
||||||
http://code.google.com/apis/accounts/docs/OAuth2.html
|
|
||||||
|
|
||||||
Or, if you'd like to dive right in, follow these steps.
|
|
||||||
- Visit https://code.google.com/apis/console/ to register your application.
|
|
||||||
- From the "Project Home" screen, activate access to "Buzz API".
|
|
||||||
- Click on "API Access" in the left column
|
|
||||||
- Click the button labeled "Create an OAuth2 client ID"
|
|
||||||
- Give your application a name and click "Next"
|
|
||||||
- Select "Web Application" as the "Application type"
|
|
||||||
- Under "Your Site or Hostname" select "http://" as the protocol and enter
|
|
||||||
"localhost" for the domain name
|
|
||||||
- click "Create client ID"
|
|
||||||
|
|
||||||
Edit the buzz.rb file and enter the values for the following properties that
|
|
||||||
you retrieved from the API Console:
|
|
||||||
|
|
||||||
- `oauth_client_id`
|
|
||||||
- `oauth_client_secret`
|
|
||||||
|
|
||||||
Or, include them in the command line as the first two arguments.
|
|
||||||
|
|
||||||
## Running the Sample
|
|
||||||
|
|
||||||
I'm assuming you've checked out the code and are reading this from a local
|
|
||||||
directory. If not check out the code to a local directory.
|
|
||||||
|
|
||||||
1. Start up the embedded Sinatra web server
|
|
||||||
|
|
||||||
$ ruby buzz.rb
|
|
||||||
|
|
||||||
2. Open your web browser and see your activities! Go to `http://localhost:4567/`
|
|
||||||
|
|
||||||
3. Be inspired and start hacking an amazing new web app!
|
|
|
@ -1,125 +0,0 @@
|
||||||
$:.unshift('lib')
|
|
||||||
#####!/usr/bin/ruby1.8
|
|
||||||
|
|
||||||
# Copyright:: Copyright 2011 Google Inc.
|
|
||||||
# License:: All Rights Reserved.
|
|
||||||
# Original Author:: Bob Aman
|
|
||||||
# Maintainer:: Daniel Dobson (mailto:wolff@google.com)
|
|
||||||
# Maintainer:: Jenny Murphy (mailto:mimming@google.com)
|
|
||||||
|
|
||||||
require 'rubygems'
|
|
||||||
require 'sinatra'
|
|
||||||
require 'google/api_client'
|
|
||||||
require 'httpadapter/adapters/net_http'
|
|
||||||
require 'pp'
|
|
||||||
|
|
||||||
use Rack::Session::Pool, :expire_after => 86400 # 1 day
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
# See README for getting API id and secret
|
|
||||||
|
|
||||||
if (ARGV.size < 2)
|
|
||||||
set :oauth_client_id, 'oauth_client_id'
|
|
||||||
set :oauth_client_secret, 'oauth_client_secret'
|
|
||||||
|
|
||||||
if (settings.oauth_client_id == 'oauth_client_id')
|
|
||||||
puts 'See README for getting API id and secret. Server terminated.'
|
|
||||||
exit(0)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
set :oauth_client_id, ARGV[0]
|
|
||||||
set :oauth_client_secret, ARGV[1]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Configuration that you probably don't have to change
|
|
||||||
set :oauth_scopes, 'https://www.googleapis.com/auth/buzz'
|
|
||||||
|
|
||||||
class TokenPair
|
|
||||||
@refresh_token
|
|
||||||
@access_token
|
|
||||||
@expires_in
|
|
||||||
@issued_at
|
|
||||||
|
|
||||||
def update_token!(object)
|
|
||||||
@refresh_token = object.refresh_token
|
|
||||||
@access_token = object.access_token
|
|
||||||
@expires_in = object.expires_in
|
|
||||||
@issued_at = object.issued_at
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_hash
|
|
||||||
return {
|
|
||||||
:refresh_token => @refresh_token,
|
|
||||||
:access_token => @access_token,
|
|
||||||
:expires_in => @expires_in,
|
|
||||||
:issued_at => Time.at(@issued_at)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# At the beginning of any request, make sure the OAuth token is available.
|
|
||||||
# If it's not available, kick off the OAuth 2 flow to authorize.
|
|
||||||
before do
|
|
||||||
@client = Google::APIClient.new(
|
|
||||||
:authorization => :oauth_2,
|
|
||||||
:host => 'www.googleapis.com',
|
|
||||||
:http_adapter => HTTPAdapter::NetHTTPAdapter.new
|
|
||||||
)
|
|
||||||
|
|
||||||
@client.authorization.client_id = settings.oauth_client_id
|
|
||||||
@client.authorization.client_secret = settings.oauth_client_secret
|
|
||||||
@client.authorization.scope = settings.oauth_scopes
|
|
||||||
@client.authorization.redirect_uri = to('/oauth2callback')
|
|
||||||
@client.authorization.code = params[:code] if params[:code]
|
|
||||||
if session[:token]
|
|
||||||
# Load the access token here if it's available
|
|
||||||
@client.authorization.update_token!(session[:token].to_hash)
|
|
||||||
end
|
|
||||||
|
|
||||||
@buzz = @client.discovered_api('buzz')
|
|
||||||
unless @client.authorization.access_token || request.path_info =~ /^\/oauth2/
|
|
||||||
redirect to('/oauth2authorize')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Part of the OAuth flow
|
|
||||||
get '/oauth2authorize' do
|
|
||||||
<<OUT
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
||||||
<title>Google Ruby API Buzz Sample</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header><h1>Google Ruby API Buzz Sample</h1></header>
|
|
||||||
<div class="box">
|
|
||||||
<a class='login' href='#{@client.authorization.authorization_uri.to_s}'>Connect Me!</a>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
OUT
|
|
||||||
end
|
|
||||||
|
|
||||||
# Part of the OAuth flow
|
|
||||||
get '/oauth2callback' do
|
|
||||||
@client.authorization.fetch_access_token!
|
|
||||||
unless session[:token]
|
|
||||||
token_pair = TokenPair.new
|
|
||||||
token_pair.update_token!(@client.authorization)
|
|
||||||
# Persist the token here
|
|
||||||
session[:token] = token_pair
|
|
||||||
end
|
|
||||||
redirect to('/')
|
|
||||||
end
|
|
||||||
|
|
||||||
# The method you're probably actually interested in. This one lists a page of your
|
|
||||||
# most recent activities
|
|
||||||
get '/' do
|
|
||||||
response = @client.execute(
|
|
||||||
@buzz.activities.list,
|
|
||||||
'userId' => '@me', 'scope' => '@consumption', 'alt'=> 'json'
|
|
||||||
)
|
|
||||||
status, headers, body = response
|
|
||||||
[status, {'Content-Type' => 'application/json'}, body]
|
|
||||||
end
|
|
|
@ -1,96 +0,0 @@
|
||||||
APIs Console Project Setup
|
|
||||||
--------------------------
|
|
||||||
If you have not yet, you must set your APIs Console project to enable Prediction
|
|
||||||
API and Google Storage. Go to APIs Console https://code.google.com/apis/console/
|
|
||||||
and select the project you want to use. Next, go to Services, and enable both
|
|
||||||
Prediction API and Google Storage. You may also need to enable Billing (Billing)
|
|
||||||
in the left menu.
|
|
||||||
|
|
||||||
|
|
||||||
Data Setup
|
|
||||||
----------
|
|
||||||
Before you can run the prediction sample prediction.rb, you must load some csv
|
|
||||||
formatted data into Google Storage.
|
|
||||||
|
|
||||||
1 - You must first create the bucket you want to use. This can be done
|
|
||||||
with the gsutil function or via the web UI (Storage Access) in the Google
|
|
||||||
APIs Console. i.e.
|
|
||||||
|
|
||||||
$ gsutil mb gs://BUCKET
|
|
||||||
|
|
||||||
OR
|
|
||||||
|
|
||||||
Go to APIs Console -> Storage Access (on left) and the Google Storage Manager,
|
|
||||||
and create your bucket there.
|
|
||||||
|
|
||||||
2 - We now load the data you want to use to Google Storage. We have supplied a
|
|
||||||
basic language identification dataset in the sample for testing.
|
|
||||||
|
|
||||||
$ chmod 744 setup.sh
|
|
||||||
$ ./setup.sh BUCKET/OBJECT
|
|
||||||
Note you need gsutil in your path for this to work.
|
|
||||||
|
|
||||||
If you have your own dataset, you can do this manually as well.
|
|
||||||
|
|
||||||
$ gsutil cp your_dataset.csv gs://BUCKET/your_dataset.csv
|
|
||||||
|
|
||||||
|
|
||||||
In the script, you must then modify the datafile string. This must correspond with the
|
|
||||||
bucket/object of your dataset (if you are using your own dataset). We have
|
|
||||||
provided a setup.sh which will upload some basic sample data. The section is
|
|
||||||
near the bottom of the script, under 'FILL IN DATAFILE'
|
|
||||||
|
|
||||||
API Setup
|
|
||||||
---------
|
|
||||||
We need to allow the application to use your API access. Go to APIs Console
|
|
||||||
https://code.google.com/apis/console, and select the project you want, go to API
|
|
||||||
Access, and create an OAuth2 client if you have not yet already. You should
|
|
||||||
generate a client ID and secret.
|
|
||||||
|
|
||||||
This example will run through the server-side example, where the application
|
|
||||||
gets authorization ahead of time, which is the normal use case for Prediction
|
|
||||||
API. You can also set it up so the user can grant access.
|
|
||||||
|
|
||||||
First, run the google-api script to generate access and refresh tokens. Ex.
|
|
||||||
|
|
||||||
$ cd google-api-ruby-client
|
|
||||||
$ google-api oauth-2-login --scope=https://www.googleapis.com/auth/prediction --client-id=NUMBER.apps.googleusercontent.com --client-secret=CLIENT_SECRET
|
|
||||||
|
|
||||||
Fill in your client-id and client-secret from the API Access page. You will
|
|
||||||
probably have to set a redirect URI in your client ID
|
|
||||||
(ex. http://localhost:12736/). You can do this by hitting 'Edit settings' in the
|
|
||||||
API Access / Client ID section, and adding it to Authorized Redirect URIs. Not
|
|
||||||
that this has to be exactly the same URI, http://localhost:12736 and
|
|
||||||
http://localhost:12736/ are not the same in this case.
|
|
||||||
|
|
||||||
This should pop up a browser window, where you grant access. This will then
|
|
||||||
generate a ~/.google-api.yaml file. You have two options here, you can either
|
|
||||||
copy the the information directly in your code, or you can store this as a file
|
|
||||||
and load it in the sample as a yaml. In this example we do the latter. NOTE: if
|
|
||||||
you are loading it as a yaml, ensure you rename/move the file, as the
|
|
||||||
~/.google-api.yaml file can get overwritten. The script will work as is if you
|
|
||||||
move the .google-api.yaml file to the sample directory.
|
|
||||||
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
At this, point, you should have
|
|
||||||
- Enabled your APIs Console account
|
|
||||||
- Created a storage bucket, if required
|
|
||||||
- Uploaded some data to Google Storage
|
|
||||||
- Modified the script to point the 'datafile' variable to the BUCKET/OBJECT name
|
|
||||||
- Modified the script to put your credentials in, either in the code or by
|
|
||||||
loading the generated .yaml file
|
|
||||||
|
|
||||||
We can now run the service!
|
|
||||||
|
|
||||||
$ ruby prediction.rb
|
|
||||||
|
|
||||||
This should start a service on `http://localhost:4567`. When you hit the service,
|
|
||||||
your ruby logs should show the Prediction API calls, and print the prediction
|
|
||||||
output in the debug.
|
|
||||||
|
|
||||||
This sample currently does not cover some newer features of Prediction API such
|
|
||||||
as streaming training, hosted models or class weights. If there are any
|
|
||||||
questions or suggestions to improve the script please email us at
|
|
||||||
prediction-api-discuss@googlegroups.com.
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,227 +0,0 @@
|
||||||
#!/usr/bin/ruby1.8
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright:: Copyright 2011 Google Inc.
|
|
||||||
# License:: All Rights Reserved.
|
|
||||||
# Original Author:: Bob Aman, Winton Davies, Robert Kaplow
|
|
||||||
# Maintainer:: Robert Kaplow (mailto:rkaplow@google.com)
|
|
||||||
|
|
||||||
require 'rubygems'
|
|
||||||
require 'sinatra'
|
|
||||||
require 'datamapper'
|
|
||||||
require 'google/api_client'
|
|
||||||
require 'yaml'
|
|
||||||
|
|
||||||
use Rack::Session::Pool, :expire_after => 86400 # 1 day
|
|
||||||
|
|
||||||
# Set up our token store
|
|
||||||
DataMapper.setup(:default, 'sqlite::memory:')
|
|
||||||
class TokenPair
|
|
||||||
include DataMapper::Resource
|
|
||||||
|
|
||||||
property :id, Serial
|
|
||||||
property :refresh_token, String
|
|
||||||
property :access_token, String
|
|
||||||
property :expires_in, Integer
|
|
||||||
property :issued_at, Integer
|
|
||||||
|
|
||||||
def update_token!(object)
|
|
||||||
self.refresh_token = object.refresh_token
|
|
||||||
self.access_token = object.access_token
|
|
||||||
self.expires_in = object.expires_in
|
|
||||||
self.issued_at = object.issued_at
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_hash
|
|
||||||
return {
|
|
||||||
:refresh_token => refresh_token,
|
|
||||||
:access_token => access_token,
|
|
||||||
:expires_in => expires_in,
|
|
||||||
:issued_at => Time.at(issued_at)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
TokenPair.auto_migrate!
|
|
||||||
|
|
||||||
before do
|
|
||||||
|
|
||||||
# FILL IN THIS SECTION
|
|
||||||
# This will work if your yaml file is stored as ./google-api.yaml
|
|
||||||
# ------------------------
|
|
||||||
oauth_yaml = YAML.load_file('.google-api.yaml')
|
|
||||||
@client = Google::APIClient.new
|
|
||||||
@client.authorization.client_id = oauth_yaml["client_id"]
|
|
||||||
@client.authorization.client_secret = oauth_yaml["client_secret"]
|
|
||||||
@client.authorization.scope = oauth_yaml["scope"]
|
|
||||||
@client.authorization.refresh_token = oauth_yaml["refresh_token"]
|
|
||||||
@client.authorization.access_token = oauth_yaml["access_token"]
|
|
||||||
# -----------------------
|
|
||||||
|
|
||||||
@client.authorization.redirect_uri = to('/oauth2callback')
|
|
||||||
|
|
||||||
# Workaround for now as expires_in may be nil, but when converted to int it becomes 0.
|
|
||||||
@client.authorization.expires_in = 1800 if @client.authorization.expires_in.to_i == 0
|
|
||||||
|
|
||||||
if session[:token_id]
|
|
||||||
# Load the access token here if it's available
|
|
||||||
token_pair = TokenPair.get(session[:token_id])
|
|
||||||
@client.authorization.update_token!(token_pair.to_hash)
|
|
||||||
end
|
|
||||||
if @client.authorization.refresh_token && @client.authorization.expired?
|
|
||||||
@client.authorization.fetch_access_token!
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
@prediction = @client.discovered_api('prediction', 'v1.3')
|
|
||||||
unless @client.authorization.access_token || request.path_info =~ /^\/oauth2/
|
|
||||||
redirect to('/oauth2authorize')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/oauth2authorize' do
|
|
||||||
redirect @client.authorization.authorization_uri.to_s, 303
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/oauth2callback' do
|
|
||||||
@client.authorization.fetch_access_token!
|
|
||||||
# Persist the token here
|
|
||||||
token_pair = if session[:token_id]
|
|
||||||
TokenPair.get(session[:token_id])
|
|
||||||
else
|
|
||||||
TokenPair.new
|
|
||||||
end
|
|
||||||
token_pair.update_token!(@client.authorization)
|
|
||||||
token_pair.save()
|
|
||||||
session[:token_id] = token_pair.id
|
|
||||||
redirect to('/')
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/' do
|
|
||||||
# FILL IN DATAFILE:
|
|
||||||
# ----------------------------------------
|
|
||||||
datafile = "BUCKET/OBJECT"
|
|
||||||
# ----------------------------------------
|
|
||||||
# Train a predictive model.
|
|
||||||
train(datafile)
|
|
||||||
# Check to make sure the training has completed.
|
|
||||||
if (is_done?(datafile))
|
|
||||||
# Do a prediction.
|
|
||||||
# FILL IN DESIRED INPUT:
|
|
||||||
# -------------------------------------------------------------------------------
|
|
||||||
# Note, the input features should match the features of the dataset.
|
|
||||||
prediction,score = get_prediction(datafile, ["Alice noticed with some surprise."])
|
|
||||||
# -------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# We currently just dump the results to output, but you can display them on the page if desired.
|
|
||||||
puts prediction
|
|
||||||
puts score
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Trains a predictive model.
|
|
||||||
#
|
|
||||||
# @param [String] filename The name of the file in Google Storage. NOTE: this do *not*
|
|
||||||
# include the gs:// part. If the Google Storage path is gs://bucket/object,
|
|
||||||
# then the correct string is "bucket/object"
|
|
||||||
def train(datafile)
|
|
||||||
input = "{\"id\" : \"#{datafile}\"}"
|
|
||||||
puts "training input: #{input}"
|
|
||||||
result = @client.execute(:api_method => @prediction.training.insert,
|
|
||||||
:merged_body => input,
|
|
||||||
:headers => {'Content-Type' => 'application/json'}
|
|
||||||
)
|
|
||||||
status, headers, body = result.response
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the current training status
|
|
||||||
#
|
|
||||||
# @param [String] filename The name of the file in Google Storage. NOTE: this do *not*
|
|
||||||
# include the gs:// part. If the Google Storage path is gs://bucket/object,
|
|
||||||
# then the correct string is "bucket/object"
|
|
||||||
# @return [Integer] status The HTTP status code of the training job.
|
|
||||||
def get_training_status(datafile)
|
|
||||||
result = @client.execute(:api_method => @prediction.training.get,
|
|
||||||
:parameters => {'data' => datafile})
|
|
||||||
status, headers, body = result.response
|
|
||||||
return status
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Checks the training status until a model exists (will loop forever).
|
|
||||||
#
|
|
||||||
# @param [String] filename The name of the file in Google Storage. NOTE: this do *not*
|
|
||||||
# include the gs:// part. If the Google Storage path is gs://bucket/object,
|
|
||||||
# then the correct string is "bucket/object"
|
|
||||||
# @return [Bool] exists True if model exists and can be used for predictions.
|
|
||||||
|
|
||||||
def is_done?(datafile)
|
|
||||||
status = get_training_status(datafile)
|
|
||||||
# We use an exponential backoff approach here.
|
|
||||||
test_counter = 0
|
|
||||||
while test_counter < 10 do
|
|
||||||
puts "Attempting to check model #{datafile} - Status: #{status} "
|
|
||||||
return true if status == 200
|
|
||||||
sleep 5 * (test_counter + 1)
|
|
||||||
status = get_training_status(datafile)
|
|
||||||
test_counter += 1
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
# Returns the prediction and most most likely class score if categorization.
|
|
||||||
#
|
|
||||||
# @param [String] filename The name of the file in Google Storage. NOTE: this do *not*
|
|
||||||
# include the gs:// part. If the Google Storage path is gs://bucket/object,
|
|
||||||
# then the correct string is "bucket/object"
|
|
||||||
# @param [List] input_features A list of input features.
|
|
||||||
#
|
|
||||||
# @return [String or Double] prediction The returned prediction, String if categorization,
|
|
||||||
# Double if regression
|
|
||||||
# @return [Double] trueclass_score The numeric score of the most likely label. (Categorical only).
|
|
||||||
|
|
||||||
def get_prediction(datafile,input_features)
|
|
||||||
# We take the input features and put it in the right input (json) format.
|
|
||||||
input="{\"input\" : { \"csvInstance\" : #{input_features}}}"
|
|
||||||
puts "Prediction Input: #{input}"
|
|
||||||
result = @client.execute(:api_method => @prediction.training.predict,
|
|
||||||
:parameters => {'data' => datafile},
|
|
||||||
:merged_body => input,
|
|
||||||
:headers => {'Content-Type' => 'application/json'})
|
|
||||||
status, headers, body = result.response
|
|
||||||
prediction_data = result.data
|
|
||||||
puts status
|
|
||||||
puts body
|
|
||||||
puts prediction_data
|
|
||||||
# Categorical
|
|
||||||
if prediction_data["outputLabel"] != nil
|
|
||||||
# Pull the most likely label.
|
|
||||||
prediction = prediction_data["outputLabel"]
|
|
||||||
# Pull the class probabilities.
|
|
||||||
probs = prediction_data["outputMulti"]
|
|
||||||
puts probs
|
|
||||||
# Verify we are getting a value result.
|
|
||||||
puts ["ERROR", input_features].join("\t") if probs.nil?
|
|
||||||
return "error", -1.0 if probs.nil?
|
|
||||||
|
|
||||||
# Extract the score for the most likely class.
|
|
||||||
trueclass_score = probs.select{|hash|
|
|
||||||
hash["label"] == prediction
|
|
||||||
}[0]["score"]
|
|
||||||
|
|
||||||
# Regression.
|
|
||||||
else
|
|
||||||
prediction = prediction_data["outputValue"]
|
|
||||||
# Class core unused.
|
|
||||||
trueclass_score = -1
|
|
||||||
end
|
|
||||||
|
|
||||||
puts [prediction,trueclass_score,input_features].join("\t")
|
|
||||||
return prediction,trueclass_score
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Copyright 2011 Google Inc. All Rights Reserved.
|
|
||||||
# Author: rkaplow@google.com (Robert Kaplow)
|
|
||||||
#
|
|
||||||
# Uploads a training data set to Google Storage to be used by this sample
|
|
||||||
# application.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# setup.sh bucket/object
|
|
||||||
#
|
|
||||||
# Requirements:
|
|
||||||
# gsutil - a client application for interacting with Google Storage. It
|
|
||||||
# can be downloaded from https://code.google.com/apis/storage/docs/gsutil.html
|
|
||||||
OBJECT_NAME=$1
|
|
||||||
gsutil cp data/language_id.txt gs://$OBJECT_NAME
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
Gem::Specification.new do |s|
|
||||||
|
s.name = "google-api-client"
|
||||||
|
s.version = "0.3.0"
|
||||||
|
|
||||||
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||||
|
s.authors = ["Bob Aman"]
|
||||||
|
s.date = "2011-11-16"
|
||||||
|
s.description = "The Google API Ruby Client makes it trivial to discover and access supported\nAPIs.\n"
|
||||||
|
s.email = "bobaman@google.com"
|
||||||
|
s.executables = ["google-api"]
|
||||||
|
s.extra_rdoc_files = ["README.md"]
|
||||||
|
s.files = ["lib/google", "lib/google/api_client", "lib/google/api_client/discovery", "lib/google/api_client/discovery/api.rb", "lib/google/api_client/discovery/method.rb", "lib/google/api_client/discovery/resource.rb", "lib/google/api_client/discovery.rb", "lib/google/api_client/environment.rb", "lib/google/api_client/errors.rb", "lib/google/api_client/parser.rb", "lib/google/api_client/parsers", "lib/google/api_client/parsers/json", "lib/google/api_client/parsers/json/error_parser.rb", "lib/google/api_client/parsers/json/pagination.rb", "lib/google/api_client/parsers/json_parser.rb", "lib/google/api_client/reference.rb", "lib/google/api_client/result.rb", "lib/google/api_client/version.rb", "lib/google/api_client.rb", "lib/google/inflection.rb", "spec/google", "spec/google/api_client", "spec/google/api_client/discovery_spec.rb", "spec/google/api_client/parsers", "spec/google/api_client/parsers/json_parser_spec.rb", "spec/google/api_client_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/clobber.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/metrics.rake", "tasks/rdoc.rake", "tasks/spec.rake", "tasks/wiki.rake", "tasks/yard.rake", "CHANGELOG", "LICENSE", "Rakefile", "README.md", "bin/google-api"]
|
||||||
|
s.homepage = "http://code.google.com/p/google-api-ruby-client/"
|
||||||
|
s.rdoc_options = ["--main", "README.md"]
|
||||||
|
s.require_paths = ["lib"]
|
||||||
|
s.rubygems_version = "1.8.11"
|
||||||
|
s.summary = "Package Summary"
|
||||||
|
|
||||||
|
if s.respond_to? :specification_version then
|
||||||
|
s.specification_version = 3
|
||||||
|
|
||||||
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||||
|
s.add_runtime_dependency(%q<signet>, ["~> 0.2.2"])
|
||||||
|
s.add_runtime_dependency(%q<addressable>, ["~> 2.2.2"])
|
||||||
|
s.add_runtime_dependency(%q<httpadapter>, ["~> 1.0.0"])
|
||||||
|
s.add_runtime_dependency(%q<json>, [">= 1.4.6"])
|
||||||
|
s.add_runtime_dependency(%q<extlib>, [">= 0.9.15"])
|
||||||
|
s.add_runtime_dependency(%q<launchy>, [">= 2.0.0"])
|
||||||
|
s.add_development_dependency(%q<sinatra>, [">= 1.2.0"])
|
||||||
|
s.add_development_dependency(%q<rake>, [">= 0.9.0"])
|
||||||
|
s.add_development_dependency(%q<rspec>, ["~> 1.2.9"])
|
||||||
|
s.add_development_dependency(%q<rcov>, [">= 0.9.9"])
|
||||||
|
s.add_development_dependency(%q<diff-lcs>, [">= 1.1.2"])
|
||||||
|
else
|
||||||
|
s.add_dependency(%q<signet>, ["~> 0.2.2"])
|
||||||
|
s.add_dependency(%q<addressable>, ["~> 2.2.2"])
|
||||||
|
s.add_dependency(%q<httpadapter>, ["~> 1.0.0"])
|
||||||
|
s.add_dependency(%q<json>, [">= 1.4.6"])
|
||||||
|
s.add_dependency(%q<extlib>, [">= 0.9.15"])
|
||||||
|
s.add_dependency(%q<launchy>, [">= 2.0.0"])
|
||||||
|
s.add_dependency(%q<sinatra>, [">= 1.2.0"])
|
||||||
|
s.add_dependency(%q<rake>, [">= 0.9.0"])
|
||||||
|
s.add_dependency(%q<rspec>, ["~> 1.2.9"])
|
||||||
|
s.add_dependency(%q<rcov>, [">= 0.9.9"])
|
||||||
|
s.add_dependency(%q<diff-lcs>, [">= 1.1.2"])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
s.add_dependency(%q<signet>, ["~> 0.2.2"])
|
||||||
|
s.add_dependency(%q<addressable>, ["~> 2.2.2"])
|
||||||
|
s.add_dependency(%q<httpadapter>, ["~> 1.0.0"])
|
||||||
|
s.add_dependency(%q<json>, [">= 1.4.6"])
|
||||||
|
s.add_dependency(%q<extlib>, [">= 0.9.15"])
|
||||||
|
s.add_dependency(%q<launchy>, [">= 2.0.0"])
|
||||||
|
s.add_dependency(%q<sinatra>, [">= 1.2.0"])
|
||||||
|
s.add_dependency(%q<rake>, [">= 0.9.0"])
|
||||||
|
s.add_dependency(%q<rspec>, ["~> 1.2.9"])
|
||||||
|
s.add_dependency(%q<rcov>, [">= 0.9.9"])
|
||||||
|
s.add_dependency(%q<diff-lcs>, [">= 1.1.2"])
|
||||||
|
end
|
||||||
|
end
|
|
@ -16,3 +16,4 @@
|
||||||
require 'google/api_client/discovery/api'
|
require 'google/api_client/discovery/api'
|
||||||
require 'google/api_client/discovery/resource'
|
require 'google/api_client/discovery/resource'
|
||||||
require 'google/api_client/discovery/method'
|
require 'google/api_client/discovery/method'
|
||||||
|
require 'google/api_client/discovery/schema'
|
||||||
|
|
|
@ -62,7 +62,10 @@ module Google
|
||||||
#
|
#
|
||||||
# @return [String] The service id.
|
# @return [String] The service id.
|
||||||
def id
|
def id
|
||||||
return @discovery_document['id']
|
return (
|
||||||
|
@discovery_document['id'] ||
|
||||||
|
"#{self.name}:#{self.version}"
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -168,15 +171,47 @@ module Google
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# A list of schemas available for this version of the API.
|
||||||
|
#
|
||||||
|
# @return [Hash] A list of {Google::APIClient::Schema} objects.
|
||||||
|
def schemas
|
||||||
|
return @schemas ||= (
|
||||||
|
(@discovery_document['schemas'] || []).inject({}) do |accu, (k, v)|
|
||||||
|
accu[k] = Google::APIClient::Schema.parse(self, v)
|
||||||
|
accu
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns a schema for a kind value.
|
||||||
|
#
|
||||||
|
# @return [Google::APIClient::Schema] The associated Schema object.
|
||||||
|
def schema_for_kind(kind)
|
||||||
|
api_name, schema_name = kind.split('#', 2)
|
||||||
|
if api_name != self.name
|
||||||
|
raise ArgumentError,
|
||||||
|
"The kind does not match this API. " +
|
||||||
|
"Expected '#{self.name}', got '#{api_name}'."
|
||||||
|
end
|
||||||
|
for k, v in self.schemas
|
||||||
|
return v if k.downcase == schema_name.downcase
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# A list of resources available at the root level of this version of the
|
# A list of resources available at the root level of this version of the
|
||||||
# service.
|
# API.
|
||||||
#
|
#
|
||||||
# @return [Array] A list of {Google::APIClient::Resource} objects.
|
# @return [Array] A list of {Google::APIClient::Resource} objects.
|
||||||
def resources
|
def resources
|
||||||
return @resources ||= (
|
return @resources ||= (
|
||||||
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
||||||
accu << Google::APIClient::Resource.new(self.method_base, k, v)
|
accu << Google::APIClient::Resource.new(
|
||||||
|
self, self.method_base, k, v
|
||||||
|
)
|
||||||
accu
|
accu
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
@ -184,13 +219,13 @@ module Google
|
||||||
|
|
||||||
##
|
##
|
||||||
# A list of methods available at the root level of this version of the
|
# A list of methods available at the root level of this version of the
|
||||||
# service.
|
# API.
|
||||||
#
|
#
|
||||||
# @return [Array] A list of {Google::APIClient::Method} objects.
|
# @return [Array] A list of {Google::APIClient::Method} objects.
|
||||||
def methods
|
def methods
|
||||||
return @methods ||= (
|
return @methods ||= (
|
||||||
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
||||||
accu << Google::APIClient::Method.new(self.method_base, k, v)
|
accu << Google::APIClient::Method.new(self, self.method_base, k, v)
|
||||||
accu
|
accu
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
|
@ -35,7 +35,8 @@ module Google
|
||||||
# The section of the discovery document that applies to this method.
|
# The section of the discovery document that applies to this method.
|
||||||
#
|
#
|
||||||
# @return [Google::APIClient::Method] The constructed method object.
|
# @return [Google::APIClient::Method] The constructed method object.
|
||||||
def initialize(method_base, method_name, discovery_document)
|
def initialize(api, method_base, method_name, discovery_document)
|
||||||
|
@api = api
|
||||||
@method_base = method_base
|
@method_base = method_base
|
||||||
@name = method_name
|
@name = method_name
|
||||||
@discovery_document = discovery_document
|
@discovery_document = discovery_document
|
||||||
|
@ -102,6 +103,32 @@ module Google
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the Schema object for the method's request, if any.
|
||||||
|
#
|
||||||
|
# @return [Google::APIClient::Schema] The request schema.
|
||||||
|
def request_schema
|
||||||
|
if @discovery_document['request']
|
||||||
|
schema_name = @discovery_document['request']['$ref']
|
||||||
|
return @api.schemas[schema_name]
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns the Schema object for the method's response, if any.
|
||||||
|
#
|
||||||
|
# @return [Google::APIClient::Schema] The response schema.
|
||||||
|
def response_schema
|
||||||
|
if @discovery_document['response']
|
||||||
|
schema_name = @discovery_document['response']['$ref']
|
||||||
|
return @api.schemas[schema_name]
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Normalizes parameters, converting to the appropriate types.
|
# Normalizes parameters, converting to the appropriate types.
|
||||||
#
|
#
|
||||||
|
|
|
@ -35,7 +35,8 @@ module Google
|
||||||
# The section of the discovery document that applies to this resource.
|
# The section of the discovery document that applies to this resource.
|
||||||
#
|
#
|
||||||
# @return [Google::APIClient::Resource] The constructed resource object.
|
# @return [Google::APIClient::Resource] The constructed resource object.
|
||||||
def initialize(method_base, resource_name, discovery_document)
|
def initialize(api, method_base, resource_name, discovery_document)
|
||||||
|
@api = api
|
||||||
@method_base = method_base
|
@method_base = method_base
|
||||||
@name = resource_name
|
@name = resource_name
|
||||||
@discovery_document = discovery_document
|
@discovery_document = discovery_document
|
||||||
|
@ -95,7 +96,9 @@ module Google
|
||||||
def resources
|
def resources
|
||||||
return @resources ||= (
|
return @resources ||= (
|
||||||
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
(@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
|
||||||
accu << Google::APIClient::Resource.new(self.method_base, k, v)
|
accu << Google::APIClient::Resource.new(
|
||||||
|
@api, self.method_base, k, v
|
||||||
|
)
|
||||||
accu
|
accu
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
@ -108,7 +111,7 @@ module Google
|
||||||
def methods
|
def methods
|
||||||
return @methods ||= (
|
return @methods ||= (
|
||||||
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
(@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
|
||||||
accu << Google::APIClient::Method.new(self.method_base, k, v)
|
accu << Google::APIClient::Method.new(@api, self.method_base, k, v)
|
||||||
accu
|
accu
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
# Copyright 2010 Google Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
require 'time'
|
||||||
|
require 'json'
|
||||||
|
require 'base64'
|
||||||
|
require 'autoparse'
|
||||||
|
require 'addressable/uri'
|
||||||
|
require 'addressable/template'
|
||||||
|
|
||||||
|
require 'google/inflection'
|
||||||
|
require 'google/api_client/errors'
|
||||||
|
|
||||||
|
module Google
|
||||||
|
class APIClient
|
||||||
|
module Schema
|
||||||
|
def self.parse(api, schema_data)
|
||||||
|
# This method is super-long, but hard to break up due to the
|
||||||
|
# unavoidable dependence on closures and execution context.
|
||||||
|
schema_name = schema_data['id']
|
||||||
|
|
||||||
|
# Due to an oversight, schema IDs may not be URI references.
|
||||||
|
# TODO(bobaman): Remove this code once this has been resolved.
|
||||||
|
schema_uri = (
|
||||||
|
api.document_base +
|
||||||
|
(schema_name[0..0] != '#' ? '#' + schema_name : schema_name)
|
||||||
|
)
|
||||||
|
# puts schema_uri
|
||||||
|
|
||||||
|
# Due to an oversight, schema IDs may not be URI references.
|
||||||
|
# TODO(bobaman): Remove this whole lambda once this has been resolved.
|
||||||
|
reformat_references = lambda do |data|
|
||||||
|
# This code is not particularly efficient due to recursive traversal
|
||||||
|
# and excess object creation, but this hopefully shouldn't be an
|
||||||
|
# issue since it should only be called only once per schema per
|
||||||
|
# process.
|
||||||
|
if data.kind_of?(Hash) && data['$ref']
|
||||||
|
reference = data['$ref']
|
||||||
|
reference = '#' + reference if reference[0..0] != '#'
|
||||||
|
data.merge({
|
||||||
|
'$ref' => reference
|
||||||
|
})
|
||||||
|
elsif data.kind_of?(Hash)
|
||||||
|
data.inject({}) do |accu, (key, value)|
|
||||||
|
if value.kind_of?(Hash)
|
||||||
|
accu[key] = reformat_references.call(value)
|
||||||
|
else
|
||||||
|
accu[key] = value
|
||||||
|
end
|
||||||
|
accu
|
||||||
|
end
|
||||||
|
else
|
||||||
|
data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
schema_data = reformat_references.call(schema_data)
|
||||||
|
# puts schema_data.inspect
|
||||||
|
|
||||||
|
if schema_name
|
||||||
|
api_name_string =
|
||||||
|
Google::INFLECTOR.camelize(api.name)
|
||||||
|
api_version_string =
|
||||||
|
Google::INFLECTOR.camelize(api.version).gsub('.', '_')
|
||||||
|
if Google::APIClient::Schema.const_defined?(api_name_string)
|
||||||
|
api_name = Google::APIClient::Schema.const_get(api_name_string)
|
||||||
|
else
|
||||||
|
api_name = Google::APIClient::Schema.const_set(
|
||||||
|
api_name_string, Module.new
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if api_name.const_defined?(api_version_string)
|
||||||
|
api_version = api_name.const_get(api_version_string)
|
||||||
|
else
|
||||||
|
api_version = api_name.const_set(api_version_string, Module.new)
|
||||||
|
end
|
||||||
|
if api_version.const_defined?(schema_name)
|
||||||
|
schema_class = api_version.const_get(schema_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# It's possible the schema has already been defined. If so, don't
|
||||||
|
# redefine it. This means that reloading a schema which has already
|
||||||
|
# been loaded into memory is not possible.
|
||||||
|
unless schema_class
|
||||||
|
schema_class = AutoParse.generate(schema_data, :uri => schema_uri)
|
||||||
|
if schema_name
|
||||||
|
api_version.const_set(schema_name, schema_class)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return schema_class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,8 +1,11 @@
|
||||||
module Google
|
module Google
|
||||||
class APIClient
|
class APIClient
|
||||||
module ENV
|
module ENV
|
||||||
OS_VERSION = if RUBY_PLATFORM =~ /win32/
|
OS_VERSION = if RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/
|
||||||
`ver`.sub(/\s*\[Version\s*/, '/').sub(']', '')
|
# TODO(bobaman)
|
||||||
|
# Confirm that all of these Windows environments actually have access
|
||||||
|
# to the `ver` command.
|
||||||
|
`ver`.sub(/\s*\[Version\s*/, '/').sub(']', '').strip
|
||||||
elsif RUBY_PLATFORM =~ /darwin/i
|
elsif RUBY_PLATFORM =~ /darwin/i
|
||||||
"Mac OS X/#{`sw_vers -productVersion`}"
|
"Mac OS X/#{`sw_vers -productVersion`}"
|
||||||
else
|
else
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
require 'google/api_client/parsers/json_parser'
|
|
||||||
|
|
||||||
module Google
|
module Google
|
||||||
class APIClient
|
class APIClient
|
||||||
##
|
##
|
||||||
|
@ -54,9 +52,27 @@ module Google
|
||||||
_, content_type = self.headers.detect do |h, v|
|
_, content_type = self.headers.detect do |h, v|
|
||||||
h.downcase == 'Content-Type'.downcase
|
h.downcase == 'Content-Type'.downcase
|
||||||
end
|
end
|
||||||
parser_type =
|
media_type = content_type[/^([^;]*);?.*$/, 1].strip.downcase
|
||||||
Google::APIClient::Parser.match_content_type(content_type)
|
data = self.body
|
||||||
parser_type.parse(self.body)
|
case media_type
|
||||||
|
when 'application/json'
|
||||||
|
data = ::JSON.parse(data)
|
||||||
|
# Strip data wrapper, if present
|
||||||
|
data = data['data'] if data.has_key?('data')
|
||||||
|
else
|
||||||
|
raise ArgumentError,
|
||||||
|
"Content-Type not supported for parsing: #{media_type}"
|
||||||
|
end
|
||||||
|
if @reference.api_method && @reference.api_method.response_schema
|
||||||
|
# Automatically parse using the schema designated for the
|
||||||
|
# response of this API method.
|
||||||
|
data = @reference.api_method.response_schema.new(data)
|
||||||
|
data
|
||||||
|
else
|
||||||
|
# Otherwise, return the raw unparsed value.
|
||||||
|
# This value must be indexable like a Hash.
|
||||||
|
data
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,12 @@ module Google
|
||||||
if defined?(ActiveSupport::Inflector)
|
if defined?(ActiveSupport::Inflector)
|
||||||
INFLECTOR = ActiveSupport::Inflector
|
INFLECTOR = ActiveSupport::Inflector
|
||||||
else
|
else
|
||||||
require 'extlib/inflection'
|
begin
|
||||||
INFLECTOR = Extlib::Inflection
|
require 'extlib/inflection'
|
||||||
|
INFLECTOR = Extlib::Inflection
|
||||||
|
rescue LoadError
|
||||||
|
require 'active_support/inflector'
|
||||||
|
INFLECTOR = ActiveSupport::Inflector
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -297,60 +297,54 @@ describe Google::APIClient do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with the buzz API' do
|
describe 'with the plus API' do
|
||||||
before do
|
before do
|
||||||
@client.authorization = nil
|
@client.authorization = nil
|
||||||
@buzz = @client.discovered_api('buzz')
|
@plus = @client.discovered_api('plus')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should correctly determine the discovery URI' do
|
it 'should correctly determine the discovery URI' do
|
||||||
@client.discovery_uri('buzz').should ===
|
@client.discovery_uri('plus').should ===
|
||||||
'https://www.googleapis.com/discovery/v1/apis/buzz/v1/rest'
|
'https://www.googleapis.com/discovery/v1/apis/plus/v1/rest'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should find APIs that are in the discovery document' do
|
it 'should find APIs that are in the discovery document' do
|
||||||
@client.discovered_api('buzz').name.should == 'buzz'
|
@client.discovered_api('plus').name.should == 'plus'
|
||||||
@client.discovered_api('buzz').version.should == 'v1'
|
@client.discovered_api('plus').version.should == 'v1'
|
||||||
@client.discovered_api(:buzz).name.should == 'buzz'
|
@client.discovered_api(:plus).name.should == 'plus'
|
||||||
@client.discovered_api(:buzz).version.should == 'v1'
|
@client.discovered_api(:plus).version.should == 'v1'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should find methods that are in the discovery document' do
|
it 'should find methods that are in the discovery document' do
|
||||||
# TODO(bobaman) Fix this when the RPC names are correct
|
# TODO(bobaman) Fix this when the RPC names are correct
|
||||||
@client.discovered_method(
|
@client.discovered_method(
|
||||||
'chili.activities.list', 'buzz'
|
'plus.activities.list', 'plus'
|
||||||
).name.should == 'list'
|
).name.should == 'list'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not find methods that are not in the discovery document' do
|
it 'should not find methods that are not in the discovery document' do
|
||||||
@client.discovered_method('buzz.bogus', 'buzz').should == nil
|
@client.discovered_method('plus.bogus', 'plus').should == nil
|
||||||
end
|
|
||||||
|
|
||||||
it 'should fail for string RPC names that do not match API name' do
|
|
||||||
(lambda do
|
|
||||||
@client.generate_request(
|
|
||||||
:api_method => 'chili.activities.list',
|
|
||||||
:parameters => {'alt' => 'json'},
|
|
||||||
:authenticated => false
|
|
||||||
)
|
|
||||||
end).should raise_error(Google::APIClient::TransmissionError)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should generate requests against the correct URIs' do
|
it 'should generate requests against the correct URIs' do
|
||||||
request = @client.generate_request(
|
request = @client.generate_request(
|
||||||
:api_method => @buzz.activities.list,
|
:api_method => @plus.activities.list,
|
||||||
:parameters => {'userId' => 'hikingfan', 'scope' => '@public'},
|
:parameters => {
|
||||||
|
'userId' => '107807692475771887386', 'collection' => 'public'
|
||||||
|
},
|
||||||
:authenticated => false
|
:authenticated => false
|
||||||
)
|
)
|
||||||
method, uri, headers, body = request
|
method, uri, headers, body = request
|
||||||
uri.should ==
|
uri.should == (
|
||||||
'https://www.googleapis.com/buzz/v1/activities/hikingfan/@public'
|
'https://www.googleapis.com/plus/v1/' +
|
||||||
|
'people/107807692475771887386/activities/public'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should correctly validate parameters' do
|
it 'should correctly validate parameters' do
|
||||||
(lambda do
|
(lambda do
|
||||||
@client.generate_request(
|
@client.generate_request(
|
||||||
:api_method => @buzz.activities.list,
|
:api_method => @plus.activities.list,
|
||||||
:parameters => {'alt' => 'json'},
|
:parameters => {'alt' => 'json'},
|
||||||
:authenticated => false
|
:authenticated => false
|
||||||
)
|
)
|
||||||
|
@ -360,33 +354,14 @@ describe Google::APIClient do
|
||||||
it 'should correctly validate parameters' do
|
it 'should correctly validate parameters' do
|
||||||
(lambda do
|
(lambda do
|
||||||
@client.generate_request(
|
@client.generate_request(
|
||||||
:api_method => @buzz.activities.list,
|
:api_method => @plus.activities.list,
|
||||||
:parameters => {'userId' => 'hikingfan', 'scope' => '@bogus'},
|
:parameters => {
|
||||||
|
'userId' => '107807692475771887386', 'collection' => 'bogus'
|
||||||
|
},
|
||||||
:authenticated => false
|
:authenticated => false
|
||||||
)
|
)
|
||||||
end).should raise_error(ArgumentError)
|
end).should raise_error(ArgumentError)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should be able to execute requests without authorization' do
|
|
||||||
result = @client.execute(
|
|
||||||
@buzz.activities.list,
|
|
||||||
{'alt' => 'json', 'userId' => 'hikingfan', 'scope' => '@public'},
|
|
||||||
'',
|
|
||||||
[],
|
|
||||||
:authenticated => false
|
|
||||||
)
|
|
||||||
status, headers, body = result.response
|
|
||||||
status.should == 200
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should not be able to execute requests without authorization' do
|
|
||||||
result = @client.execute(
|
|
||||||
@buzz.activities.list,
|
|
||||||
'alt' => 'json', 'userId' => '@me', 'scope' => '@self'
|
|
||||||
)
|
|
||||||
status, headers, body = result.response
|
|
||||||
status.should == 401
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with the latitude API' do
|
describe 'with the latitude API' do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require 'rake/gempackagetask'
|
require 'rubygems/package_task'
|
||||||
|
|
||||||
namespace :gem do
|
namespace :gem do
|
||||||
GEM_SPEC = Gem::Specification.new do |s|
|
GEM_SPEC = Gem::Specification.new do |s|
|
||||||
|
@ -17,24 +17,24 @@ namespace :gem do
|
||||||
s.files = PKG_FILES.to_a
|
s.files = PKG_FILES.to_a
|
||||||
s.executables << 'google-api'
|
s.executables << 'google-api'
|
||||||
|
|
||||||
s.has_rdoc = true
|
|
||||||
s.extra_rdoc_files = %w( README.md )
|
s.extra_rdoc_files = %w( README.md )
|
||||||
s.rdoc_options.concat ['--main', 'README.md']
|
s.rdoc_options.concat ['--main', 'README.md']
|
||||||
|
|
||||||
# Dependencies used in the main library
|
# Dependencies used in the main library
|
||||||
s.add_runtime_dependency('signet', '~> 0.2.2')
|
s.add_runtime_dependency('signet', '~> 0.2.2')
|
||||||
s.add_runtime_dependency('addressable', '~> 2.2.2')
|
s.add_runtime_dependency('addressable', '~> 2.2.2')
|
||||||
s.add_runtime_dependency('httpadapter', '~> 1.0.0')
|
s.add_runtime_dependency('httpadapter', '~> 1.0.1')
|
||||||
|
s.add_runtime_dependency('autoparse', '~> 0.2.0')
|
||||||
s.add_runtime_dependency('json', '>= 1.4.6')
|
s.add_runtime_dependency('json', '>= 1.4.6')
|
||||||
s.add_runtime_dependency('extlib', '>= 0.9.15')
|
s.add_runtime_dependency('extlib', '>= 0.9.15')
|
||||||
|
|
||||||
# Dependencies used in the CLI
|
# Dependencies used in the CLI
|
||||||
s.add_runtime_dependency('launchy', '>= 0.3.2')
|
s.add_runtime_dependency('launchy', '>= 2.0.0')
|
||||||
|
|
||||||
# Dependencies used in the examples
|
# Dependencies used in the examples
|
||||||
s.add_development_dependency('sinatra', '>= 1.2.0')
|
s.add_development_dependency('sinatra', '>= 1.2.0')
|
||||||
|
|
||||||
s.add_development_dependency('rake', '>= 0.7.3')
|
s.add_development_dependency('rake', '>= 0.9.0')
|
||||||
s.add_development_dependency('rspec', '~> 1.2.9')
|
s.add_development_dependency('rspec', '~> 1.2.9')
|
||||||
s.add_development_dependency('rcov', '>= 0.9.9')
|
s.add_development_dependency('rcov', '>= 0.9.9')
|
||||||
s.add_development_dependency('diff-lcs', '>= 1.1.2')
|
s.add_development_dependency('diff-lcs', '>= 1.1.2')
|
||||||
|
@ -44,7 +44,7 @@ namespace :gem do
|
||||||
s.homepage = PKG_HOMEPAGE
|
s.homepage = PKG_HOMEPAGE
|
||||||
end
|
end
|
||||||
|
|
||||||
Rake::GemPackageTask.new(GEM_SPEC) do |p|
|
Gem::PackageTask.new(GEM_SPEC) do |p|
|
||||||
p.gem_spec = GEM_SPEC
|
p.gem_spec = GEM_SPEC
|
||||||
p.need_tar = true
|
p.need_tar = true
|
||||||
p.need_zip = true
|
p.need_zip = true
|
||||||
|
@ -55,6 +55,21 @@ namespace :gem do
|
||||||
puts GEM_SPEC.to_ruby
|
puts GEM_SPEC.to_ruby
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "Generates .gemspec file"
|
||||||
|
task :gemspec do
|
||||||
|
spec_string = GEM_SPEC.to_ruby
|
||||||
|
|
||||||
|
begin
|
||||||
|
Thread.new { eval("$SAFE = 3\n#{spec_string}", binding) }.join
|
||||||
|
rescue
|
||||||
|
abort "unsafe gemspec: #{$!}"
|
||||||
|
else
|
||||||
|
File.open("#{GEM_SPEC.name}.gemspec", 'w') do |file|
|
||||||
|
file.write spec_string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
desc 'Install the gem'
|
desc 'Install the gem'
|
||||||
task :install => ['clobber', 'gem:package'] do
|
task :install => ['clobber', 'gem:package'] do
|
||||||
sh "#{SUDO} gem install --local pkg/#{GEM_SPEC.full_name}"
|
sh "#{SUDO} gem install --local pkg/#{GEM_SPEC.full_name}"
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
require 'rake/rdoctask'
|
require 'rubygems'
|
||||||
|
begin
|
||||||
|
# We prefer to use the RDoc gem over the site version.
|
||||||
|
gem 'rdoc'
|
||||||
|
rescue Gem::LoadError
|
||||||
|
end unless defined?(RDoc)
|
||||||
|
|
||||||
|
require 'rdoc/task'
|
||||||
|
|
||||||
namespace :doc do
|
namespace :doc do
|
||||||
desc 'Generate RDoc documentation'
|
desc 'Generate RDoc documentation'
|
||||||
Rake::RDocTask.new do |rdoc|
|
RDoc::Task.new do |rdoc|
|
||||||
rdoc.rdoc_dir = 'doc'
|
rdoc.rdoc_dir = 'doc'
|
||||||
rdoc.title = "#{PKG_NAME}-#{PKG_VERSION} Documentation"
|
rdoc.title = "#{PKG_NAME}-#{PKG_VERSION} Documentation"
|
||||||
rdoc.options << '--line-numbers' << '--inline-source' <<
|
rdoc.options << '--line-numbers' << 'cattr_accessor=object' <<
|
||||||
'--accessor' << 'cattr_accessor=object' << '--charset' << 'utf-8'
|
'--charset' << 'utf-8'
|
||||||
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
||||||
rdoc.rdoc_files.include('README.md', 'CHANGELOG', 'LICENSE')
|
rdoc.rdoc_files.include('README.md', 'CHANGELOG', 'LICENSE')
|
||||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||||
|
|
Loading…
Reference in New Issue