twdeps 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 65c4a0831441f978b94e806b7492a4cfb34ce0f7
4
+ data.tar.gz: c2ea1deb638801eac176a4c70663aef572c994fc
5
+ SHA512:
6
+ metadata.gz: c034226377e9a2707b0225729dbe3ca383e321ced8e4cfdc7d63a786ddf712783b20fa0a3b371985a9c4c7dff29fe398ae60708893c5189b570d24304d982bad
7
+ data.tar.gz: 5bd6d1f659ef348eeb503f69cdc1278432036116474a5bc349c39b0b529576cb92b0fb142c0ad17db8ba619c84efca0dee42015d8717a8a478410fe0d8bce30d
data/.travis.yml CHANGED
@@ -6,7 +6,6 @@ rvm:
6
6
  before_script:
7
7
  - mkdir ~/.task
8
8
  - echo data.location=~/.task > ~/.taskrc
9
- - task count
10
9
 
11
10
  before_install:
12
11
  - echo | sudo add-apt-repository ppa:ultrafredde/ppa
data/README.md CHANGED
@@ -14,7 +14,7 @@ Given a set of interdependent tasks described in the TaskWarrior [tutorial](http
14
14
 
15
15
  Result:
16
16
 
17
- ![party](/nerab/twdeps/raw/master/examples/party.png)
17
+ ![party](https://raw.github.com/nerab/twdeps/master/examples/party.png)
18
18
 
19
19
  ## Installation
20
20
 
@@ -26,16 +26,16 @@ Result:
26
26
  # See [Limitations](Limitations) below for why we need the extra task parms
27
27
  task export rc.json.array=on rc.verbose=nothing | twdeps > deps.png
28
28
 
29
- # Same but spefify output format
30
- task export | twdeps --format svg > deps.svg
29
+ # Same but specify output format
30
+ task export rc.json.array=on rc.verbose=nothing | twdeps --format svg > deps.svg
31
31
 
32
32
  # Create a graph from a previously exported file
33
- task export > tasks.json
33
+ task export rc.json.array=on rc.verbose=nothing > tasks.json
34
34
  cat tasks.json | twdeps > deps.png
35
35
 
36
36
  # Display graph in browser without creating an intermediate file
37
37
  # Requires bcat to be installed
38
- task export | twdeps --format svg | bcat
38
+ task export rc.json.array=on rc.verbose=nothing | twdeps --format svg | bcat
39
39
 
40
40
  ## Dependencies
41
41
 
@@ -45,7 +45,7 @@ The graph is generated with [ruby-graphviz](https://github.com/glejeune/Ruby-Gra
45
45
 
46
46
  ## Limitations
47
47
 
48
- Due to [two](http://taskwarrior.org/issues/1017) [bugs](http://taskwarrior.org/issues/1013) in JSON export, TaskWarrior 2.0 needs the command line options `rc.json.array=on` and `rc.verbose=nothing`.
48
+ Due to [two](http://taskwarrior.org/issues/1017) [bugs](http://taskwarrior.org/issues/1013) in JSON export, TaskWarrior versions before 2.1 need the additional command line options `rc.json.array=on` and `rc.verbose=nothing`.
49
49
 
50
50
  ## Contributing
51
51
 
data/bin/twdeps CHANGED
@@ -26,6 +26,7 @@ where [options] are:
26
26
 
27
27
  EOS
28
28
  opt :format, "Specify output format", :default => 'svg'
29
+ opt :title, "Specify title", :default => 'Task Dependencies'
29
30
  opt :trace, "Enable trace output", :default => false
30
31
  end
31
32
 
@@ -36,7 +37,7 @@ Trollop::die :format, "must be one of #{Graph.formats.join(', ')}" unless Graph.
36
37
 
37
38
  begin
38
39
  repo = Repository.new(ARGF.read)
39
- master = Graph.new(File.basename($0)) # TODO Move this to a CommandlinePresenter
40
+ master = Graph.new(Presenter.new(opts[:title]))
40
41
 
41
42
  # Add all projects (will add their tasks and dependencies recursively)
42
43
  repo.projects.each do |project|
data/examples/party.png CHANGED
Binary file
data/lib/twdeps/graph.rb CHANGED
@@ -1,15 +1,5 @@
1
1
  module TaskWarrior
2
2
  module Dependencies
3
- class NullPresenter
4
- def attributes
5
- {:label => 'Unknown', :fontcolor => 'red'}
6
- end
7
-
8
- def id
9
- 'null'
10
- end
11
- end
12
-
13
3
  # Builds a dependency graph
14
4
  #
15
5
  # +thing+ is added as node with all of its dependencies. A presenter is used to present the task as node label.
@@ -29,9 +19,14 @@ module TaskWarrior
29
19
 
30
20
  #
31
21
  # Build a new Graph for +thing+
32
- # # TODO Accept a presenter that would default to GlobalPresenter with {:rankdir => 'BT'}
33
- def initialize(name = :G, attributes = [])
34
- @graph = GraphViz::new(name, attributes)
22
+ #
23
+ def initialize(presenter_or_id)
24
+ if presenter_or_id.respond_to?(:attributes)
25
+ @graph = GraphViz::new(presenter_or_id.id, presenter_or_id.attributes)
26
+ else
27
+ @graph = GraphViz::new(presenter_or_id)
28
+ end
29
+
35
30
  @dependencies = []
36
31
  @edges = []
37
32
  end
@@ -52,7 +47,7 @@ module TaskWarrior
52
47
  else
53
48
  # it's a project
54
49
  project = task_or_project
55
- cluster = Graph.new(presenter(project).id, presenter(project).attributes)
50
+ cluster = Graph.new(presenter(project))
56
51
 
57
52
  project.tasks.each do |task|
58
53
  cluster << task
@@ -74,7 +69,7 @@ module TaskWarrior
74
69
  def create_edges(nodeA, nodes)
75
70
  nodes.each do |node|
76
71
  nodeB = find_or_create_node(node)
77
- create_edge(nodeA, nodeB)
72
+ create_edge(nodeB, nodeA)
78
73
  end
79
74
  end
80
75
 
@@ -90,7 +85,9 @@ module TaskWarrior
90
85
  edge = [nodeA, nodeB]
91
86
  unless @edges.include?(edge) # GraphViz lacks get_edge, so we need to track existing edges ourselfes
92
87
  @edges << edge
93
- @graph.add_edges(nodeA, nodeB)
88
+
89
+ # We present the edges in the sense of "nodeB depends on nodeA"
90
+ @graph.add_edges(nodeA, nodeB, :dir => 'back', :tooltip => "#{nodeB['label']} depends on #{nodeA['label']}")
94
91
  end
95
92
  end
96
93
 
@@ -0,0 +1,11 @@
1
+ module TaskWarrior
2
+ module Dependencies
3
+ class NullPresenter < Presenter
4
+ def initialize
5
+ super('null')
6
+ self.attributes = {:label => 'Unknown', :fontcolor => 'red'}
7
+ end
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,25 @@
1
+ module TaskWarrior
2
+ module Dependencies
3
+ #
4
+ # Presents a thing to the graph
5
+ #
6
+ class Presenter
7
+ def initialize(id)
8
+ @id = id
9
+ @attributes = {:label => id, :labelloc => 'top'}
10
+ end
11
+
12
+ def attributes
13
+ @attributes
14
+ end
15
+
16
+ def id
17
+ @id
18
+ end
19
+
20
+ protected
21
+ attr_writer :id, :attributes
22
+ end
23
+ end
24
+ end
25
+
@@ -3,17 +3,10 @@ module TaskWarrior
3
3
  #
4
4
  # Presents a project's attributes suitable for a GraphViz cluster
5
5
  #
6
- class ProjectPresenter
6
+ class ProjectPresenter < Presenter
7
7
  def initialize(project)
8
- @project = project
9
- end
10
-
11
- def attributes
12
- {:label => @project.name}
13
- end
14
-
15
- def id
16
- "cluster_#{@project.name}"
8
+ self.id = "cluster_#{project.name}"
9
+ self.attributes = {:label => project.name}
17
10
  end
18
11
  end
19
12
  end
@@ -3,25 +3,17 @@ module TaskWarrior
3
3
  #
4
4
  # Presents a task's attributes suitable for a GraphViz node
5
5
  #
6
- class TaskPresenter
6
+ class TaskPresenter < Presenter
7
7
  def initialize(task)
8
- @task = task
9
- end
10
-
11
- def attributes
12
- attrs = {:label => @task.description}
13
- attrs.merge!({:tooltip => "Status: #{@task.status}"})
14
-
15
- # TODO Once we see the urgency in the JSON export, we can color-code the nodes
16
- # http://taskwarrior.org/issues/973
17
- # attrs.merge!({:fillcolor => 'red', :style => 'filled'})
8
+ self.id = task.uuid
9
+ self.attributes = {
10
+ :label => task.description,
11
+ :tooltip => "Status: #{task.status}"
12
+ }
18
13
 
19
- attrs.merge!({:fontcolor => 'gray', :color => 'gray'}) if :completed == @task.status
20
- attrs
21
- end
22
-
23
- def id
24
- @task.uuid
14
+ if :completed == task.status
15
+ self.attributes.merge!({:fontcolor => 'gray', :color => 'gray'})
16
+ end
25
17
  end
26
18
  end
27
19
  end
@@ -1,5 +1,5 @@
1
1
  module TaskWarrior
2
2
  module Dependencies
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
5
5
  end
data/lib/twdeps.rb CHANGED
@@ -1,17 +1,13 @@
1
- require "twdeps/version"
2
-
3
- require "twdeps/task"
4
- require "twdeps/project"
5
- require "twdeps/tag"
6
-
7
- require "twdeps/task_mapper"
8
- require "twdeps/priority_mapper"
9
- require "twdeps/task_repository"
1
+ require "taskwarrior"
10
2
 
3
+ require "twdeps/version"
11
4
  require "twdeps/graph"
5
+ require "twdeps/presenter"
12
6
  require "twdeps/task_presenter"
13
7
  require "twdeps/project_presenter"
8
+ require "twdeps/null_presenter"
14
9
 
10
+ # dependencies
15
11
  require "graphviz"
16
12
  require "json"
17
13
 
@@ -8,7 +8,7 @@ module TaskWarrior
8
8
  def setup
9
9
  repo = TaskWarrior::Repository.new(File.read(fixture('party_taxes.json')))
10
10
 
11
- plain = TaskWarrior::Dependencies::Graph.new
11
+ plain = TaskWarrior::Dependencies::Graph.new(self.class.name)
12
12
 
13
13
  repo.tasks.each do |task|
14
14
  plain << task
@@ -31,12 +31,12 @@ module TaskWarrior
31
31
 
32
32
  def test_edges
33
33
  assert_equal(6, @graph.edges.size)
34
- assert_not_nil(@graph.edge('c992448a-f1ea-4982-8461-47f0705ff509', '6fd0ba4a-ab67-49cd-ac69-64aa999aff8a'))
35
- assert_not_nil(@graph.edge('3b53178e-d5a4-45e0-afc2-1292db58a59a', '9f6f3738-1c08-4f45-8eb4-1e90864c7588'))
36
- assert_not_nil(@graph.edge('9f6f3738-1c08-4f45-8eb4-1e90864c7588', 'e5a867b7-0116-457d-ba43-9ac2bee6ad2a'))
37
- assert_not_nil(@graph.edge('e5a867b7-0116-457d-ba43-9ac2bee6ad2a', 'c992448a-f1ea-4982-8461-47f0705ff509'))
38
- assert_not_nil(@graph.edge('c590941b-eb10-4569-bdc9-0e339f79305e', '6fd0ba4a-ab67-49cd-ac69-64aa999aff8a'))
39
- assert_not_nil(@graph.edge('c590941b-eb10-4569-bdc9-0e339f79305e', 'c992448a-f1ea-4982-8461-47f0705ff509'))
34
+ assert_not_nil(@graph.edge('6fd0ba4a-ab67-49cd-ac69-64aa999aff8a', 'c992448a-f1ea-4982-8461-47f0705ff509'))
35
+ assert_not_nil(@graph.edge('9f6f3738-1c08-4f45-8eb4-1e90864c7588', '3b53178e-d5a4-45e0-afc2-1292db58a59a'))
36
+ assert_not_nil(@graph.edge('e5a867b7-0116-457d-ba43-9ac2bee6ad2a', '9f6f3738-1c08-4f45-8eb4-1e90864c7588'))
37
+ assert_not_nil(@graph.edge('c992448a-f1ea-4982-8461-47f0705ff509', 'e5a867b7-0116-457d-ba43-9ac2bee6ad2a'))
38
+ assert_not_nil(@graph.edge('6fd0ba4a-ab67-49cd-ac69-64aa999aff8a', 'c590941b-eb10-4569-bdc9-0e339f79305e'))
39
+ assert_not_nil(@graph.edge('c992448a-f1ea-4982-8461-47f0705ff509', 'c590941b-eb10-4569-bdc9-0e339f79305e'))
40
40
  end
41
41
 
42
42
  private
@@ -0,0 +1,41 @@
1
+ require 'test_helper'
2
+
3
+ module TaskWarrior
4
+ module Test
5
+ class TestPresenters < ::Test::Unit::TestCase
6
+ include TaskWarrior::Dependencies
7
+ include TaskWarrior::Test::Fixtures
8
+
9
+ def setup
10
+ @repo = TaskWarrior::Repository.new(File.read(fixture('party_taxes.json')))
11
+ end
12
+
13
+ def test_string_presentation
14
+ foo = 'foo'
15
+ p = Presenter.new(foo)
16
+ assert_equal(foo, p.id)
17
+ assert_not_nil(p.attributes)
18
+ assert_equal({:label=>"foo", :labelloc=>"top"}, p.attributes)
19
+ end
20
+
21
+ def test_null_presentation
22
+ p = NullPresenter.new
23
+ assert_equal('null', p.id)
24
+ assert_equal({:label => 'Unknown', :fontcolor => 'red'}, p.attributes)
25
+ end
26
+
27
+ def test_project_presentation
28
+ p = ProjectPresenter.new(@repo.project('party'))
29
+ assert_equal('cluster_party', p.id)
30
+ assert_equal({:label => 'party'}, p.attributes)
31
+ end
32
+
33
+ def test_task_presentation
34
+ uuid = '67aafe0b-ddd7-482b-9cfa-ac42c43e7559'
35
+ p = TaskPresenter.new(@repo[uuid])
36
+ assert_equal(uuid, p.id)
37
+ assert_equal({:label => 'Get cash from ATM', :tooltip => 'Status: pending'}, p.attributes)
38
+ end
39
+ end
40
+ end
41
+ end
data/twdeps.gemspec CHANGED
@@ -16,13 +16,10 @@ Gem::Specification.new do |gem|
16
16
  gem.version = TaskWarrior::Dependencies::VERSION
17
17
 
18
18
  gem.add_dependency 'ruby-graphviz', '~> 1.0.7'
19
- gem.add_dependency 'activemodel', '~> 3.2'
20
19
  gem.add_dependency 'trollop', '~> 1'
21
- gem.add_development_dependency 'activesupport', '~> 3.2'
22
- gem.add_development_dependency 'twtest', '~> 0.0.4'
20
+ gem.add_dependency 'taskwarrior', '~> 0.0.6'
21
+ gem.add_development_dependency 'twtest', '~> 0.0.6'
23
22
  gem.add_development_dependency 'guard-test', '~> 0.5'
24
23
  gem.add_development_dependency 'guard-bundler', '~> 1.0'
25
24
  gem.add_development_dependency 'rake', '~> 0.9'
26
-
27
- gem.add_development_dependency 'pry'
28
25
  end
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twdeps
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
5
- prerelease:
4
+ version: 0.0.3
6
5
  platform: ruby
7
6
  authors:
8
7
  - Nicholas E. Rabenau
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-07-06 00:00:00.000000000 Z
11
+ date: 2013-07-21 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: ruby-graphviz
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,31 +20,13 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
29
26
  version: 1.0.7
30
- - !ruby/object:Gem::Dependency
31
- name: activemodel
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ~>
36
- - !ruby/object:Gem::Version
37
- version: '3.2'
38
- type: :runtime
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
27
  - !ruby/object:Gem::Dependency
47
28
  name: trollop
48
29
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
30
  requirements:
51
31
  - - ~>
52
32
  - !ruby/object:Gem::Version
@@ -54,47 +34,41 @@ dependencies:
54
34
  type: :runtime
55
35
  prerelease: false
56
36
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
37
  requirements:
59
38
  - - ~>
60
39
  - !ruby/object:Gem::Version
61
40
  version: '1'
62
41
  - !ruby/object:Gem::Dependency
63
- name: activesupport
42
+ name: taskwarrior
64
43
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
44
  requirements:
67
45
  - - ~>
68
46
  - !ruby/object:Gem::Version
69
- version: '3.2'
70
- type: :development
47
+ version: 0.0.6
48
+ type: :runtime
71
49
  prerelease: false
72
50
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
51
  requirements:
75
52
  - - ~>
76
53
  - !ruby/object:Gem::Version
77
- version: '3.2'
54
+ version: 0.0.6
78
55
  - !ruby/object:Gem::Dependency
79
56
  name: twtest
80
57
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
58
  requirements:
83
59
  - - ~>
84
60
  - !ruby/object:Gem::Version
85
- version: 0.0.4
61
+ version: 0.0.6
86
62
  type: :development
87
63
  prerelease: false
88
64
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
65
  requirements:
91
66
  - - ~>
92
67
  - !ruby/object:Gem::Version
93
- version: 0.0.4
68
+ version: 0.0.6
94
69
  - !ruby/object:Gem::Dependency
95
70
  name: guard-test
96
71
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
72
  requirements:
99
73
  - - ~>
100
74
  - !ruby/object:Gem::Version
@@ -102,7 +76,6 @@ dependencies:
102
76
  type: :development
103
77
  prerelease: false
104
78
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
79
  requirements:
107
80
  - - ~>
108
81
  - !ruby/object:Gem::Version
@@ -110,7 +83,6 @@ dependencies:
110
83
  - !ruby/object:Gem::Dependency
111
84
  name: guard-bundler
112
85
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
86
  requirements:
115
87
  - - ~>
116
88
  - !ruby/object:Gem::Version
@@ -118,7 +90,6 @@ dependencies:
118
90
  type: :development
119
91
  prerelease: false
120
92
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
93
  requirements:
123
94
  - - ~>
124
95
  - !ruby/object:Gem::Version
@@ -126,7 +97,6 @@ dependencies:
126
97
  - !ruby/object:Gem::Dependency
127
98
  name: rake
128
99
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
100
  requirements:
131
101
  - - ~>
132
102
  - !ruby/object:Gem::Version
@@ -134,27 +104,10 @@ dependencies:
134
104
  type: :development
135
105
  prerelease: false
136
106
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
107
  requirements:
139
108
  - - ~>
140
109
  - !ruby/object:Gem::Version
141
110
  version: '0.9'
142
- - !ruby/object:Gem::Dependency
143
- name: pry
144
- requirement: !ruby/object:Gem::Requirement
145
- none: false
146
- requirements:
147
- - - ! '>='
148
- - !ruby/object:Gem::Version
149
- version: '0'
150
- type: :development
151
- prerelease: false
152
- version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
- requirements:
155
- - - ! '>='
156
- - !ruby/object:Gem::Version
157
- version: '0'
158
111
  description: Takes a TaskWarrior export and emits a graph that visualizes the dependencies
159
112
  between tasks.
160
113
  email:
@@ -175,14 +128,10 @@ files:
175
128
  - examples/party.png
176
129
  - lib/twdeps.rb
177
130
  - lib/twdeps/graph.rb
178
- - lib/twdeps/priority_mapper.rb
179
- - lib/twdeps/project.rb
131
+ - lib/twdeps/null_presenter.rb
132
+ - lib/twdeps/presenter.rb
180
133
  - lib/twdeps/project_presenter.rb
181
- - lib/twdeps/tag.rb
182
- - lib/twdeps/task.rb
183
- - lib/twdeps/task_mapper.rb
184
134
  - lib/twdeps/task_presenter.rb
185
- - lib/twdeps/task_repository.rb
186
135
  - lib/twdeps/version.rb
187
136
  - test/fixtures/no_deps.json
188
137
  - test/fixtures/party.json
@@ -192,36 +141,30 @@ files:
192
141
  - test/integration/test_dependencies.rb
193
142
  - test/test_helper.rb
194
143
  - test/unit/test_graph.rb
195
- - test/unit/test_priority_mapper.rb
196
- - test/unit/test_project.rb
197
- - test/unit/test_repository.rb
198
- - test/unit/test_tag.rb
199
- - test/unit/test_tag_habtm.rb
200
- - test/unit/test_task.rb
144
+ - test/unit/test_presenters.rb
201
145
  - twdeps.gemspec
202
146
  homepage: ''
203
147
  licenses: []
148
+ metadata: {}
204
149
  post_install_message:
205
150
  rdoc_options: []
206
151
  require_paths:
207
152
  - lib
208
153
  required_ruby_version: !ruby/object:Gem::Requirement
209
- none: false
210
154
  requirements:
211
- - - ! '>='
155
+ - - '>='
212
156
  - !ruby/object:Gem::Version
213
157
  version: '0'
214
158
  required_rubygems_version: !ruby/object:Gem::Requirement
215
- none: false
216
159
  requirements:
217
- - - ! '>='
160
+ - - '>='
218
161
  - !ruby/object:Gem::Version
219
162
  version: '0'
220
163
  requirements: []
221
164
  rubyforge_project:
222
- rubygems_version: 1.8.24
165
+ rubygems_version: 2.0.3
223
166
  signing_key:
224
- specification_version: 3
167
+ specification_version: 4
225
168
  summary: Visualizes dependencies between TaskWarrior tasks.
226
169
  test_files:
227
170
  - test/fixtures/no_deps.json
@@ -232,9 +175,4 @@ test_files:
232
175
  - test/integration/test_dependencies.rb
233
176
  - test/test_helper.rb
234
177
  - test/unit/test_graph.rb
235
- - test/unit/test_priority_mapper.rb
236
- - test/unit/test_project.rb
237
- - test/unit/test_repository.rb
238
- - test/unit/test_tag.rb
239
- - test/unit/test_tag_habtm.rb
240
- - test/unit/test_task.rb
178
+ - test/unit/test_presenters.rb
@@ -1,9 +0,0 @@
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
@@ -1,33 +0,0 @@
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
data/lib/twdeps/tag.rb DELETED
@@ -1,48 +0,0 @@
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
data/lib/twdeps/task.rb DELETED
@@ -1,52 +0,0 @@
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
@@ -1,30 +0,0 @@
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
@@ -1,77 +0,0 @@
1
- require 'json'
2
-
3
- module TaskWarrior
4
- class SimpleTag
5
- attr_reader :name, :tasks
6
-
7
- def initialize(name)
8
- @name = name
9
- @tasks = []
10
- end
11
-
12
- def <<(task)
13
- @tasks << task unless @tasks.include?(task)
14
- end
15
- end
16
-
17
- class Repository
18
- def initialize(input)
19
- @tasks = {}
20
- @projects = Hash.new{|hash, key| hash[key] = Project.new(key)}
21
- @tags = Hash.new{|hash, key| hash[key] = Tag.new(key)}
22
-
23
- JSON.parse(input).each{|json|
24
- task = TaskWarrior::TaskMapper.map(json)
25
- @tasks[task.uuid] = task
26
- @projects[task.project].tasks << task if task.project
27
-
28
- # Create a new Tag object in @tags that is the value for each tag name
29
- task.tags.each{|tag_name| @tags[tag_name] << task}
30
- }
31
-
32
- # Replace the uuid of each dependency with the real task
33
- @tasks.each_value{|task| task.dependencies.map!{|uuid| @tasks[uuid]}}
34
-
35
- # Replace the project property of each task with a proper Project object carrying a name and all of the project's tasks
36
- @tasks.each_value{|task| task.project = @projects[task.project] if task.project}
37
-
38
- # Add child tasks to their parent, but keep them in the global index
39
- @tasks.each_value do |task|
40
- if task.parent
41
- parent = @tasks[task.parent]
42
-
43
- if parent # we know the parent
44
- parent.children << task
45
- task.parent = parent
46
- end
47
- end
48
- end
49
- end
50
-
51
- def tasks
52
- # Do not expose child tasks directly
53
- @tasks.values.reject{|t| t.parent}
54
- end
55
-
56
- # direct lookup by uuid
57
- def [](uuid)
58
- @tasks[uuid]
59
- end
60
-
61
- def projects
62
- @projects.values
63
- end
64
-
65
- def project(name)
66
- @projects[name] if @projects.has_key?(name)
67
- end
68
-
69
- def tags
70
- @tags.values
71
- end
72
-
73
- def tag(name)
74
- @tags[name] if @tags.has_key?(name)
75
- end
76
- end
77
- end
@@ -1,27 +0,0 @@
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
@@ -1,55 +0,0 @@
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
@@ -1,64 +0,0 @@
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
@@ -1,57 +0,0 @@
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
@@ -1,69 +0,0 @@
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
@@ -1,121 +0,0 @@
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