taskwarrior 0.0.2 → 0.0.3
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.
- data/examples/finished-early +26 -0
- data/lib/taskwarrior/annotation.rb +22 -0
- data/lib/taskwarrior/annotation_mapper.rb +14 -0
- data/lib/taskwarrior/tag.rb +1 -1
- data/lib/taskwarrior/task.rb +8 -16
- data/lib/taskwarrior/task_mapper.rb +5 -0
- data/lib/taskwarrior/validations.rb +20 -0
- data/lib/taskwarrior/version.rb +1 -1
- data/lib/taskwarrior.rb +6 -2
- data/test/unit/test_annotation.rb +53 -0
- data/test/unit/test_repository.rb +3 -3
- data/test/unit/test_tag_habtm.rb +1 -1
- data/test/unit/test_task.rb +85 -21
- metadata +8 -2
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# Prints those tasks the were completed before they were due.
|
5
|
+
#
|
6
|
+
# Call it like
|
7
|
+
#
|
8
|
+
# $ task export rc.json.array=on rc.verbose=nothing | examples/finished-early
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'taskwarrior'
|
12
|
+
|
13
|
+
r = TaskWarrior::Repository.new(ARGF.read)
|
14
|
+
|
15
|
+
selected = r.tasks.select do |t|
|
16
|
+
t.status == :completed && t.due_at > t.end_at if t.due_at && t.end_at
|
17
|
+
end
|
18
|
+
|
19
|
+
puts "#{selected.size} tasks completed before they were due:"
|
20
|
+
|
21
|
+
selected.group_by{|t| (t.due_at - t.end_at).truncate}.sort.each{|g, tasks|
|
22
|
+
puts "#{g} days early:"
|
23
|
+
tasks.each{|t|
|
24
|
+
puts " #{t.description}"
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module TaskWarrior
|
4
|
+
class Annotation
|
5
|
+
attr_accessor :entry, :description
|
6
|
+
|
7
|
+
include ActiveModel::Validations
|
8
|
+
validates :entry, :presence => true
|
9
|
+
validates :description, :presence => true
|
10
|
+
|
11
|
+
include TaskWarrior::Validations
|
12
|
+
validate :entry_cannot_be_in_the_future
|
13
|
+
|
14
|
+
def initialize(description = nil)
|
15
|
+
@description = description
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"Annotation (#{entry}): #{description}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module TaskWarrior
|
2
|
+
#
|
3
|
+
# A DataMapper that makes new annotations from a JSON representation
|
4
|
+
#
|
5
|
+
class AnnotationMapper
|
6
|
+
class << self
|
7
|
+
def map(json)
|
8
|
+
Annotation.new(json['description']).tap{|t|
|
9
|
+
t.entry = DateTime.parse(json['entry'])
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/taskwarrior/tag.rb
CHANGED
data/lib/taskwarrior/task.rb
CHANGED
@@ -2,9 +2,13 @@ require 'active_model'
|
|
2
2
|
|
3
3
|
module TaskWarrior
|
4
4
|
class Task
|
5
|
-
attr_accessor :description, :id, :entry, :status, :uuid,
|
5
|
+
attr_accessor :description, :id, :entry, :status, :uuid,
|
6
|
+
:project, :dependencies, :parent, :children,
|
7
|
+
:priority, :tags, :annotations,
|
8
|
+
:start_at, :wait_at, :end_at, :due_at
|
6
9
|
|
7
10
|
include ActiveModel::Validations
|
11
|
+
|
8
12
|
validates :description, :id, :entry, :status, :uuid, :presence => true
|
9
13
|
|
10
14
|
validates :id, :numericality => { :only_integer => true, :greater_than => 0}
|
@@ -21,32 +25,20 @@ module TaskWarrior
|
|
21
25
|
:message => "%{value} is not a valid priority"
|
22
26
|
}
|
23
27
|
|
28
|
+
include TaskWarrior::Validations
|
24
29
|
validate :entry_cannot_be_in_the_future
|
30
|
+
validates :start_at, :wait_at, :end_at, :due_at, :with => :must_be_date_or_nil
|
25
31
|
|
26
32
|
def initialize(description)
|
27
33
|
@description = description
|
28
34
|
@dependencies = []
|
29
35
|
@children = []
|
30
36
|
@tags = []
|
31
|
-
|
32
|
-
|
33
|
-
def tags
|
34
|
-
@tags
|
37
|
+
@annotations = []
|
35
38
|
end
|
36
39
|
|
37
40
|
def to_s
|
38
41
|
"Task '#{description}'".tap{|result| result << " <#{uuid}>" if uuid}
|
39
42
|
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
43
|
end
|
52
44
|
end
|
@@ -23,6 +23,11 @@ module TaskWarrior
|
|
23
23
|
t.parent = json['parent'] # Children will be cross-indexed in the repository
|
24
24
|
t.priority = PriorityMapper.map(json['priority'])
|
25
25
|
json['tags'].each{|tag| t.tags << tag} if json['tags']
|
26
|
+
json['annotations'].each{|annotation| t.annotations << AnnotationMapper.map(annotation)} if json['annotations']
|
27
|
+
|
28
|
+
%w{start wait end due}.each do |datish|
|
29
|
+
t.send("#{datish}_at=", DateTime.parse(json[datish])) if json[datish]
|
30
|
+
end
|
26
31
|
}
|
27
32
|
end
|
28
33
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module TaskWarrior
|
2
|
+
module Validations
|
3
|
+
def must_be_date_or_nil(sym)
|
4
|
+
datish = self.send(sym)
|
5
|
+
if !(datish.nil? or datish.is_a?(DateTime))
|
6
|
+
errors.add(sym, "must be nil or a valid DateTime object")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def entry_cannot_be_in_the_future
|
11
|
+
begin
|
12
|
+
if !entry.blank? and entry > DateTime.now
|
13
|
+
errors.add(:entry, "can't be in the future")
|
14
|
+
end
|
15
|
+
rescue
|
16
|
+
errors.add(:entry, "must be comparable to DateTime")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/taskwarrior/version.rb
CHANGED
data/lib/taskwarrior.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require "taskwarrior/version"
|
2
2
|
|
3
|
+
require "taskwarrior/validations"
|
4
|
+
|
5
|
+
require "taskwarrior/repository"
|
3
6
|
require "taskwarrior/task"
|
4
7
|
require "taskwarrior/project"
|
5
8
|
require "taskwarrior/tag"
|
6
|
-
require "taskwarrior/
|
9
|
+
require "taskwarrior/annotation"
|
10
|
+
|
7
11
|
require "taskwarrior/task_mapper"
|
8
12
|
require "taskwarrior/priority_mapper"
|
13
|
+
require "taskwarrior/annotation_mapper"
|
9
14
|
|
10
15
|
module TaskWarrior
|
11
|
-
# Your code goes here...
|
12
16
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'date'
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
|
5
|
+
class TestAnnotation < Test::Unit::TestCase
|
6
|
+
include TaskWarrior::Test::Validations
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@annotation = TaskWarrior::Annotation.new
|
10
|
+
|
11
|
+
@annotation.description = 'foo bar'
|
12
|
+
@annotation.entry = DateTime.now
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_description
|
16
|
+
assert_equal('foo bar', @annotation.description)
|
17
|
+
assert_valid(@annotation)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_description_nil
|
21
|
+
@annotation.description = nil
|
22
|
+
assert_invalid(@annotation)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_description_empty
|
26
|
+
@annotation.description = ''
|
27
|
+
assert_invalid(@annotation)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_entry_nil
|
31
|
+
@annotation.entry = nil
|
32
|
+
assert_invalid(@annotation)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_entry_empty
|
36
|
+
@annotation.entry = ''
|
37
|
+
assert_invalid(@annotation)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_entry_wrong_format
|
41
|
+
@annotation.entry = "foobar"
|
42
|
+
assert_invalid(@annotation)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_entry_future
|
46
|
+
@annotation.entry = DateTime.now.advance(:days => 1)
|
47
|
+
assert_invalid(@annotation)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_valid
|
51
|
+
assert_valid(@annotation)
|
52
|
+
end
|
53
|
+
end
|
@@ -23,9 +23,9 @@ class TestRepository < Test::Unit::TestCase
|
|
23
23
|
assert_equal('party', one.project.name)
|
24
24
|
assert_equal(:pending, one.status)
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
assert_equal(1, one.annotations.size)
|
27
|
+
assert_equal(DateTime.parse('20120629T191534Z'), one.annotations.first.entry)
|
28
|
+
assert_equal('the 13th looks good', one.annotations.first.description)
|
29
29
|
end
|
30
30
|
|
31
31
|
def test_child
|
data/test/unit/test_tag_habtm.rb
CHANGED
@@ -11,7 +11,7 @@ class TestTagHasAndBelongsToMany < Test::Unit::TestCase
|
|
11
11
|
@deadbeef = TaskWarrior::Tag.new('deadbeef')
|
12
12
|
@metasyntactic = TaskWarrior::Tag.new('metasyntactic')
|
13
13
|
|
14
|
-
#
|
14
|
+
# Cross-reference manually like the repo does
|
15
15
|
@foo << @lookup_foo
|
16
16
|
@lookup_foo.tags << @foo
|
17
17
|
@lookup_foo.tags << @metasyntactic
|
data/test/unit/test_task.rb
CHANGED
@@ -15,107 +15,171 @@ class TestTask < Test::Unit::TestCase
|
|
15
15
|
@task.status = :pending
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
18
|
+
def test_id_nil
|
19
19
|
@task.id = nil
|
20
20
|
assert_invalid(@task)
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
23
|
+
def test_id_0
|
24
24
|
@task.id = 0
|
25
25
|
assert_invalid(@task)
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
28
|
+
def test_uuid_nil
|
29
29
|
@task.uuid = nil
|
30
30
|
assert_invalid(@task)
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
33
|
+
def test_uuid_empty
|
34
34
|
@task.uuid = ''
|
35
35
|
assert_invalid(@task)
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
38
|
+
def test_uuid_wrong_format
|
39
39
|
@task.uuid = 'abcdefg'
|
40
40
|
assert_invalid(@task)
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
43
|
+
def test_description
|
44
|
+
assert_equal('foobar', @task.description)
|
45
|
+
assert_valid(@task)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_description_nil
|
49
|
+
@task.description = nil
|
50
|
+
assert_invalid(@task)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_description_empty
|
54
|
+
@task.description = ''
|
55
|
+
assert_invalid(@task)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_entry_nil
|
44
59
|
@task.entry = nil
|
45
60
|
assert_invalid(@task)
|
46
61
|
end
|
47
62
|
|
48
|
-
def
|
63
|
+
def test_entry_empty
|
49
64
|
@task.entry = ''
|
50
65
|
assert_invalid(@task)
|
51
66
|
end
|
52
67
|
|
53
|
-
def
|
68
|
+
def test_entry_wrong_format
|
54
69
|
@task.entry = "foobar"
|
55
70
|
assert_invalid(@task)
|
56
71
|
end
|
57
72
|
|
58
|
-
def
|
73
|
+
def test_entry_future
|
59
74
|
@task.entry = DateTime.now.advance(:days => 1)
|
60
75
|
assert_invalid(@task)
|
61
76
|
end
|
62
77
|
|
63
|
-
def
|
78
|
+
def test_status_nil
|
64
79
|
@task.status = nil
|
65
80
|
assert_invalid(@task)
|
66
81
|
end
|
67
82
|
|
68
|
-
def
|
83
|
+
def test_status_empty
|
69
84
|
@task.status = ''
|
70
85
|
assert_invalid(@task)
|
71
86
|
end
|
72
87
|
|
73
|
-
def
|
88
|
+
def test_status_unknown_string
|
74
89
|
@task.status = "foobar"
|
75
90
|
assert_invalid(@task)
|
76
91
|
end
|
77
92
|
|
78
|
-
def
|
93
|
+
def test_status_unknown_symbol
|
79
94
|
@task.status = :foobar
|
80
95
|
assert_invalid(@task)
|
81
96
|
end
|
82
97
|
|
83
|
-
def
|
98
|
+
def test_priority_nil
|
84
99
|
@task.priority = nil
|
85
100
|
assert_valid(@task)
|
86
101
|
end
|
87
102
|
|
88
|
-
def
|
103
|
+
def test_priority_empty
|
89
104
|
@task.priority = ''
|
90
105
|
assert_valid(@task)
|
91
106
|
end
|
92
107
|
|
93
|
-
def
|
108
|
+
def test_priority_unknown_string
|
94
109
|
@task.priority = "foobar"
|
95
110
|
assert_invalid(@task)
|
96
111
|
end
|
97
112
|
|
98
|
-
def
|
113
|
+
def test_priority_unknown_symbol
|
99
114
|
@task.priority = :foobar
|
100
115
|
assert_invalid(@task)
|
101
116
|
end
|
102
117
|
|
103
|
-
def
|
118
|
+
def test_priority_high
|
104
119
|
@task.priority = :high
|
105
120
|
assert_valid(@task)
|
106
121
|
end
|
107
122
|
|
108
|
-
def
|
123
|
+
def test_priority_medium
|
109
124
|
@task.priority = :medium
|
110
125
|
assert_valid(@task)
|
111
126
|
end
|
112
127
|
|
113
|
-
def
|
128
|
+
def test_priority_low
|
114
129
|
@task.priority = :low
|
115
130
|
assert_valid(@task)
|
116
131
|
end
|
117
132
|
|
118
|
-
def
|
133
|
+
def test_valid
|
134
|
+
assert_valid(@task)
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_start_at
|
138
|
+
assert_datish(:start_at)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_wait_at
|
142
|
+
assert_datish(:wait_at)
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_end_at
|
146
|
+
assert_datish(:end_at)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_due_at
|
150
|
+
assert_datish(:due_at)
|
151
|
+
end
|
152
|
+
|
153
|
+
def assert_datish(sym)
|
154
|
+
assert_datish_nil(sym)
|
155
|
+
assert_datish_empty(sym)
|
156
|
+
assert_datish_wrong_format(sym)
|
157
|
+
assert_datish_future(sym)
|
158
|
+
assert_datish_past(sym)
|
159
|
+
end
|
160
|
+
|
161
|
+
def assert_datish_nil(sym)
|
162
|
+
@task.send("#{sym}=", nil)
|
163
|
+
assert_valid(@task)
|
164
|
+
end
|
165
|
+
|
166
|
+
def assert_datish_empty(sym)
|
167
|
+
@task.send("#{sym}=", '')
|
168
|
+
assert_invalid(@task)
|
169
|
+
end
|
170
|
+
|
171
|
+
def assert_datish_wrong_format(sym)
|
172
|
+
@task.send("#{sym}=", "foobar")
|
173
|
+
assert_invalid(@task)
|
174
|
+
end
|
175
|
+
|
176
|
+
def assert_datish_future(sym)
|
177
|
+
@task.send("#{sym}=", DateTime.now.advance(:days => 1))
|
178
|
+
assert_valid(@task)
|
179
|
+
end
|
180
|
+
|
181
|
+
def assert_datish_past(sym)
|
182
|
+
@task.send("#{sym}=", DateTime.now.advance(:days => -1))
|
119
183
|
assert_valid(@task)
|
120
184
|
end
|
121
185
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: taskwarrior
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -138,13 +138,17 @@ files:
|
|
138
138
|
- LICENSE
|
139
139
|
- README.md
|
140
140
|
- Rakefile
|
141
|
+
- examples/finished-early
|
141
142
|
- lib/taskwarrior.rb
|
143
|
+
- lib/taskwarrior/annotation.rb
|
144
|
+
- lib/taskwarrior/annotation_mapper.rb
|
142
145
|
- lib/taskwarrior/priority_mapper.rb
|
143
146
|
- lib/taskwarrior/project.rb
|
144
147
|
- lib/taskwarrior/repository.rb
|
145
148
|
- lib/taskwarrior/tag.rb
|
146
149
|
- lib/taskwarrior/task.rb
|
147
150
|
- lib/taskwarrior/task_mapper.rb
|
151
|
+
- lib/taskwarrior/validations.rb
|
148
152
|
- lib/taskwarrior/version.rb
|
149
153
|
- taskwarrior.gemspec
|
150
154
|
- test/fixtures/no_deps.json
|
@@ -152,6 +156,7 @@ files:
|
|
152
156
|
- test/fixtures/party2.json
|
153
157
|
- test/fixtures/party_taxes.json
|
154
158
|
- test/test_helper.rb
|
159
|
+
- test/unit/test_annotation.rb
|
155
160
|
- test/unit/test_priority_mapper.rb
|
156
161
|
- test/unit/test_project.rb
|
157
162
|
- test/unit/test_repository.rb
|
@@ -188,6 +193,7 @@ test_files:
|
|
188
193
|
- test/fixtures/party2.json
|
189
194
|
- test/fixtures/party_taxes.json
|
190
195
|
- test/test_helper.rb
|
196
|
+
- test/unit/test_annotation.rb
|
191
197
|
- test/unit/test_priority_mapper.rb
|
192
198
|
- test/unit/test_project.rb
|
193
199
|
- test/unit/test_repository.rb
|