google-spreadsheet-ruby 0.1.5 → 0.1.6

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.
Files changed (3) hide show
  1. data/README.rdoc +2 -3
  2. data/lib/google_spreadsheet.rb +212 -63
  3. metadata +48 -67
data/README.rdoc CHANGED
@@ -3,7 +3,6 @@ This is a Ruby 1.8/1.9 library to read/write Google Spreadsheet.
3
3
 
4
4
  = How to install
5
5
 
6
- $ gem sources -a http://gemcutter.org
7
6
  $ sudo gem install google-spreadsheet-ruby
8
7
 
9
8
  Note that gimite-google-spreadsheet-ruby at gems.github.com is no longer updated, because github stopped hosting it.
@@ -49,14 +48,14 @@ API document: http://gimite.net/gimite/rubymess/google-spreadsheet-ruby/
49
48
 
50
49
  = Source code
51
50
 
52
- http://github.com/gimite/google-spreadsheet-ruby/tree/master
51
+ http://github.com/gimite/google-spreadsheet-ruby
53
52
 
54
53
  The license of this source is "New BSD Licence"
55
54
 
56
55
 
57
56
  = Supported environments
58
57
 
59
- Ruby 1.8.x and Ruby 1.9.x. Checked with Ruby 1.8.7 and Ruby 1.9.1.
58
+ Ruby 1.8.x and Ruby 1.9.x. Checked with Ruby 1.8.7 and Ruby 1.9.3.
60
59
 
61
60
 
62
61
  = Author
@@ -10,6 +10,7 @@ require "uri"
10
10
  require "rubygems"
11
11
  require "nokogiri"
12
12
  require "oauth"
13
+ require "oauth2"
13
14
  Net::HTTP.version_1_2
14
15
 
15
16
  module GoogleSpreadsheet
@@ -26,9 +27,31 @@ module GoogleSpreadsheet
26
27
  return Session.login(mail, password, proxy)
27
28
  end
28
29
 
29
- # Authenticates with given OAuth token.
30
+ # Authenticates with given OAuth1 or OAuth2 token.
30
31
  #
31
- # For generating oauth_token, you can proceed as follow:
32
+ # OAuth2 code example:
33
+ #
34
+ # client = OAuth2::Client.new(
35
+ # your_client_id, your_client_secret,
36
+ # :site => "https://accounts.google.com",
37
+ # :token_url => "/o/oauth2/token",
38
+ # :authorize_url => "/o/oauth2/auth")
39
+ # auth_url = client.auth_code.authorize_url(
40
+ # :redirect_uri => "http://example.com/",
41
+ # "scope" => "https://spreadsheets.google.com/feeds https://docs.google.com/feeds/")
42
+ # # Redirect the user to auth_url and get authorization code from redirect URL.
43
+ # auth_token = client.auth_code.get_token(
44
+ # authorization_code, :redirect_uri => "http://example.com/")
45
+ # session = GoogleSpreadsheet.login_with_oauth(auth_token)
46
+ #
47
+ # Or, from existing refresh token:
48
+ #
49
+ # access_token = OAuth2::AccessToken.from_hash(client,
50
+ # {:refresh_token => refresh_token, :expires_at => expires_at})
51
+ # access_token = access_token.refresh!
52
+ # session = GoogleSpreadsheet.login_with_oauth(access_token)
53
+ #
54
+ # OAuth1 code example:
32
55
  #
33
56
  # 1) First generate OAuth consumer object with key and secret for your site by registering site with google
34
57
  # @consumer = OAuth::Consumer.new( "key","secret", {:site=>"https://agree2"})
@@ -42,12 +65,21 @@ module GoogleSpreadsheet
42
65
  #
43
66
  # See these documents for details:
44
67
  #
68
+ # - https://github.com/intridea/oauth2
69
+ # - http://code.google.com/apis/accounts/docs/OAuth2.html
45
70
  # - http://oauth.rubyforge.org/
