todo.txt 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +29 -0
- data/MIT-LICENSE +21 -0
- data/NOTES.md +0 -0
- data/README.md +11 -0
- data/lib/todo.rb +20 -0
- data/lib/todo/cli.rb +39 -0
- data/lib/todo/cli/archive.rb +39 -0
- data/lib/todo/cli/cmd.rb +26 -0
- data/lib/todo/cli/list.rb +42 -0
- data/lib/todo/cli/push.rb +42 -0
- data/lib/todo/cli/toggle.rb +22 -0
- data/lib/todo/data/item.rb +58 -0
- data/lib/todo/data/list.rb +64 -0
- data/lib/todo/data/matcher.rb +42 -0
- data/lib/todo/data/parser.rb +41 -0
- data/lib/todo/helpers/hash/compact.rb +13 -0
- data/lib/todo/helpers/hash/format.rb +13 -0
- data/lib/todo/helpers/hash/slice.rb +17 -0
- data/lib/todo/helpers/object/presence.rb +26 -0
- data/lib/todo/helpers/string/camelize.rb +16 -0
- data/lib/todo/src/file.rb +24 -0
- data/lib/todo/src/idonethis.rb +52 -0
- data/lib/todo/src/io.rb +29 -0
- data/lib/todo/support/http.rb +31 -0
- data/lib/todo/support/options_parser.rb +31 -0
- data/lib/todo/version.rb +3 -0
- data/lib/todo/view.rb +49 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/io.rb +9 -0
- data/spec/todo/cli/archive_spec.rb +16 -0
- data/spec/todo/cli/list_spec.rb +13 -0
- data/spec/todo/cli/toggle_spec.rb +25 -0
- data/spec/todo/data/item_spec.rb +94 -0
- data/spec/todo/data/list_spec.rb +59 -0
- data/spec/todo/data/parser_spec.rb +27 -0
- data/spec/todo/helpers/hash/format_spec.rb +9 -0
- data/spec/todo/helpers/hash/slice_spec.rb +8 -0
- data/spec/todo/helpers/object/presence_spec.rb +42 -0
- data/spec/todo/helpers/string/string_spec.rb +7 -0
- data/spec/todo/src/file_spec.rb +33 -0
- data/spec/todo/src/io_spec.rb +18 -0
- data/spec/todo/view_spec.rb +17 -0
- data/todo.gemspec +20 -0
- data/todo.md +10 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7408515630ff0a7a199d208e569d5af69a0a9b07
|
4
|
+
data.tar.gz: fe754ec5f2d4d9c0c1bb99bfec0832bfeeff7f09
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4ee0e1ce12f4c1a5b06cd06e0ae551df1f81d9a8a1be0bd14a23c46054e7d6cad2c557667b1397775a8f0ffc5cef6af5b919c84b3df6db956cb4ad8fb24a3e21
|
7
|
+
data.tar.gz: da17c317209c29584e18fe58a2c34cd1769dc93bb3242d84cfbdb2871d1b4a8dd731aac551ccdcce04e61010ae59f198027546f2a31345277cf15bbf811e7b1c
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
capture_stdout (0.0.1)
|
5
|
+
diff-lcs (1.2.5)
|
6
|
+
metaclass (0.0.4)
|
7
|
+
mocha (1.1.0)
|
8
|
+
metaclass (~> 0.0.1)
|
9
|
+
rspec (3.3.0)
|
10
|
+
rspec-core (~> 3.3.0)
|
11
|
+
rspec-expectations (~> 3.3.0)
|
12
|
+
rspec-mocks (~> 3.3.0)
|
13
|
+
rspec-core (3.3.2)
|
14
|
+
rspec-support (~> 3.3.0)
|
15
|
+
rspec-expectations (3.3.1)
|
16
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
17
|
+
rspec-support (~> 3.3.0)
|
18
|
+
rspec-mocks (3.3.2)
|
19
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
20
|
+
rspec-support (~> 3.3.0)
|
21
|
+
rspec-support (3.3.0)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
capture_stdout
|
28
|
+
mocha
|
29
|
+
rspec
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2015 Sven Fuchs <me@svenfuchs.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/NOTES.md
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# TODO.txt
|
2
|
+
|
3
|
+
My version of the [Todo.txt](https://github.com/ginatrapani/todo.txt-cli/wiki/The-Todo.txt-Format) format.
|
4
|
+
|
5
|
+
Integration:
|
6
|
+
|
7
|
+
* Vim mapping to [toggle](https://github.com/svenfuchs/vim-todo.txt/blob/master/ftplugin/todo.vim#L1) a todo item status
|
8
|
+
* Vim mapping to [push](https://github.com/svenfuchs/vim-todo.txt/blob/master/ftplugin/todo.vim#L2) done items to idonethis
|
9
|
+
* Vim mapping to [archive](https://github.com/svenfuchs/vim-todo.txt/blob/master/ftplugin/todo.vim#L3) done items to a separate file
|
10
|
+
* [launchctl](https://github.com/svenfuchs/todo.txt/blob/master/etc/me.todo-watch.plist) to `fswatch` the file, and [git push](https://github.com/svenfuchs/todo.txt/blob/master/bin/push) changes to a Gist
|
11
|
+
|
data/lib/todo.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Todo
|
2
|
+
MSGS = {
|
3
|
+
unknown_cmd: 'Unknown command %p',
|
4
|
+
item_not_found: 'Could not find item for: %s',
|
5
|
+
multiple_items: 'Multiple items found for: %s'
|
6
|
+
}
|
7
|
+
|
8
|
+
DATES = {
|
9
|
+
two_weeks_ago: (Time.now - 60 * 60 * 24 * 14).strftime('%Y-%m-%d'),
|
10
|
+
yesterday: (Time.now - 60 * 60 * 24).strftime('%Y-%m-%d'),
|
11
|
+
today: Time.now.strftime('%Y-%m-%d')
|
12
|
+
}
|
13
|
+
|
14
|
+
STATUSES = {
|
15
|
+
done: 'x',
|
16
|
+
pend: '-'
|
17
|
+
}
|
18
|
+
|
19
|
+
Error = Class.new(StandardError)
|
20
|
+
end
|
data/lib/todo/cli.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'todo'
|
3
|
+
require 'todo/cli/archive'
|
4
|
+
require 'todo/cli/list'
|
5
|
+
require 'todo/cli/push'
|
6
|
+
require 'todo/cli/toggle'
|
7
|
+
require 'todo/helpers/string/camelize'
|
8
|
+
|
9
|
+
module Todo
|
10
|
+
class Cli
|
11
|
+
include Helpers::String::Camelize
|
12
|
+
|
13
|
+
attr_reader :cmd, :args, :opts
|
14
|
+
|
15
|
+
def initialize(args)
|
16
|
+
@args = args
|
17
|
+
@cmd = @args.shift || raise('No command given')
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
args, opts = const.parse(self.args)
|
22
|
+
const.new(args, opts).run
|
23
|
+
rescue Error => e
|
24
|
+
abort "Error: #{e.message}"
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def normalize_date(date)
|
30
|
+
DATES[date.to_sym] ? DATES[date.to_sym] : date
|
31
|
+
end
|
32
|
+
|
33
|
+
def const
|
34
|
+
@const ||= Cli.const_get(camelize(cmd))
|
35
|
+
rescue NameError
|
36
|
+
fail Error.new(MSGS[:unknown_cmd] % cmd)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'todo/cli/cmd'
|
2
|
+
|
3
|
+
module Todo
|
4
|
+
class Cli
|
5
|
+
class Archive < Cmd
|
6
|
+
opt '-a', '--archive FILENAME', 'Archive filename' do |opts, file|
|
7
|
+
opts[:archive] = file
|
8
|
+
end
|
9
|
+
|
10
|
+
opt '-b', '--before DATE', 'Before date' do |opts, date|
|
11
|
+
opts[:before] = normalize_date(date)
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
items = list.select(status: :done, before: before).items
|
16
|
+
archive.write(render(items))
|
17
|
+
io.write(render(list.items - items))
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def list
|
23
|
+
@list ||= Data::List.parse(io.read)
|
24
|
+
end
|
25
|
+
|
26
|
+
def archive
|
27
|
+
@archive ||= Src::File.new(archive_path, mode: 'a+')
|
28
|
+
end
|
29
|
+
|
30
|
+
def archive_path
|
31
|
+
opts[:archive] || File.expand_path('../archive.txt', opts[:file])
|
32
|
+
end
|
33
|
+
|
34
|
+
def before
|
35
|
+
opts[:before] || DATES[:two_weeks_ago]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/todo/cli/cmd.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'todo/helpers/hash/slice'
|
2
|
+
require 'todo/src/file'
|
3
|
+
require 'todo/src/io'
|
4
|
+
require 'todo/support/options_parser'
|
5
|
+
require 'todo/view'
|
6
|
+
|
7
|
+
module Todo
|
8
|
+
class Cli
|
9
|
+
class Cmd < Struct.new(:args, :opts)
|
10
|
+
extend Support::OptionsParser
|
11
|
+
include Helpers::Hash::Slice
|
12
|
+
|
13
|
+
opt '-f', '--file FILENAME', 'Filename' do |opts, file|
|
14
|
+
opts[:file] = file
|
15
|
+
end
|
16
|
+
|
17
|
+
def io
|
18
|
+
opts[:file] ? Src::File.new(opts[:file]) : Src::Io.new(slice(opts, :in, :out))
|
19
|
+
end
|
20
|
+
|
21
|
+
def render(list, cols = nil)
|
22
|
+
View.new(list, cols).render
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'todo/cli/cmd'
|
2
|
+
require 'todo/data/list'
|
3
|
+
|
4
|
+
module Todo
|
5
|
+
class Cli
|
6
|
+
class List < Cmd
|
7
|
+
opt '-s', '--since DATE', 'Since date' do |date|
|
8
|
+
opts[:since] = normalize_date(date)
|
9
|
+
end
|
10
|
+
|
11
|
+
opt '-b', '--before DATE', 'Before date' do |date|
|
12
|
+
opts[:before] = normalize_date(date)
|
13
|
+
end
|
14
|
+
|
15
|
+
opt '--status STATUS', 'Status' do |status|
|
16
|
+
opts[:status] = status
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
out.write(render(list.items, [:done_date, :text]))
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def list
|
26
|
+
list = Data::List.parse(io.read)
|
27
|
+
list = list.select(data)
|
28
|
+
list.sort_by { |item| item.done_date.to_s }
|
29
|
+
end
|
30
|
+
|
31
|
+
def data
|
32
|
+
data = slice(opts, :status, :before, :since)
|
33
|
+
# data = data.merge(text: args.first)
|
34
|
+
data
|
35
|
+
end
|
36
|
+
|
37
|
+
def out
|
38
|
+
Src::Io.new(out: opts[:out])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'todo'
|
2
|
+
require 'todo/cli/cmd'
|
3
|
+
require 'todo/data/list'
|
4
|
+
require 'todo/src/idonethis'
|
5
|
+
|
6
|
+
module Todo
|
7
|
+
class Cli
|
8
|
+
class Push < Cmd
|
9
|
+
opt '-s', '--since DATE', 'Since date' do |date|
|
10
|
+
opts[:since] = normalize_date(date)
|
11
|
+
end
|
12
|
+
|
13
|
+
CONFIG = {
|
14
|
+
team: ENV['IDONETHIS_TEAM'],
|
15
|
+
username: ENV['IDONETHIS_USERNAME'],
|
16
|
+
token: ENV['IDONETHIS_TOKEN']
|
17
|
+
}
|
18
|
+
|
19
|
+
def run
|
20
|
+
lines = render(list.items, [:text, :tags, :id])
|
21
|
+
src.write(lines)
|
22
|
+
io.write(lines)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def list
|
28
|
+
list = Data::List.parse(io.read)
|
29
|
+
list = list.select(status: :done, since: since)
|
30
|
+
list.reject { |item| store.include?(item) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def src
|
34
|
+
Src::Idonethis.new(config, since: since)
|
35
|
+
end
|
36
|
+
|
37
|
+
def since
|
38
|
+
opts[:since] || DATES[:yesterday]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'todo/cli/cmd'
|
2
|
+
require 'todo/data/list'
|
3
|
+
require 'todo/data/parser'
|
4
|
+
|
5
|
+
module Todo
|
6
|
+
class Cli
|
7
|
+
class Toggle < Cmd
|
8
|
+
def run
|
9
|
+
list = Data::List.parse(io.read)
|
10
|
+
list.toggle(data)
|
11
|
+
io.write(render(list.items))
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def data
|
17
|
+
data = Data::Parser.new(args.first).parse
|
18
|
+
slice(data, :id, :text)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'todo/data/matcher'
|
2
|
+
|
3
|
+
module Todo
|
4
|
+
module Data
|
5
|
+
class Item < Struct.new(:data)
|
6
|
+
PROJECT = /\s*\+([\w\-]+)/
|
7
|
+
|
8
|
+
def initialize(data)
|
9
|
+
data[:tags] ||= {}
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
[:id, :status, :tags, :text].each do |name|
|
14
|
+
define_method(name) { data[name] }
|
15
|
+
end
|
16
|
+
|
17
|
+
def done?
|
18
|
+
status == :done
|
19
|
+
end
|
20
|
+
|
21
|
+
def due_date
|
22
|
+
tags[:due].to_s if tags[:due]
|
23
|
+
end
|
24
|
+
|
25
|
+
def done_date
|
26
|
+
tags[:done].to_s if tags[:done]
|
27
|
+
end
|
28
|
+
|
29
|
+
def projects
|
30
|
+
@projects ||= text.scan(PROJECT).flatten
|
31
|
+
end
|
32
|
+
|
33
|
+
def toggle
|
34
|
+
done? ? pend : done
|
35
|
+
end
|
36
|
+
|
37
|
+
def matches?(data)
|
38
|
+
Matcher.new(self, data).matches?
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def done
|
44
|
+
data[:status] = :done
|
45
|
+
data[:tags][:done] = today
|
46
|
+
end
|
47
|
+
|
48
|
+
def pend
|
49
|
+
data[:status] = :pend
|
50
|
+
data[:tags].delete(:done)
|
51
|
+
end
|
52
|
+
|
53
|
+
def today
|
54
|
+
Time.now.strftime('%Y-%m-%d')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'todo'
|
3
|
+
require 'todo/data/item'
|
4
|
+
require 'todo/data/parser'
|
5
|
+
require 'todo/helpers/hash/format'
|
6
|
+
|
7
|
+
module Todo
|
8
|
+
module Data
|
9
|
+
class List < Struct.new(:items)
|
10
|
+
class << self
|
11
|
+
def parse(lines)
|
12
|
+
List.new(lines.map { |line| Item.new(Parser.new(line).parse) })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
extend Forwardable
|
17
|
+
include Helpers::Hash::Format
|
18
|
+
|
19
|
+
def_delegators :items, :size, :first
|
20
|
+
|
21
|
+
attr_accessor :max_id
|
22
|
+
|
23
|
+
def initialize(*)
|
24
|
+
super
|
25
|
+
@max_id = items.map(&:id).map(&:to_i).max || 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def toggle(data)
|
29
|
+
find(data).toggle
|
30
|
+
end
|
31
|
+
|
32
|
+
def select(data)
|
33
|
+
self.class.new(items.select { |item| item.matches?(data) })
|
34
|
+
end
|
35
|
+
|
36
|
+
def reject(&block)
|
37
|
+
self.class.new(items.reject(&block))
|
38
|
+
end
|
39
|
+
|
40
|
+
def sort_by(&block)
|
41
|
+
self.class.new(items.sort_by(&block))
|
42
|
+
end
|
43
|
+
|
44
|
+
def find(data)
|
45
|
+
select(data).tap { |list| validate(data, list) }.first
|
46
|
+
end
|
47
|
+
|
48
|
+
def ids
|
49
|
+
items.map(&:id).compact
|
50
|
+
end
|
51
|
+
|
52
|
+
def next_id
|
53
|
+
@max_id += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def validate(data, list)
|
59
|
+
raise Error.new(MSGS[:item_not_found] % to_pairs(data)) if list.size == 0
|
60
|
+
raise Error.new(MSGS[:multiple_items] % to_pairs(data)) if list.size > 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|