google_drive 2.1.12 → 3.0.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +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
|