googletastic 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. data/README.textile +47 -0
  2. data/Rakefile +103 -0
  3. data/lib/googletastic/access_rule.rb +45 -0
  4. data/lib/googletastic/album.rb +22 -0
  5. data/lib/googletastic/app_engine.rb +103 -0
  6. data/lib/googletastic/attendee.rb +7 -0
  7. data/lib/googletastic/base.rb +46 -0
  8. data/lib/googletastic/calendar.rb +60 -0
  9. data/lib/googletastic/comment.rb +3 -0
  10. data/lib/googletastic/document.rb +219 -0
  11. data/lib/googletastic/event.rb +149 -0
  12. data/lib/googletastic/ext/file.rb +219 -0
  13. data/lib/googletastic/ext/pretty_print.xsl +47 -0
  14. data/lib/googletastic/ext/xml.rb +10 -0
  15. data/lib/googletastic/ext.rb +1 -0
  16. data/lib/googletastic/form.rb +131 -0
  17. data/lib/googletastic/group.rb +44 -0
  18. data/lib/googletastic/helpers/document.rb +70 -0
  19. data/lib/googletastic/helpers/event.rb +26 -0
  20. data/lib/googletastic/helpers/form.rb +102 -0
  21. data/lib/googletastic/helpers.rb +18 -0
  22. data/lib/googletastic/image.rb +121 -0
  23. data/lib/googletastic/mixins/actions.rb +113 -0
  24. data/lib/googletastic/mixins/attributes.rb +27 -0
  25. data/lib/googletastic/mixins/finders.rb +78 -0
  26. data/lib/googletastic/mixins/namespaces.rb +42 -0
  27. data/lib/googletastic/mixins/parsing.rb +68 -0
  28. data/lib/googletastic/mixins/requesting.rb +84 -0
  29. data/lib/googletastic/mixins.rb +5 -0
  30. data/lib/googletastic/person.rb +41 -0
  31. data/lib/googletastic/spreadsheet.rb +35 -0
  32. data/lib/googletastic/sync/document.rb +120 -0
  33. data/lib/googletastic/sync/form.rb +106 -0
  34. data/lib/googletastic/sync.rb +46 -0
  35. data/lib/googletastic/thumbnail.rb +7 -0
  36. data/lib/googletastic/youtube.rb +25 -0
  37. data/lib/googletastic.rb +115 -0
  38. data/spec/benchmarks/document_benchmark.rb +40 -0
  39. data/spec/config.yml +6 -0
  40. data/spec/fixtures/data/Doing business in the eMarketPlace.doc +0 -0
  41. data/spec/fixtures/data/basic.txt +1 -0
  42. data/spec/fixtures/data/calendar.list.xml +64 -0
  43. data/spec/fixtures/data/doc_as_html.html +3097 -0
  44. data/spec/fixtures/data/doc_as_html_html.html +0 -0
  45. data/spec/fixtures/data/doclist.xml +76 -0
  46. data/spec/fixtures/data/document.single.xml +30 -0
  47. data/spec/fixtures/data/end.xml +446 -0
  48. data/spec/fixtures/data/event.list.xml +62 -0
  49. data/spec/fixtures/data/form.html +66 -0
  50. data/spec/fixtures/data/group.list.xml +58 -0
  51. data/spec/fixtures/data/person.list.xml +53 -0
  52. data/spec/fixtures/data/photo.list.xml +111 -0
  53. data/spec/fixtures/data/sample_upload.mp4 +0 -0
  54. data/spec/fixtures/data/spreadsheet.list.xml +43 -0
  55. data/spec/fixtures/models/document.rb +7 -0
  56. data/spec/fixtures/models/event.rb +3 -0
  57. data/spec/fixtures/models/form.rb +6 -0
  58. data/spec/fixtures/models/test_model.rb +3 -0
  59. data/spec/fixtures/results/test.txt +185 -0
  60. data/spec/googletastic/access_rule_spec.rb +13 -0
  61. data/spec/googletastic/album_spec.rb +9 -0
  62. data/spec/googletastic/app_engine_spec.rb +12 -0
  63. data/spec/googletastic/base_spec.rb +49 -0
  64. data/spec/googletastic/calendar_spec.rb +11 -0
  65. data/spec/googletastic/document_spec.rb +163 -0
  66. data/spec/googletastic/event_spec.rb +34 -0
  67. data/spec/googletastic/form_spec.rb +43 -0
  68. data/spec/googletastic/group_spec.rb +9 -0
  69. data/spec/googletastic/image_spec.rb +9 -0
  70. data/spec/googletastic/person_spec.rb +9 -0
  71. data/spec/googletastic/post_spec.rb +46 -0
  72. data/spec/googletastic/spreadsheet_spec.rb +9 -0
  73. data/spec/googletastic/youtube_spec.rb +58 -0
  74. data/spec/spec.opts +1 -0
  75. data/spec/spec_helper.rb +25 -0
  76. metadata +187 -0
