google_drive 2.1.12 → 3.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/google_drive/acl.rb +4 -4
- data/lib/google_drive/api_client_fetcher.rb +23 -17
- data/lib/google_drive/collection.rb +3 -3
- data/lib/google_drive/file.rb +9 -9
- data/lib/google_drive/session.rb +27 -14
- data/lib/google_drive/spreadsheet.rb +41 -24
- data/lib/google_drive/worksheet.rb +298 -162
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37e8e8318c40d62af473e05a2fbed3a4fc6c87c8
|
4
|
+
data.tar.gz: 8dce5cbb7f5bdcee6bf868099f45bf3cb508a3ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bccc7a33f9b60ec60efaaf7fe6cdacc7f5e0db6e4d5c05d083e2c1c31621871bcdac0fdf81acd1cb0c4b7ba40690145bdb63a619478c32c4638ca1c5431bd944
|
7
|
+
data.tar.gz: f827099020aef331134319588747b39e8acf7a58d4525a54038aed01b2e1f6ae2b16179a9fd757cd60d038bcffa795c667a69921548c423879431bb9f3d38fdf
|
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,7 +21,7 @@ module GoogleDrive
|
|
21
21
|
def initialize(session, file)
|
22
22
|
@session = session
|
23
23
|
@file = file
|
24
|
-
api_permissions = @session.
|
24
|
+
api_permissions = @session.drive_service.list_permissions(
|
25
25
|
@file.id, fields: '*', supports_team_drives: true
|
26
26
|
)
|
27
27
|
@entries =
|
@@ -70,7 +70,7 @@ 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
76
|
{ fields: '*', supports_team_drives: true }.merge(options)
|
@@ -85,7 +85,7 @@ module GoogleDrive
|
|
85
85
|
# e.g.
|
86
86
|
# spreadsheet.acl.delete(spreadsheet.acl[1])
|
87
87
|
def delete(entry)
|
88
|
-
@session.
|
88
|
+
@session.drive_service.delete_permission(
|
89
89
|
@file.id, entry.id, supports_team_drives: true
|
90
90
|
)
|
91
91
|
@entries.delete(entry)
|
@@ -93,7 +93,7 @@ module GoogleDrive
|
|
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 },
|
@@ -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,7 +19,7 @@ module GoogleDrive
|
|
19
19
|
|
20
20
|
# Adds the given GoogleDrive::File to the folder.
|
21
21
|
def add(file)
|
22
|
-
@session.
|
22
|
+
@session.drive_service.update_file(
|
23
23
|
file.id, add_parents: id, fields: '', supports_team_drives: true
|
24
24
|
)
|
25
25
|
nil
|
@@ -27,7 +27,7 @@ module GoogleDrive
|
|
27
27
|
|
28
28
|
# Removes the given GoogleDrive::File from the folder.
|
29
29
|
def remove(file)
|
30
|
-
@session.
|
30
|
+
@session.drive_service.update_file(
|
31
31
|
file.id, remove_parents: id, fields: '', supports_team_drives: true
|
32
32
|
)
|
33
33
|
end
|
@@ -61,7 +61,7 @@ module GoogleDrive
|
|
61
61
|
parents: [id]
|
62
62
|
}.merge(file_properties)
|
63
63
|
|
64
|
-
file = @session.
|
64
|
+
file = @session.drive_service.create_file(
|
65
65
|
file_metadata, fields: '*', supports_team_drives: true
|
66
66
|
)
|
67
67
|
|
data/lib/google_drive/file.rb
CHANGED
@@ -38,7 +38,7 @@ module GoogleDrive
|
|
38
38
|
|
39
39
|
# Reloads file metadata such as title and acl.
|
40
40
|
def reload_metadata
|
41
|
-
@api_file = @session.
|
41
|
+
@api_file = @session.drive_service.get_file(
|
42
42
|
id, fields: '*', supports_team_drives: true
|
43
43
|
)
|
44
44
|
@acl = Acl.new(@session, self) if @acl
|
@@ -94,7 +94,7 @@ 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
99
|
{ download_dest: path, supports_team_drives: true }.merge(params)
|
100
100
|
)
|
@@ -113,7 +113,7 @@ 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
118
|
{ download_dest: io, supports_team_drives: true }.merge(params)
|
119
119
|
)
|
@@ -185,7 +185,7 @@ module GoogleDrive
|
|
185
185
|
# Reads content from +io+ and updates the file with the content.
|
186
186
|
def update_from_io(io, params = {})
|
187
187
|
params = { upload_source: io, supports_team_drives: true }.merge(params)
|
188
|
-
@session.
|
188
|
+
@session.drive_service.update_file(id, nil, params)
|
189
189
|
nil
|
190
190
|
end
|
191
191
|
|
@@ -193,9 +193,9 @@ 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_team_drives: true)
|
197
197
|
else
|
198
|
-
@session.
|
198
|
+
@session.drive_service.update_file(
|
199
199
|
id, { trashed: true }, supports_team_drives: true
|
200
200
|
)
|
201
201
|
end
|
@@ -204,7 +204,7 @@ module GoogleDrive
|
|
204
204
|
|
205
205
|
# Renames title of the file.
|
206
206
|
def rename(title)
|
207
|
-
@session.
|
207
|
+
@session.drive_service.update_file(
|
208
208
|
id, { name: title }, supports_team_drives: true
|
209
209
|
)
|
210
210
|
nil
|
@@ -214,7 +214,7 @@ 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.
|
217
|
+
api_file = @session.drive_service.copy_file(
|
218
218
|
id, { name: title }.merge(file_properties), fields: '*', supports_team_drives: true
|
219
219
|
)
|
220
220
|
@session.wrap_api_file(api_file)
|
@@ -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
@@ -219,10 +219,17 @@ module GoogleDrive
|
|
219
219
|
attr_accessor :on_auth_fail
|
220
220
|
|
221
221
|
# Returns an instance of Google::Apis::DriveV3::DriveService.
|
222
|
-
def
|
222
|
+
def drive_service
|
223
223
|
@fetcher.drive
|
224
224
|
end
|
225
225
|
|
226
|
+
alias drive drive_service
|
227
|
+
|
228
|
+
# Returns an instance of Google::Apis::SheetsV4::SheetsService.
|
229
|
+
def sheets_service
|
230
|
+
@fetcher.sheets
|
231
|
+
end
|
232
|
+
|
226
233
|
# Returns list of files for the user as array of GoogleDrive::File or its
|
227
234
|
# subclass. You can specify parameters documented at
|
228
235
|
# https://developers.google.com/drive/v3/web/search-parameters
|
@@ -247,7 +254,7 @@ module GoogleDrive
|
|
247
254
|
def files(params = {}, &block)
|
248
255
|
params = convert_params(params)
|
249
256
|
execute_paged!(
|
250
|
-
method:
|
257
|
+
method: drive_service.method(:list_files),
|
251
258
|
parameters: { fields: '*', supports_team_drives: true }.merge(params),
|
252
259
|
items_method_name: :files,
|
253
260
|
converter: proc { |af| wrap_api_file(af) },
|
@@ -280,7 +287,7 @@ module GoogleDrive
|
|
280
287
|
# Returns an instance of GoogleDrive::File or its subclass
|
281
288
|
# (GoogleDrive::Spreadsheet, GoogleDrive::Collection).
|
282
289
|
def file_by_id(id)
|
283
|
-
api_file =
|
290
|
+
api_file = drive_service.get_file(id, fields: '*', supports_team_drives: true)
|
284
291
|
wrap_api_file(api_file)
|
285
292
|
end
|
286
293
|
|
@@ -379,13 +386,12 @@ module GoogleDrive
|
|
379
386
|
# "1smypkyAz4STrKO4Zkos5Z4UPUJKvvgIza32LnlQ7OGw/od7/private/full")
|
380
387
|
def worksheet_by_url(url)
|
381
388
|
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)}"
|
389
|
+
when %r{^https?://spreadsheets.google.com/feeds/worksheets/(.*)/.*/full/(.*)$}
|
390
|
+
spreadsheet_id = Regexp.last_match(1)
|
391
|
+
worksheet_feed_id = Regexp.last_match(2)
|
392
|
+
when %r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full(\?.*)?$}
|
393
|
+
spreadsheet_id = Regexp.last_match(1)
|
394
|
+
worksheet_feed_id = Regexp.last_match(2)
|
389
395
|
else
|
390
396
|
raise(
|
391
397
|
GoogleDrive::Error,
|
@@ -394,8 +400,15 @@ module GoogleDrive
|
|
394
400
|
)
|
395
401
|
end
|
396
402
|
|
397
|
-
|
398
|
-
|
403
|
+
spreadsheet = spreadsheet_by_key(spreadsheet_id)
|
404
|
+
worksheet = spreadsheet.worksheets.find{ |ws| ws.worksheet_feed_id == worksheet_feed_id }
|
405
|
+
unless worksheet
|
406
|
+
raise(
|
407
|
+
GoogleDrive::Error,
|
408
|
+
"Worksheet not found for the given URL: #{url}"
|
409
|
+
)
|
410
|
+
end
|
411
|
+
worksheet
|
399
412
|
end
|
400
413
|
|
401
414
|
# Returns the root folder.
|
@@ -496,7 +509,7 @@ module GoogleDrive
|
|
496
509
|
name: title,
|
497
510
|
}.merge(file_properties)
|
498
511
|
|
499
|
-
file =
|
512
|
+
file = drive_service.create_file(
|
500
513
|
file_metadata, fields: '*', supports_team_drives: true
|
501
514
|
)
|
502
515
|
|
@@ -661,7 +674,7 @@ module GoogleDrive
|
|
661
674
|
end
|
662
675
|
file_metadata[:parents] = params[:parents] if params[:parents]
|
663
676
|
|
664
|
-
file =
|
677
|
+
file = drive_service.create_file(file_metadata, api_params)
|
665
678
|
wrap_api_file(file)
|
666
679
|
end
|
667
680
|
|
@@ -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,6 +16,37 @@ 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
|
@@ -23,44 +54,63 @@ module GoogleDrive
|
|
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
|
+
# GoogleDrive::Spreadsheet which this worksheet belongs to.
|
84
|
+
attr_reader :spreadsheet
|
43
85
|
|
44
86
|
# Time object which represents the time the worksheet was last updated.
|
45
|
-
|
87
|
+
#
|
88
|
+
# DEPRECATED: From google_drive 3.0.0, it returns the time the
|
89
|
+
# *spreadsheet* was last updated, instead of the worksheet. This is because
|
90
|
+
# it looks the information is not available in Sheets v4 API.
|
91
|
+
def updated
|
92
|
+
spreadsheet.modified_time.to_time
|
93
|
+
end
|
46
94
|
|
47
95
|
# URL of cell-based feed of the worksheet.
|
96
|
+
#
|
97
|
+
# DEPRECATED: This method is deprecated, and now requires additional
|
98
|
+
# network fetch.
|
48
99
|
def cells_feed_url
|
49
|
-
|
100
|
+
worksheet_feed_entry.css(
|
50
101
|
"link[rel='http://schemas.google.com/spreadsheets/2006#cellsfeed']"
|
51
102
|
)[0]['href']
|
52
103
|
end
|
53
104
|
|
54
105
|
# URL of worksheet feed URL of the worksheet.
|
55
106
|
def worksheet_feed_url
|
56
|
-
|
107
|
+
return '%s/%s' % [spreadsheet.worksheets_feed_url, worksheet_feed_id]
|
57
108
|
end
|
58
109
|
|
59
110
|
# URL to export the worksheet as CSV.
|
60
111
|
def csv_export_url
|
61
|
-
|
62
|
-
|
63
|
-
)[0]['href']
|
112
|
+
'https://docs.google.com/spreadsheets/d/%s/export?gid=%s&format=csv' %
|
113
|
+
[spreadsheet.id, gid]
|
64
114
|
end
|
65
115
|
|
66
116
|
# Exports the worksheet as String in CSV format.
|
@@ -74,10 +124,14 @@ module GoogleDrive
|
|
74
124
|
open(path, 'wb') { |f| f.write(data) }
|
75
125
|
end
|
76
126
|
|
77
|
-
#
|
127
|
+
# ID of the worksheet.
|
128
|
+
def sheet_id
|
129
|
+
@properties.sheet_id
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns sheet_id.to_s.
|
78
133
|
def gid
|
79
|
-
|
80
|
-
CGI.parse(URI.parse(csv_export_url).query)['gid'].last
|
134
|
+
sheet_id.to_s
|
81
135
|
end
|
82
136
|
|
83
137
|
# URL to view/edit the worksheet in a Web browser.
|
@@ -85,20 +139,6 @@ module GoogleDrive
|
|
85
139
|
format("%s\#gid=%s", spreadsheet.human_url, gid)
|
86
140
|
end
|
87
141
|
|
88
|
-
# GoogleDrive::Spreadsheet which this worksheet belongs to.
|
89
|
-
def spreadsheet
|
90
|
-
unless @spreadsheet
|
91
|
-
unless worksheet_feed_url =~
|
92
|
-
%r{https?://spreadsheets\.google\.com/feeds/worksheets/(.*)/(.*)$}
|
93
|
-
raise(GoogleDrive::Error,
|
94
|
-
'Worksheet feed URL is in unknown format: ' \
|
95
|
-
"#{worksheet_feed_url}")
|
96
|
-
end
|
97
|
-
@spreadsheet = @session.file_by_id(Regexp.last_match(1))
|
98
|
-
end
|
99
|
-
@spreadsheet
|
100
|
-
end
|
101
|
-
|
102
142
|
# Returns content of the cell as String. Arguments must be either
|
103
143
|
# (row number, column number) or cell name. Top-left cell is [1, 1].
|
104
144
|
#
|
@@ -314,8 +354,19 @@ module GoogleDrive
|
|
314
354
|
# Note that changes you made by []= etc. is discarded if you haven't called
|
315
355
|
# save().
|
316
356
|
def reload
|
317
|
-
|
318
|
-
|
357
|
+
api_spreadsheet =
|
358
|
+
@session.sheets_service.get_spreadsheet(
|
359
|
+
spreadsheet.id,
|
360
|
+
ranges: "'%s'" % @title,
|
361
|
+
fields:
|
362
|
+
'sheets(properties,data.rowData.values' \
|
363
|
+
'(formattedValue,userEnteredValue,effectiveValue))'
|
364
|
+
)
|
365
|
+
api_sheet = api_spreadsheet.sheets[0]
|
366
|
+
set_properties(api_sheet.properties)
|
367
|
+
update_cells_from_api_sheet(api_sheet)
|
368
|
+
@v4_requests = []
|
369
|
+
@worksheet_feed_entry = nil
|
319
370
|
true
|
320
371
|
end
|
321
372
|
|
@@ -324,122 +375,58 @@ module GoogleDrive
|
|
324
375
|
sent = false
|
325
376
|
|
326
377
|
if @meta_modified
|
378
|
+
add_request({
|
379
|
+
update_sheet_properties: {
|
380
|
+
properties: {
|
381
|
+
sheet_id: sheet_id,
|
382
|
+
title: title,
|
383
|
+
grid_properties: {row_count: max_rows, column_count: max_cols},
|
384
|
+
},
|
385
|
+
fields: '*',
|
386
|
+
},
|
387
|
+
})
|
388
|
+
end
|
327
389
|
|
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
|
-
|
390
|
+
if !@v4_requests.empty?
|
391
|
+
self.spreadsheet.batch_update(@v4_requests)
|
392
|
+
@v4_requests = []
|
349
393
|
sent = true
|
350
394
|
end
|
395
|
+
|
396
|
+
@remote_title = @title
|
351
397
|
|
352
398
|
unless @modified.empty?
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
)
|
363
|
-
doc = @session.request(:get, url)
|
364
|
-
|
365
|
-
doc.css('entry').each do |entry|
|
366
|
-
row = entry.css('gs|cell')[0]['row'].to_i
|
367
|
-
col = entry.css('gs|cell')[0]['col'].to_i
|
368
|
-
cell_entries[[row, col]] = entry
|
369
|
-
end
|
370
|
-
|
371
|
-
xml = <<-EOS
|
372
|
-
<feed xmlns="http://www.w3.org/2005/Atom"
|
373
|
-
xmlns:batch="http://schemas.google.com/gdata/batch"
|
374
|
-
xmlns:gs="http://schemas.google.com/spreadsheets/2006">
|
375
|
-
<id>#{h(cells_feed_url)}</id>
|
376
|
-
EOS
|
377
|
-
@modified.each do |row, col|
|
378
|
-
value = @cells[[row, col]]
|
379
|
-
entry = cell_entries[[row, col]]
|
380
|
-
id = entry.css('id').text
|
381
|
-
edit_link = entry.css("link[rel='edit']")[0]
|
382
|
-
unless edit_link
|
383
|
-
raise(
|
384
|
-
GoogleDrive::Error,
|
385
|
-
format(
|
386
|
-
"The user doesn't have write permission to the spreadsheet: %p",
|
387
|
-
spreadsheet
|
388
|
-
)
|
389
|
-
)
|
390
|
-
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
|
399
|
+
min_modified_row = 1.0 / 0.0
|
400
|
+
max_modified_row = 0
|
401
|
+
min_modified_col = 1.0 / 0.0
|
402
|
+
max_modified_col = 0
|
403
|
+
@modified.each do |r, c|
|
404
|
+
min_modified_row = r if r < min_modified_row
|
405
|
+
max_modified_row = r if r > max_modified_row
|
406
|
+
min_modified_col = c if c < min_modified_col
|
407
|
+
max_modified_col = c if c > max_modified_col
|
407
408
|
end
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
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
|
-
)
|
409
|
+
|
410
|
+
# Uses update_spreadsheet_value instead batch_update_spreadsheet with
|
411
|
+
# update_cells. batch_update_spreadsheet has benefit that the request
|
412
|
+
# can be batched with other requests. But it has drawback that the
|
413
|
+
# type of the value (string_value, number_value, etc.) must be
|
414
|
+
# explicitly specified in user_entered_value. Since I don't know exact
|
415
|
+
# logic to determine the type from text, I chose to use
|
416
|
+
# update_spreadsheet_value here.
|
417
|
+
range = "'%s'!R%dC%d:R%dC%d" %
|
418
|
+
[@title, min_modified_row, min_modified_col, max_modified_row, max_modified_col]
|
419
|
+
values = (min_modified_row..max_modified_row).map do |r|
|
420
|
+
(min_modified_col..max_modified_col).map do |c|
|
421
|
+
@modified.include?([r, c]) ? (@cells[[r, c]] || '') : nil
|
429
422
|
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
423
|
end
|
424
|
+
value_range = Google::Apis::SheetsV4::ValueRange.new(values: values)
|
425
|
+
@session.sheets_service.update_spreadsheet_value(
|
426
|
+
spreadsheet.id, range, value_range, value_input_option: 'USER_ENTERED')
|
439
427
|
|
440
428
|
@modified.clear
|
441
429
|
sent = true
|
442
|
-
|
443
430
|
end
|
444
431
|
|
445
432
|
sent
|
@@ -454,17 +441,20 @@ module GoogleDrive
|
|
454
441
|
# Deletes this worksheet. Deletion takes effect right away without calling
|
455
442
|
# save().
|
456
443
|
def delete
|
457
|
-
|
458
|
-
|
459
|
-
|
444
|
+
spreadsheet.batch_update([{
|
445
|
+
delete_sheet: Google::Apis::SheetsV4::DeleteSheetRequest.new(sheet_id: sheet_id),
|
446
|
+
}])
|
460
447
|
end
|
461
448
|
|
462
|
-
# Returns true if you have changes made by []= which haven't been saved.
|
449
|
+
# Returns true if you have changes made by []= etc. which haven't been saved.
|
463
450
|
def dirty?
|
464
|
-
!@modified.empty?
|
451
|
+
!@modified.empty? || !@v4_requests.empty?
|
465
452
|
end
|
466
453
|
|
467
454
|
# List feed URL of the worksheet.
|
455
|
+
#
|
456
|
+
# DEPRECATED: This method is deprecated, and now requires additional
|
457
|
+
# network fetch.
|
468
458
|
def list_feed_url
|
469
459
|
@worksheet_feed_entry.css(
|
470
460
|
"link[rel='http://schemas.google.com/spreadsheets/2006#listfeed']"
|
@@ -517,7 +507,7 @@ module GoogleDrive
|
|
517
507
|
end
|
518
508
|
|
519
509
|
def inspect
|
520
|
-
fields = {
|
510
|
+
fields = { spreadsheet_id: spreadsheet.id, gid: gid }
|
521
511
|
fields[:title] = @title if @title
|
522
512
|
format(
|
523
513
|
"\#<%p %s>",
|
@@ -526,39 +516,165 @@ module GoogleDrive
|
|
526
516
|
)
|
527
517
|
end
|
528
518
|
|
529
|
-
|
519
|
+
# Merges a range of cells together. "MERGE_COLUMNS" is another option for merge_type
|
520
|
+
def merge_cells(top_row, left_col, num_rows, num_cols, merge_type: 'MERGE_ALL')
|
521
|
+
range = v4_range_object(top_row, left_col, num_rows, num_cols)
|
522
|
+
add_request({
|
523
|
+
merge_cells:
|
524
|
+
Google::Apis::SheetsV4::MergeCellsRequest.new(
|
525
|
+
range: range, merge_type: merge_type),
|
526
|
+
})
|
527
|
+
end
|
528
|
+
|
529
|
+
# Changes the formatting of a range of cells to match the given number format.
|
530
|
+
# For example to change A1 to a percentage with 1 decimal point:
|
531
|
+
# worksheet.set_number_format(1, 1, 1, 1, "##.#%")
|
532
|
+
# Google API reference: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#numberformat
|
533
|
+
def set_number_format(top_row, left_col, num_rows, num_cols, pattern, type: "NUMBER")
|
534
|
+
number_format = Google::Apis::SheetsV4::NumberFormat.new(type: type, pattern: pattern)
|
535
|
+
format = Google::Apis::SheetsV4::CellFormat.new(number_format: number_format)
|
536
|
+
fields = 'userEnteredFormat(numberFormat)'
|
537
|
+
format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
538
|
+
end
|
539
|
+
|
540
|
+
# Changes text alignment of a range of cells.
|
541
|
+
# Horizontal alignment can be "LEFT", "CENTER", or "RIGHT".
|
542
|
+
# Vertical alignment can be "TOP", "MIDDLE", or "BOTTOM".
|
543
|
+
# Google API reference: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#HorizontalAlign
|
544
|
+
def set_text_alignment(
|
545
|
+
top_row, left_col, num_rows, num_cols,
|
546
|
+
horizontal: nil, vertical: nil)
|
547
|
+
return if horizontal.nil? && vertical.nil?
|
548
|
+
|
549
|
+
format = Google::Apis::SheetsV4::CellFormat.new(
|
550
|
+
horizontal_alignment: horizontal, vertical_alignment: vertical)
|
551
|
+
subfields =
|
552
|
+
(horizontal.nil? ? [] : ['horizontalAlignment']) +
|
553
|
+
(vertical.nil? ? [] : ['verticalAlignment'])
|
554
|
+
|
555
|
+
fields = 'userEnteredFormat(%s)' % subfields.join(',')
|
556
|
+
format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
557
|
+
end
|
558
|
+
|
559
|
+
# Changes the background color on a range of cells. e.g.:
|
560
|
+
# worksheet.set_background_color(1, 1, 1, 1, GoogleDrive::Worksheet::Colors::DARK_YELLOW_1)
|
561
|
+
#
|
562
|
+
# background_color is an instance of Google::Apis::SheetsV4::Color.
|
563
|
+
def set_background_color(top_row, left_col, num_rows, num_cols, background_color)
|
564
|
+
format = Google::Apis::SheetsV4::CellFormat.new(background_color: background_color)
|
565
|
+
fields = 'userEnteredFormat(backgroundColor)'
|
566
|
+
format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
567
|
+
end
|
568
|
+
|
569
|
+
# Change the text formatting on a range of cells. e.g., To set cell
|
570
|
+
# A1 to have red text that is bold and italic:
|
571
|
+
# worksheet.set_text_format(
|
572
|
+
# 1, 1, 1, 1,
|
573
|
+
# bold: true,
|
574
|
+
# italic: true,
|
575
|
+
# foreground_color: GoogleDrive::Worksheet::Colors::RED_BERRY)
|
576
|
+
#
|
577
|
+
# foreground_color is an instance of Google::Apis::SheetsV4::Color.
|
578
|
+
# Google API reference:
|
579
|
+
# https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#textformat
|
580
|
+
def set_text_format(top_row, left_col, num_rows, num_cols, bold: false,
|
581
|
+
italic: false, strikethrough: false, font_size: nil,
|
582
|
+
font_family: nil, foreground_color: nil)
|
583
|
+
text_format = Google::Apis::SheetsV4::TextFormat.new(
|
584
|
+
bold: bold,
|
585
|
+
italic: italic,
|
586
|
+
strikethrough: strikethrough,
|
587
|
+
font_size: font_size,
|
588
|
+
font_family: font_family,
|
589
|
+
foreground_color: foreground_color
|
590
|
+
)
|
530
591
|
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
592
|
+
format = Google::Apis::SheetsV4::CellFormat.new(text_format: text_format)
|
593
|
+
fields = 'userEnteredFormat(textFormat)'
|
594
|
+
format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
595
|
+
end
|
596
|
+
|
597
|
+
# Update the border styles for a range of cells.
|
598
|
+
# borders is a Hash of Google::Apis::SheetsV4::Border keyed with the
|
599
|
+
# following symbols: :top, :bottom, :left, :right, :innerHorizontal, :innerVertical
|
600
|
+
# e.g., To set a black double-line on the bottom of A1:
|
601
|
+
# update_borders(
|
602
|
+
# 1, 1, 1, 1,
|
603
|
+
# {bottom: Google::Apis::SheetsV4::Border.new(
|
604
|
+
# style: "DOUBLE", color: GoogleDrive::Worksheet::Colors::BLACK)})
|
605
|
+
def update_borders(top_row, left_col, num_rows, num_cols, borders)
|
606
|
+
request = Google::Apis::SheetsV4::UpdateBordersRequest.new(borders)
|
607
|
+
request.range = v4_range_object(top_row, left_col, num_rows, num_cols)
|
608
|
+
add_request({update_borders: request})
|
609
|
+
end
|
610
|
+
|
611
|
+
# Add an instance of Google::Apis::SheetsV4::Request (or its Hash
|
612
|
+
# equivalent) which will be applied on the next call to the save method.
|
613
|
+
def add_request(request)
|
614
|
+
@v4_requests.push(request)
|
537
615
|
end
|
538
616
|
|
539
|
-
|
540
|
-
|
541
|
-
|
617
|
+
# @api private
|
618
|
+
def worksheet_feed_id
|
619
|
+
gid_int = sheet_id
|
620
|
+
xor_val = gid_int > 31578 ? 474 : 31578
|
621
|
+
letter = gid_int > 31578 ? 'o' : ''
|
622
|
+
letter + (gid_int ^ xor_val).to_s(36)
|
623
|
+
end
|
624
|
+
|
625
|
+
private
|
626
|
+
|
627
|
+
def format_cells(top_row, left_col, num_rows, num_cols, format, fields)
|
628
|
+
add_request({
|
629
|
+
repeat_cell:
|
630
|
+
Google::Apis::SheetsV4::RepeatCellRequest.new(
|
631
|
+
range: v4_range_object(top_row, left_col, num_rows, num_cols),
|
632
|
+
cell: Google::Apis::SheetsV4::CellData.new(user_entered_format: format),
|
633
|
+
fields: fields
|
634
|
+
),
|
635
|
+
})
|
636
|
+
end
|
637
|
+
|
638
|
+
def set_properties(properties)
|
639
|
+
@properties = properties
|
640
|
+
@title = @remote_title = properties.title
|
641
|
+
@max_rows = properties.grid_properties.row_count
|
642
|
+
@max_cols = properties.grid_properties.column_count
|
643
|
+
@meta_modified = false
|
542
644
|
end
|
543
645
|
|
544
646
|
def reload_cells
|
545
|
-
|
647
|
+
response =
|
648
|
+
@session.sheets_service.get_spreadsheet(
|
649
|
+
spreadsheet.id,
|
650
|
+
ranges: "'%s'" % @remote_title,
|
651
|
+
fields: 'sheets.data.rowData.values(formattedValue,userEnteredValue,effectiveValue)'
|
652
|
+
)
|
653
|
+
update_cells_from_api_sheet(response.sheets[0])
|
654
|
+
end
|
546
655
|
|
547
|
-
|
548
|
-
|
656
|
+
def update_cells_from_api_sheet(api_sheet)
|
657
|
+
rows_data = api_sheet.data[0].row_data || []
|
549
658
|
|
659
|
+
@num_rows = rows_data.size
|
660
|
+
@num_cols = 0
|
550
661
|
@cells = {}
|
551
662
|
@input_values = {}
|
552
663
|
@numeric_values = {}
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
664
|
+
|
665
|
+
rows_data.each_with_index do |row_data, r|
|
666
|
+
next if !row_data.values
|
667
|
+
@num_cols = row_data.values.size if row_data.values.size > @num_cols
|
668
|
+
row_data.values.each_with_index do |cell_data, c|
|
669
|
+
k = [r + 1, c + 1]
|
670
|
+
@cells[k] = cell_data.formatted_value || ''
|
671
|
+
@input_values[k] = extended_value_to_str(cell_data.user_entered_value)
|
672
|
+
@numeric_values[k] =
|
673
|
+
cell_data.effective_value && cell_data.effective_value.number_value ?
|
674
|
+
cell_data.effective_value.number_value.to_f : nil
|
675
|
+
end
|
561
676
|
end
|
677
|
+
|
562
678
|
@modified.clear
|
563
679
|
end
|
564
680
|
|
@@ -596,5 +712,25 @@ module GoogleDrive
|
|
596
712
|
)
|
597
713
|
end
|
598
714
|
end
|
715
|
+
|
716
|
+
def v4_range_object(top_row, left_col, num_rows, num_cols)
|
717
|
+
Google::Apis::SheetsV4::GridRange.new(
|
718
|
+
sheet_id: sheet_id,
|
719
|
+
start_row_index: top_row - 1,
|
720
|
+
start_column_index: left_col - 1,
|
721
|
+
end_row_index: top_row + num_rows - 1,
|
722
|
+
end_column_index: left_col + num_cols - 1
|
723
|
+
)
|
724
|
+
end
|
725
|
+
|
726
|
+
def extended_value_to_str(extended_value)
|
727
|
+
return '' if !extended_value
|
728
|
+
value =
|
729
|
+
extended_value.number_value ||
|
730
|
+
extended_value.string_value ||
|
731
|
+
extended_value.bool_value ||
|
732
|
+
extended_value.formula_value
|
733
|
+
value.to_s
|
734
|
+
end
|
599
735
|
end
|
600
736
|
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.0.pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroshi Ichikawa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -164,9 +164,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
164
164
|
version: 2.0.0
|
165
165
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
166
|
requirements:
|
167
|
-
- - "
|
167
|
+
- - ">"
|
168
168
|
- !ruby/object:Gem::Version
|
169
|
-
version:
|
169
|
+
version: 1.3.1
|
170
170
|
requirements: []
|
171
171
|
rubyforge_project:
|
172
172
|
rubygems_version: 2.6.14
|