taskish 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .*.swp
1
2
  *.gem
2
3
  .bundle
3
4
  Gemfile.lock
data/HISTORY CHANGED
@@ -1,3 +1,10 @@
1
+ 2011-06-23 v0.2.0
2
+ - Added 'help' command to executable
3
+ - Added 'done' command to executable
4
+ - Added 'version' command to executable
5
+ - Improved task parsing
6
+ - Added support for '@done' tag
7
+
1
8
  2011-06-23 v0.0.1
2
9
  - Initial prototype release.
3
10
 
data/bin/taskish CHANGED
@@ -1,28 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'taskish'
4
+ require 'taskish/app'
4
5
 
5
- if __FILE__ == $0
6
- # TODO Extract to class?
7
- cmd, file = ARGV.shift, ARGV.shift
8
- unless cmd && file
9
- warn "USAGE: #{ File.basename(__FILE__) } { today | week } <file>"
10
- exit
11
- end
12
- Taskish.new do |taskish|
13
- case cmd
14
- when 'today'
15
- taskish.readlines(file)
16
- puts "TODAY\n~~~~~"
17
- taskish.due(:today).each { |task| puts task }
18
- when 'week'
19
- taskish.readlines(file)
20
- puts "WEEK\n~~~~"
21
- taskish.due(:week).each { |task| puts task }
22
- else
23
- warn "unknown command: #{cmd}"
24
- exit 1
25
- end
26
- end
6
+ begin
7
+ Taskish::App.run(ARGV) || exit(1)
8
+ rescue => e
9
+ warn "#{e.class.name}: #{e.message}"
10
+ exit(1)
27
11
  end
28
12
 
data/lib/taskish.rb CHANGED
@@ -3,6 +3,8 @@ require 'taskish/version'
3
3
 
4
4
  # = Taskish - Pending
5
5
  #
6
+ # A text-based to-do list manager inspired by <TaskPaper|URL:http://www.hogbaysoftware.com/products/taskpaper>
7
+ #
6
8
  # == USAGE
7
9
  #
8
10
  # Taskish.new do |taskish|
@@ -26,16 +28,29 @@ require 'taskish/version'
26
28
  #
27
29
  # Blair Christensen, <blair.christensen@gmail.com>
28
30
  #
31
+ # == SEE ALSO
32
+ #
33
+ # <Taskish::App>
34
+ # http://www.hogbaysoftware.com/products/taskpaper
35
+ #
29
36
  class Taskish
30
37
  def initialize
31
38
  @data = {}
32
39
  yield self if block_given?
33
40
  end
34
41
 
42
+ def done
43
+ task_list = []
44
+ @data.each_pair do |project, tasks|
45
+ tasks.each { |task| task_list << task if task.done? }
46
+ end
47
+ task_list
48
+ end
49
+
35
50
  def due( due = :today )
36
51
  task_list = []
37
52
  @data.each_pair do |project, tasks|
38
- tasks.each { |task| task_list << task if task.due?(due) }
53
+ tasks.each { |task| task_list << task if ( task.due?(due) and !task.done? ) }
39
54
  end
40
55
  task_list.sort_by { |t| t.due }
41
56
  end
