taskish 0.0.1 → 0.2.0

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