markdo 0.1.12.alpha → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +15 -9
  4. data/Dockerfile +21 -7
  5. data/Guardfile +11 -0
  6. data/README.md +12 -7
  7. data/Rakefile +11 -7
  8. data/bin/markdo +1 -1
  9. data/docker-compose.yml +9 -0
  10. data/lib/markdo/cli.rb +23 -55
  11. data/lib/markdo/command_support.rb +14 -0
  12. data/lib/markdo/commands.rb +16 -0
  13. data/lib/markdo/{add_command.rb → commands/add_command.rb} +2 -6
  14. data/lib/markdo/commands/command.rb +33 -0
  15. data/lib/markdo/{edit_command.rb → commands/edit_command.rb} +2 -2
  16. data/lib/markdo/commands/forecast_command.rb +41 -0
  17. data/lib/markdo/{help_command.rb → commands/help_command.rb} +7 -8
  18. data/lib/markdo/commands/ics_command.rb +15 -0
  19. data/lib/markdo/commands/inbox_command.rb +11 -0
  20. data/lib/markdo/commands/overdue_command.rb +11 -0
  21. data/lib/markdo/commands/overview_command.rb +16 -0
  22. data/lib/markdo/commands/process_command.rb +91 -0
  23. data/lib/markdo/commands/query_command.rb +14 -0
  24. data/lib/markdo/commands/star_command.rb +11 -0
  25. data/lib/markdo/commands/summary_command.rb +25 -0
  26. data/lib/markdo/commands/tag_command.rb +11 -0
  27. data/lib/markdo/commands/today_command.rb +12 -0
  28. data/lib/markdo/commands/tomorrow_command.rb +12 -0
  29. data/lib/markdo/{version_command.rb → commands/version_command.rb} +1 -1
  30. data/lib/markdo/commands/week_command.rb +16 -0
  31. data/lib/markdo/data_source.rb +27 -0
  32. data/lib/markdo/ics_exporter.rb +65 -0
  33. data/lib/markdo/models/task.rb +46 -0
  34. data/lib/markdo/models/task_attribute.rb +22 -0
  35. data/lib/markdo/models/task_collection.rb +75 -0
  36. data/lib/markdo/version.rb +1 -1
  37. data/markdo.gemspec +6 -0
  38. data/script/build +9 -0
  39. data/spec/fixtures/add_command/Inbox.md +0 -0
  40. data/spec/fixtures/date_commands/Inbox.md +6 -0
  41. data/spec/fixtures/date_commands/Sprint.md +6 -0
  42. data/spec/fixtures/ics_command/Inbox.md +0 -0
  43. data/{test/fixtures/ics_command.md → spec/fixtures/ics_command/Sprint.md} +0 -0
  44. data/spec/fixtures/inbox_command/Inbox.md +2 -0
  45. data/spec/fixtures/inbox_command/Sprint.md +2 -0
  46. data/spec/fixtures/process_command/Backlog.md +0 -0
  47. data/spec/fixtures/process_command/Inbox.md +0 -0
  48. data/spec/fixtures/process_command/Maybe.md +0 -0
  49. data/spec/fixtures/process_command/Sprint.md +0 -0
  50. data/spec/fixtures/query_command/Inbox.md +4 -0
  51. data/spec/fixtures/query_command/Sprint.md +4 -0
  52. data/spec/fixtures/tag_command/Inbox.md +2 -0
  53. data/spec/fixtures/tag_command/Sprint.md +2 -0
  54. data/spec/lib/cli_spec.rb +79 -0
  55. data/spec/lib/commands/add_command_spec.rb +70 -0
  56. data/spec/lib/commands/edit_command_spec.rb +32 -0
  57. data/spec/lib/commands/forecast_command_spec.rb +24 -0
  58. data/spec/lib/commands/ics_command_spec.rb +30 -0
  59. data/spec/lib/commands/inbox_command_spec.rb +22 -0
  60. data/spec/lib/commands/overdue_command_spec.rb +19 -0
  61. data/spec/lib/commands/overview_command_spec.rb +25 -0
  62. data/spec/lib/commands/process_command_spec.rb +178 -0
  63. data/spec/lib/commands/query_command_spec.rb +23 -0
  64. data/spec/lib/commands/star_command_spec.rb +19 -0
  65. data/spec/lib/commands/summary_command_spec.rb +23 -0
  66. data/spec/lib/commands/tag_command_spec.rb +21 -0
  67. data/spec/lib/commands/today_command_spec.rb +19 -0
  68. data/spec/lib/commands/tomorrow_command_spec.rb +19 -0
  69. data/spec/lib/commands/week_command_spec.rb +23 -0
  70. data/spec/lib/ics_exporter_spec.rb +59 -0
  71. data/spec/lib/models/task_attribute_spec.rb +85 -0
  72. data/spec/lib/models/task_collection_spec.rb +168 -0
  73. data/spec/lib/models/task_spec.rb +79 -0
  74. data/spec/spec_helper.rb +40 -0
  75. metadata +189 -42
  76. data/.ruby-version +0 -1
  77. data/lib/markdo/command.rb +0 -12
  78. data/lib/markdo/date_command.rb +0 -9
  79. data/lib/markdo/forecast_command.rb +0 -61
  80. data/lib/markdo/ics_command.rb +0 -73
  81. data/lib/markdo/inbox_command.rb +0 -15
  82. data/lib/markdo/overdue_command.rb +0 -47
  83. data/lib/markdo/overview_command.rb +0 -17
  84. data/lib/markdo/process_command.rb +0 -68
  85. data/lib/markdo/query_command.rb +0 -24
  86. data/lib/markdo/rss_command.rb +0 -67
  87. data/lib/markdo/star_command.rb +0 -9
  88. data/lib/markdo/summary_command.rb +0 -30
  89. data/lib/markdo/tag_command.rb +0 -9
  90. data/lib/markdo/today_command.rb +0 -10
  91. data/lib/markdo/tomorrow_command.rb +0 -10
  92. data/lib/markdo/week_command.rb +0 -36
  93. data/test/fixtures/inbox.md +0 -2
  94. data/test/fixtures/rss_command.md +0 -4
  95. data/test/ics_command_test.rb +0 -38
  96. data/test/inbox_command_test.rb +0 -19
  97. data/test/rss_command_test.rb +0 -39
  98. data/test/summary_command_test.rb +0 -19
  99. data/test/test_helper.rb +0 -3
