google-spreadsheet-ruby 0.1.8 → 0.2.1

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