taskmeister 0.0.1 → 0.9.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.
- checksums.yaml +4 -4
- data/.rspec +3 -0
- data/README.md +61 -20
- data/Rakefile +10 -0
- data/bin/taskmeister +6 -3
- data/features/add.feature +17 -0
- data/features/done.feature +17 -0
- data/features/list.feature +18 -0
- data/features/project_dir.feature +22 -0
- data/features/replace.feature +17 -0
- data/features/show.feature +18 -0
- data/features/support/env.rb +14 -0
- data/lib/taskmeister.rb +7 -4
- data/lib/taskmeister/cli/main.rb +77 -0
- data/lib/taskmeister/cli/options.rb +108 -0
- data/lib/taskmeister/cli/task_list_name.rb +28 -0
- data/lib/taskmeister/task.rb +48 -0
- data/lib/taskmeister/task_list.rb +58 -0
- data/lib/taskmeister/task_list_reader.rb +25 -0
- data/lib/taskmeister/task_list_writer.rb +14 -0
- data/lib/taskmeister/version.rb +1 -1
- data/spec/lib/taskmeister/task_list_reader_spec.rb +77 -0
- data/spec/lib/taskmeister/task_list_spec.rb +106 -0
- data/spec/lib/taskmeister/task_list_writer_spec.rb +25 -0
- data/spec/lib/taskmeister/task_spec.rb +81 -0
- data/spec/spec_helper.rb +46 -0
- data/taskmeister.gemspec +6 -3
- metadata +83 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9765c5b79d2cce230bd4cdc78b11aba686f91adc
|
4
|
+
data.tar.gz: 7a1f828b681135fbedb8fc8209c6cd799fdf804d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e92cac2efc981db979f8723c8a0a4590f5e42674779e1393d234523846c1b23574d6f91ac1042821c58a08e94df5f15c49c7d147f47e4722571cb913a22507a
|
7
|
+
data.tar.gz: 193f0e2d6df20a5961622d1d4c0be8e5183773b4ba9a4b8ed149fa5fffd37cd85d0cc76567c46213731f9712e2066a56d72af97f8dfcb4f43fc22cf56680e7f7
|
data/.rspec
ADDED
data/README.md
CHANGED
@@ -1,38 +1,79 @@
|
|
1
1
|
# Taskmeister
|
2
2
|
|
3
|
-
Simple task management modelled after [t](http://stevelosh.com/projects/t/).
|
3
|
+
Simple command line task management modelled after [t](http://stevelosh.com/projects/t/).
|
4
4
|
|
5
|
-
|
5
|
+
I like the simplicity of t but there are a couple of changes I wanted.
|
6
|
+
|
7
|
+
First: I like to have separate task lists per project. So I infer the task list
|
8
|
+
name from the current project directory. It finds a project directory by walking
|
9
|
+
up from the current directory until it finds a `.git` or `.hg` directory in it.
|
10
|
+
|
11
|
+
Second: I like to have a short list of notes accompanying my tasks. You can add
|
12
|
+
notes beneath your task. They can be edited via Vim with `taskmeister -e` or
|
13
|
+
`taskmeister -e id` to seek to a specific task.
|
6
14
|
|
7
|
-
|
15
|
+
Third: I format my task files in Markdown so that when I open them on my phone
|
16
|
+
via a Markdown-enabled editor they look nice. The format is still simple:
|
8
17
|
|
9
|
-
|
18
|
+
```markdown
|
19
|
+
Add authorisation - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
|
10
20
|
|
11
|
-
|
21
|
+
> Some notes to go with the task above.
|
22
|
+
>
|
23
|
+
> Maybe paste in some links or other interesting information for later.
|
12
24
|
|
13
|
-
|
25
|
+
Refactor the task model - [id](ae0cce15-456d-48c0-a2e2-69d5f567e092)
|
26
|
+
Update the README - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
|
27
|
+
```
|
14
28
|
|
15
|
-
|
29
|
+
## Installation
|
30
|
+
|
31
|
+
Install via Rubygems:
|
16
32
|
|
17
|
-
|
33
|
+
```sh
|
34
|
+
$ gem install taskmeister
|
35
|
+
```
|
18
36
|
|
19
37
|
## Usage
|
20
38
|
|
21
|
-
|
39
|
+
```sh
|
40
|
+
$ taskmeister --help
|
41
|
+
Usage: taskmeister [options] TASK TEXT
|
42
|
+
|
43
|
+
Specific options:
|
44
|
+
If no options are specified TASK TEXT is added as a new task.
|
22
45
|
|
23
|
-
|
46
|
+
-t, --task-dir DIRECTORY The DIRECTORY where your task lists are stored. (Defaults to pwd)
|
47
|
+
-l, --list NAME The task list to use.
|
48
|
+
Will use a list named after your current project directory if not supplied.
|
49
|
+
A project directory is found by walking up from the current directory and stopping if a .git or .hg directory is found.
|
50
|
+
-d, --done TASK_ID Finish a task
|
51
|
+
-s, --show TASK_ID Show a task list item and its notes
|
52
|
+
-e, --edit TASK_ID Edit a task in Vim
|
53
|
+
-r, --replace TASK_ID Replace a task description
|
24
54
|
|
25
|
-
|
55
|
+
Common options:
|
56
|
+
-h, --help Show this message
|
57
|
+
--version Show version
|
58
|
+
```
|
26
59
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
60
|
+
I store my task files in Dropbox so I have the following shell alias set:
|
61
|
+
|
62
|
+
```sh
|
63
|
+
alias t='taskmeister -t ~/Dropbox/Tasks'
|
64
|
+
```
|
65
|
+
|
66
|
+
I let Taskmeister determine the task list name from my current directory. If
|
67
|
+
you want a set a specific task list you could add that to your alias.
|
68
|
+
|
69
|
+
```sh
|
70
|
+
alias t='taskmeister -t ~/Dropbox/Tasks -l mytasks.md'
|
71
|
+
```
|
31
72
|
|
32
73
|
## Contributing
|
33
74
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
75
|
+
Fork the project on Github, add tests for your changes, and submit a well described pull request.
|
76
|
+
|
77
|
+
## Copyright
|
78
|
+
|
79
|
+
Copyright (c) 2014 Ray Grasso. See LICENSE.txt for further details.
|
data/Rakefile
CHANGED
data/bin/taskmeister
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$LOAD_PATH << File.expand_path(
|
3
|
+
$LOAD_PATH << File.expand_path("../../lib", __FILE__)
|
4
4
|
|
5
|
-
|
5
|
+
# Exit cleanly from an early interrupt
|
6
|
+
Signal.trap("INT") { exit 1 }
|
6
7
|
|
7
|
-
|
8
|
+
require "taskmeister"
|
9
|
+
|
10
|
+
Taskmeister::Cli::Main.new(ARGV.dup).execute!
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: taskmeister adds a task to the list
|
2
|
+
|
3
|
+
Scenario: Project directory with task list
|
4
|
+
Given a file named "mylist.md" with:
|
5
|
+
"""
|
6
|
+
Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
|
7
|
+
|
8
|
+
> Notes line one
|
9
|
+
> Notes line two
|
10
|
+
|
11
|
+
Task two - [id](ae0cce15-456d-48c0-a2e2-69d5f567e092)
|
12
|
+
Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
|
13
|
+
"""
|
14
|
+
When I successfully run `taskmeister --list mylist.md A new task`
|
15
|
+
And I successfully run `taskmeister --list mylist.md`
|
16
|
+
Then the output should contain "A new task"
|
17
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: taskmeister removes finished tasks from the list
|
2
|
+
|
3
|
+
Scenario: Project directory with task list
|
4
|
+
Given a file named "mylist.md" with:
|
5
|
+
"""
|
6
|
+
Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
|
7
|
+
|
8
|
+
> Notes line one
|
9
|
+
> Notes line two
|
10
|
+
|
11
|
+
Task two - [id](ae0cce15-456d-48c0-a2e2-69d5f567e092)
|
12
|
+
Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
|
13
|
+
"""
|
14
|
+
When I successfully run `taskmeister --list mylist.md --done a`
|
15
|
+
And I successfully run `taskmeister --list mylist.md`
|
16
|
+
Then the output should not contain "Task one"
|
17
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: taskmeister lists the contents of a task list
|
2
|
+
|
3
|
+
Scenario: Normal directory with explicit task list
|
4
|
+
Given a file named "mylist.md" with:
|
5
|
+
"""
|
6
|
+
Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
|
7
|
+
|
8
|
+
> Notes line one
|
9
|
+
> Notes line two
|
10
|
+
|
11
|
+
Task two - [id](ae0cce15-456d-48c0-a2e2-69d5f567e092)
|
12
|
+
Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
|
13
|
+
"""
|
14
|
+
When I successfully run `taskmeister --list mylist.md`
|
15
|
+
Then the output should contain "a - Task one »"
|
16
|
+
And the output should contain "ae - Task two"
|
17
|
+
And the output should contain "a5 - Task three"
|
18
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Feature: taskmeister infers the name of your task list from your current project directory
|
2
|
+
|
3
|
+
Scenario: Project directory with task list
|
4
|
+
Given a directory named "project"
|
5
|
+
And a directory named "project/.git"
|
6
|
+
And a directory named "project/child"
|
7
|
+
And a file named "project.md" with:
|
8
|
+
"""
|
9
|
+
Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
|
10
|
+
|
11
|
+
> Notes line one
|
12
|
+
> Notes line two
|
13
|
+
|
14
|
+
Task two - [id](ae0cce15-456d-48c0-a2e2-69d5f567e092)
|
15
|
+
Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
|
16
|
+
"""
|
17
|
+
And I cd to "project/child"
|
18
|
+
When I successfully run `taskmeister --task-dir ../../`
|
19
|
+
Then the output should contain "a - Task one »"
|
20
|
+
And the output should contain "ae - Task two"
|
21
|
+
And the output should contain "a5 - Task three"
|
22
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: taskmeister replaces a task in the list
|
2
|
+
|
3
|
+
Scenario: Project directory with task list
|
4
|
+
Given a file named "mylist.md" with:
|
5
|
+
"""
|
6
|
+
Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
|
7
|
+
|
8
|
+
> Notes line one
|
9
|
+
> Notes line two
|
10
|
+
|
11
|
+
Task two - [id](ae0cce15-456d-48c0-a2e2-69d5f567e092)
|
12
|
+
Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
|
13
|
+
"""
|
14
|
+
When I successfully run `taskmeister --list mylist.md -r a A new task`
|
15
|
+
And I successfully run `taskmeister --list mylist.md`
|
16
|
+
Then the output should contain "a - A new task"
|
17
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: taskmeister shows the details of a task in the list
|
2
|
+
|
3
|
+
Scenario: Project directory with task list
|
4
|
+
Given a file named "mylist.md" with:
|
5
|
+
"""
|
6
|
+
Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
|
7
|
+
|
8
|
+
> Notes line one
|
9
|
+
> Notes line two
|
10
|
+
|
11
|
+
Task two - [id](ae0cce15-456d-48c0-a2e2-69d5f567e092)
|
12
|
+
Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
|
13
|
+
"""
|
14
|
+
When I successfully run `taskmeister --list mylist.md --show a`
|
15
|
+
Then the output should contain "Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)"
|
16
|
+
And the output should contain "> Notes line one"
|
17
|
+
And the output should contain "> Notes line two"
|
18
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'aruba/cucumber'
|
5
|
+
|
6
|
+
$LOAD_PATH << File.expand_path('../../../lib', __FILE__)
|
7
|
+
require 'taskmeister'
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
require 'aruba'
|
11
|
+
require 'aruba/in_process'
|
12
|
+
|
13
|
+
Aruba::InProcess.main_class = Taskmeister::Cli::Main
|
14
|
+
Aruba.process = Aruba::InProcess
|
data/lib/taskmeister.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require "taskmeister/version"
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
require "taskmeister/task"
|
3
|
+
require "taskmeister/task_list"
|
4
|
+
require "taskmeister/task_list_reader"
|
5
|
+
require "taskmeister/task_list_writer"
|
6
|
+
require "taskmeister/cli/task_list_name"
|
7
|
+
require "taskmeister/cli/main"
|
8
|
+
require "taskmeister/cli/options"
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module Taskmeister
|
4
|
+
module Cli
|
5
|
+
class Main
|
6
|
+
def initialize(argv, stdin=STDIN, stdout=STDOUT, stderr=STDERR, kernel=Kernel)
|
7
|
+
@argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute!
|
11
|
+
options = Options.new(@stdout, @kernel).parse(@argv)
|
12
|
+
|
13
|
+
task_list_path = Pathname.new(options.task_dir) + task_list_name(options)
|
14
|
+
|
15
|
+
task_list = Taskmeister::TaskListReader.from_markdown_file(task_list_path)
|
16
|
+
|
17
|
+
run_command(options, task_list_path, task_list)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def task_list_name(options)
|
23
|
+
task_list_name = options.list || TaskListName.from_project_dir(Pathname.getwd)
|
24
|
+
|
25
|
+
unless task_list_name
|
26
|
+
@stdout.puts "Could not find a project directory. Please specify a task list."
|
27
|
+
@kernel.exit 1
|
28
|
+
end
|
29
|
+
|
30
|
+
task_list_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def run_command(options, task_list_path, task_list)
|
34
|
+
case options.command
|
35
|
+
when Commands::LIST
|
36
|
+
@stdout.puts task_list.to_short_list
|
37
|
+
|
38
|
+
when Commands::SHOW
|
39
|
+
|
40
|
+
@stdout.puts task_list.details(options.task_id)
|
41
|
+
|
42
|
+
when Commands::EDIT
|
43
|
+
|
44
|
+
task = task_list[options.task_id]
|
45
|
+
|
46
|
+
search_path = task ? "+/#{task.id} " : ""
|
47
|
+
system "vim #{search_path}#{task_list_path}"
|
48
|
+
|
49
|
+
when Commands::ADD
|
50
|
+
|
51
|
+
update_task_list(task_list, task_list_path) {
|
52
|
+
task_list.add(Taskmeister::Task.create(options.task_text))
|
53
|
+
}
|
54
|
+
|
55
|
+
when Commands::DONE
|
56
|
+
|
57
|
+
update_task_list(task_list, task_list_path) {
|
58
|
+
task_list.complete options.task_id
|
59
|
+
}
|
60
|
+
|
61
|
+
when Commands::REPLACE
|
62
|
+
|
63
|
+
update_task_list(task_list, task_list_path) {
|
64
|
+
task_list.replace options.task_id, options.task_text
|
65
|
+
}
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
@kernel.exit 0
|
70
|
+
end
|
71
|
+
|
72
|
+
def update_task_list(task_list, file_path)
|
73
|
+
Taskmeister::TaskListWriter.to_markdown_file(task_list, file_path) if yield
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "ostruct"
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
module Taskmeister
|
6
|
+
module Cli
|
7
|
+
module Commands
|
8
|
+
ADD = "add"
|
9
|
+
LIST = "list"
|
10
|
+
REPLACE = "replace"
|
11
|
+
EDIT = "edit"
|
12
|
+
SHOW = "show"
|
13
|
+
DONE = "done"
|
14
|
+
end
|
15
|
+
|
16
|
+
class Options
|
17
|
+
def initialize(stdout = STDOUT, kernel = Kernel)
|
18
|
+
@stdout = stdout
|
19
|
+
@kernel = kernel
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(args)
|
23
|
+
options = default_options
|
24
|
+
|
25
|
+
opt_parser = OptionParser.new do |opts|
|
26
|
+
opts.program_name = "taskmeister"
|
27
|
+
opts.banner = "Usage: taskmeister [options] TASK TEXT"
|
28
|
+
|
29
|
+
opts.separator ""
|
30
|
+
opts.separator "Specific options:"
|
31
|
+
opts.separator " If no options are specified TASK TEXT is added as a new task."
|
32
|
+
opts.separator ""
|
33
|
+
|
34
|
+
opts.on("-t", "--task-dir DIRECTORY",
|
35
|
+
"The DIRECTORY where your task lists are stored. (Defaults to pwd)") do |dir|
|
36
|
+
options.task_dir = Pathname.new(dir)
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-l", "--list NAME",
|
40
|
+
"The task list to use.",
|
41
|
+
" Will use a list named after your current project directory if not supplied.",
|
42
|
+
" A project directory is found by walking up from the current directory and stopping if a .git or .hg directory is found.") do |list|
|
43
|
+
options.list = Pathname.new(list)
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on("-d", "--done TASK_ID",
|
47
|
+
"Finish a task") do |task_id|
|
48
|
+
options.command = Commands::DONE
|
49
|
+
options.task_id = task_id
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on("-s", "--show TASK_ID",
|
53
|
+
"Show a task list item and its notes") do |task_id|
|
54
|
+
options.command = Commands::SHOW
|
55
|
+
options.task_id = task_id
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on("-e", "--edit [TASK_ID]",
|
59
|
+
"Edit task list in Vim",
|
60
|
+
" Will search for a specific task if TASK_ID is provided") do |task_id|
|
61
|
+
options.command = Commands::EDIT
|
62
|
+
options.task_id = task_id
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on("-r", "--replace TASK_ID",
|
66
|
+
"Replace a task description") do |task_id|
|
67
|
+
options.command = Commands::REPLACE
|
68
|
+
options.task_id = task_id
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.separator ""
|
72
|
+
opts.separator "Common options:"
|
73
|
+
|
74
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
75
|
+
@stdout.puts opts
|
76
|
+
@kernel.exit
|
77
|
+
end
|
78
|
+
|
79
|
+
opts.on_tail("--version", "Show version") do
|
80
|
+
@stdout.puts Taskmeister::VERSION
|
81
|
+
@kernel.exit
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
task_text = opt_parser.parse!(args)
|
86
|
+
|
87
|
+
options.task_text = task_text.join(" ") unless task_text.empty?
|
88
|
+
|
89
|
+
# If there is task text and the default command hasn't been overwritten
|
90
|
+
# by the user, make the command add
|
91
|
+
if !task_text.empty? and options.command == Commands::LIST
|
92
|
+
options.command = Commands::ADD
|
93
|
+
end
|
94
|
+
|
95
|
+
options
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def default_options
|
101
|
+
OpenStruct.new.tap do |o|
|
102
|
+
o.command = Commands::LIST
|
103
|
+
o.task_dir = Pathname.getwd
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module Taskmeister
|
4
|
+
module Cli
|
5
|
+
class TaskListName
|
6
|
+
def self.from_project_dir(dir)
|
7
|
+
project_dir = find_project_dir(dir)
|
8
|
+
|
9
|
+
return project_dir.basename.to_s + ".md" if project_dir
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.find_project_dir(dir)
|
13
|
+
return dir if dir.children.any? { |child| is_project_dir?(child) }
|
14
|
+
|
15
|
+
return nil if dir == Pathname.new("/") || dir.parent.nil?
|
16
|
+
|
17
|
+
return self.find_project_dir(dir.parent)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.is_project_dir?(dir)
|
21
|
+
dir.directory? && (
|
22
|
+
dir.basename == Pathname.new(".git") ||
|
23
|
+
dir.basename == Pathname.new(".hg")
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Taskmeister
|
4
|
+
class Task
|
5
|
+
attr_reader :text, :notes, :id
|
6
|
+
|
7
|
+
def initialize(text, id, notes)
|
8
|
+
@text, @id, @notes = text, id, notes
|
9
|
+
end
|
10
|
+
|
11
|
+
def notes?
|
12
|
+
notes && !notes.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_markdown
|
16
|
+
[ "#{text} - [id](#{id})" ].tap do |a|
|
17
|
+
return a unless notes.match(/\S/)
|
18
|
+
a << ""
|
19
|
+
a.concat notes.split("\n").map { |n|
|
20
|
+
n.size > 0 ? "> #{n}" : ">"
|
21
|
+
}
|
22
|
+
a << ""
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create(text)
|
27
|
+
self.new(text, SecureRandom.uuid, "")
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.from_markdown(lines)
|
31
|
+
task, *notes = *lines
|
32
|
+
|
33
|
+
text, id = task_attributes(task)
|
34
|
+
|
35
|
+
notes = notes.map { |l| l.gsub(/\A> ?/, "") }.join("\n")
|
36
|
+
|
37
|
+
self.new(text, id, notes)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.task_attributes(line)
|
41
|
+
matches = line.match(/\A(.+) - \[id\]\(([\w-]+)\)\z/)
|
42
|
+
|
43
|
+
fail "Invalid task: #{line}" unless matches
|
44
|
+
|
45
|
+
[matches[1], matches[2]]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Taskmeister
|
2
|
+
class TaskList
|
3
|
+
def initialize(tasks)
|
4
|
+
@hash = {}
|
5
|
+
|
6
|
+
tasks.each do |t|
|
7
|
+
add(t)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_short_list
|
12
|
+
longest_id = @hash.keys.max_by(&:length)
|
13
|
+
@hash.map { |id, task|
|
14
|
+
marker = task.notes? ? " »" : ""
|
15
|
+
"%-#{longest_id.length}s - %s%s" % [id, task.text, marker]
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def tasks
|
20
|
+
@hash.values
|
21
|
+
end
|
22
|
+
|
23
|
+
def [](key)
|
24
|
+
@hash[key]
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(task)
|
28
|
+
prefix = assign_short_code_to_task(task)
|
29
|
+
@hash[prefix] = task
|
30
|
+
end
|
31
|
+
|
32
|
+
def complete(short_id)
|
33
|
+
@hash.delete(short_id)
|
34
|
+
end
|
35
|
+
|
36
|
+
def replace(short_id, new_text)
|
37
|
+
task = self[short_id]
|
38
|
+
return unless task
|
39
|
+
|
40
|
+
@hash[short_id] = Task.new(new_text, task.id, task.notes)
|
41
|
+
end
|
42
|
+
|
43
|
+
def details(short_id)
|
44
|
+
return [] unless @hash.has_key?(short_id)
|
45
|
+
|
46
|
+
self[short_id].to_markdown
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def assign_short_code_to_task(task)
|
52
|
+
task.id.length.times do |i|
|
53
|
+
prefix = task.id.slice(0, i + 1)
|
54
|
+
return prefix unless @hash.has_key?(prefix)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Taskmeister
|
2
|
+
class TaskListReader
|
3
|
+
def self.from_markdown(file_lines)
|
4
|
+
grouped_lines = \
|
5
|
+
file_lines.map(&:chomp)
|
6
|
+
.reject(&:empty?)
|
7
|
+
.reduce([]) do |acc, l|
|
8
|
+
acc << [l] if l.match(/\A[^\s>]/) # A new task
|
9
|
+
acc.last << l if l.match(/\A>/) # A line of note for the latest task
|
10
|
+
acc
|
11
|
+
end
|
12
|
+
|
13
|
+
tasks = grouped_lines.map do |l|
|
14
|
+
Task.from_markdown(l)
|
15
|
+
end
|
16
|
+
|
17
|
+
TaskList.new tasks
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.from_markdown_file(path)
|
21
|
+
lines = File.exist?(path) ? File.readlines(path) : []
|
22
|
+
from_markdown lines
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Taskmeister
|
2
|
+
class TaskListWriter
|
3
|
+
def self.to_markdown(task_list)
|
4
|
+
task_list.tasks.map(&:to_markdown).flatten
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.to_markdown_file(task_list, file_path)
|
8
|
+
lines = self.to_markdown(task_list)
|
9
|
+
File.open(file_path, "w") do |f|
|
10
|
+
f.puts lines
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/taskmeister/version.rb
CHANGED
@@ -0,0 +1,77 @@
|
|
1
|
+
require "taskmeister/task_list_reader"
|
2
|
+
require "taskmeister/task_list"
|
3
|
+
require "taskmeister/task"
|
4
|
+
|
5
|
+
module Taskmeister
|
6
|
+
RSpec.describe TaskListReader do
|
7
|
+
describe ".from_markdown" do
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(Task).to receive(:from_markdown).and_return(double(Task))
|
11
|
+
allow(TaskList).to receive(:new).and_return(double(TaskList))
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:it) { described_class.from_markdown(lines) }
|
15
|
+
|
16
|
+
describe "passed an empty list of lines" do
|
17
|
+
let(:lines) { [] }
|
18
|
+
|
19
|
+
it "creates an empty task list" do
|
20
|
+
expect(Task).not_to receive(:from_markdown)
|
21
|
+
expect(TaskList).to receive(:new).with([])
|
22
|
+
it
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "passed a list of simple tasks" do
|
27
|
+
let(:lines) { [
|
28
|
+
"Task number 1\n",
|
29
|
+
"Task number 2\n"
|
30
|
+
]
|
31
|
+
}
|
32
|
+
|
33
|
+
it "creates a task for each line, stripping new lines" do
|
34
|
+
expect(Task).to receive(:from_markdown).with([ "Task number 1" ])
|
35
|
+
expect(Task).to receive(:from_markdown).with([ "Task number 2" ])
|
36
|
+
it
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "passed a list of tasks with notes" do
|
41
|
+
let(:lines) { [
|
42
|
+
"Task number 1\n",
|
43
|
+
"\n",
|
44
|
+
"> note line 1\n",
|
45
|
+
"> note line 2\n",
|
46
|
+
"\n",
|
47
|
+
"Task number 2\n",
|
48
|
+
"Task number 3\n",
|
49
|
+
"\n",
|
50
|
+
"> note line 3\n",
|
51
|
+
"> note line 4\n",
|
52
|
+
"",
|
53
|
+
"",
|
54
|
+
]
|
55
|
+
}
|
56
|
+
|
57
|
+
it "creates a task for each line with their associated notes, stripping newlines" do
|
58
|
+
expect(Task).to receive(:from_markdown).with([
|
59
|
+
"Task number 1",
|
60
|
+
"> note line 1",
|
61
|
+
"> note line 2",
|
62
|
+
])
|
63
|
+
expect(Task).to receive(:from_markdown).with([
|
64
|
+
"Task number 2"
|
65
|
+
])
|
66
|
+
expect(Task).to receive(:from_markdown).with([
|
67
|
+
"Task number 3",
|
68
|
+
"> note line 3",
|
69
|
+
"> note line 4",
|
70
|
+
])
|
71
|
+
|
72
|
+
it
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "taskmeister/task_list"
|
2
|
+
require "taskmeister/task"
|
3
|
+
|
4
|
+
module Taskmeister
|
5
|
+
RSpec.describe TaskList do
|
6
|
+
|
7
|
+
let(:task1) { Task.new("task 1", "78dc2561-8c9a-4780-a560-56e1e14f2ed3", nil) }
|
8
|
+
let(:task2) { Task.new("task 2", "b2110029-ffa0-4e54-985a-2aa6d1bed53b", nil) }
|
9
|
+
let(:task3) { Task.new("task 3", "1c890df0-97a5-4310-9b01-374983416af7", "a note") }
|
10
|
+
let(:task4) { Task.new("task 4", "1c891df0-97a5-4310-9b01-374983416af7", nil) }
|
11
|
+
let(:task5) { Task.new("task 5", "ef0915ee-3d11-4358-b12c-15a4ab0d1d26", nil) }
|
12
|
+
let(:task6) { Task.new("task 6", "f2a0d281-f323-4909-8547-d4af5315a295", nil) }
|
13
|
+
let(:task7) { Task.new("task 7", "f2a0d281-4323-4909-8547-d4af5315a295", nil) }
|
14
|
+
|
15
|
+
let(:tasks) { [
|
16
|
+
task1, task2, task3, task4, task5, task6, task7
|
17
|
+
]}
|
18
|
+
|
19
|
+
let(:list) { described_class.new(tasks) }
|
20
|
+
|
21
|
+
describe "#[]" do
|
22
|
+
it "uses the shortest common prefix to index a task" do
|
23
|
+
expect(list["7"]).to eq task1
|
24
|
+
expect(list["b"]).to eq task2
|
25
|
+
expect(list["1"]).to eq task3
|
26
|
+
expect(list["1c"]).to eq task4
|
27
|
+
expect(list["e"]).to eq task5
|
28
|
+
expect(list["f"]).to eq task6
|
29
|
+
expect(list["f2"]).to eq task7
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#to_short_list" do
|
34
|
+
subject { list.to_short_list }
|
35
|
+
|
36
|
+
it "returns an array of short ids and task texts with markers for those that have notes" do
|
37
|
+
expect(subject).to eq([
|
38
|
+
"7 - task 1",
|
39
|
+
"b - task 2",
|
40
|
+
"1 - task 3 »",
|
41
|
+
"1c - task 4",
|
42
|
+
"e - task 5",
|
43
|
+
"f - task 6",
|
44
|
+
"f2 - task 7"
|
45
|
+
])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#complete" do
|
50
|
+
it "removes the identified task" do
|
51
|
+
expect(list["7"]).to eq task1
|
52
|
+
result = list.complete("7")
|
53
|
+
expect(result).to be_truthy
|
54
|
+
expect(list["7"]).to be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it "ignores non-existent tasks" do
|
58
|
+
result = list.complete("345")
|
59
|
+
expect(result).to be_falsy
|
60
|
+
expect(list.tasks.size).to eq tasks.size
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#replace" do
|
65
|
+
it "replaces the text of the specified task" do
|
66
|
+
result = list.replace("7", "A new task text")
|
67
|
+
expect(result).to be_truthy
|
68
|
+
task = list["7"]
|
69
|
+
expect(task.text).to eq "A new task text"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "ignores a non-existent task" do
|
73
|
+
result = list.replace("345", "A new task text")
|
74
|
+
expect(result).to be_falsy
|
75
|
+
expect(list.tasks.size).to eq tasks.size
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#details" do
|
80
|
+
before do
|
81
|
+
allow_any_instance_of(Task).to receive(:to_markdown).and_return([
|
82
|
+
"line 1",
|
83
|
+
"line 2"
|
84
|
+
])
|
85
|
+
end
|
86
|
+
|
87
|
+
it "returns an empty list if the id doesn't exist" do
|
88
|
+
expect(list.details("34")).to eq []
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns the lines of a task" do
|
92
|
+
expect(list.details("7")).to eq ["line 1", "line 2"]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#add" do
|
97
|
+
it "adds the task and assigns it a short id" do
|
98
|
+
task8 = Task.new("task 8", "f23891df0-97a5-4310-9b01-374983416af7", nil)
|
99
|
+
result = list.add(task8)
|
100
|
+
expect(result).to be_truthy
|
101
|
+
expect(list.tasks.size).to eq 8
|
102
|
+
expect(list["f23"]).to eq task8
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "taskmeister/task_list_writer"
|
2
|
+
require "taskmeister/task_list"
|
3
|
+
require "taskmeister/task"
|
4
|
+
|
5
|
+
module Taskmeister
|
6
|
+
RSpec.describe TaskListWriter do
|
7
|
+
describe ".to_markdown" do
|
8
|
+
let(:task1) { double(Task, to_markdown: ["line1", "line2"]) }
|
9
|
+
let(:task2) { double(Task, to_markdown: ["line3", "line4"]) }
|
10
|
+
let(:task_list) { double(TaskList, tasks: [ task1, task2 ]) }
|
11
|
+
|
12
|
+
subject { described_class.to_markdown(task_list) }
|
13
|
+
|
14
|
+
it "returns a concatenated list of all the underlying task markdown" do
|
15
|
+
expect(subject).to eq [
|
16
|
+
"line1",
|
17
|
+
"line2",
|
18
|
+
"line3",
|
19
|
+
"line4"
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "taskmeister/task"
|
2
|
+
|
3
|
+
module Taskmeister
|
4
|
+
RSpec.describe Task do
|
5
|
+
describe ".from_markdown" do
|
6
|
+
subject { described_class.from_markdown(lines) }
|
7
|
+
|
8
|
+
describe "passed a single valid line" do
|
9
|
+
let(:lines) { [
|
10
|
+
"A task name - [id](78dc2561-8c9a-4780-a560-56e1e14f2ed3)"
|
11
|
+
]}
|
12
|
+
|
13
|
+
it "sets the name and id of the task" do
|
14
|
+
expect(subject.id).to eq "78dc2561-8c9a-4780-a560-56e1e14f2ed3"
|
15
|
+
expect(subject.text).to eq "A task name"
|
16
|
+
expect(subject.notes).to eq ""
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "passed a single valid line and notes" do
|
21
|
+
let(:lines) { [
|
22
|
+
"A task name - [id](78dc2561-8c9a-4780-a560-56e1e14f2ed3)",
|
23
|
+
"> line one of a note",
|
24
|
+
">",
|
25
|
+
"> line two of a note"
|
26
|
+
]}
|
27
|
+
|
28
|
+
it "sets the name and id of the task" do
|
29
|
+
expect(subject.id).to eq "78dc2561-8c9a-4780-a560-56e1e14f2ed3"
|
30
|
+
expect(subject.text).to eq "A task name"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "concatenates together the notes of the task" do
|
34
|
+
expect(subject.notes).to eq "line one of a note\n\nline two of a note"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "passed a single invalid line" do
|
39
|
+
let(:lines) { [
|
40
|
+
"A task name"
|
41
|
+
]}
|
42
|
+
|
43
|
+
it "raises an error" do
|
44
|
+
expect{ subject }.to raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe ".create" do
|
50
|
+
it "returns a task with the specified text and a new id" do
|
51
|
+
task = described_class.create("My task text")
|
52
|
+
expect(task.text).to eq "My task text"
|
53
|
+
expect(task.id).to match(/[\w-]+/)
|
54
|
+
expect(task.notes).to eq ""
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#to_markdown" do
|
59
|
+
it "returns a list of markdown-formatted lines" do
|
60
|
+
task = described_class.new("task 8", "f23891df0-97a5-4310-9b01-374983416af7", " ")
|
61
|
+
expect(task.to_markdown).to eq [
|
62
|
+
"task 8 - [id](f23891df0-97a5-4310-9b01-374983416af7)"
|
63
|
+
]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns a list of markdown-formatted lines including notes" do
|
67
|
+
task = described_class.new("task 8", "f23891df0-97a5-4310-9b01-374983416af7",
|
68
|
+
"First line of a note\nsecond line\n\nthird line")
|
69
|
+
expect(task.to_markdown).to eq [
|
70
|
+
"task 8 - [id](f23891df0-97a5-4310-9b01-374983416af7)",
|
71
|
+
"",
|
72
|
+
"> First line of a note",
|
73
|
+
"> second line",
|
74
|
+
">",
|
75
|
+
"> third line",
|
76
|
+
""
|
77
|
+
]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
RSpec.configure do |config|
|
2
|
+
|
3
|
+
=begin
|
4
|
+
# These two settings work together to allow you to limit a spec run
|
5
|
+
# to individual examples or groups you care about by tagging them with
|
6
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
7
|
+
# get run.
|
8
|
+
config.filter_run :focus
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
|
11
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
12
|
+
# file, and it's useful to allow more verbose output when running an
|
13
|
+
# individual spec file.
|
14
|
+
|
15
|
+
# Print the 10 slowest examples and example groups at the
|
16
|
+
# end of the spec run, to help surface which specs are running
|
17
|
+
# particularly slow.
|
18
|
+
config.profile_examples = 10
|
19
|
+
|
20
|
+
# Run specs in random order to surface order dependencies. If you find an
|
21
|
+
# order dependency and want to debug it, you can fix the order by providing
|
22
|
+
# the seed, which is printed after each run.
|
23
|
+
# --seed 1234
|
24
|
+
config.order = :random
|
25
|
+
|
26
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
27
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
28
|
+
# test failures related to randomization by passing the same `--seed` value
|
29
|
+
# as the one that triggered the failure.
|
30
|
+
Kernel.srand config.seed
|
31
|
+
=end
|
32
|
+
|
33
|
+
if config.files_to_run.one?
|
34
|
+
config.default_formatter = 'doc'
|
35
|
+
end
|
36
|
+
|
37
|
+
config.expect_with :rspec do |expectations|
|
38
|
+
expectations.syntax = :expect
|
39
|
+
end
|
40
|
+
|
41
|
+
config.mock_with :rspec do |mocks|
|
42
|
+
mocks.syntax = :expect
|
43
|
+
|
44
|
+
mocks.verify_partial_doubles = true
|
45
|
+
end
|
46
|
+
end
|
data/taskmeister.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Taskmeister::VERSION
|
9
9
|
spec.authors = ["Ray Grasso"]
|
10
10
|
spec.email = ["ray.grasso@gmail.com"]
|
11
|
-
spec.summary = %q{
|
12
|
-
spec.description = %q{Another command line task manager. You know,
|
11
|
+
spec.summary = %q{Another command line task manager.}
|
12
|
+
spec.description = %q{Another command line task manager. You know, because I'm special.}
|
13
13
|
spec.homepage = "https://www.github.com/grassdog/taskmeister"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -19,5 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
-
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rake", "~> 10"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
24
|
+
spec.add_development_dependency "aruba", "~> 0.6"
|
25
|
+
spec.add_development_dependency "pry-byebug", "~> 1.3"
|
23
26
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: taskmeister
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ray Grasso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,17 +28,59 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
47
|
+
version: '3.0'
|
34
48
|
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- - "
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: aruba
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-byebug
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
39
81
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
41
|
-
description: Another command line task manager. You know,
|
82
|
+
version: '1.3'
|
83
|
+
description: Another command line task manager. You know, because I'm special.
|
42
84
|
email:
|
43
85
|
- ray.grasso@gmail.com
|
44
86
|
executables:
|
@@ -47,14 +89,34 @@ extensions: []
|
|
47
89
|
extra_rdoc_files: []
|
48
90
|
files:
|
49
91
|
- ".gitignore"
|
92
|
+
- ".rspec"
|
50
93
|
- ".ruby-version"
|
51
94
|
- Gemfile
|
52
95
|
- LICENSE.txt
|
53
96
|
- README.md
|
54
97
|
- Rakefile
|
55
98
|
- bin/taskmeister
|
99
|
+
- features/add.feature
|
100
|
+
- features/done.feature
|
101
|
+
- features/list.feature
|
102
|
+
- features/project_dir.feature
|
103
|
+
- features/replace.feature
|
104
|
+
- features/show.feature
|
105
|
+
- features/support/env.rb
|
56
106
|
- lib/taskmeister.rb
|
107
|
+
- lib/taskmeister/cli/main.rb
|
108
|
+
- lib/taskmeister/cli/options.rb
|
109
|
+
- lib/taskmeister/cli/task_list_name.rb
|
110
|
+
- lib/taskmeister/task.rb
|
111
|
+
- lib/taskmeister/task_list.rb
|
112
|
+
- lib/taskmeister/task_list_reader.rb
|
113
|
+
- lib/taskmeister/task_list_writer.rb
|
57
114
|
- lib/taskmeister/version.rb
|
115
|
+
- spec/lib/taskmeister/task_list_reader_spec.rb
|
116
|
+
- spec/lib/taskmeister/task_list_spec.rb
|
117
|
+
- spec/lib/taskmeister/task_list_writer_spec.rb
|
118
|
+
- spec/lib/taskmeister/task_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
58
120
|
- taskmeister.gemspec
|
59
121
|
homepage: https://www.github.com/grassdog/taskmeister
|
60
122
|
licenses:
|
@@ -79,5 +141,17 @@ rubyforge_project:
|
|
79
141
|
rubygems_version: 2.2.2
|
80
142
|
signing_key:
|
81
143
|
specification_version: 4
|
82
|
-
summary:
|
83
|
-
test_files:
|
144
|
+
summary: Another command line task manager.
|
145
|
+
test_files:
|
146
|
+
- features/add.feature
|
147
|
+
- features/done.feature
|
148
|
+
- features/list.feature
|
149
|
+
- features/project_dir.feature
|
150
|
+
- features/replace.feature
|
151
|
+
- features/show.feature
|
152
|
+
- features/support/env.rb
|
153
|
+
- spec/lib/taskmeister/task_list_reader_spec.rb
|
154
|
+
- spec/lib/taskmeister/task_list_spec.rb
|
155
|
+
- spec/lib/taskmeister/task_list_writer_spec.rb
|
156
|
+
- spec/lib/taskmeister/task_spec.rb
|
157
|
+
- spec/spec_helper.rb
|