google-spreadsheet-ruby 0.1.8 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,124 @@
1
+ # Author: Guy Boertje <https://github.com/guyboertje>
2
+ # Author: David R. Albrecht <https://github.com/eldavido>
3
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
4
+ # The license of this source is "New BSD Licence"
5
+
6
+ require "google_spreadsheet/acl_entry"
7
+
8
+
9
+ module GoogleSpreadsheet
10
+
11
+ # ACL (access control list) of a spreadsheet.
12
+ #
13
+ # Use GoogleSpreadsheet::Spreadsheet#acl to get GoogleSpreadsheet::Acl object.
14
+ # See GoogleSpreadsheet::Spreadsheet#acl for usage example.
15
+ #
16
+ # This code is based on https://github.com/guyboertje/gdata-spreadsheet-ruby .
17
+ class Acl
18
+
19
+ include(Util)
20
+ extend(Forwardable)
21
+
22
+ def initialize(session, acls_feed_url) #:nodoc:
23
+ @session = session
24
+ @acls_feed_url = acls_feed_url
25
+ header = {"GData-Version" => "3.0"}
26
+ doc = @session.request(:get, @acls_feed_url, :header => header, :auth => :writely)
27
+ @acls = doc.css("entry").map(){ |e| AclEntry.new(entry_to_params(e)) }
28
+ end
29
+
30
+ def_delegators(:@acls, :size, :[], :each)
31
+
32
+ # Adds a new entry. +entry+ is either a GoogleSpreadsheet::AclEntry or a Hash with keys
33
+ # :scope_type, :scope and :role. See GoogleSpreadsheet::AclEntry#scope_type and
34
+ # GoogleSpreadsheet::AclEntry#role for the document of the fields.
35
+ #
36
+ # NOTE: This sends email to the new people.
37
+ #
38
+ # e.g.
39
+ # spreadsheet.acl.push(
40
+ # {:scope_type => "user", :scope => "example2@gmail.com", :role => "reader"})
41
+ # spreadsheet.acl.push(
42
+ # {:scope_type => "user", :scope => "example3@gmail.com", :role => "writer"})
43
+ def push(entry)
44
+
45
+ entry = AclEntry.new(entry) if entry.is_a?(Hash)
46
+
47
+ header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
48
+ value_attr = entry.scope ? "value='#{h(entry.scope)}'" : ""
49
+ xml = <<-EOS
50
+ <entry
51
+ xmlns='http://www.w3.org/2005/Atom'
52
+ xmlns:gAcl='http://schemas.google.com/acl/2007'>
53
+ <category scheme='http://schemas.google.com/g/2005#kind'
54
+ term='http://schemas.google.com/acl/2007#accessRule'/>
55
+ <gAcl:role value='#{h(entry.role)}'/>
56
+ <gAcl:scope type='#{h(entry.scope_type)}' #{value_attr}/>
57
+ </entry>
58
+ EOS
59
+ doc = @session.request(
60
+ :post, @acls_feed_url, :data => xml, :header => header, :auth => :writely)
61
+
62
+ entry.params = entry_to_params(doc.root)
63
+ @acls.push(entry)
64
+ return entry
65
+
66
+ end
67
+
68
+ # Deletes an ACL entry.
69
+ #
70
+ # e.g.
71
+ # spreadsheet.acl.delete(spreadsheet.acl[1])
72
+ def delete(entry)
73
+ header = {"GData-Version" => "3.0"}
74
+ @session.request(:delete, entry.edit_url, :header => header, :auth => :writely)
75
+ @acls.delete(entry)
76
+ end
77
+
78
+ def update_role(entry, role) #:nodoc:
79
+
80
+ header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
81
+ value_attr = entry.scope ? "value='#{h(entry.scope)}'" : ""
82
+ xml = <<-EOS
83
+ <entry
84
+ xmlns='http://www.w3.org/2005/Atom'
85
+ xmlns:gAcl='http://schemas.google.com/acl/2007'
86
+ xmlns:gd='http://schemas.google.com/g/2005'
87
+ gd:etag='#{h(entry.etag)}'>
88
+ <category
89
+ scheme='http://schemas.google.com/g/2005#kind'
90
+ term='http://schemas.google.com/acl/2007#accessRule'/>
91
+ <gAcl:role value='#{h(role)}'/>
92
+ <gAcl:scope type='#{h(entry.scope_type)}' #{value_attr}/>
93
+ </entry>
94
+ EOS
95
+ doc = @session.request(
96
+ :put, entry.edit_url, :data => xml, :header => header, :auth => :writely)
97
+
98
+ entry.params = entry_to_params(doc.root)
99
+ return entry
100
+
101
+ end
102
+
103
+ def inspect
104
+ return "\#<%p %p>" % [self.class, @acls]
105
+ end
106
+
107
+ private
108
+
109
+ def entry_to_params(entry)
110
+ # TODO Support with-link roles.
111
+ return {
112
+ :acl => self,
113
+ :scope_type => entry.css("gAcl|scope")[0]["type"],
114
+ :scope => entry.css("gAcl|scope")[0]["value"],
115
+ :role => entry.css("gAcl|role")[0]["value"],
116
+ :title => entry.css("title").text,
117
+ :edit_url => entry.css("link[rel='edit']")[0]["href"],
118
+ :etag => entry["etag"],
119
+ }
120
+ end
121
+
122
+ end
123
+
124
+ end
@@ -0,0 +1,58 @@
1
+ # Author: Guy Boertje <https://github.com/guyboertje>
2
+ # Author: David R. Albrecht <https://github.com/eldavido>
3
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
4
+ # The license of this source is "New BSD Licence"
5
+
6
+ # acl.rb, derived from https://github.com/guyboertje/gdata-spreadsheet-ruby/blob/master/lib/document.rb
7
+ # more frankensteining of the original library
8
+
9
+ module GoogleSpreadsheet
10
+
11
+ # An entry of an ACL (access control list) of a spreadsheet.
12
+ #
13
+ # Use GoogleSpreadsheet::Acl#[] to get GoogleSpreadsheet::AclEntry object.
14
+ #
15
+ # This code is based on https://github.com/guyboertje/gdata-spreadsheet-ruby .
16
+ class AclEntry
17
+
18
+ include(Util)
19
+
20
+ PARAM_NAMES = [:acl, :scope_type, :scope, :role, :title, :edit_url, :etag] #:nodoc:
21
+
22
+ # +params+ is a Hash object with keys +:scope_type+, +:scope+ and +:role+.
23
+ # See scope_type and role for the document of the fields.
24
+ def initialize(params)
25
+ @params = {:role => "reader"}
26
+ for name, value in params
27
+ if !PARAM_NAMES.include?(name)
28
+ raise(ArgumentError, "Invalid key: %p" % name)
29
+ end
30
+ @params[name] = value
31
+ end
32
+ end
33
+
34
+ attr_accessor(:params) #:nodoc:
35
+
36
+ PARAM_NAMES.each() do |name|
37
+ define_method(name) do
38
+ return @params[name]
39
+ end
40
+ end
41
+
42
+ # Changes the role of the scope.
43
+ #
44
+ # e.g.
45
+ # spreadsheet.acl[1].role = "writer"
46
+ def role=(role)
47
+ @params[:acl].update_role(self, role)
48
+ end
49
+
50
+ def inspect
51
+ return "\#<%p scope_type=%p, scope=%p, role=%p>" %
52
+ [self.class, @params[:scope_type], @params[:scope], @params[:role]]
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
@@ -0,0 +1,14 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "google_spreadsheet/error"
5
+
6
+
7
+ module GoogleSpreadsheet
8
+
9
+ # Raised when GoogleSpreadsheet.login has failed.
10
+ class AuthenticationError < GoogleSpreadsheet::Error
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,56 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "net/https"
5
+ require "uri"
6
+ Net::HTTP.version_1_2
7
+
8
+
9
+ module GoogleSpreadsheet
10
+
11
+ class ClientLoginFetcher #:nodoc:
12
+
13
+ def initialize(auth_tokens, proxy)
14
+ @auth_tokens = auth_tokens
15
+ if proxy
16
+ @proxy = proxy
17
+ elsif ENV["http_proxy"] && !ENV["http_proxy"].empty?
18
+ proxy_url = URI.parse(ENV["http_proxy"])
19
+ @proxy = Net::HTTP.Proxy(proxy_url.host, proxy_url.port)
20
+ else
21
+ @proxy = Net::HTTP
22
+ end
23
+ end
24
+
25
+ attr_accessor(:auth_tokens)
26
+
27
+ def request_raw(method, url, data, extra_header, auth)
28
+ uri = URI.parse(url)
29
+ http = @proxy.new(uri.host, uri.port)
30
+ http.use_ssl = true
31
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
32
+ http.start() do
33
+ path = uri.path + (uri.query ? "?#{uri.query}" : "")
34
+ header = auth_header(auth).merge(extra_header)
35
+ if method == :delete || method == :get
36
+ return http.__send__(method, path, header)
37
+ else
38
+ return http.__send__(method, path, data, header)
39
+ end
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def auth_header(auth)
46
+ token = auth == :none ? nil : @auth_tokens[auth]
47
+ if token
48
+ return {"Authorization" => "GoogleLogin auth=#{token}"}
49
+ else
50
+ return {}
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,62 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "google_spreadsheet/util"
5
+ require "google_spreadsheet/error"
6
+ require "google_spreadsheet/spreadsheet"
7
+
8
+
9
+ module GoogleSpreadsheet
10
+
11
+ # Use GoogleSpreadsheet::Session#collection_by_url to get GoogleSpreadsheet::Collection object.
12
+ class Collection
13
+
14
+ include(Util)
15
+
16
+ def initialize(session, collection_feed_url) #:nodoc:
17
+ @session = session
18
+ @collection_feed_url = collection_feed_url
19
+ end
20
+
21
+ attr_reader(:collection_feed_url)
22
+
23
+ # Adds the given GoogleSpreadsheet::Spreadsheet to the collection.
24
+ def add(spreadsheet)
25
+ contents_url = concat_url(@collection_feed_url, "/contents")
26
+ header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
27
+ xml = <<-"EOS"
28
+ <entry xmlns="http://www.w3.org/2005/Atom">
29
+ <id>#{h(spreadsheet.document_feed_url)}</id>
30
+ </entry>
31
+ EOS
32
+ @session.request(
33
+ :post, contents_url, :data => xml, :header => header, :auth => :writely)
34
+ return nil
35
+ end
36
+
37
+ # Returns all the spreadsheets in the collection.
38
+ def spreadsheets
39
+
40
+ contents_url = concat_url(@collection_feed_url, "/contents")
41
+ header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml"}
42
+ doc = @session.request(:get, contents_url, :header => header, :auth => :writely)
43
+
44
+ result = []
45
+ for entry in doc.css("feed > entry")
46
+ title = entry.css("title").text
47
+ worksheets_feed_link = entry.css(
48
+ "link[rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed']")[0]
49
+ if worksheets_feed_link
50
+ result.push(GoogleSpreadsheet::Spreadsheet.new(
51
+ @session, worksheets_feed_link["href"], title))
52
+ end
53
+ end
54
+ return result
55
+
56
+ end
57
+
58
+ # TODO Add other operations.
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,12 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+
5
+ module GoogleSpreadsheet
6
+
7
+ # Raised when spreadsheets.google.com has returned error.
8
+ class Error < RuntimeError
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,115 @@
1
+ # Author: Hiroshi Ichikawa <http://gimite.net/>
2
+ # The license of this source is "New BSD Licence"
3
+
4
+ require "google_spreadsheet/util"
5
+ require "google_spreadsheet/error"
6
+ require "google_spreadsheet/list_row"
7
+
8
+
9
+ module GoogleSpreadsheet
10
+
11
+ # Provides access to cells using column names.
12
+ # Use GoogleSpreadsheet::Worksheet#list to get GoogleSpreadsheet::List object.
13
+ #--
14
+ # This is implemented as wrapper of GoogleSpreadsheet::Worksheet i.e. using cells
15
+ # feed, not list feed. In this way, we can easily provide consistent API as
16
+ # GoogleSpreadsheet::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 (GoogleSpreadsheet::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 GoogleSpreadsheet::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 GoogleSpreadsheet::Worksheet#save().
46
+ def []=(index, hash)
47
+ self[index].replace(hash)
48
+ end
49
+
50
+ # Iterates over Hash-like object (GoogleSpreadsheet::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 GoogleSpreadsheet::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 GoogleSpreadsheet::ListRow for the new row.
81
+ #
82
+ # Note that update is not sent to the server until
83
+ # you call GoogleSpreadsheet::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 set(index, key, value) #:nodoc:
101
+ @worksheet[index + 2, key_to_col(key)] = value
102
+ end
103
+
104
+ private
105
+
106
+ def key_to_col(key)
107
+ key = key.to_s()
108
+ col = (1..@worksheet.num_cols).find(){ |c| @worksheet[1, c] == key }
109
+ raise(GoogleSpreadsheet::Error, "Colunm doesn't exist: %p" % key) if !col
110
+ return col
111
+ end
112
+
113
+ end
114
+
115
+ end