@@ -0,0 +1,86 @@
1
+
2
+ class Taskish # :nodoc:
3
+
4
+ # = Taskish::App - Taskish application.
5
+ #
6
+ # == USAGE
7
+ #
8
+ # API:
9
+ #
10
+ # Taskish::App.run(ARGV)
11
+ #
12
+ # Command Line:
13
+ #
14
+ # % taskish [args]
15
+ #
16
+ # == SEE ALSO
17
+ #
18
+ # <Taskish>
19
+ #
20
+ class App
21
+
22
+ attr_reader :command, :file
23
+
24
+ def initialize
25
+ @command = nil
26
+ @file = nil
27
+ yield self if block_given?
28
+ end
29
+
30
+ def abort(message = nil)
31
+ warn "ERROR: #{message}" if message
32
+ warn self.usage
33
+ false
34
+ end
35
+
36
+ def args(args)
37
+ raise(ArgumentError, 'invalid argument(s)') if ( args.nil? || !args.kind_of?(Array) )
38
+ @command = args.shift
39
+ @file = args.shift
40
+ self
41
+ end
42
+
43
+ def self.run(args)
44
+ Taskish::App.new do |app|
45
+ app.args(args)
46
+ return app.abort('no command specified') unless app.command
47
+
48
+ case app.command
49
+ when 'help'
50
+ puts app.usage
51
+ return true
52
+ when 'version'
53
+ puts "Taskish v#{ Taskish::VERSION }"
54
+ return true
55
+ else
56
+ return app.abort('no file specified') unless app.file
57
+ Taskish.new do |taskish|
58
+ case app.command
59
+ when 'done'
60
+ taskish.readlines(app.file)
61
+ puts "DONE\n~~~~~"
62
+ taskish.done.each { |task| puts task }
63
+ when 'today'
64
+ taskish.readlines(app.file)
65
+ puts "TODAY\n~~~~~"
66
+ taskish.due(:today).each { |task| puts task }
67
+ when 'week'
68
+ taskish.readlines(app.file)
69
+ puts "WEEK\n~~~~"
70
+ taskish.due(:week).each { |task| puts task }
71
+ else
72
+ return app.abort("unknown command: #{app.command}")
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ def usage
80
+ "USAGE: taskish { done | today | week } <file>"
81
+ end
82
+
83
+ end # class Taskish::App
84
+
85
+ end # class Taskish
86
+
data/lib/taskish/task.rb CHANGED
@@ -10,19 +10,20 @@ class Taskish # :nodoc:
10
10
  # ...
11
11
  # end
12
12
  #
13
+ # == SEE ALSO
14
+ #
15
+ # <Taskish>
16
+ #
13
17
  class Task
14
18
  def initialize(project, task)
15
- raise(ArgumentError, 'invalid project') if ( project.nil? || project.empty? )
16
- raise(ArgumentError, 'invalid task') if ( task.nil? || task.empty? )
17
- @data = { :project => project, :task => task }
18
- if task =~ /^(.+?)\s+\@due(.*?)\s*$/
19
- @data[:task] = $1
20
- @data[:due] = $2.empty? ? Date.today : Date.parse( $2.gsub(/^\(/, '').gsub(/\)$/, '') )
21
- else
22
- end
19
+ @data = Task.parse(project, task)
23
20
  yield self if block_given?
24
21
  end
25
-
22
+
23
+ def done?
24
+ @data.key?(:done) && @data[:done]
25
+ end
26
+
26
27
  def due
27
28
  @data[:due] || nil
28
29
  end
@@ -46,6 +47,32 @@ class Taskish # :nodoc:
46
47
  @data.key? key
47
48
  end
48
49
 
50
+ def self.parse(project, task)
51
+ raise(ArgumentError, 'invalid project') if ( project.nil? || project.empty? )
52
+ raise(ArgumentError, 'invalid task') if ( task.nil? || task.empty? )
53
+ data = { :project => project }
54
+
55
+ # TODO Extract to something that sucks less.
56
+ task.gsub!(/\s*$/, '')
57
+ # @done
58
+ if task =~ /^(.+?)\s+\@done\s?(.*)$/
59
+ task = "#{ $1 }#{ $3 }"
60
+ data[:done] = true
61
+ end
62
+ # @due
63
+ if task =~ /^(.+?)\s+\@due(\S+)(.*)$/
64
+ task = "#{ $1 }#{ $3 }"
65
+ due = $2.gsub(/^\(/, '').gsub(/\)$/, '')
66
+ data[:due] = Date.parse(due)
67
+ elsif task =~ /^(.+?)\s+\@due\s?(.*)$/
68
+ task = "#{ $1 }#{ $3 }"
69
+ data[:due] = Date.today
70
+ end
71
+
72
+ data[:task] = task
73
+ data
74
+ end
75
+
49
76
  def task
50
77
  @data[:task]
