gtasks 0.0.0

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,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 kimoto
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ = gtasks
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2012 kimoto. See LICENSE for details.
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "gtasks"
8
+ gem.summary = %Q{GoogleTasks CommandLine Interface}
9
+ gem.description = %Q{GoogleTasks CommandLine Interface}
10
+ gem.email = "sub+peerler@gmail.com"
11
+ gem.homepage = "http://github.com/kimoto/gtasks"
12
+ gem.authors = ["kimoto"]
13
+ gem.add_development_dependency "thoughtbot-shoulda"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/*_test.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+ task :test => :check_dependencies
41
+
42
+ task :default => :test
43
+
44
+ require 'rake/rdoctask'
45
+ Rake::RDocTask.new do |rdoc|
46
+ if File.exist?('VERSION')
47
+ version = File.read('VERSION')
48
+ else
49
+ version = ""
50
+ end
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "gtasks #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # Author: kimoto
4
+ require 'gtasks'
5
+ require 'logger'
6
+
7
+ if $0 == __FILE__
8
+ sub_command = ARGV.shift || 'list'
9
+ cli = GoogleTaskCLI.new(
10
+ :client_id => '',
11
+ :client_secret => '',
12
+ #:logger => Logger.new(STDERR),
13
+ :no_refresh => true
14
+ )
15
+
16
+ case sub_command
17
+ when 'list'
18
+ cli.list(ARGV.shift || 'default')
19
+ when 'lists'
20
+ cli.lists
21
+ when 'add'
22
+ raise ArgumentError if ARGV.empty?
23
+ cli.add(ARGV.join(' '))
24
+ when 'clear'
25
+ cli.clear
26
+ when 'done'
27
+ param = ARGV.shift or raise ArgumentError
28
+ cli.done(param)
29
+ when 'delete'
30
+ param = ARGV.shift or raise ArgumentError
31
+ cli.delete(param)
32
+ when 'choice'
33
+ cli.choice
34
+ else
35
+ raise ArgumentError
36
+ end
37
+ end
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{gtasks}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["kimoto"]
12
+ s.date = %q{2012-02-03}
13
+ s.description = %q{GoogleTasks CommandLine Interface}
14
+ s.email = %q{sub+peerler@gmail.com}
15
+ s.default_executable = %q{gtasks}
16
+ s.executables = %q{gtasks}
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/gtasks",
29
+ "lib/gtasks.rb",
30
+ "test/gtasks_test.rb",
31
+ "test/test_helper.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/kimoto/gtasks}
34
+ s.rdoc_options = ["--charset=UTF-8"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.3.7}
37
+ s.summary = %q{GoogleTasks CommandLine Interface}
38
+ s.test_files = [
39
+ "test/test_helper.rb",
40
+ "test/gtasks_test.rb"
41
+ ]
42
+
43
+ s.add_dependency 'oauth2'
44
+ s.add_dependency 'rack'
45
+ s.add_dependency 'yaml'
46
+ s.add_dependency 'json'
47
+ s.add_dependency 'awesome_print'
48
+
49
+ if s.respond_to? :specification_version then
50
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
60
+ end
61
+ end
@@ -0,0 +1,441 @@
1
+ # encoding: utf-8
2
+ require 'oauth2'
3
+ require 'open-uri'
4
+ require 'webrick'
5
+ require 'rack'
6
+ require 'uri'
7
+ require 'yaml'
8
+ require 'json'
9
+ require 'awesome_print'
10
+ require 'logger'
11
+ require 'fileutils'
12
+
13
+ class GoogleTaskAPI
14
+ public
15
+ class << self
16
+ def default_dat_path
17
+ File.join(ENV['HOME'], ".google_tasks.yml")
18
+ end
19
+
20
+ def default_callback_uri
21
+ scheme = "http"
22
+ hostname = `hostname`.chomp
23
+ port = 9999
24
+ callback = '/oauth_callback'
25
+
26
+ base_url = "#{scheme}://#{hostname}:#{port}"
27
+ URI.join(base_url, callback).to_s
28
+ end
29
+ end
30
+
31
+ def initialize(options={})
32
+ @client_id = options[:client_id] or raise ArgumentError.new
33
+ @client_secret = options[:client_secret] or raise ArgumentError.new
34
+ @logger = options[:logger] ||= Logger.new(nil)
35
+ @callback_uri = options[:callback_uri] ||= GoogleTaskAPI::default_callback_uri
36
+ @no_refresh = options[:no_refresh] ||= false
37
+
38
+ @client = OAuth2::Client.new(
39
+ @client_id,
40
+ @client_secret,
41
+ :site => 'https://www.googleapis.com/',
42
+ :authorize_url => 'https://accounts.google.com/o/oauth2/auth',
43
+ :token_url => 'https://accounts.google.com/o/oauth2/token')
44
+
45
+ refresh_or_auth GoogleTaskAPI.default_dat_path
46
+
47
+ if block_given?
48
+ yield self
49
+ end
50
+ end
51
+
52
+
53
+ def task_list(tasklist_ident='@default')
54
+ @token.get("/tasks/v1/lists/#{tasklist_ident}/tasks").parsed
55
+ end
56
+
57
+ def task_get(tasklist_ident, task_ident)
58
+ @token.get("/tasks/v1/lists/#{tasklist_ident}/tasks/#{task_ident}").parsed
59
+ end
60
+
61
+ def task_insert(tasklist_ident, params={})
62
+ @token.post("/tasks/v1/lists/#{tasklist_ident}/tasks"){ |req|
63
+ req.headers["Content-Type"] = "application/json"
64
+ req.body = params.to_json
65
+ }
66
+ end
67
+
68
+ def task_update(tasklist_ident, task_ident, opts={})
69
+ task_info = task_get(tasklist_ident, task_ident)
70
+ params = task_info.merge(opts)
71
+
72
+ @token.put("/tasks/v1/lists/#{tasklist_ident}/tasks/#{task_ident}"){ |req|
73
+ req.headers["Content-Type"] = "application/json"
74
+ req.body = params.to_json
75
+ }
76
+ end
77
+
78
+ def task_delete(tasklist_ident, task_ident)
79
+ @token.delete("/tasks/v1/lists/#{tasklist_ident}/tasks/#{task_ident}")
80
+ end
81
+
82
+ ## ORDER系
83
+ def task_move(tasklist_ident, task_ident)
84
+ # TODO
85
+ end
86
+
87
+ # 完了済みタスクの全削除
88
+ def task_clear(tasklist_ident)
89
+ @token.post("/tasks/v1/lists/#{tasklist_ident}/clear").parsed
90
+ end
91
+
92
+ def tasklist_list(username = '@me')
93
+ @token.get("/tasks/v1/users/#{username}/lists").parsed
94
+ end
95
+
96
+ def tasklist_get(username, ident)
97
+ @token.get("/tasks/v1/users/#{username}/lists/#{ident}").parsed
98
+ end
99
+
100
+ def tasklist_insert(username, listname)
101
+ @token.post("/tasks/v1/users/#{username}/lists"){ |req|
102
+ req.headers["Content-Type"] = "application/json"
103
+ req.body = {:title => listname}.to_json
104
+ }
105
+ end
106
+
107
+ def tasklist_update(username, tasklist_ident, params={})
108
+ info = tasklist_get(username, tasklist_ident)
109
+ params = info.merge(params)
110
+
111
+ @token.put("/tasks/v1/users/#{username}/lists/#{tasklist_ident}"){ |req|
112
+ req.headers["Content-Type"] = "application/json"
113
+ req.body = params.to_json
114
+ }
115
+ end
116
+
117
+ def tasklist_delete(username, tasklist_ident)
118
+ @token.delete("/tasks/v1/users/#{username}/lists/#{tasklist_ident}")
119
+ end
120
+
121
+ def refresh_or_auth(dat_path)
122
+ @dat_path = dat_path
123
+ @logger.info "dat_path is #{@dat_path.inspect}"
124
+ if File.exists? @dat_path
125
+ @logger.info "dat_path already exist"
126
+ load_from_file @dat_path # load access token
127
+ @logger.info "loaded"
128
+
129
+ if @token.refresh_token.nil?
130
+ @logger.info "retry auth"
131
+ auth @callback_uri
132
+ @logger.info "successful auth"
133
+
134
+ @logger.info "save to #{@dat_path}"
135
+ save_to_file @dat_path
136
+ @logger.info "saved"
137
+ else
138
+ @logger.info "try to refresh"
139
+ refresh @dat_path # refresh and save access token
140
+ @logger.info "successful refresh"
141
+ end
142
+ else
143
+ begin
144
+ @logger.info "try to oauth2 authentication"
145
+ auth @callback_uri # generate access token
146
+ @logger.info "successful oauth2 authentication"
147
+
148
+ @logger.info "save to #{@dat_path}"
149
+ save_to_file @dat_path # save token
150
+ @logger.info "saved"
151
+ rescue => ex
152
+ FileUtils.rm @dat_path
153
+ @logger.info "error detect. remove #{@dat_path.inspect}"
154
+ @logger.info "error information: #{ex.inspect}"
155
+ end
156
+ end
157
+ end
158
+
159
+ private
160
+ def auth(redirect_uri = GoogleTaskAPI.default_callback_uri)
161
+ @logger.info "oauth2 authentication start"
162
+ url = @client.auth_code.authorize_url(
163
+ :scope => 'https://www.googleapis.com/auth/tasks',
164
+ :redirect_uri => redirect_uri,
165
+ :access_type => 'offline',
166
+ :approval_prompt => 'force')
167
+ puts "please open this OAuth2 authentication URL: #{url}"
168
+
169
+ uri = URI.parse(redirect_uri)
170
+ server = WEBrick::HTTPServer.new(:BindAddress => uri.host, :Port => uri.port, :Logger => @logger)
171
+ trap(:INT){server.shutdown}
172
+
173
+ server.mount_proc(uri.path){ |req, res|
174
+ request_params = Rack::Utils.parse_query(req.query_string)
175
+ @logger.info "accept queries: #{request_params.inspect}"
176
+
177
+ @code = request_params['code']
178
+ @logger.info "authenticate code is #{@code.inspect}"
179
+
180
+ res.body = <<EOT
181
+ <html>
182
+ <body>
183
+ <h1>authorization successful</h1>
184
+ <p>#{@code}</p>
185
+ </body>
186
+ </html>
187
+ EOT
188
+ @logger.info "webrick shutting down"
189
+ server.shutdown
190
+ @logger.info "shutdown"
191
+
192
+ @logger.info "try to get access token"
193
+ @token = @client.auth_code.get_token(@code, :redirect_uri => redirect_uri)
194
+ @logger.info "got access token: #{@token.token.inspect}"
195
+ }
196
+ @logger.info "starting webrick server: #{uri.to_s}"
197
+ server.start
198
+
199
+ puts "authentication success"
200
+
201
+ @token
202
+ end
203
+
204
+ def refresh(path=GoogleTaskAPI.default_dat_path)
205
+ @logger.info "current state is " + token_params.ai
206
+ @logger.info "refresh option specified: #{@no_refresh.inspect}"
207
+ if @no_refresh
208
+ @logger.info "refresh ignored"
209
+ return
210
+ end
211
+
212
+ new_token = @token.refresh!
213
+
214
+ params = {
215
+ :refresh_token => @token.refresh_token,
216
+ :expires_at => new_token.expires_at,
217
+ :expires_in => new_token.expires_in
218
+ }
219
+ @token = OAuth2::AccessToken.new(@client, new_token.token, params)
220
+
221
+ @logger.info "refreshed!"
222
+ @logger.info "refreshed state is " + token_params.ai
223
+
224
+ @logger.info "try to save to #{path}"
225
+ save_to_file(path)
226
+ @logger.info "saved"
227
+ end
228
+
229
+ def token_params
230
+ {
231
+ :expires_at => @token.expires_at,
232
+ :expires_in => @token.expires_in,
233
+ :refresh_token => @token.refresh_token,
234
+ :token => @token.token
235
+ }
236
+ end
237
+
238
+ def save_to_file(path)
239
+ File.open(path, "w"){ |f|
240
+ f.write token_params.to_yaml
241
+ }
242
+ end
243
+
244
+ def load_from_file(path)
245
+ opts = YAML.load_file(path)
246
+ token = opts.delete(:token)
247
+ @token = OAuth2::AccessToken.new(@client, token, opts)
248
+ end
249
+ end
250
+
251
+ class GoogleTask
252
+ public
253
+ def initialize(options={})
254
+ @client_id = options[:client_id] or raise ArgumentError.new
255
+ @client_secret = options[:client_secret] or raise ArgumentError.new
256
+ @logger = options[:logger] ||= Logger.new(nil)
257
+ @no_refresh = options[:no_refresh] ||= false
258
+
259
+ @gs_api = GoogleTaskAPI.new(:client_id => @client_id, :client_secret => @client_secret, :logger => @logger, :no_refresh => @no_refresh)
260
+ end
261
+
262
+ def tasks(list_ident = '@default')
263
+ @gs_api.task_list(list_ident)["items"]
264
+ end
265
+
266
+ def clear(list_ident = '@default')
267
+ @gs_api.task_clear(list_ident)
268
+ end
269
+
270
+ def add(task_name, list_ident = '@default')
271
+ @gs_api.task_insert(list_ident, :title => task_name)
272
+ end
273
+
274
+ def regexp_if(regexp, list_ident = '@default')
275
+ matched = []
276
+ @gs_api.task_list(list_ident)["items"].each{ |item|
277
+ if regexp.match(item["title"])
278
+ yield(item) if block_given?
279
+ matched << item
280
+ end
281
+ }
282
+ matched
283
+ end
284
+
285
+ def delete(task_number, list_ident = '@default')
286
+ task_proc(task_number){ |task|
287
+ @gs_api.task_delete(list_ident, task["id"])
288
+ }
289
+ end
290
+
291
+ def delete_if(regexp, list_ident = '@default')
292
+ regexp_if(regexp, list_ident){ |item|
293
+ @logger.info "try to delete: #{item["title"]} (#{item["id"]})"
294
+ @gs_api.task_delete(list_ident, item["id"])
295
+ @logger.info "deleted: #{item["title"]}"
296
+ }
297
+ end
298
+
299
+ def done(task_number, list_ident = '@default')
300
+ task_proc(task_number) { |task|
301
+ @gs_api.task_update(list_ident, task["id"], "status" => "completed")
302
+ }
303
+ end
304
+
305
+ def done_if(regexp, list_ident = '@default')
306
+ regexp_if(regexp, list_ident){ |item|
307
+ @logger.info "try to done task: #{item["title"]} (#{item["id"]})"
308
+ @gs_api.task_update(list_ident, item["id"], "status" => "completed")
309
+ @logger.info "updated: #{item["title"]}"
310
+ }
311
+ end
312
+
313
+ def lists(username = '@me')
314
+ @gs_api.tasklist_list(username)["items"]
315
+ end
316
+
317
+ def all_tasks(username = '@me')
318
+ hash = {}
319
+ @gs_api.tasklist_list(username)["items"].map{ |item|
320
+ hash[item["title"]] ||= []
321
+ hash[item["title"]] += tasks(item["id"]).map{|e| e["title"]}
322
+ }
323
+ hash
324
+ end
325
+
326
+ def show(username = '@me')
327
+ all_tasks.each{ |list_title, tasks|
328
+ puts "*#{list_title}"
329
+ tasks.each{ |task|
330
+ puts "\t#{task}"
331
+ }
332
+ }
333
+ end
334
+
335
+ private
336
+ def task_proc(task_number, &block)
337
+ tasks.each_with_index{ |task, index|
338
+ if index == task_number
339
+ block.call(task)
340
+ break
341
+ end
342
+ }
343
+ end
344
+ end
345
+
346
+ class GoogleTaskCLI
347
+ def initialize(options={})
348
+ @gtasks = GoogleTask.new(options)
349
+ end
350
+
351
+ def list(scope = 'default')
352
+ case scope
353
+ when 'all'
354
+ list_all
355
+ when /^[0-9]+/
356
+ list_number = scope.to_i
357
+ list_id = @gtasks.lists[list_number]["id"]
358
+ print_list(list_id)
359
+ when 'default'
360
+ print_list('@default')
361
+ else
362
+ raise ArgumentError
363
+ end
364
+ end
365
+
366
+ def lists
367
+ print_selector @gtasks.lists.map{|e| e["title"]}
368
+ end
369
+
370
+ def list_all
371
+ @gtasks.show
372
+ end
373
+
374
+ def print_list(list_id)
375
+ @gtasks.tasks(list_id).each_with_index{ |task, index|
376
+ title = task["title"]
377
+ if task["status"] == 'completed'
378
+ done_string = '☑'
379
+ else
380
+ done_string = '☐'
381
+ end
382
+ puts "[#{index}] #{done_string} #{title}"
383
+ }
384
+ end
385
+
386
+ def add(task_name)
387
+ @gtasks.add(task_name)
388
+ list
389
+ end
390
+
391
+ def clear
392
+ @gtasks.clear
393
+ list
394
+ end
395
+
396
+ def done(param)
397
+ # 数字オンリーだったら番号指定のタスクdoneと認識する
398
+ if param =~ /^[0-9]+$/
399
+ @gtasks.done(param.to_i)
400
+ else
401
+ # それ以外は正規表現として認識、タスク名が正規表現にマッチしたものをすべて完了する
402
+ @gtasks.done_if Regexp.new(param.to_s)
403
+ end
404
+ list
405
+ end
406
+
407
+ def delete(param)
408
+ # 数字オンリーだったら番号指定のタスクdoneと認識する
409
+ if param =~ /^[0-9]+$/
410
+ @gtasks.delete(param.to_i)
411
+ else
412
+ # それ意外は正規表現として認識、タスク名がマッチしたものをすべて完了する
413
+ @gtasks.delete_if Regexp.new(param.to_s)
414
+ end
415
+ list
416
+ end
417
+
418
+ def choice
419
+ items = @gtasks.tasks.map{|e| e["title"]}
420
+ rand_index = ((rand * items.size) + 1).to_i
421
+ build_selector_format(rand_index, items[rand_index]).display
422
+ end
423
+
424
+ private
425
+ # 指定された配列を番号表記の文字列に変換します
426
+ def array_to_selector(array)
427
+ string = ""
428
+ array.each_with_index{ |item, index|
429
+ string += build_selector_format(index, item)
430
+ }
431
+ string
432
+ end
433
+
434
+ def print_selector(array)
435
+ array_to_selector(array).display
436
+ end
437
+
438
+ def build_selector_format(index, identify, linefeed=$/)
439
+ "[#{index}] #{identify}#{linefeed}"
440
+ end
441
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class GtasksTest < Test::Unit::TestCase
4
+ should "do not anything" do
5
+ true
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'gtasks'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gtasks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - kimoto
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thoughtbot-shoulda
16
+ requirement: &253209700 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *253209700
25
+ description: GoogleTasks CommandLine Interface
26
+ email: sub+peerler@gmail.com
27
+ executables:
28
+ - gtasks
29
+ extensions: []
30
+ extra_rdoc_files:
31
+ - LICENSE
32
+ - README.rdoc
33
+ files:
34
+ - .document
35
+ - LICENSE
36
+ - README.rdoc
37
+ - Rakefile
38
+ - VERSION
39
+ - bin/gtasks
40
+ - gtasks.gemspec
41
+ - lib/gtasks.rb
42
+ - test/gtasks_test.rb
43
+ - test/test_helper.rb
44
+ homepage: http://github.com/kimoto/gtasks
45
+ licenses: []
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 1.8.11
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: GoogleTasks CommandLine Interface
68
+ test_files: []