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 +4 -4
- data/README.md +5 -1
- data/lib/google_spreadsheets.rb +4 -1
- data/lib/google_spreadsheets/enhanced.rb +10 -0
- data/lib/google_spreadsheets/enhanced/collection.rb +33 -0
- data/lib/google_spreadsheets/enhanced/namespace_preservable.rb +134 -0
- data/lib/google_spreadsheets/enhanced/row.rb +11 -0
- data/lib/google_spreadsheets/enhanced/spreadsheet.rb +11 -0
- data/lib/google_spreadsheets/enhanced/synchronizer.rb +54 -0
- data/lib/google_spreadsheets/enhanced/worksheet.rb +11 -0
- data/lib/google_spreadsheets/link_relations.rb +77 -0
- data/lib/google_spreadsheets/version.rb +1 -1
- metadata +22 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 532729ef07bce877223dd5be8b7b9ca86d2759f6
|
4
|
+
data.tar.gz: 0418b8eb8fc8bea6d0c0600bf930f0641d29340a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
|
data/lib/google_spreadsheets.rb
CHANGED
@@ -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 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
|
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.
|
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:
|
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.
|
120
|
+
rubygems_version: 2.2.0
|
113
121
|
signing_key:
|
114
122
|
specification_version: 4
|
115
123
|
summary: Google Spreadsheets accessor with ActiveResource
|