google_drive 1.0.6 → 2.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.rdoc +3 -7
- data/doc_src/google_drive/acl.rb +13 -17
- data/lib/google_drive.rb +130 -160
- data/lib/google_drive/acl.rb +77 -93
- data/lib/google_drive/acl_entry.rb +149 -105
- data/lib/google_drive/api_client_fetcher.rb +22 -41
- data/lib/google_drive/authentication_error.rb +4 -8
- data/lib/google_drive/collection.rb +127 -149
- data/lib/google_drive/config.rb +23 -25
- data/lib/google_drive/error.rb +3 -3
- data/lib/google_drive/file.rb +215 -273
- data/lib/google_drive/list.rb +108 -113
- data/lib/google_drive/list_row.rb +65 -70
- data/lib/google_drive/response_code_error.rb +11 -16
- data/lib/google_drive/session.rb +412 -444
- data/lib/google_drive/spreadsheet.rb +62 -67
- data/lib/google_drive/util.rb +200 -160
- data/lib/google_drive/worksheet.rb +453 -469
- metadata +60 -22
data/lib/google_drive/list.rb
CHANGED
@@ -1,123 +1,118 @@
|
|
1
1
|
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
2
|
# The license of this source is "New BSD Licence"
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
|
4
|
+
require 'google_drive/util'
|
5
|
+
require 'google_drive/error'
|
6
|
+
require 'google_drive/list_row'
|
8
7
|
|
9
8
|
module GoogleDrive
|
9
|
+
# Provides access to cells using column names.
|
10
|
+
# Use GoogleDrive::Worksheet#list to get GoogleDrive::List object.
|
11
|
+
#--
|
12
|
+
# This is implemented as wrapper of GoogleDrive::Worksheet i.e. using cells
|
13
|
+
# feed, not list feed. In this way, we can easily provide consistent API as
|
14
|
+
# GoogleDrive::Worksheet using save()/reload().
|
15
|
+
class List
|
16
|
+
include(Enumerable)
|
17
|
+
|
18
|
+
def initialize(worksheet) #:nodoc:
|
19
|
+
@worksheet = worksheet
|
20
|
+
end
|
21
|
+
|
22
|
+
# Number of non-empty rows in the worksheet excluding the first row.
|
23
|
+
def size
|
24
|
+
@worksheet.num_rows - 1
|
25
|
+
end
|
10
26
|
|
11
|
-
#
|
12
|
-
#
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# GoogleDrive::Worksheet
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
# Column names i.e. the contents of the first row.
|
60
|
-
# Duplicates are removed.
|
61
|
-
def keys
|
62
|
-
return (1..@worksheet.num_cols).map(){ |i| @worksheet[1, i] }.uniq()
|
63
|
-
end
|
64
|
-
|
65
|
-
# Updates column names i.e. the contents of the first row.
|
66
|
-
#
|
67
|
-
# Note that update is not sent to the server until
|
68
|
-
# you call GoogleDrive::Worksheet#save().
|
69
|
-
def keys=(ary)
|
70
|
-
for i in 1..ary.size
|
71
|
-
@worksheet[1, i] = ary[i - 1]
|
72
|
-
end
|
73
|
-
for i in (ary.size + 1)..@worksheet.num_cols
|
74
|
-
@worksheet[1, i] = ""
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Adds a new row to the bottom.
|
79
|
-
# Keys of +hash+ are colum names (the first row).
|
80
|
-
# Returns GoogleDrive::ListRow for the new row.
|
81
|
-
#
|
82
|
-
# Note that update is not sent to the server until
|
83
|
-
# you call GoogleDrive::Worksheet#save().
|
84
|
-
def push(hash)
|
85
|
-
row = self[self.size]
|
86
|
-
row.update(hash)
|
87
|
-
return row
|
88
|
-
end
|
89
|
-
|
90
|
-
# Returns all rows (except for the first row) as Array of Hash.
|
91
|
-
# Keys of Hash objects are colum names (the first row).
|
92
|
-
def to_hash_array()
|
93
|
-
return self.map(){ |r| r.to_hash() }
|
94
|
-
end
|
95
|
-
|
96
|
-
def get(index, key) #:nodoc:
|
97
|
-
return @worksheet[index + 2, key_to_col(key)]
|
98
|
-
end
|
99
|
-
|
100
|
-
def numeric_value(index, key) #:nodoc:
|
101
|
-
return @worksheet.numeric_value(index + 2, key_to_col(key))
|
102
|
-
end
|
103
|
-
|
104
|
-
def input_value(index, key) #:nodoc:
|
105
|
-
return @worksheet.input_value(index + 2, key_to_col(key))
|
106
|
-
end
|
107
|
-
|
108
|
-
def set(index, key, value) #:nodoc:
|
109
|
-
@worksheet[index + 2, key_to_col(key)] = value
|
110
|
-
end
|
111
|
-
|
112
|
-
private
|
113
|
-
|
114
|
-
def key_to_col(key)
|
115
|
-
key = key.to_s()
|
116
|
-
col = (1..@worksheet.num_cols).find(){ |c| @worksheet[1, c] == key }
|
117
|
-
raise(GoogleDrive::Error, "Column doesn't exist: %p" % key) if !col
|
118
|
-
return col
|
119
|
-
end
|
27
|
+
# Returns Hash-like object (GoogleDrive::ListRow) for the row with the
|
28
|
+
# index. Keys of the object are colum names (the first row).
|
29
|
+
# The second row has index 0.
|
30
|
+
#
|
31
|
+
# Note that updates to the returned object are not sent to the server until
|
32
|
+
# you call GoogleDrive::Worksheet#save().
|
33
|
+
def [](index)
|
34
|
+
ListRow.new(self, index)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Updates the row with the index with the given Hash object.
|
38
|
+
# Keys of +hash+ are colum names (the first row).
|
39
|
+
# The second row has index 0.
|
40
|
+
#
|
41
|
+
# Note that update is not sent to the server until
|
42
|
+
# you call GoogleDrive::Worksheet#save().
|
43
|
+
def []=(index, hash)
|
44
|
+
self[index].replace(hash)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Iterates over Hash-like object (GoogleDrive::ListRow) for each row
|
48
|
+
# (except for the first row).
|
49
|
+
# Keys of the object are colum names (the first row).
|
50
|
+
def each(&_block)
|
51
|
+
for i in 0...size
|
52
|
+
yield(self[i])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Column names i.e. the contents of the first row.
|
57
|
+
# Duplicates are removed.
|
58
|
+
def keys
|
59
|
+
(1..@worksheet.num_cols).map { |i| @worksheet[1, i] }.uniq
|
60
|
+
end
|
61
|
+
|
62
|
+
# Updates column names i.e. the contents of the first row.
|
63
|
+
#
|
64
|
+
# Note that update is not sent to the server until
|
65
|
+
# you call GoogleDrive::Worksheet#save().
|
66
|
+
def keys=(ary)
|
67
|
+
for i in 1..ary.size
|
68
|
+
@worksheet[1, i] = ary[i - 1]
|
69
|
+
end
|
70
|
+
for i in (ary.size + 1)..@worksheet.num_cols
|
71
|
+
@worksheet[1, i] = ''
|
72
|
+
end
|
73
|
+
end
|
120
74
|
|
75
|
+
# Adds a new row to the bottom.
|
76
|
+
# Keys of +hash+ are colum names (the first row).
|
77
|
+
# Returns GoogleDrive::ListRow for the new row.
|
78
|
+
#
|
79
|
+
# Note that update is not sent to the server until
|
80
|
+
# you call GoogleDrive::Worksheet#save().
|
81
|
+
def push(hash)
|
82
|
+
row = self[size]
|
83
|
+
row.update(hash)
|
84
|
+
row
|
121
85
|
end
|
122
86
|
|
87
|
+
# Returns all rows (except for the first row) as Array of Hash.
|
88
|
+
# Keys of Hash objects are colum names (the first row).
|
89
|
+
def to_hash_array
|
90
|
+
map(&:to_hash)
|
91
|
+
end
|
92
|
+
|
93
|
+
def get(index, key) #:nodoc:
|
94
|
+
@worksheet[index + 2, key_to_col(key)]
|
95
|
+
end
|
96
|
+
|
97
|
+
def numeric_value(index, key) #:nodoc:
|
98
|
+
@worksheet.numeric_value(index + 2, key_to_col(key))
|
99
|
+
end
|
100
|
+
|
101
|
+
def input_value(index, key) #:nodoc:
|
102
|
+
@worksheet.input_value(index + 2, key_to_col(key))
|
103
|
+
end
|
104
|
+
|
105
|
+
def set(index, key, value) #:nodoc:
|
106
|
+
@worksheet[index + 2, key_to_col(key)] = value
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def key_to_col(key)
|
112
|
+
key = key.to_s
|
113
|
+
col = (1..@worksheet.num_cols).find { |c| @worksheet[1, c] == key }
|
114
|
+
fail(GoogleDrive::Error, "Column doesn't exist: %p" % key) unless col
|
115
|
+
col
|
116
|
+
end
|
117
|
+
end
|
123
118
|
end
|
@@ -1,92 +1,87 @@
|
|
1
1
|
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
2
|
# The license of this source is "New BSD Licence"
|
3
3
|
|
4
|
-
require
|
5
|
-
|
6
|
-
require "google_drive/util"
|
7
|
-
require "google_drive/error"
|
4
|
+
require 'forwardable'
|
8
5
|
|
6
|
+
require 'google_drive/util'
|
7
|
+
require 'google_drive/error'
|
9
8
|
|
10
9
|
module GoogleDrive
|
10
|
+
# Hash-like object returned by GoogleDrive::List#[].
|
11
|
+
class ListRow
|
12
|
+
include(Enumerable)
|
13
|
+
extend(Forwardable)
|
14
|
+
|
15
|
+
def_delegators(:to_hash,
|
16
|
+
:keys, :values, :each_key, :each_value, :each, :each_pair, :hash,
|
17
|
+
:assoc, :fetch, :flatten, :key, :invert, :size, :length, :rassoc,
|
18
|
+
:merge, :reject, :select, :sort, :to_a, :values_at)
|
19
|
+
|
20
|
+
def initialize(list, index) #:nodoc:
|
21
|
+
@list = list
|
22
|
+
@index = index
|
23
|
+
end
|
11
24
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
include(Enumerable)
|
16
|
-
extend(Forwardable)
|
17
|
-
|
18
|
-
def_delegators(:to_hash,
|
19
|
-
:keys, :values, :each_key, :each_value, :each, :each_pair, :hash,
|
20
|
-
:assoc, :fetch, :flatten, :key, :invert, :size, :length, :rassoc,
|
21
|
-
:merge, :reject, :select, :sort, :to_a, :values_at)
|
22
|
-
|
23
|
-
def initialize(list, index) #:nodoc:
|
24
|
-
@list = list
|
25
|
-
@index = index
|
26
|
-
end
|
27
|
-
|
28
|
-
def [](key)
|
29
|
-
return @list.get(@index, key)
|
30
|
-
end
|
31
|
-
|
32
|
-
def numeric_value(key)
|
33
|
-
return @list.numeric_value(@index, key)
|
34
|
-
end
|
25
|
+
def [](key)
|
26
|
+
@list.get(@index, key)
|
27
|
+
end
|
35
28
|
|
36
|
-
|
37
|
-
|
38
|
-
|
29
|
+
def numeric_value(key)
|
30
|
+
@list.numeric_value(@index, key)
|
31
|
+
end
|
39
32
|
|
40
|
-
|
41
|
-
|
42
|
-
|
33
|
+
def input_value(key)
|
34
|
+
@list.input_value(@index, key)
|
35
|
+
end
|
43
36
|
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
def []=(key, value)
|
38
|
+
@list.set(@index, key, value)
|
39
|
+
end
|
47
40
|
|
48
|
-
|
49
|
-
|
50
|
-
|
41
|
+
def has_key?(key)
|
42
|
+
@list.keys.include?(key)
|
43
|
+
end
|
51
44
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
45
|
+
alias_method :include?, :has_key?
|
46
|
+
alias_method :key?, :has_key?
|
47
|
+
alias_method :member?, :has_key?
|
57
48
|
|
58
|
-
|
49
|
+
def update(hash)
|
50
|
+
hash.each do |k, v|
|
51
|
+
self[k] = v
|
52
|
+
end
|
53
|
+
end
|
59
54
|
|
60
|
-
|
61
|
-
clear()
|
62
|
-
update(hash)
|
63
|
-
end
|
55
|
+
alias_method :merge!, :update
|
64
56
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
57
|
+
def replace(hash)
|
58
|
+
clear
|
59
|
+
update(hash)
|
60
|
+
end
|
70
61
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
return result
|
77
|
-
end
|
62
|
+
def clear
|
63
|
+
@list.keys.each do |key|
|
64
|
+
self[key] = ''
|
65
|
+
end
|
66
|
+
end
|
78
67
|
|
79
|
-
|
80
|
-
|
81
|
-
|
68
|
+
def to_hash
|
69
|
+
result = {}
|
70
|
+
@list.keys.each do |key|
|
71
|
+
result[key] = self[key]
|
72
|
+
end
|
73
|
+
result
|
74
|
+
end
|
82
75
|
|
83
|
-
|
84
|
-
|
76
|
+
def ==(other)
|
77
|
+
self.class == other.class && to_hash == other.to_hash
|
78
|
+
end
|
85
79
|
|
86
|
-
|
87
|
-
|
88
|
-
end
|
80
|
+
alias_method :===, :==
|
81
|
+
alias_method :eql?, :==
|
89
82
|
|
83
|
+
def inspect
|
84
|
+
"\#<%p %p>" % [self.class, to_hash]
|
90
85
|
end
|
91
|
-
|
86
|
+
end
|
92
87
|
end
|
@@ -1,24 +1,19 @@
|
|
1
1
|
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
2
|
# The license of this source is "New BSD Licence"
|
3
3
|
|
4
|
-
require
|
5
|
-
|
6
|
-
require "google_drive/error"
|
4
|
+
require 'cgi'
|
7
5
|
|
6
|
+
require 'google_drive/error'
|
8
7
|
|
9
8
|
module GoogleDrive
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@body = body
|
17
|
-
super("Response code %s for %s %s: %s" % [code, method, url, CGI.unescapeHTML(body)])
|
18
|
-
end
|
19
|
-
|
20
|
-
attr_reader(:code, :body)
|
21
|
-
|
9
|
+
# Raised when an HTTP request has returned an unexpected response code.
|
10
|
+
class ResponseCodeError < GoogleDrive::Error
|
11
|
+
def initialize(code, body, method, url) #:nodoc:#
|
12
|
+
@code = code
|
13
|
+
@body = body
|
14
|
+
super('Response code %s for %s %s: %s' % [code, method, url, CGI.unescapeHTML(body)])
|
22
15
|
end
|
23
|
-
|
16
|
+
|
17
|
+
attr_reader(:code, :body)
|
18
|
+
end
|
24
19
|
end
|
data/lib/google_drive/session.rb
CHANGED
@@ -1,489 +1,457 @@
|
|
1
1
|
# Author: Hiroshi Ichikawa <http://gimite.net/>
|
2
2
|
# The license of this source is "New BSD Licence"
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
|
4
|
+
require 'cgi'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'nokogiri'
|
9
|
+
require 'oauth'
|
10
|
+
require 'oauth2'
|
11
|
+
require 'googleauth'
|
12
|
+
|
13
|
+
require 'google_drive/util'
|
14
|
+
require 'google_drive/api_client_fetcher'
|
15
|
+
require 'google_drive/error'
|
16
|
+
require 'google_drive/authentication_error'
|
17
|
+
require 'google_drive/response_code_error'
|
18
|
+
require 'google_drive/spreadsheet'
|
19
|
+
require 'google_drive/worksheet'
|
20
|
+
require 'google_drive/collection'
|
21
|
+
require 'google_drive/file'
|
22
|
+
require 'google_drive/config'
|
24
23
|
|
25
24
|
module GoogleDrive
|
25
|
+
# Use GoogleDrive.login_with_oauth or GoogleDrive.saved_session to get
|
26
|
+
# GoogleDrive::Session object.
|
27
|
+
class Session
|
28
|
+
include(Util)
|
29
|
+
extend(Util)
|
30
|
+
|
31
|
+
# The same as GoogleDrive.login_with_oauth.
|
32
|
+
def self.login_with_oauth(credentials_or_access_token, proxy = nil)
|
33
|
+
Session.new(credentials_or_access_token, proxy)
|
34
|
+
end
|
26
35
|
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
include(Util)
|
32
|
-
extend(Util)
|
33
|
-
|
34
|
-
# The same as GoogleDrive.login_with_oauth.
|
35
|
-
def self.login_with_oauth(client_or_access_token, proxy = nil)
|
36
|
-
return Session.new(client_or_access_token, proxy)
|
37
|
-
end
|
36
|
+
# Creates a dummy GoogleDrive::Session object for testing.
|
37
|
+
def self.new_dummy
|
38
|
+
Session.new(nil)
|
39
|
+
end
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
41
|
+
def initialize(credentials_or_access_token, proxy = nil)
|
42
|
+
if proxy
|
43
|
+
fail(
|
44
|
+
ArgumentError,
|
45
|
+
"Specifying a proxy object is no longer supported. Set ENV[\"http_proxy\"] instead.")
|
46
|
+
end
|
47
|
+
|
48
|
+
if credentials_or_access_token
|
49
|
+
case credentials_or_access_token
|
50
|
+
when String
|
51
|
+
credentials = Google::Auth::UserRefreshCredentials.new(
|
52
|
+
access_token: credentials_or_access_token)
|
53
|
+
when OAuth2::AccessToken
|
54
|
+
credentials = Google::Auth::UserRefreshCredentials.new(
|
55
|
+
access_token: credentials_or_access_token.token)
|
56
|
+
when OAuth::AccessToken
|
57
|
+
fail(
|
58
|
+
ArgumentError,
|
59
|
+
'OAuth1 is no longer supported. Use OAuth2 instead.')
|
60
|
+
else
|
61
|
+
credentials = credentials_or_access_token
|
42
62
|
end
|
63
|
+
@fetcher = ApiClientFetcher.new(credentials)
|
64
|
+
else
|
65
|
+
@fetcher = nil
|
66
|
+
end
|
67
|
+
end
|
43
68
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
raise(
|
48
|
-
ArgumentError,
|
49
|
-
"Specifying a proxy object is no longer supported. Set ENV[\"http_proxy\"] instead.")
|
50
|
-
end
|
51
|
-
|
52
|
-
if client_or_access_token
|
53
|
-
api_client_params = {
|
54
|
-
:application_name => "google_drive Ruby library",
|
55
|
-
:application_version => "0.4.0",
|
56
|
-
}
|
57
|
-
case client_or_access_token
|
58
|
-
when Google::APIClient
|
59
|
-
client = client_or_access_token
|
60
|
-
when String
|
61
|
-
client = Google::APIClient.new(api_client_params)
|
62
|
-
client.authorization.access_token = client_or_access_token
|
63
|
-
when OAuth2::AccessToken
|
64
|
-
client = Google::APIClient.new(api_client_params)
|
65
|
-
client.authorization.access_token = client_or_access_token.token
|
66
|
-
when OAuth::AccessToken
|
67
|
-
raise(
|
68
|
-
ArgumentError,
|
69
|
-
"Passing OAuth::AccessToken to login_with_oauth is no longer supported. " +
|
70
|
-
"You can use OAuth1 by passing Google::APIClient.")
|
71
|
-
else
|
72
|
-
raise(
|
73
|
-
ArgumentError,
|
74
|
-
("client_or_access_token is neither Google::APIClient, " +
|
75
|
-
"String nor OAuth2::AccessToken: %p") %
|
76
|
-
client_or_access_token)
|
77
|
-
end
|
78
|
-
@fetcher = ApiClientFetcher.new(client)
|
79
|
-
else
|
80
|
-
@fetcher = nil
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
69
|
+
# Proc or Method called when authentication has failed.
|
70
|
+
# When this function returns +true+, it tries again.
|
71
|
+
attr_accessor :on_auth_fail
|
84
72
|
|
85
|
-
|
86
|
-
|
87
|
-
|
73
|
+
# Returns an instance of Google::Apis::DriveV3::DriveService.
|
74
|
+
def drive
|
75
|
+
@fetcher.drive
|
76
|
+
end
|
88
77
|
|
89
|
-
|
90
|
-
|
91
|
-
|
78
|
+
# Returns list of files for the user as array of GoogleDrive::File or its subclass.
|
79
|
+
# You can specify parameters documented at
|
80
|
+
# https://developers.google.com/drive/v3/web/search-parameters
|
81
|
+
#
|
82
|
+
# e.g.
|
83
|
+
# session.files
|
84
|
+
# session.files(q: "name = 'hoge'")
|
85
|
+
# session.files(q: ["name = ?", "hoge"]) # Same as above with a placeholder
|
86
|
+
#
|
87
|
+
# By default, it returns the first 100 files. You can get all files by calling with a block:
|
88
|
+
# session.files do |file|
|
89
|
+
# p file
|
90
|
+
# end
|
91
|
+
# Or passing "pageToken" parameter:
|
92
|
+
# page_token = nil
|
93
|
+
# begin
|
94
|
+
# (files, page_token) = session.files(page_token: page_token)
|
95
|
+
# p files
|
96
|
+
# end while page_token
|
97
|
+
def files(params = {}, &block)
|
98
|
+
params = convert_params(params)
|
99
|
+
execute_paged!(
|
100
|
+
method: self.drive.method(:list_files),
|
101
|
+
parameters: {fields: '*'}.merge(params),
|
102
|
+
items_method_name: :files,
|
103
|
+
converter: proc { |af| wrap_api_file(af) },
|
104
|
+
&block)
|
105
|
+
end
|
92
106
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
107
|
+
# Returns GoogleDrive::File or its subclass whose title exactly matches +title+.
|
108
|
+
# Returns nil if not found. If multiple files with the +title+ are found, returns
|
109
|
+
# one of them.
|
110
|
+
#
|
111
|
+
# If given an Array, traverses collections by title. e.g.
|
112
|
+
# session.file_by_title(["myfolder", "mysubfolder/even/w/slash", "myfile"])
|
113
|
+
def file_by_title(title)
|
114
|
+
if title.is_a?(Array)
|
115
|
+
root_collection.file_by_title(title)
|
116
|
+
else
|
117
|
+
files(q: ['name = ?', title], page_size: 1)[0]
|
118
|
+
end
|
119
|
+
end
|
97
120
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
121
|
+
# Returns GoogleDrive::File or its subclass with a given +id+.
|
122
|
+
def file_by_id(id)
|
123
|
+
api_file = self.drive.get_file(id, fields: '*')
|
124
|
+
wrap_api_file(api_file)
|
125
|
+
end
|
102
126
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
# session.files("q" => "title = 'hoge'")
|
110
|
-
# session.files("q" => ["title = ?", "hoge"]) # Same as above with a placeholder
|
111
|
-
#
|
112
|
-
# By default, it returns the first 100 files. You can get all files by calling with a block:
|
113
|
-
# session.files do |file|
|
114
|
-
# p file
|
115
|
-
# end
|
116
|
-
# Or passing "pageToken" parameter:
|
117
|
-
# page_token = nil
|
118
|
-
# begin
|
119
|
-
# (files, page_token) = session.files("pageToken" => page_token)
|
120
|
-
# p files
|
121
|
-
# end while page_token
|
122
|
-
def files(params = {}, &block)
|
123
|
-
params = convert_params(params)
|
124
|
-
return execute_paged!(
|
125
|
-
:api_method => self.drive.files.list,
|
126
|
-
:parameters => params,
|
127
|
-
:converter => proc(){ |af| wrap_api_file(af) },
|
128
|
-
&block)
|
129
|
-
end
|
127
|
+
# Returns GoogleDrive::File or its subclass with a given +url+. +url+ must be eitehr of:
|
128
|
+
# - URL of the page you open to access a document/spreadsheet in your browser
|
129
|
+
# - URL of worksheet-based feed of a spreadseet
|
130
|
+
def file_by_url(url)
|
131
|
+
file_by_id(url_to_id(url))
|
132
|
+
end
|
130
133
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
134
|
+
# Returns list of spreadsheets for the user as array of GoogleDrive::Spreadsheet.
|
135
|
+
# You can specify parameters documented at
|
136
|
+
# https://developers.google.com/drive/v3/web/search-parameters
|
137
|
+
#
|
138
|
+
# e.g.
|
139
|
+
# session.spreadsheets
|
140
|
+
# session.spreadsheets(q: "name = 'hoge'")
|
141
|
+
# session.spreadsheets(q: ["name = ?", "hoge"]) # Same as above with a placeholder
|
142
|
+
#
|
143
|
+
# By default, it returns the first 100 spreadsheets. See document of files method for how to get
|
144
|
+
# all spreadsheets.
|
145
|
+
def spreadsheets(params = {}, &block)
|
146
|
+
params = convert_params(params)
|
147
|
+
query = construct_and_query([
|
148
|
+
"mimeType = 'application/vnd.google-apps.spreadsheet'",
|
149
|
+
params[:q]
|
150
|
+
])
|
151
|
+
files(params.merge(q: query), &block)
|
152
|
+
end
|
144
153
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
154
|
+
# Returns GoogleDrive::Spreadsheet with given +key+.
|
155
|
+
#
|
156
|
+
# e.g.
|
157
|
+
# # https://docs.google.com/spreadsheets/d/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/edit
|
158
|
+
# session.spreadsheet_by_key("1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0")
|
159
|
+
def spreadsheet_by_key(key)
|
160
|
+
file = file_by_id(key)
|
161
|
+
unless file.is_a?(Spreadsheet)
|
162
|
+
fail(GoogleDrive::Error, 'The file with the ID is not a spreadsheet: %s' % key)
|
163
|
+
end
|
164
|
+
file
|
165
|
+
end
|
152
166
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
167
|
+
# Returns GoogleDrive::Spreadsheet with given +url+. You must specify either of:
|
168
|
+
# - URL of the page you open to access the spreadsheet in your browser
|
169
|
+
# - URL of worksheet-based feed of the spreadseet
|
170
|
+
#
|
171
|
+
# e.g.
|
172
|
+
# session.spreadsheet_by_url(
|
173
|
+
# "https://docs.google.com/spreadsheets/d/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/edit")
|
174
|
+
# session.spreadsheet_by_url(
|
175
|
+
# "https://spreadsheets.google.com/feeds/" +
|
176
|
+
# "worksheets/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/private/full")
|
177
|
+
def spreadsheet_by_url(url)
|
178
|
+
file = file_by_url(url)
|
179
|
+
unless file.is_a?(Spreadsheet)
|
180
|
+
fail(GoogleDrive::Error, 'The file with the URL is not a spreadsheet: %s' % url)
|
181
|
+
end
|
182
|
+
file
|
183
|
+
end
|
159
184
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
# session.spreadsheets("q" => ["title = ?", "hoge"]) # Same as above with a placeholder
|
167
|
-
#
|
168
|
-
# By default, it returns the first 100 spreadsheets. See document of files method for how to get
|
169
|
-
# all spreadsheets.
|
170
|
-
def spreadsheets(params = {}, &block)
|
171
|
-
params = convert_params(params)
|
172
|
-
query = construct_and_query([
|
173
|
-
"mimeType = 'application/vnd.google-apps.spreadsheet'",
|
174
|
-
params["q"],
|
175
|
-
])
|
176
|
-
return files(params.merge({"q" => query}), &block)
|
177
|
-
end
|
185
|
+
# Returns GoogleDrive::Spreadsheet with given +title+.
|
186
|
+
# Returns nil if not found. If multiple spreadsheets with the +title+ are found, returns
|
187
|
+
# one of them.
|
188
|
+
def spreadsheet_by_title(title)
|
189
|
+
spreadsheets(q: ['name = ?', title], page_size: 1)[0]
|
190
|
+
end
|
178
191
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
192
|
+
# Returns GoogleDrive::Worksheet with given +url+.
|
193
|
+
# You must specify URL of cell-based feed of the worksheet.
|
194
|
+
#
|
195
|
+
# e.g.
|
196
|
+
# session.worksheet_by_url(
|
197
|
+
# "http://spreadsheets.google.com/feeds/" +
|
198
|
+
# "cells/pz7XtlQC-PYxNmbBVgyiNWg/od6/private/full")
|
199
|
+
def worksheet_by_url(url)
|
200
|
+
unless url =~
|
201
|
+
%r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full((\?.*)?)$}
|
202
|
+
fail(GoogleDrive::Error, "URL is not a cell-based feed URL: #{url}")
|
203
|
+
end
|
204
|
+
worksheet_feed_url = "https://spreadsheets.google.com/feeds/worksheets/" +
|
205
|
+
"#{Regexp.last_match(1)}/private/full/#{Regexp.last_match(2)}#{Regexp.last_match(3)}"
|
206
|
+
worksheet_feed_entry = request(:get, worksheet_feed_url)
|
207
|
+
Worksheet.new(self, nil, worksheet_feed_entry)
|
208
|
+
end
|
191
209
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
# e.g.
|
197
|
-
# session.spreadsheet_by_url(
|
198
|
-
# "https://docs.google.com/spreadsheets/d/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/edit")
|
199
|
-
# session.spreadsheet_by_url(
|
200
|
-
# "https://spreadsheets.google.com/feeds/" +
|
201
|
-
# "worksheets/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/private/full")
|
202
|
-
def spreadsheet_by_url(url)
|
203
|
-
file = file_by_url(url)
|
204
|
-
if !file.is_a?(Spreadsheet)
|
205
|
-
raise(GoogleDrive::Error, "The file with the URL is not a spreadsheet: %s" % url)
|
206
|
-
end
|
207
|
-
return file
|
208
|
-
end
|
210
|
+
# Returns the root collection.
|
211
|
+
def root_collection
|
212
|
+
@root_collection ||= file_by_id('root')
|
213
|
+
end
|
209
214
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
215
|
+
# Returns the top-level collections (direct children of the root collection).
|
216
|
+
#
|
217
|
+
# By default, it returns the first 100 collections. See document of files method for how to get
|
218
|
+
# all collections.
|
219
|
+
def collections(params = {}, &block)
|
220
|
+
root_collection.subcollections(params, &block)
|
221
|
+
end
|
216
222
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
def worksheet_by_url(url)
|
225
|
-
if !(url =~
|
226
|
-
%r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full((\?.*)?)$})
|
227
|
-
raise(GoogleDrive::Error, "URL is not a cell-based feed URL: #{url}")
|
228
|
-
end
|
229
|
-
worksheet_feed_url = "https://spreadsheets.google.com/feeds/worksheets/#{$1}/private/full/#{$2}#{$3}"
|
230
|
-
worksheet_feed_entry = request(:get, worksheet_feed_url)
|
231
|
-
return Worksheet.new(self, nil, worksheet_feed_entry)
|
232
|
-
end
|
223
|
+
# Returns a top-level collection whose title exactly matches +title+ as
|
224
|
+
# GoogleDrive::Collection.
|
225
|
+
# Returns nil if not found. If multiple collections with the +title+ are found, returns
|
226
|
+
# one of them.
|
227
|
+
def collection_by_title(title)
|
228
|
+
root_collection.subcollection_by_title(title)
|
229
|
+
end
|
233
230
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
231
|
+
# Returns GoogleDrive::Collection with given +url+.
|
232
|
+
# You must specify either of:
|
233
|
+
# - URL of the page you get when you go to https://docs.google.com/ with your browser and
|
234
|
+
# open a collection
|
235
|
+
# - URL of collection (folder) feed
|
236
|
+
#
|
237
|
+
# e.g.
|
238
|
+
# session.collection_by_url(
|
239
|
+
# "https://drive.google.com/#folders/" +
|
240
|
+
# "0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
|
241
|
+
# session.collection_by_url(
|
242
|
+
# "http://docs.google.com/feeds/default/private/full/folder%3A" +
|
243
|
+
# "0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
|
244
|
+
def collection_by_url(url)
|
245
|
+
file = file_by_url(url)
|
246
|
+
unless file.is_a?(Collection)
|
247
|
+
fail(GoogleDrive::Error, 'The file with the URL is not a collection: %s' % url)
|
248
|
+
end
|
249
|
+
file
|
250
|
+
end
|
238
251
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
252
|
+
# Creates new spreadsheet and returns the new GoogleDrive::Spreadsheet.
|
253
|
+
#
|
254
|
+
# e.g.
|
255
|
+
# session.create_spreadsheet("My new sheet")
|
256
|
+
def create_spreadsheet(title = 'Untitled')
|
257
|
+
file_metadata = {
|
258
|
+
name: title,
|
259
|
+
mime_type: 'application/vnd.google-apps.spreadsheet'
|
260
|
+
}
|
261
|
+
file = self.drive.create_file(file_metadata, fields: '*')
|
262
|
+
wrap_api_file(file)
|
263
|
+
end
|
246
264
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
265
|
+
# Uploads a file with the given +title+ and +content+.
|
266
|
+
# Returns a GoogleSpreadsheet::File object.
|
267
|
+
#
|
268
|
+
# e.g.
|
269
|
+
# # Uploads and converts to a Google Docs document:
|
270
|
+
# session.upload_from_string(
|
271
|
+
# "Hello world.", "Hello", :content_type => "text/plain")
|
272
|
+
#
|
273
|
+
# # Uploads without conversion:
|
274
|
+
# session.upload_from_string(
|
275
|
+
# "Hello world.", "Hello", :content_type => "text/plain", :convert => false)
|
276
|
+
#
|
277
|
+
# # Uploads and converts to a Google Spreadsheet:
|
278
|
+
# session.upload_from_string("hoge\tfoo\n", "Hoge", :content_type => "text/tab-separated-values")
|
279
|
+
# session.upload_from_string("hoge,foo\n", "Hoge", :content_type => "text/tsv")
|
280
|
+
def upload_from_string(content, title = 'Untitled', params = {})
|
281
|
+
upload_from_source(StringIO.new(content), title, params)
|
282
|
+
end
|
254
283
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
284
|
+
# Uploads a local file.
|
285
|
+
# Returns a GoogleSpreadsheet::File object.
|
286
|
+
#
|
287
|
+
# e.g.
|
288
|
+
# # Uploads a text file and converts to a Google Docs document:
|
289
|
+
# session.upload_from_file("/path/to/hoge.txt")
|
290
|
+
#
|
291
|
+
# # Uploads without conversion:
|
292
|
+
# session.upload_from_file("/path/to/hoge.txt", "Hoge", :convert => false)
|
293
|
+
#
|
294
|
+
# # Uploads with explicit content type:
|
295
|
+
# session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/plain")
|
296
|
+
#
|
297
|
+
# # Uploads a text file and converts to a Google Spreadsheet:
|
298
|
+
# session.upload_from_file("/path/to/hoge.csv", "Hoge")
|
299
|
+
# session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/csv")
|
300
|
+
def upload_from_file(path, title = nil, params = {})
|
301
|
+
# TODO: Add a feature to upload to a folder.
|
302
|
+
file_name = ::File.basename(path)
|
303
|
+
default_content_type =
|
304
|
+
EXT_TO_CONTENT_TYPE[::File.extname(file_name).downcase] ||
|
305
|
+
'application/octet-stream'
|
306
|
+
upload_from_source(
|
307
|
+
path,
|
308
|
+
title || file_name,
|
309
|
+
{content_type: default_content_type}.merge(params))
|
310
|
+
end
|
275
311
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
file = self.drive.files.insert.request_schema.new({
|
282
|
-
"title" => title,
|
283
|
-
"mimeType" => "application/vnd.google-apps.spreadsheet",
|
284
|
-
})
|
285
|
-
api_result = execute!(
|
286
|
-
:api_method => self.drive.files.insert,
|
287
|
-
:body_object => file)
|
288
|
-
return wrap_api_file(api_result.data)
|
289
|
-
end
|
312
|
+
# Uploads a file. Reads content from +io+.
|
313
|
+
# Returns a GoogleSpreadsheet::File object.
|
314
|
+
def upload_from_io(io, title = 'Untitled', params = {})
|
315
|
+
upload_from_source(io, title, params)
|
316
|
+
end
|
290
317
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
# "Hello world.", "Hello", :content_type => "text/plain", :convert => false)
|
302
|
-
#
|
303
|
-
# # Uploads and converts to a Google Spreadsheet:
|
304
|
-
# session.upload_from_string("hoge\tfoo\n", "Hoge", :content_type => "text/tab-separated-values")
|
305
|
-
# session.upload_from_string("hoge,foo\n", "Hoge", :content_type => "text/tsv")
|
306
|
-
def upload_from_string(content, title = "Untitled", params = {})
|
307
|
-
media = new_upload_io(StringIO.new(content), params)
|
308
|
-
return upload_from_media(media, title, params)
|
309
|
-
end
|
318
|
+
def wrap_api_file(api_file) #:nodoc:
|
319
|
+
case api_file.mime_type
|
320
|
+
when 'application/vnd.google-apps.folder'
|
321
|
+
return Collection.new(self, api_file)
|
322
|
+
when 'application/vnd.google-apps.spreadsheet'
|
323
|
+
return Spreadsheet.new(self, api_file)
|
324
|
+
else
|
325
|
+
return File.new(self, api_file)
|
326
|
+
end
|
327
|
+
end
|
310
328
|
|
311
|
-
|
312
|
-
|
313
|
-
#
|
314
|
-
# e.g.
|
315
|
-
# # Uploads a text file and converts to a Google Docs document:
|
316
|
-
# session.upload_from_file("/path/to/hoge.txt")
|
317
|
-
#
|
318
|
-
# # Uploads without conversion:
|
319
|
-
# session.upload_from_file("/path/to/hoge.txt", "Hoge", :convert => false)
|
320
|
-
#
|
321
|
-
# # Uploads with explicit content type:
|
322
|
-
# session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/plain")
|
323
|
-
#
|
324
|
-
# # Uploads a text file and converts to a Google Spreadsheet:
|
325
|
-
# session.upload_from_file("/path/to/hoge.csv", "Hoge")
|
326
|
-
# session.upload_from_file("/path/to/hoge", "Hoge", :content_type => "text/csv")
|
327
|
-
def upload_from_file(path, title = nil, params = {})
|
328
|
-
file_name = ::File.basename(path)
|
329
|
-
params = {:file_name => file_name}.merge(params)
|
330
|
-
media = new_upload_io(path, params)
|
331
|
-
return upload_from_media(media, title || file_name, params)
|
332
|
-
end
|
329
|
+
def execute_paged!(opts, &block) #:nodoc:
|
330
|
+
if block
|
333
331
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
end
|
332
|
+
page_token = nil
|
333
|
+
begin
|
334
|
+
parameters = (opts[:parameters] || {}).merge({page_token: page_token})
|
335
|
+
(items, page_token) = execute_paged!(opts.merge(parameters: parameters))
|
336
|
+
items.each(&block)
|
337
|
+
end while page_token
|
340
338
|
|
341
|
-
|
342
|
-
# Returns a GoogleSpreadsheet::File object.
|
343
|
-
def upload_from_media(media, title = "Untitled", params = {})
|
344
|
-
file = self.drive.files.insert.request_schema.new({
|
345
|
-
"title" => title,
|
346
|
-
})
|
347
|
-
api_result = execute!(
|
348
|
-
:api_method => self.drive.files.insert,
|
349
|
-
:body_object => file,
|
350
|
-
:media => media,
|
351
|
-
:parameters => {
|
352
|
-
"uploadType" => "multipart",
|
353
|
-
"convert" => params[:convert] == false ? "false" : "true",
|
354
|
-
})
|
355
|
-
return wrap_api_file(api_result.data)
|
356
|
-
end
|
339
|
+
elsif opts[:parameters] && opts[:parameters].key?(:page_token)
|
357
340
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
return Collection.new(self, api_file)
|
362
|
-
when "application/vnd.google-apps.spreadsheet"
|
363
|
-
return Spreadsheet.new(self, api_file)
|
364
|
-
else
|
365
|
-
return File.new(self, api_file)
|
366
|
-
end
|
341
|
+
response = opts[:method].call(opts[:parameters])
|
342
|
+
items = response.__send__(opts[:items_method_name]).map do |item|
|
343
|
+
opts[:converter] ? opts[:converter].call(item) : item
|
367
344
|
end
|
345
|
+
return [items, response.next_page_token]
|
368
346
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
parameters = (opts[:parameters] || {}).merge({"pageToken" => page_token})
|
376
|
-
(items, page_token) = execute_paged!(opts.merge({:parameters => parameters}))
|
377
|
-
items.each(&block)
|
378
|
-
end while page_token
|
379
|
-
|
380
|
-
elsif opts[:parameters] && opts[:parameters].has_key?("pageToken")
|
381
|
-
|
382
|
-
api_result = self.execute!(
|
383
|
-
:api_method => opts[:api_method],
|
384
|
-
:parameters => opts[:parameters])
|
385
|
-
items = api_result.data.items.map() do |item|
|
386
|
-
opts[:converter] ? opts[:converter].call(item) : item
|
387
|
-
end
|
388
|
-
return [items, api_result.data.next_page_token]
|
389
|
-
|
390
|
-
else
|
391
|
-
|
392
|
-
parameters = (opts[:parameters] || {}).merge({"pageToken" => nil})
|
393
|
-
(items, next_page_token) = execute_paged!(opts.merge({:parameters => parameters}))
|
394
|
-
return items
|
395
|
-
|
396
|
-
end
|
347
|
+
else
|
348
|
+
parameters = (opts[:parameters] || {}).merge({page_token: nil})
|
349
|
+
(items, next_page_token) = execute_paged!(opts.merge(parameters: parameters))
|
350
|
+
items
|
351
|
+
end
|
352
|
+
end
|
397
353
|
|
354
|
+
def request(method, url, params = {}) #:nodoc:
|
355
|
+
# Always uses HTTPS.
|
356
|
+
url = url.gsub(%r{^http://}, 'https://')
|
357
|
+
data = params[:data]
|
358
|
+
auth = params[:auth] || :wise
|
359
|
+
response_type = params[:response_type] || :xml
|
360
|
+
|
361
|
+
if params[:header]
|
362
|
+
extra_header = params[:header]
|
363
|
+
elsif data
|
364
|
+
extra_header = { 'Content-Type' => 'application/atom+xml;charset=utf-8' }
|
365
|
+
else
|
366
|
+
extra_header = {}
|
367
|
+
end
|
368
|
+
extra_header = { 'GData-Version' => '3.0' }.merge(extra_header)
|
369
|
+
|
370
|
+
loop do
|
371
|
+
response = @fetcher.request_raw(method, url, data, extra_header, auth)
|
372
|
+
next if response.code == '401' && @on_auth_fail && @on_auth_fail.call
|
373
|
+
unless response.code =~ /^2/
|
374
|
+
fail((response.code == '401' ? AuthenticationError : ResponseCodeError)
|
375
|
+
.new(response.code, response.body, method, url))
|
398
376
|
end
|
377
|
+
return convert_response(response, response_type)
|
378
|
+
end
|
379
|
+
end
|
399
380
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
url = url.gsub(%r{^http://}, "https://")
|
404
|
-
data = params[:data]
|
405
|
-
auth = params[:auth] || :wise
|
406
|
-
response_type = params[:response_type] || :xml
|
407
|
-
|
408
|
-
if params[:header]
|
409
|
-
extra_header = params[:header]
|
410
|
-
elsif data
|
411
|
-
extra_header = {"Content-Type" => "application/atom+xml;charset=utf-8"}
|
412
|
-
else
|
413
|
-
extra_header = {}
|
414
|
-
end
|
415
|
-
extra_header = {"GData-Version" => "3.0"}.merge(extra_header)
|
416
|
-
|
417
|
-
while true
|
418
|
-
response = @fetcher.request_raw(method, url, data, extra_header, auth)
|
419
|
-
if response.code == "401" && @on_auth_fail && @on_auth_fail.call()
|
420
|
-
next
|
421
|
-
end
|
422
|
-
if !(response.code =~ /^2/)
|
423
|
-
raise((response.code == "401" ? AuthenticationError : ResponseCodeError).
|
424
|
-
new(response.code, response.body, method, url))
|
425
|
-
end
|
426
|
-
return convert_response(response, response_type)
|
427
|
-
end
|
381
|
+
def inspect
|
382
|
+
'#<%p:0x%x>' % [self.class, object_id]
|
383
|
+
end
|
428
384
|
|
385
|
+
private
|
386
|
+
|
387
|
+
def upload_from_source(source, title, params = {})
|
388
|
+
api_params = {
|
389
|
+
upload_source: source,
|
390
|
+
content_type: 'application/octet-stream',
|
391
|
+
fields: '*',
|
392
|
+
}
|
393
|
+
for k, v in params
|
394
|
+
if ![:convert, :convert_mime_type].include?(k)
|
395
|
+
api_params[k] = v
|
429
396
|
end
|
397
|
+
end
|
398
|
+
|
399
|
+
file_metadata = { name: title }
|
400
|
+
content_type = api_params[:content_type]
|
401
|
+
if params[:convert_mime_type]
|
402
|
+
file_metadata[:mime_type] = params[:convert_mime_type]
|
403
|
+
elsif params.fetch(:convert, true) && IMPORTABLE_CONTENT_TYPE_MAP.key?(content_type)
|
404
|
+
file_metadata[:mime_type] = IMPORTABLE_CONTENT_TYPE_MAP[content_type]
|
405
|
+
end
|
406
|
+
|
407
|
+
file = self.drive.create_file(file_metadata, api_params)
|
408
|
+
wrap_api_file(file)
|
409
|
+
end
|
430
410
|
|
431
|
-
|
432
|
-
|
433
|
-
|
411
|
+
def convert_response(response, response_type)
|
412
|
+
case response_type
|
413
|
+
when :xml
|
414
|
+
return Nokogiri.XML(response.body)
|
415
|
+
when :raw
|
416
|
+
return response.body
|
417
|
+
when :response
|
418
|
+
return response
|
419
|
+
else
|
420
|
+
fail(GoogleDrive::Error,
|
421
|
+
'Unknown params[:response_type]: %s' % response_type)
|
422
|
+
end
|
423
|
+
end
|
434
424
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
425
|
+
def url_to_id(url)
|
426
|
+
uri = URI.parse(url)
|
427
|
+
if ['spreadsheets.google.com', 'docs.google.com', 'drive.google.com'].include?(uri.host)
|
428
|
+
case uri.path
|
429
|
+
# Document feed.
|
430
|
+
when /^\/feeds\/\w+\/private\/full\/\w+%3A(.*)$/
|
431
|
+
return Regexp.last_match(1)
|
432
|
+
# Worksheets feed of a spreadsheet.
|
433
|
+
when /^\/feeds\/worksheets\/([^\/]+)/
|
434
|
+
return Regexp.last_match(1)
|
435
|
+
# Human-readable new spreadsheet/document.
|
436
|
+
when /\/d\/([^\/]+)/
|
437
|
+
return Regexp.last_match(1)
|
438
|
+
# Human-readable new collection page.
|
439
|
+
when /^\/drive\/[^\/]+\/([^\/]+)/
|
440
|
+
return Regexp.last_match(1)
|
441
|
+
# Human-readable old folder view.
|
442
|
+
when /\/folderview$/
|
443
|
+
return Regexp.last_match(1) if (uri.query || '').split(/&/).find { |s| s =~ /^id=(.*)$/ }
|
444
|
+
# Human-readable old spreadsheet.
|
445
|
+
when /\/ccc$/
|
446
|
+
return Regexp.last_match(1) if (uri.query || '').split(/&/).find { |s| s =~ /^key=(.*)$/ }
|
449
447
|
end
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
case uri.path
|
455
|
-
# Document feed.
|
456
|
-
when /^\/feeds\/\w+\/private\/full\/\w+%3A(.*)$/
|
457
|
-
return $1
|
458
|
-
# Worksheets feed of a spreadsheet.
|
459
|
-
when /^\/feeds\/worksheets\/([^\/]+)/
|
460
|
-
return $1
|
461
|
-
# Human-readable new spreadsheet/document.
|
462
|
-
when /\/d\/([^\/]+)/
|
463
|
-
return $1
|
464
|
-
# Human-readable new collection page.
|
465
|
-
when /^\/drive\/[^\/]+\/([^\/]+)/
|
466
|
-
return $1
|
467
|
-
# Human-readable old folder view.
|
468
|
-
when /\/folderview$/
|
469
|
-
if (uri.query || "").split(/&/).find(){ |s| s=~ /^id=(.*)$/ }
|
470
|
-
return $1
|
471
|
-
end
|
472
|
-
# Human-readable old spreadsheet.
|
473
|
-
when /\/ccc$/
|
474
|
-
if (uri.query || "").split(/&/).find(){ |s| s=~ /^key=(.*)$/ }
|
475
|
-
return $1
|
476
|
-
end
|
477
|
-
end
|
478
|
-
case uri.fragment
|
479
|
-
# Human-readable old collection page.
|
480
|
-
when /^folders\/(.+)$/
|
481
|
-
return $1
|
482
|
-
end
|
483
|
-
end
|
484
|
-
raise(GoogleDrive::Error, "The given URL is not a known Google Drive URL: %s" % url)
|
448
|
+
case uri.fragment
|
449
|
+
# Human-readable old collection page.
|
450
|
+
when /^folders\/(.+)$/
|
451
|
+
return Regexp.last_match(1)
|
485
452
|
end
|
486
|
-
|
453
|
+
end
|
454
|
+
fail(GoogleDrive::Error, 'The given URL is not a known Google Drive URL: %s' % url)
|
487
455
|
end
|
488
|
-
|
456
|
+
end
|
489
457
|
end
|