todotxt 0.0.1

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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in todotxt.gemspec
4
+ gemspec
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Johan Sahlén, http://jsahlen.se/
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.md ADDED
@@ -0,0 +1,65 @@
1
+ # Todotxt.rb
2
+
3
+ *todo.txt with a ruby flair*
4
+
5
+
6
+ ## About
7
+
8
+ Todotxt is a ruby CLI interface to work with a
9
+ [todo.txt](http://www.todotxt.com) file
10
+
11
+
12
+ ## Install
13
+
14
+ Clone from [jsahlen/todotxt](http://github.com/jsahlen/todotxt) and do
15
+
16
+ rake install
17
+
18
+ I might release it as a proper gem in the future…
19
+
20
+ Todotxt relies on a configuration file (`.todotxt.cfg`) in your home directory,
21
+ which points to the location of your todo.txt. You can run
22
+
23
+ todotxt generate_cfg
24
+
25
+ to generate this file, which will then point to `~/todo.txt`.
26
+
27
+
28
+ ## Usage
29
+
30
+ The gem will install a command, `todotxt` which is used to interact with your
31
+ todo.txt.
32
+
33
+ Tasks:
34
+ todotxt add | a TEXT # Add a new Todo item
35
+ todotxt append | app ITEM# STRING # Append STRING to ITEM#
36
+ todotxt del | rm ITEM#[, ITEM#, ITEM#, ...] # Remove ITEM#
37
+ todotxt do ITEM#[, ITEM#, ITEM#, ...] # Mark ITEM# as done
38
+ todotxt dp | depri ITEM#[, ITEM#, ITEM#, ...] # Remove priority for ITEM#
39
+ todotxt generate_cfg # Create a sample todo.txt
40
+ todotxt generate_config # Create a .todotxt.cfg file in your home folder, containing the path to todo.txt
41
+ todotxt help [TASK] # Describe available tasks or one specific task
42
+ todotxt list | ls [SEARCH] # List all todos, or todos matching SEARCH
43
+ todotxt listproj | lsproj # List all projects
44
+ todotxt lscon | lsc # List all contexts
45
+ todotxt lsdone | lsd # List all done items
46
+ todotxt prepend | prep ITEM# STRING # Prepend STRING to ITEM#
47
+ todotxt pri | p ITEM# PRIORITY # Set priority of ITEM# to PRIORITY
48
+ todotxt replace ITEM# TEXT # Completely replace ITEM# text with TEXT
49
+ todotxt undo | u ITEM#[, ITEM#, ITEM#, ...] # Mark ITEM# item as not done
50
+ todotxt version # Show todotxt version
51
+
52
+ Calling simply `todotxt` will automatically run the `ls` command.
53
+
54
+
55
+ ## Dependencies
56
+
57
+ * [Thor](http://github.com/wycats/thor)
58
+ * [Rainbow](http://github.com/sickill/rainbow)
59
+ * [ParseConfig](http://www.5dollarwhitebox.org/drupal/?q=node/21)
60
+
61
+
62
+ ## Bugs
63
+
64
+ Please report any bugs using the
65
+ [GitHub Issue Tracker](http://github.com/jsahlen/todotxt/issues).
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/bin/todotxt ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ libdir = File.join(File.dirname(File.dirname(__FILE__)), "lib")
4
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
5
+
6
+ args = ARGV.clone
7
+
8
+ if args.empty?
9
+ args.push "ls"
10
+ end
11
+
12
+ require "todotxt"
13
+ Todotxt::CLI.start(args)
data/conf/todo.txt ADDED
@@ -0,0 +1 @@
1
+ Learn todo.txt +myproject @home
data/conf/todotxt.cfg ADDED
@@ -0,0 +1 @@
1
+ todo_txt_path = ~/todo.txt
@@ -0,0 +1,3 @@
1
+ an item +project1 +project2 @context2
2
+ an item +project1 @context1
3
+ (A) an item
@@ -0,0 +1,4 @@
1
+ First item
2
+ Second item
3
+ Third item
4
+ x First done item
@@ -0,0 +1,289 @@
1
+ require "thor"
2
+ require "rainbow"
3
+ require "parseconfig"
4
+
5
+ module Todotxt
6
+ CFG_PATH = File.expand_path("~/.todotxt.cfg")
7
+
8
+ class CLI < Thor
9
+ include Thor::Actions
10
+ include Todotxt::CLIHelpers
11
+
12
+ def self.source_root
13
+ File.join File.dirname(__FILE__), "..", "..", "conf"
14
+ end
15
+
16
+ def initialize(*args)
17
+ super
18
+
19
+ unless ["help", "generate_config"].include? ARGV[0]
20
+ parse_config
21
+
22
+ @list = TodoList.new @txt_path
23
+ end
24
+ end
25
+
26
+ #
27
+ # Listing
28
+ #
29
+
30
+ desc "list | ls [SEARCH]", "List all todos, or todos matching SEARCH"
31
+ method_option :done, :type => :boolean, :aliases => "-d", :desc => "Include todo items that have been marked as done"
32
+ method_option :simple, :type => :boolean, :desc => "Simple output (for scripts, etc)"
33
+ 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
+
40
+ render_list :simple => !!options[:simple]
41
+ end
42
+ map "ls" => :list
43
+
44
+ desc "lsdone | lsd", "List all done items"
45
+ def lsdone search=""
46
+ @list.filter(search, :only_done => true)
47
+
48
+ render_list
49
+ end
50
+ map "lsd" => :lsdone
51
+
52
+ desc "listproj | lsproj", "List all projects"
53
+ def listproj
54
+ @list.projects.each { |p| say p }
55
+ end
56
+ map "lsproj" => :listproj
57
+
58
+ desc "lscon | lsc", "List all contexts"
59
+ def lscon
60
+ @list.contexts.each { |c| say c }
61
+ end
62
+ map "lsc" => :lscon
63
+
64
+ #
65
+ # Todo management
66
+ #
67
+
68
+ desc "add | a TEXT", "Add a new Todo item"
69
+ def add(str, *str2)
70
+ string = "#{str} #{str2.join(' ')}"
71
+ todo = @list.add string
72
+
73
+ puts format_todo(todo)
74
+
75
+ @list.save
76
+ end
77
+ map "a" => :add
78
+
79
+ desc "do ITEM#[, ITEM#, ITEM#, ...]", "Mark ITEM# as done"
80
+ def do line1, *lines
81
+ lines.unshift(line1).each do |line|
82
+ todo = @list.find_by_line line
83
+ if todo
84
+ todo.do
85
+ puts format_todo(todo)
86
+
87
+ @list.save
88
+ else
89
+ error "No todo found at line #{line}"
90
+ end
91
+ end
92
+ end
93
+
94
+ desc "undo | u ITEM#[, ITEM#, ITEM#, ...]", "Mark ITEM# item as not done"
95
+ def undo line1, *lines
96
+ lines.unshift(line1).each do |line|
97
+ todo = @list.find_by_line line
98
+ if todo
99
+ todo.undo
100
+ puts format_todo(todo)
101
+
102
+ @list.save
103
+ else
104
+ error "No todo found at line #{line}"
105
+ end
106
+ end
107
+ end
108
+ map "u" => :undo
109
+
110
+ desc "pri | p ITEM# PRIORITY", "Set priority of ITEM# to PRIORITY"
111
+ def pri line, priority
112
+ todo = @list.find_by_line line
113
+ if todo
114
+ todo.prioritize priority
115
+ puts format_todo(todo)
116
+
117
+ @list.save
118
+ else
119
+ error "No todo found at line #{line}"
120
+ end
121
+ end
122
+ map "p" => :pri
123
+
124
+ desc "dp | depri ITEM#[, ITEM#, ITEM#, ...]", "Remove priority for ITEM#"
125
+ def dp line1, *lines
126
+ lines.unshift(line1).each do |line|
127
+ todo = @list.find_by_line line
128
+ if todo
129
+ todo.prioritize
130
+ puts format_todo(todo)
131
+
132
+ @list.save
133
+ else
134
+ error "No todo found at line #{line}"
135
+ end
136
+ end
137
+ end
138
+ map "depri" => :dp
139
+
140
+ desc "append | app ITEM# STRING", "Append STRING to ITEM#"
141
+ def append line, str, *str2
142
+ string = "#{str} #{str2.join(' ')}"
143
+ todo = @list.find_by_line line
144
+ if todo
145
+ todo.append string
146
+ puts format_todo(todo)
147
+
148
+ @list.save
149
+ else
150
+ error "No todo found at line #{line}"
151
+ end
152
+ end
153
+ map "app" => :append
154
+
155
+ desc "prepend | prep ITEM# STRING", "Prepend STRING to ITEM#"
156
+ def prepend line, str, *str2
157
+ string = "#{str} #{str2.join(' ')}"
158
+ todo = @list.find_by_line line
159
+ if todo
160
+ todo.prepend string
161
+ puts format_todo(todo)
162
+
163
+ @list.save
164
+ else
165
+ error "No todo found at line #{line}"
166
+ end
167
+ end
168
+ map "prep" => :prepend
169
+
170
+ desc "replace ITEM# TEXT", "Completely replace ITEM# text with TEXT"
171
+ def replace line, str, *str2
172
+ string = "#{str} #{str2.join(' ')}"
173
+ todo = @list.find_by_line line
174
+ if todo
175
+ todo.replace string
176
+ puts format_todo(todo)
177
+
178
+ @list.save
179
+ else
180
+ error "No todo found at line #{line}"
181
+ end
182
+ end
183
+
184
+ desc "del | rm ITEM#[, ITEM#, ITEM#, ...]", "Remove ITEM#"
185
+ method_option :force, :type => :boolean, :aliases => "-f", :desc => "Don't confirm removal"
186
+ def del line1, *lines
187
+ lines.unshift(line1).each do |line|
188
+ todo = @list.find_by_line line
189
+ if todo
190
+ say format_todo(todo)
191
+ if options[:force] || yes?("Remove this item? [y/N]")
192
+ @list.remove line
193
+ notice "Removed from list"
194
+
195
+ @list.save
196
+ end
197
+ else
198
+ error "No todo found at line #{line}"
199
+ end
200
+ end
201
+ end
202
+ map "rm" => :del
203
+
204
+ #
205
+ # File generation
206
+ #
207
+
208
+ desc "generate_config", "Create a .todotxt.cfg file in your home folder, containing the path to todo.txt"
209
+ def generate_config
210
+ copy_file "todotxt.cfg", CFG_PATH
211
+ puts ""
212
+
213
+ parse_config
214
+ end
215
+
216
+ desc "generate_cfg", "Create a sample todo.txt"
217
+ def generate_txt
218
+ copy_file "todo.txt", @txt_path
219
+ puts ""
220
+ end
221
+
222
+ #
223
+ # Extras
224
+ #
225
+
226
+ desc "version", "Show todotxt version"
227
+ def version
228
+ say "todotxt #{VERSION}"
229
+ end
230
+
231
+ private
232
+
233
+ def render_list opts={}
234
+ numsize = @list.count + 1
235
+ numsize = numsize.to_s.length + 0
236
+
237
+ @list.each do |t|
238
+ if opts[:simple]
239
+ say "#{t.line} #{t.to_s}"
240
+ else
241
+ say format_todo(t, numsize)
242
+ end
243
+ end
244
+
245
+ unless opts[:simple]
246
+ puts "TODO: #{@list.count} items".color(:black).bright
247
+ end
248
+ end
249
+
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]"
254
+
255
+ if confirm_generate
256
+ generate_config
257
+ else
258
+ puts ""
259
+ exit
260
+ end
261
+ end
262
+
263
+ cfg = ParseConfig.new(CFG_PATH)
264
+
265
+ txt = cfg.get_value "todo_txt_path"
266
+
267
+ if txt
268
+ @txt_path = File.expand_path(txt)
269
+
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]"
273
+
274
+ if confirm_generate
275
+ generate_txt
276
+ else
277
+ puts ""
278
+ exit
279
+ end
280
+ end
281
+ 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
286
+ end
287
+ end
288
+ end
289
+ end
@@ -0,0 +1,54 @@
1
+ module Todotxt
2
+ module CLIHelpers
3
+
4
+ def format_todo(todo, number_padding=nil)
5
+ line = todo.line.to_s
6
+
7
+ if number_padding
8
+ line = line.rjust number_padding
9
+ end
10
+
11
+ text = todo.to_s
12
+
13
+ unless todo.done
14
+ text.gsub! PRIORITY_REGEX do |p|
15
+ case p[1]
16
+ when "A"
17
+ color = :red
18
+ when "B"
19
+ color = :yellow
20
+ when "C"
21
+ color = :green
22
+ else
23
+ color = :white
24
+ end
25
+
26
+ p.to_s.color(color)
27
+ end
28
+
29
+ text.gsub! PROJECT_REGEX, '\1'.color(:green)
30
+ text.gsub! CONTEXT_REGEX, '\1'.color(:blue)
31
+ else
32
+ text = text.color(:black).bright
33
+ end
34
+
35
+ ret = ""
36
+
37
+ ret << "#{line}. ".color(:black).bright
38
+ ret << "#{text}"
39
+ end
40
+
41
+ def warn message=""
42
+ puts "WARN: #{message}".color(:yellow)
43
+ end
44
+
45
+ def notice message=""
46
+ puts "=> #{message}".color(:green)
47
+ end
48
+
49
+ def error message=""
50
+ puts "ERROR: #{message}".color(:red)
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,6 @@
1
+ module Todotxt
2
+ PRIORITY_REGEX = /^\(([A-Z])\) /
3
+ PROJECT_REGEX = /(\+\w+)/
4
+ CONTEXT_REGEX = /(@\w+)/
5
+ DONE_REGEX = /^(\([A-Z]\) )?x /
6
+ end
@@ -0,0 +1,90 @@
1
+ require "todotxt/regex"
2
+
3
+ module Todotxt
4
+ class Todo
5
+
6
+ attr_accessor :text
7
+ attr_accessor :line
8
+ attr_accessor :priority
9
+ attr_accessor :projects
10
+ attr_accessor :contexts
11
+ attr_accessor :done
12
+
13
+ def initialize text, line=nil
14
+ @line = line
15
+
16
+ create_from_text text
17
+ end
18
+
19
+ def create_from_text text
20
+ @text = text
21
+ @priority = text.scan(PRIORITY_REGEX).flatten.first || nil
22
+ @projects = text.scan(PROJECT_REGEX).flatten.uniq || []
23
+ @contexts = text.scan(CONTEXT_REGEX).flatten.uniq || []
24
+ @done = !text.scan(DONE_REGEX).empty?
25
+ end
26
+
27
+ def do
28
+ unless done
29
+ @text = "x #{text}".strip
30
+ @done = true
31
+ end
32
+ end
33
+
34
+ def undo
35
+ if done
36
+ @text = text.sub(DONE_REGEX, "").strip
37
+ @done = false
38
+ end
39
+ end
40
+
41
+ def prioritize new_priority=nil, opts={}
42
+ if new_priority && !new_priority.match(/^[A-Z]$/i)
43
+ return
44
+ end
45
+
46
+ if new_priority
47
+ new_priority = new_priority.upcase
48
+ end
49
+
50
+ priority_string = new_priority ? "(#{new_priority}) " : ""
51
+
52
+ if priority && !opts[:force]
53
+ @text.gsub! PRIORITY_REGEX, priority_string
54
+ else
55
+ @text = "#{priority_string}#{text}".strip
56
+ end
57
+
58
+ @priority = new_priority
59
+ end
60
+
61
+ def append appended_text=""
62
+ @text << " " << appended_text
63
+ end
64
+
65
+ def prepend prepended_text=""
66
+ @text = "#{prepended_text} #{text.gsub(PRIORITY_REGEX, '')}"
67
+ prioritize priority, :force => true
68
+ end
69
+
70
+ def replace text
71
+ create_from_text text
72
+ end
73
+
74
+ def to_s
75
+ text.clone
76
+ end
77
+
78
+ def <=> b
79
+ if priority.nil? && b.priority.nil?
80
+ return line <=> b.line
81
+ end
82
+
83
+ return 1 if priority.nil?
84
+ return -1 if b.priority.nil?
85
+
86
+ return priority <=> b.priority
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,83 @@
1
+ require "todotxt/todo"
2
+
3
+ module Todotxt
4
+ class TodoList
5
+ include Enumerable
6
+
7
+ attr_accessor :todos
8
+
9
+ def initialize file
10
+ @todos = []
11
+ @file = file
12
+
13
+ File.open(file).read.each_line do |l|
14
+ add l.strip unless l.empty?
15
+ end
16
+ end
17
+
18
+ def add str
19
+ todo = Todo.new str, (@todos.count + 1)
20
+ @todos.push todo
21
+ @todos.sort!
22
+
23
+ return todo
24
+ end
25
+
26
+ def remove line
27
+ @todos.reject! { |t| t.line.to_s == line.to_s }
28
+ end
29
+
30
+ def projects
31
+ map { |t| t.projects }.flatten.uniq.sort
32
+ end
33
+
34
+ def contexts
35
+ map { |t| t.contexts }.flatten.uniq.sort
36
+ end
37
+
38
+ def find_by_line line
39
+ @todos.find { |t| t.line.to_s == line.to_s }
40
+ end
41
+
42
+ def save
43
+ File.open(@file, "w") { |f| f.write to_txt }
44
+ end
45
+
46
+ def each &block
47
+ @todos.each &block
48
+ end
49
+
50
+ def filter search="", opts={}
51
+ @todos.select! do |t|
52
+ select = false
53
+
54
+ text = t.to_s.downcase
55
+
56
+ if opts[:only_done]
57
+ select = true if t.done
58
+ else
59
+ if opts[:with_done]
60
+ select = true
61
+ else
62
+ select = true unless t.done
63
+ end
64
+ end
65
+
66
+ select = false unless text.include?(search.downcase)
67
+
68
+ select
69
+ end
70
+
71
+ self
72
+ end
73
+
74
+ def to_txt
75
+ @todos.sort { |a,b| a.line <=> b.line }.map { |t| t.to_s.strip }.join("\n")
76
+ end
77
+
78
+ def to_a
79
+ map { |t| ["#{t.line}. ", t.to_s] }
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,3 @@
1
+ module Todotxt
2
+ VERSION = "0.0.1"
3
+ end
data/lib/todotxt.rb ADDED
@@ -0,0 +1,13 @@
1
+ # Setup our load paths
2
+ libdir = File.dirname(__FILE__)
3
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
4
+
5
+ module Todotxt
6
+ autoload :Todo, "todotxt/todo"
7
+ autoload :TodoList, "todotxt/todolist"
8
+ autoload :CLI, "todotxt/cli"
9
+ autoload :CLIHelpers, "todotxt/clihelpers"
10
+ end
11
+
12
+ require "todotxt/regex"
13
+ require "todotxt/version"
data/spec/todo_spec.rb ADDED
@@ -0,0 +1,129 @@
1
+ require "todotxt/todo"
2
+
3
+ describe Todotxt::Todo do
4
+
5
+ it "should create a todo item string" do
6
+ todo = Todotxt::Todo.new "an item"
7
+ todo.to_s.should eql("an item")
8
+ end
9
+
10
+ it "should parse metadata when creating a simple item" do
11
+ todo = Todotxt::Todo.new "x an item +project1 +project2 @context1 @context2"
12
+
13
+ todo.to_s.should eql "x an item +project1 +project2 @context1 @context2"
14
+ todo.priority.should eql nil
15
+ todo.projects.should eql ["+project1", "+project2"]
16
+ todo.contexts.should eql ["@context1", "@context2"]
17
+ todo.done.should eql true
18
+ end
19
+
20
+ it "should parse metadata when creating an item with priority" do
21
+ todo = Todotxt::Todo.new "(A) x an item +project1 +project2 @context1 @context2"
22
+
23
+ todo.to_s.should eql "(A) x an item +project1 +project2 @context1 @context2"
24
+ todo.priority.should eql "A"
25
+ todo.projects.should eql ["+project1", "+project2"]
26
+ todo.contexts.should eql ["@context1", "@context2"]
27
+ todo.done.should eql true
28
+ end
29
+
30
+ it "should store line number when creating an item" do
31
+ todo = Todotxt::Todo.new "an item", "2"
32
+
33
+ todo.line.should eql "2"
34
+ end
35
+
36
+ it "should set an item as done" do
37
+ todo = Todotxt::Todo.new "an item"
38
+
39
+ todo.do
40
+
41
+ todo.to_s.should eql "x an item"
42
+ todo.done.should eql true
43
+ end
44
+
45
+ it "should set an item as not done" do
46
+ todo = Todotxt::Todo.new "x an item"
47
+
48
+ todo.undo
49
+
50
+ todo.to_s.should eql "an item"
51
+ todo.done.should eql false
52
+ end
53
+
54
+ it "should add priority to an item" do
55
+ todo = Todotxt::Todo.new "an item"
56
+
57
+ todo.prioritize "a"
58
+
59
+ todo.to_s.should eql "(A) an item"
60
+ todo.priority.should eql "A"
61
+ end
62
+
63
+ it "should change priority of an item" do
64
+ todo = Todotxt::Todo.new "(A) an item"
65
+
66
+ todo.prioritize "z"
67
+
68
+ todo.to_s.should eql "(Z) an item"
69
+ todo.priority.should eql "Z"
70
+ end
71
+
72
+ it "should remove priority from an item" do
73
+ todo = Todotxt::Todo.new "(A) an item"
74
+
75
+ todo.prioritize
76
+
77
+ todo.to_s.should eql "an item"
78
+ todo.priority.should eql nil
79
+ end
80
+
81
+ it "should append text to an item" do
82
+ todo = Todotxt::Todo.new "an item"
83
+
84
+ todo.append "more text"
85
+
86
+ todo.to_s.should eql "an item more text"
87
+ end
88
+
89
+ it "should prepend text to an item" do
90
+ todo = Todotxt::Todo.new "an item"
91
+
92
+ todo.prepend "more text"
93
+
94
+ todo.to_s.should eql "more text an item"
95
+ end
96
+
97
+ it "should preserve priority when prepending text to an item" do
98
+ todo = Todotxt::Todo.new "(A) an item"
99
+
100
+ todo.prepend "more text"
101
+
102
+ todo.to_s.should eql "(A) more text an item"
103
+ todo.priority.should eql "A"
104
+ end
105
+
106
+ it "should replace an item with new text" do
107
+ todo = Todotxt::Todo.new "an item"
108
+
109
+ todo.replace "(A) a replacement item"
110
+
111
+ todo.to_s.should eql "(A) a replacement item"
112
+ todo.priority.should eql "A"
113
+ end
114
+
115
+ it "should sort based on line number" do
116
+ todo1 = Todotxt::Todo.new "an item 1", 1
117
+ todo2 = Todotxt::Todo.new "an item 2", 2
118
+
119
+ (todo1 <=> todo2).should eql -1
120
+ end
121
+
122
+ it "should value items with priority higher when sorting" do
123
+ todo1 = Todotxt::Todo.new "an item 1", 1
124
+ todo2 = Todotxt::Todo.new "(A) an item 2", 2
125
+
126
+ (todo1 <=> todo2).should eql 1
127
+ end
128
+
129
+ end
@@ -0,0 +1,99 @@
1
+ require "todotxt/todolist"
2
+
3
+ describe Todotxt::TodoList do
4
+
5
+ describe "with simple list" do
6
+ before :each do
7
+ @list = Todotxt::TodoList.new File.join(File.dirname(__FILE__), "..", "fixtures", "simple_todo.txt")
8
+ end
9
+
10
+ it "should parse a file on creation" do
11
+ @list.todos[0].to_s.should eql "First item"
12
+ @list.todos[1].to_s.should eql "Second item"
13
+ @list.todos[2].to_s.should eql "Third item"
14
+ @list.todos[3].to_s.should eql "x First done item"
15
+
16
+ @list.todos[0].line.should eql 1
17
+ @list.todos[1].line.should eql 2
18
+ @list.todos[2].line.should eql 3
19
+ @list.todos[3].line.should eql 4
20
+ end
21
+
22
+ it "should add a new item" do
23
+ @list.add "Fourth item"
24
+
25
+ @list.todos[4].to_s.should eql "Fourth item"
26
+ @list.todos[4].line.should eql 5
27
+ end
28
+
29
+ it "should remove an item" do
30
+ @list.remove 1
31
+
32
+ @list.todos[0].to_s.should eql "Second item"
33
+ end
34
+
35
+ it "should find item by line" do
36
+ todo = @list.find_by_line 3
37
+
38
+ todo.to_s.should eql "Third item"
39
+ end
40
+
41
+ it "should filter list when searching" do
42
+ @list.filter "First"
43
+
44
+ @list.todos.count.should eql 1
45
+ end
46
+
47
+ it "should filter list when searching case-sensitive" do
48
+ @list.filter "first"
49
+
50
+ @list.todos.count.should eql 1
51
+ end
52
+
53
+ it "should include done items in search when told to do so" do
54
+ @list.filter "first", :with_done => true
55
+
56
+ @list.todos.count.should eql 2
57
+ end
58
+
59
+ it "should only include done items in search when told to do so" do
60
+ @list.filter "first", :only_done => true
61
+
62
+ @list.todos.count.should eql 1
63
+ end
64
+
65
+ it "should render plain text" do
66
+ comparison_string = <<EOF
67
+ First item
68
+ Second item
69
+ Third item
70
+ x First done item
71
+ EOF
72
+ @list.to_txt.should eql comparison_string.strip
73
+ end
74
+ end
75
+
76
+ describe "with complex list" do
77
+ before :each do
78
+ @list = Todotxt::TodoList.new File.join(File.dirname(__FILE__), "..", "fixtures", "complex_todo.txt")
79
+ end
80
+
81
+ it "should sort itself automatically on parse" do
82
+ @list.todos[0].to_s.should eql "(A) an item"
83
+ @list.todos[0].line.should eql 3
84
+ end
85
+
86
+ it "should re-sort itself after adding a new item" do
87
+ @list.add "(B) A new item"
88
+
89
+ @list.todos[1].to_s.should eql "(B) A new item"
90
+ @list.todos[1].line.should eql 4
91
+ end
92
+
93
+ it "should list all projects and contexts in the list" do
94
+ @list.projects.should eql ["+project1", "+project2"]
95
+ @list.contexts.should eql ["@context1", "@context2"]
96
+ end
97
+ end
98
+
99
+ end
data/todotxt.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "todotxt/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "todotxt"
7
+ s.version = Todotxt::VERSION
8
+ s.authors = ["Johan Sahlén"]
9
+ s.email = ["johan@monospace.se"]
10
+ s.homepage = "http://github.com/jsahlen/todotxt"
11
+ s.summary = %q{todo.txt with a Ruby flair}
12
+ s.description = %q{Interact with your todo.txt using a Ruby-base command-line tool}
13
+
14
+ s.rubyforge_project = "todotxt"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "thor", ">= 0.14.6"
22
+ s.add_dependency "rainbow", ">= 1.1.1"
23
+ s.add_dependency "parseconfig", ">= 0.5.2"
24
+
25
+ s.add_development_dependency "rspec", ">= 2.6.0"
26
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: todotxt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Johan Sahlén
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-09 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &2164860840 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.14.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2164860840
25
+ - !ruby/object:Gem::Dependency
26
+ name: rainbow
27
+ requirement: &2164860340 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.1
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2164860340
36
+ - !ruby/object:Gem::Dependency
37
+ name: parseconfig
38
+ requirement: &2164859880 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 0.5.2
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *2164859880
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &2164859420 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.6.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2164859420
58
+ description: Interact with your todo.txt using a Ruby-base command-line tool
59
+ email:
60
+ - johan@monospace.se
61
+ executables:
62
+ - todotxt
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - .gitignore
67
+ - Gemfile
68
+ - MIT-LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - bin/todotxt
72
+ - conf/todo.txt
73
+ - conf/todotxt.cfg
74
+ - fixtures/complex_todo.txt
75
+ - fixtures/simple_todo.txt
76
+ - lib/todotxt.rb
77
+ - lib/todotxt/cli.rb
78
+ - lib/todotxt/clihelpers.rb
79
+ - lib/todotxt/regex.rb
80
+ - lib/todotxt/todo.rb
81
+ - lib/todotxt/todolist.rb
82
+ - lib/todotxt/version.rb
83
+ - spec/todo_spec.rb
84
+ - spec/todolist_spec.rb
85
+ - todotxt.gemspec
86
+ homepage: http://github.com/jsahlen/todotxt
87
+ licenses: []
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project: todotxt
106
+ rubygems_version: 1.8.6
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: todo.txt with a Ruby flair
110
+ test_files:
111
+ - spec/todo_spec.rb
112
+ - spec/todolist_spec.rb