activeresource-google_spreadsheets 0.0.2 → 0.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e0556a89297114ca3f0a98c5e7b2ec582fbdcce
4
- data.tar.gz: 015504c5967d2a903225c2960866683dd3304a1f
3
+ metadata.gz: 532729ef07bce877223dd5be8b7b9ca86d2759f6
4
+ data.tar.gz: 0418b8eb8fc8bea6d0c0600bf930f0641d29340a
5
5
  SHA512:
6
- metadata.gz: 9900a1b1a1f57b07ce2eeb30e7e2ff7f092f7bb028d3900ffc6ca66e8c9600689e319cfd03d522b16c12538a8b01ec355487a25e550bd0913364d22de133908e
7
- data.tar.gz: fffb23b5aa36a4c8beb9a9935544955215b0b83a4f04fe05fea482d52cf4e28236ed1eb31266d5b1aad78008c1e1083ee55d50d53ed775536d9fa77db6890961
6
+ metadata.gz: 0382a122b75e1c62c5a85ed38e58dc35907a7db1e6cf8d43c2280d139e117972534a6f941e47a8640ea1e3eac3aad6a9ebaa62827e70734e489829ddd999f706
7
+ data.tar.gz: d5684ee8736054c9816b41bfa30b2c097d99b774774dc9f6bebdea8e71557a856aafce95ee8fa895bf94e3193e4080d63c718add570e6b47bec7e9d2043c00dd
data/README.md CHANGED
@@ -20,7 +20,11 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ http://webos-goodies.jp/archives/active_resource_google_spreadsheets_data_api.html
24
+
25
+ ### ActiveRecord Syncing Feature (Experimental)
26
+
27
+ http://qiita.com/tkawa/items/04fc6f0574122d4a3fd2
24
28
 
25
29
  ## Contributing
26
30
 
@@ -1,5 +1,5 @@
1
1
  require 'google_spreadsheets/version'
2
- require 'active_support'
2
+ require 'active_support/all'
3
3
  require 'active_resource'
4
4
  require 'time'
5
5
  require 'erb'
@@ -14,6 +14,9 @@ module GoogleSpreadsheets
14
14
  autoload :Worksheet
15
15
  autoload :List
16
16
 
17
+ autoload :Enhanced
18
+ autoload :LinkRelations
19
+
17
20
  class BaseError < StandardError
18
21
  DefaultMessage = nil
19
22
  def initialize(message=nil)
