taskwarrior 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # taskwarrior
2
2
 
3
- Ruby bindings for [TaskWarrior](http://taskwarrior.org)
3
+ Ruby bindings for [TaskWarrior](http://taskwarrior.org). Right now this gem provides read-only access to tasks, projects, tags etc.
4
4
 
5
5
  [![Build Status](https://secure.travis-ci.org/nerab/taskwarrior.png?branch=master)](http://travis-ci.org/nerab/taskwarrior)
6
6
 
@@ -20,7 +20,22 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ `TaskWarrior::Repository` is the main entry point. It expects an array of JSON objects, typically produced by `task export`. Technically, anything that can be consumed by `JSON.parse` is fine as long as it follows the format TaskWarrior uses.
24
+
25
+ # Assuming that a TaskWarrior export was written to a file
26
+ r = TaskWarrior::Repository.new(File.read('/tmp/task_export.json'))
27
+
28
+ Once instantiated, the repository provides access to tasks, projects and tags. Each task will also carry its attributes (description, uuid, etc) as well as its project and tags.
29
+
30
+ puts r.tasks.size
31
+ puts r.projects.size
32
+ puts r.tags.size
33
+
34
+ puts r.tasks.first.description
35
+ puts r.tasks.first.project.name
36
+ puts r.tasks.first.tags.join(' ')
37
+
38
+ Please see the [examples](/nerab/taskwarrior/tree/master/examples) for further use, or have a look at the [twdeps](/nerab/twdeps) tool which creates a graph that visualizes the dependencies between tasks.
24
39
 
25
40
  ## Contributing
26
41
 
@@ -1,4 +1,5 @@
1
1
  require 'active_model'
2
+ require 'date'
2
3
 
3
4
  module TaskWarrior
4
5
  class Annotation
@@ -11,12 +12,24 @@ module TaskWarrior
11
12
  include TaskWarrior::Validations
12
13
  validate :entry_cannot_be_in_the_future
13
14
 
14
- def initialize(description = nil)
15
+ def initialize(description = nil, entry = nil)
15
16
  @description = description
17
+ @entry = entry
16
18
  end
17
19
 
18
20
  def to_s
19
21
  "Annotation (#{entry}): #{description}"
20
22
  end
23
+
24
+ def hash
25
+ entry.hash + description.hash
26
+ end
27
+
28
+ # Annotations are value objects. They have no identity.
29
+ # If entry date and description are the same, the annotations are identical.
30
+ def ==(other)
31
+ return false unless other.is_a?(Annotation)
32
+ entry.eql?(other.entry) && description.eql?(other.description)
33
+ end
21
34
  end
22
35
  end
@@ -23,6 +23,17 @@ module TaskWarrior
23
23
  "Project #{name} (#{@tasks.size} tasks)"
24
24
  end
25
25
 
26
+ def hash
27
+ name.hash + tasks.hash
28
+ end
29
+
30
+ # Projects are value objects. They have no identity.
31
+ # If name and tasks are the same, the projects are identical.
32
+ def ==(other)
33
+ return false unless other.is_a?(Project)
34
+ name.eql?(other.name) && tasks.eql?(other.tasks)
35
+ end
36
+
26
37
  private
27
38
  def name_may_not_contain_spaces
28
39
  if !name.blank? and name[/\s/]
@@ -34,8 +34,15 @@ module TaskWarrior
34
34
  "Tag: #{name} (#{@tasks.size} tasks)"
35
35
  end
36
36
 
37
+ def hash
38
+ name.hash + tasks.hash
39
+ end
40
+
41
+ # Tags are value objects. They have no identity.
42
+ # If name and tasks are the same, the tags are identical.
37
43
  def ==(other)
38
- name == other.name
44
+ return false unless other.is_a?(Tag)
45
+ name.eql?(other.name) && tasks.eql?(other.tasks)
39
46
  end
40
47
 
41
48
  private
@@ -35,10 +35,37 @@ module TaskWarrior
35
35
  @children = []
36
36
  @tags = []
37
37
  @annotations = []
38
+
39
+ # http://www.ruby-forum.com/topic/164078#722181
40
+ @uuid = %x[uuidgen].strip
38
41
  end
39
42
 
40
43
  def to_s
41
44
  "Task '#{description}'".tap{|result| result << " <#{uuid}>" if uuid}
42
45
  end
46
+
47
+ # other may have the same uuid, but if its attributes differ, it will not be equal
48
+ def eql?(other)
49
+ # TODO Find a way to call attributes instead of listing them here again
50
+ # Maybe Virtus?
51
+ # http://solnic.eu/2012/01/10/ruby-datamapper-status.html
52
+ [:description, :id, :entry, :status, :uuid,
53
+ :project, :dependencies, :parent, :children,
54
+ :priority, :tags, :annotations, :start_at, :wait_at,
55
+ :end_at, :due_at].each do |attr|
56
+ return false unless send(attr).eql?(other.send(attr))
57
+ end
58
+ end
59
+
60
+ def hash
61
+ uuid.hash
62
+ end
63
+
64
+ # Tasks are entity objects. They have their identity defined by the uuid.
65
+ # If the uuids are the same, the tasks are identical.
66
+ def ==(other)
67
+ return false unless other.is_a?(Task)
68
+ uuid == other.uuid
69
+ end
43
70
  end
44
71
  end
@@ -1,3 +1,3 @@
1
1
  module TaskWarrior
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/test/test_helper.rb CHANGED
@@ -18,6 +18,24 @@ module TaskWarrior
18
18
  assert(task.invalid?, 'Expect validation to fail')
19
19
  end
20
20
 
21
+ def assert_equality(a1, a2)
22
+ assert_not_equal(a1.object_id, a2.object_id)
23
+ assert_equal(a1, a2)
24
+ assert(a1 == a2)
25
+ assert(a1.hash == a2.hash)
26
+ assert(a1.eql?(a2))
27
+ assert_equal(1, [a1, a2].uniq.size)
28
+ end
29
+
30
+ def assert_inequality(a1, a2)
31
+ assert_not_equal(a1.object_id, a2.object_id)
32
+ assert_not_equal(a1, a2)
33
+ assert(!(a1 == a2))
34
+ assert(!(a1.hash == a2.hash))
35
+ assert(!a1.eql?(a2))
36
+ assert_equal(2, [a1, a2].uniq.size)
37
+ end
38
+
21
39
  def error_message(errors)
22
40
  errors.each_with_object([]){|e, result|
23
41
  result << e.join(' ')
@@ -50,4 +50,37 @@ class TestAnnotation < Test::Unit::TestCase
50
50
  def test_valid
51
51
  assert_valid(@annotation)
52
52
  end
53
+
54
+ def test_equality
55
+ a1 = TaskWarrior::Annotation.new('foo')
56
+ a2 = TaskWarrior::Annotation.new('foo')
57
+
58
+ assert_equal(a1, a2)
59
+ end
60
+
61
+ def test_equality_different_description
62
+ a1 = TaskWarrior::Annotation.new('foo')
63
+ a2 = TaskWarrior::Annotation.new('bar')
64
+ assert_inequality(a1, a2)
65
+ end
66
+
67
+ def test_equality_different_entry
68
+ a1 = TaskWarrior::Annotation.new('foo')
69
+ a1.entry = DateTime.now
70
+
71
+ a2 = TaskWarrior::Annotation.new('foo')
72
+ a2.entry = DateTime.now.advance(:days => -1)
73
+
74
+ assert_inequality(a1, a2)
75
+ end
76
+
77
+ def test_equality_different_description_and_entry
78
+ a1 = TaskWarrior::Annotation.new('foo')
79
+ a1.entry = DateTime.now
80
+
81
+ a2 = TaskWarrior::Annotation.new('bar')
82
+ a2.entry = DateTime.now.advance(:days => -1)
83
+
84
+ assert_inequality(a1, a2)
85
+ end
53
86
  end
@@ -52,4 +52,31 @@ class TestProject < Test::Unit::TestCase
52
52
  assert_equal(project, t1.project)
53
53
  assert_equal(project, t2.project)
54
54
  end
55
+
56
+ def test_equality
57
+ a1 = TaskWarrior::Project.new('foo')
58
+ a2 = TaskWarrior::Project.new('foo')
59
+
60
+ assert_equal(a1, a2)
61
+ end
62
+
63
+ def test_equality_different_name
64
+ a1 = TaskWarrior::Project.new('foo')
65
+ a2 = TaskWarrior::Project.new('bar')
66
+ assert_inequality(a1, a2)
67
+ end
68
+
69
+ def test_equality_different_tasks
70
+ a1 = TaskWarrior::Project.new('foo')
71
+ a2 = TaskWarrior::Project.new('foo', [TaskWarrior::Task.new('foobar')])
72
+
73
+ assert_inequality(a1, a2)
74
+ end
75
+
76
+ def test_equality_different_name_and_tasks
77
+ a1 = TaskWarrior::Project.new('foo')
78
+ a2 = TaskWarrior::Project.new('bar', [TaskWarrior::Task.new('baz')])
79
+
80
+ assert_inequality(a1, a2)
81
+ end
55
82
  end
@@ -46,8 +46,8 @@ class TestRepository < Test::Unit::TestCase
46
46
  tags = @repo.tags
47
47
  assert_not_nil(tags)
48
48
  assert_equal(2, tags.size)
49
- assert(tags.include?(Tag.new('finance')))
50
- assert(tags.include?(Tag.new('mall')))
49
+ assert(tags.include?(@repo.tag('finance')))
50
+ assert(tags.include?(@repo.tag('mall')))
51
51
  end
52
52
 
53
53
  def test_tasks_of_tag_finance
@@ -61,4 +61,14 @@ class TestRepository < Test::Unit::TestCase
61
61
  assert_not_nil(mall)
62
62
  assert_equal(3, mall.tasks.size)
63
63
  end
64
+
65
+ def test_equality
66
+ t1 = @repo['b587f364-c68e-4438-b4d6-f2af6ad62518']
67
+ t2 = t1.dup
68
+ assert_not_equal(t1.object_id, t2.object_id)
69
+
70
+ t1.description = 'changed'
71
+ assert_equal(t1, t2)
72
+ assert(!(t1.eql?(t2)))
73
+ end
64
74
  end
@@ -48,10 +48,32 @@ class TestTag < Test::Unit::TestCase
48
48
  assert_equal(Tag.new(foo), foo)
49
49
  end
50
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)
51
+ def test_equality
52
+ a1 = Tag.new('foo')
53
+ a2 = Tag.new('foo')
54
+
55
+ assert_equal(a1, a2)
56
+ end
57
+
58
+ def test_equality_different_name
59
+ a1 = Tag.new('foo')
60
+ a2 = Tag.new('bar')
61
+ assert_inequality(a1, a2)
62
+ end
63
+
64
+ def test_equality_different_tasks
65
+ a1 = Tag.new('foo')
66
+ a2 = Tag.new('foo')
67
+ a2 << TaskWarrior::Task.new('baz')
68
+
69
+ assert_inequality(a1, a2)
70
+ end
71
+
72
+ def test_equality_different_name_and_tasks
73
+ a1 = Tag.new('foo')
74
+ a2 = Tag.new('bar')
75
+ a2 << TaskWarrior::Task.new('baz')
76
+
77
+ assert_inequality(a1, a2)
56
78
  end
57
79
  end
@@ -5,10 +5,11 @@ require 'active_support/core_ext'
5
5
  # TODO Add tests for dependencies
6
6
 
7
7
  class TestTask < Test::Unit::TestCase
8
+ include TaskWarrior
8
9
  include TaskWarrior::Test::Validations
9
10
 
10
11
  def setup
11
- @task = TaskWarrior::Task.new('foobar')
12
+ @task = Task.new('foobar')
12
13
  @task.id = 1
13
14
  @task.uuid = '66465716-b08d-41ea-8567-91b988a2bcbf'
14
15
  @task.entry = DateTime.now
@@ -182,4 +183,43 @@ class TestTask < Test::Unit::TestCase
182
183
  @task.send("#{sym}=", DateTime.now.advance(:days => -1))
183
184
  assert_valid(@task)
184
185
  end
186
+
187
+ def test_equality
188
+ a1 = Task.new('foo')
189
+ a2 = Task.new('foo')
190
+
191
+ # Tasks are entities, so even with the same attributes, two different objects
192
+ # must not be treated equal
193
+ assert_inequality(a1, a2)
194
+
195
+ # But comparing the same thing to itself is fine
196
+ assert_equal(a1, a1)
197
+ assert_equal(a2, a2)
198
+ end
199
+
200
+ def test_equality_different_description
201
+ a1 = Task.new('foo')
202
+ a2 = Task.new('bar')
203
+ assert_inequality(a1, a2)
204
+ end
205
+
206
+ def test_equality_different_entry
207
+ a1 = Task.new('foo')
208
+ a1.entry = DateTime.now
209
+
210
+ a2 = Task.new('foo')
211
+ a2.entry = DateTime.now.advance(:days => -1)
212
+
213
+ assert_inequality(a1, a2)
214
+ end
215
+
216
+ def test_equality_different_description_and_entry
217
+ a1 = Task.new('foo')
218
+ a1.entry = DateTime.now
219
+
220
+ a2 = Task.new('bar')
221
+ a2.entry = DateTime.now.advance(:days => -1)
222
+
223
+ assert_inequality(a1, a2)
224
+ end
185
225
  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.3
4
+ version: 0.0.4
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-09 00:00:00.000000000 Z
12
+ date: 2012-07-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel