markdo 0.1.12.alpha → 0.2.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/.gitignore +1 -0
- data/.travis.yml +15 -9
- data/Dockerfile +21 -7
- data/Guardfile +11 -0
- data/README.md +12 -7
- data/Rakefile +11 -7
- data/bin/markdo +1 -1
- data/docker-compose.yml +9 -0
- data/lib/markdo/cli.rb +23 -55
- data/lib/markdo/command_support.rb +14 -0
- data/lib/markdo/commands.rb +16 -0
- data/lib/markdo/{add_command.rb → commands/add_command.rb} +2 -6
- data/lib/markdo/commands/command.rb +33 -0
- data/lib/markdo/{edit_command.rb → commands/edit_command.rb} +2 -2
- data/lib/markdo/commands/forecast_command.rb +41 -0
- data/lib/markdo/{help_command.rb → commands/help_command.rb} +7 -8
- data/lib/markdo/commands/ics_command.rb +15 -0
- data/lib/markdo/commands/inbox_command.rb +11 -0
- data/lib/markdo/commands/overdue_command.rb +11 -0
- data/lib/markdo/commands/overview_command.rb +16 -0
- data/lib/markdo/commands/process_command.rb +91 -0
- data/lib/markdo/commands/query_command.rb +14 -0
- data/lib/markdo/commands/star_command.rb +11 -0
- data/lib/markdo/commands/summary_command.rb +25 -0
- data/lib/markdo/commands/tag_command.rb +11 -0
- data/lib/markdo/commands/today_command.rb +12 -0
- data/lib/markdo/commands/tomorrow_command.rb +12 -0
- data/lib/markdo/{version_command.rb → commands/version_command.rb} +1 -1
- data/lib/markdo/commands/week_command.rb +16 -0
- data/lib/markdo/data_source.rb +27 -0
- data/lib/markdo/ics_exporter.rb +65 -0
- data/lib/markdo/models/task.rb +46 -0
- data/lib/markdo/models/task_attribute.rb +22 -0
- data/lib/markdo/models/task_collection.rb +75 -0
- data/lib/markdo/version.rb +1 -1
- data/markdo.gemspec +6 -0
- data/script/build +9 -0
- data/spec/fixtures/add_command/Inbox.md +0 -0
- data/spec/fixtures/date_commands/Inbox.md +6 -0
- data/spec/fixtures/date_commands/Sprint.md +6 -0
- data/spec/fixtures/ics_command/Inbox.md +0 -0
- data/{test/fixtures/ics_command.md → spec/fixtures/ics_command/Sprint.md} +0 -0
- data/spec/fixtures/inbox_command/Inbox.md +2 -0
- data/spec/fixtures/inbox_command/Sprint.md +2 -0
- data/spec/fixtures/process_command/Backlog.md +0 -0
- data/spec/fixtures/process_command/Inbox.md +0 -0
- data/spec/fixtures/process_command/Maybe.md +0 -0
- data/spec/fixtures/process_command/Sprint.md +0 -0
- data/spec/fixtures/query_command/Inbox.md +4 -0
- data/spec/fixtures/query_command/Sprint.md +4 -0
- data/spec/fixtures/tag_command/Inbox.md +2 -0
- data/spec/fixtures/tag_command/Sprint.md +2 -0
- data/spec/lib/cli_spec.rb +79 -0
- data/spec/lib/commands/add_command_spec.rb +70 -0
- data/spec/lib/commands/edit_command_spec.rb +32 -0
- data/spec/lib/commands/forecast_command_spec.rb +24 -0
- data/spec/lib/commands/ics_command_spec.rb +30 -0
- data/spec/lib/commands/inbox_command_spec.rb +22 -0
- data/spec/lib/commands/overdue_command_spec.rb +19 -0
- data/spec/lib/commands/overview_command_spec.rb +25 -0
- data/spec/lib/commands/process_command_spec.rb +178 -0
- data/spec/lib/commands/query_command_spec.rb +23 -0
- data/spec/lib/commands/star_command_spec.rb +19 -0
- data/spec/lib/commands/summary_command_spec.rb +23 -0
- data/spec/lib/commands/tag_command_spec.rb +21 -0
- data/spec/lib/commands/today_command_spec.rb +19 -0
- data/spec/lib/commands/tomorrow_command_spec.rb +19 -0
- data/spec/lib/commands/week_command_spec.rb +23 -0
- data/spec/lib/ics_exporter_spec.rb +59 -0
- data/spec/lib/models/task_attribute_spec.rb +85 -0
- data/spec/lib/models/task_collection_spec.rb +168 -0
- data/spec/lib/models/task_spec.rb +79 -0
- data/spec/spec_helper.rb +40 -0
- metadata +189 -42
- data/.ruby-version +0 -1
- data/lib/markdo/command.rb +0 -12
- data/lib/markdo/date_command.rb +0 -9
- data/lib/markdo/forecast_command.rb +0 -61
- data/lib/markdo/ics_command.rb +0 -73
- data/lib/markdo/inbox_command.rb +0 -15
- data/lib/markdo/overdue_command.rb +0 -47
- data/lib/markdo/overview_command.rb +0 -17
- data/lib/markdo/process_command.rb +0 -68
- data/lib/markdo/query_command.rb +0 -24
- data/lib/markdo/rss_command.rb +0 -67
- data/lib/markdo/star_command.rb +0 -9
- data/lib/markdo/summary_command.rb +0 -30
- data/lib/markdo/tag_command.rb +0 -9
- data/lib/markdo/today_command.rb +0 -10
- data/lib/markdo/tomorrow_command.rb +0 -10
- data/lib/markdo/week_command.rb +0 -36
- data/test/fixtures/inbox.md +0 -2
- data/test/fixtures/rss_command.md +0 -4
- data/test/ics_command_test.rb +0 -38
- data/test/inbox_command_test.rb +0 -19
- data/test/rss_command_test.rb +0 -39
- data/test/summary_command_test.rb +0 -19
- data/test/test_helper.rb +0 -3
data/lib/markdo/ics_command.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
require 'markdo/command'
|
2
|
-
require 'date'
|
3
|
-
require 'uri'
|
4
|
-
|
5
|
-
module Markdo
|
6
|
-
class IcsCommand < Command
|
7
|
-
def run
|
8
|
-
events = Dir.
|
9
|
-
glob(markdown_glob).
|
10
|
-
map { |path| File.readlines(path, encoding: 'UTF-8') }.
|
11
|
-
flatten.
|
12
|
-
grep(date_regexp).
|
13
|
-
reject { |line| line.match(/[-*] \[x\]/) }.
|
14
|
-
map { |line|
|
15
|
-
begin
|
16
|
-
raw_due_date = line.match(date_regexp)
|
17
|
-
due_date = Date.parse(raw_due_date[0])
|
18
|
-
Event.new(due_date, due_date, clean(line))
|
19
|
-
rescue ArgumentError
|
20
|
-
# invalid date, skip it
|
21
|
-
end
|
22
|
-
}.compact
|
23
|
-
|
24
|
-
ics = template(events)
|
25
|
-
|
26
|
-
@stdout.puts(ics)
|
27
|
-
end
|
28
|
-
|
29
|
-
protected
|
30
|
-
|
31
|
-
Event = Struct.new(:date_start, :date_end, :summary) do
|
32
|
-
def to_ics
|
33
|
-
buf = []
|
34
|
-
buf << 'BEGIN:VEVENT'
|
35
|
-
buf << "DTSTART;VALUE=DATE:#{date_start.strftime('%Y%m%d')}"
|
36
|
-
buf << "DTEND;VALUE=DATE:#{date_end.strftime('%Y%m%d')}"
|
37
|
-
buf << "SUMMARY:#{summary}"
|
38
|
-
buf << 'END:VEVENT'
|
39
|
-
buf.join("\n")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def markdown_glob
|
44
|
-
"#{@env['MARKDO_ROOT']}/*.md"
|
45
|
-
end
|
46
|
-
|
47
|
-
def date_regexp
|
48
|
-
%r(\b\d{4}-\d{2}-\d{2}\b)
|
49
|
-
end
|
50
|
-
|
51
|
-
def clean(line)
|
52
|
-
line.
|
53
|
-
sub(/\s*[-*] \[.\]\s+/, '').
|
54
|
-
sub(date_regexp, '').
|
55
|
-
sub('@due()', '').
|
56
|
-
strip
|
57
|
-
end
|
58
|
-
|
59
|
-
def template(events)
|
60
|
-
buf = []
|
61
|
-
|
62
|
-
buf << 'BEGIN:VCALENDAR'
|
63
|
-
buf << 'VERSION:2.0'
|
64
|
-
buf << 'CALSCALE:GREGORIAN'
|
65
|
-
buf << 'METHOD:PUBLISH'
|
66
|
-
buf << 'X-WR-CALNAME:Markdo Due Dates'
|
67
|
-
buf << events.map { |event| event.to_ics }
|
68
|
-
buf << 'END:VCALENDAR'
|
69
|
-
|
70
|
-
buf.flatten.join("\n")
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
data/lib/markdo/inbox_command.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'date'
|
2
|
-
require 'markdo/query_command'
|
3
|
-
|
4
|
-
module Markdo
|
5
|
-
# TODO: More testing of this logic. As of 2016-01-23, I was building this
|
6
|
-
# project as a proof of concept.
|
7
|
-
class OverdueCommand < Command
|
8
|
-
def initialize(*)
|
9
|
-
@date = Date.today
|
10
|
-
super
|
11
|
-
end
|
12
|
-
|
13
|
-
def run
|
14
|
-
query_command = QueryCommand.new(@stdout, @stderr, @env)
|
15
|
-
|
16
|
-
all_queries.each do |query|
|
17
|
-
query_command.run(query)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def all_queries
|
24
|
-
[previous_years, previous_months_this_year, previous_days_this_month].flatten
|
25
|
-
end
|
26
|
-
|
27
|
-
def previous_days_this_month
|
28
|
-
(1...@date.day).to_a.map { |day|
|
29
|
-
"#{@date.year}-#{justify(@date.month)}-#{justify(day)}"
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
def previous_months_this_year
|
34
|
-
(1...@date.month).to_a.map { |month|
|
35
|
-
"#{@date.year}-#{justify(month)}"
|
36
|
-
}
|
37
|
-
end
|
38
|
-
|
39
|
-
def previous_years
|
40
|
-
(2000...@date.year).to_a.map { |year| "#{year}-" }
|
41
|
-
end
|
42
|
-
|
43
|
-
def justify(less_than_100)
|
44
|
-
less_than_100.to_s.rjust(2, '0')
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'markdo/command'
|
2
|
-
require 'markdo/overdue_command'
|
3
|
-
require 'markdo/star_command'
|
4
|
-
require 'markdo/today_command'
|
5
|
-
require 'markdo/tomorrow_command'
|
6
|
-
|
7
|
-
module Markdo
|
8
|
-
class OverviewCommand < Command
|
9
|
-
def run
|
10
|
-
commands = [OverdueCommand, StarCommand, TodayCommand, TomorrowCommand]
|
11
|
-
|
12
|
-
commands.each do |command|
|
13
|
-
command.new(@stdout, @stderr, @env).run
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require 'date'
|
2
|
-
require 'markdo/command'
|
3
|
-
|
4
|
-
module Markdo
|
5
|
-
class ProcessCommand < Command
|
6
|
-
# Built as a prototype/proof of concept to see how much I like this idea...
|
7
|
-
def run
|
8
|
-
lines = File.readlines(inbox_path)
|
9
|
-
lines_by_filename = Hash.new { [] }
|
10
|
-
|
11
|
-
index = 0
|
12
|
-
|
13
|
-
while index < lines.length
|
14
|
-
line = lines[index]
|
15
|
-
@stdout.puts line
|
16
|
-
@stdout.print 'File [hisbma]? '
|
17
|
-
choice = $stdin.gets.chomp.downcase
|
18
|
-
|
19
|
-
case choice
|
20
|
-
when 'h'
|
21
|
-
@stdout.puts 'i - inbox (keep in inbox)'
|
22
|
-
@stdout.puts 's - sprint'
|
23
|
-
@stdout.puts 'b - backlog'
|
24
|
-
@stdout.puts 'm - maybe'
|
25
|
-
@stdout.puts 'a - abort; make no changes'
|
26
|
-
when 'i'
|
27
|
-
lines_by_filename['Inbox.md'] <<= line
|
28
|
-
index += 1
|
29
|
-
when 's'
|
30
|
-
lines_by_filename['Sprint.md'] <<= line
|
31
|
-
index += 1
|
32
|
-
when 'b'
|
33
|
-
lines_by_filename['Backlog.md'] <<= line
|
34
|
-
index += 1
|
35
|
-
when 'm'
|
36
|
-
lines_by_filename['Maybe.md'] <<= line
|
37
|
-
index += 1
|
38
|
-
when 'a'
|
39
|
-
exit
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
date = Date.today.iso8601
|
44
|
-
inbox_lines = lines_by_filename.delete('Inbox.md')
|
45
|
-
File.write(inbox_path, inbox_lines ? inbox_lines.join : '')
|
46
|
-
|
47
|
-
lines_by_filename.each do |filename, lines|
|
48
|
-
path = file_path(filename)
|
49
|
-
new_content = ["\n## Processed on #{date}\n\n"] << lines
|
50
|
-
|
51
|
-
File.open(path, 'a') do |file|
|
52
|
-
file.puts(new_content.join)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def file_path(filename)
|
60
|
-
File.join(@env['MARKDO_ROOT'], filename)
|
61
|
-
end
|
62
|
-
|
63
|
-
def inbox_path
|
64
|
-
File.join(@env['MARKDO_ROOT'], @env['MARKDO_INBOX'])
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
data/lib/markdo/query_command.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'markdo/command'
|
2
|
-
|
3
|
-
module Markdo
|
4
|
-
class QueryCommand < Command
|
5
|
-
def run(string)
|
6
|
-
regexp = Regexp.new(string, Regexp::IGNORECASE)
|
7
|
-
|
8
|
-
matches = Dir.
|
9
|
-
glob(markdown_glob).
|
10
|
-
map { |path| File.readlines(path, encoding: 'UTF-8') }.
|
11
|
-
flatten.
|
12
|
-
grep(regexp).
|
13
|
-
reject { |line| line.match(/[-*] \[x\]/) }
|
14
|
-
|
15
|
-
@stdout.puts(matches)
|
16
|
-
end
|
17
|
-
|
18
|
-
protected
|
19
|
-
|
20
|
-
def markdown_glob
|
21
|
-
"#{@env['MARKDO_ROOT']}/*.md"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/markdo/rss_command.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'markdo/command'
|
2
|
-
require 'uri'
|
3
|
-
|
4
|
-
module Markdo
|
5
|
-
class RssCommand < Command
|
6
|
-
def run
|
7
|
-
uri_parser = URI::Parser.new
|
8
|
-
|
9
|
-
items = Dir.
|
10
|
-
glob(markdown_glob).
|
11
|
-
map { |path| File.readlines(path, encoding: 'UTF-8') }.
|
12
|
-
flatten.
|
13
|
-
grep(%r(https?://)).
|
14
|
-
map { |line| Item.new(title: clean(line), links: uri_parser.extract(line)) }
|
15
|
-
|
16
|
-
xml = template(items)
|
17
|
-
|
18
|
-
@stdout.puts(xml)
|
19
|
-
end
|
20
|
-
|
21
|
-
protected
|
22
|
-
|
23
|
-
class Item
|
24
|
-
attr_reader :title, :links
|
25
|
-
|
26
|
-
def initialize(kwargs)
|
27
|
-
@title = kwargs[:title]
|
28
|
-
@links = kwargs[:links]
|
29
|
-
end
|
30
|
-
|
31
|
-
def link
|
32
|
-
links && !links.empty? && links[0]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def markdown_glob
|
37
|
-
"#{@env['MARKDO_ROOT']}/*.md"
|
38
|
-
end
|
39
|
-
|
40
|
-
def clean(line)
|
41
|
-
line.sub(/\s*[-*] \[.\]\s+/, '').chomp
|
42
|
-
end
|
43
|
-
|
44
|
-
def template(items)
|
45
|
-
buf = []
|
46
|
-
|
47
|
-
# No beginning of line whitespace allowed
|
48
|
-
buf << %(<?xml version="1.0" encoding="UTF-8"?>)
|
49
|
-
|
50
|
-
buf << %(<rss version="2.0">)
|
51
|
-
buf << %(<channel>)
|
52
|
-
buf << %(<title>Links in Markdo</title>)
|
53
|
-
|
54
|
-
items.each do |item|
|
55
|
-
buf << %(<item>)
|
56
|
-
buf << %(<title>#{item.title}</title>)
|
57
|
-
buf << %(<link>#{item.link}</link>)
|
58
|
-
buf << %(</item>)
|
59
|
-
end
|
60
|
-
|
61
|
-
buf << %(</channel>)
|
62
|
-
buf << %(</rss>)
|
63
|
-
|
64
|
-
buf.join("\n")
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
data/lib/markdo/star_command.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'stringio'
|
2
|
-
|
3
|
-
require 'markdo/command'
|
4
|
-
require 'markdo/inbox_command'
|
5
|
-
require 'markdo/overdue_command'
|
6
|
-
require 'markdo/star_command'
|
7
|
-
require 'markdo/today_command'
|
8
|
-
require 'markdo/tomorrow_command'
|
9
|
-
require 'markdo/week_command'
|
10
|
-
|
11
|
-
module Markdo
|
12
|
-
class SummaryCommand < Command
|
13
|
-
def run
|
14
|
-
commands = [OverdueCommand, StarCommand, TodayCommand, TomorrowCommand, WeekCommand, InboxCommand]
|
15
|
-
|
16
|
-
commands.each do |command|
|
17
|
-
out = StringIO.new
|
18
|
-
command.new(out, @stderr, @env).run
|
19
|
-
|
20
|
-
title = command.to_s.sub(/^Markdo::/, '').sub(/Command$/, '')
|
21
|
-
lines = out.string.split("\n")
|
22
|
-
sum = lines.length
|
23
|
-
|
24
|
-
unless sum.zero?
|
25
|
-
@stdout.puts("#{title}: #{sum}")
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/markdo/tag_command.rb
DELETED
data/lib/markdo/today_command.rb
DELETED
data/lib/markdo/week_command.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'date'
|
2
|
-
require 'markdo/query_command'
|
3
|
-
|
4
|
-
module Markdo
|
5
|
-
# TODO: More testing of this logic. As of 2016-01-23, I was building this
|
6
|
-
# project as a proof of concept.
|
7
|
-
class WeekCommand < Command
|
8
|
-
attr_accessor :date
|
9
|
-
|
10
|
-
def initialize(*)
|
11
|
-
@date = Date.today
|
12
|
-
super
|
13
|
-
end
|
14
|
-
|
15
|
-
def run
|
16
|
-
query_command = QueryCommand.new(@stdout, @stderr, @env)
|
17
|
-
|
18
|
-
dates_over_the_next_week.each do |query|
|
19
|
-
query_command.run(query)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def dates_over_the_next_week
|
26
|
-
(0..7).to_a.map { |offset|
|
27
|
-
adjusted_date = @date + offset
|
28
|
-
"#{adjusted_date.year}-#{justify(adjusted_date.month)}-#{justify(adjusted_date.day)}"
|
29
|
-
}
|
30
|
-
end
|
31
|
-
|
32
|
-
def justify(less_than_100)
|
33
|
-
less_than_100.to_s.rjust(2, '0')
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/test/fixtures/inbox.md
DELETED
data/test/ics_command_test.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'markdo/ics_command'
|
3
|
-
|
4
|
-
module Markdo
|
5
|
-
describe IcsCommand do
|
6
|
-
it 'outputs an iCalendar feed from the input Markdown, skipping invalid dates' do
|
7
|
-
out = StringIO.new
|
8
|
-
err = StringIO.new
|
9
|
-
env = { 'MARKDO_ROOT' => 'test/fixtures' }
|
10
|
-
|
11
|
-
IcsCommand.new(out, err, env).run
|
12
|
-
|
13
|
-
out.string.must_equal <<-ICS
|
14
|
-
BEGIN:VCALENDAR
|
15
|
-
VERSION:2.0
|
16
|
-
CALSCALE:GREGORIAN
|
17
|
-
METHOD:PUBLISH
|
18
|
-
X-WR-CALNAME:Markdo Due Dates
|
19
|
-
BEGIN:VEVENT
|
20
|
-
DTSTART;VALUE=DATE:20140401
|
21
|
-
DTEND;VALUE=DATE:20140401
|
22
|
-
SUMMARY:Task with long-past due date
|
23
|
-
END:VEVENT
|
24
|
-
BEGIN:VEVENT
|
25
|
-
DTSTART;VALUE=DATE:20160401
|
26
|
-
DTEND;VALUE=DATE:20160401
|
27
|
-
SUMMARY:Task with due date
|
28
|
-
END:VEVENT
|
29
|
-
BEGIN:VEVENT
|
30
|
-
DTSTART;VALUE=DATE:20160401
|
31
|
-
DTEND;VALUE=DATE:20160401
|
32
|
-
SUMMARY:Task with tag-style due date
|
33
|
-
END:VEVENT
|
34
|
-
END:VCALENDAR
|
35
|
-
ICS
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|