google_drive 2.1.12 → 3.0.7
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 +5 -5
- data/README.md +2 -2
- data/lib/google_drive/acl.rb +8 -8
- data/lib/google_drive/api_client_fetcher.rb +23 -17
- data/lib/google_drive/collection.rb +6 -6
- data/lib/google_drive/file.rb +16 -16
- data/lib/google_drive/session.rb +36 -25
- data/lib/google_drive/spreadsheet.rb +41 -24
- data/lib/google_drive/worksheet.rb +331 -161
- metadata +28 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8579ea758131c51c083928052abf518b1f327b9b9666e798c17007801f0c1476
|
4
|
+
data.tar.gz: c04c47fe2d0337bb2e471227ad66e90b857b33784f01f8d60d7406f63fcad92b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d52bac1e4e05bd2dee4503a67a4c9da7eaeee700dfa9bca2f668bc88c04df065b5a7c209a4808d98a63610cb27318df3bef859e6e016ba4fbe1029782440aa58
|
7
|
+
data.tar.gz: 24facac6a6116210ea76b82f139fcd5c93e5624fbdb889f2fb89de65c98a6eb11ae31fb0c892cb221a5b689e2fc5271bb6636ad1215559e2689a8ef9b5edbf85
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ This is a Ruby library to read/write files/spreadsheets in Google Drive/Docs.
|
|
5
5
|
NOTE: This is NOT a library to create Google Drive App.
|
6
6
|
|
7
7
|
|
8
|
-
* [Migration from ver.
|
8
|
+
* [Migration from ver. 2.x.x or before](#migration)
|
9
9
|
* [How to install](#install)
|
10
10
|
* [How to use](#use)
|
11
11
|
* [API documentation](http://www.rubydoc.info/gems/google_drive)
|
@@ -16,7 +16,7 @@ NOTE: This is NOT a library to create Google Drive App.
|
|
16
16
|
* [Author](#author)
|
17
17
|
|
18
18
|
|
19
|
-
## <a name="migration">Migration from ver.
|
19
|
+
## <a name="migration">Migration from ver. 2.x.x or before</a>
|
20
20
|
|
21
21
|
There are some incompatible API changes. See
|
22
22
|
[MIGRATING.md](https://github.com/gimite/google-drive-ruby/blob/master/MIGRATING.md).
|
data/lib/google_drive/acl.rb
CHANGED
@@ -21,8 +21,8 @@ module GoogleDrive
|
|
21
21
|
def initialize(session, file)
|
22
22
|
@session = session
|
23
23
|
@file = file
|
24
|
-
api_permissions = @session.
|
25
|
-
@file.id, fields: '*',
|
24
|
+
api_permissions = @session.drive_service.list_permissions(
|
25
|
+
@file.id, fields: '*', supports_all_drives: true
|
26
26
|
)
|
27
27
|
@entries =
|
28
28
|
api_permissions.permissions.map { |perm| AclEntry.new(perm, self) }
|
@@ -70,10 +70,10 @@ module GoogleDrive
|
|
70
70
|
def push(params_or_entry, options = {})
|
71
71
|
entry = params_or_entry.is_a?(AclEntry) ?
|
72
72
|
params_or_entry : AclEntry.new(params_or_entry)
|
73
|
-
api_permission = @session.
|
73
|
+
api_permission = @session.drive_service.create_permission(
|
74
74
|
@file.id,
|
75
75
|
entry.params,
|
76
|
-
{ fields: '*',
|
76
|
+
**{ fields: '*', supports_all_drives: true }.merge(options)
|
77
77
|
)
|
78
78
|
new_entry = AclEntry.new(api_permission, self)
|
79
79
|
@entries.push(new_entry)
|
@@ -85,20 +85,20 @@ module GoogleDrive
|
|
85
85
|
# e.g.
|
86
86
|
# spreadsheet.acl.delete(spreadsheet.acl[1])
|
87
87
|
def delete(entry)
|
88
|
-
@session.
|
89
|
-
@file.id, entry.id,
|
88
|
+
@session.drive_service.delete_permission(
|
89
|
+
@file.id, entry.id, supports_all_drives: true
|
90
90
|
)
|
91
91
|
@entries.delete(entry)
|
92
92
|
end
|
93
93
|
|
94
94
|
# @api private
|
95
95
|
def update_role(entry)
|
96
|
-
api_permission = @session.
|
96
|
+
api_permission = @session.drive_service.update_permission(
|
97
97
|
@file.id,
|
98
98
|
entry.id,
|
99
99
|
{ role: entry.role },
|
100
100
|
fields: '*',
|
101
|
-
|
101
|
+
supports_all_drives: true
|
102
102
|
)
|
103
103
|
entry.api_permission = api_permission
|
104
104
|
entry
|
@@ -4,6 +4,7 @@
|
|
4
4
|
require 'net/https'
|
5
5
|
require 'uri'
|
6
6
|
require 'google/apis/drive_v3'
|
7
|
+
require 'google/apis/sheets_v4'
|
7
8
|
Net::HTTP.version_1_2
|
8
9
|
|
9
10
|
module GoogleDrive
|
@@ -19,30 +20,35 @@ module GoogleDrive
|
|
19
20
|
|
20
21
|
def initialize(authorization, client_options, request_options)
|
21
22
|
@drive = Google::Apis::DriveV3::DriveService.new
|
22
|
-
@
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
23
|
+
@sheets = Google::Apis::SheetsV4::SheetsService.new
|
24
|
+
|
25
|
+
[@drive, @sheets].each do |service|
|
26
|
+
service.authorization = authorization
|
27
|
+
|
28
|
+
# Make the timeout virtually infinite because some of the operations
|
29
|
+
# (e.g., uploading a large file) can take very long.
|
30
|
+
# This value is the maximal allowed timeout in seconds on JRuby.
|
31
|
+
t = (2**31 - 1) / 1000
|
32
|
+
service.client_options.open_timeout_sec = t
|
33
|
+
service.client_options.read_timeout_sec = t
|
34
|
+
service.client_options.send_timeout_sec = t
|
35
|
+
|
36
|
+
if client_options
|
37
|
+
service.client_options.members.each do |name|
|
38
|
+
if !client_options[name].nil?
|
39
|
+
service.client_options[name] = client_options[name]
|
40
|
+
end
|
36
41
|
end
|
37
42
|
end
|
38
|
-
end
|
39
43
|
|
40
|
-
|
41
|
-
|
44
|
+
if request_options
|
45
|
+
service.request_options = service.request_options.merge(request_options)
|
46
|
+
end
|
42
47
|
end
|
43
48
|
end
|
44
49
|
|
45
50
|
attr_reader(:drive)
|
51
|
+
attr_reader(:sheets)
|
46
52
|
|
47
53
|
def request_raw(method, url, data, extra_header, _auth)
|
48
54
|
options = @drive.request_options.merge(header: extra_header)
|
@@ -19,16 +19,16 @@ module GoogleDrive
|
|
19
19
|
|
20
20
|
# Adds the given GoogleDrive::File to the folder.
|
21
21
|
def add(file)
|
22
|
-
@session.
|
23
|
-
file.id, add_parents: id, fields: '',
|
22
|
+
@session.drive_service.update_file(
|
23
|
+
file.id, add_parents: id, fields: '', supports_all_drives: true
|
24
24
|
)
|
25
25
|
nil
|
26
26
|
end
|
27
27
|
|
28
28
|
# Removes the given GoogleDrive::File from the folder.
|
29
29
|
def remove(file)
|
30
|
-
@session.
|
31
|
-
file.id, remove_parents: id, fields: '',
|
30
|
+
@session.drive_service.update_file(
|
31
|
+
file.id, remove_parents: id, fields: '', supports_all_drives: true
|
32
32
|
)
|
33
33
|
end
|
34
34
|
|
@@ -61,8 +61,8 @@ module GoogleDrive
|
|
61
61
|
parents: [id]
|
62
62
|
}.merge(file_properties)
|
63
63
|
|
64
|
-
file = @session.
|
65
|
-
file_metadata, fields: '*',
|
64
|
+
file = @session.drive_service.create_file(
|
65
|
+
file_metadata, fields: '*', supports_all_drives: true
|
66
66
|
)
|
67
67
|
|
68
68
|
@session.wrap_api_file(file)
|
data/lib/google_drive/file.rb
CHANGED
@@ -38,8 +38,8 @@ module GoogleDrive
|
|
38
38
|
|
39
39
|
# Reloads file metadata such as title and acl.
|
40
40
|
def reload_metadata
|
41
|
-
@api_file = @session.
|
42
|
-
id, fields: '*',
|
41
|
+
@api_file = @session.drive_service.get_file(
|
42
|
+
id, fields: '*', supports_all_drives: true
|
43
43
|
)
|
44
44
|
@acl = Acl.new(@session, self) if @acl
|
45
45
|
end
|
@@ -94,9 +94,9 @@ module GoogleDrive
|
|
94
94
|
#
|
95
95
|
# To export the file in other formats, use export_as_file.
|
96
96
|
def download_to_file(path, params = {})
|
97
|
-
@session.
|
97
|
+
@session.drive_service.get_file(
|
98
98
|
id,
|
99
|
-
{ download_dest: path,
|
99
|
+
{ download_dest: path, supports_all_drives: true }.merge(params)
|
100
100
|
)
|
101
101
|
end
|
102
102
|
|
@@ -113,9 +113,9 @@ module GoogleDrive
|
|
113
113
|
#
|
114
114
|
# To export the file in other formats, use export_to_io.
|
115
115
|
def download_to_io(io, params = {})
|
116
|
-
@session.
|
116
|
+
@session.drive_service.get_file(
|
117
117
|
id,
|
118
|
-
{ download_dest: io,
|
118
|
+
**{ download_dest: io, supports_all_drives: true }.merge(params)
|
119
119
|
)
|
120
120
|
end
|
121
121
|
|
@@ -184,8 +184,8 @@ module GoogleDrive
|
|
184
184
|
|
185
185
|
# Reads content from +io+ and updates the file with the content.
|
186
186
|
def update_from_io(io, params = {})
|
187
|
-
params = { upload_source: io,
|
188
|
-
@session.
|
187
|
+
params = { upload_source: io, supports_all_drives: true }.merge(params)
|
188
|
+
@session.drive_service.update_file(id, nil, **params)
|
189
189
|
nil
|
190
190
|
end
|
191
191
|
|
@@ -193,10 +193,10 @@ module GoogleDrive
|
|
193
193
|
# If +permanent+ is +true+, deletes the file permanently.
|
194
194
|
def delete(permanent = false)
|
195
195
|
if permanent
|
196
|
-
@session.
|
196
|
+
@session.drive_service.delete_file(id, supports_all_drives: true)
|
197
197
|
else
|
198
|
-
@session.
|
199
|
-
id, { trashed: true },
|
198
|
+
@session.drive_service.update_file(
|
199
|
+
id, { trashed: true }, supports_all_drives: true
|
200
200
|
)
|
201
201
|
end
|
202
202
|
nil
|
@@ -204,8 +204,8 @@ module GoogleDrive
|
|
204
204
|
|
205
205
|
# Renames title of the file.
|
206
206
|
def rename(title)
|
207
|
-
@session.
|
208
|
-
id, { name: title },
|
207
|
+
@session.drive_service.update_file(
|
208
|
+
id, { name: title }, supports_all_drives: true
|
209
209
|
)
|
210
210
|
nil
|
211
211
|
end
|
@@ -214,8 +214,8 @@ module GoogleDrive
|
|
214
214
|
|
215
215
|
# Creates copy of this file with the given title.
|
216
216
|
def copy(title, file_properties = {})
|
217
|
-
api_file = @session.
|
218
|
-
id, { name: title }.merge(file_properties), fields: '*',
|
217
|
+
api_file = @session.drive_service.copy_file(
|
218
|
+
id, { name: title }.merge(file_properties), fields: '*', supports_all_drives: true
|
219
219
|
)
|
220
220
|
@session.wrap_api_file(api_file)
|
221
221
|
end
|
@@ -259,7 +259,7 @@ module GoogleDrive
|
|
259
259
|
|
260
260
|
def export_to_dest(dest, format)
|
261
261
|
mime_type = EXT_TO_CONTENT_TYPE['.' + format] || format
|
262
|
-
@session.
|
262
|
+
@session.drive_service.export_file(id, mime_type, download_dest: dest)
|
263
263
|
nil
|
264
264
|
end
|
265
265
|
end
|
data/lib/google_drive/session.rb
CHANGED
@@ -141,15 +141,13 @@ module GoogleDrive
|
|
141
141
|
config.client_id = options[:client_id]
|
142
142
|
config.client_secret = options[:client_secret]
|
143
143
|
end
|
144
|
-
if !config.client_id
|
145
|
-
config.client_id =
|
146
|
-
'452925651630-egr1f18o96acjjvphpbbd1qlsevkho1d.' \
|
147
|
-
'apps.googleusercontent.com'
|
148
|
-
config.client_secret = '1U3-Krii5x1oLPrwD5zgn-ry'
|
149
|
-
elsif !config.client_id || !config.client_secret
|
144
|
+
if !config.client_id || !config.client_secret
|
150
145
|
raise(
|
151
146
|
ArgumentError,
|
152
|
-
'client_id
|
147
|
+
'client_id or client_secret is missing in the config. Follow ' \
|
148
|
+
'https://github.com/gimite/google-drive-ruby/blob/master/doc/authorization.md ' \
|
149
|
+
'to provide a valid config. google_drive library no longer provides ' \
|
150
|
+
'the default credential due to a limitation of Google API.'
|
153
151
|
)
|
154
152
|
end
|
155
153
|
|
@@ -219,10 +217,17 @@ module GoogleDrive
|
|
219
217
|
attr_accessor :on_auth_fail
|
220
218
|
|
221
219
|
# Returns an instance of Google::Apis::DriveV3::DriveService.
|
222
|
-
def
|
220
|
+
def drive_service
|
223
221
|
@fetcher.drive
|
224
222
|
end
|
225
223
|
|
224
|
+
alias drive drive_service
|
225
|
+
|
226
|
+
# Returns an instance of Google::Apis::SheetsV4::SheetsService.
|
227
|
+
def sheets_service
|
228
|
+
@fetcher.sheets
|
229
|
+
end
|
230
|
+
|
226
231
|
# Returns list of files for the user as array of GoogleDrive::File or its
|
227
232
|
# subclass. You can specify parameters documented at
|
228
233
|
# https://developers.google.com/drive/v3/web/search-parameters
|
@@ -247,8 +252,8 @@ module GoogleDrive
|
|
247
252
|
def files(params = {}, &block)
|
248
253
|
params = convert_params(params)
|
249
254
|
execute_paged!(
|
250
|
-
method:
|
251
|
-
parameters: { fields: '*',
|
255
|
+
method: drive_service.method(:list_files),
|
256
|
+
parameters: { fields: '*', supports_all_drives: true, include_items_from_all_drives: true }.merge(params),
|
252
257
|
items_method_name: :files,
|
253
258
|
converter: proc { |af| wrap_api_file(af) },
|
254
259
|
&block
|
@@ -280,7 +285,7 @@ module GoogleDrive
|
|
280
285
|
# Returns an instance of GoogleDrive::File or its subclass
|
281
286
|
# (GoogleDrive::Spreadsheet, GoogleDrive::Collection).
|
282
287
|
def file_by_id(id)
|
283
|
-
api_file =
|
288
|
+
api_file = drive_service.get_file(id, fields: '*', supports_all_drives: true)
|
284
289
|
wrap_api_file(api_file)
|
285
290
|
end
|
286
291
|
|
@@ -379,13 +384,12 @@ module GoogleDrive
|
|
379
384
|
# "1smypkyAz4STrKO4Zkos5Z4UPUJKvvgIza32LnlQ7OGw/od7/private/full")
|
380
385
|
def worksheet_by_url(url)
|
381
386
|
case url
|
382
|
-
when %r{^https?://spreadsheets.google.com/feeds/worksheets
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
"#{Regexp.last_match(2)}#{Regexp.last_match(3)}"
|
387
|
+
when %r{^https?://spreadsheets.google.com/feeds/worksheets/(.*)/.*/full/(.*)$}
|
388
|
+
spreadsheet_id = Regexp.last_match(1)
|
389
|
+
worksheet_feed_id = Regexp.last_match(2)
|
390
|
+
when %r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full(\?.*)?$}
|
391
|
+
spreadsheet_id = Regexp.last_match(1)
|
392
|
+
worksheet_feed_id = Regexp.last_match(2)
|
389
393
|
else
|
390
394
|
raise(
|
391
395
|
GoogleDrive::Error,
|
@@ -394,8 +398,15 @@ module GoogleDrive
|
|
394
398
|
)
|
395
399
|
end
|
396
400
|
|
397
|
-
|
398
|
-
|
401
|
+
spreadsheet = spreadsheet_by_key(spreadsheet_id)
|
402
|
+
worksheet = spreadsheet.worksheets.find{ |ws| ws.worksheet_feed_id == worksheet_feed_id }
|
403
|
+
unless worksheet
|
404
|
+
raise(
|
405
|
+
GoogleDrive::Error,
|
406
|
+
"Worksheet not found for the given URL: #{url}"
|
407
|
+
)
|
408
|
+
end
|
409
|
+
worksheet
|
399
410
|
end
|
400
411
|
|
401
412
|
# Returns the root folder.
|
@@ -496,8 +507,8 @@ module GoogleDrive
|
|
496
507
|
name: title,
|
497
508
|
}.merge(file_properties)
|
498
509
|
|
499
|
-
file =
|
500
|
-
file_metadata, fields: '*',
|
510
|
+
file = drive_service.create_file(
|
511
|
+
file_metadata, fields: '*', supports_all_drives: true
|
501
512
|
)
|
502
513
|
|
503
514
|
wrap_api_file(file)
|
@@ -587,7 +598,7 @@ module GoogleDrive
|
|
587
598
|
end
|
588
599
|
|
589
600
|
elsif opts[:parameters] && opts[:parameters].key?(:page_token)
|
590
|
-
response = opts[:method].call(opts[:parameters])
|
601
|
+
response = opts[:method].call(**opts[:parameters])
|
591
602
|
items = response.__send__(opts[:items_method_name]).map do |item|
|
592
603
|
opts[:converter] ? opts[:converter].call(item) : item
|
593
604
|
end
|
@@ -643,7 +654,7 @@ module GoogleDrive
|
|
643
654
|
upload_source: source,
|
644
655
|
content_type: 'application/octet-stream',
|
645
656
|
fields: '*',
|
646
|
-
|
657
|
+
supports_all_drives: true
|
647
658
|
}
|
648
659
|
for k, v in params
|
649
660
|
unless %i[convert convert_mime_type parents].include?(k)
|
@@ -661,7 +672,7 @@ module GoogleDrive
|
|
661
672
|
end
|
662
673
|
file_metadata[:parents] = params[:parents] if params[:parents]
|
663
674
|
|
664
|
-
file =
|
675
|
+
file = drive_service.create_file(file_metadata, **api_params)
|
665
676
|
wrap_api_file(file)
|
666
677
|
end
|
667
678
|
|
@@ -16,6 +16,10 @@ module GoogleDrive
|
|
16
16
|
# create_spreadsheet in GoogleDrive::Session to get GoogleDrive::Spreadsheet
|
17
17
|
# object.
|
18
18
|
class Spreadsheet < GoogleDrive::File
|
19
|
+
|
20
|
+
# TODO: Bump up the major version before switching the existing methods to
|
21
|
+
# v4 API because it requires to turn on a new API in the API console.
|
22
|
+
|
19
23
|
include(Util)
|
20
24
|
|
21
25
|
SUPPORTED_EXPORT_FORMAT = Set.new(%w[xlsx csv pdf])
|
@@ -45,16 +49,8 @@ module GoogleDrive
|
|
45
49
|
|
46
50
|
# Returns worksheets of the spreadsheet as array of GoogleDrive::Worksheet.
|
47
51
|
def worksheets
|
48
|
-
|
49
|
-
|
50
|
-
raise(GoogleDrive::Error,
|
51
|
-
format(
|
52
|
-
"%s doesn't look like a worksheets feed URL because its root " \
|
53
|
-
'is not <feed>.',
|
54
|
-
worksheets_feed_url
|
55
|
-
))
|
56
|
-
end
|
57
|
-
doc.css('entry').map { |e| Worksheet.new(@session, self, e) }.freeze
|
52
|
+
api_spreadsheet = @session.sheets_service.get_spreadsheet(id, fields: 'sheets.properties')
|
53
|
+
api_spreadsheet.sheets.map{ |s| Worksheet.new(@session, self, s.properties) }
|
58
54
|
end
|
59
55
|
|
60
56
|
# Returns a GoogleDrive::Worksheet with the given title in the spreadsheet.
|
@@ -68,24 +64,32 @@ module GoogleDrive
|
|
68
64
|
# Returns a GoogleDrive::Worksheet with the given gid.
|
69
65
|
#
|
70
66
|
# Returns nil if not found.
|
71
|
-
def
|
72
|
-
|
73
|
-
worksheets.find { |ws| ws.
|
67
|
+
def worksheet_by_sheet_id(sheet_id)
|
68
|
+
sheet_id = sheet_id.to_i
|
69
|
+
worksheets.find { |ws| ws.sheet_id == sheet_id }
|
74
70
|
end
|
75
71
|
|
72
|
+
alias worksheet_by_gid worksheet_by_sheet_id
|
73
|
+
|
76
74
|
# Adds a new worksheet to the spreadsheet. Returns added
|
77
75
|
# GoogleDrive::Worksheet.
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
76
|
+
#
|
77
|
+
# When +index+ is specified, the worksheet is inserted at the given
|
78
|
+
# +index+.
|
79
|
+
def add_worksheet(title, max_rows = 100, max_cols = 20, index: nil)
|
80
|
+
(response,) = batch_update([{
|
81
|
+
add_sheet: {
|
82
|
+
properties: {
|
83
|
+
title: title,
|
84
|
+
index: index,
|
85
|
+
grid_properties: {
|
86
|
+
row_count: max_rows,
|
87
|
+
column_count: max_cols,
|
88
|
+
},
|
89
|
+
},
|
90
|
+
},
|
91
|
+
}])
|
92
|
+
Worksheet.new(@session, self, response.add_sheet.properties)
|
89
93
|
end
|
90
94
|
|
91
95
|
# Not available for GoogleDrive::Spreadsheet. Use export_as_file instead.
|
@@ -114,5 +118,18 @@ module GoogleDrive
|
|
114
118
|
'Use export_to_io instead.'
|
115
119
|
)
|
116
120
|
end
|
121
|
+
|
122
|
+
# Performs batch update of the spreadsheet.
|
123
|
+
#
|
124
|
+
# +requests+ is an Array of Google::Apis::SheetsV4::Request or its Hash
|
125
|
+
# equivalent. Returns an Array of Google::Apis::SheetsV4::Response.
|
126
|
+
def batch_update(requests)
|
127
|
+
batch_request =
|
128
|
+
Google::Apis::SheetsV4::BatchUpdateSpreadsheetRequest.new(
|
129
|
+
requests: requests)
|
130
|
+
batch_response =
|
131
|
+
@session.sheets_service.batch_update_spreadsheet(id, batch_request)
|
132
|
+
batch_response.replies
|
133
|
+
end
|
117
134
|
end
|
118
135
|
end
|
@@ -16,51 +16,104 @@ module GoogleDrive
|
|
16
16
|
class Worksheet
|
17
17
|
include(Util)
|
18
18
|
|
19
|
+
# A few default color instances that match the colors from the Google Sheets web UI.
|
20
|
+
#
|
21
|
+
# TODO: Add more colors from
|
22
|
+
# https://github.com/denilsonsa/gimp-palettes/blob/master/palettes/Google-Drive.gpl
|
23
|
+
module Colors
|
24
|
+
RED = Google::Apis::SheetsV4::Color.new(red: 1.0)
|
25
|
+
DARK_RED_1 = Google::Apis::SheetsV4::Color.new(red: 0.8)
|
26
|
+
RED_BERRY = Google::Apis::SheetsV4::Color.new(red: 0.596)
|
27
|
+
DARK_RED_BERRY_1 = Google::Apis::SheetsV4::Color.new(red: 0.659, green: 0.11)
|
28
|
+
ORANGE = Google::Apis::SheetsV4::Color.new(red: 1.0, green: 0.6)
|
29
|
+
DARK_ORANGE_1 = Google::Apis::SheetsV4::Color.new(red: 0.9, green: 0.569, blue: 0.22)
|
30
|
+
YELLOW = Google::Apis::SheetsV4::Color.new(red: 1.0, green: 1.0)
|
31
|
+
DARK_YELLOW_1 = Google::Apis::SheetsV4::Color.new(red: 0.945, green: 0.76, blue: 0.196)
|
32
|
+
GREEN = Google::Apis::SheetsV4::Color.new(green: 1.0)
|
33
|
+
DARK_GREEN_1 = Google::Apis::SheetsV4::Color.new(red: 0.416, green: 0.659, blue: 0.31)
|
34
|
+
CYAN = Google::Apis::SheetsV4::Color.new(green: 1.0, blue: 1.0)
|
35
|
+
DARK_CYAN_1 = Google::Apis::SheetsV4::Color.new(red: 0.27, green: 0.506, blue: 0.557)
|
36
|
+
CORNFLOWER_BLUE = Google::Apis::SheetsV4::Color.new(red: 0.29, green: 0.525, blue: 0.91)
|
37
|
+
DARK_CORNFLOWER_BLUE_1 = Google::Apis::SheetsV4::Color.new(red: 0.235, green: 0.47, blue: 0.847)
|
38
|
+
BLUE = Google::Apis::SheetsV4::Color.new(blue: 1.0)
|
39
|
+
DARK_BLUE_1 = Google::Apis::SheetsV4::Color.new(red: 0.239, green: 0.522, blue: 0.776)
|
40
|
+
PURPLE = Google::Apis::SheetsV4::Color.new(red: 0.6, blue: 1.0)
|
41
|
+
DARK_PURPLE_1 = Google::Apis::SheetsV4::Color.new(red: 0.404, green: 0.306, blue: 0.655)
|
42
|
+
MAGENTA = Google::Apis::SheetsV4::Color.new(red: 1.0, blue: 1.0)
|
43
|
+
DARK_MAGENTA_1 = Google::Apis::SheetsV4::Color.new(red: 0.651, green: 0.302, blue: 0.475)
|
44
|
+
WHITE = Google::Apis::SheetsV4::Color.new(red: 1.0, green: 1.0, blue: 1.0)
|
45
|
+
BLACK = Google::Apis::SheetsV4::Color.new(red: 0.0, green: 0.0, blue: 0.0)
|
46
|
+
GRAY = Google::Apis::SheetsV4::Color.new(red: 0.8, green: 0.8, blue: 0.8)
|
47
|
+
DARK_GRAY_1 = Google::Apis::SheetsV4::Color.new(red: 0.714, green: 0.714, blue: 0.714)
|
48
|
+
end
|
49
|
+
|
19
50
|
# @api private
|
20
51
|
# A regexp which matches an invalid character in XML 1.0:
|
21
52
|
# https://en.wikipedia.org/wiki/Valid_characters_in_XML#XML_1.0
|
22
|
-
|
53
|
+
XML_INVALID_CHAR_REGEXP =
|
23
54
|
/[^\u0009\u000a\u000d\u0020-\ud7ff\ue000-\ufffd\u{10000}-\u{10ffff}]/
|
24
55
|
|
25
56
|
# @api private
|
26
|
-
def initialize(session, spreadsheet,
|
57
|
+
def initialize(session, spreadsheet, properties)
|
27
58
|
@session = session
|
28
59
|
@spreadsheet = spreadsheet
|
29
|
-
|
30
|
-
|
60
|
+
set_properties(properties)
|
31
61
|
@cells = nil
|
32
62
|
@input_values = nil
|
33
63
|
@numeric_values = nil
|
34
64
|
@modified = Set.new
|
35
65
|
@list = nil
|
66
|
+
@v4_requests = []
|
36
67
|
end
|
37
68
|
|
38
69
|
# Nokogiri::XML::Element object of the <entry> element in a worksheets feed.
|
39
|
-
|
70
|
+
#
|
71
|
+
# DEPRECATED: This method is deprecated, and now requires additional
|
72
|
+
# network fetch. Consider using properties instead.
|
73
|
+
def worksheet_feed_entry
|
74
|
+
@worksheet_feed_entry ||= @session.request(:get, worksheet_feed_url).root
|
75
|
+
end
|
76
|
+
|
77
|
+
# Google::Apis::SheetsV4::SheetProperties object for this worksheet.
|
78
|
+
attr_reader :properties
|
40
79
|
|
41
80
|
# Title of the worksheet (shown as tab label in Web interface).
|
42
|
-
attr_reader
|
81
|
+
attr_reader :title
|
82
|
+
|
83
|
+
# Index of the worksheet (affects tab order in web interface).
|
84
|
+
attr_reader :index
|
85
|
+
|
86
|
+
# GoogleDrive::Spreadsheet which this worksheet belongs to.
|
87
|
+
attr_reader :spreadsheet
|
43
88
|
|
44
89
|
# Time object which represents the time the worksheet was last updated.
|
45
|
-
|
90
|
+
#
|
91
|
+
# DEPRECATED: From google_drive 3.0.0, it returns the time the
|
92
|
+
# *spreadsheet* was last updated, instead of the worksheet. This is because
|
93
|
+
# it looks the information is not available in Sheets v4 API.
|
94
|
+
def updated
|
95
|
+
spreadsheet.modified_time.to_time
|
96
|
+
end
|
46
97
|
|
47
98
|
# URL of cell-based feed of the worksheet.
|
99
|
+
#
|
100
|
+
# DEPRECATED: This method is deprecated, and now requires additional
|
101
|
+
# network fetch.
|
48
102
|
def cells_feed_url
|
49
|
-
|
103
|
+
worksheet_feed_entry.css(
|
50
104
|
"link[rel='http://schemas.google.com/spreadsheets/2006#cellsfeed']"
|
51
105
|
)[0]['href']
|
52
106
|
end
|
53
107
|
|
54
108
|
# URL of worksheet feed URL of the worksheet.
|
55
109
|
def worksheet_feed_url
|
56
|
-
|
110
|
+
return '%s/%s' % [spreadsheet.worksheets_feed_url, worksheet_feed_id]
|
57
111
|
end
|
58
112
|
|
59
113
|
# URL to export the worksheet as CSV.
|
60
114
|
def csv_export_url
|
61
|
-
|
62
|
-
|
63
|
-
)[0]['href']
|
115
|
+
'https://docs.google.com/spreadsheets/d/%s/export?gid=%s&format=csv' %
|
116
|
+
[spreadsheet.id, gid]
|
64
117
|
end
|
65
118
|
|
66
119
|
# Exports the worksheet as String in CSV format.
|
@@ -74,10 +127,14 @@ module GoogleDrive
|
|
74
127
|
open(path, 'wb') { |f| f.write(data) }
|
75
128
|
end
|
76
129
|
|
77
|
-
#
|
130
|
+
# ID of the worksheet.
|
131
|
+
def sheet_id
|
132
|
+
@properties.sheet_id
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns sheet_id.to_s.
|
78
136
|
def gid
|
79
|
-
|
80
|
-
CGI.parse(URI.parse(csv_export_url).query)['gid'].last
|
137
|
+
sheet_id.to_s
|
81
138
|
end
|
82
139
|
|
83
140
|
# URL to view/edit the worksheet in a Web browser.
|
@@ -85,18 +142,22 @@ module GoogleDrive
|
|
85
142
|
format("%s\#gid=%s", spreadsheet.human_url, gid)
|
86
143
|
end
|
87
144
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
145
|
+
# Copy worksheet to specified spreadsheet.
|
146
|
+
# This method can take either instance of GoogleDrive::Spreadsheet or its id.
|
147
|
+
def copy_to(spreadsheet_or_id)
|
148
|
+
destination_spreadsheet_id =
|
149
|
+
spreadsheet_or_id.respond_to?(:id) ?
|
150
|
+
spreadsheet_or_id.id : spreadsheet_or_id
|
151
|
+
request = Google::Apis::SheetsV4::CopySheetToAnotherSpreadsheetRequest.new(
|
152
|
+
destination_spreadsheet_id: destination_spreadsheet_id,
|
153
|
+
)
|
154
|
+
@session.sheets_service.copy_spreadsheet(spreadsheet.id, sheet_id, request)
|
155
|
+
nil
|
156
|
+
end
|
157
|
+
|
158
|
+
# Copy worksheet to owner spreadsheet.
|
159
|
+
def duplicate
|
160
|
+
copy_to(spreadsheet)
|
100
161
|
end
|
101
162
|
|
102
163
|
# Returns content of the cell as String. Arguments must be either
|
@@ -240,6 +301,13 @@ module GoogleDrive
|
|
240
301
|
@meta_modified = true
|
241
302
|
end
|
242
303
|
|
304
|
+
# Updates index of the worksheet.
|
305
|
+
# Note that update is not sent to the server until you call save().
|
306
|
+
def index=(index)
|
307
|
+
@index = index
|
308
|
+
@meta_modified = true
|
309
|
+
end
|
310
|
+
|
243
311
|
# @api private
|
244
312
|
def cells
|
245
313
|
reload_cells unless @cells
|
@@ -314,8 +382,19 @@ module GoogleDrive
|
|
314
382
|
# Note that changes you made by []= etc. is discarded if you haven't called
|
315
383
|
# save().
|
316
384
|
def reload
|
317
|
-
|
318
|
-
|
385
|
+
api_spreadsheet =
|
386
|
+
@session.sheets_service.get_spreadsheet(
|
387
|
+
spreadsheet.id,
|
388
|
+
ranges: "'%s'" % @title,
|
389
|
+
fields:
|
390
|
+
'sheets(properties,data.rowData.values' \
|
391
|
+
'(formattedValue,userEnteredValue,effectiveValue))'
|
392
|
+
)
|
393
|
+
api_sheet = api_spreadsheet.sheets[0]
|
394
|
+
set_properties(api_sheet.properties)
|
395
|
+
update_cells_from_api_sheet(api_sheet)
|
396
|
+
@v4_requests = []
|
397
|
+
@worksheet_feed_entry = nil
|
319
398
|
true
|
320
399
|
end
|
321
400
|
|
@@ -324,122 +403,59 @@ module GoogleDrive
|
|
324
403
|
sent = false
|
325
404
|
|
326
405
|
if @meta_modified
|
406
|
+
add_request({
|
407
|
+
update_sheet_properties: {
|
408
|
+
properties: {
|
409
|
+
sheet_id: sheet_id,
|
410
|
+
title: title,
|
411
|
+
index: index,
|
412
|
+
grid_properties: {row_count: max_rows, column_count: max_cols},
|
413
|
+
},
|
414
|
+
fields: '*',
|
415
|
+
},
|
416
|
+
})
|
417
|
+
end
|
327
418
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
xmlns:gs='http://schemas.google.com/spreadsheets/2006'>
|
332
|
-
<title>#{h(title)}</title>
|
333
|
-
<gs:rowCount>#{h(max_rows)}</gs:rowCount>
|
334
|
-
<gs:colCount>#{h(max_cols)}</gs:colCount>
|
335
|
-
</entry>
|
336
|
-
EOS
|
337
|
-
|
338
|
-
result = @session.request(
|
339
|
-
:put,
|
340
|
-
edit_url,
|
341
|
-
data: xml,
|
342
|
-
header: {
|
343
|
-
'Content-Type' => 'application/atom+xml;charset=utf-8',
|
344
|
-
'If-Match' => '*'
|
345
|
-
}
|
346
|
-
)
|
347
|
-
set_worksheet_feed_entry(result.root)
|
348
|
-
|
419
|
+
if !@v4_requests.empty?
|
420
|
+
self.spreadsheet.batch_update(@v4_requests)
|
421
|
+
@v4_requests = []
|
349
422
|
sent = true
|
350
423
|
end
|
351
424
|
|
352
|
-
|
353
|
-
# Gets id and edit URL for each cell.
|
354
|
-
# Note that return-empty=true is required to get those info for empty cells.
|
355
|
-
cell_entries = {}
|
356
|
-
rows = @modified.map { |r, _c| r }
|
357
|
-
cols = @modified.map { |_r, c| c }
|
358
|
-
url = concat_url(
|
359
|
-
cells_feed_url,
|
360
|
-
"?return-empty=true&min-row=#{rows.min}&max-row=#{rows.max}" \
|
361
|
-
"&min-col=#{cols.min}&max-col=#{cols.max}"
|
362
|
-
)
|
363
|
-
doc = @session.request(:get, url)
|
425
|
+
@remote_title = @title
|
364
426
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
427
|
+
unless @modified.empty?
|
428
|
+
min_modified_row = 1.0 / 0.0
|
429
|
+
max_modified_row = 0
|
430
|
+
min_modified_col = 1.0 / 0.0
|
431
|
+
max_modified_col = 0
|
432
|
+
@modified.each do |r, c|
|
433
|
+
min_modified_row = r if r < min_modified_row
|
434
|
+
max_modified_row = r if r > max_modified_row
|
435
|
+
min_modified_col = c if c < min_modified_col
|
436
|
+
max_modified_col = c if c > max_modified_col
|
369
437
|
end
|
370
438
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
raise(
|
384
|
-
GoogleDrive::Error,
|
385
|
-
format(
|
386
|
-
"The user doesn't have write permission to the spreadsheet: %p",
|
387
|
-
spreadsheet
|
388
|
-
)
|
389
|
-
)
|
439
|
+
# Uses update_spreadsheet_value instead batch_update_spreadsheet with
|
440
|
+
# update_cells. batch_update_spreadsheet has benefit that the request
|
441
|
+
# can be batched with other requests. But it has drawback that the
|
442
|
+
# type of the value (string_value, number_value, etc.) must be
|
443
|
+
# explicitly specified in user_entered_value. Since I don't know exact
|
444
|
+
# logic to determine the type from text, I chose to use
|
445
|
+
# update_spreadsheet_value here.
|
446
|
+
range = "'%s'!R%dC%d:R%dC%d" %
|
447
|
+
[@title, min_modified_row, min_modified_col, max_modified_row, max_modified_col]
|
448
|
+
values = (min_modified_row..max_modified_row).map do |r|
|
449
|
+
(min_modified_col..max_modified_col).map do |c|
|
450
|
+
@modified.include?([r, c]) ? (@cells[[r, c]] || '') : nil
|
390
451
|
end
|
391
|
-
edit_url = edit_link['href']
|
392
|
-
xml << <<-EOS
|
393
|
-
<entry>
|
394
|
-
<batch:id>#{h(row)},#{h(col)}</batch:id>
|
395
|
-
<batch:operation type="update"/>
|
396
|
-
<id>#{h(id)}</id>
|
397
|
-
<link
|
398
|
-
rel="edit"
|
399
|
-
type="application/atom+xml"
|
400
|
-
href="#{h(edit_url)}"/>
|
401
|
-
<gs:cell
|
402
|
-
row="#{h(row)}"
|
403
|
-
col="#{h(col)}"
|
404
|
-
inputValue="#{h(value)}"/>
|
405
|
-
</entry>
|
406
|
-
EOS
|
407
|
-
end
|
408
|
-
xml << <<-"EOS"
|
409
|
-
</feed>
|
410
|
-
EOS
|
411
|
-
|
412
|
-
batch_url = concat_url(cells_feed_url, '/batch')
|
413
|
-
result = @session.request(
|
414
|
-
:post,
|
415
|
-
batch_url,
|
416
|
-
data: xml,
|
417
|
-
header: {
|
418
|
-
'Content-Type' => 'application/atom+xml;charset=utf-8',
|
419
|
-
'If-Match' => '*'
|
420
|
-
}
|
421
|
-
)
|
422
|
-
result.css('entry').each do |entry|
|
423
|
-
interrupted = entry.css('batch|interrupted')[0]
|
424
|
-
if interrupted
|
425
|
-
raise(
|
426
|
-
GoogleDrive::Error,
|
427
|
-
format('Update has failed: %s', interrupted['reason'])
|
428
|
-
)
|
429
|
-
end
|
430
|
-
next if entry.css('batch|status').first['code'] =~ /^2/
|
431
|
-
raise(
|
432
|
-
GoogleDrive::Error,
|
433
|
-
format(
|
434
|
-
'Updating cell %s has failed: %s',
|
435
|
-
entry.css('id').text, entry.css('batch|status')[0]['reason']
|
436
|
-
)
|
437
|
-
)
|
438
452
|
end
|
453
|
+
value_range = Google::Apis::SheetsV4::ValueRange.new(values: values)
|
454
|
+
@session.sheets_service.update_spreadsheet_value(
|
455
|
+
spreadsheet.id, range, value_range, value_input_option: 'USER_ENTERED')
|
439
456
|
|
440
457
|
@modified.clear
|
441
458
|
sent = true
|
442
|
-
|
443
459
|
end
|
444
460
|
|
445
461
|
sent
|
@@ -454,17 +470,20 @@ module GoogleDrive
|
|
454
470
|
# Deletes this worksheet. Deletion takes effect right away without calling
|
455
471
|
# save().
|
456
472
|
def delete
|
457
|
-
|
458
|
-
|
459
|
-
|
473
|
+
spreadsheet.batch_update([{
|
474
|
+
delete_sheet: Google::Apis::SheetsV4::DeleteSheetRequest.new(sheet_id: sheet_id),
|
475
|
+
}])
|
460
476
|
end
|
461
477
|
|
462
|
-
# Returns true if you have changes made by []= which haven't been saved.
|
478
|
+
# Returns true if you have changes made by []= etc. which haven't been saved.
|
463
479
|
def dirty?
|
464
|
-
!@modified.empty?
|
480
|
+
!@modified.empty? || !@v4_requests.empty?
|
465
481
|
end
|
466
482
|
|
467
483
|
# List feed URL of the worksheet.
|
484
|
+
#
|
485
|
+
# DEPRECATED: This method is deprecated, and now requires additional
|
486
|
+
# network fetch.
|
468
487
|
def list_feed_url
|
469
488
|
@worksheet_feed_entry.css(
|
470
489
|
"link[rel='http://schemas.google.com/spreadsheets/2006#listfeed']"
|
@@ -517,7 +536,7 @@ module GoogleDrive
|
|
517
536
|
end
|
518
537
|
|
519
538
|
def inspect
|
520
|
-
fields = {
|
539
|
+
fields = { spreadsheet_id: spreadsheet.id, gid: gid }
|
521
540
|
fields[:title] = @title if @title
|
522
541
|
format(
|
523
542
|
"\#<%p %s>",
|
@@ -526,39 +545,170 @@ module GoogleDrive
|
|
526
545
|
)
|
527
546
|
end
|
528
547
|
|
529
|
-
|
548
|
+
# Merges a range of cells together. "MERGE_COLUMNS" is another option for merge_type
|
549
|
+
def merge_cells(top_row, left_col, num_rows, num_cols, merge_type: 'MERGE_ALL')
|
550
|
+
range = v4_range_object(top_row, left_col, num_rows, num_cols)
|
551
|
+
add_request({
|
552
|
+
merge_cells:
|
553
|
+
Google::Apis::SheetsV4::MergeCellsRequest.new(
|
554
|
+
range: range, merge_type: merge_type),
|
555
|
+
})
|
556
|
+
end
|
557
|
+
|
558
|
+
# Changes the formatting of a range of cells to match the given number format.
|
559
|
+
# For example to change A1 to a percentage with 1 decimal point:
|
560
|
+
# worksheet.set_number_format(1, 1, 1, 1, "##.#%")
|
561
|
+
# Google API reference: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#numberformat
|
562
|
+
def set_number_format(top_row, left_col, num_rows, num_cols, pattern, type: "NUMBER")
|
563
|
+
number_format = Google::Apis::SheetsV4::NumberFormat.new(type: type, pattern: pattern)
|
564
|
+
format = Google::Apis::SheetsV4::CellFormat.new(number_format: number_format)
|
565
|
+
fields = 'userEnteredFormat(numberFormat)'
|
566
|
+
format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
567
|
+
end
|
568
|
+
|
569
|
+
# Changes text alignment of a range of cells.
|
570
|
+
# Horizontal alignment can be "LEFT", "CENTER", or "RIGHT".
|
571
|
+
# Vertical alignment can be "TOP", "MIDDLE", or "BOTTOM".
|
572
|
+
# Google API reference: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#HorizontalAlign
|
573
|
+
def set_text_alignment(
|
574
|
+
top_row, left_col, num_rows, num_cols,
|
575
|
+
horizontal: nil, vertical: nil)
|
576
|
+
return if horizontal.nil? && vertical.nil?
|
577
|
+
|
578
|
+
format = Google::Apis::SheetsV4::CellFormat.new(
|
579
|
+
horizontal_alignment: horizontal, vertical_alignment: vertical)
|
580
|
+
subfields =
|
581
|
+
(horizontal.nil? ? [] : ['horizontalAlignment']) +
|
582
|
+
(vertical.nil? ? [] : ['verticalAlignment'])
|
583
|
+
|
584
|
+
fields = 'userEnteredFormat(%s)' % subfields.join(',')
|
585
|
+
format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
586
|
+
end
|
587
|
+
|
588
|
+
# Changes the background color on a range of cells. e.g.:
|
589
|
+
# worksheet.set_background_color(1, 1, 1, 1, GoogleDrive::Worksheet::Colors::DARK_YELLOW_1)
|
590
|
+
#
|
591
|
+
# background_color is an instance of Google::Apis::SheetsV4::Color.
|
592
|
+
def set_background_color(top_row, left_col, num_rows, num_cols, background_color)
|
593
|
+
format = Google::Apis::SheetsV4::CellFormat.new(background_color: background_color)
|
594
|
+
fields = 'userEnteredFormat(backgroundColor)'
|
595
|
+
format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
596
|
+
end
|
597
|
+
|
598
|
+
# Change the text formatting on a range of cells. e.g., To set cell
|
599
|
+
# A1 to have red text that is bold and italic:
|
600
|
+
# worksheet.set_text_format(
|
601
|
+
# 1, 1, 1, 1,
|
602
|
+
# bold: true,
|
603
|
+
# italic: true,
|
604
|
+
# foreground_color: GoogleDrive::Worksheet::Colors::RED_BERRY)
|
605
|
+
#
|
606
|
+
# foreground_color is an instance of Google::Apis::SheetsV4::Color.
|
607
|
+
# Google API reference:
|
608
|
+
# https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#textformat
|
609
|
+
def set_text_format(top_row, left_col, num_rows, num_cols, bold: false,
|
610
|
+
italic: false, strikethrough: false, font_size: nil,
|
611
|
+
font_family: nil, foreground_color: nil)
|
612
|
+
text_format = Google::Apis::SheetsV4::TextFormat.new(
|
613
|
+
bold: bold,
|
614
|
+
italic: italic,
|
615
|
+
strikethrough: strikethrough,
|
616
|
+
font_size: font_size,
|
617
|
+
font_family: font_family,
|
618
|
+
foreground_color: foreground_color
|
619
|
+
)
|
530
620
|
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
621
|
+
format = Google::Apis::SheetsV4::CellFormat.new(text_format: text_format)
|
622
|
+
fields = 'userEnteredFormat(textFormat)'
|
623
|
+
format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
624
|
+
end
|
625
|
+
|
626
|
+
# Update the border styles for a range of cells.
|
627
|
+
# borders is a Hash of Google::Apis::SheetsV4::Border keyed with the
|
628
|
+
# following symbols: :top, :bottom, :left, :right, :innerHorizontal, :innerVertical
|
629
|
+
# e.g., To set a black double-line on the bottom of A1:
|
630
|
+
# update_borders(
|
631
|
+
# 1, 1, 1, 1,
|
632
|
+
# {bottom: Google::Apis::SheetsV4::Border.new(
|
633
|
+
# style: "DOUBLE", color: GoogleDrive::Worksheet::Colors::BLACK)})
|
634
|
+
def update_borders(top_row, left_col, num_rows, num_cols, borders)
|
635
|
+
request = Google::Apis::SheetsV4::UpdateBordersRequest.new(borders)
|
636
|
+
request.range = v4_range_object(top_row, left_col, num_rows, num_cols)
|
637
|
+
add_request({update_borders: request})
|
638
|
+
end
|
639
|
+
|
640
|
+
# Add an instance of Google::Apis::SheetsV4::Request (or its Hash
|
641
|
+
# equivalent) which will be applied on the next call to the save method.
|
642
|
+
def add_request(request)
|
643
|
+
@v4_requests.push(request)
|
537
644
|
end
|
538
645
|
|
539
|
-
|
540
|
-
|
541
|
-
|
646
|
+
# @api private
|
647
|
+
def worksheet_feed_id
|
648
|
+
gid_int = sheet_id
|
649
|
+
xor_val = gid_int > 31578 ? 474 : 31578
|
650
|
+
letter = gid_int > 31578 ? 'o' : ''
|
651
|
+
letter + (gid_int ^ xor_val).to_s(36)
|
652
|
+
end
|
653
|
+
|
654
|
+
private
|
655
|
+
|
656
|
+
def format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
657
|
+
add_request({
|
658
|
+
repeat_cell:
|
659
|
+
Google::Apis::SheetsV4::RepeatCellRequest.new(
|
660
|
+
range: v4_range_object(top_row, left_col, num_rows, num_cols),
|
661
|
+
cell: Google::Apis::SheetsV4::CellData.new(user_entered_format: format),
|
662
|
+
fields: fields
|
663
|
+
),
|
664
|
+
})
|
665
|
+
end
|
666
|
+
|
667
|
+
def set_properties(properties)
|
668
|
+
@properties = properties
|
669
|
+
@title = @remote_title = properties.title
|
670
|
+
@index = properties.index
|
671
|
+
if properties.grid_properties.nil?
|
672
|
+
@max_rows = @max_cols = 0
|
673
|
+
else
|
674
|
+
@max_rows = properties.grid_properties.row_count
|
675
|
+
@max_cols = properties.grid_properties.column_count
|
676
|
+
end
|
677
|
+
@meta_modified = false
|
542
678
|
end
|
543
679
|
|
544
680
|
def reload_cells
|
545
|
-
|
681
|
+
response =
|
682
|
+
@session.sheets_service.get_spreadsheet(
|
683
|
+
spreadsheet.id,
|
684
|
+
ranges: "'%s'" % @remote_title,
|
685
|
+
fields: 'sheets.data.rowData.values(formattedValue,userEnteredValue,effectiveValue)'
|
686
|
+
)
|
687
|
+
update_cells_from_api_sheet(response.sheets[0])
|
688
|
+
end
|
546
689
|
|
547
|
-
|
548
|
-
|
690
|
+
def update_cells_from_api_sheet(api_sheet)
|
691
|
+
rows_data = api_sheet.data[0].row_data || []
|
549
692
|
|
693
|
+
@num_rows = rows_data.size
|
694
|
+
@num_cols = 0
|
550
695
|
@cells = {}
|
551
696
|
@input_values = {}
|
552
697
|
@numeric_values = {}
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
698
|
+
|
699
|
+
rows_data.each_with_index do |row_data, r|
|
700
|
+
next if !row_data.values
|
701
|
+
@num_cols = row_data.values.size if row_data.values.size > @num_cols
|
702
|
+
row_data.values.each_with_index do |cell_data, c|
|
703
|
+
k = [r + 1, c + 1]
|
704
|
+
@cells[k] = cell_data.formatted_value || ''
|
705
|
+
@input_values[k] = extended_value_to_str(cell_data.user_entered_value)
|
706
|
+
@numeric_values[k] =
|
707
|
+
cell_data.effective_value && cell_data.effective_value.number_value ?
|
708
|
+
cell_data.effective_value.number_value.to_f : nil
|
709
|
+
end
|
561
710
|
end
|
711
|
+
|
562
712
|
@modified.clear
|
563
713
|
end
|
564
714
|
|
@@ -589,12 +739,32 @@ module GoogleDrive
|
|
589
739
|
end
|
590
740
|
|
591
741
|
def validate_cell_value(value)
|
592
|
-
if value =~
|
742
|
+
if value =~ XML_INVALID_CHAR_REGEXP
|
593
743
|
raise(
|
594
744
|
ArgumentError,
|
595
745
|
format('Contains invalid character %p for XML 1.0: %p', $&, value)
|
596
746
|
)
|
597
747
|
end
|
598
748
|
end
|
749
|
+
|
750
|
+
def v4_range_object(top_row, left_col, num_rows, num_cols)
|
751
|
+
Google::Apis::SheetsV4::GridRange.new(
|
752
|
+
sheet_id: sheet_id,
|
753
|
+
start_row_index: top_row - 1,
|
754
|
+
start_column_index: left_col - 1,
|
755
|
+
end_row_index: top_row + num_rows - 1,
|
756
|
+
end_column_index: left_col + num_cols - 1
|
757
|
+
)
|
758
|
+
end
|
759
|
+
|
760
|
+
def extended_value_to_str(extended_value)
|
761
|
+
return '' if !extended_value
|
762
|
+
value =
|
763
|
+
extended_value.number_value ||
|
764
|
+
extended_value.string_value ||
|
765
|
+
extended_value.bool_value ||
|
766
|
+
extended_value.formula_value
|
767
|
+
value.to_s
|
768
|
+
end
|
599
769
|
end
|
600
770
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google_drive
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroshi Ichikawa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -31,25 +31,45 @@ dependencies:
|
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 2.0.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name: google-
|
34
|
+
name: google-apis-drive_v3
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.
|
39
|
+
version: 0.5.0
|
40
40
|
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 0.
|
42
|
+
version: 1.0.0
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: 0.
|
49
|
+
version: 0.5.0
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.0.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: google-apis-sheets_v4
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 0.4.0
|
50
60
|
- - "<"
|
51
61
|
- !ruby/object:Gem::Version
|
52
|
-
version: 0.
|
62
|
+
version: 1.0.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.4.0
|
70
|
+
- - "<"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 1.0.0
|
53
73
|
- !ruby/object:Gem::Dependency
|
54
74
|
name: googleauth
|
55
75
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,8 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
188
|
- !ruby/object:Gem::Version
|
169
189
|
version: '0'
|
170
190
|
requirements: []
|
171
|
-
|
172
|
-
rubygems_version: 2.6.14
|
191
|
+
rubygems_version: 3.2.3
|
173
192
|
signing_key:
|
174
193
|
specification_version: 4
|
175
194
|
summary: A library to read/write files/spreadsheets in Google Drive/Docs.
|