46
71
  # - http://code.google.com/apis/accounts/docs/OAuth.html
47
72
  def self.login_with_oauth(oauth_token)
48
73
  return Session.login_with_oauth(oauth_token)
49
74
  end
50
75
 
76
+ # Restores session using return value of auth_tokens method of previous session.
77
+ #
78
+ # See GoogleSpreadsheet.login for description of parameter +proxy+.
79
+ def self.restore_session(auth_tokens, proxy = nil)
80
+ return Session.restore_session(auth_tokens, proxy)
81
+ end
82
+
51
83
  # Restores GoogleSpreadsheet::Session from +path+ and returns it.
52
84
  # If +path+ doesn't exist or authentication has failed, prompts mail and password on console,
53
85
  # authenticates with them, stores the session to +path+ and returns it.
@@ -100,6 +132,13 @@ module GoogleSpreadsheet
100
132
  def encode_query(params)
101
133
  return params.map(){ |k, v| CGI.escape(k) + "=" + CGI.escape(v) }.join("&")
102
134
  end
135
+
136
+ def concat_url(url, piece)
137
+ (url_base, url_query) = url.split(/\?/, 2)
138
+ (piece_base, piece_query) = piece.split(/\?/, 2)
139
+ result_query = [url_query, piece_query].select(){ |s| s && !s.empty? }.join("&")
140
+ return url_base + piece_base + (result_query.empty? ? "" : "?#{result_query}")
141
+ end
103
142
 
104
143
  def h(str)
105
144
  return CGI.escapeHTML(str.to_s())
@@ -118,6 +157,89 @@ module GoogleSpreadsheet
118
157
  class AuthenticationError < GoogleSpreadsheet::Error
119
158
 
120
159
  end
160
+
161
+
162
+ class ClientLoginFetcher #:nodoc:
163
+
164
+ def initialize(auth_tokens, proxy)
165
+ @auth_tokens = auth_tokens
166
+ if proxy
167
+ @proxy = proxy
168
+ elsif ENV["http_proxy"] && !ENV["http_proxy"].empty?
169
+ proxy_url = URI.parse(ENV["http_proxy"])
170
+ @proxy = Net::HTTP.Proxy(proxy_url.host, proxy_url.port)
171
+ else
172
+ @proxy = Net::HTTP
173
+ end
174
+ end
175
+
176
+ attr_accessor(:auth_tokens)
177
+
178
+ def request_raw(method, url, data, extra_header, auth)
179
+ uri = URI.parse(url)
180
+ http = @proxy.new(uri.host, uri.port)
181
+ http.use_ssl = true
182
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
183
+ http.start() do
184
+ path = uri.path + (uri.query ? "?#{uri.query}" : "")
185
+ header = auth_header(auth).merge(extra_header)
186
+ if method == :delete || method == :get
187
+ return http.__send__(method, path, header)
188
+ else
189
+ return http.__send__(method, path, data, header)
190
+ end
191
+ end
192
+ end
193
+
194
+ private
195
+
196
+ def auth_header(auth)
197
+ token = auth == :none ? nil : @auth_tokens[auth]
198
+ if token
199
+ return {"Authorization" => "GoogleLogin auth=#{token}"}
200
+ else
201
+ return {}
202
+ end
203
+ end
204
+
205
+ end
206
+
207
+
208
+ class OAuth1Fetcher #:nodoc:
209
+
210
+ def initialize(oauth1_token)
211
+ @oauth1_token = oauth1_token
212
+ end
213
+
214
+ def request_raw(method, url, data, extra_header, auth)
215
+ if method == :delete || method == :get
216
+ return @oauth1_token.__send__(method, url, extra_header)
217
+ else
218
+ return @oauth1_token.__send__(method, url, data, extra_header)
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+
225
+ class OAuth2Fetcher #:nodoc:
226
+
227
+ Response = Struct.new(:code, :body)
228
+
229
+ def initialize(oauth2_token)
230
+ @oauth2_token = oauth2_token
231
+ end
232
+
233
+ def request_raw(method, url, data, extra_header, auth)
234
+ if method == :delete || method == :get
235
+ raw_res = @oauth2_token.request(method, url, {:header => extra_header})
236
+ else
237
+ raw_res = @oauth2_token.request(method, url, {:header => extra_header, :body => data})
238
+ end
239
+ return Response.new(raw_res.status.to_s(), raw_res.body)
240
+ end
241
+
242
+ end
121
243
 
