todotxt 0.0.3 → 0.1.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.
Files changed (49) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +2 -0
  3. data/README.md +1 -0
  4. data/bin/todotxt +3 -3
  5. data/conf/todotxt.cfg +13 -1
  6. data/cucumber.yml +3 -0
  7. data/features/add.feature +24 -0
  8. data/features/append.feature +28 -0
  9. data/features/backwards.feature +28 -0
  10. data/features/colors.feature +51 -0
  11. data/features/del.feature +52 -0
  12. data/features/depri.feature +38 -0
  13. data/features/do.feature +47 -0
  14. data/features/due.feature +49 -0
  15. data/features/edit.feature +31 -0
  16. data/features/generate_config.feature +19 -0
  17. data/features/generate_txt.feature +20 -0
  18. data/features/initialize.feature +73 -0
  19. data/features/list.feature +132 -0
  20. data/features/move.feature +33 -0
  21. data/features/prepend.feature +28 -0
  22. data/features/pri.feature +40 -0
  23. data/features/replace.feature +28 -0
  24. data/features/step_definitions/environment_steps.rb +47 -0
  25. data/features/step_definitions/list_steps.rb +34 -0
  26. data/features/support/ansi.rb +5 -0
  27. data/features/support/aruba.rb +9 -0
  28. data/features/support/debugger.rb +1 -0
  29. data/features/undo.feature +54 -0
  30. data/lib/todotxt/cli.rb +131 -45
  31. data/lib/todotxt/clihelpers.rb +4 -1
  32. data/lib/todotxt/config.rb +58 -0
  33. data/lib/todotxt/regex.rb +1 -0
  34. data/lib/todotxt/todo.rb +5 -0
  35. data/lib/todotxt/todofile.rb +40 -0
  36. data/lib/todotxt/todolist.rb +20 -2
  37. data/lib/todotxt/version.rb +1 -1
  38. data/lib/todotxt.rb +2 -0
  39. data/spec/cli_spec.rb +6 -0
  40. data/spec/config_spec.rb +52 -0
  41. data/spec/fixtures/config_both.cfg +4 -0
  42. data/spec/fixtures/config_new.cfg +2 -0
  43. data/spec/fixtures/config_old.cfg +1 -0
  44. data/spec/spec_helper.rb +3 -0
  45. data/spec/todo_spec.rb +12 -0
  46. data/spec/todofile_spec.rb +31 -0
  47. data/spec/todolist_spec.rb +20 -2
  48. data/todotxt.gemspec +4 -0
  49. metadata +154 -28
