google_drive2 3.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +136 -0
- data/lib/google_drive/access_token_credentials.rb +19 -0
- data/lib/google_drive/acl.rb +111 -0
- data/lib/google_drive/acl_entry.rb +181 -0
- data/lib/google_drive/api_client_fetcher.rb +59 -0
- data/lib/google_drive/authentication_error.rb +10 -0
- data/lib/google_drive/collection.rb +207 -0
- data/lib/google_drive/config.rb +36 -0
- data/lib/google_drive/error.rb +8 -0
- data/lib/google_drive/file.rb +266 -0
- data/lib/google_drive/list.rb +125 -0
- data/lib/google_drive/list_row.rb +89 -0
- data/lib/google_drive/response_code_error.rb +23 -0
- data/lib/google_drive/session.rb +733 -0
- data/lib/google_drive/spreadsheet.rb +135 -0
- data/lib/google_drive/util.rb +243 -0
- data/lib/google_drive/worksheet.rb +770 -0
- data/lib/google_drive.rb +35 -0
- metadata +196 -0
@@ -0,0 +1,207 @@
|
|
1
|
+
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
|
+
# The license of this source is "New BSD Licence"
|
3
|
+
|
4
|
+
require 'google_drive/util'
|
5
|
+
require 'google_drive/error'
|
6
|
+
require 'google_drive/spreadsheet'
|
7
|
+
|
8
|
+
module GoogleDrive
|
9
|
+
# Represents a folder in Google Drive.
|
10
|
+
#
|
11
|
+
# Use GoogleDrive::Session#root_collection,
|
12
|
+
# GoogleDrive::Collection#subcollections,
|
13
|
+
# or GoogleDrive::Session#collection_by_url to get GoogleDrive::Collection
|
14
|
+
# object.
|
15
|
+
class Collection < GoogleDrive::File
|
16
|
+
include(Util)
|
17
|
+
|
18
|
+
alias collection_feed_url document_feed_url
|
19
|
+
|
20
|
+
# Adds the given GoogleDrive::File to the folder.
|
21
|
+
def add(file)
|
22
|
+
@session.drive_service.update_file(
|
23
|
+
file.id, add_parents: id, fields: '', supports_all_drives: true
|
24
|
+
)
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Removes the given GoogleDrive::File from the folder.
|
29
|
+
def remove(file)
|
30
|
+
@session.drive_service.update_file(
|
31
|
+
file.id, remove_parents: id, fields: '', supports_all_drives: true
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates a sub-folder with given title in this folder.
|
36
|
+
# Returns GoogleDrive::Collection object.
|
37
|
+
def create_subcollection(title, file_properties = {})
|
38
|
+
create_file(title, file_properties.merge(mime_type: 'application/vnd.google-apps.folder'))
|
39
|
+
end
|
40
|
+
|
41
|
+
alias create_subfolder create_subcollection
|
42
|
+
|
43
|
+
# Creates a spreadsheet with given title in this folder.
|
44
|
+
# Returns GoogleDrive::Spreadsheet object.
|
45
|
+
def create_spreadsheet(title, file_properties = {})
|
46
|
+
create_file(title, file_properties.merge(mime_type: 'application/vnd.google-apps.spreadsheet'))
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates a file with given title and properties in this folder.
|
50
|
+
# Returns objects with the following types:
|
51
|
+
# GoogleDrive::Spreadsheet, GoogleDrive::File, GoogleDrive::Collection
|
52
|
+
#
|
53
|
+
# You can pass a MIME Type using the file_properties-function parameter,
|
54
|
+
# for example: create_file('Document Title', mime_type: 'application/vnd.google-apps.document')
|
55
|
+
#
|
56
|
+
# A list of available Drive MIME Types can be found here:
|
57
|
+
# https://developers.google.com/drive/v3/web/mime-types
|
58
|
+
def create_file(title, file_properties = {})
|
59
|
+
file_metadata = {
|
60
|
+
name: title,
|
61
|
+
parents: [id]
|
62
|
+
}.merge(file_properties)
|
63
|
+
|
64
|
+
file = @session.drive_service.create_file(
|
65
|
+
file_metadata, fields: '*', supports_all_drives: true
|
66
|
+
)
|
67
|
+
|
68
|
+
@session.wrap_api_file(file)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns true if this is a root folder.
|
72
|
+
def root?
|
73
|
+
!api_file.parents || api_file.parents.empty?
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns all the files (including spreadsheets, documents, subfolders) in
|
77
|
+
# the folder. You can specify parameters documented at
|
78
|
+
# https://developers.google.com/drive/v3/web/search-parameters
|
79
|
+
#
|
80
|
+
# e.g.
|
81
|
+
#
|
82
|
+
# # Gets all the files in the folder, including subfolders.
|
83
|
+
# collection.files
|
84
|
+
#
|
85
|
+
# # Gets only files with title "hoge".
|
86
|
+
# collection.files(q: "name = 'hoge'")
|
87
|
+
#
|
88
|
+
# # Same as above with a placeholder.
|
89
|
+
# collection.files(q: ["name = ?", "hoge"])
|
90
|
+
#
|
91
|
+
# By default, it returns the first 100 files. See document of
|
92
|
+
# GoogleDrive::Session#files method for how to get all files.
|
93
|
+
def files(params = {}, &block)
|
94
|
+
files_with_type(nil, params, &block)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Uploads a file to this folder. See Session#upload_from_file for details.
|
98
|
+
def upload_from_file(path, title = nil, params = {})
|
99
|
+
params = { parents: [id] }.merge(params)
|
100
|
+
@session.upload_from_file(path, title, params)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Uploads a file to this folder. See Session#upload_from_io for details.
|
104
|
+
def upload_from_io(io, title = 'Untitled', params = {})
|
105
|
+
params = { parents: [id] }.merge(params)
|
106
|
+
@session.upload_from_io(io, title, params)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Uploads a file to this folder. See Session#upload_from_string for details.
|
110
|
+
def upload_from_string(content, title = 'Untitled', params = {})
|
111
|
+
params = { parents: [id] }.merge(params)
|
112
|
+
@session.upload_from_string(content, title, params)
|
113
|
+
end
|
114
|
+
|
115
|
+
alias contents files
|
116
|
+
|
117
|
+
# Returns all the spreadsheets in the folder.
|
118
|
+
#
|
119
|
+
# By default, it returns the first 100 spreadsheets. See document of
|
120
|
+
# GoogleDrive::Session#files method for how to get all spreadsheets.
|
121
|
+
def spreadsheets(params = {}, &block)
|
122
|
+
files_with_type('application/vnd.google-apps.spreadsheet', params, &block)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns all the Google Docs documents in the folder.
|
126
|
+
#
|
127
|
+
# By default, it returns the first 100 documents. See document of
|
128
|
+
# GoogleDrive::Session#files method for how to get all documents.
|
129
|
+
def documents(params = {}, &block)
|
130
|
+
files_with_type('application/vnd.google-apps.document', params, &block)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns all its subfolders.
|
134
|
+
#
|
135
|
+
# By default, it returns the first 100 subfolders. See document of
|
136
|
+
# GoogleDrive::Session#files method for how to get all subfolders.
|
137
|
+
def subcollections(params = {}, &block)
|
138
|
+
files_with_type('application/vnd.google-apps.folder', params, &block)
|
139
|
+
end
|
140
|
+
|
141
|
+
alias subfolders subcollections
|
142
|
+
|
143
|
+
# Returns a file (can be a spreadsheet, document, subfolder or other files)
|
144
|
+
# in the folder which exactly matches +title+ as GoogleDrive::File.
|
145
|
+
# Returns nil if not found. If multiple folders with the +title+ are found,
|
146
|
+
# returns one of them.
|
147
|
+
#
|
148
|
+
# If given an Array, does a recursive subfolder traversal.
|
149
|
+
def file_by_title(title)
|
150
|
+
file_by_title_with_type(title, nil)
|
151
|
+
end
|
152
|
+
|
153
|
+
alias file_by_name file_by_title
|
154
|
+
|
155
|
+
# Returns its subfolder whose title exactly matches +title+ as
|
156
|
+
# GoogleDrive::Collection.
|
157
|
+
# Returns nil if not found. If multiple folders with the +title+ are found,
|
158
|
+
# returns one of them.
|
159
|
+
#
|
160
|
+
# If given an Array, does a recursive subfolder traversal.
|
161
|
+
def subcollection_by_title(title)
|
162
|
+
file_by_title_with_type(title, 'application/vnd.google-apps.folder')
|
163
|
+
end
|
164
|
+
|
165
|
+
alias subfolder_by_name subcollection_by_title
|
166
|
+
|
167
|
+
# Returns URL of the deprecated contents feed.
|
168
|
+
def contents_url
|
169
|
+
document_feed_url + '/contents'
|
170
|
+
end
|
171
|
+
|
172
|
+
protected
|
173
|
+
|
174
|
+
def file_by_title_with_type(title, type)
|
175
|
+
if title.is_a?(Array)
|
176
|
+
rel_path = title
|
177
|
+
if rel_path.empty?
|
178
|
+
return self
|
179
|
+
else
|
180
|
+
parent = subcollection_by_title(rel_path[0...-1])
|
181
|
+
return parent && parent.file_by_title_with_type(rel_path[-1], type)
|
182
|
+
end
|
183
|
+
else
|
184
|
+
files_with_type(type, q: ['name = ?', title], page_size: 1)[0]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
alias file_by_name_with_type file_by_title_with_type
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
def files_with_type(type, params = {}, &block)
|
193
|
+
params = convert_params(params)
|
194
|
+
query = construct_and_query([
|
195
|
+
['? in parents', id],
|
196
|
+
type ? ['mimeType = ?', type] : nil,
|
197
|
+
params[:q]
|
198
|
+
])
|
199
|
+
params = params.merge(q: query)
|
200
|
+
# This is faster than calling children.list and then files.get for each
|
201
|
+
# file.
|
202
|
+
@session.files(params, &block)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
Folder = Collection
|
207
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Author: Mateusz Czerwinski <mtczerwinski@gmail.com>
|
2
|
+
# The license of this source is "New BSD Licence"
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module GoogleDrive
|
7
|
+
# @api private
|
8
|
+
class Config
|
9
|
+
FIELDS = %w[client_id client_secret scope refresh_token type].freeze
|
10
|
+
attr_accessor(*FIELDS)
|
11
|
+
|
12
|
+
def initialize(config_path)
|
13
|
+
@config_path = config_path
|
14
|
+
if ::File.exist?(config_path)
|
15
|
+
JSON.parse(::File.read(config_path)).each do |key, value|
|
16
|
+
instance_variable_set("@#{key}", value) if FIELDS.include?(key)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def save
|
22
|
+
::File.open(@config_path, 'w', 0o600) { |f| f.write(to_json) }
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def to_json
|
28
|
+
hash = {}
|
29
|
+
FIELDS.each do |field|
|
30
|
+
value = __send__(field)
|
31
|
+
hash[field] = value if value
|
32
|
+
end
|
33
|
+
JSON.pretty_generate(hash)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
|
+
# The license of this source is "New BSD Licence"
|
3
|
+
|
4
|
+
require 'cgi'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'stringio'
|
7
|
+
|
8
|
+
require 'google_drive/util'
|
9
|
+
require 'google_drive/acl'
|
10
|
+
|
11
|
+
module GoogleDrive
|
12
|
+
# A file in Google Drive, including a Google Docs
|
13
|
+
# document/spreadsheet/presentation and a folder.
|
14
|
+
#
|
15
|
+
# Use GoogleDrive::Session#files or GoogleDrive::Session#file_by_title to
|
16
|
+
# get this object.
|
17
|
+
#
|
18
|
+
# In addition to the methods below, properties defined here are also available
|
19
|
+
# as attributes:
|
20
|
+
# https://developers.google.com/drive/v3/reference/files#resource
|
21
|
+
#
|
22
|
+
# e.g.,
|
23
|
+
# file.mime_type # ==> "text/plain"
|
24
|
+
class File
|
25
|
+
include(Util)
|
26
|
+
extend(Forwardable)
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def initialize(session, api_file)
|
30
|
+
@session = session
|
31
|
+
@api_file = api_file
|
32
|
+
@acl = nil
|
33
|
+
delegate_api_methods(self, @api_file, [:title])
|
34
|
+
end
|
35
|
+
|
36
|
+
# Wrapped Google::APIClient::Schema::Drive::V3::File object.
|
37
|
+
attr_reader(:api_file)
|
38
|
+
|
39
|
+
# Reloads file metadata such as title and acl.
|
40
|
+
def reload_metadata
|
41
|
+
@api_file = @session.drive_service.get_file(
|
42
|
+
id, fields: '*', supports_all_drives: true
|
43
|
+
)
|
44
|
+
@acl = Acl.new(@session, self) if @acl
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns resource_type + ":" + id.
|
48
|
+
def resource_id
|
49
|
+
format('%s:%s', resource_type, id)
|
50
|
+
end
|
51
|
+
|
52
|
+
# URL of feed used in the deprecated document list feed API.
|
53
|
+
def document_feed_url
|
54
|
+
'https://docs.google.com/feeds/default/private/full/' +
|
55
|
+
CGI.escape(resource_id)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Deprecated ACL feed URL of the file.
|
59
|
+
def acl_feed_url
|
60
|
+
document_feed_url + '/acl'
|
61
|
+
end
|
62
|
+
|
63
|
+
# The type of resourse. e.g. "document", "spreadsheet", "folder"
|
64
|
+
def resource_type
|
65
|
+
mime_type.slice(/^application\/vnd.google-apps.(.+)$/, 1) || 'file'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Title of the file.
|
69
|
+
def title(params = {})
|
70
|
+
reload_metadata if params[:reload]
|
71
|
+
api_file.name
|
72
|
+
end
|
73
|
+
|
74
|
+
alias name title
|
75
|
+
|
76
|
+
# URL to view/edit the file in a Web browser.
|
77
|
+
#
|
78
|
+
# e.g. "https://docs.google.com/file/d/xxxx/edit"
|
79
|
+
def human_url
|
80
|
+
api_file.web_view_link
|
81
|
+
end
|
82
|
+
|
83
|
+
# Content types you can specify in methods download_to_file,
|
84
|
+
# download_to_string, download_to_io.
|
85
|
+
#
|
86
|
+
# This returns zero or one file type. You may be able to download the file
|
87
|
+
# in other formats using export_as_file, export_as_string, or export_to_io.
|
88
|
+
def available_content_types
|
89
|
+
api_file.web_content_link ? [api_file.mime_type] : []
|
90
|
+
end
|
91
|
+
|
92
|
+
# Downloads the file to a local file. e.g.
|
93
|
+
# file.download_to_file("/path/to/hoge.txt")
|
94
|
+
#
|
95
|
+
# To export the file in other formats, use export_as_file.
|
96
|
+
def download_to_file(path, params = {})
|
97
|
+
@session.drive_service.get_file(
|
98
|
+
id,
|
99
|
+
{ download_dest: path, supports_all_drives: true }.merge(params)
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Downloads the file and returns as a String.
|
104
|
+
#
|
105
|
+
# To export the file in other formats, use export_as_string.
|
106
|
+
def download_to_string(params = {})
|
107
|
+
sio = StringIO.new
|
108
|
+
download_to_io(sio, params)
|
109
|
+
sio.string
|
110
|
+
end
|
111
|
+
|
112
|
+
# Downloads the file and writes it to +io+.
|
113
|
+
#
|
114
|
+
# To export the file in other formats, use export_to_io.
|
115
|
+
def download_to_io(io, params = {})
|
116
|
+
@session.drive_service.get_file(
|
117
|
+
id,
|
118
|
+
**{ download_dest: io, supports_all_drives: true }.merge(params)
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Export the file to +path+ in content type +format+.
|
123
|
+
# If +format+ is nil, it is guessed from the file name.
|
124
|
+
#
|
125
|
+
# e.g.,
|
126
|
+
# spreadsheet.export_as_file("/path/to/hoge.csv")
|
127
|
+
# spreadsheet.export_as_file("/path/to/hoge", "text/csv")
|
128
|
+
#
|
129
|
+
# If you want to download the file in the original format,
|
130
|
+
# use download_to_file instead.
|
131
|
+
def export_as_file(path, format = nil)
|
132
|
+
unless format
|
133
|
+
format = EXT_TO_CONTENT_TYPE[::File.extname(path).downcase]
|
134
|
+
unless format
|
135
|
+
raise(ArgumentError,
|
136
|
+
format("Cannot guess format from the file name: %s\n" \
|
137
|
+
'Specify format argument explicitly.', path))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
export_to_dest(path, format)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Export the file as String in content type +format+.
|
144
|
+
#
|
145
|
+
# e.g.,
|
146
|
+
# spreadsheet.export_as_string("text/csv")
|
147
|
+
#
|
148
|
+
# If you want to download the file in the original format, use
|
149
|
+
# download_to_string instead.
|
150
|
+
def export_as_string(format)
|
151
|
+
sio = StringIO.new
|
152
|
+
export_to_dest(sio, format)
|
153
|
+
sio.string
|
154
|
+
end
|
155
|
+
|
156
|
+
# Export the file to +io+ in content type +format+.
|
157
|
+
#
|
158
|
+
# If you want to download the file in the original format, use
|
159
|
+
# download_to_io instead.
|
160
|
+
def export_to_io(io, format)
|
161
|
+
export_to_dest(io, format)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Updates the file with +content+.
|
165
|
+
#
|
166
|
+
# e.g.
|
167
|
+
# file.update_from_string("Good bye, world.")
|
168
|
+
def update_from_string(content, params = {})
|
169
|
+
update_from_io(StringIO.new(content), params)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Updates the file with the content of the local file.
|
173
|
+
#
|
174
|
+
# e.g.
|
175
|
+
# file.update_from_file("/path/to/hoge.txt")
|
176
|
+
def update_from_file(path, params = {})
|
177
|
+
# Somehow it doesn't work if I specify the file name directly as
|
178
|
+
# upload_source.
|
179
|
+
open(path, 'rb') do |f|
|
180
|
+
update_from_io(f, params)
|
181
|
+
end
|
182
|
+
nil
|
183
|
+
end
|
184
|
+
|
185
|
+
# Reads content from +io+ and updates the file with the content.
|
186
|
+
def update_from_io(io, params = {})
|
187
|
+
params = { upload_source: io, supports_all_drives: true }.merge(params)
|
188
|
+
@session.drive_service.update_file(id, nil, **params)
|
189
|
+
nil
|
190
|
+
end
|
191
|
+
|
192
|
+
# If +permanent+ is +false+, moves the file to the trash.
|
193
|
+
# If +permanent+ is +true+, deletes the file permanently.
|
194
|
+
def delete(permanent = false)
|
195
|
+
if permanent
|
196
|
+
@session.drive_service.delete_file(id, supports_all_drives: true)
|
197
|
+
else
|
198
|
+
@session.drive_service.update_file(
|
199
|
+
id, { trashed: true }, supports_all_drives: true
|
200
|
+
)
|
201
|
+
end
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
|
205
|
+
# Renames title of the file.
|
206
|
+
def rename(title)
|
207
|
+
@session.drive_service.update_file(
|
208
|
+
id, { name: title }, supports_all_drives: true
|
209
|
+
)
|
210
|
+
nil
|
211
|
+
end
|
212
|
+
|
213
|
+
alias title= rename
|
214
|
+
|
215
|
+
# Creates copy of this file with the given title.
|
216
|
+
def copy(title, file_properties = {})
|
217
|
+
api_file = @session.drive_service.copy_file(
|
218
|
+
id, { name: title }.merge(file_properties), fields: '*', supports_all_drives: true
|
219
|
+
)
|
220
|
+
@session.wrap_api_file(api_file)
|
221
|
+
end
|
222
|
+
|
223
|
+
alias duplicate copy
|
224
|
+
|
225
|
+
# Returns GoogleDrive::Acl object for the file.
|
226
|
+
#
|
227
|
+
# With the object, you can see and modify people who can access the file.
|
228
|
+
# Modifications take effect immediately.
|
229
|
+
#
|
230
|
+
# e.g.
|
231
|
+
# # Dumps people who have access:
|
232
|
+
# for entry in file.acl
|
233
|
+
# p [entry.type, entry.email_address, entry.role]
|
234
|
+
# # => e.g. ["user", "example1@gmail.com", "owner"]
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# # Shares the file with new people:
|
238
|
+
# # NOTE: This sends email to the new people.
|
239
|
+
# file.acl.push(
|
240
|
+
# {type: "user", email_address: "example2@gmail.com", role: "reader"})
|
241
|
+
# file.acl.push(
|
242
|
+
# {type: "user", email_address: "example3@gmail.com", role: "writer"})
|
243
|
+
#
|
244
|
+
# # Changes the role of a person:
|
245
|
+
# file.acl[1].role = "writer"
|
246
|
+
#
|
247
|
+
# # Deletes an ACL entry:
|
248
|
+
# file.acl.delete(file.acl[1])
|
249
|
+
def acl(params = {})
|
250
|
+
@acl = Acl.new(@session, self) if !@acl || params[:reload]
|
251
|
+
@acl
|
252
|
+
end
|
253
|
+
|
254
|
+
def inspect
|
255
|
+
format("\#<%p id=%p title=%p>", self.class, id, title)
|
256
|
+
end
|
257
|
+
|
258
|
+
private
|
259
|
+
|
260
|
+
def export_to_dest(dest, format)
|
261
|
+
mime_type = EXT_TO_CONTENT_TYPE['.' + format] || format
|
262
|
+
@session.drive_service.export_file(id, mime_type, download_dest: dest)
|
263
|
+
nil
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
|
+
# The license of this source is "New BSD Licence"
|
3
|
+
|
4
|
+
require 'google_drive/util'
|
5
|
+
require 'google_drive/error'
|
6
|
+
require 'google_drive/list_row'
|
7
|
+
|
8
|
+
module GoogleDrive
|
9
|
+
# Provides access to cells using column names.
|
10
|
+
# Use GoogleDrive::Worksheet#list to get GoogleDrive::List object.
|
11
|
+
#--
|
12
|
+
# This is implemented as wrapper of GoogleDrive::Worksheet i.e. using cells
|
13
|
+
# feed, not list feed. In this way, we can easily provide consistent API as
|
14
|
+
# GoogleDrive::Worksheet using save()/reload().
|
15
|
+
class List
|
16
|
+
include(Enumerable)
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
def initialize(worksheet)
|
20
|
+
@worksheet = worksheet
|
21
|
+
end
|
22
|
+
|
23
|
+
# Number of non-empty rows in the worksheet excluding the first row.
|
24
|
+
def size
|
25
|
+
@worksheet.num_rows - 1
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns Hash-like object (GoogleDrive::ListRow) for the row with the
|
29
|
+
# index. Keys of the object are colum names (the first row).
|
30
|
+
# The second row has index 0.
|
31
|
+
#
|
32
|
+
# Note that updates to the returned object are not sent to the server until
|
33
|
+
# you call GoogleDrive::Worksheet#save().
|
34
|
+
def [](index)
|
35
|
+
ListRow.new(self, index)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Updates the row with the index with the given Hash object.
|
39
|
+
# Keys of +hash+ are colum names (the first row).
|
40
|
+
# The second row has index 0.
|
41
|
+
#
|
42
|
+
# Note that update is not sent to the server until
|
43
|
+
# you call GoogleDrive::Worksheet#save().
|
44
|
+
def []=(index, hash)
|
45
|
+
self[index].replace(hash)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Iterates over Hash-like object (GoogleDrive::ListRow) for each row
|
49
|
+
# (except for the first row).
|
50
|
+
# Keys of the object are colum names (the first row).
|
51
|
+
def each(&_block)
|
52
|
+
for i in 0...size
|
53
|
+
yield(self[i])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Column names i.e. the contents of the first row.
|
58
|
+
# Duplicates are removed.
|
59
|
+
def keys
|
60
|
+
(1..@worksheet.num_cols).map { |i| @worksheet[1, i] }.uniq
|
61
|
+
end
|
62
|
+
|
63
|
+
# Updates column names i.e. the contents of the first row.
|
64
|
+
#
|
65
|
+
# Note that update is not sent to the server until
|
66
|
+
# you call GoogleDrive::Worksheet#save().
|
67
|
+
def keys=(ary)
|
68
|
+
for i in 1..ary.size
|
69
|
+
@worksheet[1, i] = ary[i - 1]
|
70
|
+
end
|
71
|
+
for i in (ary.size + 1)..@worksheet.num_cols
|
72
|
+
@worksheet[1, i] = ''
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Adds a new row to the bottom.
|
77
|
+
# Keys of +hash+ are colum names (the first row).
|
78
|
+
# Returns GoogleDrive::ListRow for the new row.
|
79
|
+
#
|
80
|
+
# Note that update is not sent to the server until
|
81
|
+
# you call GoogleDrive::Worksheet#save().
|
82
|
+
def push(hash)
|
83
|
+
row = self[size]
|
84
|
+
row.update(hash)
|
85
|
+
row
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns all rows (except for the first row) as Array of Hash.
|
89
|
+
# Keys of Hash objects are colum names (the first row).
|
90
|
+
def to_hash_array
|
91
|
+
map(&:to_hash)
|
92
|
+
end
|
93
|
+
|
94
|
+
# @api private
|
95
|
+
def get(index, key)
|
96
|
+
@worksheet[index + 2, key_to_col(key)]
|
97
|
+
end
|
98
|
+
|
99
|
+
# @api private
|
100
|
+
def numeric_value(index, key)
|
101
|
+
@worksheet.numeric_value(index + 2, key_to_col(key))
|
102
|
+
end
|
103
|
+
|
104
|
+
# @api private
|
105
|
+
def input_value(index, key)
|
106
|
+
@worksheet.input_value(index + 2, key_to_col(key))
|
107
|
+
end
|
108
|
+
|
109
|
+
# @api private
|
110
|
+
def set(index, key, value)
|
111
|
+
@worksheet[index + 2, key_to_col(key)] = value
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def key_to_col(key)
|
117
|
+
key = key.to_s
|
118
|
+
col = (1..@worksheet.num_cols).find { |c| @worksheet[1, c] == key }
|
119
|
+
unless col
|
120
|
+
raise(GoogleDrive::Error, format("Column doesn't exist: %p", key))
|
121
|
+
end
|
122
|
+
col
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|