122
244
 
123
245
  # Use GoogleSpreadsheet.login or GoogleSpreadsheet.saved_session to get
@@ -129,29 +251,36 @@ module GoogleSpreadsheet
129
251
 
130
252
  # The same as GoogleSpreadsheet.login.
131
253
  def self.login(mail, password, proxy = nil)
132
- session = Session.new(nil, nil, proxy)
254
+ session = Session.new(nil, ClientLoginFetcher.new({}, proxy))
133
255
  session.login(mail, password)
134
256
  return session
135
257
  end
136
258
 
137
259
  # The same as GoogleSpreadsheet.login_with_oauth.
138
260
  def self.login_with_oauth(oauth_token)
139
- session = Session.new(nil, oauth_token)
261
+ case oauth_token
262
+ when OAuth::AccessToken
263
+ fetcher = OAuth1Fetcher.new(oauth_token)
264
+ when OAuth2::AccessToken
265
+ fetcher = OAuth2Fetcher.new(oauth_token)
266
+ else
267
+ raise(GoogleSpreadsheet::Error,
268
+ "oauth_token is neither OAuth::Token nor OAuth2::Token: %p" % oauth_token)
269
+ end
270
+ return Session.new(nil, fetcher)
140
271
  end
141
272
 
142
- # Restores session using return value of auth_tokens method of previous session.
143
- #
144
- # See GoogleSpreadsheet.login for description of parameter +proxy+.
145
- def initialize(auth_tokens = nil, oauth_token = nil, proxy = nil)
146
- @oauth_token = oauth_token
147
- @auth_tokens = auth_tokens || {}
148
- if proxy
149
- @proxy = proxy
150
- elsif ENV["http_proxy"] && !ENV["http_proxy"].empty?
151
- proxy_url = URI.parse(ENV["http_proxy"])
152
- @proxy = Net::HTTP.Proxy(proxy_url.host, proxy_url.port)
273
+ # The same as GoogleSpreadsheet.restore_session.
274
+ def self.restore_session(auth_tokens, proxy = nil)
275
+ return Session.new(auth_tokens, nil, proxy)
276
+ end
277
+
278
+ # DEPRECATED: Use GoogleSpreadsheet.restore_session instead.
279
+ def initialize(auth_tokens = nil, fetcher = nil, proxy = nil)
280
+ if fetcher
281
+ @fetcher = fetcher
153
282
  else
154
- @proxy = Net::HTTP
283
+ @fetcher = ClientLoginFetcher.new(auth_tokens || {}, proxy)
155
284
  end
156
285
  end
157
286
 
@@ -159,10 +288,15 @@ module GoogleSpreadsheet
159
288
  # if succeeds. Raises GoogleSpreadsheet::AuthenticationError if fails.
160
289
  # Google Apps account is supported.
161
290
  def login(mail, password)
291
+ if !@fetcher.is_a?(ClientLoginFetcher)
292
+ raise(GoogleSpreadsheet::Error,
293
+ "Cannot call login for session created by login_with_oauth or login_with_oauth2.")
294
+ end
162
295
  begin
163
- @auth_tokens = {}
164
- authenticate(mail, password, :wise)
165
- authenticate(mail, password, :writely)
296
+ @fetcher.auth_tokens = {
297
+ :wise => authenticate(mail, password, :wise),
298
+ :writely => authenticate(mail, password, :writely),
299
+ }
166
300
  rescue GoogleSpreadsheet::Error => ex
