taskwarrior 0.0.3 → 0.0.4

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/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