work_md 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/lib/work_md.rb +4 -0
- data/lib/work_md/cli.rb +32 -8
- data/lib/work_md/commands/parse.rb +90 -0
- data/lib/work_md/commands/today.rb +24 -18
- data/lib/work_md/config.rb +44 -5
- data/lib/work_md/parser/engine.rb +154 -0
- data/lib/work_md/version.rb +1 -1
- metadata +33 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1c858bf12a976912f85e9fd1a22b39e2bd5daf4e56ec46299c1297aa4e576cb
|
4
|
+
data.tar.gz: 8a542af4507b9765d9317f23ad7db72bc1f4cf8ffe7bc27342ea9c1e8f592e82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '02389407af0f604e5cf9fac532639b5cb5553179cd98d67fa18aecf56bc182cccbc2bc674cd1f8ca3f5b11ede62d82d8b85320613a55e0cf6d432f273618e06a'
|
7
|
+
data.tar.gz: 3983b233410dd07224abf01bf74998c31307780b52b43cdb83495d4745ed83938c72d0f0cb449e34dcdb7cded9e28fd5dec440fedacd823446f8ec0309152457
|
data/lib/work_md.rb
CHANGED
@@ -3,9 +3,13 @@
|
|
3
3
|
require_relative 'work_md/version'
|
4
4
|
require_relative 'work_md/config'
|
5
5
|
require_relative 'work_md/commands/today'
|
6
|
+
require_relative 'work_md/parser/engine'
|
7
|
+
require_relative 'work_md/commands/parse'
|
6
8
|
require_relative 'work_md/cli'
|
7
9
|
require 'date'
|
8
10
|
require 'fileutils'
|
11
|
+
require 'tty-box'
|
12
|
+
require 'tty-editor'
|
9
13
|
|
10
14
|
module WorkMd
|
11
15
|
end
|
data/lib/work_md/cli.rb
CHANGED
@@ -6,7 +6,8 @@ module WorkMd
|
|
6
6
|
|
7
7
|
ALIAS_COMMANDS =
|
8
8
|
{
|
9
|
-
't' => 'today'
|
9
|
+
't' => 'today',
|
10
|
+
'p' => 'parse'
|
10
11
|
}.freeze
|
11
12
|
|
12
13
|
DEFAULT_COMMAND = WorkMd::Commands::Today
|
@@ -23,17 +24,40 @@ module WorkMd
|
|
23
24
|
.const_get("WorkMd::Commands::#{command}")
|
24
25
|
.send(:execute, argv)
|
25
26
|
rescue NameError
|
26
|
-
|
27
|
+
puts info(
|
28
|
+
::TTY::Box.frame(
|
29
|
+
"Command '#{first_argv_argument}' not found!",
|
30
|
+
**error_frame_style
|
31
|
+
)
|
32
|
+
)
|
27
33
|
rescue CommandMissing
|
28
34
|
DEFAULT_COMMAND.execute(argv)
|
29
35
|
end
|
30
36
|
|
31
|
-
def self.
|
32
|
-
|
33
|
-
puts
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
+
def self.info(message = '')
|
38
|
+
# rubocop:disable Layout/LineLength
|
39
|
+
puts ::TTY::Box.frame(
|
40
|
+
message,
|
41
|
+
'Track your work activities, write annotations, recap what you did for a week, month or specific days... and much more!',
|
42
|
+
'',
|
43
|
+
'commands available:',
|
44
|
+
'',
|
45
|
+
'- work_md',
|
46
|
+
'- work_md today',
|
47
|
+
'- work_md parse',
|
48
|
+
'',
|
49
|
+
'read more in github.com/henriquefernandez/work_md',
|
50
|
+
padding: 1,
|
51
|
+
title: { top_left: '(work_md)', bottom_right: "(v#{WorkMd::VERSION})" }
|
52
|
+
)
|
53
|
+
# rubocop:enable Layout/LineLength
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.error_frame_style
|
57
|
+
{
|
58
|
+
padding: 1,
|
59
|
+
title: { top_left: '(error)' }
|
60
|
+
}
|
37
61
|
end
|
38
62
|
end
|
39
63
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WorkMd
|
4
|
+
module Commands
|
5
|
+
class Parse
|
6
|
+
PARSED_FILE_PATH = WorkMd::Config.work_dir + '/parsed.md'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def execute(argv = [])
|
10
|
+
begin
|
11
|
+
args = Hash[argv.join(' ').scan(/-?([^=\s]+)(?:=(\S+))?/)]
|
12
|
+
parser = WorkMd::Parser::Engine.new
|
13
|
+
t = WorkMd::Config.translations
|
14
|
+
|
15
|
+
year = args['y'] || Time.new.year
|
16
|
+
month = args['m'] || Time.new.month
|
17
|
+
|
18
|
+
month = "0#{month.to_i}" if month.to_i < 10
|
19
|
+
|
20
|
+
args['d'].split(',').each do |day|
|
21
|
+
day = "0#{day.to_i}" if day.to_i < 10
|
22
|
+
|
23
|
+
file_name = WorkMd::Config.work_dir + "/#{year}/#{month}/#{day}.md"
|
24
|
+
|
25
|
+
parser.add_file(file_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
parser.freeze
|
29
|
+
|
30
|
+
File.delete(PARSED_FILE_PATH) if File.exist? PARSED_FILE_PATH
|
31
|
+
|
32
|
+
File.open(PARSED_FILE_PATH, 'w+') do |f|
|
33
|
+
f.puts("# #{WorkMd::Config.title}\n\n")
|
34
|
+
f.puts("### #{t[:tasks]} (#{parser.tasks.size}):\n\n")
|
35
|
+
parser.tasks.each do |task|
|
36
|
+
f.puts("- [#{task}\n\n") if task != ' ]'
|
37
|
+
end
|
38
|
+
f.puts("---\n\n")
|
39
|
+
f.puts("### #{t[:meetings]} (#{parser.meetings.size}):\n\n")
|
40
|
+
parser.meetings.each do |meeting|
|
41
|
+
f.puts("- #{meeting}\n\n")
|
42
|
+
end
|
43
|
+
f.puts("---\n\n")
|
44
|
+
f.puts("### #{t[:annotations]}:\n\n")
|
45
|
+
parser.annotations.each do |annotation|
|
46
|
+
f.puts("- #{annotation.gsub('###', '')}") unless annotation.nil?
|
47
|
+
end
|
48
|
+
f.puts("###### #{t[:meeting_annotations]}:\n\n")
|
49
|
+
parser.meeting_annotations.each do |meeting_annotation|
|
50
|
+
f.puts("- #{meeting_annotation}\n\n")
|
51
|
+
end
|
52
|
+
f.puts("---\n\n")
|
53
|
+
f.puts("### #{t[:interruptions]} (#{parser.interruptions.size}):\n\n")
|
54
|
+
parser.interruptions.each do |interruption|
|
55
|
+
f.puts("- #{interruption}\n\n")
|
56
|
+
end
|
57
|
+
f.puts("---\n\n")
|
58
|
+
f.puts("### #{t[:difficulties]} (#{parser.difficulties.size}):\n\n")
|
59
|
+
parser.difficulties.each do |difficulty|
|
60
|
+
f.puts("- #{difficulty}\n\n")
|
61
|
+
end
|
62
|
+
f.puts("---\n\n")
|
63
|
+
f.puts("### #{t[:pomodoros]}:\n\n")
|
64
|
+
f.puts(parser.pomodoros)
|
65
|
+
end
|
66
|
+
|
67
|
+
editor = WorkMd::Config.editor
|
68
|
+
|
69
|
+
unless editor.nil?
|
70
|
+
::TTY::Editor.open(PARSED_FILE_PATH, {command: editor})
|
71
|
+
else
|
72
|
+
::TTY::Editor.open(PARSED_FILE_PATH)
|
73
|
+
end
|
74
|
+
rescue
|
75
|
+
WorkMd::Cli.info(
|
76
|
+
::TTY::Box.frame(
|
77
|
+
"Usage examples:",
|
78
|
+
"",
|
79
|
+
"work_md parse -d=1 -m=5 -y=2000 | get day 1 from month 5 and year 2000",
|
80
|
+
"work_md parse -d=1,2,3 | get day 1, 2 and 3 from the current month and year",
|
81
|
+
"work_md parse -d=1,2 -m=4 | get day 1 and 2 from month 4 and current year",
|
82
|
+
**WorkMd::Cli.error_frame_style
|
83
|
+
)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -4,44 +4,50 @@ module WorkMd
|
|
4
4
|
module Commands
|
5
5
|
class Today
|
6
6
|
class << self
|
7
|
-
def description; end
|
8
|
-
|
9
7
|
def execute(_argv = [])
|
10
8
|
today = DateTime.now
|
9
|
+
t = WorkMd::Config.translations
|
10
|
+
work_dir = WorkMd::Config.work_dir
|
11
11
|
|
12
12
|
::FileUtils
|
13
|
-
.mkdir_p("#{
|
13
|
+
.mkdir_p("#{work_dir}/#{today.strftime('%Y/%m')}")
|
14
14
|
unless ::File
|
15
15
|
.exist?(
|
16
|
-
"#{
|
16
|
+
"#{work_dir}/#{today.strftime('%Y/%m/%d')}.md"
|
17
17
|
)
|
18
18
|
::File.open(
|
19
|
-
"#{
|
19
|
+
"#{work_dir}/#{today.strftime('%Y/%m/%d')}.md",
|
20
20
|
'w+'
|
21
21
|
) do |f|
|
22
|
-
f.puts("# #{today.strftime('%d/%m/%Y')} \n\n")
|
23
|
-
f.puts("###
|
22
|
+
f.puts("# #{today.strftime('%d/%m/%Y')} - #{WorkMd::Config.title} \n\n")
|
23
|
+
f.puts("### #{t[:tasks]}:\n\n")
|
24
24
|
f.puts("- [ ]\n\n")
|
25
25
|
f.puts("---\n\n")
|
26
|
-
f.puts("###
|
26
|
+
f.puts("### #{t[:meetings]}:\n\n")
|
27
27
|
f.puts("---\n\n")
|
28
|
-
f.puts("###
|
29
|
-
f.puts("######
|
28
|
+
f.puts("### #{t[:annotations]}:\n\n")
|
29
|
+
f.puts("###### #{t[:meeting_annotations]}:\n\n")
|
30
30
|
f.puts("---\n\n")
|
31
|
-
f.puts("###
|
31
|
+
f.puts("### #{t[:interruptions]}:\n\n")
|
32
32
|
f.puts("---\n\n")
|
33
|
-
f.puts("###
|
33
|
+
f.puts("### #{t[:difficulties]}:\n\n")
|
34
34
|
f.puts("---\n\n")
|
35
|
-
f.puts("###
|
35
|
+
f.puts("### #{t[:pomodoros]}:\n\n")
|
36
36
|
f.puts("0\n\n")
|
37
|
-
f.puts("---\n\n")
|
38
|
-
f.puts("### Ponto:\n\n")
|
39
|
-
f.puts("- \n\n")
|
40
37
|
end
|
41
38
|
end
|
42
39
|
|
43
|
-
|
44
|
-
|
40
|
+
editor = WorkMd::Config.editor
|
41
|
+
|
42
|
+
::FileUtils.cd(work_dir) do
|
43
|
+
unless editor.nil?
|
44
|
+
::TTY::Editor.open(
|
45
|
+
"#{today.strftime('%Y/%m/%d')}.md",
|
46
|
+
{command: editor}
|
47
|
+
)
|
48
|
+
else
|
49
|
+
::TTY::Editor.open("#{today.strftime('%Y/%m/%d')}.md")
|
50
|
+
end
|
45
51
|
end
|
46
52
|
end
|
47
53
|
end
|
data/lib/work_md/config.rb
CHANGED
@@ -1,16 +1,55 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
# TODO: Set language (i18n) as a config
|
3
|
+
require 'yaml'
|
4
|
+
|
6
5
|
module WorkMd
|
7
6
|
module Config
|
7
|
+
DEFAULT_WORK_DIR = Dir.home + '/work_md'
|
8
|
+
TRANSLATIONS = {
|
9
|
+
'pt' =>
|
10
|
+
{
|
11
|
+
tasks: 'Atividades',
|
12
|
+
meetings: 'Reuniões',
|
13
|
+
annotations: 'Anotações',
|
14
|
+
meeting_annotations: 'Anotações de Reunião',
|
15
|
+
interruptions: 'Interrupções',
|
16
|
+
difficulties: 'Dificuldades',
|
17
|
+
pomodoros: 'Pomodoros'
|
18
|
+
},
|
19
|
+
'en' =>
|
20
|
+
{
|
21
|
+
tasks: 'Tasks',
|
22
|
+
meetings: 'Meetings',
|
23
|
+
annotations: 'Annotations',
|
24
|
+
meeting_annotations: 'Meeting Annotations',
|
25
|
+
interruptions: 'Interruptions',
|
26
|
+
difficulties: 'Difficulties',
|
27
|
+
pomodoros: 'Pomodoros'
|
28
|
+
}
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
def self.title
|
32
|
+
yaml_file['title'] || ''
|
33
|
+
end
|
34
|
+
|
8
35
|
def self.editor
|
9
|
-
ENV['EDITOR']
|
36
|
+
ENV['EDITOR'] || ENV['VISUAL'] || yaml_file['editor'] || nil
|
10
37
|
end
|
11
38
|
|
12
39
|
def self.work_dir
|
13
|
-
|
40
|
+
ENV['WORK_MD_DIR'] || DEFAULT_WORK_DIR
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.translations
|
44
|
+
TRANSLATIONS[ENV['WORK_MD_LANG']] ||
|
45
|
+
TRANSLATIONS[yaml_file['lang']] ||
|
46
|
+
TRANSLATIONS['en']
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.yaml_file
|
50
|
+
YAML.load_file(DEFAULT_WORK_DIR + '/config.yml')
|
51
|
+
rescue StandardError
|
52
|
+
{}
|
14
53
|
end
|
15
54
|
end
|
16
55
|
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module WorkMd
|
4
|
+
module Parser
|
5
|
+
class Engine
|
6
|
+
IS_FROZEN_ERROR_MESSAGE = 'WorkMd::Parser::Engine is frozen'
|
7
|
+
IS_NOT_FROZEN_ERROR_MESSAGE = 'WorkMd::Parser::Engine is not frozen'
|
8
|
+
|
9
|
+
class ParsedFile
|
10
|
+
attr_accessor :tasks,
|
11
|
+
:annotations,
|
12
|
+
:meeting_annotations,
|
13
|
+
:meetings,
|
14
|
+
:interruptions,
|
15
|
+
:difficulties,
|
16
|
+
:pomodoros
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@t = WorkMd::Config.translations
|
21
|
+
@parsed_files = []
|
22
|
+
@frozen = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_file(file)
|
26
|
+
raise IS_FROZEN_ERROR_MESSAGE if @frozen
|
27
|
+
|
28
|
+
begin
|
29
|
+
file_content = File.read(file)
|
30
|
+
rescue Errno::ENOENT
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
return unless file_content.start_with?('# ')
|
35
|
+
|
36
|
+
@parsed_files.push(parse_file_content(file_content))
|
37
|
+
end
|
38
|
+
|
39
|
+
def done_tasks
|
40
|
+
raise IS_NOT_FROZEN_ERROR_MESSAGE unless @frozen
|
41
|
+
|
42
|
+
@done_tasks ||=
|
43
|
+
tasks.filter { |t| t.start_with?('x]') || t.start_with?('X]') }
|
44
|
+
end
|
45
|
+
|
46
|
+
def tasks
|
47
|
+
raise IS_NOT_FROZEN_ERROR_MESSAGE unless @frozen
|
48
|
+
|
49
|
+
@tasks ||= @parsed_files.map(&:tasks).flatten
|
50
|
+
end
|
51
|
+
|
52
|
+
def annotations
|
53
|
+
raise IS_NOT_FROZEN_ERROR_MESSAGE unless @frozen
|
54
|
+
|
55
|
+
@annotations ||= @parsed_files.map(&:annotations).flatten
|
56
|
+
end
|
57
|
+
|
58
|
+
def meeting_annotations
|
59
|
+
raise IS_NOT_FROZEN_ERROR_MESSAGE unless @frozen
|
60
|
+
|
61
|
+
@meeting_annotations ||=
|
62
|
+
@parsed_files.map(&:meeting_annotations).flatten
|
63
|
+
end
|
64
|
+
|
65
|
+
def meetings
|
66
|
+
raise IS_NOT_FROZEN_ERROR_MESSAGE unless @frozen
|
67
|
+
|
68
|
+
@meetings ||= @parsed_files.map(&:meetings).flatten
|
69
|
+
end
|
70
|
+
|
71
|
+
def interruptions
|
72
|
+
raise IS_NOT_FROZEN_ERROR_MESSAGE unless @frozen
|
73
|
+
|
74
|
+
@interruptions ||= @parsed_files.map(&:interruptions).flatten
|
75
|
+
end
|
76
|
+
|
77
|
+
def difficulties
|
78
|
+
raise IS_NOT_FROZEN_ERROR_MESSAGE unless @frozen
|
79
|
+
|
80
|
+
@difficulties ||= @parsed_files.map(&:difficulties).flatten
|
81
|
+
end
|
82
|
+
|
83
|
+
def pomodoros
|
84
|
+
raise IS_NOT_FROZEN_ERROR_MESSAGE unless @frozen
|
85
|
+
|
86
|
+
@pomodoros ||=
|
87
|
+
@parsed_files.reduce(0) { |sum, f| sum + f.pomodoros || 0 }
|
88
|
+
end
|
89
|
+
|
90
|
+
def freeze
|
91
|
+
@frozen = true
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def parse_file_content(file_content)
|
97
|
+
parsed_file = ParsedFile.new
|
98
|
+
|
99
|
+
file_content
|
100
|
+
.split('### ')
|
101
|
+
.each { |content| parse_content(parsed_file, content) }
|
102
|
+
|
103
|
+
parsed_file
|
104
|
+
end
|
105
|
+
|
106
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
107
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
108
|
+
def parse_content(parsed_file, content)
|
109
|
+
if content.start_with?(@t[:tasks])
|
110
|
+
parsed_file.tasks = parse_task_list(content)
|
111
|
+
elsif content.start_with?(@t[:meetings])
|
112
|
+
parsed_file.meetings = parse_list(content)
|
113
|
+
elsif content.start_with?(@t[:meeting_annotations])
|
114
|
+
parsed_file.meeting_annotations = basic_parse(content)
|
115
|
+
elsif content.start_with?(@t[:annotations])
|
116
|
+
parsed_file.annotations = basic_parse(content)
|
117
|
+
elsif content.start_with?(@t[:interruptions])
|
118
|
+
parsed_file.interruptions = parse_list(content)
|
119
|
+
elsif content.start_with?(@t[:difficulties])
|
120
|
+
parsed_file.difficulties = parse_list(content)
|
121
|
+
elsif content.start_with?(@t[:pomodoros])
|
122
|
+
parsed_file.pomodoros = parse_pomodoro(content)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
126
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
127
|
+
|
128
|
+
def parse_task_list(content)
|
129
|
+
clear_list(basic_parse(content).split('- ['))
|
130
|
+
end
|
131
|
+
|
132
|
+
def parse_list(content)
|
133
|
+
clear_list(basic_parse(content).split('- '))
|
134
|
+
end
|
135
|
+
|
136
|
+
def parse_pomodoro(content)
|
137
|
+
basic_parse(content).scan(/\d+/).first.to_i
|
138
|
+
end
|
139
|
+
|
140
|
+
def basic_parse(content)
|
141
|
+
content.split(":\n\n")[1]
|
142
|
+
end
|
143
|
+
|
144
|
+
def clear_list(list)
|
145
|
+
return list unless list.is_a?(Array)
|
146
|
+
|
147
|
+
list
|
148
|
+
.map { |s| s.gsub('---', '') unless s.nil? }
|
149
|
+
.filter { |s| (s != '') && (s != "\n\n") }
|
150
|
+
.map(&:strip)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/lib/work_md/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: work_md
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henrique Fernandez Teixeira
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
12
|
-
dependencies:
|
11
|
+
date: 2021-07-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tty-box
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.7.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.7.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tty-editor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.7.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.7.0
|
13
41
|
description:
|
14
42
|
email:
|
15
43
|
- hriqueft@gmail.com
|
@@ -23,8 +51,10 @@ files:
|
|
23
51
|
- bin/work_md
|
24
52
|
- lib/work_md.rb
|
25
53
|
- lib/work_md/cli.rb
|
54
|
+
- lib/work_md/commands/parse.rb
|
26
55
|
- lib/work_md/commands/today.rb
|
27
56
|
- lib/work_md/config.rb
|
57
|
+
- lib/work_md/parser/engine.rb
|
28
58
|
- lib/work_md/version.rb
|
29
59
|
homepage:
|
30
60
|
licenses:
|