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
|
||||
* renamed some switches in the command line tool
|
||||
* added additional configuration capabilities
|
||||
* fixed a few deprecation warnings from dependencies
|
||||
* added gemspec to source control
|
||||
|
||||
== 0.2.0
|
||||
|
||||
|
|
4
Rakefile
4
Rakefile
|
@ -4,10 +4,6 @@ $LOAD_PATH.uniq!
|
|||
|
||||
require 'rubygems'
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
|
||||
gem 'rspec', '~> 1.2.9'
|
||||
begin
|
||||
|
|
|
@ -294,13 +294,12 @@ HTML
|
|||
exit(0)
|
||||
else
|
||||
$verifier = nil
|
||||
# TODO(bobaman): Cross-platform?
|
||||
logger = WEBrick::Log.new('/dev/null')
|
||||
server = WEBrick::HTTPServer.new(
|
||||
:Port => OAUTH_SERVER_PORT,
|
||||
:Logger => logger,
|
||||
:AccessLog => logger
|
||||
:Logger => WEBrick::Log.new,
|
||||
:AccessLog => WEBrick::Log.new
|
||||
)
|
||||
server.logger.level = 0
|
||||
trap("INT") { server.shutdown }
|
||||
|
||||
server.mount("/", OAuthVerifierServlet)
|
||||
|
@ -366,8 +365,8 @@ HTML
|
|||
exit(0)
|
||||
else
|
||||
$verifier = nil
|
||||
# TODO(bobaman): Cross-platform?
|
||||
logger = WEBrick::Log.new('/dev/null')
|
||||
logger = WEBrick::Log.new
|
||||
logger.level = 0
|
||||
server = WEBrick::HTTPServer.new(
|
||||
:Port => OAUTH_SERVER_PORT,
|
||||
:Logger => logger,
|
||||
|
@ -389,7 +388,7 @@ HTML
|
|||
)
|
||||
|
||||
# Launch browser
|
||||
Launchy::Browser.run(oauth_client.authorization_uri.to_s)
|
||||
Launchy.open(oauth_client.authorization_uri.to_s)
|
||||
|
||||
server.start
|
||||
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/resource'
|
||||
require 'google/api_client/discovery/method'
|
||||
require 'google/api_client/discovery/schema'
|
||||
|
|
|
@ -62,7 +62,10 @@ module Google
|
|||
#
|
||||
# @return [String] The service id.
|
||||
def id
|
||||
return @discovery_document['id']
|
||||
return (
|
||||
@discovery_document['id'] ||
|
||||
"#{self.name}:#{self.version}"
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -168,15 +171,47 @@ module Google
|
|||
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
|
||||
# service.
|
||||
# API.
|
||||
#
|
||||
# @return [Array] A list of {Google::APIClient::Resource} objects.
|
||||
def resources
|
||||
return @resources ||= (
|
||||
(@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
|
||||
end
|
||||
)
|
||||
|
@ -184,13 +219,13 @@ module Google
|
|||
|
||||
##
|
||||
# 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.
|
||||
def methods
|
||||
return @methods ||= (
|
||||
(@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
|
||||
end
|
||||
)
|
||||
|
|
|
@ -35,7 +35,8 @@ module Google
|
|||
# The section of the discovery document that applies to this method.
|
||||
#
|
||||
# @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
|
||||
@name = method_name
|
||||
@discovery_document = discovery_document
|
||||
|
@ -102,6 +103,32 @@ module Google
|
|||
)
|
||||
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.
|
||||
#
|
||||
|
|
|
@ -35,7 +35,8 @@ module Google
|
|||
# The section of the discovery document that applies to this resource.
|
||||
#
|
||||
# @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
|
||||
@name = resource_name
|
||||
@discovery_document = discovery_document
|
||||
|
@ -95,7 +96,9 @@ module Google
|
|||
def resources
|
||||
return @resources ||= (
|
||||
(@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
|
||||
end
|
||||
)
|
||||
|
@ -108,7 +111,7 @@ module Google
|
|||
def methods
|
||||
return @methods ||= (
|
||||
(@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
|
||||
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
|
||||
class APIClient
|
||||
module ENV
|
||||
OS_VERSION = if RUBY_PLATFORM =~ /win32/
|
||||
`ver`.sub(/\s*\[Version\s*/, '/').sub(']', '')
|
||||
OS_VERSION = if RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/
|
||||
# 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
|
||||
"Mac OS X/#{`sw_vers -productVersion`}"
|
||||
else
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'google/api_client/parsers/json_parser'
|
||||
|
||||
module Google
|
||||
class APIClient
|
||||
##
|
||||
|
@ -54,9 +52,27 @@ module Google
|
|||
_, content_type = self.headers.detect do |h, v|
|
||||
h.downcase == 'Content-Type'.downcase
|
||||
end
|
||||
parser_type =
|
||||
Google::APIClient::Parser.match_content_type(content_type)
|
||||
parser_type.parse(self.body)
|
||||
media_type = content_type[/^([^;]*);?.*$/, 1].strip.downcase
|
||||
data = 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
|
||||
|
||||
|
|
|
@ -17,7 +17,12 @@ module Google
|
|||
if defined?(ActiveSupport::Inflector)
|
||||
INFLECTOR = ActiveSupport::Inflector
|
||||
else
|
||||
require 'extlib/inflection'
|
||||
INFLECTOR = Extlib::Inflection
|
||||
begin
|
||||
require 'extlib/inflection'
|
||||
INFLECTOR = Extlib::Inflection
|
||||
rescue LoadError
|
||||
require 'active_support/inflector'
|
||||
INFLECTOR = ActiveSupport::Inflector
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -297,60 +297,54 @@ describe Google::APIClient do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'with the buzz API' do
|
||||
describe 'with the plus API' do
|
||||
before do
|
||||
@client.authorization = nil
|
||||
@buzz = @client.discovered_api('buzz')
|
||||
@plus = @client.discovered_api('plus')
|
||||
end
|
||||
|
||||
it 'should correctly determine the discovery URI' do
|
||||
@client.discovery_uri('buzz').should ===
|
||||
'https://www.googleapis.com/discovery/v1/apis/buzz/v1/rest'
|
||||
@client.discovery_uri('plus').should ===
|
||||
'https://www.googleapis.com/discovery/v1/apis/plus/v1/rest'
|
||||
end
|
||||
|
||||
it 'should find APIs that are in the discovery document' do
|
||||
@client.discovered_api('buzz').name.should == 'buzz'
|
||||
@client.discovered_api('buzz').version.should == 'v1'
|
||||
@client.discovered_api(:buzz).name.should == 'buzz'
|
||||
@client.discovered_api(:buzz).version.should == 'v1'
|
||||
@client.discovered_api('plus').name.should == 'plus'
|
||||
@client.discovered_api('plus').version.should == 'v1'
|
||||
@client.discovered_api(:plus).name.should == 'plus'
|
||||
@client.discovered_api(:plus).version.should == 'v1'
|
||||
end
|
||||
|
||||
it 'should find methods that are in the discovery document' do
|
||||
# TODO(bobaman) Fix this when the RPC names are correct
|
||||
@client.discovered_method(
|
||||
'chili.activities.list', 'buzz'
|
||||
'plus.activities.list', 'plus'
|
||||
).name.should == 'list'
|
||||
end
|
||||
|
||||
it 'should not find methods that are not in the discovery document' do
|
||||
@client.discovered_method('buzz.bogus', 'buzz').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)
|
||||
@client.discovered_method('plus.bogus', 'plus').should == nil
|
||||
end
|
||||
|
||||
it 'should generate requests against the correct URIs' do
|
||||
request = @client.generate_request(
|
||||
:api_method => @buzz.activities.list,
|
||||
:parameters => {'userId' => 'hikingfan', 'scope' => '@public'},
|
||||
:api_method => @plus.activities.list,
|
||||
:parameters => {
|
||||
'userId' => '107807692475771887386', 'collection' => 'public'
|
||||
},
|
||||
:authenticated => false
|
||||
)
|
||||
method, uri, headers, body = request
|
||||
uri.should ==
|
||||
'https://www.googleapis.com/buzz/v1/activities/hikingfan/@public'
|
||||
uri.should == (
|
||||
'https://www.googleapis.com/plus/v1/' +
|
||||
'people/107807692475771887386/activities/public'
|
||||
)
|
||||
end
|
||||
|
||||
it 'should correctly validate parameters' do
|
||||
(lambda do
|
||||
@client.generate_request(
|
||||
:api_method => @buzz.activities.list,
|
||||
:api_method => @plus.activities.list,
|
||||
:parameters => {'alt' => 'json'},
|
||||
:authenticated => false
|
||||
)
|
||||
|
@ -360,33 +354,14 @@ describe Google::APIClient do
|
|||
it 'should correctly validate parameters' do
|
||||
(lambda do
|
||||
@client.generate_request(
|
||||
:api_method => @buzz.activities.list,
|
||||
:parameters => {'userId' => 'hikingfan', 'scope' => '@bogus'},
|
||||
:api_method => @plus.activities.list,
|
||||
:parameters => {
|
||||
'userId' => '107807692475771887386', 'collection' => 'bogus'
|
||||
},
|
||||
:authenticated => false
|
||||
)
|
||||
end).should raise_error(ArgumentError)
|
||||
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
|
||||
|
||||
describe 'with the latitude API' do
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
require 'rake/gempackagetask'
|
||||
require 'rubygems/package_task'
|
||||
|
||||
namespace :gem do
|
||||
GEM_SPEC = Gem::Specification.new do |s|
|
||||
|
@ -17,24 +17,24 @@ namespace :gem do
|
|||
s.files = PKG_FILES.to_a
|
||||
s.executables << 'google-api'
|
||||
|
||||
s.has_rdoc = true
|
||||
s.extra_rdoc_files = %w( README.md )
|
||||
s.rdoc_options.concat ['--main', 'README.md']
|
||||
|
||||
# Dependencies used in the main library
|
||||
s.add_runtime_dependency('signet', '~> 0.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('extlib', '>= 0.9.15')
|
||||
|
||||
# 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
|
||||
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('rcov', '>= 0.9.9')
|
||||
s.add_development_dependency('diff-lcs', '>= 1.1.2')
|
||||
|
@ -44,7 +44,7 @@ namespace :gem do
|
|||
s.homepage = PKG_HOMEPAGE
|
||||
end
|
||||
|
||||
Rake::GemPackageTask.new(GEM_SPEC) do |p|
|
||||
Gem::PackageTask.new(GEM_SPEC) do |p|
|
||||
p.gem_spec = GEM_SPEC
|
||||
p.need_tar = true
|
||||
p.need_zip = true
|
||||
|
@ -55,6 +55,21 @@ namespace :gem do
|
|||
puts GEM_SPEC.to_ruby
|
||||
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'
|
||||
task :install => ['clobber', 'gem:package'] do
|
||||
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
|
||||
desc 'Generate RDoc documentation'
|
||||
Rake::RDocTask.new do |rdoc|
|
||||
RDoc::Task.new do |rdoc|
|
||||
rdoc.rdoc_dir = 'doc'
|
||||
rdoc.title = "#{PKG_NAME}-#{PKG_VERSION} Documentation"
|
||||
rdoc.options << '--line-numbers' << '--inline-source' <<
|
||||
'--accessor' << 'cattr_accessor=object' << '--charset' << 'utf-8'
|
||||
rdoc.options << '--line-numbers' << 'cattr_accessor=object' <<
|
||||
'--charset' << 'utf-8'
|
||||
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
||||
rdoc.rdoc_files.include('README.md', 'CHANGELOG', 'LICENSE')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
|
|
Loading…
Reference in New Issue