google_drive 1.0.6 → 2.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.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
|