#!/usr/bin/ruby -w # # Copyright:: Copyright 2008 Google Inc. # License:: All Rights Reserved. # Original Author:: Jochen Hartmann (mailto:jhartmann@google.com) # # Simple class that contains all the methods listed in the 'Using Ruby with the # Google Data APIs' article # # Contains method for ClientLogin authentication and performing GET, # POST and PUT requests # # SpreadsheetExamples: contains methods as build in the article # # $Id: //depot/google3/googledata/codesite/html/articles/support/ruby/SpreadsheetExamples.rb $ require 'net/http' require 'net/https' require 'rubygems' require 'xmlsimple' require 'rexml/document' # Contains all the methods listed in the # 'Using Ruby with the Google Data API's article'. # # Performs authentication via ClientLogin, feed retrieval, post and batch # update requests. # class SpreadsheetExamples SPREADSHEET_FEED = \ 'http://spreadsheets.google.com/feeds/spreadsheets/private/full' CONTENT_TYPE_FORM = 'application/x-www-form-urlencoded' CONTENT_TYPE_ATOMXML = 'application/atom+xml' attr_reader :headers # Authenticate with ClientLogin # # Args: # email: string # password: string # def authenticate(email, password) http = Net::HTTP.new('www.google.com', 443) http.use_ssl = true path = '/accounts/ClientLogin' data = "accountType=HOSTED_OR_GOOGLE&Email=#{email}" \ "&Passwd=#{password}&service=wise" @headers = { 'Content-Type' => CONTENT_TYPE_FORM } resp, data = http.post(path, data, headers) cl_string = data[/Auth=(.*)/, 1] @headers["Authorization"] = "GoogleLogin auth=#{cl_string}" end # Set 'Content-Type' header to 'application/atom+xml' def set_header_content_type_to_xml() @headers["Content-Type"] = CONTENT_TYPE_ATOMXML end # Perform a GET request to a given uri # # Args: # uri: string # # Returns: # Net::HTTPResponse # def get_feed(uri) uri = URI.parse(uri) Net::HTTP.start(uri.host, uri.port) do |http| return http.get(uri.path, @headers) end end # Parse xml into a datastructure using xmlsimple # # Args: # xml: string # # Returns: # A hash containing the xml data provided in the argument # def create_datastructure_from_xml(xml) return XmlSimple.xml_in(xml, 'KeyAttr' => 'name') end # Get spreadsheet feed for currently authenticated user def get_my_spreadsheets() spreadsheet_feed_response = get_feed(SPREADSHEET_FEED) create_datastructure_from_xml(spreadsheet_feed_response.body) end # Get the worksheets feed for a given spreadsheet # # Args: # spreadsheet_key: string # # Returns: # Net::HTTPResponse: The worksheet feed # def get_worksheet(spreadsheet_key) worksheet_feed_uri = "http://spreadsheets.google.com/feeds/" << "worksheets/#{spreadsheet_key}/private/full" return get_feed(worksheet_feed_uri) end # Post data to a specific uri # # Args: # uri: string # data: string (typically xml) # # Returns: # Net::HTTPResponse # def post(uri, data) uri = URI.parse(uri) http = Net::HTTP.new(uri.host, uri.port) return http.post(uri.path, data, @headers) end # Obtain the version string for a specific cell # # Args: # uri: string # # Returns: # A string containing the version string # def get_version_string(uri) response = get_feed(uri) xml = REXML::Document.new response.body # use XPath to strip the href attribute of the first link whose # 'rel' attribute is set to edit edit_link = REXML::XPath.first(xml, '//[@rel="edit"]') edit_link_href = edit_link.attribute('href').to_s # return the version string at the end of the link's href attribute return edit_link_href.split(/\//)[10] end # Perform a batch update using the cellsfeed of a specific spreadsheet # # Args: # batch_data: array of hashes of data to post # sample hash: +batch_id+: string (i.e. "A") # +cell_id+: string (i.e. "R1C1") # +data+: string (i.e. "My data") # # Returns: # Net::HTTPResponse # def batch_update(batch_data, cellfeed_uri) batch_uri = cellfeed_uri + '/batch' batch_request = < \ #{cellfeed_uri} FEED batch_data.each do |batch_request_data| version_string = get_version_string(cellfeed_uri + '/' + batch_request_data[:cell_id]) data = batch_request_data[:data] batch_id = batch_request_data[:batch_id] cell_id = batch_request_data[:cell_id] row = batch_request_data[:cell_id][1,1] column = batch_request_data[:cell_id][3,1] edit_link = cellfeed_uri + '/' + cell_id + '/' + version_string batch_request<< < #{batch_id} #{cellfeed_uri}/#{cell_id} ENTRY end batch_request << '' return post(batch_uri, batch_request) end end