taskmeister 0.9.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9765c5b79d2cce230bd4cdc78b11aba686f91adc
4
- data.tar.gz: 7a1f828b681135fbedb8fc8209c6cd799fdf804d
3
+ metadata.gz: 591ce55195a674c8070990555d81b0adb170bbfb
4
+ data.tar.gz: ba6c0b5b60a931b6b88ed9b1fbd4972593ddd6cc
5
5
  SHA512:
6
- metadata.gz: 3e92cac2efc981db979f8723c8a0a4590f5e42674779e1393d234523846c1b23574d6f91ac1042821c58a08e94df5f15c49c7d147f47e4722571cb913a22507a
7
- data.tar.gz: 193f0e2d6df20a5961622d1d4c0be8e5183773b4ba9a4b8ed149fa5fffd37cd85d0cc76567c46213731f9712e2066a56d72af97f8dfcb4f43fc22cf56680e7f7
6
+ metadata.gz: e6b26c40298e84d9849c7938ffe0b9e0eeb7c75d8eece34a3d3f056383d6e1f5d6b740a0a420c53a7c2e5840f9813865754a5f5ce7656ab64e30bde23c3b2b11
7
+ data.tar.gz: aa049e066b54e142feee77aea27e427e71c61557bfca4891f859ba7f499c680695dac19cd96f5d340b0533c65f8e8c58ed2257884b98932d960105ae6ade0664
data/README.md CHANGED
@@ -49,7 +49,8 @@ Specific options:
49
49
  A project directory is found by walking up from the current directory and stopping if a .git or .hg directory is found.
50
50
  -d, --done TASK_ID Finish a task
51
51
  -s, --show TASK_ID Show a task list item and its notes
52
- -e, --edit TASK_ID Edit a task in Vim
52
+ -e, --edit [TASK_ID] Edit task list in Vim
53
+ Will search for a specific task if TASK_ID is provided
53
54
  -r, --replace TASK_ID Replace a task description
54
55
 
55
56
  Common options:
data/Rakefile CHANGED
@@ -9,4 +9,4 @@ require 'rspec/core/rake_task'
9
9
 
10
10
  RSpec::Core::RakeTask.new(:spec)
11
11
 
12
- task :default => :spec
12
+ task :default => [:spec, :cucumber]
@@ -1,6 +1,6 @@
1
1
  Feature: taskmeister adds a task to the list
2
2
 
3
- Scenario: Project directory with task list
3
+ Scenario: Add a task to the list
4
4
  Given a file named "mylist.md" with:
5
5
  """
6
6
  Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
@@ -15,3 +15,8 @@ Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
15
15
  And I successfully run `taskmeister --list mylist.md`
16
16
  Then the output should contain "A new task"
17
17
 
18
+ Scenario: Add a task to an empty list
19
+ When I successfully run `taskmeister --list mylist.md A new task`
20
+ And I successfully run `taskmeister --list mylist.md`
21
+ Then the output should contain "A new task"
22
+ And a file named "mylist.md" should exist
@@ -1,6 +1,6 @@
1
1
  Feature: taskmeister removes finished tasks from the list
2
2
 
3
- Scenario: Project directory with task list
3
+ Scenario: Complete a task in the list
4
4
  Given a file named "mylist.md" with:
5
5
  """
6
6
  Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
@@ -15,3 +15,14 @@ Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
15
15
  And I successfully run `taskmeister --list mylist.md`
16
16
  Then the output should not contain "Task one"
17
17
 
18
+ Scenario: Delete the task list when you remove the last task
19
+ Given a file named "mylist.md" with:
20
+ """
21
+ Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
22
+
23
+ > Notes line one
24
+ > Notes line two
25
+ """
26
+ When I successfully run `taskmeister --list mylist.md --done a`
27
+ Then the file "mylist.md" should not exist
28
+
@@ -0,0 +1,34 @@
1
+ Feature: taskmeister opens vim to edit your task list
2
+
3
+ Scenario: Edit entire 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
+ And I double `vim`
15
+ When I run `taskmeister --list mylist.md --edit`
16
+ Then the double `vim` should have been run with file "mylist.md"
17
+ And the exit status should be 0
18
+
19
+ Scenario: Edit specific task in the list
20
+ Given a file named "mylist.md" with:
21
+ """
22
+ Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
23
+
24
+ > Notes line one
25
+ > Notes line two
26
+
27
+ Task two - [id](ae0cce15-456d-48c0-a2e2-69d5f567e092)
28
+ Task three - [id](a5d4d3a9-2b9a-427a-9047-b47c6aec8f93)
29
+ """
30
+ And I double `vim`
31
+ When I run `taskmeister --list mylist.md --edit a`
32
+ Then the double `vim` should have been run with "+/aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8" and file "mylist.md"
33
+ And the exit status should be 0
34
+
@@ -1,6 +1,6 @@
1
1
  Feature: taskmeister lists the contents of a task list