@@ -0,0 +1,33 @@
1
+ Feature: move
2
+
3
+ So that I can keep items organised
4
+ As a user
5
+ I want to move items between files
6
+
7
+ Background:
8
+ Given a config exists with the following files:
9
+ | alias | path |
10
+ | todo | todo.txt |
11
+ | wishlist | wishlist.txt |
12
+ And a todofile with the following items exists:
13
+ | todo |
14
+ | Getting Things Done @bookstore |
15
+ | Label Maker @officesupply |
16
+ And an empty todofile named "wishlist.txt" exists
17
+
18
+ Scenario: Move item from todo.txt to wishlist.txt
19
+ When I run `todotxt move 1 wishlist`
20
+ Then it should pass with:
21
+ """
22
+ 1. Getting Things Done @bookstore
23
+ => Moved to wishlist.txt
24
+ """
25
+ And the file "todo.txt" should not contain "Getting Things Done @bookstore"
26
+ And the file "wishlist.txt" should contain "Getting Things Done @bookstore"
27
+
28
+ Scenario: Move an illegal item
29
+ When I run `todotxt move 1337 wishlist`
30
+ Then it should pass with:
31
+ """
32
+ ERROR: No todo found at line 1337
33
+ """
@@ -0,0 +1,28 @@
1
+ Feature: Prepend
2
+
3
+ So that I can change items
4
+ As a user
5
+ I want to prepend text to an item
6
+
7
+ Background:
8
+ Given a default config exists
9
+ And a todofile with the following items exists:
10
+ | todo |
11
+ | (B) Install todotxt @cli +todotxt |
12
+ | Drink coffee |
13
+
14
+ Scenario: Add text to an item
15
+ When I run `todotxt prepend 2 Brew and`
16
+ Then it should pass with:
17
+ """
18
+ 2. Brew and Drink coffee
19
+ """
20
+ And the file "todo.txt" should contain "Brew and Drink coffee"
21
+
22
+
23
+ Scenario: Add text to an illegal item:
24
+ When I run `todotxt prepend 1337 @sofa`
25
+ Then it should pass with:
26
+ """
27
+ ERROR: No todo found at line 1337
28
+ """
@@ -0,0 +1,40 @@
1
+ Feature: Prioritise
2
+
3
+ So that I can make items more important
4
+ As a user
5
+ I want to prioritise items
6
+
7
+ Background:
8
+ Given a default config exists
9
+ And a todofile with the following items exists:
10
+ | todo |
11
+ | (B) Install todotxt @cli +todotxt |
12
+ | Drink coffee |
13
+
14
+ Scenario: Set priority of an item should report it and change it in the file
15
+ When I run `todotxt pri 2 A`
16
+ Then it should pass with:
17
+ """
18
+ 2. (A) Drink coffee
19
+ """
20
+ And the file "todo.txt" should contain "(A) Drink coffee"
21
+
22
+ Scenario: Set the priority of an already prioritised item
23
+ When I run `todotxt pri 1 A`
24
+ Then the file "todo.txt" should contain "(A) Install todotxt @cli +todotxt"
25
+
26
+ #todo: make it throw an error instead.
27
+ Scenario: Attempt to set priority to an illegal priority
28
+ When I run `todotxt pri 2 Foo`
29
+ Then it should pass with:
30
+ """
31
+ 2. Drink coffee
32
+ """
33
+ And the file "todo.txt" should not contain "(Foo) Drink coffee"
34
+
35
+ Scenario: Attempt to set the priority of an illegal line
36
+ When I run `todotxt pri 1337 A`
37
+ Then it should pass with:
38
+ """
39
+ ERROR: No todo found at line 1337
40
+ """
@@ -0,0 +1,28 @@
1
+ Feature: Replace
2
+
3
+ So that I can change items
4
+ As a user
5
+ I want to completely replace an item with new text
6
+
7
+ Background:
8
+ Given a default config exists
9
+ And a todofile with the following items exists:
10
+ | todo |
11
+ | (B) Install todotxt @cli +todotxt |
12
+ | Drink coffee |
13
+
14
+ Scenario: Add text to an item
15
+ When I run `todotxt replace 2 sip frappucino @buckstar`
16
+ Then it should pass with:
17
+ """
18
+ 2. sip frappucino @buckstar
19
+ """
20
+ And the file "todo.txt" should contain "sip frappucino @buckstar"
21
+ And the file "todo.txt" should not contain "Drink coffee"
22
+
23
+ Scenario: Add text to an illegal item:
24
+ When I run `todotxt prepend 1337 @sofa`
25
+ Then it should pass with:
26
+ """
27
+ ERROR: No todo found at line 1337
28
+ """
@@ -0,0 +1,47 @@
1
+ Given /^a default config exists$/ do
2
+ write_file(".todotxt.cfg", "[files]\ntodo = todo.txt")
3
+ end
4
+
5
+ Given /^an old config exists$/ do
6
+ write_file(".todotxt.cfg", "todo_txt_path = todo.txt")
7
+ end
8
+
9
+ Given /^an empty environment$/ do
10
+ step %{a file named ".todotxt.cfg" should not exist}
11
+ step %{a file named "todo.txt" should not exist}
12
+ end
13
+
14
+ Given /^a config exists with the following files:$/ do |files|
15
+ files_directive = "[files]\n"
16
+ files_directive += files.hashes.map {|file| "#{file["alias"]}=#{file["path"]}" }.join("\n")
17
+ write_file(".todotxt.cfg", files_directive)
18
+ end
19
+
20
+ Given /^a default config exists with the editor set to "(.*?)"$/ do |editor|
21
+ write_file(".todotxt.cfg", "editor=#{editor}\n[files]\ntodo = todo.txt")
22
+ end
23
+
24
+ Given /^a todofile exists$/ do
25
+ write_file("todo.txt", "Read documentation for todotxt\nWrite cucumber steps for todotxt")
26
+ end
27
+
28
+ Given /^a todofile with done items exists$/ do
29
+ write_file("todo.txt", "Read documentation for todotxt\nx Install todotxt\nWrite cucumber steps for todotxt")
30
+ end
31
+
32
+ Given /^a todofile with the following items exists:$/ do |todolist|
33
+ contents = todolist.hashes.map {|row| row["todo"] }.join("\n")
34
+ write_file("todo.txt", contents)
35
+ end
36
+
37
+ Given /^an empty todofile named "(.*?)" exists$/ do |filename|
38
+ write_file(filename, "")
39
+ end
40
+
41
+ Given /^the enviromnent variable "(.*?)" is set to "(.*?)"$/ do |name, value|
42
+ ENV[name] = value
43
+ end
44
+
45
+ Given /^the date is "(.*?)"$/ do |date|
46
+ step %{the enviromnent variable "date" is set to "#{date}"}
47
+ end
@@ -0,0 +1,34 @@
1
+ Then /^I should see all entries from the todofile with numbers$/ do
2
+ contents = ""
3
+ File.open(File.join(ENV["HOME"], "todo.txt")).each_line do |line|
4
+ # matching "1. Do Something"
5
+ contents += "([\\d]\.\\s+)#{Regexp.escape(line.strip)}.*"
6
+ end
7
+ step "it should pass with regex:", contents
8
+ end
9
+
10
+ Then /^I should see all entries from the todofile without formatting$/ do
11
+ contents = ""
12
+ File.open(File.join(ENV["HOME"], "todo.txt")).each_line do |line|
13
+ # matching "1 Do something", note the missing dot .
14
+ contents += "([\\d]\\s+)#{Regexp.escape(line.strip)}.*"
15
+ end
16
+ step "it should pass with regex:", contents
17
+ step "the output should not match /TODO: [\d]+ items/"
18
+ end
19
+
20
+ Then /^it should count (\d+) TODO\-items$/ do |count|
21
+ step %{the output should match /^TODO: #{count} items$/}
22
+ end
23
+
24
+ Then /^it should output "([^"]*)" brightly in "([^"]*)"$/ do |string, color|
25
+ assert_partial_output(string.color(color.to_sym).bright, all_output)
26
+ end
27
+ Then /^it should output "([^"]*)" in "([^"]*)"$/ do |string, color|
28
+ assert_partial_output(string.color(color.to_sym), all_output)
29
+ end
30
+
31
+ Then /^it should pass with todays date$/ do
32
+ today = DateTime.now.strftime("%Y-%m-%d")
33
+ step "it should pass with regex:", ".*#{today}.*"
34
+ end
@@ -0,0 +1,5 @@
1
+ require "rainbow"
2
+
3
+ Before('@ansi') do
4
+ ENV["FORCE_COLORS"] = "TRUE"
5
+ end
@@ -0,0 +1,9 @@
1
+ require 'aruba/cucumber'
2
+
3
+ # Temporarily enforce an isolated, fake, homedir.
4
+ Around do |scenario, block|
5
+ @__aruba_original_home = ENV["HOME"]
6
+ ENV["HOME"] = File.expand_path(File.join("tmp", "aruba"))
7
+ block.call
8
+ ENV["HOME"] = @__aruba_original_home
9
+ end
@@ -0,0 +1 @@
1
+ require "debugger"
@@ -0,0 +1,54 @@
1
+ Feature: Undo
2
+
3
+ So that I can fix mistakes
4
+ As a user
5
+ I want to mark items as not done
6
+
7
+ Background:
8
+ Given a default config exists
9
+ Given a todofile with the following items exists:
10
+ | todo |
11
+ | x 2013-01-01 Install todotxt @cli +todotxt |
12
+ | x Read documentation +todotxt |
13
+ | 2012-12-12 Buy GTD book @amazon +wishlist |
14
+
15
+ Scenario: Undo a single item reports it back and marks it as not done in the file
16
+ When I run `todotxt undo 2`
17
+ Then it should pass with:
18
+ """
19
+ 2. Read documentation +todotxt
20
+ """
21
+ And the file "todo.txt" should contain exactly:
22
+ """
23
+ x 2013-01-01 Install todotxt @cli +todotxt
24
+ Read documentation +todotxt
25
+ 2012-12-12 Buy GTD book @amazon +wishlist
26
+ """
27
+
28
+ Scenario: Undo multiple items
29
+ When I run `todotxt undo 1 2`
30
+ Then it should pass with:
31
+ """
32
+ 1. 2013-01-01 Install todotxt @cli +todotxt
33
+ 2. Read documentation +todotxt
34
+ """
35
+ And the file "todo.txt" should contain exactly:
36
+ """
37
+ 2013-01-01 Install todotxt @cli +todotxt
38
+ Read documentation +todotxt
39
+ 2012-12-12 Buy GTD book @amazon +wishlist
40
+ """
41
+
42
+ Scenario: Undo an item that was not marked as done
43
+ When I run `todotxt undo 3`
44
+ Then it should pass with:
45
+ """
46
+ 3. 2012-12-12 Buy GTD book @amazon +wishlist
47
+ """
48
+
49
+ Scenario: Undo invalid items
50
+ When I run `todotxt undo 1337`
51
+ Then it should pass with:
52
+ """
53
+ ERROR: No todo found at line 1337
54
+ """
data/lib/todotxt/cli.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  require "thor"
2
2
  require "rainbow"
3
+ require "chronic"
3
4
  require "parseconfig"
4
5
 
5
6
  module Todotxt
6
- CFG_PATH = File.expand_path("~/.todotxt.cfg")
7
-
8
7
  class CLI < Thor
9
8
  include Thor::Actions
10
9
  include Todotxt::CLIHelpers
@@ -15,14 +14,31 @@ module Todotxt
15
14
 
16
15
  def initialize(*args)
17
16
  super
17
+ # Allow testing colors, rainbow usually detects whether
18
+ # the output goes to a TTY, but Aruba/Cucumber is not a
19
+ # TTY, so we enforce it here, based on an environment var
20
+ Sickill::Rainbow.enabled = true if ENV["FORCE_COLORS"] == "TRUE"
21
+ @config = Config.new
22
+ @list = nil
23
+ unless ["help", "generate_config", "generate_txt"].include? ARGV[0]
24
+ ask_and_create @config unless @config.file_exists?
25
+ if @config.deprecated? and options[:file]
26
+ error_and_exit "You are using an old config, which has no support for mulitple files. Please update your configuration."
27
+ end
18
28
 
19
- unless ["help", "generate_config"].include? ARGV[0]
20
- parse_config
21
-
22
- @list = TodoList.new @txt_path
29
+ parse_conf
30
+ ask_and_create @file unless @file.exists?
31
+ @list = TodoList.new @file
23
32
  end
33
+
24
34
  end
25
35
 
36
+ class_option :file, :type => :string, :desc => "Use a different file than todo.txt
37
+ E.g. use 'done' to have the action performed on the file you set for 'done' in the todotxt
38
+ configuration under [files]."
39
+
40
+ default_task :list
41
+
26
42
  #
27
43
  # Listing
28
44
  #
@@ -31,12 +47,7 @@ module Todotxt
31
47
  method_option :done, :type => :boolean, :aliases => "-d", :desc => "Include todo items that have been marked as done"
32
48
  method_option :simple, :type => :boolean, :desc => "Simple output (for scripts, etc)"
33
49
  def list search=""
34
- with_done = false
35
-
36
- with_done = true if options[:done]
37
-
38
- @list.filter(search, :with_done => with_done)
39
-
50
+ @list.filter(search, :with_done => (options[:done] ? true : false))
40
51
  render_list :simple => !!options[:simple]
41
52
  end
42
53
  map "ls" => :list
@@ -61,6 +72,24 @@ module Todotxt
61
72
  end
62
73
  map "lsc" => :lscon
63
74
 
75
+ desc "due", "List due items"
76
+ def due
77
+ if ENV["date"] # Allow testing to "freeze" the date
78
+ today = DateTime.parse(ENV["date"]).to_date
79
+ else
80
+ today = DateTime.now.to_date
81
+ end
82
+
83
+ puts "Due today (#{today.strftime("%Y-%m-%d")})".bright
84
+ @list.on_date(today).each { |todo| puts format_todo(todo) }
85
+ puts "\nPast-due items".bright
86
+ @list.before_date(today).each { |todo| puts format_todo(todo) }
87
+ puts "\nDue 7 days in advance".bright
88
+ ((today+1)..(today+7)).each do |day|
89
+ @list.on_date(day).each { |todo| puts format_todo(todo) }
90
+ end
91
+ end
92
+
64
93
  #
65
94
  # Todo management
66
95
  #
@@ -201,21 +230,72 @@ module Todotxt
201
230
  end
202
231
  map "rm" => :del
203
232
 
233
+ desc "edit", "Open todo.txt file in your default editor"
234
+ def edit
235
+ system "#{@editor} #{@file.path}"
236
+ end
237
+
238
+ desc "move | mv ITEM#[, ITEM#, ITEM#, ...] file", "Move ITEM# to another file"
239
+ def move line1, *lines, other_list_alias
240
+ if @files[other_list_alias.to_sym].nil?
241
+ error_and_exit "File alias #{other_list_alias} not found"
242
+ else
243
+ other_list = TodoList.new @files[other_list_alias.to_sym]
244
+ end
245
+
246
+ lines.unshift(line1).each do |line|
247
+ todo = @list.find_by_line line
248
+ if todo
249
+ say format_todo(todo)
250
+ @list.move line, other_list
251
+ notice "Moved to #{other_list}"
252
+
253
+ other_list.save
254
+ @list.save
255
+ else
256
+ error "No todo found at line #{line}"
257
+ end
258
+ end
259
+ end
260
+ map "mv" => :move
261
+
262
+ desc "move | mv ITEM#[, ITEM#, ITEM#, ...] file", "Move ITEM# to another file"
263
+ def move line1, *lines, other_list_alias
264
+ if @files[other_list_alias.to_sym].nil?
265
+ error_and_exit "File alias #{other_list_alias} not found"
266
+ else
267
+ other_list = TodoList.new @files[other_list_alias.to_sym]
268
+ end
269
+
270
+ lines.unshift(line1).each do |line|
271
+ todo = @list.find_by_line line
272
+ if todo
273
+ say format_todo(todo)
274
+ @list.move line, other_list
275
+ notice "Moved to #{other_list}"
276
+
277
+ other_list.save
278
+ @list.save
279
+ else
280
+ error "No todo found at line #{line}"
281
+ end
282
+ end
283
+ end
284
+ map "mv" => :move
285
+
204
286
  #
205
287
  # File generation
206
288
  #
207
289
 
208
290
  desc "generate_config", "Create a .todotxt.cfg file in your home folder, containing the path to todo.txt"
209
291
  def generate_config
210
- copy_file "todotxt.cfg", CFG_PATH
292
+ copy_file "todotxt.cfg", Config.config_path
211
293
  puts ""
212
-
213
- parse_config
214
294
  end
215
295
 
216
296
  desc "generate_txt", "Create a sample todo.txt"
217
297
  def generate_txt
218
- copy_file "todo.txt", @txt_path
298
+ copy_file "todo.txt", @file
219
299
  puts ""
220
300
  end
221
301
 
@@ -229,7 +309,6 @@ module Todotxt
229
309
  end
230
310
 
231
311
  private
232
-
233
312
  def render_list opts={}
234
313
  numsize = @list.count + 1
235
314
  numsize = numsize.to_s.length + 0
@@ -247,43 +326,50 @@ module Todotxt
247
326
  end
248
327
  end
249
328
 
250
- def parse_config
251
- unless File.exist? CFG_PATH
252
- puts "You need a .todotxt.cfg file in your home folder to continue (used to determine the path of your todo.txt.) Answer yes to have it generated for you (pointing to ~/todo.txt), or no to create it yourself.\n\n"
253
- confirm_generate = yes? "Create ~/.todotxt.cfg? [y/N]"
329
+ # File should respond_to "basename", "path" and "generate!"
330
+ def ask_and_create file
331
+ puts "#{file.basename} doesn't exist yet. Would you like to generate a sample file?"
332
+ confirm_generate = yes? "Create #{file.path}? [y/N]"
254
333
 
255
- if confirm_generate
256
- generate_config
257
- else
258
- puts ""
259
- exit
260
- end
334
+ if confirm_generate
335
+ file.generate!
336
+ else
337
+ puts ""
338
+ exit
261
339
  end
340
+ end
262
341
 
263
- cfg = ParseConfig.new(CFG_PATH)
264
-
265
- txt = cfg["todo_txt_path"]
266
-
267
- if txt
268
- @txt_path = File.expand_path(txt)
342
+ def parse_conf
343
+ @files = {}
269
344
 
270
- unless File.exist? @txt_path
271
- puts "#{txt} doesn't exist yet. Would you like to generate a sample file?"
272
- confirm_generate = yes? "Create #{txt}? [y/N]"
345
+ return if @config.nil?
273
346
 
274
- if confirm_generate
275
- generate_txt
276
- else
277
- puts ""
278
- exit
347
+ # Backwards compatibility with todo_txt_path
348
+ # when old variable is still set, and no files=>todo
349
+ # given, fallback to this old version.
350
+ if @config["todo_txt_path"]
351
+ @files[:todo] ||= TodoFile.new(@config["todo_txt_path"])
352
+ else
353
+ # Fill the @files from settings.
354
+ @config["files"].each do |name, file_path|
355
+ unless file_path.empty?
356
+ @files[name.to_sym] = TodoFile.new(file_path)
279
357
  end
280
358
  end
359
+ end
360
+
361
+ # Determine what file should be activated, set that in @file
362
+ if options[:file]
363
+ file_sym = options[:file].to_sym
364
+ if @files.has_key? file_sym
365
+ @file = @files[file_sym]
366
+ end
281
367
  else
282
- error "Couldn't find todo_txt_path setting in ~/.todotxt.cfg."
283
- puts "Please run the following to create a new configuration file:"
284
- puts " todotxt generate_config"
285
- exit
368
+ @file = @files[:todo]
286
369
  end
370
+
371
+ # Determine the editor
372
+ @editor = @config["editor"] || ENV["EDITOR"]
287
373
  end
288
374
  end
289
375
  end
@@ -3,7 +3,6 @@ module Todotxt
3
3
 
4
4
  def format_todo(todo, number_padding=nil)
5
5
  line = todo.line.to_s
6
-
7
6
  if number_padding
8
7
  line = line.rjust number_padding
9
8
  end
@@ -50,5 +49,9 @@ module Todotxt
50
49
  puts "ERROR: #{message}".color(:red)
51
50
  end
52
51
 
52
+ def error_and_exit message =""
53
+ error message
54
+ exit
55
+ end
53
56
  end
54
57
  end
@@ -0,0 +1,58 @@
1
+ require "parseconfig"
2
+ require "fileutils"
3
+
4
+ module Todotxt
5
+ class Config < ParseConfig
6
+ def initialize config_file = ""
7
+ if config_file.empty?
8
+ @config_file = Config.config_path
9
+ else
10
+ @config_file = config_file
11
+ end
12
+
13
+ if file_exists?
14
+ super @config_file
15
+ validate
16
+ else
17
+ @params = {}
18
+ @groups = []
19
+ end
20
+ end
21
+
22
+ def file_exists?
23
+ File.exists? @config_file
24
+ end
25
+
26
+ def files
27
+ params["files"] || {"todo" => params["todo_txt_path"] }
28
+ end
29
+
30
+ def generate!
31
+ FileUtils.copy File.join(File.dirname(File.expand_path(__FILE__)), "..", "..", "conf", "todotxt.cfg"), @config_file
32
+ import_config
33
+ end
34
+
35
+ def path
36
+ @config_file
37
+ end
38
+
39
+ def basename
40
+ File.basename @config_file
41
+ end
42
+
43
+ def self.config_path
44
+ File.join ENV["HOME"], ".todotxt.cfg"
45
+ end
46
+
47
+ def deprecated?
48
+ params["files"].nil?
49
+ end
50
+
51
+ private
52
+ def validate
53
+ if params["files"] && params["todo_txt_path"]
54
+ raise "Bad configuration file: use either files or todo_txt_path"
55
+ end
56
+ end
57
+ end
58
+ end
data/lib/todotxt/regex.rb CHANGED
@@ -2,5 +2,6 @@ module Todotxt
2
2
  PRIORITY_REGEX = /^\(([A-Z])\) /
3
3
  PROJECT_REGEX = /(\+\w+)/
4
4
  CONTEXT_REGEX = /(@\w+)/
5
+ DATE_REGEX = /^(\([A-Z]\) )?(x )?((\d{4}-)(\d{1,2}-)(\d{1,2}))\s?/
5
6
  DONE_REGEX = /^(\([A-Z]\) )?x /
6
7
  end
data/lib/todotxt/todo.rb CHANGED
@@ -24,6 +24,11 @@ module Todotxt
24
24
  @done = !text.scan(DONE_REGEX).empty?
25
25
  end
26
26
 
27
+ def due
28
+ date = Chronic.parse(text.scan(DATE_REGEX).flatten[2])
29
+ date.nil? ? nil : date.to_date
30
+ end
31
+
27
32
  def do
28
33
  unless done
29
34
  @text = "x #{text}".strip
@@ -0,0 +1,40 @@
1
+ module Todotxt
2
+ class TodoFile
3
+
4
+ def initialize path
5
+ @path = File.expand_path(path)
6
+ end
7
+
8
+ # Generate a file from template
9
+ def generate!
10
+ FileUtils.copy File.join(File.dirname(File.expand_path(__FILE__)), "..", "..", "conf", "todo.txt"), @path
11
+ end
12
+
13
+ def path
14
+ @path
15
+ end
16
+
17
+ def basename
18
+ File.basename @path
19
+ end
20
+
21
+ def exists?
22
+ File.exists? File.expand_path(@path)
23
+ end
24
+
25
+ def self.from_key(key)
26
+ config = Todotxt::Config.new
27
+ if config.files.has_key? key
28
+ path = config.files[key]
29
+ self.new path
30
+ else
31
+ raise "Key not found in config"
32
+ end
33
+ end
34
+
35
+
36
+ def to_s
37
+ @path
38
+ end
39
+ end
40
+ end