taskwarrior 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+
6
+ before_script:
7
+ - task rc.confirmation=off version
8
+
9
+ before_install:
10
+ - echo | sudo add-apt-repository ppa:ultrafredde/ppa
11
+ - sudo apt-get update
12
+ - sudo apt-get install task
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in taskwarrior.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,12 @@
1
+ guard 'bundler' do
2
+ watch('Gemfile')
3
+ watch(/^.+\.gemspec/)
4
+ end
5
+
6
+ guard :test, :test_paths => ['test/unit', 'test/integration'] do
7
+ watch('lib/twdeps.rb'){"test"}
8
+ watch(%r{^lib/twdeps/(.+)\.rb$}){|m| "test/unit/test_#{m[1]}.rb"}
9
+ watch(%r{^test/unit/test_(.+)\.rb$})
10
+ watch('test/test_helper.rb'){"test"}
11
+ watch('test/helpers/**/*'){"test"}
12
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Nicholas E. Rabenau
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # taskwarrior
2
+
3
+ Ruby bindings for [TaskWarrior](http://taskwarrior.org)
4
+
5
+ [![Build Status](https://secure.travis-ci.org/nerab/taskwarrior.png?branch=master)](http://travis-ci.org/nerab/taskwarrior)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'taskwarrior'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install taskwarrior
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test' << 'test/helpers'
7
+ test.test_files = FileList['test/**/test_*.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,12 @@
1
+ require "taskwarrior/version"
2
+
3
+ require "taskwarrior/task"
4
+ require "taskwarrior/project"
5
+ require "taskwarrior/tag"
6
+ require "taskwarrior/repository"
7
+ require "taskwarrior/task_mapper"
8
+ require "taskwarrior/priority_mapper"
9
+
10
+ module TaskWarrior
11
+ # Your code goes here...
12
+ end
@@ -0,0 +1,9 @@
1
+ module TaskWarrior
2
+ class PriorityMapper
3
+ class << self
4
+ def map(json)
5
+ {'H' => :high, 'M' => :medium, 'L' => :low}[json]
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ require 'active_model'
2
+
3
+ module TaskWarrior
4
+ class Project
5
+ attr_reader :name, :tasks
6
+
7
+ include ActiveModel::Validations
8
+ validates :name, :presence => true
9
+ validate :name_may_not_contain_spaces
10
+
11
+ def initialize(name, tasks = [])
12
+ @name = name
13
+ @tasks = tasks
14
+ @tasks.each{|t| t.project = self}
15
+ end
16
+
17
+ def <<(task)
18
+ @tasks << task
19
+ task.project = self
20
+ end
21
+
22
+ def to_s
23
+ "Project #{name} (#{@tasks.size} tasks)"
24
+ end
25
+
26
+ private
27
+ def name_may_not_contain_spaces
28
+ if !name.blank? and name[/\s/]
29
+ errors.add(:name, "may not contain spaces")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,64 @@
1
+ require 'json'
2
+
3
+ module TaskWarrior
4
+ class Repository
5
+ def initialize(input)
6
+ @tasks = {}
7
+ @projects = Hash.new{|hash, key| hash[key] = Project.new(key)}
8
+ @tags = Hash.new{|hash, key| hash[key] = Tag.new(key)}
9
+
10
+ JSON.parse(input).each{|json|
11
+ task = TaskWarrior::TaskMapper.map(json)
12
+ @tasks[task.uuid] = task
13
+ @projects[task.project].tasks << task if task.project
14
+
15
+ # Create a new Tag object in @tags that is the value for each tag name
16
+ task.tags.each{|tag_name| @tags[tag_name] << task}
17
+ }
18
+
19
+ # Replace the uuid of each dependency with the real task
20
+ @tasks.each_value{|task| task.dependencies.map!{|uuid| @tasks[uuid]}}
21
+
22
+ # Replace the project property of each task with a proper Project object carrying a name and all of the project's tasks
23
+ @tasks.each_value{|task| task.project = @projects[task.project] if task.project}
24
+
25
+ # Add child tasks to their parent, but keep them in the global index
26
+ @tasks.each_value do |task|
27
+ if task.parent
28
+ parent = @tasks[task.parent]
29
+
30
+ if parent # we know the parent
31
+ parent.children << task
32
+ task.parent = parent
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def tasks
39
+ # Do not expose child tasks directly
40
+ @tasks.values.reject{|t| t.parent}
41
+ end
42
+
43
+ # direct lookup by uuid
44
+ def [](uuid)
45
+ @tasks[uuid]
46
+ end
47
+
48
+ def projects
49
+ @projects.values
50
+ end
51
+
52
+ def project(name)
53
+ @projects[name] if @projects.has_key?(name)
54
+ end
55
+
56
+ def tags
57
+ @tags.values
58
+ end
59
+
60
+ def tag(name)
61
+ @tags[name] if @tags.has_key?(name)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,48 @@
1
+ require 'active_model'
2
+
3
+ module TaskWarrior
4
+ class Tag
5
+ attr_reader :name
6
+
7
+ include ActiveModel::Validations
8
+ validates :name, :presence => true
9
+ validate :name_may_not_contain_spaces
10
+
11
+ def initialize(tag_or_name, tasks = [])
12
+ if tag_or_name.respond_to?(:name)
13
+ @name = tag_or_name.name
14
+ @tasks = tag_or_name.tasks
15
+ else
16
+ @name = tag_or_name
17
+ @tasks = []
18
+ end
19
+
20
+ tasks.each{|task|
21
+ self << task
22
+ }
23
+ end
24
+
25
+ def <<(task)
26
+ @tasks << task unless @tasks.include?(task)
27
+ end
28
+
29
+ def tasks
30
+ @tasks #.dup
31
+ end
32
+
33
+ def to_s
34
+ "Tag: #{name} (#{@tasks.size} tasks)"
35
+ end
36
+
37
+ def ==(other)
38
+ name == other.name
39
+ end
40
+
41
+ private
42
+ def name_may_not_contain_spaces
43
+ if !name.blank? and name[/\s/]
44
+ errors.add(:name, "may not contain spaces")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,52 @@
1
+ require 'active_model'
2
+
3
+ module TaskWarrior
4
+ class Task
5
+ attr_accessor :description, :id, :entry, :status, :uuid, :project, :dependencies, :parent, :children, :priority
6
+
7
+ include ActiveModel::Validations
8
+ validates :description, :id, :entry, :status, :uuid, :presence => true
9
+
10
+ validates :id, :numericality => { :only_integer => true, :greater_than => 0}
11
+
12
+ validates :uuid, :format => {:with => /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/,
13
+ :message => "'%{value}' does not match the expected format of a UUID"}
14
+
15
+ validates :status, :inclusion => {:in => [:pending, :waiting, :complete], :message => "%{value} is not a valid status"}
16
+
17
+ validates :priority, :inclusion => {
18
+ :in => [:high, :medium, :low],
19
+ :allow_nil => true,
20
+ :allow_blank => true,
21
+ :message => "%{value} is not a valid priority"
22
+ }
23
+
24
+ validate :entry_cannot_be_in_the_future
25
+
26
+ def initialize(description)
27
+ @description = description
28
+ @dependencies = []
29
+ @children = []
30
+ @tags = []
31
+ end
32
+
33
+ def tags
34
+ @tags
35
+ end
36
+
37
+ def to_s
38
+ "Task '#{description}'".tap{|result| result << " <#{uuid}>" if uuid}
39
+ end
40
+
41
+ private
42
+ def entry_cannot_be_in_the_future
43
+ begin
44
+ if !entry.blank? and entry > DateTime.now
45
+ errors.add(:entry, "can't be in the future")
46
+ end
47
+ rescue
48
+ errors.add(:entry, "must be comparable to DateTime")
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,30 @@
1
+ module TaskWarrior
2
+ #
3
+ # A DataMapper that makes new Tasks from a JSON representation
4
+ #
5
+ class TaskMapper
6
+ class << self
7
+ def map(json)
8
+ Task.new(json['description']).tap{|t|
9
+ t.id = json['id'].to_i
10
+ t.uuid = json['uuid']
11
+ t.entry = DateTime.parse(json['entry'])
12
+ t.status = json['status'].to_sym
13
+ t.project = json['project']
14
+
15
+ if json['depends']
16
+ if json['depends'].respond_to?(:split)
17
+ t.dependencies = json['depends'].split(',')
18
+ else
19
+ t.dependencies = json['depends']
20
+ end
21
+ end
22
+
23
+ t.parent = json['parent'] # Children will be cross-indexed in the repository
24
+ t.priority = PriorityMapper.map(json['priority'])
25
+ json['tags'].each{|tag| t.tags << tag} if json['tags']
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module TaskWarrior
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/taskwarrior/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Nicholas E. Rabenau"]
6
+ gem.email = ["nerab@gmx.net"]
7
+ gem.summary = %q{Ruby wrapper for TaskWarrior}
8
+ gem.description = %q{Wraps access to TaskWarrior, the command-line task manager, in a Ruby gem.}
9
+
10
+ gem.files = `git ls-files`.split($\)
11
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
12
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
+ gem.name = "taskwarrior"
14
+ gem.require_paths = ["lib"]
15
+ gem.version = TaskWarrior::VERSION
16
+
17
+ gem.add_dependency 'activemodel', '~> 3.2'
18
+
19
+ gem.add_development_dependency 'activesupport', '~> 3.2'
20
+ gem.add_development_dependency 'twtest', '~> 0.0.5'
21
+ gem.add_development_dependency 'guard-test', '~> 0.5'
22
+ gem.add_development_dependency 'guard-bundler', '~> 1.0'
23
+ gem.add_development_dependency 'rake', '~> 0.9'
24
+
25
+ gem.add_development_dependency 'pry'
26
+ end
@@ -0,0 +1,7 @@
1
+ [{"id":1,"description":"Select a free weekend in November","entry":"20120629T191421Z","priority":"H","project":"party","status":"pending","uuid":"6fd0ba4a-ab67-49cd-ac69-64aa999aff8a","annotations":[{"entry":"20120629T191534Z","description":"the 13th looks good"}]},
2
+ {"id":2,"description":"Select and book a venue","entry":"20120629T191634Z","priority":"H","project":"party","status":"pending","uuid":"c992448a-f1ea-4982-8461-47f0705ff509"},
3
+ {"id":3,"description":"Mail invitations","entry":"20120629T191919Z","project":"party","status":"pending","uuid":"3b53178e-d5a4-45e0-afc2-1292db58a59a"},
4
+ {"id":4,"description":"Select a caterer","entry":"20120629T191919Z","project":"party","status":"pending","uuid":"c590941b-eb10-4569-bdc9-0e339f79305e"},
5
+ {"id":5,"description":"Design invitations","entry":"20120629T191919Z","priority":"H","project":"party","status":"pending","tags":["mall"],"uuid":"e5a867b7-0116-457d-ba43-9ac2bee6ad2a"},
6
+ {"id":6,"description":"Print invitations","entry":"20120629T191920Z","project":"party","status":"pending","tags":["mall"],"uuid":"9f6f3738-1c08-4f45-8eb4-1e90864c7588"}
7
+ ]
@@ -0,0 +1,7 @@
1
+ [{"id":1,"description":"Select a free weekend in November","entry":"20120629T191421Z","priority":"H","project":"party","status":"pending","uuid":"6fd0ba4a-ab67-49cd-ac69-64aa999aff8a","annotations":[{"entry":"20120629T191534Z","description":"the 13th looks good"}]},
2
+ {"id":2,"depends":"6fd0ba4a-ab67-49cd-ac69-64aa999aff8a","description":"Select and book a venue","entry":"20120629T191634Z","priority":"H","project":"party","status":"pending","uuid":"c992448a-f1ea-4982-8461-47f0705ff509"},
3
+ {"id":3,"depends":"9f6f3738-1c08-4f45-8eb4-1e90864c7588","description":"Mail invitations","entry":"20120629T191919Z","project":"party","status":"pending","uuid":"3b53178e-d5a4-45e0-afc2-1292db58a59a"},
4
+ {"id":4,"depends":"6fd0ba4a-ab67-49cd-ac69-64aa999aff8a,c992448a-f1ea-4982-8461-47f0705ff509","description":"Select a caterer","entry":"20120629T191919Z","project":"party","status":"pending","uuid":"c590941b-eb10-4569-bdc9-0e339f79305e"},
5
+ {"id":5,"depends":"c992448a-f1ea-4982-8461-47f0705ff509","description":"Design invitations","entry":"20120629T191919Z","priority":"H","project":"party","status":"pending","tags":["mall"],"uuid":"e5a867b7-0116-457d-ba43-9ac2bee6ad2a"},
6
+ {"id":6,"depends":"e5a867b7-0116-457d-ba43-9ac2bee6ad2a","description":"Print invitations","entry":"20120629T191920Z","project":"party","status":"pending","tags":["mall"],"uuid":"9f6f3738-1c08-4f45-8eb4-1e90864c7588"}
7
+ ]
@@ -0,0 +1,7 @@
1
+ [{"id":1,"description":"Select a free weekend in November","entry":"20120629T191421Z","priority":"H","project":"party","status":"pending","uuid":"6fd0ba4a-ab67-49cd-ac69-64aa999aff8a","annotations":[{"entry":"20120629T191534Z","description":"the 13th looks good"}]},
2
+ {"id":2,"depends":["6fd0ba4a-ab67-49cd-ac69-64aa999aff8a"],"description":"Select and book a venue","entry":"20120629T191634Z","priority":"H","project":"party","status":"pending","uuid":"c992448a-f1ea-4982-8461-47f0705ff509"},
3
+ {"id":3,"depends":["9f6f3738-1c08-4f45-8eb4-1e90864c7588"],"description":"Mail invitations","entry":"20120629T191919Z","project":"party","status":"pending","uuid":"3b53178e-d5a4-45e0-afc2-1292db58a59a"},
4
+ {"id":4,"depends":["6fd0ba4a-ab67-49cd-ac69-64aa999aff8a","c992448a-f1ea-4982-8461-47f0705ff509"],"description":"Select a caterer","entry":"20120629T191919Z","project":"party","status":"pending","uuid":"c590941b-eb10-4569-bdc9-0e339f79305e"},
5
+ {"id":5,"depends":["c992448a-f1ea-4982-8461-47f0705ff509"],"description":"Design invitations","entry":"20120629T191919Z","priority":"H","project":"party","status":"pending","tags":["mall"],"uuid":"e5a867b7-0116-457d-ba43-9ac2bee6ad2a"},
6
+ {"id":6,"depends":["e5a867b7-0116-457d-ba43-9ac2bee6ad2a"],"description":"Print invitations","entry":"20120629T191920Z","project":"party","status":"pending","tags":["mall"],"uuid":"9f6f3738-1c08-4f45-8eb4-1e90864c7588"}
7
+ ]
@@ -0,0 +1,10 @@
1
+ [{"id":1,"description":"Select a free weekend in November","entry":"20120629T191421Z","priority":"H","project":"party","status":"pending","uuid":"6fd0ba4a-ab67-49cd-ac69-64aa999aff8a","annotations":[{"entry":"20120629T191534Z","description":"the 13th looks good"}]},
2
+ {"id":2,"depends":"6fd0ba4a-ab67-49cd-ac69-64aa999aff8a","description":"Select and book a venue","entry":"20120629T191634Z","priority":"H","project":"party","status":"pending","uuid":"c992448a-f1ea-4982-8461-47f0705ff509"},
3
+ {"id":3,"depends":"9f6f3738-1c08-4f45-8eb4-1e90864c7588","description":"Mail invitations","entry":"20120629T191919Z","project":"party","status":"pending","uuid":"3b53178e-d5a4-45e0-afc2-1292db58a59a"},
4
+ {"id":4,"depends":"6fd0ba4a-ab67-49cd-ac69-64aa999aff8a,c992448a-f1ea-4982-8461-47f0705ff509","description":"Select a caterer","entry":"20120629T191919Z","project":"party","status":"pending","uuid":"c590941b-eb10-4569-bdc9-0e339f79305e"},
5
+ {"id":5,"depends":"c992448a-f1ea-4982-8461-47f0705ff509","description":"Design invitations","entry":"20120629T191919Z","priority":"H","project":"party","status":"pending","tags":["mall"],"uuid":"e5a867b7-0116-457d-ba43-9ac2bee6ad2a"},
6
+ {"id":6,"depends":"e5a867b7-0116-457d-ba43-9ac2bee6ad2a","description":"Print invitations","entry":"20120629T191920Z","project":"party","status":"pending","tags":["mall"],"uuid":"9f6f3738-1c08-4f45-8eb4-1e90864c7588"},
7
+ {"id":7,"description":"Pay taxes","due":"20130429T220000Z","entry":"20120630T092759Z","mask":"-","recur":"yearly","status":"recurring","uuid":"b587f364-c68e-4438-b4d6-f2af6ad62518"},
8
+ {"id":8,"description":"Pay taxes","due":"20130429T220000Z","entry":"20120630T092800Z","imask":"0","parent":"b587f364-c68e-4438-b4d6-f2af6ad62518","recur":"yearly","status":"pending","tags":["finance"],"uuid":"99c9e1bb-ed75-4525-b05d-cf153a7ee1a1"},
9
+ {"id":9,"description":"Get cash from ATM","entry":"20120702T130056Z","status":"pending","tags":["finance","mall"],"uuid":"67aafe0b-ddd7-482b-9cfa-ac42c43e7559"}
10
+ ]
@@ -0,0 +1,28 @@
1
+ require 'twtest'
2
+ require 'taskwarrior'
3
+
4
+ module TaskWarrior
5
+ module Test
6
+ module Fixtures
7
+ def fixture(name)
8
+ File.join(File.dirname(__FILE__), 'fixtures', name)
9
+ end
10
+ end
11
+
12
+ module Validations
13
+ def assert_valid(task)
14
+ assert(task.valid?, error_message(task.errors))
15
+ end
16
+
17
+ def assert_invalid(task)
18
+ assert(task.invalid?, 'Expect validation to fail')
19
+ end
20
+
21
+ def error_message(errors)
22
+ errors.each_with_object([]){|e, result|
23
+ result << e.join(' ')
24
+ }.join("\n")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+
3
+ class TestPriorityMapper < Test::Unit::TestCase
4
+ def test_nil
5
+ assert_nil(TaskWarrior::PriorityMapper.map(nil))
6
+ end
7
+
8
+ def test_empty
9
+ assert_nil(TaskWarrior::PriorityMapper.map(''))
10
+ end
11
+
12
+ def test_low
13
+ assert_equal(:low, TaskWarrior::PriorityMapper.map('L'))
14
+ end
15
+
16
+ def test_medium
17
+ assert_equal(:medium, TaskWarrior::PriorityMapper.map('M'))
18
+ end
19
+
20
+ def test_high
21
+ assert_equal(:high, TaskWarrior::PriorityMapper.map('H'))
22
+ end
23
+
24
+ def test_unknown
25
+ assert_nil(TaskWarrior::PriorityMapper.map('crap'))
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ require 'test_helper'
2
+
3
+ class TestProject < Test::Unit::TestCase
4
+ include TaskWarrior::Test::Validations
5
+
6
+ def test_name
7
+ project = TaskWarrior::Project.new('foo')
8
+ assert_valid(project)
9
+ assert_empty(project.tasks)
10
+ end
11
+
12
+ def test_empty_tasks
13
+ project = TaskWarrior::Project.new('foo', [])
14
+ assert_valid(project)
15
+ assert_empty(project.tasks)
16
+ end
17
+
18
+ def test_with_tasks
19
+ project = TaskWarrior::Project.new('foo', [TaskWarrior::Task.new('foobar')])
20
+ assert_valid(project)
21
+ assert_equal(1, project.tasks.size)
22
+ end
23
+
24
+ def test_name_nil
25
+ project = TaskWarrior::Project.new(nil)
26
+ assert_invalid(project)
27
+ end
28
+
29
+ def test_name_empty
30
+ project = TaskWarrior::Project.new('')
31
+ assert_invalid(project)
32
+ end
33
+
34
+ def test_name_with_space
35
+ project = TaskWarrior::Project.new('foo bar')
36
+ assert_invalid(project)
37
+ end
38
+
39
+ def test_name_just_space
40
+ project = TaskWarrior::Project.new(' ')
41
+ assert_invalid(project)
42
+ end
43
+
44
+ def test_add_task
45
+ project = TaskWarrior::Project.new('foo')
46
+ assert_empty(project.tasks)
47
+ t1 = TaskWarrior::Task.new('foobar')
48
+ t2 = TaskWarrior::Task.new('foobaz')
49
+ project << t1
50
+ project << t2
51
+ assert_equal(2, project.tasks.size)
52
+ assert_equal(project, t1.project)
53
+ assert_equal(project, t2.project)
54
+ end
55
+ end
@@ -0,0 +1,64 @@
1
+ require 'test_helper'
2
+
3
+ class TestRepository < Test::Unit::TestCase
4
+ include TaskWarrior
5
+ include TaskWarrior::Test::Fixtures
6
+
7
+ def setup
8
+ @repo = Repository.new(File.read(fixture('party_taxes.json')))
9
+ end
10
+
11
+ def test_tags_of_task
12
+ atm = @repo['67aafe0b-ddd7-482b-9cfa-ac42c43e7559']
13
+ assert_not_nil(atm)
14
+ assert_equal(2, atm.tags.size)
15
+ end
16
+
17
+ def test_all
18
+ assert_equal(8, @repo.tasks.size)
19
+
20
+ one = @repo['6fd0ba4a-ab67-49cd-ac69-64aa999aff8a']
21
+ assert_equal('Select a free weekend in November', one.description)
22
+ assert_equal(:high, one.priority)
23
+ assert_equal('party', one.project.name)
24
+ assert_equal(:pending, one.status)
25
+
26
+ # assert_equal(1, one.annotations.size)
27
+ # assert_equal(DateTime.new('20120629T191534Z'), one.annotations.first.entry)
28
+ # assert_equal('the 13th looks good', one.annotations.first.entry.description)
29
+ end
30
+
31
+ def test_child
32
+ assert_equal(1, @repo['b587f364-c68e-4438-b4d6-f2af6ad62518'].children.size)
33
+ end
34
+
35
+ def test_parent
36
+ assert_equal(@repo['b587f364-c68e-4438-b4d6-f2af6ad62518'], @repo['99c9e1bb-ed75-4525-b05d-cf153a7ee1a1'].parent)
37
+ end
38
+
39
+ def test_projects
40
+ party = @repo.project('party')
41
+ assert_not_nil(party)
42
+ assert_equal(6, party.tasks.size)
43
+ end
44
+
45
+ def test_tags
46
+ tags = @repo.tags
47
+ assert_not_nil(tags)
48
+ assert_equal(2, tags.size)
49
+ assert(tags.include?(Tag.new('finance')))
50
+ assert(tags.include?(Tag.new('mall')))
51
+ end
52
+
53
+ def test_tasks_of_tag_finance
54
+ finance = @repo.tag('finance')
55
+ assert_not_nil(finance)
56
+ assert_equal(2, finance.tasks.size)
57
+ end
58
+
59
+ def test_tasks_of_tag_mall
60
+ mall = @repo.tag('mall')
61
+ assert_not_nil(mall)
62
+ assert_equal(3, mall.tasks.size)
63
+ end
64
+ end
@@ -0,0 +1,57 @@
1
+ require 'test_helper'
2
+
3
+ class TestTag < Test::Unit::TestCase
4
+ include TaskWarrior
5
+ include TaskWarrior::Test::Validations
6
+
7
+ def test_name
8
+ tag = Tag.new('foo')
9
+ assert_valid(tag)
10
+ assert_empty(tag.tasks)
11
+ end
12
+
13
+ def test_empty_tasks
14
+ tag = Tag.new('foo', [])
15
+ assert_valid(tag)
16
+ assert_empty(tag.tasks)
17
+ end
18
+
19
+ def test_with_tasks
20
+ tag = Tag.new('foo', [Task.new('foobar')])
21
+ assert_valid(tag)
22
+ assert_equal(1, tag.tasks.size)
23
+ end
24
+
25
+ def test_name_nil
26
+ tag = Tag.new(nil)
27
+ assert_invalid(tag)
28
+ end
29
+
30
+ def test_name_empty
31
+ tag = Tag.new('')
32
+ assert_invalid(tag)
33
+ end
34
+
35
+ def test_name_with_space
36
+ tag = Tag.new('foo bar')
37
+ assert_invalid(tag)
38
+ end
39
+
40
+ def test_name_just_space
41
+ tag = Tag.new(' ')
42
+ assert_invalid(tag)
43
+ end
44
+
45
+ def test_construction
46
+ foo = Tag.new('foo')
47
+ assert_equal(foo, Tag.new(foo))
48
+ assert_equal(Tag.new(foo), foo)
49
+ end
50
+
51
+ def test_value_object
52
+ f1 = Tag.new('foo')
53
+ f2 = Tag.new('foo')
54
+ assert_not_equal(f1.object_id, f2.object_id)
55
+ assert_equal(f1, f2)
56
+ end
57
+ end
@@ -0,0 +1,69 @@
1
+ require 'test_helper'
2
+
3
+ class TestTagHasAndBelongsToMany < Test::Unit::TestCase
4
+ include TaskWarrior::Test::Validations
5
+
6
+ def setup
7
+ @lookup_foo = TaskWarrior::Task.new('Lookup foo in Wikipedia')
8
+ @lookup_deadbeef = TaskWarrior::Task.new('Lookup deadbeef in Wikipedia')
9
+
10
+ @foo = TaskWarrior::Tag.new('foo')
11
+ @deadbeef = TaskWarrior::Tag.new('deadbeef')
12
+ @metasyntactic = TaskWarrior::Tag.new('metasyntactic')
13
+
14
+ # We need to do what the repo does - cross-reference manually.
15
+ @foo << @lookup_foo
16
+ @lookup_foo.tags << @foo
17
+ @lookup_foo.tags << @metasyntactic
18
+
19
+ @deadbeef << @lookup_deadbeef
20
+ @lookup_deadbeef.tags << @deadbeef
21
+ @lookup_deadbeef.tags << @metasyntactic
22
+
23
+ @metasyntactic << @lookup_foo
24
+ @metasyntactic << @lookup_deadbeef
25
+ end
26
+
27
+ def test_task_tagged
28
+ assert_equal(2, @lookup_foo.tags.size)
29
+ assert_equal(2, @lookup_deadbeef.tags.size)
30
+
31
+ assert_tagged_with(@lookup_foo, @foo)
32
+ assert_tagged_with(@lookup_foo, @metasyntactic)
33
+ assert_not_tagged_with(@lookup_foo, @deadbeef)
34
+
35
+ assert_not_tagged_with(@lookup_deadbeef, @foo)
36
+ assert_tagged_with(@lookup_deadbeef, @metasyntactic)
37
+ assert_tagged_with(@lookup_deadbeef, @deadbeef)
38
+ end
39
+
40
+ def test_tag_has_tasks
41
+ assert_equal(1, @foo.tasks.size)
42
+ assert_equal(1, @deadbeef.tasks.size)
43
+ assert_equal(2, @metasyntactic.tasks.size)
44
+
45
+ assert_contains_task(@deadbeef, @lookup_deadbeef)
46
+ assert_not_contains_task(@deadbeef, @lookup_foo)
47
+ assert_not_contains_task(@foo, @lookup_deadbeef)
48
+ assert_contains_task(@foo, @lookup_foo)
49
+
50
+ assert_contains_task(@metasyntactic, @lookup_deadbeef)
51
+ assert_contains_task(@metasyntactic, @lookup_foo)
52
+ end
53
+
54
+ def assert_tagged_with(task, tag)
55
+ assert(task.tags.include?(tag), "#{task} expected to be tagged with #{tag}, but it isn't.'")
56
+ end
57
+
58
+ def assert_not_tagged_with(task, tag)
59
+ assert(!task.tags.include?(tag), "#{task} expected not to be tagged with #{tag}, but it actually is.")
60
+ end
61
+
62
+ def assert_contains_task(tag, task)
63
+ assert(tag.tasks.include?(task), "#{tag} expected to contain #{task}, but it doesn't.")
64
+ end
65
+
66
+ def assert_not_contains_task(tag, task)
67
+ assert(!tag.tasks.include?(task), "#{tag} expected to not contain #{task}, but it actually does.")
68
+ end
69
+ end
@@ -0,0 +1,121 @@
1
+ require 'test_helper'
2
+ require 'date'
3
+ require 'active_support/core_ext'
4
+
5
+ # TODO Add tests for dependencies
6
+
7
+ class TestTask < Test::Unit::TestCase
8
+ include TaskWarrior::Test::Validations
9
+
10
+ def setup
11
+ @task = TaskWarrior::Task.new('foobar')
12
+ @task.id = 1
13
+ @task.uuid = '66465716-b08d-41ea-8567-91b988a2bcbf'
14
+ @task.entry = DateTime.now
15
+ @task.status = :pending
16
+ end
17
+
18
+ def test_task_id_nil
19
+ @task.id = nil
20
+ assert_invalid(@task)
21
+ end
22
+
23
+ def test_task_id_0
24
+ @task.id = 0
25
+ assert_invalid(@task)
26
+ end
27
+
28
+ def test_task_uuid_nil
29
+ @task.uuid = nil
30
+ assert_invalid(@task)
31
+ end
32
+
33
+ def test_task_uuid_empty
34
+ @task.uuid = ''
35
+ assert_invalid(@task)
36
+ end
37
+
38
+ def test_task_uuid_wrong_format
39
+ @task.uuid = 'abcdefg'
40
+ assert_invalid(@task)
41
+ end
42
+
43
+ def test_task_entry_nil
44
+ @task.entry = nil
45
+ assert_invalid(@task)
46
+ end
47
+
48
+ def test_task_entry_empty
49
+ @task.entry = ''
50
+ assert_invalid(@task)
51
+ end
52
+
53
+ def test_task_entry_wrong_format
54
+ @task.entry = "foobar"
55
+ assert_invalid(@task)
56
+ end
57
+
58
+ def test_task_entry_future
59
+ @task.entry = DateTime.now.advance(:days => 1)
60
+ assert_invalid(@task)
61
+ end
62
+
63
+ def test_task_status_nil
64
+ @task.status = nil
65
+ assert_invalid(@task)
66
+ end
67
+
68
+ def test_task_status_empty
69
+ @task.status = ''
70
+ assert_invalid(@task)
71
+ end
72
+
73
+ def test_task_status_unknown_string
74
+ @task.status = "foobar"
75
+ assert_invalid(@task)
76
+ end
77
+
78
+ def test_task_status_unknown_symbol
79
+ @task.status = :foobar
80
+ assert_invalid(@task)
81
+ end
82
+
83
+ def test_task_priority_nil
84
+ @task.priority = nil
85
+ assert_valid(@task)
86
+ end
87
+
88
+ def test_task_priority_empty
89
+ @task.priority = ''
90
+ assert_valid(@task)
91
+ end
92
+
93
+ def test_task_priority_unknown_string
94
+ @task.priority = "foobar"
95
+ assert_invalid(@task)
96
+ end
97
+
98
+ def test_task_priority_unknown_symbol
99
+ @task.priority = :foobar
100
+ assert_invalid(@task)
101
+ end
102
+
103
+ def test_task_priority_high
104
+ @task.priority = :high
105
+ assert_valid(@task)
106
+ end
107
+
108
+ def test_task_priority_medium
109
+ @task.priority = :medium
110
+ assert_valid(@task)
111
+ end
112
+
113
+ def test_task_priority_low
114
+ @task.priority = :low
115
+ assert_valid(@task)
116
+ end
117
+
118
+ def test_task_valid
119
+ assert_valid(@task)
120
+ end
121
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: taskwarrior
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nicholas E. Rabenau
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activemodel
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.2'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.2'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.2'
46
+ - !ruby/object:Gem::Dependency
47
+ name: twtest
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.0.5
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.5
62
+ - !ruby/object:Gem::Dependency
63
+ name: guard-test
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.5'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '0.5'
78
+ - !ruby/object:Gem::Dependency
79
+ name: guard-bundler
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '1.0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1.0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rake
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '0.9'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '0.9'
110
+ - !ruby/object:Gem::Dependency
111
+ name: pry
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: Wraps access to TaskWarrior, the command-line task manager, in a Ruby
127
+ gem.
128
+ email:
129
+ - nerab@gmx.net
130
+ executables: []
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - .gitignore
135
+ - .travis.yml
136
+ - Gemfile
137
+ - Guardfile
138
+ - LICENSE
139
+ - README.md
140
+ - Rakefile
141
+ - lib/taskwarrior.rb
142
+ - lib/taskwarrior/priority_mapper.rb
143
+ - lib/taskwarrior/project.rb
144
+ - lib/taskwarrior/repository.rb
145
+ - lib/taskwarrior/tag.rb
146
+ - lib/taskwarrior/task.rb
147
+ - lib/taskwarrior/task_mapper.rb
148
+ - lib/taskwarrior/version.rb
149
+ - taskwarrior.gemspec
150
+ - test/fixtures/no_deps.json
151
+ - test/fixtures/party.json
152
+ - test/fixtures/party2.json
153
+ - test/fixtures/party_taxes.json
154
+ - test/test_helper.rb
155
+ - test/unit/test_priority_mapper.rb
156
+ - test/unit/test_project.rb
157
+ - test/unit/test_repository.rb
158
+ - test/unit/test_tag.rb
159
+ - test/unit/test_tag_habtm.rb
160
+ - test/unit/test_task.rb
161
+ homepage:
162
+ licenses: []
163
+ post_install_message:
164
+ rdoc_options: []
165
+ require_paths:
166
+ - lib
167
+ required_ruby_version: !ruby/object:Gem::Requirement
168
+ none: false
169
+ requirements:
170
+ - - ! '>='
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ none: false
175
+ requirements:
176
+ - - ! '>='
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubyforge_project:
181
+ rubygems_version: 1.8.24
182
+ signing_key:
183
+ specification_version: 3
184
+ summary: Ruby wrapper for TaskWarrior
185
+ test_files:
186
+ - test/fixtures/no_deps.json
187
+ - test/fixtures/party.json
188
+ - test/fixtures/party2.json
189
+ - test/fixtures/party_taxes.json
190
+ - test/test_helper.rb
191
+ - test/unit/test_priority_mapper.rb
192
+ - test/unit/test_project.rb
193
+ - test/unit/test_repository.rb
194
+ - test/unit/test_tag.rb
195
+ - test/unit/test_tag_habtm.rb
196
+ - test/unit/test_task.rb