Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

version 0.0.4, working with spreadsheet data manipulation

  • Loading branch information...
commit 448900b57f6a9e6284de5e395aee4414877251af 1 parent 837f073
@lancejpollard authored
View
3  .gitignore
@@ -4,4 +4,5 @@ doc/**/*
*.tgz
*.gem
*.result
-*.yml
+*.yml
+spec/config.yml
View
2  README.textile
@@ -38,6 +38,8 @@ If this is for Google Apps, you must go to Google Docs Settings in the Admin Pan
h2. Top 10 Things I Need the Google Data API to Have
"Submit Your Ideas to Google!!!":http://productideas.appspot.com/#15/e=220cb&t=2192a&f=22150
+http://productideas.appspot.com/#15/e=220cb&t=cabc1
+
# Partial Responses for everything.
So we can get only the data we need. This way we can poll our google docs for any changes and run processes on them.
View
3  Rakefile
@@ -17,9 +17,6 @@ def files(path, from = __FILE__, &block)
Dir.glob(File.join(File.dirname(from), path)) {|file| yield file}
end
-APP_ROOT = defined?(RAILS_ROOT) ? RAILS_ROOT : File.dirname(__FILE__)
-RAILS_ROOT = File.dirname(__FILE__)
-
# http://docs.rubygems.org/read/chapter/20
spec = Gem::Specification.new do |s|
s.name = "googletastic"
View
4 googletastic.gemspec
@@ -2,7 +2,7 @@
Gem::Specification.new do |s|
s.name = %q{googletastic}
- s.version = "0.0.1"
+ s.version = "0.0.3"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Lance Pollard"]
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
s.description = %q{Googletastic: A New Way of Googling}
s.email = %q{lancejpollard@gmail.com}
s.extra_rdoc_files = ["README.textile"]
- s.files = ["README.textile", "Rakefile", "lib/googletastic", "lib/googletastic/access_rule.rb", "lib/googletastic/album.rb", "lib/googletastic/app_engine.rb", "lib/googletastic/attendee.rb", "lib/googletastic/base.rb", "lib/googletastic/calendar.rb", "lib/googletastic/comment.rb", "lib/googletastic/document.rb", "lib/googletastic/event.rb", "lib/googletastic/ext", "lib/googletastic/ext/file.rb", "lib/googletastic/ext/pretty_print.xsl", "lib/googletastic/ext/xml.rb", "lib/googletastic/ext.rb", "lib/googletastic/form.rb", "lib/googletastic/group.rb", "lib/googletastic/helpers", "lib/googletastic/helpers/document.rb", "lib/googletastic/helpers/event.rb", "lib/googletastic/helpers/form.rb", "lib/googletastic/helpers.rb", "lib/googletastic/image.rb", "lib/googletastic/mixins", "lib/googletastic/mixins/actions.rb", "lib/googletastic/mixins/attributes.rb", "lib/googletastic/mixins/finders.rb", "lib/googletastic/mixins/namespaces.rb", "lib/googletastic/mixins/parsing.rb", "lib/googletastic/mixins/requesting.rb", "lib/googletastic/mixins.rb", "lib/googletastic/person.rb", "lib/googletastic/spreadsheet.rb", "lib/googletastic/sync", "lib/googletastic/sync/document.rb", "lib/googletastic/sync/form.rb", "lib/googletastic/sync.rb", "lib/googletastic/thumbnail.rb", "lib/googletastic/youtube.rb", "lib/googletastic.rb", "spec/benchmarks", "spec/benchmarks/document_benchmark.rb", "spec/config.yml", "spec/fixtures", "spec/fixtures/data", "spec/fixtures/data/basic.txt", "spec/fixtures/data/calendar.list.xml", "spec/fixtures/data/doc_as_html.html", "spec/fixtures/data/doc_as_html_html.html", "spec/fixtures/data/doclist.xml", "spec/fixtures/data/document.single.xml", "spec/fixtures/data/Doing business in the eMarketPlace.doc", "spec/fixtures/data/end.xml", "spec/fixtures/data/event.list.xml", "spec/fixtures/data/form.html", "spec/fixtures/data/group.list.xml", "spec/fixtures/data/person.list.xml", "spec/fixtures/data/photo.list.xml", "spec/fixtures/data/sample_upload.mp4", "spec/fixtures/data/spreadsheet.list.xml", "spec/fixtures/models", "spec/fixtures/models/document.rb", "spec/fixtures/models/event.rb", "spec/fixtures/models/form.rb", "spec/fixtures/models/test_model.rb", "spec/fixtures/results", "spec/fixtures/results/test.txt", "spec/googletastic", "spec/googletastic/access_rule_spec.rb", "spec/googletastic/album_spec.rb", "spec/googletastic/app_engine_spec.rb", "spec/googletastic/base_spec.rb", "spec/googletastic/calendar_spec.rb", "spec/googletastic/document_spec.rb", "spec/googletastic/event_spec.rb", "spec/googletastic/form_spec.rb", "spec/googletastic/group_spec.rb", "spec/googletastic/image_spec.rb", "spec/googletastic/person_spec.rb", "spec/googletastic/post_spec.rb", "spec/googletastic/spreadsheet_spec.rb", "spec/googletastic/youtube_spec.rb", "spec/spec.opts", "spec/spec_helper.rb"]
+ s.files = ["README.textile", "Rakefile", "lib/googletastic", "lib/googletastic/access_rule.rb", "lib/googletastic/album.rb", "lib/googletastic/analytics.rb", "lib/googletastic/app_engine.rb", "lib/googletastic/apps.rb", "lib/googletastic/attendee.rb", "lib/googletastic/base.rb", "lib/googletastic/calendar.rb", "lib/googletastic/comment.rb", "lib/googletastic/document.rb", "lib/googletastic/event.rb", "lib/googletastic/ext", "lib/googletastic/ext/file.rb", "lib/googletastic/ext/pretty_print.xsl", "lib/googletastic/ext/xml.rb", "lib/googletastic/ext.rb", "lib/googletastic/form.rb", "lib/googletastic/group.rb", "lib/googletastic/helpers", "lib/googletastic/helpers/document.rb", "lib/googletastic/helpers/event.rb", "lib/googletastic/helpers/form.rb", "lib/googletastic/helpers.rb", "lib/googletastic/image.rb", "lib/googletastic/mixins", "lib/googletastic/mixins/actions.rb", "lib/googletastic/mixins/attributes.rb", "lib/googletastic/mixins/finders.rb", "lib/googletastic/mixins/namespaces.rb", "lib/googletastic/mixins/parsing.rb", "lib/googletastic/mixins/requesting.rb", "lib/googletastic/mixins.rb", "lib/googletastic/person.rb", "lib/googletastic/spreadsheet.rb", "lib/googletastic/sync", "lib/googletastic/sync/document.rb", "lib/googletastic/sync/form.rb", "lib/googletastic/sync.rb", "lib/googletastic/thumbnail.rb", "lib/googletastic/youtube.rb", "lib/googletastic.rb", "spec/benchmarks", "spec/benchmarks/document_benchmark.rb", "spec/config.yml", "spec/fixtures", "spec/fixtures/data", "spec/fixtures/data/basic.txt", "spec/fixtures/data/calendar.list.xml", "spec/fixtures/data/doc_as_html.html", "spec/fixtures/data/doc_as_html_html.html", "spec/fixtures/data/doclist.xml", "spec/fixtures/data/document.single.xml", "spec/fixtures/data/Doing business in the eMarketPlace.doc", "spec/fixtures/data/end.xml", "spec/fixtures/data/event.list.xml", "spec/fixtures/data/form.html", "spec/fixtures/data/group.list.xml", "spec/fixtures/data/person.list.xml", "spec/fixtures/data/photo.list.xml", "spec/fixtures/data/sample_upload.mp4", "spec/fixtures/data/spreadsheet.list.xml", "spec/fixtures/models", "spec/fixtures/models/document.rb", "spec/fixtures/models/event.rb", "spec/fixtures/models/form.rb", "spec/fixtures/models/test_model.rb", "spec/fixtures/results", "spec/fixtures/results/test.txt", "spec/googletastic", "spec/googletastic/access_rule_spec.rb", "spec/googletastic/album_spec.rb", "spec/googletastic/app_engine_spec.rb", "spec/googletastic/base_spec.rb", "spec/googletastic/calendar_spec.rb", "spec/googletastic/document_spec.rb", "spec/googletastic/event_spec.rb", "spec/googletastic/form_spec.rb", "spec/googletastic/group_spec.rb", "spec/googletastic/image_spec.rb", "spec/googletastic/person_spec.rb", "spec/googletastic/post_spec.rb", "spec/googletastic/spreadsheet_spec.rb", "spec/googletastic/youtube_spec.rb", "spec/spec.opts", "spec/spec_helper.rb"]
s.homepage = %q{http://github.com/viatropos/googletastic}
s.require_paths = ["lib"]
s.rubyforge_project = %q{googletastic}
View
5 lib/googletastic.rb
@@ -9,6 +9,7 @@
require 'active_record'
require 'gdata'
require 'liquid'
+require 'mechanize'
GOOGLETASTIC_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(GOOGLETASTIC_ROOT)
@@ -58,7 +59,7 @@ def parameterize(sep = '-')
module Googletastic
# :stopdoc:
- VERSION = '0.0.1'
+ VERSION = '0.0.4'
# :startdoc
class << self; attr_accessor :keys, :clients, :options; end
@@ -69,7 +70,7 @@ def self.credentials
raise "Sorry, you must have #{config_file}" unless File.exists?(config_file)
self.keys = YAML.load_file(config_file).symbolize_keys
end
-
+
def self.client_for(model)
self.clients ||= {}
model = model.to_sym
View
34 lib/googletastic/analytics.rb
@@ -0,0 +1,34 @@
+module Googletastic::Analytics
+ # https://www.google.com/accounts/ServiceLoginBox?service=analytics&nui=1&hl=en-US&continue=https://www.google.com/analytics/settings/?et=reset&hl=en&et=reset&hl=en-US
+
+ def create(options = {})
+ agent = WWW::Mechanize.new
+ agent.cookie_jar.load(options[:cookies])
+ scid = "15601175" # one of the options options[:profile]
+ form.fields_with("scid").first.value = scid
+ next_page = agent.submit(form)
+ new_analytics = "https://www.google.com/analytics/settings/add_profile?scid=#{scid}"
+ # ucpr_protocol
+ form = next_page.forms_with(:name => "mform").first
+ form.ucpr_url = options[:domain]
+ tracking = agent.submit(form)
+ tracking_code = tracking.parser.xpath("//script").to_s.match(/getTracker\(["|']([^"|']+)["|']\)/).captures.first
+ end
+
+ # returns an array of account names you can use
+ def login(options = {})
+ agent = WWW::Mechanize.new
+ url = "https://www.google.com/accounts/ServiceLoginBox?service=analytics&nui=1&hl=en-US&continue=https://www.google.com/analytics/settings/?et=reset&hl=en&et=reset&hl=en-US"
+ page = agent.get(url)
+ login_form = page.forms.first
+ login_form.Email = options[:email]
+ login_form.Passwd = options[:password]
+
+ # agent.cookie_jar.save_as("something.yml")
+
+ next_page = agent.submit(login_form)
+ home = next_page.links.first.click
+
+ form = home.forms_with("account_selector").first
+ end
+end
View
5 lib/googletastic/app_engine.rb
@@ -83,6 +83,9 @@ def push(username, password, options = {})
output.write("#{password}\n")
end
while ((str = input.gets) != nil)
+ if str =~ /Checking if new version is ready to serve/
+
+ end
puts str
end
rescue Exception => e
@@ -98,6 +101,6 @@ def push(username, password, options = {})
end
end
-module Googletastic::AppEngine
+class Googletastic::AppEngine < Googletastic::Base
end
View
62 lib/googletastic/apps.rb
@@ -0,0 +1,62 @@
+class Googletastic::Apps < Googletastic::Base
+
+ class << self
+
+ def new_url
+ "http://www.google.com/a/cpanel/domain/new"
+ end
+
+ # follow_meta_refresh for FORMS!!!
+ # might have to save cookiejar between requests as captcha is presented
+ # domain, first_name, last_name, email, phone, country, username, password, password_confirmation
+ def create(options = {})
+ # precaptcha and postcaptcha
+ agent = WWW::Mechanize.new
+ page = agent.get(new_url)
+ # fill out domain name (must already have)
+ form = page.forms_with("domainEntry").first
+ form.radiobuttons.first.check
+ form.fields_with("existingDomain").first.value = options[:domain]
+ second_page = agent.submit(form)
+ # fill out profile
+ form = second_page.forms.first
+ form.firstName = options[:first_name]
+ form.lastName = options[:last_name]
+ form.email = options[:email]
+ form.phone = options[:phone]
+ #form.jobTitle = ""
+ #form.orgName = ""
+ # default value is "US"
+ form.country = options[:country] || "US"
+ # form.orgType = ""
+ # form.orgSize
+ # DO YOU AGREE???
+ form.checkboxes_with("domainAdminCheck").first.check
+ # third page must be filled out within about a minute it seems
+ third_page = agent.submit(form)
+ form = last_page.forms.first
+ # sample CAPTCHA URL (or "format=audio")
+ # form.captchaToken
+ # https://www.google.com/a/cpanel/captcha?format=image&captchaToken=crazy-token
+ form.captchaAnswer = "progshi"
+ form.newUserName = options[:username]
+ # minimum 6 chars
+ form.fields_with("newPassword.alpha").first.value = options[:password]
+ form.fields_with("newPassword.beta").first.value = options[:password_confirmation]
+ last_page = agent.submit(form)
+
+ # now you have your account
+ form = last_page.forms_with(:action => "VerifyDomainOwnership").first
+ form.radiobuttons_with(:value => "htmlVer").first.check
+
+ verify_page = agent.submit(form)
+ form = verify_page.forms_with(:action => "VerifyDomainOwnership") # or "id => 'verificationPages'"
+ # upload file "googlehostedservice.html" with special text, and let google know it's okay
+ special_text = verify_page.parser.xpath("//span[@class='callout']").first.text
+ # upload to http://tinker.heroku.com/googlehostedservice.html
+ apps_home = agent.submit(form)
+ end
+
+ end
+
+end
View
2  lib/googletastic/base.rb
@@ -18,6 +18,8 @@ class Googletastic::Base < Hash
# classes/records it is synced with
attr_accessor :synced_with
attr_accessor :response
+ attr_accessor :keep_raw
+ attr_accessor :raw
def synced_with
@synced_with ||= []
View
28 lib/googletastic/document.rb
@@ -47,7 +47,7 @@ def content
end
end
body.xpath("//div[@id='google-view-footer']").each { |n| n.unlink }
- @content = body.xpath("//div[@id='doc-contents']").first
+ @content = body.xpath("//div[@id='doc-contents']").first.to_html
end
def acl
@@ -98,11 +98,12 @@ def valid_queries
:language => "sourceLanguage",
:permanent_delete => "delete",
:convert => "convert",
- :format => "exportFormat"
+ :format => "exportFormat",
+ :kind => "category"
}.merge(super)
end
- def valid_category?(value)
+ def valid_kind?(value)
%w(document spreadsheet folder presentation pdf form).include?(value)
end
@@ -173,7 +174,7 @@ def unmarshall(xml)
title = record.xpath("atom:title", ns_tag("atom")).text
categories = record.xpath("atom:category", ns_tag("atom")).collect do |category|
value = category["label"].to_s
- kind = value if !kind and valid_category?(value)
+ kind = value if !kind and valid_kind?(value)
value
end
resource_id = record.xpath("gd:resourceId", ns_tag("gd")).text
@@ -215,5 +216,24 @@ def marshall(record)
}
}.to_xml
end
+
+ def get_clean_content(remote)
+ title = remote.title
+ ext = remote.ext
+ if ext == ".textile"
+ # google is putting strange characters at beginning of downloaded files
+ content = remote.download("txt").body.gsub(/\357\273\277/, "")
+ content = RedCloth.new(content).to_html
+ elsif ext == ".markdown"
+ content = remote.download("txt").body.gsub(/\357\273\277/, "")
+ content = BlueCloth.new(content).to_html
+ elsif ext.nil? || ext.empty?
+ # just use the html we have already
+ content = remote.content
+ else
+ content = remote.download("txt").body.gsub(/\357\273\277/, "")
+ end
+ content
+ end
end
end
View
3  lib/googletastic/ext/pretty_print.xsl
@@ -1,5 +1,6 @@
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:output method="xml" encoding="ISO-8859-1"/>
+ <xsl:output method="html" indent="yes" encoding="ISO-8859-1"/>
+
<xsl:param name="indent-increment" select="' '"/>
<xsl:template name="newline">
View
29 lib/googletastic/ext/xml.rb
@@ -2,9 +2,38 @@
module Googletastic::PrettyPrint
class << self
def xml(xml)
+ return "" if xml.nil?
+ raise "will throw segmentation error if not an Nokogiri::XML::Document" unless xml.is_a?(Nokogiri::XML::Document)
pretty_printer = File.join(File.dirname(__FILE__), "pretty_print.xsl")
xsl = Nokogiri::XSLT(IO.read(pretty_printer))
xsl.transform(xml).children.to_xml.gsub(/\t/, "")
end
+
+ def pretty_html(html)
+ return "" if html.nil?
+ raise "will throw segmentation error if not an Nokogiri::HTML::Document" unless xml.is_a?(Nokogiri::HTML::Document)
+ pretty_printer = File.join(File.dirname(__FILE__), "pretty_print.xsl")
+ xsl = Nokogiri::XSLT(IO.read(pretty_printer))
+ # they get erased
+ top_level_attributes = []
+ elements = html.is_a?(Nokogiri::XML::NodeSet) ? html : [html]
+ puts "ELEMENTS: #{elements[0].class}"
+ elements.each do |element|
+ top_level_attributes.push(element.attributes)
+ end
+ top_level_attributes.reverse!
+ puts "??"
+ children = xsl.transform(html)
+ #.children
+ # reapply top-level attributes
+ puts "TOP ATTRIBUTES: #{top_level_attributes.inspect}"
+ children.each do |child|
+ attributes = top_level_attributes.pop
+ attributes.each do |k,v|
+ child[k] = v
+ end unless attributes.nil?
+ end
+ children.to_html.gsub(/\t/, "")
+ end
end
end
View
58 lib/googletastic/form.rb
@@ -1,7 +1,9 @@
# from http://github.com/mocra/custom_google_forms
class Googletastic::Form < Googletastic::Base
- attr_accessor :title, :body, :redirect_to, :form_key, :form_only
+ FORM_KEY_EXPRESSION = /formkey["|']\s*:["|']\s*([^"|']+)"/ unless defined?(FORM_KEY_EXPRESSION)
+
+ attr_accessor :title, :body, :redirect_to, :form_key, :form_only, :authenticity_token
def body(options = {}, &block)
@body ||= get(options, &block)
@@ -36,7 +38,11 @@ def show_url(id)
def unmarshall(xml)
records = xml.xpath("//atom:entry", ns_tag("atom")).collect do |record|
- id = record.xpath("atom:id", ns_tag("atom")).first.text.gsub("http://spreadsheets.google.com/feeds/spreadsheets/", "")
+ #id = record.xpath("atom:id", ns_tag("atom")).first.text.gsub("http://spreadsheets.google.com/feeds/spreadsheets/", "")
+ id = record.xpath("atom:link[@rel='alternate']", ns_tag("atom")).first
+ if id
+ id = id["href"].gsub("http://spreadsheets.google.com/ccc?key=", "")
+ end
title = record.xpath("atom:title", ns_tag("atom")).first.text
created_at = record.xpath("atom:published", ns_tag("atom")).text
updated_at = record.xpath("atom:updated", ns_tag("atom")).text
@@ -53,13 +59,44 @@ def unmarshall(xml)
end
- def submit(form_key, params)
- action = submit_url(form_key)
- uri = URI.parse(action)
+ def get_form_key
+ begin
+ agent = defined?(Mechanize) ? Mechanize.new : WWW::Mechanize.new
+ # google wants recent browsers!
+ # http://docs.google.com/support/bin/answer.py?answer=37560&hl=en
+ agent.user_agent = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; ru-ru) AppleWebKit/533.2+ (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10"
+ url = "http://spreadsheets.google.com/"
+ # for spreadsheet, we need the domain!
+ if Googletastic.credentials[:domain]
+ url << "a/#{Googletastic.credentials[:domain]}/"
+ end
+ url << "ccc?key=#{self.id}&hl=en&pli=1"
+ login_form = agent.get(url).forms.first
+ login_form.Email = Googletastic.credentials[:username].split("@").first # don't want emails
+ login_form.Passwd = Googletastic.credentials[:password]
+ page = agent.submit(login_form)
+ match = page.body.match(FORM_KEY_EXPRESSION)
+ if page.meta.first and (page.title == "Redirecting" || match.nil?)
+ page = page.meta.first.click
+ match = page.body.match(FORM_KEY_EXPRESSION)
+ end
+ formkey = match.captures.first if match
+ rescue Exception => e
+ puts "ERROR: #{e.to_s}"
+ nil
+ end
+ end
+
+ def submit(form_key, params, options)
+ uri = URI.parse(submit_url)
req = Net::HTTP::Post.new("#{uri.path}?#{uri.query}")
req.form_data = params
response = Net::HTTP.new(uri.host).start {|h| h.request(req)}
- response
+ if response.is_a?(Net::HTTPSuccess) || response.is_a?(GData::HTTP::Response)
+ unmarshall(Nokogiri::HTML(response.body), options).to_html
+ else
+ response.body
+ end
end
# get(:redirect => {:url => "/our-forms", :params => {:one => "hello"}})
@@ -78,16 +115,23 @@ def unmarshall(html, options, &block)
# title = html.xpath("//h1[@class='ss-form-title']").first.text
add_redirect(html, options, &block)
+ html.xpath("//textarea").each do |node|
+ node.add_child Nokogiri::XML::Text.new("\n", html)
+ end
+
if self.form_only
html.xpath("//form").first.unlink
else
html.xpath("//div[@class='ss-footer']").first.unlink
+ html.xpath("//script").each {|x| x.unlink }
html.xpath("//div[@class='ss-form-container']").first.unlink
end
end
def add_redirect(doc, options, &block)
- action = doc.xpath("//form").first["action"].to_s
+ action = doc.xpath("//form").first
+ return if action.nil?
+ action = action["action"].to_s
submit_key = action.gsub(self.submit_url, "")
form = doc.xpath("//form").first
View
1  lib/googletastic/helpers.rb
@@ -3,7 +3,6 @@ def self.included(base)
base.extend(ClassMethods)
end
-
module ClassMethods
def googletastic(model, options = {})
View
15 lib/googletastic/mixins/actions.rb
@@ -63,9 +63,7 @@ def download_url
end
def upload_url
- puts "UPLOADURL"
self.class.upload_url(self.id)
- puts "POST"
end
def save
@@ -95,17 +93,20 @@ def create_or_update
def create
if has_attachment?
- self.class.client.post_file(self.class.index_url, self.attachment_path, mime_type, self.to_xml)
+ self.class.client.post_file(self.index_url, self.attachment_path, mime_type, self.to_xml)
else
- self.class.client.post(self.class.index_url, self.to_xml)
+ self.class.client.post(self.index_url, self.to_xml)
end
end
-
+
def update(attribute_names = @attributes.keys)
if has_attachment?
- self.class.client.put_file(self.class.index_url, self.attachment_path, mime_type, self.to_xml)
+ self.class.client.put_file(self.index_url, self.attachment_path, mime_type, self.to_xml)
else
- self.class.client.put(self.edit_url || self.class.index_url, self.to_xml)
+ original_headers = self.client.headers.dup
+ self.client.headers["If-Match"] = self.etag if self.respond_to?(:etag)
+ self.class.client.put(self.edit_url || self.index_url, self.to_xml)
+ self.client.headers = original_headers
end
end
end
View
2  lib/googletastic/mixins/attributes.rb
@@ -21,7 +21,7 @@ def has_attribute?(attr_name)
def inspect
hash = ""
- attributes.each { |k,v| hash << " @#{k.to_s}=#{v.inspect}" }
+ attributes.each { |k,v| hash << " @#{k.to_s}=#{v.inspect}" unless k.to_s == "raw" }
"#<#{self.class.to_s}#{hash}/>"
end
end
View
4 lib/googletastic/mixins/namespaces.rb
@@ -12,7 +12,9 @@ module Googletastic::Mixins::Namespaces
"app" => "http://www.w3.org/2007/app",
"gCal" => "http://schemas.google.com/gCal/2005",
"gContact" => "http://schemas.google.com/contact/2008",
- "batch" => "http://schemas.google.com/gdata/batch"
+ "batch" => "http://schemas.google.com/gdata/batch",
+ "gs" => "http://schemas.google.com/spreadsheets/2006",
+ "gsx" => "http://schemas.google.com/spreadsheets/2006/extended"
} unless defined?(NAMESPACES)
def self.included(base)
View
2  lib/googletastic/mixins/requesting.rb
@@ -50,7 +50,7 @@ def extract_params(options)
options.inject({}) do |converted, (key, value)|
real_key = queries[key]
if queries.has_key?(key)
- next if self.respond_to?("valid_#{real_key}?") and !self["valid_#{real_key}?"]
+ next if self.respond_to?("valid_#{real_key}?") and !self.send("valid_#{real_key}?", value)
value = self.send("convert_#{real_key}", value) if self.respond_to?("convert_#{real_key}")
converted[real_key] = value
end
View
108 lib/googletastic/row.rb
@@ -0,0 +1,108 @@
+class Googletastic::Row < Googletastic::Base
+
+ attr_accessor :data, :worksheet_id, :spreadsheet_id, :title, :etag
+
+ def get_url
+ self.class.get_url(File.join(self.spreadsheet_id, self.worksheet_id), self.id)
+ end
+
+ def index_url
+ "http://spreadsheets.google.com/feeds/list/#{self.spreadsheet_id}/#{self.worksheet_id}/private/full"
+ end
+
+ def edit_url
+ "http://spreadsheets.google.com/feeds/list/#{self.spreadsheet_id}/#{self.worksheet_id}/private/full/#{self.id}"
+ end
+
+ # Time.now.xmlschema
+ class << self
+
+ def client_class
+ "Spreadsheets"
+ end
+
+ def index_url(path)
+ "http://spreadsheets.google.com/feeds/list/#{path}/private/full"
+ end
+
+ def show_url(path, id)
+ "http://spreadsheets.google.com/feeds/list/#{path}/private/full/#{id}"
+ end
+
+ def get_url(path, id)
+ "http://spreadsheets.google.com/feeds/list/#{path}/private/full/#{id}"
+ end
+
+ def build_url(options)
+ raise "You must specify a spreadsheet key 'key' and a 'worksheet_id' for a list of rows" unless (options[:key] and options[:worksheet_id])
+ options[:url] ||= index_url(File.join(options[:key], options[:worksheet_id]))
+ super(options)
+ end
+
+ def unmarshall(xml)
+ records = xml.xpath("//atom:entry", ns_tag("atom")).collect do |record|
+ etag = record["etag"]
+ id = record.xpath("atom:id", ns_tag("atom")).first.text
+ ids = id =~ /http:\/\/spreadsheets\.google\.com\/feeds\/list\/([^\/]+)\/([^\/]+)\/([^\/]+)/
+ spreadsheet_id = $1
+ worksheet_id = $2
+ id = $3
+ title = record.xpath("atom:title", ns_tag("atom")).first.text
+ content = record.xpath("atom:content", ns_tag("atom")).first.text
+ created_at = record.xpath("atom:published", ns_tag("atom")).text
+ updated_at = record.xpath("atom:updated", ns_tag("atom")).text
+ data = {}
+
+ record.xpath("//gsx:*", ns_tag('gsx')).each do |node|
+ next unless node.elem?
+ data[node.name.to_sym] = node.text
+ end
+
+ Googletastic::Row.new(
+ :id => id,
+ :etag => etag,
+ :title => title,
+ :spreadsheet_id => spreadsheet_id,
+ :worksheet_id => worksheet_id,
+ :data => data,
+ :updated_at => DateTime.parse(updated_at),
+ :raw => record.to_xml
+ )
+ end
+ records
+ end
+
+ # for save and update
+ def marshall(record)
+ Nokogiri::XML::Builder.new { |xml|
+ attributes = nil
+ if record.id
+ attributes = {"etag" => record.etag}.merge(ns_xml("atom", "gsx"))
+ else
+ ns_xml("atom", "gsx")
+ end
+ xml.entry(attributes) {
+ if record.id # PUT = update
+ xml.id_ {
+ xml.text record.get_url
+ }
+ #xml.updated {
+ # xml.text record.updated.to_s
+ #}
+ end
+ if record.title
+ xml.title(:type => "text") {
+ xml.text record.title
+ }
+ end
+ record.data.each do |k,v|
+ xml["gsx"].send(k) {
+ xml.text v
+ }
+ end
+ }
+ }.to_xml
+ end
+
+ end
+end
View
38 lib/googletastic/spreadsheet.rb
@@ -1,6 +1,22 @@
class Googletastic::Spreadsheet < Googletastic::Base
- attr_accessor :title, :content
+ attr_accessor :title, :content, :edit_id
+
+ def worksheet_url
+ self.class.worksheet_url(self.id)
+ end
+
+ def worksheet
+ @worksheet ||= Googletastic::Worksheet.first(:key => self.id)
+ end
+
+ def table
+ @table ||= Googletastic::Table.first(:key => self.id)
+ end
+
+ def rows
+ @rows ||= Googletastic::Row.all(:key => self.id, :worksheet_id => worksheet.id)
+ end
# Time.now.xmlschema
class << self
@@ -12,20 +28,28 @@ def client_class
def index_url
"http://spreadsheets.google.com/feeds/spreadsheets/private/full"
end
+
+ def worksheet_url(id)
+ "http://spreadsheets.google.com/feeds/worksheets/#{id}/private/full"
+ end
def unmarshall(xml)
records = xml.xpath("//atom:entry", ns_tag("atom")).collect do |record|
id = record.xpath("atom:id", ns_tag("atom")).first.text.gsub("http://spreadsheets.google.com/feeds/spreadsheets/", "")
- title = record.xpath("atom:title", ns_tag("atom")).first.text
- content = record.xpath("atom:content", ns_tag("atom")).first.text
- created_at = record.xpath("atom:published", ns_tag("atom")).text
- updated_at = record.xpath("atom:updated", ns_tag("atom")).text
-
+ edit_id = record.xpath("atom:link[@rel='alternate']", ns_tag("atom")).first
+ edit_id = edit_id["href"].gsub("http://spreadsheets.google.com/ccc?key=", "") if edit_id
+ title = record.xpath("atom:title", ns_tag("atom")).first.text
+ content = record.xpath("atom:content", ns_tag("atom")).first.text
+ created_at = record.xpath("atom:published", ns_tag("atom")).text
+ updated_at = record.xpath("atom:updated", ns_tag("atom")).text
+
Googletastic::Spreadsheet.new(
:id => id,
+ :edit_id => edit_id,
:title => title,
:content => content,
- :updated_at => DateTime.parse(updated_at)
+ :updated_at => DateTime.parse(updated_at),
+ :raw => record.to_xml
)
end
records
View
59 lib/googletastic/table.rb
@@ -0,0 +1,59 @@
+class Googletastic::Table < Googletastic::Base
+
+ attr_accessor :title, :content, :summary, :columns, :spreadsheet_id, :num_rows, :start_row
+
+ # Time.now.xmlschema
+ class << self
+
+ def client_class
+ "Spreadsheets"
+ end
+
+ def show_url(id)
+ "http://spreadsheets.google.com/feeds/#{id}/tables"
+ end
+
+ def build_url(options)
+ raise "You must specify an spreadsheet key 'key' for a table" unless options[:key]
+ options[:url] ||= show_url(options[:key])
+ puts "URL: #{options[:url]}"
+ super(options)
+ end
+
+ def unmarshall(xml)
+ records = xml.xpath("//atom:entry", ns_tag("atom")).collect do |record|
+ id = record.xpath("atom:id", ns_tag("atom")).first.text
+ spreadsheet_id = id.gsub("http://spreadsheets.google.com/feeds/([^\/]+)/tables", "\1")
+ id = id.gsub("http://spreadsheets.google.com/feeds/([^\/]+)/tables/([^\/]+)", "\2")
+ title = record.xpath("atom:title", ns_tag("atom")).first.text
+ summary = record.xpath("atom:summary", ns_tag("atom")).first.text
+ content = record.xpath("atom:content", ns_tag("atom")).first.text
+ data = record.xpath("gs:data", ns_tag("gs"))
+ num_rows = data["numRows"].to_i
+ start_row = data["startRow"].to_i
+ columns = []
+ data.xpath("gs:column", ns_tag("gs")).each do |column|
+ columns << {:name => column["name"], :index => column["index"]}
+ end
+ columns = columns.sort {|a,b| b["index"] <=> a["index"]}.collect{|c| c["name"]}
+ created_at = record.xpath("atom:published", ns_tag("atom")).text
+ updated_at = record.xpath("atom:updated", ns_tag("atom")).text
+
+ Googletastic::Table.new(
+ :id => id,
+ :spreadsheet_id => spreadsheet_id,
+ :title => title,
+ :summary => summary,
+ :content => content,
+ :start_row => start_row,
+ :num_rows => num_rows,
+ :columns => columns,
+ :updated_at => DateTime.parse(updated_at),
+ :raw => record.to_xml
+ )
+ end
+ records
+ end
+
+ end
+end
View
47 lib/googletastic/worksheet.rb
@@ -0,0 +1,47 @@
+class Googletastic::Worksheet < Googletastic::Base
+
+ attr_accessor :title, :content, :spreadsheet_id
+
+ # Time.now.xmlschema
+ class << self
+
+ def client_class
+ "Spreadsheets"
+ end
+
+ def show_url(id)
+ "http://spreadsheets.google.com/feeds/worksheets/#{id}/private/full"
+ end
+
+ def build_url(options)
+ raise "You must specify an spreadsheet key 'key' for a worksheet" unless options[:key]
+ options[:url] ||= show_url(options[:key])
+ super(options)
+ end
+
+ def unmarshall(xml)
+ records = xml.xpath("//atom:entry", ns_tag("atom")).collect do |record|
+ id = record.xpath("atom:id", ns_tag("atom")).first.text
+ ids = id =~ /http:\/\/spreadsheets\.google\.com\/feeds\/worksheets\/([^\/]+)\/([^\/]+)/
+ spreadsheet_id = $1
+ id = $2
+ title = record.xpath("atom:title", ns_tag("atom")).first.text
+ content = record.xpath("atom:content", ns_tag("atom")).first.text
+ updated_at = record.xpath("atom:updated", ns_tag("atom")).text
+
+ worksheet = Googletastic::Worksheet.new(
+ :id => id,
+ :spreadsheet_id => spreadsheet_id,
+ :title => title,
+ :content => content,
+ :updated_at => DateTime.parse(updated_at),
+ :raw => record.to_xml
+ )
+
+ worksheet
+ end
+ records
+ end
+
+ end
+end
View
2  spec/fixtures/data/doclist.xml
@@ -1,4 +1,4 @@
-?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:docs="http://schemas.google.com/docs/2007" xmlns:batch="http://schemas.google.com/gdata/batch" xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/&quot;CkACSH88eip7ImA9WxBaEUQ.&quot;">
<id>http://docs.google.com/feeds/documents/private/full</id>
<updated>2010-03-21T16:59:29.172Z</updated>
View
1  spec/googletastic/document_spec.rb
@@ -14,6 +14,7 @@
doc = Googletastic::Document.first
doc.should_not == nil
doc.title.should_not be_empty
+ puts doc.inspect
end
it "should find all documents from google docs, and they should be an array" do
View
31 spec/googletastic/form_spec.rb
@@ -8,7 +8,9 @@
describe "find" do
it "should list all spreadsheets as forms" do
-
+ Googletastic::Form.all.each do |form|
+ form.should be_an_instance_of(Googletastic::Form)
+ end
end
end
@@ -23,21 +25,22 @@
end
end
- describe "unmarshalling" do
- it "should strip the html page down to a form (unmarshall)" do
- @html = Nokogiri::HTML(IO.read(File.join(FIXTURES_DIR, "data/form.html")))
- form = Googletastic::Form.unmarshall(@html)
- form.redirect = "/forms/my-custom-id"
+ describe "mechanize" do
+ it "it should get the formkey via mechanize" do
+ form = Googletastic::Form.first
+ formkey = form.get_form_key
+ puts "FORMKEY: #{formkey}"
+ formkey.should_not be_nil
end
- end
-
- describe "redirecting" do
- it "should add generic redirect" do
- Googletastic::Form.redirect_to = "/my-generic-redirect"
- @html = Nokogiri::HTML(IO.read(File.join(FIXTURES_DIR, "data/form.html")))
- form = Googletastic::Form.unmarshall(@html)
- Nokogiri::HTML(form.body).xpath("//form").first["action"].should == "/my-generic-redirect"
+
+ it "should remove unnecessary html from form" do
+ form = Googletastic::Form.first
+ form.form_key = form.get_form_key
+ body = form.body
+ puts "BODY!: #{body.to_s}"
+ body.should_not == nil
end
end
+
end
View
22 spec/googletastic/spreadsheet_spec.rb
@@ -3,7 +3,27 @@
describe Googletastic::Spreadsheet do
it "should retrieve a list of spreadsheets" do
- puts Googletastic::Spreadsheet.all.inspect
+ Googletastic::Spreadsheet.all
+ end
+
+ it "should retrieve the records from a single spreadsheet" do
+ Googletastic::Spreadsheet.first.should be_an_instance_of(Googletastic::Spreadsheet)
+ end
+
+ it "should retrieve a spreadsheets worksheet" do
+ Googletastic::Spreadsheet.first.worksheet.should_not be_nil
+ end
+
+ it "should retrieve a table within a spreadsheet" do
+ pending
+ end
+
+ it "should retrieve a list of rows for a worksheet" do
+ rows = Googletastic::Spreadsheet.first.rows
+# rows.each do |row|
+# row.data[:firstname] = "Appleseed"
+# row.save
+# end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.