167
301
  return true if @on_auth_fail && @on_auth_fail.call()
168
302
  raise(AuthenticationError, "authentication failed for #{mail}: #{ex.message}")
@@ -170,26 +304,24 @@ module GoogleSpreadsheet
170
304
  end
171
305
 
172
306
  # Authentication tokens.
173
- attr_reader(:auth_tokens)
307
+ def auth_tokens
308
+ if !@fetcher.is_a?(ClientLoginFetcher)
309
+ raise(GoogleSpreadsheet::Error,
310
+ "Cannot call auth_tokens for session created by " +
311
+ "login_with_oauth or login_with_oauth2.")
312
+ end
313
+ return @fetcher.auth_tokens
314
+ end
174
315
 
175
316
  # Authentication token.
176
317
  def auth_token(auth = :wise)
177
- return @auth_tokens[auth]
318
+ return self.auth_tokens[auth]
178
319
  end
179
320
 
180
321
  # Proc or Method called when authentication has failed.
181
322
  # When this function returns +true+, it tries again.
182
323
  attr_accessor :on_auth_fail
183
324
 
184
- def auth_header(auth) #:nodoc:
185
- token = auth == :none ? nil : @auth_tokens[auth]
186
- if token
187
- return {"Authorization" => "GoogleLogin auth=#{token}"}
188
- else
189
- return {}
190
- end
191
- end
192
-
193
325
  # Returns list of spreadsheets for the user as array of GoogleSpreadsheet::Spreadsheet.
194
326
  # You can specify query parameters described at
195
327
  # http://code.google.com/apis/spreadsheets/docs/2.0/reference.html#Parameters
@@ -251,6 +383,17 @@ module GoogleSpreadsheet
251
383
  return Worksheet.new(self, nil, url)
252
384
  end
253
385
 
386
+ # Returns GoogleSpreadsheet::Collection with given +url+.
387
+ # You must specify URL of collection (folder) feed.
388
+ #
389
+ # e.g.
390
+ # session.collection_by_url(
391
+ # "http://docs.google.com/feeds/default/private/full/folder%3A" +
392
+ # "0B9GfDpQ2pBVUODNmOGE0NjIzMWU3ZC00NmUyLTk5NzEtYaFkZjY1MjAyxjMc")
393
+ def collection_by_url(url)
394
+ return Collection.new(self, url)
395
+ end
396
+
254
397
  # Creates new spreadsheet and returns the new GoogleSpreadsheet::Spreadsheet.
255
398
  #
256
399
  # e.g.
@@ -287,7 +430,7 @@ module GoogleSpreadsheet
287
430
  response_type = params[:response_type] || :xml
288
431
 
289
432
  while true
290
- response = request_raw(method, url, data, extra_header, auth)
433
+ response = @fetcher.request_raw(method, url, data, extra_header, auth)
291
434
  if response.code == "401" && @on_auth_fail && @on_auth_fail.call()
292
435
  next
293
436
  end
@@ -303,30 +446,6 @@ module GoogleSpreadsheet
303
446
 
304
447
  private
305
448
 
306
- def request_raw(method, url, data, extra_header, auth)
307
- if @oauth_token
308
- if method == :delete || method == :get
309
- return @oauth_token.__send__(method, url, extra_header)
310
- else
311
- return @oauth_token.__send__(method, url, data, extra_header)
312
- end
313
- else
314
- uri = URI.parse(url)
315
- http = @proxy.new(uri.host, uri.port)
316
- http.use_ssl = true
317
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
318
- http.start() do
319
- path = uri.path + (uri.query ? "?#{uri.query}" : "")
320
- header = auth_header(auth).merge(extra_header)
321
- if method == :delete || method == :get
322
- return http.__send__(method, path, header)
323
- else
324
- return http.__send__(method, path, data, header)
325
- end
326
- end
327
- end
328
- end
329
-
330
449
  def convert_response(response, response_type)