51
78
  end
@@ -1,3 +1,3 @@
1
1
  class Taskish # :nodoc:
2
- VERSION = '0.0.1'
2
+ VERSION = '0.2.0'
3
3
  end
data/taskish.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
16
16
  s.files = `git ls-files`.split("\n")
17
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ["lib"]
19
+ s.require_paths = ['lib']
20
20
 
21
21
  s.add_development_dependency( %q<rdoc-readme>, [ '>=0.1.1' ] )
22
22
  s.add_development_dependency( %q<shoulda>, [ '>=2.11.3' ] )
data/test/app_test.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'test_helper'
2
+ require 'taskish/app'
3
+
4
+ class AppTest < Test::Unit::TestCase
5
+
6
+ context '#initialize()' do
7
+ should 'return object if no block given' do
8
+ assert_instance_of Taskish::App, Taskish::App.new
9
+ end
10
+ should 'work as a block' do
11
+ Taskish::App.new do |app|
12
+ assert_instance_of Taskish::App, app
13
+ end
14
+ end
15
+ end
16
+
17
+ context '#args()' do
18
+ setup do
19
+ @app = Taskish::App.new
20
+ end
21
+
22
+ context 'with non-array argument' do
23
+ should 'raise ArgumentError' do
24
+ assert_raise(ArgumentError, 'invalid argument(s)') { @app.args(nil) }
25
+ end
26
+ end
27
+
28
+ context 'with arguments' do
29
+ should 'have nil args before parsing args' do
30
+ assert_nil @app.command
31
+ assert_nil @app.file
32
+ end
33
+ should 'have set args after parsing args' do
34
+ @app.args( [ 'command', 'file' ] )
35
+ assert_equal 'command', @app.command
36
+ assert_equal 'file', @app.file
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ context '#usage()' do
43
+ should 'return expected usage string' do
44
+ assert_equal "USAGE: taskish { done | today | week } <file>", Taskish::App.new.usage
45
+ end
46
+ end
47
+
48
+ end # class AppTest
49
+
data/test/task_test.rb CHANGED
@@ -1,27 +1,239 @@
1
1
  require 'test_helper'
2
+ require 'date'
2
3
 
3
4
  class TaskTest < Test::Unit::TestCase
4
5
 
5
6
  context '#initialize()' do
