todo.txt 0.0.3

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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +29 -0
  4. data/MIT-LICENSE +21 -0
  5. data/NOTES.md +0 -0
  6. data/README.md +11 -0
  7. data/lib/todo.rb +20 -0
  8. data/lib/todo/cli.rb +39 -0
  9. data/lib/todo/cli/archive.rb +39 -0
  10. data/lib/todo/cli/cmd.rb +26 -0
  11. data/lib/todo/cli/list.rb +42 -0
  12. data/lib/todo/cli/push.rb +42 -0
  13. data/lib/todo/cli/toggle.rb +22 -0
  14. data/lib/todo/data/item.rb +58 -0
  15. data/lib/todo/data/list.rb +64 -0
  16. data/lib/todo/data/matcher.rb +42 -0
  17. data/lib/todo/data/parser.rb +41 -0
  18. data/lib/todo/helpers/hash/compact.rb +13 -0
  19. data/lib/todo/helpers/hash/format.rb +13 -0
  20. data/lib/todo/helpers/hash/slice.rb +17 -0
  21. data/lib/todo/helpers/object/presence.rb +26 -0
  22. data/lib/todo/helpers/string/camelize.rb +16 -0
  23. data/lib/todo/src/file.rb +24 -0
  24. data/lib/todo/src/idonethis.rb +52 -0
  25. data/lib/todo/src/io.rb +29 -0
  26. data/lib/todo/support/http.rb +31 -0
  27. data/lib/todo/support/options_parser.rb +31 -0
  28. data/lib/todo/version.rb +3 -0
  29. data/lib/todo/view.rb +49 -0
  30. data/spec/spec_helper.rb +9 -0
  31. data/spec/support/io.rb +9 -0
  32. data/spec/todo/cli/archive_spec.rb +16 -0
  33. data/spec/todo/cli/list_spec.rb +13 -0
  34. data/spec/todo/cli/toggle_spec.rb +25 -0
  35. data/spec/todo/data/item_spec.rb +94 -0
  36. data/spec/todo/data/list_spec.rb +59 -0
  37. data/spec/todo/data/parser_spec.rb +27 -0
  38. data/spec/todo/helpers/hash/format_spec.rb +9 -0
  39. data/spec/todo/helpers/hash/slice_spec.rb +8 -0
  40. data/spec/todo/helpers/object/presence_spec.rb +42 -0
  41. data/spec/todo/helpers/string/string_spec.rb +7 -0
  42. data/spec/todo/src/file_spec.rb +33 -0
  43. data/spec/todo/src/io_spec.rb +18 -0
  44. data/spec/todo/view_spec.rb +17 -0
  45. data/todo.gemspec +20 -0
  46. data/todo.md +10 -0
  47. metadata +89 -0