331
450
  case response_type
332
451
  when :xml
@@ -350,7 +469,7 @@ module GoogleSpreadsheet
350
469
  response = request(:post,
351
470
  "https://www.google.com/accounts/ClientLogin",
352
471
  :data => encode_query(params), :auth => :none, :header => header, :response_type => :raw)
353
- @auth_tokens[auth] = response.slice(/^Auth=(.*)$/, 1)
472
+ return response.slice(/^Auth=(.*)$/, 1)
354
473
  end
355
474
 
356
475
  end
@@ -459,7 +578,7 @@ module GoogleSpreadsheet
459
578
  "link[@rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']").first["href"]
460
579
  return Spreadsheet.new(@session, ss_url, new_title)
461
580
  end
462
-
581
+
463
582
  # If +permanent+ is +false+, moves the spreadsheet to the trash.
464
583
  # If +permanent+ is +true+, deletes the spreadsheet permanently.
465
584
  def delete(permanent = false)
@@ -562,7 +681,35 @@ module GoogleSpreadsheet
562
681
  end
563
682
 
564
683
  end
684
+
685
+ # Use GoogleSpreadsheet::Session#collection_by_url to get GoogleSpreadsheet::Collection object.
686
+ class Collection
687
+
688
+ include(Util)
689
+
690
+ def initialize(session, collection_feed_url) #:nodoc:
691
+ @session = session
692
+ @collection_feed_url = collection_feed_url
693
+ end
694
+
695
+ # Adds the given GoogleSpreadsheet::Spreadsheet to the collection.
696
+ def add(spreadsheet)
697
+ contents_url = concat_url(@collection_feed_url, "/contents")
698
+ header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
699
+ xml = <<-"EOS"
700
+ <entry xmlns="http://www.w3.org/2005/Atom">
701
+ <id>#{h(spreadsheet.document_feed_url)}</id>
702
+ </entry>
703
+ EOS
704
+ @session.request(
705
+ :post, contents_url, :data => xml, :header => header, :auth => :writely)
706
+ return nil
707
+ end
708
+
709
+ # TODO Add other operations.
565
710
 
711
+ end
712
+
566
713
  # DEPRECATED: Table and Record feeds are deprecated and they will not be available after
567
714
  # March 2012.
568
715
  #
@@ -658,18 +805,18 @@ module GoogleSpreadsheet
658
805
  # Probably it would be cleaner to keep worksheet feed URL and get cells feed URL
659
806
  # from it.
660
807
  if !(@cells_feed_url =~
661
- %r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full$})
808
+ %r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full((\?.*)?)$})
662
809
  raise(GoogleSpreadsheet::Error,
663
810
  "cells feed URL is in unknown format: #{@cells_feed_url}")
664
811
  end
665
- return "https://spreadsheets.google.com/feeds/worksheets/#{$1}/private/full/#{$2}"
812
+ return "https://spreadsheets.google.com/feeds/worksheets/#{$1}/private/full/#{$2}#{$3}"
666
813
  end
667
814
 
668
815
  # GoogleSpreadsheet::Spreadsheet which this worksheet belongs to.
669
816
  def spreadsheet
670
817
  if !@spreadsheet