7
+ should 'return object if no block given' do
8
+ assert_instance_of Taskish::Task, Taskish::Task.new("p", "t")
9
+ end
10
+ should 'work as a block' do
11
+ Taskish::Task.new("p", "t") do |task|
12
+ assert_instance_of Taskish::Task, task
13
+ end
14
+ end
15
+ end
16
+
17
+ context '#done?' do
18
+ should 'return false if @done not set' do
19
+ assert_equal false, Taskish::Task.new('proj', 'foo').done?
20
+ end
21
+ should 'return true if @done set' do
22
+ assert_equal true, Taskish::Task.new('proj', 'foo @done').done?
23
+ end
24
+ end
25
+
26
+ context '#due() and #due?()' do
27
+
28
+ context ' with no due date' do
29
+ setup do
30
+ @task = Taskish::Task.new('proj', 'do something')
31
+ end
32
+ should 'be nil' do
33
+ assert_nil @task.due
34
+ end
35
+ should 'not be due today' do
36
+ assert_equal false, @task.due?(:today)
37
+ end
38
+ should 'not be due this week' do
39
+ assert_equal false, @task.due?(:week)
40
+ end
41
+ end
42
+
43
+ context ' with implicit due date of today' do
44
+ setup do
45
+ @d = Date.today
46
+ @task = Taskish::Task.new('proj', 'do something @due')
47
+ end
48
+ should 'not be nil' do
49
+ assert_not_nil @task.due
50
+ end
51
+ should 'be expected date' do
52
+ assert_equal @d, @task.due
53
+ end
54
+ should 'be due today' do
55
+ assert_equal true, @task.due?(:today)
56
+ end
57
+ should 'be due this week' do
58
+ assert_equal true, @task.due?(:week)
59
+ end
60
+ end
61
+
62
+ context ' with implicit due date of today and additional tag' do
63
+ setup do
64
+ @d = Date.today
65
+ @task = Taskish::Task.new('proj', 'do something @due @weekly')
66
+ end
67
+ should 'not be nil' do
68
+ assert_not_nil @task.due
69
+ end
70
+ should 'be expected date' do
71
+ assert_equal @d, @task.due
72
+ end
73
+ should 'be due today' do
74
+ assert_equal true, @task.due?(:today)
75
+ end
76
+ should 'be due this week' do
77
+ assert_equal true, @task.due?(:week)
78
+ end
79
+ end
80
+
81
+ context ' with explicit due date of today' do
82
+ setup do
83
+ @d = Date.today
84
+ @task = Taskish::Task.new('proj', "do something @due(#{ @d.strftime('%Y-%m-%d') })")
85
+ end
86
+ should 'not be nil' do
87
+ assert_not_nil @task.due
88
+ end
89
+ should 'be expected date' do
90
+ assert_equal @d, @task.due
91
+ end
92
+ should 'be due today' do
93
+ assert_equal true, @task.due?(:today)
94
+ end
95
+ should 'be due this week' do
96
+ assert_equal true, @task.due?(:week)
97
+ end
98
+ end
99
+
100
+ context ' with explicit due date of today and additional tag' do
101
+ setup do
102
+ @d = Date.today
103
+ @task = Taskish::Task.new('proj', "do something @due(#{ @d.strftime('%Y-%m-%d') }) @weekly")
104
+ end
105
+ should 'not be nil' do
106
+ assert_not_nil @task.due
107
+ end
108
+ should 'be expected date' do
109
+ assert_equal @d, @task.due
110
+ end
111
+ should 'be due today' do
112
+ assert_equal true, @task.due?(:today)
113
+ end
114
+ should 'be due this week' do
115
+ assert_equal true, @task.due?(:week)
116
+ end
117
+ end
118
+
119
+ context ' with explicit due date of tomorrow' do
120
+ setup do
121
+ @d = Date.today + 1
122
+ @task = Taskish::Task.new('proj', "do something @due(#{ @d.strftime('%Y-%m-%d') })")
123
+ end
124
+ should 'not be nil' do
125
+ assert_not_nil @task.due
126
+ end
127
+ should 'be expected date' do
128
+ assert_equal @d, @task.due
129
+ end
130
+ should 'not be due today' do
131
+ assert_equal false, @task.due?(:today)
132
+ end
133
+ should 'be due this week' do
134
+ assert_equal true, @task.due?(:week)
135
+ end
136
+ end
137
+ end
138
+
139
+ context 'parse()' do
140
+ setup do
141
+ @project = 'some project'
142
+ @task = 'some task'
143
+ @today = Date.today
144
+ end
145
+
6
146
  should 'raise ArgumentError if nil project' do
7
- assert_raise(ArgumentError, 'invalid project') { Taskish::Task.new(nil, "t") }
147
+ assert_raise(ArgumentError, 'invalid project') { Taskish::Task.new(nil, @task) }
8
148
  end
9
149
  should 'raise ArgumentError if empty project' do
10
- assert_raise(ArgumentError, 'invalid project') { Taskish::Task.new('', "t") }
150
+ assert_raise(ArgumentError, 'invalid project') { Taskish::Task.new('', @task) }
11
151
  end
12
152
  should 'raise ArgumentError if nil task' do
13
- assert_raise(ArgumentError, 'invalid task') { Taskish::Task.new("p", nil) }
153
+ assert_raise(ArgumentError, 'invalid task') { Taskish::Task.new(@project, nil) }
14
154
  end
15
155
  should 'raise ArgumentError if empty task' do
16
- assert_raise(ArgumentError, 'invalid task') { Taskish::Task.new("p", '') }
156
+ assert_raise(ArgumentError, 'invalid task') { Taskish::Task.new(@project, '') }
17
157
  end
