rufus-google 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,98 @@
1
+
2
+ = rufus-google
3
+
4
+ rufus-google should probably be named "rufus-gcal" for now, as only google calendar stuff is implemented.
5
+
6
+ This gem leverages 'atom-tools' to play with Google Data APIs.
7
+
8
+ The only authentication mechanism implemented for now is "ClientLogin".
9
+
10
+ (There is a one way synchronization tool for ical to gcal at
11
+
12
+ http://github.com/jmettraux/rufus-google/tree/master/tools/itog.rb
13
+
14
+ work in progress...)
15
+
16
+
17
+ == getting it
18
+
19
+ sudo gem install rufus-google
20
+
21
+ or at
22
+
23
+ http://rubyforge.org/frs/?group_id=4812
24
+
25
+
26
+ == usage
27
+
28
+ Using Google Calendar :
29
+
30
+ require 'rubygems'
31
+ require 'rufus/gcal'
32
+
33
+ calendars = Rufus::Google::Calendar.get_calendars(
34
+ :account => ENV['GUSER'], :password => ENV['GPASS'])
35
+
36
+ #calendars.values.each { |c| p [ c.name, c.href ] }
37
+
38
+ cal = calendars['gwork']
39
+
40
+ event_id = cal.post_quick!('Tennis with John November 13 3pm-4:30pm')
41
+
42
+ cal.events(:q => 'tennis').each do |e|
43
+ puts
44
+ puts e.to_s
45
+ end
46
+
47
+ cal.delete!(event_id)
48
+
49
+ puts "#{cal.events(:q => 'tennis').size} tennis events"
50
+
51
+
52
+ Other Google APIs will be covered later, if the need arise.
53
+
54
+
55
+ == dependencies
56
+
57
+ the 'rufus-verbs' and the 'atom-tools' gems.
58
+
59
+
60
+ == mailing list
61
+
62
+ On the rufus-ruby list[http://groups.google.com/group/rufus-ruby] :
63
+
64
+ http://groups.google.com/group/rufus-ruby
65
+
66
+
67
+ == issue tracker
68
+
69
+ http://rubyforge.org/tracker/?atid=18584&group_id=4812&func=browse
70
+
71
+
72
+ == irc
73
+
74
+ irc.freenode.net #ruote
75
+
76
+
77
+ == source
78
+
79
+ http://github.com/jmettraux/rufus-google
80
+
81
+ git clone git://github.com/jmettraux/rufus-google.git
82
+
83
+
84
+ == author
85
+
86
+ John Mettraux, jmettraux@gmail.com
87
+ http://jmettraux.wordpress.com
88
+
89
+
90
+ == the rest of Rufus
91
+
92
+ http://rufus.rubyforge.org
93
+
94
+
95
+ == license
96
+
97
+ MIT
98
+
@@ -0,0 +1,3 @@
1
+
2
+ require 'rufus/gcal'
3
+
@@ -0,0 +1,64 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2008, John Mettraux, jmettraux@gmail.com
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+ # (MIT license)
24
+ #++
25
+ #
26
+
27
+ #
28
+ # John Mettraux
29
+ #
30
+ # Made in Japan
31
+ #
32
+ # Tue Nov 11 22:18:23 JST 2008
33
+ #
34
+
35
+ require 'atom/http'
36
+
37
+ module Rufus
38
+ module Google
39
+
40
+ class Http < Atom::HTTP
41
+
42
+ def initialize (auth_token)
43
+
44
+ @auth_token = auth_token
45
+
46
+ super(nil)
47
+ #super({})
48
+
49
+ @allow_all_redirects = true
50
+ end
51
+
52
+ def http_request (
53
+ url_s, method, body=nil, headers={}, www_a=nil, redir_limit=5)
54
+
55
+ headers['Authorization'] = "GoogleLogin auth=#{@auth_token}"
56
+ headers['GData-Version'] = GDATA_VERSION
57
+
58
+ super(url_s, method, body, headers, www_a, redir_limit)
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+
@@ -0,0 +1,208 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2008, John Mettraux, jmettraux@gmail.com
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+ # (MIT license)
24
+ #++
25
+ #
26
+
27
+ #
28
+ # John Mettraux
29
+ #
30
+ # "Made in Japan" as opposed to "Swiss Made"
31
+ #
32
+ # Wed Nov 12 09:14:09 JST 2008
33
+ #
34
+
35
+ require 'rexml/element'
36
+ require 'rufus/google'
37
+
38
+
39
+ module Rufus
40
+ module Google
41
+
42
+ class Calendar
43
+
44
+ include CollectionMixin
45
+
46
+ #
47
+ # Returns all the events in the calendar.
48
+ #
49
+ # The query hash can be used to 'query' those events. It currently
50
+ # accepts :q, :start_min and :start_max as keys.
51
+ #
52
+ def events (query={})
53
+
54
+ q = query.inject([]) { |a, (k, v)|
55
+ a << "#{k.to_s.gsub(/\_/, '-')}=#{v}"
56
+ }.join("&")
57
+
58
+ q = "?#{q}" if q.length > 0
59
+
60
+ feed = Rufus::Google.feed_for("#{href}#{q}", @token)
61
+ feed.update!
62
+
63
+ feed.entries.collect { |e| Event.new(e) }
64
+ end
65
+
66
+ #
67
+ # Posts (creates) a QuickAdd event
68
+ # in this calendar.
69
+ #
70
+ # http://code.google.com/apis/calendar/developers_guide_protocol.html#CreatingQuickAdd
71
+ #
72
+ def post_quick! (event_text)
73
+
74
+ post!(Event.create_quick(event_text))
75
+ end
76
+
77
+ #
78
+ # Returns a hash calendar_name => calendar
79
+ #
80
+ # an example :
81
+ #
82
+ # calendars = Rufus::Google::Calendar.get_calendars(
83
+ # :account => ENV['GUSER'], :password => env['GPASS'])
84
+ # calendars.values.each { |c| p [ c.name, c.href ] }
85
+ #
86
+ def self.get_calendars (options)
87
+
88
+ options[:service] = :cl
89
+
90
+ feed = Rufus::Google.feed_for(
91
+ 'https://www.google.com/calendar/feeds/default', options)
92
+
93
+ feed.update! # fetch the data over the net
94
+
95
+ feed.entries.inject({}) { |h, e|
96
+ c = Calendar.new(options[:auth], e)
97
+ h[c.name] = c
98
+ h
99
+ }
100
+ end
101
+ end
102
+
103
+ #
104
+ # A google calendar event.
105
+ #
106
+ class Event
107
+
108
+ include EntryMixin
109
+
110
+ def start_time
111
+ evalue('when', 'startTime', :time => true)
112
+ end
113
+
114
+ def end_time
115
+ evalue('when', 'endTime', :time => true)
116
+ end
117
+
118
+ def where
119
+ evalue('where', 'valueString')
120
+ end
121
+
122
+ # TODO : add method for recurrence
123
+
124
+ def to_s
125
+ {
126
+ :id => @entry.id,
127
+ :etag => etag,
128
+ :title => @entry.title.to_s,
129
+ :start_time => start_time,
130
+ :end_time => end_time,
131
+ :where => where,
132
+ :author => "#{author.name} #{author.email}"
133
+ }.inspect
134
+ end
135
+
136
+ def self.create (opts)
137
+
138
+ e = Atom::Entry.new
139
+ e.title = opts[:title]
140
+ e.updated!
141
+
142
+ if c = opts[:content]
143
+ e.content = c
144
+ e.content['type'] = opts[:type] || 'text'
145
+ end
146
+
147
+ if st = opts[:start_time]
148
+
149
+ st = st.is_a?(DateTime) ? st : DateTime.parse(st)
150
+ st = st.to_s
151
+ st = st[0, 10] if opts[:all_day]
152
+
153
+ w = REXML::Element.new('gd:when')
154
+ w.add_attribute('startTime', st)
155
+
156
+ if et = opts[:end_time]
157
+
158
+ et = et.is_a?(DateTime) ? et : DateTime.parse(et)
159
+ et = et.to_s
160
+ et = et[0, 10] if opts[:all_day]
161
+
162
+ w.add_attribute('endTime', et)
163
+ end
164
+
165
+ e.extensions << w
166
+ end
167
+
168
+ if rc = opts[:recurrence]
169
+
170
+ r = REXML::Element.new('gd:recurrence')
171
+ r.text = rc
172
+
173
+ e.extensions << r
174
+ end
175
+
176
+ e.extensions.attributes['xmlns:gd'] =
177
+ 'http://schemas.google.com/g/2005'
178
+ e.extensions.attributes['xmlns:gCal'] =
179
+ 'http://schemas.google.com/gCal/2005'
180
+
181
+ #p e.to_xml.to_s
182
+
183
+ Event.new(e)
184
+ end
185
+
186
+ #
187
+ # Creates a QuickAdd event.
188
+ #
189
+ # http://code.google.com/apis/calendar/developers_guide_protocol.html#CreatingQuickAdd
190
+ #
191
+ def self.create_quick (text)
192
+
193
+ e = create(
194
+ :title => 'nada',
195
+ :type => 'html',
196
+ :content => text)
197
+
198
+ qa = REXML::Element.new('gCal:quickadd')
199
+ qa.add_attribute('value', 'true')
200
+ e.entry.extensions << qa
201
+
202
+ e
203
+ end
204
+ end
205
+
206
+ end
207
+ end
208
+
@@ -0,0 +1,228 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2008, John Mettraux, jmettraux@gmail.com
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+ # (MIT license)
24
+ #++
25
+ #
26
+
27
+ #
28
+ # John Mettraux
29
+ #
30
+ # Made in Japan
31
+ #
32
+ # Tue Nov 11 15:21:44 JST 2008
33
+ #
34
+
35
+ require 'cgi'
36
+ require 'uri'
37
+ require 'time'
38
+ require 'rufus/verbs'
39
+ require 'atom/feed'
40
+ #require 'atom/service'
41
+ require 'atom/collection'
42
+ require 'rufus/ahttp'
43
+
44
+ module Rufus
45
+ module Google
46
+
47
+ GDATA_VERSION = '2'
48
+
49
+ #
50
+ # Gets an auth token via the Google ClientLogin facility
51
+ #
52
+ def self.get_auth_tokens (options)
53
+
54
+ account = options[:account]
55
+ account_type = options[:account_type] || 'GOOGLE'
56
+ password = options[:password]
57
+ service = options[:service] || :cl
58
+ source = options[:source] || "rufus.rubyforge.org-rufus_google-#{VERSION}"
59
+
60
+ account = "#{account}@gmail.com" unless account.index('@')
61
+
62
+ password = CGI.escape(password)
63
+
64
+ data = ''
65
+ data << "accountType=#{account_type}&"
66
+ data << "Email=#{account}&"
67
+ data << "Passwd=#{password}&"
68
+ data << "service=#{service}&"
69
+ data << "source=#{source}"
70
+
71
+ headers = { 'Content-type' => 'application/x-www-form-urlencoded' }
72
+ headers['GData-Version'] = GDATA_VERSION
73
+
74
+ r = Rufus::Verbs.post(
75
+ 'https://www.google.com/accounts/ClientLogin',
76
+ :headers => headers,
77
+ :data => data)
78
+
79
+ code = r.code.to_i
80
+
81
+ raise r.body if code == 403
82
+ raise "not a 200 OK reply : #{code} : #{r.body}" unless code == 200
83
+
84
+ tokens = r.body.split.inject({}) { |h, l|
85
+ md = l.match(/^(.*)=(.*$)/)
86
+ h[md[1].downcase.to_sym] = md[2]
87
+ h
88
+ }
89
+
90
+ options.merge!(tokens)
91
+
92
+ tokens
93
+ end
94
+
95
+ #
96
+ # Returns the auth token for a google account.
97
+ #
98
+ def self.get_auth_token (options)
99
+
100
+ return options if options.is_a?(String)
101
+
102
+ options[:auth] || get_auth_tokens(options)[:auth]
103
+ end
104
+
105
+ #
106
+ # A small method for getting an atom-tools Feed instance.
107
+ # The options hash is a get_auth_token() hash.
108
+ #
109
+ def self.feed_for (feed_uri, options)
110
+
111
+ token = get_auth_token(options)
112
+
113
+ Atom::Feed.new(feed_uri, Rufus::Google::Http.new(token))
114
+ end
115
+
116
+ module CollectionMixin
117
+
118
+ attr_reader :name, :href
119
+
120
+ def initialize (auth_token, entry)
121
+
122
+ @token = auth_token
123
+ @name = entry.title.to_s
124
+ @href = entry.links.find { |l| l.rel == 'alternate' }.href
125
+ end
126
+
127
+ #
128
+ # Posts (creates) an object
129
+ #
130
+ # Returns the URI of the created resource.
131
+ #
132
+ def post! (o)
133
+
134
+ r = collection.post!(o.entry)
135
+
136
+ raise "posting object of class #{o.class} failed : #{r.body}" \
137
+ unless r.code.to_i == 201
138
+
139
+ r['Location']
140
+ end
141
+
142
+ #
143
+ # Removes an object from the collection
144
+ #
145
+ def delete! (entry)
146
+
147
+ uri = entry.entry.edit_url
148
+
149
+ #r = collection.delete!(nil, uri)
150
+ r = collection.http.delete(uri, nil, { 'If-Match' => entry.etag })
151
+
152
+ raise "failed to delete entry (#{r.code}): #{r.body}" \
153
+ unless r.code.to_i == 200
154
+
155
+ r
156
+ end
157
+
158
+ protected
159
+
160
+ #
161
+ # returns the Atom::Collection instance
162
+ #
163
+ def collection
164
+
165
+ return @collection if @collection
166
+
167
+ @collection = Atom::Collection.new(
168
+ href, Rufus::Google::Http.new(@token))
169
+ end
170
+ end
171
+
172
+ #
173
+ # A mixin for entry based objects (like cal events for example)
174
+ #
175
+ module EntryMixin
176
+
177
+ attr_reader :entry
178
+
179
+ #
180
+ # Creates a google calendar event based on the info found in an
181
+ # atom-tools Entry instance.
182
+ #
183
+ def initialize (entry)
184
+ @entry = entry
185
+ end
186
+
187
+ def title
188
+ @entry.title.to_s
189
+ end
190
+
191
+ def author
192
+ @entry.authors.first
193
+ end
194
+
195
+ def authors
196
+ @entry.authors
197
+ end
198
+
199
+ def etag
200
+ @entry.extensions.attributes['gd:etag']
201
+ end
202
+
203
+ protected
204
+
205
+ #
206
+ # fetches a value in the extension part of the entry
207
+ #
208
+ # :time => true will attempt to parse the value to a Time instance
209
+ #
210
+ def evalue (elt_name, att_name, options={})
211
+
212
+ v = @entry.extensions.find { |e|
213
+ e.name == elt_name
214
+ }
215
+
216
+ return nil unless v
217
+
218
+ v = v.attribute(att_name)
219
+
220
+ v = Time.parse(v.value) if options[:time] == true
221
+
222
+ v
223
+ end
224
+ end
225
+
226
+ end
227
+ end
228
+
@@ -0,0 +1,42 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2008, John Mettraux, jmettraux@gmail.com
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+ # (MIT license)
24
+ #++
25
+ #
26
+
27
+ #
28
+ # John Mettraux
29
+ #
30
+ # Made in Japan
31
+ #
32
+ # Wed Nov 12 20:08:24 JST 2008
33
+ #
34
+
35
+ module Rufus
36
+ module Google
37
+
38
+ VERSION = '0.0.1'
39
+
40
+ end
41
+ end
42
+
@@ -0,0 +1,31 @@
1
+
2
+ require 'rubygems'
3
+ require 'rufus/gcal'
4
+
5
+ calendars = Rufus::Google::Calendar.get_calendars(
6
+ :account => ENV['GUSER'], :password => ENV['GPASS'])
7
+
8
+ #calendars.values.each { |c| p [ c.name, c.href ] }
9
+
10
+ cal = calendars['gtest']
11
+
12
+ #id = cal.post_quick!('Tennis with John November 13 3pm-4:30pm')
13
+ #t = Time.now
14
+ #id = cal.post!(Rufus::Google::Event.create(
15
+ # :title => 'drink Tequila at the Tennis club',
16
+ # :start_time => t,
17
+ # :end_time => t + 3600))
18
+
19
+ #cal.events(:q => 'tennis').each do |e|
20
+ cal.events().each do |e|
21
+ puts
22
+ puts e.to_s
23
+ #puts e.entry.to_s.gsub(/</, "\n<")
24
+ #puts e.entry.inspect
25
+ #p e.entry.extensions.attributes
26
+ #cal.delete!(e)
27
+ end
28
+ #cal.delete!(id)
29
+
30
+ #puts "#{cal.events(:q => 'tennis').size} tennis events"
31
+
@@ -0,0 +1,39 @@
1
+
2
+ #
3
+ # Testing rufus-google
4
+ #
5
+ # Wed Nov 12 20:59:36 JST 2008
6
+ #
7
+
8
+ require 'test/unit'
9
+ require 'rubygems'
10
+ require 'rufus/gcal'
11
+
12
+ class Test0Cal < Test::Unit::TestCase
13
+
14
+ def test_0
15
+
16
+ calendars = Rufus::Google::Calendar.get_calendars(
17
+ :account => ENV['GUSER'], :password => ENV['GPASS'])
18
+
19
+ cal = calendars['gtest']
20
+
21
+ #cal.events(:q => 'zorglub').each { |e| puts e.entry.to_s }
22
+ #cal.events(:q => 'zorglub').each { |e| puts e.to_s }
23
+ #return
24
+ cal.events(:q => 'zorglub').each { |e| cal.delete!(e) }
25
+
26
+ event_id = cal.post_quick!('Tennis with Zorglub November 13 3pm-4:30pm')
27
+
28
+ evts = cal.events(:q => 'zorglub')
29
+
30
+ assert_equal 1, evts.size
31
+ assert_equal 'Tennis with Zorglub', evts.first.title
32
+
33
+ cal.delete!(evts.first)
34
+
35
+ assert_equal [], cal.events(:q => 'zorglub')
36
+ end
37
+
38
+ end
39
+
@@ -0,0 +1,3 @@
1
+
2
+ require 't_0_cal.rb'
3
+
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rufus-google
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - John Mettraux
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-03 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rufus-verbs
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: atom-tools
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description:
36
+ email: john at gmail dot com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.txt
43
+ files:
44
+ - lib/rufus
45
+ - lib/rufus/ahttp.rb
46
+ - lib/rufus/gcal.rb
47
+ - lib/rufus/google.rb
48
+ - lib/rufus/gversion.rb
49
+ - lib/rufus-google.rb
50
+ - test/t0.rb
51
+ - test/t_0_cal.rb
52
+ - test/test.rb
53
+ - README.txt
54
+ has_rdoc: true
55
+ homepage: http://rufus.rubyforge.org/rufus-google
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ requirements:
74
+ - rufus-verbs
75
+ - atom-tools
76
+ rubyforge_project: rufus
77
+ rubygems_version: 1.3.1
78
+ signing_key:
79
+ specification_version: 2
80
+ summary: snippets of Ruby code for accessing Google stuff
81
+ test_files:
82
+ - test/test.rb