todorb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Rahul Kumar
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,20 @@
1
+ # todo.rb
2
+
3
+ ## Command-line todo manager
4
+
5
+ This is a port of my [todoapp written in shell](http://github.com/rkumar/todoapp). That todo app is similar to the famous one by Gina Trapani, except that it added various features including sub-tasks, and notes.
6
+
7
+ I may not make this application as feature-rich as the [shell version](http://github.com/rkumar/todoapp), however I needed to do this so I stop writing command-line programs using shell (portability issues across BSD and GNU versions of all commands). The shell version used `sed` extensively.
8
+
9
+ The fun things about this app, is that I am having to write ruby code that will give me sed's functionality (subset of course). Some of the stuff is present in sed.rb and is heavily being rewritten and improved as I go along.
10
+
11
+ The TODO file output is TODO2.txt and is a plain text file. A TAB separates the task number from the Task. I use task numbers, since I may refer to tasks elsewhere. Gina's app never saved a task Id but kept showing them.
12
+
13
+ The shell version, todoapp, allowed for any levels of sub-tasks. I have not yet added that, I may.
14
+
15
+ I also may fork this and make a YAML file, so that the format is standard, especially when having sub-tasks.
16
+ After this, I will port over my bug tracker, [bugzy.txt](http://github.com/rkumar/bugzy.txt), which uses a TAB delimited file. It's a cool app to use for bug tracking - you should try it out. I will possibly use sqlite instead of screwing around with a delimited file.
17
+
18
+ ## Copyright
19
+
20
+ Copyright (c) 2010 Rahul Kumar. See LICENSE for details.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/todorb ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ #require 'todorb/todo.rb'
4
+ require 'todorb'
5
+ Todo.main(ARGV)
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Color constants so we can print onto console using print or puts
4
+ # @example
5
+ # string = "hello ruby"
6
+ # puts " #{RED}#{BOLD}#{UNDERLINE}#{string}#{CLEAR}"
7
+ #
8
+ # http://wiki.bash-hackers.org/scripting/terminalcodes
9
+ # ripped off highline gem
10
+ module ColorConstants
11
+
12
+ # Embed in a String to clear all previous ANSI sequences. This *MUST* be
13
+ # done before the program exits!
14
+ #
15
+ CLEAR = "\e[0m"
16
+ # An alias for CLEAR.
17
+ RESET = CLEAR
18
+ NORMAL = CLEAR
19
+ # Erase the current line of terminal output.
20
+ ERASE_LINE = "\e[K"
21
+ # Erase the character under the cursor.
22
+ ERASE_CHAR = "\e[P"
23
+ # The start of an ANSI bold sequence.
24
+ BOLD = "\e[1m"
25
+ # The start of an ANSI dark sequence. (Terminal support uncommon.)
26
+ DARK = "\e[2m"
27
+ DIM = DARK
28
+ # The start of an ANSI underline sequence.
29
+ UNDERLINE = "\e[4m"
30
+ # An alias for UNDERLINE.
31
+ UNDERSCORE = UNDERLINE
32
+ # The start of an ANSI blink sequence. (Terminal support uncommon.)
33
+ BLINK = "\e[5m"
34
+ # The start of an ANSI reverse sequence.
35
+ REVERSE = "\e[7m"
36
+ # The start of an ANSI concealed sequence. (Terminal support uncommon.)
37
+ CONCEALED = "\e[8m"
38
+
39
+ # added from http://understudy.net/custom.html
40
+ BOLD_OFF = "\e[22m"
41
+ UNDERILNE_OFF = "\e[24m"
42
+ BLINK_OFF = "\e[25m"
43
+ REVERSE_OFF = "\e[27m"
44
+
45
+ # Set the terminal's foreground ANSI color to black.
46
+ BLACK = "\e[30m"
47
+ # Set the terminal's foreground ANSI color to red.
48
+ RED = "\e[31m"
49
+ # Set the terminal's foreground ANSI color to green.
50
+ GREEN = "\e[32m"
51
+ # Set the terminal's foreground ANSI color to yellow.
52
+ YELLOW = "\e[33m"
53
+ # Set the terminal's foreground ANSI color to blue.
54
+ BLUE = "\e[34m"
55
+ # Set the terminal's foreground ANSI color to magenta.
56
+ MAGENTA = "\e[35m"
57
+ # Set the terminal's foreground ANSI color to cyan.
58
+ CYAN = "\e[36m"
59
+ # Set the terminal's foreground ANSI color to white.
60
+ WHITE = "\e[37m"
61
+
62
+ # Set the terminal's background ANSI color to black.
63
+ ON_BLACK = "\e[40m"
64
+ # Set the terminal's background ANSI color to red.
65
+ ON_RED = "\e[41m"
66
+ # Set the terminal's background ANSI color to green.
67
+ ON_GREEN = "\e[42m"
68
+ # Set the terminal's background ANSI color to yellow.
69
+ ON_YELLOW = "\e[43m"
70
+ # Set the terminal's background ANSI color to blue.
71
+ ON_BLUE = "\e[44m"
72
+ # Set the terminal's background ANSI color to magenta.
73
+ ON_MAGENTA = "\e[45m"
74
+ # Set the terminal's background ANSI color to cyan.
75
+ ON_CYAN = "\e[46m"
76
+ # Set the terminal's background ANSI color to white.
77
+ ON_WHITE = "\e[47m"
78
+
79
+ end
data/lib/common/sed.rb ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby -w
2
+ #*************************************************************
3
+ # Sed like operations - just change row and delete row
4
+ # While converting some shell scripts in which i have used
5
+ # sed extensively, I need this kind of functionality
6
+ #
7
+ #*************************************************************
8
+ ##
9
+ # changes one or more rows based on pattern and replacement
10
+ # Also if replacement is not given, expects a block and yields
11
+ # matching lines to it
12
+
13
+ module Sed
14
+ def change_row filename, pattern, replacement = nil
15
+ d = _read filename
16
+ d.each { |row|
17
+ if row =~ pattern
18
+ if replacement
19
+ row.gsub!( pattern, replacement)
20
+ else
21
+ yield row
22
+ end
23
+ end
24
+ }
25
+ _write filename, d
26
+ end
27
+ def change_file filename
28
+ d = _read filename
29
+ d.each { |row|
30
+ yield row
31
+ }
32
+ _write filename, d
33
+ end
34
+ ##
35
+ # deletes on more rows based on a pattern
36
+ # Also takes a block and yields each row to it
37
+ def delete_row filename, pattern = nil
38
+ d = _read filename
39
+ if pattern
40
+ d.delete_if { |row| row =~ pattern }
41
+ else
42
+ d.delete_if { |row| yield row }
43
+ end
44
+ _write filename, d
45
+ end
46
+ ##
47
+ # read the given filename into an array
48
+ def _read filename
49
+ d = []
50
+ File.open(filename).each { |line|
51
+ d << line
52
+ }
53
+ return d
54
+ end
55
+ ##
56
+ # write the given array to the filename
57
+ def _write filename, array
58
+ File.open(filename, "w") do |file|
59
+ array.each { |row| file.puts row }
60
+ end
61
+ end
62
+ end # module
63
+
64
+ if __FILE__ == $0
65
+ include Sed
66
+ filename = "tmp.txt"
67
+ change_row filename, /_10_/ do |row|
68
+ row.sub!(/_10_/,"10")
69
+ end
70
+ change_row filename, /\+13\+/, "13"
71
+ delete_row(filename,/XXX/)
72
+ delete_row(filename) do |line|
73
+ line =~ /junk/
74
+ end
75
+ end
data/lib/todorb.rb ADDED
@@ -0,0 +1,698 @@
1
+ #!/usr/bin/env ruby -w
2
+ =begin
3
+ * Name: todorb.rb
4
+ * Description: a command line todo list manager
5
+ * Author: rkumar
6
+ * Date: 2010-06-10 20:10
7
+ * License: GPL
8
+
9
+ =end
10
+ require 'rubygems'
11
+ #require 'csv'
12
+ require 'common/colorconstants'
13
+ include ColorConstants
14
+ require 'common/sed'
15
+ include Sed
16
+
17
+ PRI_A = YELLOW + BOLD
18
+ PRI_B = WHITE + BOLD
19
+ PRI_C = GREEN + BOLD
20
+ PRI_D = CYAN + BOLD
21
+ VERSION = "1.0"
22
+ DATE = "2010-06-10"
23
+ APPNAME = $0
24
+ AUTHOR = "rkumar"
25
+
26
+ class Todo
27
+ def initialize options, argv
28
+
29
+ @options = options
30
+ @argv = argv
31
+ @file = options[:file]
32
+ ## data is a 2 dim array: rows and fields. It contains each row of the file
33
+ # as an array of strings. The item number is space padded.
34
+ @data = []
35
+ init_vars
36
+ end
37
+ def init_vars
38
+ @todo_default_action = "list"
39
+ @todo_file_path = @options[:file] || "TODO2.txt"
40
+ @archive_path = "archive.txt" # should take path of todo and put there TODO:
41
+ @todo_delim = "\t"
42
+ @appname = File.basename( Dir.getwd ) #+ ".#{$0}"
43
+ t = Time.now
44
+ @now = t.strftime("%Y-%m-%d %H:%M:%S")
45
+ @today = t.strftime("%Y-%m-%d")
46
+ @verbose = @options[:verbose]
47
+ #@actions = %w[ list add pri priority depri tag del delete status redo note archive help]
48
+ @actions = {}
49
+ @actions["list"] = "List all tasks.\n\t --hide-numbering --renumber"
50
+ @actions["add"] = "Add a task. \n\t #{$0} add <TEXT>\n\t --component C --project P --priority X add <TEXT>"
51
+ @actions["pri"] = "Add priority to task. \n\t #{$0} pri <ITEM> [A-Z]"
52
+ @actions["priority"] = "Same as pri"
53
+ @actions["depri"] = "Remove priority of task. \n\t #{$0} depri <ITEM>"
54
+ @actions["delete"] = "Delete a task. \n\t #{$0} delete <ITEM>"
55
+ @actions["del"] = "Same as delete"
56
+ @actions["status"] = "Change the status of a task. \n\t #{$0} status <STAT> <ITEM>\n\t<STAT> are closed started pending unstarted hold next"
57
+ @actions["redo"] = "Renumbers the todo file starting 1"
58
+ @actions["note"] = "Add a note to an item. \n\t #{$0} note <ITEM> <TEXT>"
59
+ @actions["archive"] = "archive closed tasks to archive.txt"
60
+ @actions["help"] = "Display help"
61
+
62
+
63
+ # TODO config
64
+ # we need to read up from config file and update
65
+ end
66
+ # menu MENU
67
+ def run
68
+ @action = @argv[0] || @todo_default_action
69
+ @action = @action.downcase
70
+ @action.sub!('priority', 'pri')
71
+ @action.sub!(/^del$/, 'delete')
72
+
73
+
74
+ @argv.shift
75
+ if @actions.include? @action
76
+ send(@action, @argv)
77
+ else
78
+ help @argv
79
+ end
80
+ end
81
+ def help args
82
+ #puts "Actions are #{@actions.join(", ")} "
83
+ @actions.each_pair { |name, val| puts "#{name}\t#{val}" }
84
+ end
85
+ def add args
86
+ if args.empty?
87
+ print "Enter todo: "
88
+ STDOUT.flush
89
+ text = gets.chomp
90
+ if text.empty?
91
+ exit 1
92
+ end
93
+ Kernel.print("You gave me '#{text}'")
94
+ else
95
+ text = args.join " "
96
+ Kernel.print("I got '#{text}'")
97
+ end
98
+ # convert actual newline to C-a. slash n's are escapes so echo -e does not muck up.
99
+ text.tr! "\n", ''
100
+ Kernel.print("Got '#{text}'\n")
101
+ item = _get_serial_number
102
+ paditem = _paditem(item)
103
+ print "item no is:#{paditem}:\n"
104
+ priority = @options[:priority] ? " (#{@options[:priority]})" : ""
105
+ project = @options[:project] ? " +#{@options[:project]}" : ""
106
+ component = @options[:component] ? " @#{@options[:component]}" : ""
107
+ newtext="#{paditem}#{@todo_delim}[ ]#{priority}#{project}#{component} #{text} (#{@today})"
108
+ puts "Adding"
109
+ puts newtext
110
+ File.open(@todo_file_path, "a") { | file| file.puts newtext }
111
+
112
+ end
113
+ ##
114
+ # reads serial_number file, returns serialno for this app
115
+ # and increments the serial number and writes back.
116
+ def _get_serial_number
117
+ require 'fileutils'
118
+ appname = @appname
119
+ filename = "/Users/rahul/serial_numbers"
120
+ h = {}
121
+ File.open(filename).each { |line|
122
+ #sn = $1 if line.match regex
123
+ x = line.split ":"
124
+ h[x[0]] = x[1].chomp
125
+ }
126
+ sn = h[appname] || 1
127
+ # update the sn in file
128
+ nsn = sn.to_i + 1
129
+ # this will create if not exists in addition to storing if it does
130
+ h[appname] = nsn
131
+ # write back to file
132
+ File.open(filename, "w") do |f|
133
+ h.each_pair {|k,v| f.print "#{k}:#{v}\n"}
134
+ end
135
+ return sn
136
+ end
137
+ ##
138
+ # After doing a redo of the numbering, we need to reset the numbers for that app
139
+ def _set_serial_number number
140
+ appname = @appname
141
+ pattern = Regexp.new "^#{appname}:.*$"
142
+ filename = "/Users/rahul/serial_numbers"
143
+ _backup filename
144
+ change_row filename, pattern, "#{appname}:#{number}"
145
+ end
146
+ def _backup filename=@todo_file_path
147
+ require 'fileutils'
148
+ FileUtils.cp filename, "#{filename}.org"
149
+ end
150
+ ##
151
+ # for historical reasons, I pad item to 3 spaces in text file.
152
+ # It used to help me in printing straight off without any formatting in unix shell
153
+ def _paditem item
154
+ return sprintf("%3s", item)
155
+ end
156
+ def populate
157
+ @ctr = 0
158
+ @total = 0
159
+ #CSV.foreach(@file,:col_sep => "\t") do |row| # 1.9 2009-10-05 11:12
160
+ File.open(@file).each do |line|
161
+ row = line.chomp.split "\t"
162
+ @total += 1
163
+ if @options[:show_all]
164
+ @data << row
165
+ @ctr += 1
166
+ else
167
+ unless row[1] =~ /^\[x\]/
168
+ @data << row
169
+ @ctr += 1
170
+ end
171
+ end
172
+ end
173
+ end
174
+ ##
175
+ # filters output based on project and or component and or priority
176
+ def filter
177
+ project = @options[:project]
178
+ component = @options[:component]
179
+ priority = @options[:priority]
180
+ if project
181
+ r = Regexp.new "\\+#{project}"
182
+ @data = @data.select { |row| row[1] =~ r }
183
+ end
184
+ if component
185
+ r = Regexp.new "@#{component}"
186
+ @data = @data.select { |row| row[1] =~ r }
187
+ end
188
+ if priority
189
+ r = Regexp.new "\\(#{priority}\\)"
190
+ @data = @data.select { |row| row[1] =~ r }
191
+ end
192
+ end
193
+ def list args
194
+ populate
195
+ grep if @options[:grep]
196
+ filter if @options[:filter]
197
+ sort if @options[:sort]
198
+ renumber if @options[:renumber]
199
+ colorize # << currently this is where I print !! Since i colorize the whole line
200
+ puts
201
+ puts " #{@data.length} of #{@total} rows displayed from #{@todo_file_path} "
202
+
203
+ end
204
+ def print_todo
205
+ @ctr = 0
206
+ @data.each { |row|
207
+ unless row[1] =~ /^\[x\]/
208
+ puts " #{row[0]} | #{row[1]} " #unless row[1] =~ /^\[x\]/
209
+ @ctr += 1
210
+ end
211
+ }
212
+ end
213
+ def each
214
+ @data.each { |row|
215
+ yield row
216
+ }
217
+ end
218
+ def active_tasks
219
+ @ctr = 0
220
+ @data.each { |row|
221
+ unless row[1] =~ /^\[x\]/
222
+ yield row
223
+ @ctr += 1
224
+ end
225
+ }
226
+ end
227
+ ##
228
+ # colorize each line, if required.
229
+ # However, we should put the colors in some Map, so it can be changed at configuration level.
230
+ #
231
+ def colorize
232
+ colorme = @options[:colorize]
233
+ @data.each do |r|
234
+ if @options[:hide_numbering]
235
+ string = "#{r[1]} "
236
+ else
237
+ string = " #{r[0]} #{r[1]} "
238
+ end
239
+ if colorme
240
+ m=string.match(/\(([A-Z])\)/)
241
+ if m
242
+ case m[1]
243
+ when "A", "B", "C", "D"
244
+ pri = self.class.const_get("PRI_#{m[1]}")
245
+ #string = "#{YELLOW}#{BOLD}#{string}#{CLEAR}"
246
+ string = "#{pri}#{string}#{CLEAR}"
247
+ else
248
+ string = "#{NORMAL}#{GREEN}#{string}#{CLEAR}"
249
+ #string = "#{BLUE}\e[6m#{string}#{CLEAR}"
250
+ #string = "#{BLUE}#{string}#{CLEAR}"
251
+ end
252
+ else
253
+ string = "#{NORMAL}#{string}#{CLEAR}"
254
+ end
255
+ end # colorme
256
+ ## since we've added notes, we convert C-a to newline with spaces
257
+ # so it prints in next line with some neat indentation.
258
+ string.gsub!('', "\n ")
259
+ #string.tr! '', "\n"
260
+ puts string
261
+ end
262
+ end
263
+ def sort
264
+ @data.sort! { |a,b| b[1] <=> a[1] }
265
+ end
266
+ def grep
267
+ r = Regexp.new @options[:grep]
268
+ #@data = @data.grep r
269
+ @data = @data.find_all {|i| i[1] =~ r }
270
+ end
271
+ ##
272
+ # Adds or changes priority for a task
273
+ #
274
+ # @param [Array] priority, single char A-Z, item or items
275
+ # @return
276
+ # @ example:
277
+ # pri A 5 6 7
278
+ # pri 5 6 7 A
279
+ # pri A 5 6 7 B 1 2 3
280
+ # pri 5 6 7 A 1 2 3 B
281
+
282
+ def pri args
283
+ populate
284
+ changeon = nil
285
+ items = []
286
+ prior = nil
287
+ item = nil
288
+ ## if the first arg is priority then following items all have that priority
289
+ ## if the first arg is item/s then wait for priority and use that
290
+ if args[0] =~ /^[A-Z]$/
291
+ changeon = :ITEM
292
+ elsif args[0] =~ /^[0-9]+$/
293
+ changeon = :PRI
294
+ else
295
+ puts "ERROR! "
296
+ exit 1
297
+ end
298
+ puts "args 0 is #{args[0]} "
299
+ args.each do |arg|
300
+ if arg =~ /^[A-Z]$/
301
+ prior = arg #$1
302
+ if changeon == :PRI
303
+ puts " changing previous items #{items} to #{prior} "
304
+ items.each { |i| _pri(i, prior) }
305
+ items = []
306
+ end
307
+ elsif arg =~ /^[0-9]+$/
308
+ item = arg #$1
309
+ if changeon == :ITEM
310
+ puts " changing #{item} to #{prior} "
311
+ _pri(item, prior)
312
+ else
313
+ items << item
314
+ end
315
+ else
316
+ puts "ERROR in arg :#{arg}:"
317
+ end
318
+ end
319
+ save_array
320
+ end
321
+ ##
322
+ # Reove the priority of a task
323
+ #
324
+ # @param [Array] items to deprioritize
325
+ # @return
326
+ public
327
+ def depri(args)
328
+ populate
329
+ puts "depri got #{args} "
330
+ each do |row|
331
+ item = row[0].sub(/^[ -]*/,'')
332
+ if args.include? item
333
+ if row[1] =~ /\] (\([A-Z]\) )/
334
+ puts row[1]
335
+ row[1].sub!(/\([A-Z]\) /,"")
336
+ puts "#{RED}#{row[1]}#{CLEAR}"
337
+ end
338
+ end
339
+ end
340
+ end
341
+ ##
342
+ # saves the task array to disk
343
+ def save_array
344
+ File.open(@todo_file_path, "w") do |file|
345
+ @data.each { |row| file.puts "#{row[0]}\t#{row[1]}" }
346
+ end
347
+ end
348
+ ##
349
+ # change priority of given item to priority in array
350
+ private
351
+ def _pri item, pri
352
+ paditem = _paditem(item)
353
+ @data.each { |row|
354
+ if row[0] == paditem
355
+ puts " #{row[0]} : #{row[1]} "
356
+ if row[1] =~ /\] (\([A-Z]\) )/
357
+ row[1].sub!(/\([A-Z]\) /,"")
358
+ end
359
+ row[1].sub!(/\] /,"] (#{pri}) ")
360
+ puts " #{RED}#{row[0]} : #{row[1]} #{CLEAR}"
361
+ return true
362
+ end
363
+ }
364
+ puts " #{RED} no such item #{item} #{CLEAR} "
365
+ return false
366
+
367
+ end
368
+ ##
369
+ # Appends a tag to task
370
+ #
371
+ # @param [Array] items and tag, or tag and items
372
+ # @return
373
+ public
374
+ def tag(args)
375
+ puts "tags args #{args} "
376
+ items_first = items_first? args
377
+ items = []
378
+ tag = nil
379
+ args.each do |arg|
380
+ if arg =~ /^[a-zA-Z]/
381
+ tag = arg
382
+ elsif arg =~ /^[0-9]+$/
383
+ items << arg
384
+ end
385
+ end
386
+ #items.each { |i| change_row }
387
+ change_file @todo_file_path do |line|
388
+ item = line.match(/^ *([0-9]+)/)
389
+ if items.include? item[1]
390
+ puts "#{line}" if @verbose
391
+ line.sub!(/$/, " @#{tag}")
392
+ puts "#{RED}#{line}#{CLEAR} " if @verbose
393
+ end
394
+ end
395
+ end
396
+ ##
397
+ # deletes one or more items
398
+ #
399
+ # @param [Array, #include?] items to delete
400
+ # @return
401
+ public
402
+ def delete(args)
403
+ puts "delete with #{args} "
404
+ delete_row @todo_file_path do |line|
405
+ #puts "line #{line} "
406
+ item = line.match(/^ *([0-9]+)/)
407
+ #puts "item #{item} "
408
+ if args.include? item[1]
409
+ if @options[:force]
410
+ true
411
+ else
412
+ puts line
413
+ print "Do you wish to delete (Y/N): "
414
+ STDOUT.flush
415
+ ans = STDIN.gets.chomp
416
+ ans =~ /[Yy]/
417
+ end
418
+ end
419
+ end
420
+ end
421
+ ##
422
+ # Change status of given items
423
+ #
424
+ # @param [Array, #include?] items to delete
425
+ # @return [true, false] success or fail
426
+ public
427
+ def status(args)
428
+ stat, items = _separate args
429
+ status, newstatus = _resolve_status stat
430
+ if status.nil?
431
+ print_red "Status #{stat} is invalid!"
432
+ exit 1
433
+ end
434
+ change_items(items, /(\[.\])/, "[#{newstatus}]")
435
+ #change_items items do |item, line|
436
+ #puts line if @verbose
437
+ #line.sub!(/(\[.\])/, "[#{newstatus}]")
438
+ #puts "#{RED}#{line}#{CLEAR}" if @verbose
439
+ #end
440
+ end
441
+ ##
442
+ # separates args into tag or subcommand and items
443
+ # This allows user to pass e.g. a priority first and then item list
444
+ # or item list first and then priority.
445
+ # This can only be used if the tag or pri or status is non-numeric and the item is numeric.
446
+ def _separate args
447
+ tag = nil
448
+ items = []
449
+ args.each do |arg|
450
+ if arg =~ /^[a-zA-Z]/
451
+ tag = arg
452
+ elsif arg =~ /^[0-9]+$/
453
+ items << arg
454
+ end
455
+ end
456
+ return tag, items
457
+ end
458
+ ##
459
+ # Renumber while displaying
460
+ #
461
+ # @return [true, false] success or fail
462
+ private
463
+ def renumber
464
+ @data.each_with_index { |row, i|
465
+ paditem = _paditem(i+1)
466
+ row[0] = paditem
467
+ }
468
+ end
469
+ ##
470
+ # For given items, add a note
471
+ #
472
+ # @param [Array, #include?] items to add note to, note
473
+ # @return [true, false] success or fail
474
+ public
475
+ def note(args)
476
+ _backup
477
+ text = args.pop
478
+ change_items args do |item, line|
479
+ m = line.match(/^ */)
480
+ indent = m[0]
481
+ puts line if @verbose
482
+ # we place the text before the date, adding a C-a and indent
483
+ # At printing the C-a is replaced with a newline and some spaces
484
+ ret = line.sub!(/ (\([0-9]{4})/," #{indent}* #{text} "+'\1')
485
+ print_red line if @verbose
486
+ end
487
+ end
488
+ ##
489
+ # Archive all items
490
+ #
491
+ # @param none (ignored)
492
+ # @return [true, false] success or fail
493
+ public
494
+ def archive(args=nil)
495
+ filename = @archive_path
496
+ file = File.open(filename, "a")
497
+ ctr = 0
498
+ delete_row @todo_file_path do |line|
499
+ if line =~ /\[x\]/
500
+ file.puts line
501
+ ctr += 1
502
+ puts line if @verbose
503
+ true
504
+ end
505
+ end
506
+ file.close
507
+ puts "Archived #{ctr} tasks."
508
+ end
509
+ ##
510
+ # For given items, ...
511
+ #
512
+ # @param [Array, #include?] items to delete
513
+ # @return [true, false] success or fail
514
+ public
515
+ def CHANGEME(args)
516
+ end
517
+ ##
518
+ # yields lines from file that match the given item
519
+ # We do not need to now parse and match the item in each method
520
+ def change_items args, pattern=nil, replacement=nil
521
+ change_file @todo_file_path do |line|
522
+ item = line.match(/^ *([0-9]+)/)
523
+ if args.include? item[1]
524
+ if pattern
525
+ puts line if @verbose
526
+ line.sub!(pattern, replacement)
527
+ print_red line if @verbose
528
+ else
529
+ yield item[1], line
530
+ end
531
+ end
532
+ end
533
+ end
534
+ ##
535
+ # Redoes the numbering in the file.
536
+ # Useful if the numbers have gone high and you want to start over.
537
+ def redo args
538
+ ctr = 1
539
+ require 'fileutils'
540
+ FileUtils.cp @todo_file_path, "#{@todo_file_path}.org"
541
+ puts "Saved #{@todo_file_path} as #{@todo_file_path}.org"
542
+ change_file @todo_file_path do |line|
543
+ paditem = _paditem ctr
544
+ line.sub!(/^ *[0-9]+/, paditem)
545
+ ctr += 1
546
+ end
547
+ _set_serial_number ctr
548
+ puts "Redone numbering"
549
+ end
550
+ ##
551
+ # does this command start with items or something else
552
+ private
553
+ def items_first?(args)
554
+ return true if args[0] =~ /^[0-9]+$/
555
+ return false
556
+ end
557
+ def print_red line
558
+ puts "#{RED}#{line}#{CLEAR}"
559
+ end
560
+ private
561
+ def _resolve_status stat
562
+ status = nil
563
+ #puts " got #{stat} "
564
+ case stat
565
+ when "@","sta","star","start","started"
566
+ status="start"
567
+ newstatus = "@"
568
+ when "P","pen","pend","pending"
569
+ status="pend"
570
+ newstatus = "P"
571
+ when "x","clo","clos","close","closed"
572
+ status="close"
573
+ newstatus = "x"
574
+ when "1","next"
575
+ status="next"
576
+ newstatus = "1"
577
+ when "H","hold"
578
+ status="hold"
579
+ newstatus = "H"
580
+ when "u","uns","unst","unstart","unstarted"
581
+ status="unstarted"
582
+ newstatus = " "
583
+ end
584
+ #puts " after #{status} "
585
+ #newstatus=$( echo $status | sed 's/^start/@/;s/^pend/P/;s/^close/x/;s/hold/H/;s/next/1/;s/^unstarted/ /' )
586
+ return status, newstatus
587
+ end
588
+
589
+ def self.main args
590
+ begin
591
+ # http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html
592
+ require 'optparse'
593
+ options = {}
594
+ options[:verbose] = false
595
+ options[:colorize] = true
596
+
597
+ OptionParser.new do |opts|
598
+ opts.banner = "Usage: #{$0} [options] action"
599
+
600
+ opts.separator ""
601
+ opts.separator "Specific options:"
602
+
603
+
604
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
605
+ options[:verbose] = v
606
+ end
607
+ opts.on("-f", "--file FILENAME", "CSV filename") do |v|
608
+ options[:file] = v
609
+ end
610
+ opts.on("-P", "--project PROJECTNAME", "name of project for add or list") { |v|
611
+ options[:project] = v
612
+ options[:filter] = true
613
+ }
614
+ opts.on("-p", "--priority A-Z", "priority code for add or list") { |v|
615
+ options[:priority] = v
616
+ options[:filter] = true
617
+ }
618
+ opts.on("-C", "--component COMPONENT", "component name for add or list") { |v|
619
+ options[:component] = v
620
+ options[:filter] = true
621
+ }
622
+ opts.on("--force", "force delete or add without prompting") do |v|
623
+ options[:force] = v
624
+ end
625
+ opts.separator ""
626
+ opts.separator "List options:"
627
+
628
+ opts.on("--[no-]color", "--[no-]colors", "colorize listing") do |v|
629
+ options[:colorize] = v
630
+ options[:color_scheme] = 1
631
+ end
632
+ opts.on("-s", "--sort", "sort list on priority") do |v|
633
+ options[:sort] = v
634
+ end
635
+ opts.on("-g", "--grep REGEXP", "filter list on pattern") do |v|
636
+ options[:grep] = v
637
+ end
638
+ opts.on("--renumber", "renumber while listing") do |v|
639
+ options[:renumber] = v
640
+ end
641
+ opts.on("--hide-numbering", "hide-numbering while listing ") do |v|
642
+ options[:hide_numbering] = v
643
+ end
644
+ opts.on("--show-all", "show all tasks (incl closed)") do |v|
645
+ options[:show_all] = v
646
+ end
647
+
648
+ opts.separator ""
649
+ opts.separator "Common options:"
650
+
651
+ opts.on_tail("-d DIR", "--dir DIR", "Use TODO file in this directory") do |v|
652
+ require 'FileUtils'
653
+ dir = File.expand_path v
654
+ if File.directory? dir
655
+ options[:dir] = dir
656
+ FileUtils.cd dir
657
+ else
658
+ puts "#{RED}#{v}: no such directory #{CLEAR}"
659
+ exit 1
660
+ end
661
+ end
662
+ # No argument, shows at tail. This will print an options summary.
663
+ # Try it and see!
664
+ opts.on_tail("-h", "--help", "Show this message") do
665
+ puts opts
666
+ exit
667
+ end
668
+
669
+ opts.on_tail("--show-actions", "show actions ") do |v|
670
+ todo = Todo.new(options, ARGV)
671
+ todo.help nil
672
+ exit 0
673
+ end
674
+
675
+ opts.on_tail("--version", "Show version") do
676
+ puts "#{APPNAME} version #{VERSION}, #{DATE}"
677
+ puts "by #{AUTHOR}. This software is under the GPL License."
678
+ exit 0
679
+ end
680
+ end.parse!(args)
681
+
682
+ #options[:file] ||= "rbcurse/TODO2.txt"
683
+ options[:file] ||= "TODO2.txt"
684
+ if options[:verbose]
685
+ p options
686
+ print "ARGV: "
687
+ p args #ARGV
688
+ end
689
+ #raise "-f FILENAME is mandatory" unless options[:file]
690
+
691
+ todo = Todo.new(options, args)
692
+ todo.run
693
+ ensure
694
+ end
695
+ end # main
696
+ end # class Todo
697
+
698
+ Todo.main(ARGV) if __FILE__ == $0
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: todorb
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Rahul Kumar
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-13 00:00:00 +05:30
18
+ default_executable: todorb
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: thoughtbot-shoulda
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ description: "command-line program that manages a todo list text file "
33
+ email: sentinel1879@gmail.com
34
+ executables:
35
+ - todorb
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - LICENSE
40
+ - README.markdown
41
+ files:
42
+ - README.markdown
43
+ - VERSION
44
+ - lib/common/colorconstants.rb
45
+ - lib/common/sed.rb
46
+ - lib/todorb.rb
47
+ - LICENSE
48
+ has_rdoc: true
49
+ homepage: http://github.com/rkumar/todorb
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options:
54
+ - --charset=UTF-8
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.3.6
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: command-line todo list manager
78
+ test_files: []
79
+