18
- should 'return object if no block given' do
19
- assert_instance_of Taskish::Task, Taskish::Task.new("p", "t")
158
+
159
+ should 'handle :project and :task' do
160
+ task = @task
161
+ hash = Taskish::Task.parse(@project, task)
162
+ assert_equal @project, hash[:project]
163
+ assert_equal @task, hash[:task]
164
+ assert_equal false, hash.key?(:due)
165
+ assert_equal false, hash.key?(:done)
166
+ assert_equal false, hash.key?(:weekly)
20
167
  end
21
- should 'work as a block' do
22
- Taskish::Task.new("p", "t") do |task|
23
- assert_instance_of Taskish::Task, task
24
- end
168
+
169
+ should 'handle :project and :task with trailing whitespace' do
170
+ task = "#{ @task } "
171
+ hash = Taskish::Task.parse(@project, task)
172
+ assert_equal @project, hash[:project]
173
+ assert_equal @task, hash[:task]
174
+ assert_equal false, hash.key?(:due)
175
+ assert_equal false, hash.key?(:done)
176
+ assert_equal false, hash.key?(:weekly)
177
+ end
178
+
179
+ should 'handle :project, :task and implicit :due' do
180
+ task = "#{ @task } @due"
181
+ hash = Taskish::Task.parse(@project, task)
182
+ assert_equal @project, hash[:project]
183
+ assert_equal @task, hash[:task]
184
+ assert_equal @today.to_s, hash[:due].to_s
185
+ assert_equal false, hash.key?(:done)
186
+ assert_equal false, hash.key?(:weekly)
187
+ end
188
+
189
+ should 'handle :project, :task and :done' do
190
+ task = "#{ @task } @done"
191
+ hash = Taskish::Task.parse(@project, task)
192
+ assert_equal @project, hash[:project]
193
+ assert_equal @task, hash[:task]
194
+ assert_equal false, hash.key?(:due)
195
+ assert_equal true, hash.key?(:done)
196
+ assert_equal false, hash.key?(:weekly)
197
+ end
198
+
199
+ should 'handle :project, :task, implicit :due and :done' do
200
+ task = "#{ @task } @due @done"
201
+ hash = Taskish::Task.parse(@project, task)
202
+ assert_equal @project, hash[:project]
203
+ assert_equal @task, hash[:task]
204
+ assert_equal @today.to_s, hash[:due].to_s
205
+ assert_equal true, hash.key?(:done)
206
+ assert_equal false, hash.key?(:weekly)
207
+ end
208
+
209
+ should 'handle :project, :task and explicit :due' do
210
+ task = "#{ @task } @due(#{ @today.to_s })"
211
+ hash = Taskish::Task.parse(@project, task)
212
+ assert_equal @project, hash[:project]
213
+ assert_equal @task, hash[:task]
214
+ assert_equal @today.to_s, hash[:due].to_s
215
+ assert_equal false, hash.key?(:done)
216
+ assert_equal false, hash.key?(:weekly)
217
+ end
218
+
219
+ should 'handle :project, :task, explicit :due and :done' do
220
+ task = "#{ @task } @due(#{ @today.to_s }) @done"
221
+ hash = Taskish::Task.parse(@project, task)
222
+ assert_equal @project, hash[:project]
223
+ assert_equal @task, hash[:task]
224
+ assert_equal @today.to_s, hash[:due].to_s
225
+ assert_equal true, hash.key?(:done)
226
+ assert_equal false, hash.key?(:weekly)
227
+ end
228
+
229
+ should 'handle :project, :task and random other tag (by ignoring random other tag)' do
230
+ task = "#{ @task } @weekly"
231
+ hash = Taskish::Task.parse(@project, task)
232
+ assert_equal @project, hash[:project]
233
+ assert_equal task, hash[:task]
234
+ assert_equal false, hash.key?(:due)
235
+ assert_equal false, hash.key?(:done)
236
+ assert_equal false, hash.key?(:weekly)
25
237
  end
26
238
  end
27
239
 