@@ -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
@@ -1,15 +0,0 @@
1
- require 'markdo/command'
2
-
3
- module Markdo
4
- class InboxCommand < Command
5
- def run
6
- @stdout.puts(File.read(inbox_path))
7
- end
8
-
9
- protected
10
-
11
- def inbox_path
12
- File.join(@env['MARKDO_ROOT'], @env['MARKDO_INBOX'])
13
- end
14
- end
15
- end
@@ -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
-
@@ -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
@@ -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
@@ -1,9 +0,0 @@
1
- require 'markdo/tag_command'
2
-
3
- module Markdo
4
- class StarCommand < TagCommand
5
- def run
6
- super('star')
7
- end
8
- end
9
- end
@@ -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
@@ -1,9 +0,0 @@
1
- require 'markdo/query_command'
2
-
3
- module Markdo
4
- class TagCommand < QueryCommand
5
- def run(string)
6
- super("@#{string}")
7
- end
8
- end
9
- end
@@ -1,10 +0,0 @@
1
- require 'date'
2
- require 'markdo/date_command'
3
-
4
- module Markdo
5
- class TodayCommand < DateCommand
6
- def run
7
- super(Date.today)
8
- end
9
- end
10
- end
@@ -1,10 +0,0 @@
1
- require 'date'
2
- require 'markdo/date_command'
3
-
4
- module Markdo
5
- class TomorrowCommand < DateCommand
6
- def run
7
- super(Date.today + 1)
8
- end
9
- end
10
- end
@@ -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
@@ -1,2 +0,0 @@
1
- - [ ] Test 1
2
- - [ ] Test 2
@@ -1,4 +0,0 @@
1
- - [ ] Task 1
2
- - [ ] Task with HTTP URL http://www.example.com/
3
- - [ ] Task with HTTPS URL https://www.example.com/
4
- - [ ] Task with HTTP URL http://www.example.com/ and trailing text
@@ -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