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.
@@ -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 "google_drive/util"
5
- require "google_drive/error"
6
- require "google_drive/list_row"
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
- # Provides access to cells using column names.
12
- # Use GoogleDrive::Worksheet#list to get GoogleDrive::List object.
13
- #--
14
- # This is implemented as wrapper of GoogleDrive::Worksheet i.e. using cells
15
- # feed, not list feed. In this way, we can easily provide consistent API as
16
- # GoogleDrive::Worksheet using save()/reload().
17
- class List
18
-
19
- include(Enumerable)
20
-
21
- def initialize(worksheet) #:nodoc:
22
- @worksheet = worksheet
23
- end
24
-
25
- # Number of non-empty rows in the worksheet excluding the first row.
26
- def size
27
- return @worksheet.num_rows - 1
28
- end
29
-
30
- # Returns Hash-like object (GoogleDrive::ListRow) for the row with the
31
- # index. Keys of the object are colum names (the first row).
32
- # The second row has index 0.
33
- #
34
- # Note that updates to the returned object are not sent to the server until
35
- # you call GoogleDrive::Worksheet#save().
36
- def [](index)
37
- return ListRow.new(self, index)
38
- end
39
-
40
- # Updates the row with the index with the given Hash object.
41
- # Keys of +hash+ are colum names (the first row).
42
- # The second row has index 0.
43
- #
44
- # Note that update is not sent to the server until
45
- # you call GoogleDrive::Worksheet#save().
46
- def []=(index, hash)
47
- self[index].replace(hash)
48
- end
49
-
50
- # Iterates over Hash-like object (GoogleDrive::ListRow) for each row
51
- # (except for the first row).
52
- # Keys of the object are colum names (the first row).
53
- def each(&block)
54
- for i in 0...self.size
55
- yield(self[i])
56
- end
57
- end
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 "forwardable"
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
- # Hash-like object returned by GoogleDrive::List#[].
13
- class ListRow
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
- def input_value(key)
37
- return @list.input_value(@index, key)
38
- end
29
+ def numeric_value(key)
30
+ @list.numeric_value(@index, key)
31
+ end
39
32
 
40
- def []=(key, value)
41
- @list.set(@index, key, value)
42
- end
33
+ def input_value(key)
34
+ @list.input_value(@index, key)
35
+ end
43
36
 
44
- def has_key?(key)
45
- return @list.keys.include?(key)
46
- end
37
+ def []=(key, value)
38
+ @list.set(@index, key, value)
39
+ end
47
40
 
48
- alias include? has_key?
49
- alias key? has_key?
50
- alias member? has_key?
41
+ def has_key?(key)
42
+ @list.keys.include?(key)
43
+ end
51
44
 
52
- def update(hash)
53
- for k, v in hash
54
- self[k] = v
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
- alias merge! update
49
+ def update(hash)
50
+ hash.each do |k, v|
51
+ self[k] = v
52
+ end
53
+ end
59
54
 
60
- def replace(hash)
61
- clear()
62
- update(hash)
63
- end
55
+ alias_method :merge!, :update
64
56
 
65
- def clear()
66
- for key in @list.keys
67
- self[key] = ""
68
- end
69
- end
57
+ def replace(hash)
58
+ clear
59
+ update(hash)
60
+ end
70
61
 
71
- def to_hash()
72
- result = {}
73
- for key in @list.keys
74
- result[key] = self[key]
75
- end
76
- return result
77
- end
62
+ def clear
63
+ @list.keys.each do |key|
64
+ self[key] = ''
65
+ end
66
+ end
78
67
 
79
- def ==(other)
80
- return self.class == other.class && self.to_hash() == other.to_hash()
81
- end
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
- alias === ==
84
- alias eql? ==
76
+ def ==(other)
77
+ self.class == other.class && to_hash == other.to_hash
78
+ end
85
79
 
86
- def inspect
87
- return "\#<%p %p>" % [self.class, to_hash()]
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 "cgi"
5
-
6
- require "google_drive/error"
4
+ require 'cgi'
7
5
 
6
+ require 'google_drive/error'
8
7
 
9
8
  module GoogleDrive