data/test/taskish.txt CHANGED
@@ -2,3 +2,10 @@ Project 1:
2
2
  - Task 1-A @due
3
3
  - Task 1-B
4
4
 
5
+ Project 2:
6
+ - Task 2-A @due @done
7
+ - Task 2-B @done
8
+
9
+ Project 3:
10
+ - Task 3-A @weekly
11
+
data/test/taskish_test.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class TaskishTest < Test::Unit::TestCase
4
-
5
4
  context '#initialize()' do
6
5
  should 'return object if no block given' do
7
6
  assert_instance_of Taskish, Taskish.new
@@ -13,21 +12,42 @@ class TaskishTest < Test::Unit::TestCase
13
12
  end
14
13
  end
15
14
 
15
+ context '#done' do
16
+ setup do
17
+ @taskish = Taskish.new
18
+ @fn = File.join( File.dirname(__FILE__), 'taskish.txt' )
19
+ @taskish.readlines(@fn)
20
+ end
21
+ should 'return correct # of entries' do
22
+ assert_equal 2, @taskish.done.size
23
+ end
24
+ end
25
+
26
+ context '#due' do
27
+ setup do
28
+ @taskish = Taskish.new
29
+ @fn = File.join( File.dirname(__FILE__), 'taskish.txt' )
30
+ @taskish.readlines(@fn)
31
+ end
32
+ should 'return correct # of entries for :today' do
33
+ assert_equal 1, @taskish.due(:today).size
34
+ end
35
+ end
36
+
16
37
  context '#readlines()' do
17
38
  setup do
18
- @taskish = Taskish.new
19
- @bad_file = File.join( File.dirname(__FILE__), 'no_such_file.txt' )
20
- @good_file = File.join( File.dirname(__FILE__), 'taskish.txt' )
39
+ @taskish = Taskish.new
40
+ @fn = File.join( File.dirname(__FILE__), 'taskish.txt' )
21
41
  end
22
42
 
23
43
  should 'raise ArgumentError if file does not exist' do
24
- assert_raise(ArgumentError, 'no such file') { @taskish.readlines(nil) }
25
- assert_raise(ArgumentError, 'no such file') { @taskish.readlines('') }
26
- assert_raise(ArgumentError, 'no such file') { @taskish.readlines(@bad_file) }
44
+ assert_raise(ArgumentError, 'no such file') { @taskish.readlines(nil) }
45
+ assert_raise(ArgumentError, 'no such file') { @taskish.readlines('') }
46
+ assert_raise(ArgumentError, 'no such file') { @taskish.readlines('no such file') }
27
47
  end
28
48
 
29
49
  should 'not return self after reading file' do
30
- assert_equal @taskish, @taskish.readlines(@good_file)
50
+ assert_equal @taskish, @taskish.readlines(@fn)
31
51
  end
32
52
  end
33
53
 
data/test/version_test.rb CHANGED
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  class VersionTest < Test::Unit::TestCase
4
4
 
5
5
  should 'have expected version' do
6
- assert_equal '0.0.1', Taskish::VERSION
6
+ assert_equal '0.2.0', Taskish::VERSION
7
7
  end
8
8
 
9
9
  end # class VersionTest
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
+ - 2
7
8
  - 0
8
- - 1
9
- version: 0.0.1
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - blair christensen.
@@ -64,9 +64,11 @@ files:
64
64
  - Rakefile
65
65
  - bin/taskish
66
66
  - lib/taskish.rb
67
+ - lib/taskish/app.rb
67
68
  - lib/taskish/task.rb
68
69
  - lib/taskish/version.rb
69
70
  - taskish.gemspec
71
+ - test/app_test.rb
70
72
  - test/task_test.rb
71
73
  - test/taskish.txt
72
74
  - test/taskish_test.rb
@@ -105,6 +107,7 @@ signing_key:
105
107
  specification_version: 3
106
108
  summary: Pending
107
109
  test_files:
110
+ - test/app_test.rb
108
111
  - test/task_test.rb
109
112
  - test/taskish.txt
110
113
  - test/taskish_test.rb