671
818
  if !(@cells_feed_url =~
672
- %r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full$})
819
+ %r{^https?://spreadsheets.google.com/feeds/cells/(.*)/(.*)/private/full(\?.*)?$})
673
820
  raise(GoogleSpreadsheet::Error,
674
821
  "cells feed URL is in unknown format: #{@cells_feed_url}")
675
822
  end
@@ -832,8 +979,9 @@ module GoogleSpreadsheet
832
979
  cell_entries = {}
833
980
  rows = @modified.map(){ |r, c| r }
834
981
  cols = @modified.map(){ |r, c| c }
835
- url = "#{@cells_feed_url}?return-empty=true&min-row=#{rows.min}&max-row=#{rows.max}" +
836
- "&min-col=#{cols.min}&max-col=#{cols.max}"
982
+ url = concat_url(@cells_feed_url,
983
+ "?return-empty=true&min-row=#{rows.min}&max-row=#{rows.max}" +
984
+ "&min-col=#{cols.min}&max-col=#{cols.max}")
837
985
  doc = @session.request(:get, url)
838
986
 
839
987
  doc.css('entry').each() do |entry|
@@ -872,7 +1020,8 @@ module GoogleSpreadsheet
872
1020
  </feed>
873
1021
  EOS
874
1022
 
875
- result = @session.request(:post, "#{@cells_feed_url}/batch", :data => xml)
1023
+ batch_url = concat_url(@cells_feed_url, "/batch")
1024
+ result = @session.request(:post, batch_url, :data => xml)
876
1025
  result.css('atom|entry').each() do |entry|
877
1026
  interrupted = entry.css('batch|interrupted').first
878
1027
  if interrupted
metadata CHANGED
@@ -1,102 +1,83 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: google-spreadsheet-ruby
3
- version: !ruby/object:Gem::Version
4
- hash: 17
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 1
9
- - 5
10
- version: 0.1.5
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.6
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Hiroshi Ichikawa
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-05-14 00:00:00 +09:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2011-11-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: nokogiri
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &81815340 !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 113
30
- segments:
31
- - 1
32
- - 4
33
- - 3
34
- - 1
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
35
21
  version: 1.4.3.1
36
22
  type: :runtime
37
- version_requirements: *id001
38
- - !ruby/object:Gem::Dependency
39
- name: oauth
40
23
  prerelease: false
41
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *81815340
25
+ - !ruby/object:Gem::Dependency
26
+ name: oauth
27
+ requirement: &81815050 !ruby/object:Gem::Requirement
42
28
  none: false
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- hash: 31
47
- segments:
48
- - 0
49
- - 3
50
- - 6
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
51
32
  version: 0.3.6
52
33
  type: :runtime
53
- version_requirements: *id002
34
+ prerelease: false
35
+ version_requirements: *81815050
36
+ - !ruby/object:Gem::Dependency
37
+ name: oauth2
38
+ requirement: &81814770 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 0.5.0
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *81814770
54
47
  description: This is a library to read/write Google Spreadsheet.
55
- email:
48
+ email:
56
49
  - gimite+github@gmail.com
57
50
  executables: []
58
-
59
51
  extensions: []
60
-
61
- extra_rdoc_files:
52
+ extra_rdoc_files:
62
53
  - README.rdoc
63
- files:
54
+ files:
64
55
  - README.rdoc
65
56
  - lib/google_spreadsheet.rb
66
- has_rdoc: true
67
57
  homepage: https://github.com/gimite/google-spreadsheet-ruby
68
58
  licenses: []
69
-
70
59
  post_install_message:
71
- rdoc_options:
60
+ rdoc_options:
72
61
  - --main
73
62
  - README.rdoc
74
- require_paths:
63
+ require_paths:
75
64
  - lib
76
- required_ruby_version: !ruby/object:Gem::Requirement
65
+ required_ruby_version: !ruby/object:Gem::Requirement
77
66
  none: false
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- hash: 3
82
- segments:
83
- - 0
84
- version: "0"
85
- required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
72
  none: false
87
- requirements:
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- hash: 3
91
- segments:
92
- - 0
93
- version: "0"
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
94
77
  requirements: []
95
-
96
78
  rubyforge_project:
97
- rubygems_version: 1.3.7
79
+ rubygems_version: 1.8.11
98
80
  signing_key:
99
81
  specification_version: 3
100
82
  summary: This is a library to read/write Google Spreadsheet.
101
83
  test_files: []
102
-