Skip to content

Instantly share code, notes, and snippets.

@nixterrimus
Created October 3, 2011 01:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nixterrimus/1258255 to your computer and use it in GitHub Desktop.
Save nixterrimus/1258255 to your computer and use it in GitHub Desktop.
Todo.rb

todo.rb

todo.rb is a dead simple command line todo list manager written in Ruby by Nick Rowe. It was originally written for Codebrawl. It's now a slightly more filled out gem (with tests!). The todo.rb gem is on Github.

Making it Go - A Simple Tutorial

todo.rb is simple, first lets add some items to our list

./todo.rb buy tomato seeds
./todo.rb buy a new green hose
./todo.rb buy potting soil
./todo.rb plant tomatoes

Next, lets have a look at the list

todo.rb

produce this output

[  1] buy tomato seeds
[  2] buy a new green hose
[  3] buy potting soil
[  4] plant tomatoes

Now, we've gone to the store and bought ourselves a nice new green garden hose. Time to check that one off:

./todo.rb done 2

If we check the list, ./todo.rb, we see:

[  1] buy tomato seeds
[  2] buy potting soil
[  3] plant tomatoes

That's it, that's the easiest way to manage your list with todo.rb

Managing Multiple lists

Managing multiple lists is simple, too. To manage a list specify the location with -f flag:

./todo.rb -f work.txt Click the keys on the keyboard
./todo.rb -f dog.txt buy a new squeaky toy

Why does this Rock?

It's easy- it's easy to use and it's easy to modify. It's also portable. You can pickup your todo file and move it at any time. Want to add todo's when you're away from the command line? That's no big deal- keep the file in dropbox and you can edit it on your phone, tablet, or anywhere else you can edit a text file.

On the code front- it's well organized Ruby with rdoc style comments.

Some Notes on a todo.txt Workflow

Personally, I use a todo.txt file on my desktop. I like that it's lightweight. On a mac you can use Quicklook to get a quick view of what's inside a file. To do this, click on the todo.txt file and then hit the space bar.

I've also created an Alfred action for appending to the todo.txt file. This action can be added by downloading the file and dragging it into extension pane. From there you can use todo followed by the task. For example todo clean the fish tank.

Who took that Dog Photo?

The dog picture was taken by Randy Son Of Robert on Flickr and is used under a creative commons 2.0 CC by attribution license.

Shut up and take my money - The license

You're money is no good here, cowboy. All code, documentation, and the alfred extension are distributed under an MIT license. Please fork it, hack it, fix it, share it, break it, now upgrade it. As they say, technologic.


Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#!/usr/bin/env ruby
# License:: Distributed under MIT license
require 'optparse'
# TodoItem represents a todo item it is primarily used as a structured container
# for todo information
class TodoItem
attr_accessor :description, :line_number
def initialize(todo, options = {})
@description = todo
@line_number = options[:line_number]
end
# Represents the todo item as a string with the line number taking up 3 spaces
# and the description immediately following it
def to_s
"[#{"% 3d" % (line_number)}] #{description}"
end
end
# TodoList is a container class for many TodoItems it includes methods for
# adding todos, removing todos, and getting todos at a given index. It also
# interacts with the filesystem to read and save the file
class TodoList
attr_accessor :todo_list, :file_location
# Reads todos from a file if the file exists and sets up variables for the
# class
def initialize(file_location)
@file_location = file_location
@todo_list = []
if File.exist? file_location
File.open(@file_location).each_with_index do |line, line_number|
@todo_list << TodoItem.new(line.chomp, {:line_number => line_number + 1})
end
end
end
# Appends a new todo to the list by getting next line number and then appending
# the todo to the @todo_list
def append(todo)
todo.line_number = next_line_number()
@todo_list << todo
save_list()
end
# Removes a todo from the list
def remove(todo)
@todo_list.delete_at(todo.line_number - 1)
update_todo_line_numbers()
save_list()
end
# Gets a todo at an index if that index is a number. If the index isn't a number
# then nil is returned. If there is no todo at an index nil is returned.
def todo_at_index(index)
begin
index = Integer(index)
index-=1
@todo_list[index]
rescue
return nil
end
end
# Represents the todo list as a String with each todo on its on line and the def the
# newest todo at the bottom of the list
def to_s
return "" if @todo_list.empty?
return @todo_list.first.to_s if @todo_list.size == 1
@todo_list.reduce { |todo, string| "#{todo.to_s}\n#{string}" }
end
private
def next_line_number
return 0 if @todo_list.empty?
@todo_list.last.line_number + 1
end
def update_todo_line_numbers
@todo_list.each_with_index{ |todo, index| todo.line_number = index}
end
def save_list
File.open(@file_location, "wb") do |file|
@todo_list.each { |todo| file.write(todo.description + "\n")}
end
end
end
options = {:file => "todo.txt"}
OptionParser.new do |opts|
opts.on("-f", "--file F", String, "Use a custom todo file") do |f|
options[:file] = f
end
end.parse!
todo_list = TodoList.new(options[:file])
if ARGV.count == 0
puts todo_list
else
if ARGV[0].downcase == "done"
todo = todo_list.todo_at_index(ARGV[1])
if todo.nil?
puts "Couldn't find todo at location #{ARGV[1]}"
else
todo_list.remove(todo)
end
else
todo = TodoItem.new(ARGV.join(" "))
todo_list.append(todo)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment