activeresource-google_spreadsheets 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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