@@ -0,0 +1,10 @@
1
+ module GoogleSpreadsheets
2
+ module Enhanced
3
+ autoload :Spreadsheet, 'google_spreadsheets/enhanced/spreadsheet'
4
+ autoload :Worksheet, 'google_spreadsheets/enhanced/worksheet'
5
+ autoload :Row, 'google_spreadsheets/enhanced/row'
6
+ autoload :Collection, 'google_spreadsheets/enhanced/collection'
7
+ autoload :NamespacePreservable, 'google_spreadsheets/enhanced/namespace_preservable'
8
+ autoload :Synchronizer, 'google_spreadsheets/enhanced/synchronizer'
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ require 'ostruct'
2
+
3
+ module GoogleSpreadsheets
4
+ module Enhanced
5
+ class Collection < ActiveResource::Collection
6
+ def find(id)
7
+ if block_given?
8
+ to_a.find{|*block_args| yield(*block_args) }
9
+ else
10
+ find_by!(id: id)
11
+ end
12
+ end
13
+
14
+ def find_by(condition_hash)
15
+ to_a.find do |element|
16
+ # TODO: compare with consideration of type cast
17
+ condition_hash.all?{|attr, value| element.send(attr) == value }
18
+ end
19
+ end
20
+
21
+ def find_by!(condition_hash)
22
+ find_by(condition_hash) ||
23
+ raise(ActiveResource::ResourceNotFound.new(OpenStruct.new(message: "Couldn't find #{self.class.name} with #{condition_hash}")))
24
+ end
25
+
26
+ def where(condition_hash)
27
+ condition_hash.inject(self.to_a) do |array, (attr, value)|
28
+ array.find_all{|element| element.send(attr) == value }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,134 @@
1
+ require 'nokogiri'
2
+
3
+ module GoogleSpreadsheets
4
+ module Enhanced
5
+ module NamespacePreservable
6
+ extend ActiveSupport::Concern
7
+
8
+ class Format < GoogleSpreadsheets::GDataFormat
9
+ def decode(xml)
10
+ xml.force_encoding('UTF-8') # cf. http://d.hatena.ne.jp/kitamomonga/20101218/ruby_19_net_http_encoding
11
+ e = hash_from_xml_with_namespace(xml)
12
+ if e.has_key?('feed')
13
+ e = e['feed']['entry'] || []
14
+ (e.is_a?(Array) ? e : [e]).each{|i| format_entry(i) }
15
+ else
16
+ format_entry(e['entry'])
17
+ end
18
+ end
19
+
20
+ def encode(hash, options = {})
21
+ super(hash.select{|key, _| key.match(/^gsx:(.+)/) },
22
+ { :namespaces => { 'gsx' => 'http://schemas.google.com/spreadsheets/2006/extended' } })
23
+ end
24
+
25
+ private
26
+
27
+ # convert to Hash from XML including namespace
28
+ # https://gist.github.com/baroquebobcat/1603671
29
+ def hash_from_xml_with_namespace(xml_io)
30
+ begin
31
+ result = Nokogiri::XML(xml_io)
32
+ { result.root.name => xml_node_to_hash(result.root) }
33
+ rescue Exception => e
34
+ # raise your custom exception here
35
+ raise
36
+ end
37
+ end
38
+
39
+ def xml_node_to_hash(node)
40
+ # If we are at the root of the document, start the hash
41
+ if node.element?
42
+ result_hash = {}
43
+
44
+ node.attributes.each do |key, attr|
45
+ result_hash[attr.namespaced_name] = prepare(attr.value)
46
+ end
47
+
48
+ node.children.each do |child|
49
+ result = xml_node_to_hash(child)
50
+ if child.is_a? Nokogiri::XML::Text
51
+ unless child.next_sibling || child.previous_sibling
52
+ return prepare(result)
53
+ end
54
+ elsif result_hash[child_name = child.namespaced_name]
55
+ result_hash[child_name] = [result_hash[child_name]] unless result_hash[child_name].is_a?(Object::Array)
56
+ result_hash[child_name] << prepare(result)
57
+ else
58
+ result_hash[child_name] = prepare(result)
59
+ end
60
+ end
61
+
62
+ result_hash
63
+ else
64
+ prepare(node.content.to_s)
65
+ end
66
+ end
67
+
68
+ def prepare(data)
69
+ if data.is_a?(String) && data.to_i.to_s == data
70
+ data.to_i
71
+ elsif data == {}
72
+ ''
73
+ else
74
+ data
75
+ end
76
+ end
77
+ end
78
+
79
+ included do
80
+ class_attribute :_attr_aliases
81
+ self.format = Format.new
82
+ end
83
+
84
+ module ClassMethods
85
+ def attr_aliases(aliases)
86
+ self._attr_aliases = aliases
87
+ aliases.each do |new_attr, original_attr|
88
+ define_method(new_attr) {|*args| send(original_attr, *args) }
89
+ define_method("#{new_attr}=") {|*args| send("#{original_attr}=", *args) }
90
+ end
91
+ end
92
+ end
93
+
94
+ def aliased_attributes
95
+ aliased = _attr_aliases.invert
96
+ gsx_attributes = self.attributes.keys.map do |attr|
97
+ if matches = attr.match(/^(gsx:)/)
98
+ (aliased[matches.post_match] || matches.post_match).to_s
99
+ else
100
+ nil
101
+ end
102
+ end.compact
103
+ (self.class.known_attributes + gsx_attributes).uniq
104
+ end
105
+
106
+ def respond_to?(method, include_priv = false)
107
+ method_name = method.to_s
108
+ ((matches = method_name.match(/(=|\?)$/)) && attributes.include?("gsx:#{matches.pre_match}")) ||
109
+ attributes.include?("gsx:#{method_name}") ||
110
+ super
111
+ end
112
+
113
+ def method_missing(method_symbol, *arguments)
114
+ method_name = method_symbol.to_s
115
+
116
+ if (matches = method_name.match(/(=)$/)) && attributes.include?("gsx:#{matches.pre_match}")
117
+ attributes["gsx:#{matches.pre_match}"] = arguments.first
118
+ elsif (matches = method_name.match(/(\?)$/)) && attributes.include?("gsx:#{matches.pre_match}")
119
+ attributes["gsx:#{matches.pre_match}"]
120
+ elsif attributes.include?("gsx:#{method_name}")
121
+ attributes["gsx:#{method_name}"]
122
+ else
123
+ super
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ class Nokogiri::XML::Node
131
+ def namespaced_name
132
+ (namespace.try(:prefix).present? ? "#{namespace.prefix}:" : '') + name
133
+ end
134
+ end
@@ -0,0 +1,11 @@
1
+ module GoogleSpreadsheets
2
+ module Enhanced
3
+ class Row < GoogleSpreadsheets::List
4
+ include GoogleSpreadsheets::LinkRelations
5
+ include NamespacePreservable
6
+
7
+ self.collection_parser = Collection
8
+ self.primary_key = :'gsx:id'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module GoogleSpreadsheets
2
+ module Enhanced
3
+ class Spreadsheet < GoogleSpreadsheets::Spreadsheet
4
+ include GoogleSpreadsheets::LinkRelations
5
+ include NamespacePreservable
6
+
7
+ links_to_many :worksheets, rel: 'http://schemas.google.com/spreadsheets/2006#worksheetsfeed'
8
+ self.collection_parser = Collection
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,54 @@
1
+ module GoogleSpreadsheets
2
+ module Enhanced
3
+ module Synchronizer
4
+
5
+ # === Example
6
+ # class User < ActiveRecord::Base
7
+ # extend GoogleSpreadsheets::Enhanced::Synchronizer
8
+ # sync_with :user_rows, spreadsheet_id: 'xxxx',
9
+ # worksheet_title: 'users'
10
+ # after_commit :sync_user_row
11
+ def sync_with(rows_name, options)
12
+ options.assert_valid_keys(:spreadsheet_id, :worksheet_title, :class_name)
13
+ options[:worksheet_title] ||= rows_name.to_s
14
+ spreadsheet_class_name = LinkRelations.class_name_mappings['http://schemas.google.com/spreadsheets/2006#spreadsheet'].classify
15
+ define_singleton_method(rows_name) do
16
+ @worksheet ||= spreadsheet_class_name.constantize
17
+ .find(options[:spreadsheet_id])
18
+ .worksheets
19
+ .find_by!(title: options[:worksheet_title])
20
+ @worksheet.rows
21
+ end
22
+
23
+ # import all
24
+ define_singleton_method("sync_with_#{rows_name}") do
25
+ rows = send(rows_name)
26
+ rows.each do |row|
27
+ record = self.find_or_initialize_by(id: row.id)
28
+ row.aliased_attributes.each do |attr|
29
+ record.send("#{attr}=", row.send(attr))
30
+ end
31
+ record.instance_variable_set(:@_skip_outbound_sync, true)
32
+ record.save
33
+ record.remove_instance_variable(:@_skip_outbound_sync)
34
+ end
35
+ end
36
+
37
+ # export one
38
+ define_method("sync_#{rows_name.to_s.singularize}") do
39
+ return if @_skip_outbound_sync
40
+ row = self.class.send(rows_name).find(self.id)
41
+ if destroyed?
42
+ row.destroy
43
+ else
44
+ # TODO: separate by AttributeAssignment
45
+ self.attributes_before_type_cast.each do |attr, value|
46
+ row.send("#{attr}=", value)
47
+ end
48
+ row.save
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,11 @@
1
+ module GoogleSpreadsheets
2
+ module Enhanced
3
+ class Worksheet < GoogleSpreadsheets::Worksheet
4
+ include GoogleSpreadsheets::LinkRelations
5
+ include NamespacePreservable
6
+
7
+ links_to_many :rows, rel: 'http://schemas.google.com/spreadsheets/2006#listfeed'
8
+ self.collection_parser = Collection
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,77 @@
1
+ module GoogleSpreadsheets
2
+ module LinkRelations
3
+ extend ActiveSupport::Concern
4
+
5
+ class << self
6
+ DEFAULT_CLASS_NAME_MAPPINGS = {
7
+ 'http://schemas.google.com/spreadsheets/2006#spreadsheet' => 'GoogleSpreadsheets::Enhanced::Spreadsheet',
8
+ 'http://schemas.google.com/spreadsheets/2006#worksheetsfeed' => 'GoogleSpreadsheets::Enhanced::Worksheet',
9
+ 'http://schemas.google.com/spreadsheets/2006#listfeed' => 'GoogleSpreadsheets::Enhanced::Row'
10
+ }
11
+ def class_name_mappings
12
+ @class_name_mappings ||= DEFAULT_CLASS_NAME_MAPPINGS
13
+ end
14
+ attr_writer :class_name_mappings
15
+ end
16
+
17
+ module Builder
18
+ class LinksToMany < ActiveResource::Associations::Builder::Association
19
+ self.macro = :links_to_many
20
+ self.valid_options = [:class_name, :rel]
21
+
22
+ def build
23
+ validate_options
24
+ model.create_reflection(self.class.macro, name, options).tap do |reflection|
25
+ model.defines_links_to_many_finder_method(reflection.name, reflection.options[:rel], reflection.klass)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ module ClassMethods
32
+ def links_to_many(name, options = {})
33
+ Builder::LinksToMany.build(self, name, options)
34
+ end
35
+
36
+ def defines_links_to_many_finder_method(method_name, relation_name, association_model)
37
+ ivar_name = :"@#{method_name}"
38
+
39
+ define_method(method_name) do
40
+ if instance_variable_defined?(ivar_name)
41
+ instance_variable_get(ivar_name)
42
+ elsif attributes.include?(method_name)
43
+ attributes[method_name]
44
+ else
45
+ link = self.link.find{|l| l.rel == relation_name }
46
+ path = link.href.slice(%r|^https://spreadsheets\.google\.com(/.*)|, 1)
47
+ instance_variable_set(ivar_name, association_model.find(:all, from: path))
48
+ end
49
+ end
50
+ end
51
+
52
+ def create_reflection(macro, name, options)
53
+ # TODO: improve
54
+ if macro == :links_to_many
55
+ reflection = LinkRelationReflection.new(macro, name, options)
56
+ self.reflections = self.reflections.merge(name => reflection)
57
+ reflection
58
+ else
59
+ super
60
+ end
61
+ end
62
+ end
63
+
64
+ class LinkRelationReflection < ActiveResource::Reflection::AssociationReflection
65
+ private
66
+ def derive_class_name
67
+ if options[:class_name]
68
+ options[:class_name].to_s
69
+ elsif options[:rel]
70
+ GoogleSpreadsheets::LinkRelations.class_name_mappings.fetch(options[:rel])
71
+ else
72
+ name.to_s
73
+ end.classify
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module GoogleSpreadsheets
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeresource-google_spreadsheets
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chihiro Ito
@@ -9,62 +9,62 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-26 00:00:00.000000000 Z
12
+ date: 2014-01-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activeresource
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: activesupport
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - '>='
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - '>='
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: bundler
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ~>
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
48
  version: '1.3'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ~>
53
+ - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: '1.3'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: rake
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - '>='
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: '0'
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - '>='
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
70
  description: Google Spreadsheets accessor with ActiveResource
@@ -74,7 +74,7 @@ executables: []
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
- - .gitignore
77
+ - ".gitignore"
78
78
  - Gemfile
79
79
  - LICENSE.txt
80
80
  - README.md
@@ -84,7 +84,15 @@ files:
84
84
  - lib/google_spreadsheets.rb
85
85
  - lib/google_spreadsheets/base.rb
86
86
  - lib/google_spreadsheets/connection.rb
87
+ - lib/google_spreadsheets/enhanced.rb
88
+ - lib/google_spreadsheets/enhanced/collection.rb
89
+ - lib/google_spreadsheets/enhanced/namespace_preservable.rb
90
+ - lib/google_spreadsheets/enhanced/row.rb
91
+ - lib/google_spreadsheets/enhanced/spreadsheet.rb
92
+ - lib/google_spreadsheets/enhanced/synchronizer.rb
93
+ - lib/google_spreadsheets/enhanced/worksheet.rb
87
94
  - lib/google_spreadsheets/g_data_format.rb
95
+ - lib/google_spreadsheets/link_relations.rb
88
96
  - lib/google_spreadsheets/list.rb
89
97
  - lib/google_spreadsheets/spreadsheet.rb
90
98
  - lib/google_spreadsheets/version.rb
@@ -99,17 +107,17 @@ require_paths:
99
107
  - lib
100
108
  required_ruby_version: !ruby/object:Gem::Requirement
101
109
  requirements:
102
- - - '>='
110
+ - - ">="
103
111
  - !ruby/object:Gem::Version
104
112
  version: '0'
105
113
  required_rubygems_version: !ruby/object:Gem::Requirement
106
114
  requirements:
107
- - - '>='
115
+ - - ">="
108
116
  - !ruby/object:Gem::Version
109
117
  version: '0'
110
118
  requirements: []
111
119
  rubyforge_project:
112
- rubygems_version: 2.1.11
120
+ rubygems_version: 2.2.0
113
121
  signing_key:
114
122
  specification_version: 4
115
123
  summary: Google Spreadsheets accessor with ActiveResource