@@ -0,0 +1,26 @@
1
+ module Googletastic::Helpers::EventModelHelper
2
+
3
+ def self.included(base, &block)
4
+ base.extend ClassMethods
5
+ base.class_eval do
6
+ include InstanceMethods
7
+ end
8
+ end
9
+
10
+ module InstanceMethods
11
+ attr_accessor :google_doc
12
+
13
+ def hello
14
+ # puts _googletastic_options.inspect + " OPTIONS!"
15
+ end
16
+
17
+ def google_doc
18
+ @google_doc ||= Googletastic::DocList.find(self.remote_id)
19
+ @google_doc
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+
25
+ end
26
+ end
@@ -0,0 +1,102 @@
1
+ # was Googletastic::Helpers::Form, but rails through fits with namespacing problems
2
+ module Googletastic::Helpers::FormModelHelper
3
+
4
+ # REQUIREMENTS:
5
+ # DEFINE 'formkey' property on model
6
+
7
+ # class options for Form:
8
+ # as: property name for the googletastic form
9
+ # foreign_key: foreign key to reference it, defaults to "as"_id
10
+ # sync: the properties you want to sync with the form
11
+ # redirect_to: where to redirect the forms submission
12
+ # form_only: don't include title and header that google gives you (defaults to false)
13
+ def self.included(base)
14
+ # defaults
15
+ options = Googletastic[base]
16
+ options[:as] ||= "google_form"
17
+ options[:foreign_key] ||= "#{options[:as]}_id"
18
+ options[:form_key] ||= "form_key"
19
+ options[:form_only] = false unless options.has_key?(:form_only)
20
+ if options.has_key?(:sync)
21
+ options[:sync] = case options[:sync].class.to_s
22
+ when "Symbol"
23
+ {options[:sync] => options[:sync]}
24
+ when "String"
25
+ {options[:sync].to_sym => options[:sync].to_sym}
26
+ when "Array"
27
+ options[:sync].collect { |v| {v.to_sym => v.to_sym} }
28
+ else
29
+ options[:sync].symbolize_keys
30
+ end
31
+ end
32
+
33
+ # fast access
34
+ as = options[:as]
35
+ foreign_key = options[:foreign_key]
36
+ sync = options[:sync]
37
+ form_key = options[:form_key]
38
+
39
+ # eval
40
+ base.class_eval <<-end_eval, __FILE__, __LINE__
41
+ attr_accessor :#{as}
42
+ attr_accessor :content
43
+
44
+ def self.find_with_#{as}(*args)
45
+ google_records = Googletastic::Form.all
46
+ foreign_keys = google_records.collect { |record| record.id }
47
+ records = find_all_by_#{foreign_key}(foreign_keys) || []
48
+ record_keys = records.collect { |record| record.#{foreign_key} }
49
+ google_records.each do |google_record|
50
+ if !record_keys.include?(google_record.id)
51
+ record = self.new(
52
+ :#{foreign_key} => google_record.id,
53
+ :updated_at => google_record.updated_at,
54
+ :#{as} => google_record,
55
+ :title => google_record.title
56
+ )
57
+ record.save
58
+ records << record
59
+ end
60
+ end
61
+
62
+ records.each do |record|
63
+ record.#{as} = google_records.select { |r| r.id == record.#{foreign_key} }.first
64
+ end
65
+ records
66
+ end
67
+
68
+ # get form content
69
+ def get
70
+ self.#{as}.form_key ||= self.#{form_key}
71
+ self.#{as}.get
72
+ end
73
+
74
+ if base.is_a?(ActiveRecord::Base)
75
+
76
+ before_validation :clean_form_key
77
+ validates_presence_of :#{as}
78
+ validates_uniqueness_of :#{as}
79
+ validate :validate_formkey_is_valid
80
+ before_save :sync_with_google
81
+
82
+ def sync_with_google
83
+ Hash(#{sync}).each do |mine, theirs|
84
+ self[mine] = self.#{as}[theirs]
85
+ end if Googletastic[self].has_key?(:sync)
86
+ end
87
+
88
+ def validate_form_key_is_valid
89
+ case self.#{as}.get
90
+ when Net::HTTPSuccess
91
+ true
92
+ else
93
+ errors.add(:form_key, "is not a valid Google Forms key or URL or error connecting to Google")
94
+ false
95
+ end
96
+ end
97
+
98
+ end
99
+ end_eval
100
+ end
101
+
102
+ end
@@ -0,0 +1,18 @@
1
+ module Googletastic::Helpers
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+
7
+ module ClassMethods
8
+
9
+ def googletastic(model, options = {})
10
+ Googletastic.options_for(self, options)
11
+
12
+ include ("Googletastic::Helpers::#{model.to_s.camelize}ModelHelper").constantize
13
+ end
14
+
15
+ end
16
+ end
17
+
18
+ require_local "helpers/*", __FILE__
@@ -0,0 +1,121 @@
1
+ class Googletastic::Image < Googletastic::Base
2
+
3
+ attr_accessor :url, :width, :height, :size, :thumbnails, :title, :summary, :content_type
4
+ attr_accessor :album_id, :access, :commentable, :id, :created_at, :updated_at, :kind
5
+
6
+ class << self
7
+
8
+ # http://code.google.com/apis/picasaweb/docs/2.0/reference.html#Parameters
9
+ def valid_queries
10
+ {
11
+ :access => "access",
12
+ :geo_coordinates => "bbox",
13
+ :geo_location => "l",
14
+ :image_max_size => "imgmax",
15
+ :thumb_size => "thumbsize",
16
+ :kind => "kind",
17
+ :tag => "tag",
18
+ }.merge(super)
19
+ end
20
+
21
+ def valid_access?(value)
22
+ %w(all private public visible).include?(value)
23
+ end
24
+
25
+ def valid_image_max_size?(value)
26
+ [94, 110, 128, 200, 220, 288, 320, 400, 512, 576, 640, 720, 800, 912, 1024, 1152, 1280, 1440, 1600].include?(value)
27
+ end
28
+
29
+ def valid_kind?(value)
30
+ %w(album photo comment tag user).include?(value)
31
+ end
32
+
33
+ def client_class
34
+ "Photos"
35
+ end
36
+
37
+ def index_url
38
+ "http://picasaweb.google.com/data/feed/api/user/#{Googletastic.credentials[:username]}"
39
+ end
40
+
41
+ def build_url(options)
42
+ base = options.has_key?(:url) ? options[:url] : self.index_url
43
+ options[:url] = base
44
+ options[:kind] = "photo" unless options.has_key?(:kind)
45
+ options[:access] ||= "all"
46
+ #options[:image_max_size] = 720 unless options.has_key?(:image_max_size)
47
+ super(options)
48
+ end
49
+
50
+ def unmarshall(xml)
51
+ records = xml.xpath("//atom:entry", ns_tag("atom")).collect do |record|
52
+ # thumbnails
53
+ thumbnails = record.xpath("media:group/media:thumbnail").collect do |thumbnail|
54
+ url = thumbnail["url"]
55
+ width = thumbnail["width"].to_i
56
+ height = thumbnail["height"].to_i
57
+ Googletastic::Thumbnail.new(
58
+ :url => url,
59
+ :width => width,
60
+ :height => height
61
+ )
62
+ end
63
+
64
+ id = record.xpath("atom:id", ns_tag("atom")).first.text
65
+ created_at = record.xpath("atom:published", ns_tag("atom")).first.text
66
+ updated_at = record.xpath("atom:updated", ns_tag("atom")).first.text
67
+ kind = "photo"
68
+ title = record.xpath("atom:title", ns_tag("atom")).first.text
69
+ summary = record.xpath("atom:summary", ns_tag("atom")).first.text
70
+
71
+ album_id = record.xpath("gphoto:albumid", ns_tag("gphoto")).first.text
72
+ access = record.xpath("gphoto:access", ns_tag("gphoto")).first.text
73
+ width = record.xpath("gphoto:width", ns_tag("gphoto")).first.text.to_i
74
+ height = record.xpath("gphoto:height", ns_tag("gphoto")).first.text.to_i
75
+ size = record.xpath("gphoto:size", ns_tag("gphoto")).first.text.to_i
76
+
77
+ commentable = record.xpath("gphoto:commentingEnabled", ns_tag("gphoto")).first.text == "true" ? true : false
78
+
79
+ content = record.xpath("media:group/media:content").first
80
+ url = content["url"].to_s
81
+ content_type = content["type"].to_s
82
+
83
+ Googletastic::Image.new(
84
+ :id => id,
85
+ :created_at => created_at,
86
+ :kind => kind,
87
+ :title => title,
88
+ :summary => summary,
89
+ :album_id => album_id,
90
+ :access => access,
91
+ :width => width,
92
+ :height => height,
93
+ :size => size,
94
+ :commentable => commentable,
95
+ :url => url,
96
+ :content_type => content_type,
97
+ :thumbnails => thumbnails
98
+ )
99
+ end
100
+ records
101
+ end
102
+
103
+ # not implemented
104
+ def marshall(record)
105
+ Nokogiri::XML::Builder.new { |xml|
106
+ xml.entry('xmlns' => Googletastic::ATOM_NS, 'xmlns:docs' => ns("docs")) {
107
+ if record.id
108
+ xml.id {
109
+ xml.text show_url(record.id)
110
+ }
111
+ end
112
+ xml.title {
113
+ xml.text record.title
114
+ }
115
+ }
116
+ }.to_xml
117
+ end
118
+
119
+ end
120
+
121
+ end
@@ -0,0 +1,113 @@
1
+ module Googletastic::Mixins::Actions
2
+ include_class_and_instance_modules
3
+
4
+ module ClassMethods
5
+
6
+ # see the data live on google docs
7
+ def show_url(id)
8
+ raise "Implement in Sublass"
9
+ end
10
+
11
+ # edit the data on google docs
12
+ def edit_url(id)
13
+ raise "Implement in Subclass"
14
+ end
15
+
16
+ # update the data via xml
17
+ def update_url(id)
18
+ raise "Implement in Subclass"
19
+ end
20
+
21
+ # xml feed
22
+ def index_url(ids = nil)
23
+ raise "Implement in Subclass"
24
+ end
25
+
26
+ # xml entry feed
27
+ def get_url(id)
28
+ raise "Implement 'get' in subclass"
29
+ end
30
+
31
+ def upload_url(id = nil)
32
+ raise "Implement in Subclass"
33
+ end
34
+
35
+ def download_url(id)
36
+ raise "Implement in Subclass"
37
+ end
38
+ end
39
+
40
+ module InstanceMethods
41
+ def show_url
42
+ self.class.show_url(self.id)
43
+ end
44
+
45
+ def edit_url
46
+ self.class.edit_url(self.id)
47
+ end
48
+
49
+ def index_url(ids = nil)
50
+ self.class.index_url(ids)
51
+ end
52
+
53
+ def get_url
54
+ self.class.get_url(self.id)
55
+ end
56
+
57
+ def update_url
58
+ self.class.update_url(self.id)
59
+ end
60
+
61
+ def download_url
62
+ self.class.download_url(self.id)
63
+ end
64
+
65
+ def upload_url
66
+ puts "UPLOADURL"
67
+ self.class.upload_url(self.id)
68
+ puts "POST"
69
+ end
70
+
71
+ def save
72
+ create_or_update
73
+ end
74
+
75
+ def destroy
76
+
77
+ end
78
+
79
+ def clone
80
+
81
+ end
82
+
83
+ def reload(options = nil)
84
+ end
85
+
86
+ def new_record?
87
+ self.id.nil?
88
+ end
89
+
90
+ private
91
+ def create_or_update
92
+ result = new_record? ? create : update
93
+ result != false
94
+ end
95
+
96
+ def create
97
+ if has_attachment?
98
+ self.class.client.post_file(self.class.index_url, self.attachment_path, mime_type, self.to_xml)
99
+ else
100
+ self.class.client.post(self.class.index_url, self.to_xml)
101
+ end
102
+ end
103
+
104
+ def update(attribute_names = @attributes.keys)
105
+ if has_attachment?
106
+ self.class.client.put_file(self.class.index_url, self.attachment_path, mime_type, self.to_xml)
107
+ else
108
+ self.class.client.put(self.edit_url || self.class.index_url, self.to_xml)
109
+ end
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,27 @@
1
+ module Googletastic::Mixins::Attributes
2
+ attr_accessor :attributes
3
+
4
+ def attributes=(value)
5
+ return if value.nil?
6
+ attributes = value.dup
7
+ attributes.stringify_keys!
8
+ @attributes = attributes
9
+ attributes.each do |k, v|
10
+ respond_to?(:"#{k}=") ? send(:"#{k}=", v) : raise("unknown attribute: #{k}")
11
+ end
12
+ end
13
+
14
+ def attribute_names
15
+ @attributes.keys.sort
16
+ end
17
+
18
+ def has_attribute?(attr_name)
19
+ @attributes.has_key?(attr_name.to_s)
20
+ end
21
+
22
+ def inspect
23
+ hash = ""
24
+ attributes.each { |k,v| hash << " @#{k.to_s}=#{v.inspect}" }
25
+ "#<#{self.class.to_s}#{hash}/>"
26
+ end
27
+ end
@@ -0,0 +1,78 @@
1
+ module Googletastic::Mixins::Finders
2
+
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def first(*args)
9
+ find(:first, *args)
10
+ end
11
+
12
+ def last(*args)
13
+ find(:last, *args)
14
+ end
15
+
16
+ def all(*args)
17
+ find(:all, *args)
18
+ end
19
+
20
+ def find(*args)
21
+ options = args.extract_options!
22
+
23
+ case args.first
24
+ when :first then find_initial(options)
25
+ when :last then find_last(options)
26
+ when :all then find_every(options)
27
+ else find_from_ids(args, options)
28
+ end
29
+ end
30
+
31
+ def find_initial(options)
32
+ find_by_api(options.merge({:limit => 1})).first
33
+ end
34
+
35
+ def find_last(options)
36
+
37
+ end
38
+
39
+ def find_every(options)
40
+ find_by_api(options)
41
+ end
42
+
43
+ def find_from_ids(ids, options)
44
+ expects_array = ids.first.kind_of?(Array)
45
+ return ids.first if expects_array && ids.first.empty?
46
+
47
+ ids = ids.flatten.compact.uniq
48
+
49
+ case ids.size
50
+ when 0
51
+ raise "Couldn't find #{self.to_s} without an ID"
52
+ when 1
53
+ result = find_one(ids.first, options)
54
+ expects_array ? [ result ] : result
55
+ else
56
+ find_some(ids, options)
57
+ end
58
+ end
59
+
60
+ def find_one(id, options)
61
+ options[:id] = id
62
+ find_by_api(options).first
63
+ end
64
+
65
+ def find_some(ids, options)
66
+
67
+ end
68
+
69
+ def find_by_api(options)
70
+ url = build_url(options)
71
+ agent = options.has_key?(:client) ? options[:client] : client
72
+ data = agent.get(url)
73
+ return data if options.has_key?(:raw) and options[:raw] == true
74
+ records = unmarshall(Nokogiri::XML(data.body)).collect {|r| r.response = data; r}
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,42 @@
1
+ module Googletastic::Mixins::Namespaces
2
+
3
+ NAMESPACES = {
4
+ "gphoto" => "http://schemas.google.com/photos/2007",
5
+ "media" => "http://search.yahoo.com/mrss",
6
+ "openSearch" => "http://a9.com/-/spec/opensearchrss/1.0/",
7
+ "docs" => "http://schemas.google.com/docs/2007",
8
+ "atom" => "http://www.w3.org/2005/Atom",
9
+ "gd" => "http://schemas.google.com/g/2005",
10
+ "gAcl" => "http://schemas.google.com/acl/2007",
11
+ "exif" => "http://schemas.google.com/photos/exif/2007",
12
+ "app" => "http://www.w3.org/2007/app",
13
+ "gCal" => "http://schemas.google.com/gCal/2005",
14
+ "gContact" => "http://schemas.google.com/contact/2008",
15
+ "batch" => "http://schemas.google.com/gdata/batch"
16
+ } unless defined?(NAMESPACES)
17
+
18
+ def self.included(base)
19
+ base.extend ClassMethods
20
+ end
21
+
22
+ module ClassMethods
23
+ def ns(name)
24
+ NAMESPACES[name]
25
+ end
26
+
27
+ def ns_tag(name)
28
+ {name => ns(name)}
29
+ end
30
+
31
+ def ns_xml(*names)
32
+ first = names[0]
33
+ names.inject({}) do |hash, name|
34
+ xmlns = "xmlns"
35
+ xmlns << ":#{name}" unless name == first
36
+ hash[xmlns] = ns(name)
37
+ hash
38
+ end
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,68 @@
1
+ module Googletastic::Mixins::Parsing
2
+
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ base.class_eval do
6
+ include InstanceMethods
7
+
8
+ # if you want to hook into these processes easily,
9
+ # without having to override/copy-paste/alias-method
10
+ # they're placed at convenient locations
11
+ # define them as a block
12
+ # base.define_callbacks :before_unmarshall, :during_unmarshall, :after_unmarshall
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ # cached nokogiri xml, false by default
19
+ attr_accessor :cache_parsed
20
+
21
+ def cache_parsed?
22
+ @cache_parsed == true
23
+ end
24
+
25
+ # cache xml as string?
26
+ attr_accessor :cache_result
27
+
28
+ def cache_result?
29
+ @cache_result == true
30
+ end
31
+
32
+ # implement in subclasses
33
+ def unmarshall(xml_records)
34
+ raise "Implemnent in subclasses"
35
+ end
36
+
37
+ # implement in subclasses
38
+ def marshall(records)
39
+ raise "Implemnent in subclasses"
40
+ end
41
+ end
42
+
43
+ module InstanceMethods
44
+ # cached nokogiri xml, false by default
45
+ attr_accessor :cache_parsed
46
+
47
+ def cache_parsed?
48
+ @cache_parsed != false || self.class.cache_result?
49
+ end
50
+
51
+ # cache xml as string?
52
+ attr_accessor :cache_result
53
+
54
+ def cache_result?
55
+ @cache_result != false || self.class.cache_result?
56
+ end
57
+
58
+ def from_xml(xml)
59
+ self.class.unmarshall(xml)
60
+ end
61
+
62
+ def after_parse(parsed)
63
+
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,84 @@
1
+ module Googletastic::Mixins::Requesting
2
+
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ base.class_eval do
6
+ include InstanceMethods
7
+ end
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ def valid_queries
13
+ {
14
+ :limit => "max-result",
15
+ :offset => "start-index",
16
+ :start => "start-index",
17
+ :end => "end-index",
18
+ :categories => "category",
19
+ :with => "q"
20
+ # :only => "fields", # only the fields we want!
21
+ # :fields => "fields"
22
+ }
23
+ end
24
+
25
+ def urlify(url, params = {})
26
+ if params && !params.empty?
27
+ query = params.collect do |k,v|
28
+ v = v.to_json if %w{key startkey endkey}.include?(k.to_s)
29
+ "#{k}=#{CGI.escape(v.to_s)}"
30
+ end.join("&")
31
+ url = "#{url}?#{query}"
32
+ end
33
+ url
34
+ end
35
+
36
+ # helper method for google client
37
+ def client(name = self.client_class)
38
+ Googletastic.client_for(name.to_s.underscore)
39
+ end
40
+
41
+ def build_url(options)
42
+ base = options.has_key?(:url) ? options[:url] : self.index_url
43
+ options[:url] = base
44
+ urlify(base, extract_params(options))
45
+ end
46
+
47
+ # http://code.google.com/apis/gdata/docs/2.0/reference.html#Queries
48
+ def extract_params(options)
49
+ queries = self.valid_queries
50
+ options.inject({}) do |converted, (key, value)|
51
+ real_key = queries[key]
52
+ if queries.has_key?(key)
53
+ next if self.respond_to?("valid_#{real_key}?") and !self["valid_#{real_key}?"]
54
+ value = self.send("convert_#{real_key}", value) if self.respond_to?("convert_#{real_key}")
55
+ converted[real_key] = value
56
+ end
57
+ converted
58
+ end
59
+ end
60
+
61
+ # http://code.google.com/apis/gdata/docs/2.0/reference.html#PartialResponse
62
+ # link,entry(@gd:etag,id,updated,link[@rel='edit']))
63
+ # fields=entry[author/name='Lance']
64
+ def convert_fields(value)
65
+ value
66
+ end
67
+ end
68
+
69
+ module InstanceMethods
70
+
71
+ def has_attachment?
72
+ !self.attachment_path.nil?
73
+ end
74
+
75
+ def client
76
+ self.class.client
77
+ end
78
+
79
+ def mime_type
80
+ return "" if has_attachment?
81
+ return "" #TODO
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,5 @@
1
+ module Googletastic::Mixins
2
+
3
+ end
4
+
5
+ require_local "mixins/*", __FILE__