2
2
 
3
- Scenario: Normal directory with explicit task list
3
+ Scenario: List tasks in list
4
4
  Given a file named "mylist.md" with:
5
5
  """
6
6
  Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
@@ -1,6 +1,6 @@
1
1
  Feature: taskmeister infers the name of your task list from your current project directory
2
2
 
3
- Scenario: Project directory with task list
3
+ Scenario: List tasks in list found from project directory
4
4
  Given a directory named "project"
5
5
  And a directory named "project/.git"
6
6
  And a directory named "project/child"
@@ -1,6 +1,6 @@
1
1
  Feature: taskmeister replaces a task in the list
2
2
 
3
- Scenario: Project directory with task list
3
+ Scenario: Replace text of task in list
4
4
  Given a file named "mylist.md" with:
5
5
  """
6
6
  Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
@@ -1,6 +1,6 @@
1
1
  Feature: taskmeister shows the details of a task in the list
2
2
 
3
- Scenario: Project directory with task list
3
+ Scenario: Show task in list
4
4
  Given a file named "mylist.md" with:
5
5
  """
6
6
  Task one - [id](aaf83a9b-02f7-4cc0-8ee1-4d98b98903b8)
@@ -0,0 +1,12 @@
1
+
2
+ Then(/^the double `([^`]*)` should have been run with file "(.*?)"$/) do |cmd, file|
3
+ in_current_dir {
4
+ expect(history).to include [cmd, Pathname.new(file).expand_path.to_s]
5
+ }
6
+ end
7
+
8
+ Then(/^the double `([^`]*)` should have been run with "(.*?)" and file "(.*?)"$/) do |cmd, arg, file|
9
+ in_current_dir {
10
+ expect(history).to include [cmd, arg, Pathname.new(file).expand_path.to_s]
11
+ }
12
+ end
@@ -2,6 +2,7 @@ require 'rubygems'
2
2
  require 'bundler/setup'
3
3
 
4
4
  require 'aruba/cucumber'
5
+ require 'aruba-doubles/cucumber'
5
6
 
6
7
  $LOAD_PATH << File.expand_path('../../../lib', __FILE__)
7
8
  require 'taskmeister'
@@ -10,67 +10,66 @@ module Taskmeister
10
10
  def execute!
11
11
  options = Options.new(@stdout, @kernel).parse(@argv)
12
12
 
13
- task_list_path = Pathname.new(options.task_dir) + task_list_name(options)
13
+ task_list = Taskmeister::TaskListReader.from_markdown_file(task_list_path(options))
14
14
 
15
- task_list = Taskmeister::TaskListReader.from_markdown_file(task_list_path)
16
-
17
- run_command(options, task_list_path, task_list)
15
+ run_command(options, task_list)
18
16
  end
19
17
 
20
18
  private
21
19
 
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)
20
+ def run_command(options, task_list)
34
21
  case options.command
35
22
  when Commands::LIST
36
23
  @stdout.puts task_list.to_short_list
37
24
 
38
25
  when Commands::SHOW
39
26
 
40
- @stdout.puts task_list.details(options.task_id)
27
+ @stdout.puts task_list.markdown_for(options.task_id)
41
28
 
42
29
  when Commands::EDIT
43
30
 
44
31
  task = task_list[options.task_id]
45
32
 
46
33
  search_path = task ? "+/#{task.id} " : ""
47
- system "vim #{search_path}#{task_list_path}"
34
+ system "vim #{search_path}#{task_list.file_path}"
48
35
 
49
36
  when Commands::ADD
50
37
 
51
- update_task_list(task_list, task_list_path) {
52
- task_list.add(Taskmeister::Task.create(options.task_text))
53
- }
38
+ task_list.add(Taskmeister::Task.create(options.task_text))
39
+ update task_list
54
40
 
55
41
  when Commands::DONE
56
42
 
57
- update_task_list(task_list, task_list_path) {
58
- task_list.complete options.task_id
59
- }
43
+ task_list.complete(options.task_id)
44
+ update task_list
60
45
 
61
46
  when Commands::REPLACE
62
47
 
63
- update_task_list(task_list, task_list_path) {
64
- task_list.replace options.task_id, options.task_text
65
- }
48
+ task_list.replace(options.task_id, options.task_text)
49
+ update task_list
66
50
 
67
51
  end
68
52
 
69
53
  @kernel.exit 0
70
54
  end
71
55
 
72
- def update_task_list(task_list, file_path)
73
- Taskmeister::TaskListWriter.to_markdown_file(task_list, file_path) if yield
56
+ def task_list_path(options)
57
+ Pathname.new(options.task_dir) + task_list_name(options)
58
+ end
59
+
60
+ def task_list_name(options)
61
+ task_list_name = options.list || TaskListName.from_project_dir(Pathname.getwd)
62
+
63
+ unless task_list_name
64
+ @stderr.puts "Could not find a project directory. Please specify a task list."
65
+ @kernel.exit 1
66
+ end
67
+
68
+ task_list_name
69
+ end
70
+
71
+ def update(task_list)
72
+ Taskmeister::TaskListWriter.to_markdown_file(task_list)
74
73
  end
75
74
  end
76
75
  end
@@ -86,8 +86,8 @@ module Taskmeister
86
86
 
87
87
  options.task_text = task_text.join(" ") unless task_text.empty?
88
88
 
89
- # If there is task text and the default command hasn't been overwritten
90
- # by the user, make the command add
89
+ # If there is TASK TEXT and the default command hasn't been overwritten
90
+ # by the user, set the command to ADD
91
91
  if !task_text.empty? and options.command == Commands::LIST
92
92
  options.command = Commands::ADD
93
93
  end
@@ -1,11 +1,17 @@
1
1
  module Taskmeister
2
2
  class TaskList
3
- def initialize(tasks)
3
+ attr_reader :file_path
4
+
5
+ def initialize(tasks, file_path)
6
+ @file_path = file_path
7
+
4
8
  @hash = {}
5
9
 
6
10
  tasks.each do |t|
7
11
  add(t)
8
12
  end
13
+
14
+ @dirty = false
9
15
  end
10
16
 
11
17
  def to_short_list
@@ -24,13 +30,23 @@ module Taskmeister
24
30
  @hash[key]
25
31
  end
26
32
 
33
+ def empty?
34
+ @hash.empty?
35
+ end
36
+
37
+ def dirty?
38
+ @dirty
39
+ end
40
+
27
41
  def add(task)
28
42
  prefix = assign_short_code_to_task(task)
29
43
  @hash[prefix] = task
44
+ @dirty = true
30
45
  end
31
46
 
32
47
  def complete(short_id)
33
- @hash.delete(short_id)
48
+ removed_val = @hash.delete(short_id)
49
+ @dirty = true if removed_val
34
50
  end
35
51
 
36
52
  def replace(short_id, new_text)
@@ -38,9 +54,10 @@ module Taskmeister
38
54
  return unless task
39
55
 
40
56
  @hash[short_id] = Task.new(new_text, task.id, task.notes)
57
+ @dirty = true
41
58
  end
42
59
 
43
- def details(short_id)
60
+ def markdown_for(short_id)
44
61
  return [] unless @hash.has_key?(short_id)
45
62
 
46
63
  self[short_id].to_markdown
@@ -1,6 +1,6 @@
1
1
  module Taskmeister
2
2
  class TaskListReader
3
- def self.from_markdown(file_lines)
3
+ def self.from_markdown(file_lines, file_path)
4
4
  grouped_lines = \
5
5
  file_lines.map(&:chomp)
6
6
  .reject(&:empty?)
@@ -10,16 +10,16 @@ module Taskmeister
10
10
  acc
11
11
  end
12
12
 
13
- tasks = grouped_lines.map do |l|
14
- Task.from_markdown(l)
13
+ tasks = grouped_lines.map do |ls|
14
+ Task.from_markdown ls
15
15
  end
16
16
 
17
- TaskList.new tasks
17
+ TaskList.new tasks, file_path
18
18
  end
19
19
 
20
- def self.from_markdown_file(path)
21
- lines = File.exist?(path) ? File.readlines(path) : []
22
- from_markdown lines
20
+ def self.from_markdown_file(file_path)
21
+ lines = File.exist?(file_path) ? File.readlines(file_path) : []
22
+ self.from_markdown lines, file_path
23
23
  end
24
24
  end
25
25
  end
@@ -4,9 +4,13 @@ module Taskmeister
4
4
  task_list.tasks.map(&:to_markdown).flatten
5
5
  end
6
6
 
7
- def self.to_markdown_file(task_list, file_path)
7
+ def self.to_markdown_file(task_list)
8
+ return unless task_list.dirty?
9
+
10
+ return task_list.file_path.delete if task_list.empty? && File.exist?(task_list.file_path)
11
+
8
12
  lines = self.to_markdown(task_list)
9
- File.open(file_path, "w") do |f|
13
+ File.open(task_list.file_path, "w") do |f|
10
14
  f.puts lines
11
15
  end
12
16
  end
@@ -1,3 +1,3 @@
1
1
  module Taskmeister
2
- VERSION = "0.9.0"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -11,14 +11,14 @@ module Taskmeister
11
11
  allow(TaskList).to receive(:new).and_return(double(TaskList))
12
12
  end
13
13
 
14
- let(:it) { described_class.from_markdown(lines) }
14
+ let(:it) { described_class.from_markdown(lines, "fake file") }
15
15
 
16
16
  describe "passed an empty list of lines" do
17
17
  let(:lines) { [] }
18
18
 
19
19
  it "creates an empty task list" do
20
20
  expect(Task).not_to receive(:from_markdown)
21
- expect(TaskList).to receive(:new).with([])
21
+ expect(TaskList).to receive(:new).with([], "fake file")
22
22
  it
23
23
  end
24
24
  end
@@ -16,7 +16,15 @@ module Taskmeister
16
16
  task1, task2, task3, task4, task5, task6, task7
17
17
  ]}
18
18
 
19
- let(:list) { described_class.new(tasks) }
19
+ let(:list) { described_class.new(tasks, "fake file") }
20
+
21
+ it "saves its file path" do
22
+ expect(list.file_path).to eq "fake file"
23
+ end
24
+
25
+ it "is initially clean" do
26
+ expect(list.dirty?).to eq false
27
+ end
20
28
 
21
29
  describe "#[]" do
22
30
  it "uses the shortest common prefix to index a task" do
@@ -49,34 +57,58 @@ module Taskmeister
49
57
  describe "#complete" do
50
58
  it "removes the identified task" do
51
59
  expect(list["7"]).to eq task1
52
- result = list.complete("7")
53
- expect(result).to be_truthy
60
+ list.complete("7")
54
61
  expect(list["7"]).to be_nil
55
62
  end
56
63
 
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
64
+ it "marks the list as dirty" do
65
+ list.complete("7")
66
+ expect(list.dirty?).to eq true
67
+ end
68
+
69
+ context "when removing a non-existent task" do
70
+ before do
71
+ list.complete("345")
72
+ end
73
+
74
+ it "doesn't change the list" do
75
+ expect(list.tasks.size).to eq tasks.size
76
+ end
77
+
78
+ it "is not marked as dirty" do
79
+ expect(list.dirty?).to eq false
80
+ end
61
81
  end
62
82
  end
63
83
 
64
84
  describe "#replace" do
65
85
  it "replaces the text of the specified task" do
66
- result = list.replace("7", "A new task text")
67
- expect(result).to be_truthy
86
+ list.replace("7", "A new task text")
68
87
  task = list["7"]
69
88
  expect(task.text).to eq "A new task text"
70
89
  end
71
90
 
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
91
+ it "marks the list as dirty" do
92
+ list.replace("7", "A new task text")
93
+ expect(list.dirty?).to eq true
94
+ end
95
+
96
+ context "when removing a non-existent task" do
97
+ before do
98
+ list.replace("345", "A new task text")
99
+ end
100
+
101
+ it "doesn't change the list" do
102
+ expect(list.tasks.size).to eq tasks.size
103
+ end
104
+
105
+ it "is not marked as dirty" do
106
+ expect(list.dirty?).to eq false
107
+ end
76
108
  end
77
109
  end
78
110
 
79
- describe "#details" do
111
+ describe "#markdown_for" do
80
112
  before do
81
113
  allow_any_instance_of(Task).to receive(:to_markdown).and_return([
82
114
  "line 1",
@@ -85,22 +117,29 @@ module Taskmeister
85
117
  end
86
118
 
87
119
  it "returns an empty list if the id doesn't exist" do
88
- expect(list.details("34")).to eq []
120
+ expect(list.markdown_for("34")).to eq []
89
121
  end
90
122
 
91
123
  it "returns the lines of a task" do
92
- expect(list.details("7")).to eq ["line 1", "line 2"]
124
+ expect(list.markdown_for("7")).to eq ["line 1", "line 2"]
93
125
  end
94
126
  end
95
127
 
96
128
  describe "#add" do
129
+ let(:task8) { Task.new("task 8", "f23891df0-97a5-4310-9b01-374983416af7", nil) }
130
+
131
+ before do
132
+ list.add(task8)
133
+ end
134
+
97
135
  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
136
  expect(list.tasks.size).to eq 8
102
137
  expect(list["f23"]).to eq task8
103
138
  end
139
+
140
+ it "marks the list as dirty" do
141
+ expect(list.dirty?).to eq true
142
+ end
104
143
  end
105
144
  end
106
145
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["ray.grasso@gmail.com"]
11
11
  spec.summary = %q{Another command line task manager.}
12
12
  spec.description = %q{Another command line task manager. You know, because I'm special.}
13
- spec.homepage = "https://www.github.com/grassdog/taskmeister"
13
+ spec.homepage = "https://github.com/grassdog/taskmeister"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -22,5 +22,6 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rake", "~> 10"
23
23
  spec.add_development_dependency "rspec", "~> 3.0"
24
24
  spec.add_development_dependency "aruba", "~> 0.6"
25
+ spec.add_development_dependency "aruba-doubles", "~> 1.2"
25
26
  spec.add_development_dependency "pry-byebug", "~> 1.3"
26
27
  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.9.0
4
+ version: 1.0.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-29 00:00:00.000000000 Z
11
+ date: 2014-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: aruba-doubles
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: pry-byebug
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -98,10 +112,12 @@ files:
98
112
  - bin/taskmeister
99
113
  - features/add.feature
100
114
  - features/done.feature
115
+ - features/edit.feature
101
116
  - features/list.feature
102
117
  - features/project_dir.feature
103
118
  - features/replace.feature
104
119
  - features/show.feature
120
+ - features/step_definitions/command_double_steps.rb
105
121
  - features/support/env.rb
106
122
  - lib/taskmeister.rb
107
123
  - lib/taskmeister/cli/main.rb
@@ -118,7 +134,7 @@ files:
118
134
  - spec/lib/taskmeister/task_spec.rb
119
135
  - spec/spec_helper.rb
120
136
  - taskmeister.gemspec
121
- homepage: https://www.github.com/grassdog/taskmeister
137
+ homepage: https://github.com/grassdog/taskmeister
122
138
  licenses:
123
139
  - MIT
124
140
  metadata: {}
@@ -145,10 +161,12 @@ summary: Another command line task manager.
145
161
  test_files:
146
162
  - features/add.feature
147
163
  - features/done.feature
164
+ - features/edit.feature
148
165
  - features/list.feature
149
166
  - features/project_dir.feature
150
167
  - features/replace.feature
151
168
  - features/show.feature
169
+ - features/step_definitions/command_double_steps.rb
152
170
  - features/support/env.rb
153
171
  - spec/lib/taskmeister/task_list_reader_spec.rb
154
172
  - spec/lib/taskmeister/task_list_spec.rb