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.
@@ -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
@@ -27,7 +27,7 @@ module TaskWarrior
27
27
  end
28
28
 
29
29
  def tasks
30
- @tasks #.dup
30
+ @tasks
31
31
  end
32
32
 
33
33
  def to_s
@@ -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, :project, :dependencies, :parent, :children, :priority
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
- end
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
@@ -1,3 +1,3 @@
1
1
  module TaskWarrior
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
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/repository"
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
- # 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)
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
@@ -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
- # We need to do what the repo does - cross-reference manually.
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
@@ -15,107 +15,171 @@ class TestTask < Test::Unit::TestCase
15
15
  @task.status = :pending
16
16
  end
17
17
 
18
- def test_task_id_nil
18
+ def test_id_nil
19
19
  @task.id = nil
20
20
  assert_invalid(@task)
21
21
  end
22
22
 
23
- def test_task_id_0
23
+ def test_id_0
24
24
  @task.id = 0
25
25
  assert_invalid(@task)
26
26
  end
27
27
 
28
- def test_task_uuid_nil
28
+ def test_uuid_nil
29
29
  @task.uuid = nil
30
30
  assert_invalid(@task)
31
31
  end
32
32
 
33
- def test_task_uuid_empty
33
+ def test_uuid_empty
34
34
  @task.uuid = ''
35
35
  assert_invalid(@task)
36
36
  end
37
37
 
38
- def test_task_uuid_wrong_format
38
+ def test_uuid_wrong_format
39
39
  @task.uuid = 'abcdefg'
40
40
  assert_invalid(@task)
41
41
  end
42
42
 
43
- def test_task_entry_nil
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 test_task_entry_empty
63
+ def test_entry_empty
49
64
  @task.entry = ''
50
65
  assert_invalid(@task)
51
66
  end
52
67
 
53
- def test_task_entry_wrong_format
68
+ def test_entry_wrong_format
54
69
  @task.entry = "foobar"
55
70
  assert_invalid(@task)
56
71
  end
57
72
 
58
- def test_task_entry_future
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 test_task_status_nil
78
+ def test_status_nil
64
79
  @task.status = nil
65
80
  assert_invalid(@task)
66
81
  end
67
82
 
68
- def test_task_status_empty
83
+ def test_status_empty
69
84
  @task.status = ''
70
85
  assert_invalid(@task)
71
86
  end
72
87
 
73
- def test_task_status_unknown_string
88
+ def test_status_unknown_string
74
89
  @task.status = "foobar"
75
90
  assert_invalid(@task)
76
91
  end
77
92
 
78
- def test_task_status_unknown_symbol
93
+ def test_status_unknown_symbol
79
94
  @task.status = :foobar
80
95
  assert_invalid(@task)
81
96
  end
82
97
 
83
- def test_task_priority_nil
98
+ def test_priority_nil
84
99
  @task.priority = nil
85
100
  assert_valid(@task)
86
101
  end
87
102
 
88
- def test_task_priority_empty
103
+ def test_priority_empty
89
104
  @task.priority = ''
90
105
  assert_valid(@task)
91
106
  end
92
107
 
93
- def test_task_priority_unknown_string
108
+ def test_priority_unknown_string
94
109
  @task.priority = "foobar"
95
110
  assert_invalid(@task)
96
111
  end
97
112
 
98
- def test_task_priority_unknown_symbol
113
+ def test_priority_unknown_symbol
99
114
  @task.priority = :foobar
100
115
  assert_invalid(@task)
101
116
  end
102
117
 
103
- def test_task_priority_high
118
+ def test_priority_high
104
119
  @task.priority = :high
105
120
  assert_valid(@task)
106
121
  end
107
122
 
108
- def test_task_priority_medium
123
+ def test_priority_medium
109
124
  @task.priority = :medium
110
125
  assert_valid(@task)
111
126
  end
112
127
 
113
- def test_task_priority_low
128
+ def test_priority_low
114
129
  @task.priority = :low
115
130
  assert_valid(@task)
116
131
  end
117
132
 
118
- def test_task_valid
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.2
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-08 00:00:00.000000000 Z
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