toga 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/Gemfile +4 -0
- data/README.md +80 -0
- data/Rakefile +1 -0
- data/Togafile +30 -0
- data/USAGE +26 -0
- data/bin/toga +4 -0
- data/lib/toga/cli.rb +43 -0
- data/lib/toga/command.rb +10 -0
- data/lib/toga/commands/add.rb +11 -0
- data/lib/toga/commands/commit.rb +79 -0
- data/lib/toga/commands/complete.rb +11 -0
- data/lib/toga/commands/current.rb +23 -0
- data/lib/toga/commands/init.rb +25 -0
- data/lib/toga/commands/later.rb +14 -0
- data/lib/toga/commands/list.rb +18 -0
- data/lib/toga/commands/now.rb +8 -0
- data/lib/toga/commands/remove.rb +12 -0
- data/lib/toga/commands/rm.rb +6 -0
- data/lib/toga/commands/top.rb +20 -0
- data/lib/toga/commands/uncomplete.rb +11 -0
- data/lib/toga/error.rb +20 -0
- data/lib/toga/extensions.rb +62 -0
- data/lib/toga/scaffold/Togafile +12 -0
- data/lib/toga/tasks.rb +9 -0
- data/lib/toga/togafile.rb +156 -0
- data/lib/toga/version.rb +3 -0
- data/lib/toga.rb +15 -0
- data/spec/toga_spec.rb +83 -0
- data/toga.gemspec +28 -0
- metadata +122 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# toga
|
2
|
+
|
3
|
+
#### a todo-list for git
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Toga is a rubygem.
|
8
|
+
|
9
|
+
gem install toga
|
10
|
+
|
11
|
+
----
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
$ mate Togafile
|
16
|
+
|
17
|
+
|
18
|
+
A sample Togafile looks like:
|
19
|
+
|
20
|
+
CURRENT
|
21
|
+
|
22
|
+
Finish serialization methods
|
23
|
+
Write better regexes
|
24
|
+
Resolve issue #205
|
25
|
+
|
26
|
+
|
27
|
+
LATER
|
28
|
+
|
29
|
+
Use cloud database for production instead of local redis server
|
30
|
+
|
31
|
+
This is simply your todo list. `CURRENT` marks things you are working on right now; `LATER` marks things you want to finish in the near future; and `COMPLETED` obviously marks done tasks.
|
32
|
+
|
33
|
+
Let's say we want to finish the first task on the list:
|
34
|
+
|
35
|
+
$ toga complete Finish seria
|
36
|
+
|
37
|
+
(You don't need to type the whole line, just the first part.)
|
38
|
+
|
39
|
+
This will stage a git commit with your commit already set to your todo's text; you can then add more to your commit message, of course!
|
40
|
+
|
41
|
+
Now, check your `Togafile`:
|
42
|
+
|
43
|
+
$ toga list
|
44
|
+
|
45
|
+
CURRENT
|
46
|
+
|
47
|
+
Write better regexes
|
48
|
+
Resolve issue #205
|
49
|
+
[x] Finish serialization methods # => completed at 2:06pm today
|
50
|
+
|
51
|
+
LATER
|
52
|
+
|
53
|
+
Use cloud database for production instead of local redis server
|
54
|
+
|
55
|
+
By default, completed tasks are left in the current list so that you can feel awesome about them. If you want, you can clean the `current` Todos:
|
56
|
+
|
57
|
+
$ toga clean
|
58
|
+
|
59
|
+
We can use toga to push commits, too, if you want:
|
60
|
+
|
61
|
+
$ toga push
|
62
|
+
|
63
|
+
This will move done tasks to the `completed` group:
|
64
|
+
|
65
|
+
CURRENT
|
66
|
+
|
67
|
+
Write better regexes
|
68
|
+
Resolve issue #205
|
69
|
+
|
70
|
+
LATER
|
71
|
+
|
72
|
+
Use cloud database for production instead of local redis server
|
73
|
+
|
74
|
+
COMPLETED
|
75
|
+
[x] Finish serialization methods # => completed at 2:06pm today, http://github.com/colinyoung/toga/commits/abc939499cb…
|
76
|
+
|
77
|
+
It also provides a link to the git project and the commit ref so that you can see how you completed your task.
|
78
|
+
|
79
|
+
VOILA!
|
80
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/Togafile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
CURRENT
|
2
|
+
|
3
|
+
Regularly clean up whitespace in Togafile
|
4
|
+
Synchronize how docs refer to "complete" with the codebase
|
5
|
+
|
6
|
+
Add later command and current command.
|
7
|
+
LATER
|
8
|
+
|
9
|
+
|
10
|
+
Append timestamps on complete
|
11
|
+
Append commit logs on push
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
Add later
|
16
|
+
|
17
|
+
MAYBE
|
18
|
+
|
19
|
+
Import previous git commit messages and put into completed group, so that toga is already sexy
|
20
|
+
Scan for @todos in project and create `later` tasks for them
|
21
|
+
Support multiline tasks (kind of don't want to)
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
COMPLETED
|
26
|
+
Make toga commit interactive
|
27
|
+
! If you use a random heading in your file, the system includes its tasks in the preceding group
|
28
|
+
|
29
|
+
|
30
|
+
|
data/USAGE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Toga is a todo list for git.
|
2
|
+
|
3
|
+
Usage:
|
4
|
+
toga -h/--help
|
5
|
+
toga -v/--version
|
6
|
+
toga command [arguments...] [options...]
|
7
|
+
|
8
|
+
Examples:
|
9
|
+
toga An empty command just prints this usage.
|
10
|
+
toga <PATH> Creates a Togafile in that directory.
|
11
|
+
toga list <GROUP> Prints the task list. Optionally, print a specific list by name.
|
12
|
+
toga edit Opens up the Togafile in your local editor.
|
13
|
+
toga ignore .gitignores your Togafile
|
14
|
+
toga share un-ignores your Togafile in .gitignore
|
15
|
+
|
16
|
+
toga complete
|
17
|
+
do
|
18
|
+
finish
|
19
|
+
done Marks a task as completed.
|
20
|
+
|
21
|
+
toga clean Moves all completed tasks to the COMPLETED group.
|
22
|
+
toga push Performs a `git push`, and adds commit refs to the finished tasks in your Togafile.
|
23
|
+
|
24
|
+
Further help:
|
25
|
+
|
26
|
+
http://github.com/colinyoung/toga
|
data/bin/toga
ADDED
data/lib/toga/cli.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Toga
|
2
|
+
|
3
|
+
# The main root class of Toga
|
4
|
+
class CLI
|
5
|
+
|
6
|
+
include Error
|
7
|
+
|
8
|
+
attr_accessor :args
|
9
|
+
attr_accessor :options
|
10
|
+
attr_accessor :return_value
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
@args = args
|
14
|
+
@return_value = 0
|
15
|
+
|
16
|
+
return usage! if args.length == 0
|
17
|
+
|
18
|
+
cmd = @args.shift
|
19
|
+
|
20
|
+
begin
|
21
|
+
@command = Commands.const_get(cmd.capitalize)
|
22
|
+
rescue
|
23
|
+
if !@command
|
24
|
+
fail "Invalid command '#{cmd}'.", "Type `toga` or `toga help` for usage"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
result = @command.run!(@args)
|
30
|
+
if result.is_a? String
|
31
|
+
$stdout.puts result
|
32
|
+
end
|
33
|
+
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
def usage!
|
38
|
+
path = File.expand_path(File.dirname(__FILE__) + '/../../USAGE')
|
39
|
+
$stdout.puts File.open(path).read
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/lib/toga/command.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'git'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Toga
|
5
|
+
module Commands
|
6
|
+
class Commit < Command
|
7
|
+
include Error
|
8
|
+
|
9
|
+
def self.run!(args)
|
10
|
+
git = Git.open(Dir.getwd)
|
11
|
+
untracked = git.status.untracked!.keys
|
12
|
+
modified = git.status.modified.keys
|
13
|
+
added = git.status.added.keys
|
14
|
+
|
15
|
+
# Get the git message to commit with
|
16
|
+
message = Toga::Commands::Top.run!
|
17
|
+
if args.count > 0
|
18
|
+
task_search = args.join(' ')
|
19
|
+
full, group, offset = Togafile.search(task_search)
|
20
|
+
message = full
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "Committing task:\n #{message}\n\n"
|
24
|
+
|
25
|
+
# Show the user the files they're leaving behind and ask to continue or die
|
26
|
+
files_to_add = '.'
|
27
|
+
if untracked.count > 0 || modified.count > 0 || added.count == 0
|
28
|
+
if untracked.count > 0
|
29
|
+
puts error("You didn't add the following files:\n")
|
30
|
+
puts untracked.join("\n") + "\n\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
if modified.count > 0
|
34
|
+
puts error("The following files are modified, but their changes aren't added:\n")
|
35
|
+
puts modified.join("\n") + "\n\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
if added.count == 0
|
39
|
+
changed = git.status.changed.keys
|
40
|
+
files_to_add = changed
|
41
|
+
puts error("The following files are modified, but their changes aren't added:\n")
|
42
|
+
puts changed.join("\n") + "\n\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
puts "Continue committing? [y/a/n] (
|
46
|
+
y: continue, don't stage
|
47
|
+
a: add them using git add #{files_to_add}
|
48
|
+
n: cancel/exit)"
|
49
|
+
continue = $stdin.gets
|
50
|
+
response = continue[0].downcase
|
51
|
+
if !["a", "y"].include? response
|
52
|
+
return 0
|
53
|
+
end
|
54
|
+
|
55
|
+
if response == "a"
|
56
|
+
git.add(files_to_add)
|
57
|
+
puts "Added:\n" + (untracked + modified + (changed || [])).join("\n")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Okay, files are all ready for commit.
|
62
|
+
|
63
|
+
# Print off files
|
64
|
+
|
65
|
+
|
66
|
+
# Prepare git commit.
|
67
|
+
git.status.added.keys.each do |filename|
|
68
|
+
puts "# Staged: #{filename}"
|
69
|
+
end
|
70
|
+
|
71
|
+
puts "# Add an optional message (or press enter): "
|
72
|
+
full_message = message << $stdin.gets
|
73
|
+
`git commit -m "#{full_message.gsub(/"/, '\"')}"`
|
74
|
+
|
75
|
+
Commands::Complete.run!(message)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.join File.dirname(__FILE__), 'list.rb'
|
2
|
+
|
3
|
+
module Toga
|
4
|
+
module Commands
|
5
|
+
class Current < List
|
6
|
+
|
7
|
+
def self.run!(*args)
|
8
|
+
if !args.first || args.first.count == 0
|
9
|
+
return super [:current]
|
10
|
+
end
|
11
|
+
|
12
|
+
# Make a task current.
|
13
|
+
prefix = args.join(' ')
|
14
|
+
full = Togafile.remove_from_group :later, prefix
|
15
|
+
if !full
|
16
|
+
return error "Wasn't found."
|
17
|
+
end
|
18
|
+
Togafile.append_to_group :current, full
|
19
|
+
puts "Moved '#{full}' to current tasks."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Toga
|
4
|
+
module Commands
|
5
|
+
|
6
|
+
class Init < Command
|
7
|
+
|
8
|
+
def self.run!(args)
|
9
|
+
dir = File.expand_path args.first
|
10
|
+
|
11
|
+
# Recursively creates the file
|
12
|
+
FileUtils.mkdir_p dir if !File.directory?(dir)
|
13
|
+
|
14
|
+
# Copies the Togafile scaffold to the new Togafile
|
15
|
+
File.open(File.expand_path(File.join(dir, Toga::TOGAFILE_NAME)), 'w') do |f|
|
16
|
+
togafile = File.expand_path(File.join(Toga::SCAFFOLD_PATH, Toga::TOGAFILE_NAME))
|
17
|
+
f.write File.open(togafile).read
|
18
|
+
end
|
19
|
+
|
20
|
+
"Created #{Toga::TOGAFILE_NAME} in #{dir}."
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Toga
|
2
|
+
module Commands
|
3
|
+
class Later < Command
|
4
|
+
|
5
|
+
def self.run!(*args)
|
6
|
+
if args.first && args.first.count == 0
|
7
|
+
puts Commands::List.run! [:later]
|
8
|
+
end
|
9
|
+
Togafile.append_to_group :later, args.join(' ')
|
10
|
+
Togafile.lines_in_group :later
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Toga
|
2
|
+
module Commands
|
3
|
+
class List < Command
|
4
|
+
|
5
|
+
def self.run!(*args)
|
6
|
+
out = ""
|
7
|
+
|
8
|
+
group_names = args.first.empty? ? [:current, :later] : args.first
|
9
|
+
group_names.each_with_index do |n, i|
|
10
|
+
out << Togafile.lines_in_group(n).join("\n")
|
11
|
+
if i < group_names.length-1 then out << ""; end
|
12
|
+
end
|
13
|
+
|
14
|
+
out
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Toga
|
2
|
+
module Commands
|
3
|
+
class Remove < Command
|
4
|
+
|
5
|
+
def self.run!(*args)
|
6
|
+
removed = Togafile.remove_from_group :current, args.join(' ')
|
7
|
+
puts removed ? "Removed '#{removed}'.\r\n\r\n" : ""
|
8
|
+
Togafile.lines_in_group(:current)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Toga
|
2
|
+
module Commands
|
3
|
+
class Top < Command
|
4
|
+
|
5
|
+
def self.run!(*args)
|
6
|
+
# Move the given task to the top of the group
|
7
|
+
if args.first && args.first.count > 0
|
8
|
+
Togafile.promote(args.first.join(' '))
|
9
|
+
end
|
10
|
+
|
11
|
+
lines = Togafile.lines_in_group(:current)
|
12
|
+
|
13
|
+
lines.shift
|
14
|
+
lines.delete_if {|l| l.strip.length == 0 }
|
15
|
+
|
16
|
+
lines.first
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/toga/error.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Toga
|
2
|
+
module Error
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
base.send :include, ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def error(*args)
|
12
|
+
args.map {|a| puts "[Toga] Error: " + a }
|
13
|
+
end
|
14
|
+
|
15
|
+
def fail(*args)
|
16
|
+
args.map {|a| puts "[Toga] Failure: " + a }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class String
|
4
|
+
def starts_with?(prefix, options={})
|
5
|
+
if prefix.is_a? Array
|
6
|
+
prefix.each do |p|
|
7
|
+
return true if self.starts_with?(p)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
prefix = prefix.to_s
|
12
|
+
left = self[0, prefix.length]
|
13
|
+
right = prefix
|
14
|
+
|
15
|
+
return left.downcase == right.downcase if options[:case_sensitive] == false
|
16
|
+
|
17
|
+
left == right
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Array
|
22
|
+
def includes_prefix?(prefix)
|
23
|
+
self.each_with_index do |str, i|
|
24
|
+
next if !str.is_a? String
|
25
|
+
return i if str.starts_with?(prefix)
|
26
|
+
end
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Git
|
32
|
+
class Status
|
33
|
+
|
34
|
+
# Retrieves files that are ignored
|
35
|
+
def ignored
|
36
|
+
ignored = @base.lib.send :command, 'clean', '-ndX'
|
37
|
+
ignored = ignored.split("\n").collect {|i| i.gsub('Would remove ', '') }
|
38
|
+
files = @files.values.dup
|
39
|
+
subdirectory_ignores = {}
|
40
|
+
ignored.each do |i|
|
41
|
+
if !i[/\/(|\*)$/].nil? # ends in either / or /*
|
42
|
+
files.each do |f|
|
43
|
+
if f.path.starts_with?(i)
|
44
|
+
subdirectory_ignores[f.path] = f
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
subdirectory_ignores
|
50
|
+
end
|
51
|
+
|
52
|
+
def untracked!
|
53
|
+
ignored_paths = self.ignored.keys
|
54
|
+
self.untracked.reject {|k,v| ignored_paths.include?(v.path) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def modified
|
58
|
+
regex = /^[0]+$/
|
59
|
+
added.select {|k,v| v.sha_index[regex] && v.sha_repo[regex] }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/toga/tasks.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Toga
|
4
|
+
class Togafile
|
5
|
+
|
6
|
+
HEADING_REGEX = /^[A-Z\ ]{3,}+/
|
7
|
+
|
8
|
+
def self.path
|
9
|
+
@@path ||= File.expand_path(File.join(Dir.getwd, Toga::TOGAFILE_NAME))
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.path=(path)
|
13
|
+
@@path = path
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
|
18
|
+
def file_handle(mode='r')
|
19
|
+
if block_given?
|
20
|
+
File.open(self.path, mode) { yield }
|
21
|
+
else
|
22
|
+
File.open(self.path, mode)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def lines_in_group(group_name)
|
27
|
+
self.to_a[group_range(group_name)]
|
28
|
+
end
|
29
|
+
|
30
|
+
def append_to_group(group_name, string)
|
31
|
+
lines = self.to_a
|
32
|
+
range = group_range(group_name)
|
33
|
+
last_index = range.last
|
34
|
+
|
35
|
+
# Insert string at the end of the group
|
36
|
+
lines.insert(last_index+1, string)
|
37
|
+
|
38
|
+
# Write array back to file
|
39
|
+
overwrite(lines)
|
40
|
+
end
|
41
|
+
|
42
|
+
def prepend_to_group(group_name, string)
|
43
|
+
lines = self.to_a
|
44
|
+
range = group_range(group_name)
|
45
|
+
first_index = range.first + 1 # Add one to bypass title
|
46
|
+
|
47
|
+
# Insert string at the end of the group
|
48
|
+
lines.insert(first_index+1, string)
|
49
|
+
|
50
|
+
# Write array back to file
|
51
|
+
overwrite(lines)
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_from_group(group_name, string)
|
55
|
+
offset = lines_in_group(group_name).includes_prefix?(string)
|
56
|
+
if !offset
|
57
|
+
puts "[Warning] Task '#{string}' doesn't exist in #{group_name}."
|
58
|
+
return
|
59
|
+
end
|
60
|
+
range = group_range(group_name)
|
61
|
+
index = range.first + offset
|
62
|
+
|
63
|
+
# Insert string at the end of the group
|
64
|
+
lines = self.to_a
|
65
|
+
full = lines.delete_at(index)
|
66
|
+
|
67
|
+
# Write array back to file
|
68
|
+
overwrite(lines)
|
69
|
+
|
70
|
+
# Return full task that was removed
|
71
|
+
full
|
72
|
+
end
|
73
|
+
|
74
|
+
def move(prefix, move_hash)
|
75
|
+
from = move_hash.keys.first
|
76
|
+
to = move_hash.values.first
|
77
|
+
if !lines_in_group(from).includes_prefix?(prefix)
|
78
|
+
return false # Didn't contain this, can't move it
|
79
|
+
end
|
80
|
+
|
81
|
+
full = self.remove_from_group(from, prefix)
|
82
|
+
self.append_to_group(to, full)
|
83
|
+
end
|
84
|
+
|
85
|
+
def search(prefix)
|
86
|
+
lines = self.to_a
|
87
|
+
offset = lines.includes_prefix?(prefix)
|
88
|
+
group_name = group_at(offset)
|
89
|
+
full = lines[offset]
|
90
|
+
offset_in_group = offset - group_range(group_name).first
|
91
|
+
[full, group_name, offset_in_group]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Moves a task to the top of its group
|
95
|
+
def promote(prefix)
|
96
|
+
full, group_name, offset_in_group = search(prefix)
|
97
|
+
self.remove_from_group(group_name, prefix)
|
98
|
+
self.prepend_to_group(group_name, full)
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_a
|
102
|
+
file_handle.collect { |l| l.strip }
|
103
|
+
end
|
104
|
+
|
105
|
+
def group_range(group_name)
|
106
|
+
group_name = group_name.to_s
|
107
|
+
|
108
|
+
lines = []
|
109
|
+
in_group = false
|
110
|
+
i = 0
|
111
|
+
range_start = 0
|
112
|
+
range_end = i
|
113
|
+
|
114
|
+
file_handle.each do |line|
|
115
|
+
is_heading = line.match(HEADING_REGEX)
|
116
|
+
first_line = line.starts_with?(group_name, case_sensitive: false)
|
117
|
+
is_other_heading = !first_line
|
118
|
+
in_group = first_line || in_group && !is_heading
|
119
|
+
|
120
|
+
range_start = i if first_line
|
121
|
+
|
122
|
+
if in_group
|
123
|
+
range_end = i
|
124
|
+
end
|
125
|
+
|
126
|
+
i += 1
|
127
|
+
end
|
128
|
+
|
129
|
+
Range.new(range_start, range_end)
|
130
|
+
end
|
131
|
+
|
132
|
+
def group_at(offset)
|
133
|
+
group = ""
|
134
|
+
file_handle.each_with_index do |line, i|
|
135
|
+
if line.match(HEADING_REGEX)
|
136
|
+
group = line[0../\W/ =~ line].strip
|
137
|
+
end
|
138
|
+
|
139
|
+
if i >= offset
|
140
|
+
return group
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
group
|
145
|
+
end
|
146
|
+
|
147
|
+
def overwrite(lines)
|
148
|
+
handle = file_handle('w')
|
149
|
+
lines.each {|l| handle.puts(l) }
|
150
|
+
handle.close
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
data/lib/toga/version.rb
ADDED
data/lib/toga.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$:.unshift File.dirname(File.join(__FILE__))
|
2
|
+
|
3
|
+
module Toga
|
4
|
+
SCAFFOLD_PATH = File.join(File.dirname(__FILE__), 'toga/scaffold')
|
5
|
+
TOGAFILE_NAME = 'Togafile'
|
6
|
+
end
|
7
|
+
|
8
|
+
require "toga/extensions"
|
9
|
+
require "toga/version"
|
10
|
+
require "toga/error"
|
11
|
+
require "toga/togafile"
|
12
|
+
require "toga/tasks"
|
13
|
+
require "toga/command"
|
14
|
+
Dir.glob(File.dirname(__FILE__) + '/toga/commands/*', &method(:require))
|
15
|
+
require "toga/cli"
|
data/spec/toga_spec.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/unit'
|
3
|
+
require 'mocha'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
require_relative '../lib/toga'
|
7
|
+
|
8
|
+
describe Toga::CLI do
|
9
|
+
before do
|
10
|
+
# => pass
|
11
|
+
@directory = File.expand_path(File.dirname(__FILE__) + '/test_output')
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'init' do
|
15
|
+
it 'creates the file' do
|
16
|
+
seed_togafile
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'add' do
|
21
|
+
before { seed_togafile }
|
22
|
+
|
23
|
+
it 'adds a new task to the current group' do
|
24
|
+
add_new_task('Run toga tests')
|
25
|
+
|
26
|
+
assert Toga::Tasks.group(:current).includes_prefix?('Run toga t')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'complete' do
|
31
|
+
before do
|
32
|
+
seed_togafile
|
33
|
+
add_new_task('Run toga tests')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'moves a task to the completed group' do
|
37
|
+
Toga::Commands::Complete.run! ['Run toga t']
|
38
|
+
|
39
|
+
refute Toga::Tasks.group(:current).includes_prefix?('Run toga t'), "Current group should NOT have task"
|
40
|
+
Toga::Tasks.group(:completed).include?('Run toga tests').must_equal(true)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'uncomplete, current' do
|
45
|
+
before do
|
46
|
+
seed_togafile
|
47
|
+
add_new_task('Run toga tests')
|
48
|
+
Toga::Commands::Complete.run! ['Run toga t']
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'moves a task back to current group' do
|
52
|
+
Toga::Commands::Uncomplete.run! ["Run toga t"]
|
53
|
+
|
54
|
+
refute Toga::Tasks.group(:completed).includes_prefix?('Run toga t'), "Completed group should NOT have task"
|
55
|
+
Toga::Tasks.group(:current).include?('Run toga tests').must_equal(true)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
after do
|
60
|
+
# I hardcoded this so that the tests can't seriously screw you up
|
61
|
+
safe_clean
|
62
|
+
end
|
63
|
+
|
64
|
+
def safe_clean
|
65
|
+
temp_dir = File.expand_path(File.dirname(__FILE__) + '/test_output')
|
66
|
+
if File.directory?(temp_dir)
|
67
|
+
FileUtils.remove_dir(temp_dir)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def seed_togafile
|
72
|
+
test_togafile = File.join(@directory, Toga::TOGAFILE_NAME)
|
73
|
+
Toga::Togafile.path = test_togafile
|
74
|
+
|
75
|
+
Toga::Commands::Init.run! [@directory]
|
76
|
+
File.directory?(@directory).must_equal(true)
|
77
|
+
File.exists?(test_togafile).must_equal(true)
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_new_task(task)
|
81
|
+
Toga::Commands::Add.run! [task]
|
82
|
+
end
|
83
|
+
end
|
data/toga.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "toga/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "toga"
|
7
|
+
s.version = Toga::VERSION
|
8
|
+
s.authors = ["Colin Young"]
|
9
|
+
s.email = ["me@colinyoung.com"]
|
10
|
+
s.homepage = "https://github.com/colinyoung/toga"
|
11
|
+
s.summary = %q{a todo list that integrates seamlessly with git}
|
12
|
+
s.description = %q{a todo list that integrates seamlessly with git}
|
13
|
+
|
14
|
+
s.rubyforge_project = "toga"
|
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
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
s.add_runtime_dependency "git"
|
24
|
+
|
25
|
+
s.add_development_dependency 'require_relative'
|
26
|
+
s.add_development_dependency 'minitest'
|
27
|
+
s.add_development_dependency 'mocha'
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: toga
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Colin Young
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-17 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: git
|
16
|
+
requirement: &70286308535840 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70286308535840
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: require_relative
|
27
|
+
requirement: &70286308535240 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70286308535240
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: minitest
|
38
|
+
requirement: &70286308534640 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70286308534640
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: mocha
|
49
|
+
requirement: &70286308533960 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70286308533960
|
58
|
+
description: a todo list that integrates seamlessly with git
|
59
|
+
email:
|
60
|
+
- me@colinyoung.com
|
61
|
+
executables:
|
62
|
+
- toga
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- Gemfile
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- Togafile
|
71
|
+
- USAGE
|
72
|
+
- bin/toga
|
73
|
+
- lib/toga.rb
|
74
|
+
- lib/toga/cli.rb
|
75
|
+
- lib/toga/command.rb
|
76
|
+
- lib/toga/commands/add.rb
|
77
|
+
- lib/toga/commands/commit.rb
|
78
|
+
- lib/toga/commands/complete.rb
|
79
|
+
- lib/toga/commands/current.rb
|
80
|
+
- lib/toga/commands/init.rb
|
81
|
+
- lib/toga/commands/later.rb
|
82
|
+
- lib/toga/commands/list.rb
|
83
|
+
- lib/toga/commands/now.rb
|
84
|
+
- lib/toga/commands/remove.rb
|
85
|
+
- lib/toga/commands/rm.rb
|
86
|
+
- lib/toga/commands/top.rb
|
87
|
+
- lib/toga/commands/uncomplete.rb
|
88
|
+
- lib/toga/error.rb
|
89
|
+
- lib/toga/extensions.rb
|
90
|
+
- lib/toga/scaffold/Togafile
|
91
|
+
- lib/toga/tasks.rb
|
92
|
+
- lib/toga/togafile.rb
|
93
|
+
- lib/toga/version.rb
|
94
|
+
- spec/toga_spec.rb
|
95
|
+
- toga.gemspec
|
96
|
+
homepage: https://github.com/colinyoung/toga
|
97
|
+
licenses: []
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project: toga
|
116
|
+
rubygems_version: 1.8.10
|
117
|
+
signing_key:
|
118
|
+
specification_version: 3
|
119
|
+
summary: a todo list that integrates seamlessly with git
|
120
|
+
test_files:
|
121
|
+
- spec/toga_spec.rb
|
122
|
+
has_rdoc:
|