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.
@@ -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