10
-
11
- # Raised when an HTTP request has returned an unexpected response code.
12
- class ResponseCodeError < GoogleDrive::Error
13
-
14
- def initialize(code, body, method, url) #:nodoc:#
15
- @code = code
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
@@ -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 "cgi"
5
- require "stringio"
6
-
7
- require "rubygems"
8
- require "nokogiri"
9
- require "oauth"
10
- require "oauth2"
11
- require "google/api_client"
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"
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
- # Use GoogleDrive.login_with_oauth or GoogleDrive.saved_session to get
28
- # GoogleDrive::Session object.
29
- class Session
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
- # Creates a dummy GoogleDrive::Session object for testing.
40
- def self.new_dummy()
41
- return Session.new(nil)
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
- def initialize(client_or_access_token, proxy = nil)
45
-
46
- if proxy
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
- # Proc or Method called when authentication has failed.
86
- # When this function returns +true+, it tries again.
87
- attr_accessor :on_auth_fail
73
+ # Returns an instance of Google::Apis::DriveV3::DriveService.
74
+ def drive
75
+ @fetcher.drive
76
+ end
88
77
 
89
- def execute!(*args) #:nodoc:
90
- return @fetcher.client.execute!(*args)
91
- end
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
- # Returns the Google::APIClient object.
94
- def client
95
- return @fetcher.client
96
- end
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
- # Returns client.discovered_api("drive", "v2").
99
- def drive
100
- return @fetcher.drive
101
- end
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
- # Returns list of files for the user as array of GoogleDrive::File or its subclass.
104
- # You can specify parameters documented at
105
- # https://developers.google.com/drive/v2/reference/files/list
106
- #
107
- # e.g.
108
- # session.files
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
- # Returns GoogleDrive::File or its subclass whose title exactly matches +title+.
132
- # Returns nil if not found. If multiple files with the +title+ are found, returns
133
- # one of them.
134
- #
135
- # If given an Array, traverses collections by title. e.g.
136
- # session.file_by_title(["myfolder", "mysubfolder/even/w/slash", "myfile"])
137
- def file_by_title(title)
138
- if title.is_a?(Array)
139
- return self.root_collection.file_by_title(title)
140
- else
141
- return files("q" => ["title = ?", title], "maxResults" => 1)[0]
142
- end
143
- end
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
- # Returns GoogleDrive::File or its subclass with a given +id+.
146
- def file_by_id(id)
147
- api_result = execute!(
148
- :api_method => self.drive.files.get,
149
- :parameters => { "fileId" => id })
150
- return wrap_api_file(api_result.data)
151
- end
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
- # Returns GoogleDrive::File or its subclass with a given +url+. +url+ must be eitehr of:
154
- # - URL of the page you open to access a document/spreadsheet in your browser
155
- # - URL of worksheet-based feed of a spreadseet
156
- def file_by_url(url)
157
- return file_by_id(url_to_id(url))
158
- end
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
- # Returns list of spreadsheets for the user as array of GoogleDrive::Spreadsheet.
161
- # You can specify query parameters e.g. "title", "title-exact".
162
- #
163
- # e.g.
164
- # session.spreadsheets
165
- # session.spreadsheets("q" => "title = 'hoge'")
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
- # Returns GoogleDrive::Spreadsheet with given +key+.
180
- #
181
- # e.g.
182
- # # https://docs.google.com/spreadsheets/d/1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0/edit
183
- # session.spreadsheet_by_key("1L3-kvwJblyW_TvjYD-7pE-AXxw5_bkb6S_MljuIPVL0")
184
- def spreadsheet_by_key(key)
185
- file = file_by_id(key)
186
- if !file.is_a?(Spreadsheet)
187
- raise(GoogleDrive::Error, "The file with the ID is not a spreadsheet: %s" % key)
188
- end
189
- return file
190
- end
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
- # Returns GoogleDrive::Spreadsheet with given +url+. You must specify either of:
193
- # - URL of the page you open to access the spreadsheet in your browser
194
- # - URL of worksheet-based feed of the spreadseet
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
- # Returns GoogleDrive::Spreadsheet with given +title+.
211
- # Returns nil if not found. If multiple spreadsheets with the +title+ are found, returns
212
- # one of them.
213
- def spreadsheet_by_title(title)
214
- return spreadsheets("q" => ["title = ?", title], "maxResults" => 1)[0]
215
- end
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
- # Returns GoogleDrive::Worksheet with given +url+.
218
- # You must specify URL of cell-based feed of the worksheet.
219
- #
220
- # e.g.
221
- # session.worksheet_by_url(
222
- # "http://spreadsheets.google.com/feeds/" +
223
- # "cells/pz7XtlQC-PYxNmbBVgyiNWg/od6/private/full")
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
- # Returns the root collection.
235
- def root_collection
236
- return @root_collection ||= file_by_id("root")
237
- end
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
- # Returns the top-level collections (direct children of the root collection).
240
- #
241
- # By default, it returns the first 100 collections. See document of files method for how to get
242
- # all collections.
243
- def collections
244
- return self.root_collection.subcollections
245
- end
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
- # Returns a top-level collection whose title exactly matches +title+ as
248
- # GoogleDrive::Collection.
249
- # Returns nil if not found. If multiple collections with the +title+ are found, returns
250
- # one of them.
251
- def collection_by_title(title)
252
- return self.root_collection.subcollection_by_title(title)
253
- end
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
- # Returns GoogleDrive::Collection with given +url+.
256
- # You must specify either of:
257
- # - URL of the page you get when you go to https://docs.google.com/ with your browser and
258
- # open a collection
259
- # - URL of collection (folder) feed
260
- #
261
- # e.g.
262
- # session.collection_by_url(
263
- # "https://drive.google.com/#folders/" +
264
- # "0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
265
- # session.collection_by_url(
266
- # "http://docs.google.com/feeds/default/private/full/folder%3A" +
267
- # "0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
268
- def collection_by_url(url)
269
- file = file_by_url(url)
270
- if !file.is_a?(Collection)
271
- raise(GoogleDrive::Error, "The file with the URL is not a collection: %s" % url)
272
- end
273
- return file
274
- end
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
- # Creates new spreadsheet and returns the new GoogleDrive::Spreadsheet.
277
- #
278
- # e.g.
279
- # session.create_spreadsheet("My new sheet")
280
- def create_spreadsheet(title = "Untitled")
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
- # Uploads a file with the given +title+ and +content+.
292
- # Returns a GoogleSpreadsheet::File object.
293
- #
294
- # e.g.
295
- # # Uploads and converts to a Google Docs document:
296
- # session.upload_from_string(
297
- # "Hello world.", "Hello", :content_type => "text/plain")
298
- #
299
- # # Uploads without conversion:
300
- # session.upload_from_string(
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
- # Uploads a local file.
312
- # Returns a GoogleSpreadsheet::File object.
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
- # Uploads a file. Reads content from +io+.
335
- # Returns a GoogleSpreadsheet::File object.
336
- def upload_from_io(io, title = "Untitled", params = {})
337
- media = new_upload_io(io, params)
338
- return upload_from_media(media, title, params)
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
- # Uploads a file. Reads content from +media+.
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
- def wrap_api_file(api_file) #:nodoc:
359
- case api_file.mime_type
360
- when "application/vnd.google-apps.folder"
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
- def execute_paged!(opts, &block) #:nodoc:
370
-
371
- if block
372
-
373
- page_token = nil
374
- begin
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
- def request(method, url, params = {}) #:nodoc:
401
-
402
- # Always uses HTTPS.
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
- def inspect
432
- return "#<%p:0x%x>" % [self.class, self.object_id]
433
- end
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
- private
436
-
437
- def convert_response(response, response_type)
438
- case response_type
439
- when :xml
440
- return Nokogiri.XML(response.body)
441
- when :raw
442
- return response.body
443
- when :response
444
- return response
445
- else
446
- raise(GoogleDrive::Error,
447
- "Unknown params[:response_type]: %s" % response_type)
448
- end
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
- def url_to_id(url)
452
- uri = URI.parse(url)
453
- if ["spreadsheets.google.com", "docs.google.com", "drive.google.com"].include?(uri.host)
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