@@ -0,0 +1,13 @@
1
+ require 'todo/cli/list'
2
+
3
+ describe Todo::Cli::List do
4
+ let(:lines) { ['- foo [1]', 'x bar done:2015-12-01 [2]'] }
5
+ let(:io) { Support::Io.new(lines.join("\n")) }
6
+ let(:out) { Support::Io.new }
7
+ let(:opts) { { in: io, out: out } }
8
+
9
+ subject { described_class.new(nil, opts) }
10
+ before { subject.run }
11
+
12
+ it { expect(out.readlines).to eq ['foo', '2015-12-01 bar'] }
13
+ end
@@ -0,0 +1,25 @@
1
+ require 'todo/cli/toggle'
2
+
3
+ describe Todo::Cli::Toggle do
4
+ let(:io) { Support::Io.new(lines.join("\n")) }
5
+ let(:out) { Support::Io.new }
6
+ let(:opts) { { in: io, out: out } }
7
+
8
+ subject { described_class.new(['- foo [1]'], opts) }
9
+ before { subject.run }
10
+
11
+ describe 'with a pending line' do
12
+ let(:lines) { ['- foo [1]', 'x bar done:2015-12-01 [2]'] }
13
+ it { expect(out.readlines).to eq ['x foo done:2015-12-01 [1]', 'x bar done:2015-12-01 [2]'] }
14
+ end
15
+
16
+ describe 'with a done line' do
17
+ let(:lines) { ['x foo done:2015-12-01 [1]', 'x bar done:2015-12-01 [2]'] }
18
+ it { expect(out.readlines).to eq ['- foo [1]', 'x bar done:2015-12-01 [2]'] }
19
+ end
20
+
21
+ describe 'does not touch other lines' do
22
+ let(:lines) { ['# FOO', '', 'x foo done:2015-12-01 [1]', ' comment'] }
23
+ it { expect(out.readlines).to eq ['# FOO', '', '- foo [1]', ' comment'] }
24
+ end
25
+ end
@@ -0,0 +1,94 @@
1
+ require 'todo/data/item'
2
+
3
+ describe Todo::Data::Item do
4
+ let(:data) { { id: 1, status: :done, text: 'foo +bar', tags: { done: '2015-12-01' } } }
5
+ subject { described_class.new(data) }
6
+
7
+ it { expect(subject.id).to eq data[:id] }
8
+ it { expect(subject.status).to eq data[:status] }
9
+ it { expect(subject.text).to eq data[:text] }
10
+ it { expect(subject.tags).to eq data[:tags] }
11
+
12
+ describe 'done?' do
13
+ describe 'when status is :done' do
14
+ let(:data) { { status: :done } }
15
+ it { should be_done }
16
+ end
17
+
18
+ describe 'when status is not :done' do
19
+ let(:data) { { status: :pend } }
20
+ it { should_not be_done }
21
+ end
22
+ end
23
+
24
+ describe 'done_date' do
25
+ describe 'given a :done tag' do
26
+ let(:data) { { tags: { done: '2015-12-01' } } }
27
+ it { expect(subject.done_date).to eq '2015-12-01' }
28
+ end
29
+
30
+ describe 'given no :done tag' do
31
+ let(:data) { { tags: {} } }
32
+ it { expect(subject.done_date).to be_nil }
33
+ end
34
+ end
35
+
36
+ describe 'due_date' do
37
+ describe 'given a :due tag' do
38
+ let(:data) { { tags: { due: '2015-12-01' } } }
39
+ it { expect(subject.due_date).to eq '2015-12-01' }
40
+ end
41
+
42
+ describe 'given no :due tag' do
43
+ let(:data) { { tags: {} } }
44
+ it { expect(subject.due_date).to be_nil }
45
+ end
46
+ end
47
+
48
+ describe 'projects' do
49
+ let(:data) { { text: '+foo text +bar text +baz' } }
50
+ it { expect(subject.projects).to eq %w(foo bar baz) }
51
+ end
52
+
53
+ describe 'toggle' do
54
+ before { subject.toggle }
55
+
56
+ describe 'given a pending item' do
57
+ let(:data) { { status: :pend } }
58
+ it { expect(subject.status).to eq :done }
59
+ it { expect(subject.done_date).to eq '2015-12-01' }
60
+ end
61
+
62
+ describe 'given a done item' do
63
+ let(:data) { { status: :done, tags: { done: '2015-12-01' } } }
64
+ it { expect(subject.status).to eq :pend }
65
+ it { expect(subject.done_date).to be_nil }
66
+ end
67
+ end
68
+
69
+ describe 'matches?' do
70
+ describe 'given an id' do
71
+ describe 'matches' do
72
+ let(:other) { { id: 1, text: 'does not match' } }
73
+ it { expect(subject.matches?(other)).to be true }
74
+ end
75
+
76
+ describe 'does not match' do
77
+ let(:other) { { id: 2, text: 'does not match' } }
78
+ it { expect(subject.matches?(other)).to be false }
79
+ end
80
+ end
81
+
82
+ describe 'given a text' do
83
+ describe 'matches' do
84
+ let(:other) { { text: 'foo +bar' } }
85
+ it { expect(subject.matches?(other)).to be true }
86
+ end
87
+
88
+ describe 'does not match' do
89
+ let(:other) { { text: 'does not match' } }
90
+ it { expect(subject.matches?(other)).to be false }
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,59 @@
1
+ require 'todo/data/list'
2
+
3
+ describe Todo::Data::List do
4
+ let(:items) { data.map { |data| Todo::Data::Item.new(data) } }
5
+ subject { described_class.new(items) }
6
+
7
+ describe 'ids' do
8
+ let(:data) { [{ id: 1 }] }
9
+ it { expect(subject.ids).to eq [1] }
10
+ end
11
+
12
+ describe 'max_id' do
13
+ describe 'with a known id' do
14
+ let(:data) { [{ id: 1 }] }
15
+ it { expect(subject.max_id).to eq 1 }
16
+ end
17
+
18
+ describe 'with an empty list' do
19
+ let(:data) { [] }
20
+ it { expect(subject.max_id).to eq 0 }
21
+ end
22
+ end
23
+
24
+ describe 'next_id' do
25
+ describe 'with a known id' do
26
+ let(:data) { [{ id: 1 }] }
27
+ it { expect(subject.next_id).to eq 2 }
28
+ end
29
+
30
+ describe 'with an empty list' do
31
+ let(:data) { [] }
32
+ it { expect(subject.next_id).to eq 1 }
33
+ end
34
+ end
35
+
36
+ describe 'toggle' do
37
+ describe 'given a pending line' do
38
+ let(:data) { [ { id: 1, status: :pend }] }
39
+ before { subject.toggle(id: 1) }
40
+ it { expect(subject.send(:items).first.status).to eq :done }
41
+ end
42
+
43
+ describe 'given a done line' do
44
+ let(:data) { [ { id: 1, status: :done }] }
45
+ before { subject.toggle(id: 1) }
46
+ it { expect(subject.send(:items).first.status).to eq :pend }
47
+ end
48
+
49
+ describe 'given multiple matching items' do
50
+ let(:data) { [{ text: 'foo bar' }, { text: 'foo baz' }] }
51
+ it { expect { subject.toggle(text: 'foo') }.to raise_error(Todo::Error, 'Multiple items found for: text=foo') }
52
+ end
53
+
54
+ describe 'no matching item' do
55
+ let(:data) { [{ text: 'buz' }] }
56
+ it { expect { subject.toggle(text: 'foo') }.to raise_error(Todo::Error, 'Could not find item for: text=foo') }
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,27 @@
1
+ require 'todo/data/parser'
2
+
3
+ describe Todo::Data::Parser do
4
+ let(:data) { described_class.new(line).parse }
5
+
6
+ shared_examples_for 'parses the line' do |data|
7
+ it { expect(data[:id]).to eq data[:id] }
8
+ it { expect(data[:text]).to eq data[:text] }
9
+ it { expect(data[:tags]).to eq data[:tags] }
10
+ it { expect(data[:status]).to eq data[:status] }
11
+ end
12
+
13
+ describe 'given a pending line' do
14
+ let(:line) { '- foo +bar due:2015-12-01 [1]' }
15
+ include_examples 'parses the line', id: 1, status: :pend, text: 'foo +bar', tags: { due: '2015-12-01' }
16
+ end
17
+
18
+ describe 'given a done line' do
19
+ let(:line) { 'x foo +bar done:2015-12-01 [1]' }
20
+ include_examples 'parses the line', id: 1, status: :done, text: 'foo +bar', tags: { done: '2015-12-01' }
21
+ end
22
+
23
+ describe 'given a non-todo line' do
24
+ let(:line) { '## foo bar' }
25
+ include_examples 'parses the line', text: '## foo bar', tags: {}
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ require 'todo/helpers/hash/format'
2
+
3
+ describe Todo::Helpers::Hash::Format do
4
+ let(:hash) { { foo: 'foo', bar: 'bar' } }
5
+ subject { described_class }
6
+
7
+ it { expect(subject.to_pairs(hash)).to eq ['foo=foo', 'bar=bar'] }
8
+ it { expect(subject.to_pairs(hash, ':')).to eq ['foo:foo', 'bar:bar'] }
9
+ end
@@ -0,0 +1,8 @@
1
+ require 'todo/helpers/hash/slice'
2
+
3
+ describe Todo::Helpers::Hash::Slice do
4
+ let(:hash) { { foo: 'foo', bar: 'bar' } }
5
+ subject { described_class }
6
+
7
+ it { expect(subject.slice(hash, :foo, :baz)).to eq(foo: 'foo') }
8
+ end
@@ -0,0 +1,42 @@
1
+ require 'todo/helpers/object/presence'
2
+
3
+ describe Todo::Helpers::Object::Presence do
4
+ subject { described_class }
5
+
6
+ describe 'present?' do
7
+ it { expect(subject.present?(nil)).to be false }
8
+ it { expect(subject.present?(true)).to be true }
9
+ it { expect(subject.present?(false)).to be false }
10
+
11
+ it { expect(subject.present?(1)).to be true }
12
+ it { expect(subject.present?(1.1)).to be true }
13
+
14
+ it { expect(subject.present?([])).to be false }
15
+ it { expect(subject.present?([1])).to be true }
16
+
17
+ it { expect(subject.present?({})).to be false }
18
+ it { expect(subject.present?(foo: :bar)).to be true }
19
+
20
+ it { expect(subject.present?('')).to be false }
21
+ it { expect(subject.present?('foo')).to be true }
22
+ end
23
+
24
+ describe 'blank?' do
25
+ it { expect(subject.blank?(nil)).to be true }
26
+ it { expect(subject.blank?(true)).to be false }
27
+ it { expect(subject.blank?(false)).to be true }
28
+
29
+ it { expect(subject.blank?(1)).to be false }
30
+ it { expect(subject.blank?(1.1)).to be false }
31
+
32
+ it { expect(subject.blank?([])).to be true }
33
+ it { expect(subject.blank?([1])).to be false }
34
+
35
+ it { expect(subject.blank?({})).to be true }
36
+ it { expect(subject.blank?(foo: :bar)).to be false }
37
+
38
+ it { expect(subject.blank?('')).to be true }
39
+ it { expect(subject.blank?('foo')).to be false }
40
+ end
41
+ end
42
+
@@ -0,0 +1,7 @@
1
+ require 'todo/helpers/string/camelize'
2
+
3
+ describe Todo::Helpers::String::Camelize do
4
+ subject { described_class }
5
+
6
+ it { expect(subject.camelize('foo_bar')).to eq 'FooBar' }
7
+ end
@@ -0,0 +1,33 @@
1
+ require 'fileutils'
2
+ require 'todo/src/file'
3
+
4
+ describe Todo::Src::File do
5
+ let(:mode) {}
6
+ let(:path) { '/tmp/todo.test.txt' }
7
+ let(:lines) { ['- foo [1]', 'x bar done:2015-12-01 [2]'] }
8
+
9
+ subject { described_class.new(path, mode: mode) }
10
+
11
+ describe 'read' do
12
+ before { File.open(path, 'w+') { |f| f.puts(lines.join("\n")) } }
13
+ it { expect(subject.read).to eq lines }
14
+ end
15
+
16
+ describe 'write' do
17
+ before { File.open(path, 'w+') { |f| f.puts('- buz') } }
18
+ before { subject.write(lines) }
19
+ after { FileUtils.rm_f(path) }
20
+
21
+ describe 'mode a+' do
22
+ let(:mode) { 'a+' }
23
+ it { expect(File.exists?(path)).to be true }
24
+ it { expect(File.read(path)).to eq "- buz\n#{lines.join("\n")}\n" }
25
+ end
26
+
27
+ describe 'mode w+' do
28
+ let(:mode) { 'w+' }
29
+ it { expect(File.exists?(path)).to be true }
30
+ it { expect(File.read(path)).to eq "#{lines.join("\n")}\n" }
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ require 'todo/src/io'
2
+
3
+ describe Todo::Src::Io do
4
+ let!(:io) { Support::Io.new }
5
+ let(:lines) { ['- foo [1]', 'x bar done:2015-12-01 [2]'] }
6
+
7
+ subject { described_class.new(in: io, out: io) }
8
+
9
+ describe 'read' do
10
+ before { io.puts(lines.join("\n")) }
11
+ it { expect(subject.read).to eq lines }
12
+ end
13
+
14
+ describe 'write' do
15
+ before { subject.write(lines) }
16
+ it { expect(io.string).to eq "#{lines.join("\n")}\n" }
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ require 'todo/view'
2
+
3
+ describe Todo::View do
4
+ let(:lines) { ['- foo [1]', 'x bar done:2015-12-01 [2]'] }
5
+ let(:items) { Todo::Data::List.parse(lines).items }
6
+ subject { described_class.new(items, cols) }
7
+
8
+ describe 'default columns' do
9
+ let(:cols) {}
10
+ it { expect(subject.render).to eq(lines) }
11
+ end
12
+
13
+ describe 'selected columns' do
14
+ let(:cols) { [:done_date, :text] }
15
+ it { expect(subject.render).to eq(['foo', '2015-12-01 bar']) }
16
+ end
17
+ end
data/todo.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.expand_path('../lib', __FILE__)
4
+ require 'todo/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'todo.txt'
8
+ s.version = Todo::VERSION
9
+ s.authors = ['Sven Fuchs']
10
+ s.email = 'me@svenfuchs.com'
11
+ s.homepage = 'https://github.com/svenfuchs/todo.txt'
12
+ s.summary = 'My flavor of todo.txt'
13
+ s.description = "#{s.summary}."
14
+ s.licenses = ['MIT']
15
+
16
+ s.files = Dir['{lib/**/*,spec/**/*,[A-Z]*}']
17
+ s.platform = Gem::Platform::RUBY
18
+ s.require_paths = ['lib']
19
+ s.rubyforge_project = '[none]'
20
+ end
data/todo.md ADDED
@@ -0,0 +1,10 @@
1
+ # Hub
2
+
3
+ x Deploy @hub done:2015-11-09
4
+ x Try @hub done:2015-11-13
5
+
6
+ # Tasks
7
+
8
+ - Deploy @tasks
9
+
10
+
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: todo.txt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Sven Fuchs
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: My flavor of todo.txt.
14
+ email: me@svenfuchs.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - Gemfile
20
+ - Gemfile.lock
21
+ - MIT-LICENSE
22
+ - NOTES.md
23
+ - README.md
24
+ - lib/todo.rb
25
+ - lib/todo/cli.rb
26
+ - lib/todo/cli/archive.rb
27
+ - lib/todo/cli/cmd.rb
28
+ - lib/todo/cli/list.rb
29
+ - lib/todo/cli/push.rb
30
+ - lib/todo/cli/toggle.rb
31
+ - lib/todo/data/item.rb
32
+ - lib/todo/data/list.rb
33
+ - lib/todo/data/matcher.rb
34
+ - lib/todo/data/parser.rb
35
+ - lib/todo/helpers/hash/compact.rb
36
+ - lib/todo/helpers/hash/format.rb
37
+ - lib/todo/helpers/hash/slice.rb
38
+ - lib/todo/helpers/object/presence.rb
39
+ - lib/todo/helpers/string/camelize.rb
40
+ - lib/todo/src/file.rb
41
+ - lib/todo/src/idonethis.rb
42
+ - lib/todo/src/io.rb
43
+ - lib/todo/support/http.rb
44
+ - lib/todo/support/options_parser.rb
45
+ - lib/todo/version.rb
46
+ - lib/todo/view.rb
47
+ - spec/spec_helper.rb
48
+ - spec/support/io.rb
49
+ - spec/todo/cli/archive_spec.rb
50
+ - spec/todo/cli/list_spec.rb
51
+ - spec/todo/cli/toggle_spec.rb
52
+ - spec/todo/data/item_spec.rb
53
+ - spec/todo/data/list_spec.rb
54
+ - spec/todo/data/parser_spec.rb
55
+ - spec/todo/helpers/hash/format_spec.rb
56
+ - spec/todo/helpers/hash/slice_spec.rb
57
+ - spec/todo/helpers/object/presence_spec.rb
58
+ - spec/todo/helpers/string/string_spec.rb
59
+ - spec/todo/src/file_spec.rb
60
+ - spec/todo/src/io_spec.rb
61
+ - spec/todo/view_spec.rb
62
+ - todo.gemspec
63
+ - todo.md
64
+ homepage: https://github.com/svenfuchs/todo.txt
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project: "[none]"
84
+ rubygems_version: 2.4.5
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: My flavor of todo.txt
88
+ test_files: []
89
+ has_rdoc: