google_drive2 3.0.8
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 +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
|