gtasks 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []