toga 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 +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:
|