standup_md 0.3.1 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +11 -9
- data/README.md +77 -43
- data/Rakefile +3 -1
- data/doc/README_md.html +63 -59
- data/doc/StandupMD.html +4 -23
- data/doc/StandupMD/Cli.html +11 -11
- data/doc/StandupMD/Cli/Helpers.html +8 -7
- data/doc/StandupMD/Config/Cli.html +29 -20
- data/doc/StandupMD/Config/Entry.html +26 -14
- data/doc/StandupMD/Config/EntryList.html +26 -11
- data/doc/StandupMD/Config/File.html +30 -26
- data/doc/StandupMD/Entry.html +1 -1
- data/doc/StandupMD/EntryList.html +116 -194
- data/doc/StandupMD/File.html +67 -25
- data/doc/StandupMD/Version.html +176 -0
- data/doc/created.rid +15 -15
- data/doc/index.html +62 -58
- data/doc/js/navigation.js.gz +0 -0
- data/doc/js/search_index.js +1 -1
- data/doc/js/search_index.js.gz +0 -0
- data/doc/js/searcher.js.gz +0 -0
- data/doc/table_of_contents.html +66 -59
- data/lib/standup_md.rb +4 -3
- data/lib/standup_md/cli.rb +2 -3
- data/lib/standup_md/cli/helpers.rb +66 -34
- data/lib/standup_md/config.rb +2 -2
- data/lib/standup_md/config/cli.rb +24 -23
- data/lib/standup_md/config/entry.rb +14 -9
- data/lib/standup_md/config/entry_list.rb +10 -5
- data/lib/standup_md/config/file.rb +26 -16
- data/lib/standup_md/entry.rb +2 -2
- data/lib/standup_md/entry_list.rb +24 -41
- data/lib/standup_md/file.rb +42 -15
- data/lib/standup_md/file/helpers.rb +13 -15
- data/lib/standup_md/version.rb +23 -6
- data/standup_md.gemspec +12 -16
- metadata +7 -6
@@ -1,9 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module StandupMD
|
2
4
|
class Config
|
3
5
|
|
4
6
|
##
|
5
7
|
# The configuration class for StandupMD::File
|
6
8
|
class File
|
9
|
+
|
10
|
+
##
|
11
|
+
# The default options.
|
12
|
+
#
|
13
|
+
# @return [Hash]
|
14
|
+
DEFAULTS = {
|
15
|
+
header_date_format: '%Y-%m-%d',
|
16
|
+
header_depth: 1,
|
17
|
+
sub_header_depth: 2,
|
18
|
+
current_header: 'Current',
|
19
|
+
previous_header: 'Previous',
|
20
|
+
impediments_header: 'Impediments',
|
21
|
+
notes_header: 'Notes',
|
22
|
+
sub_header_order: %w[previous current impediments notes],
|
23
|
+
directory: ::File.join(ENV['HOME'], '.cache', 'standup_md'),
|
24
|
+
bullet_character: '-',
|
25
|
+
name_format: '%Y_%m.md',
|
26
|
+
create: true,
|
27
|
+
}
|
28
|
+
|
7
29
|
##
|
8
30
|
# Number of octothorps that should preface entry headers.
|
9
31
|
#
|
@@ -116,27 +138,15 @@ module StandupMD
|
|
116
138
|
##
|
117
139
|
# Initializes the config with default values.
|
118
140
|
def initialize
|
119
|
-
|
141
|
+
reset
|
120
142
|
end
|
121
143
|
|
122
144
|
##
|
123
145
|
# Sets all config values back to their defaults.
|
124
146
|
#
|
125
|
-
# @return [
|
126
|
-
def
|
127
|
-
|
128
|
-
@header_depth = 1
|
129
|
-
@sub_header_depth = 2
|
130
|
-
@current_header = 'Current'
|
131
|
-
@previous_header = 'Previous'
|
132
|
-
@impediments_header = 'Impediments'
|
133
|
-
@notes_header = 'Notes'
|
134
|
-
@sub_header_order = %w[previous current impediments notes]
|
135
|
-
@directory = ::File.join(ENV['HOME'], '.cache', 'standup_md')
|
136
|
-
@bullet_character = '-'
|
137
|
-
@name_format = '%Y_%m.md'
|
138
|
-
@create = true
|
139
|
-
true
|
147
|
+
# @return [Hash]
|
148
|
+
def reset
|
149
|
+
DEFAULTS.each { |k, v| instance_variable_set("@#{k}", v) }
|
140
150
|
end
|
141
151
|
|
142
152
|
##
|
data/lib/standup_md/entry.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'json'
|
3
4
|
|
4
5
|
module StandupMD
|
5
|
-
|
6
6
|
##
|
7
7
|
# Class for handling single entries. Includes the comparable module, and
|
8
8
|
# compares by date.
|
@@ -38,7 +38,7 @@ module StandupMD
|
|
38
38
|
attr_accessor :previous
|
39
39
|
|
40
40
|
##
|
41
|
-
#
|
41
|
+
# Impediments for this entry.
|
42
42
|
#
|
43
43
|
# @return [Array]
|
44
44
|
attr_accessor :impediments
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'forwardable'
|
4
4
|
|
5
|
+
module StandupMD
|
5
6
|
##
|
6
7
|
# Enumerable list of entries.
|
7
8
|
class EntryList
|
9
|
+
extend Forwardable
|
8
10
|
include Enumerable
|
9
11
|
|
10
12
|
##
|
@@ -29,12 +31,6 @@ module StandupMD
|
|
29
31
|
@entries = entries
|
30
32
|
end
|
31
33
|
|
32
|
-
##
|
33
|
-
# Iterate over the list and yield each entry.
|
34
|
-
def each(&block)
|
35
|
-
@entries.each(&block)
|
36
|
-
end
|
37
|
-
|
38
34
|
##
|
39
35
|
# Appends entries to list.
|
40
36
|
#
|
@@ -51,24 +47,12 @@ module StandupMD
|
|
51
47
|
##
|
52
48
|
# Finds an entry based on date. This method assumes the list has already
|
53
49
|
# been sorted.
|
54
|
-
def find(key)
|
55
|
-
to_a.bsearch { |e| e.date == key }
|
56
|
-
end
|
57
|
-
|
58
|
-
##
|
59
|
-
# How many entries are in the list.
|
60
50
|
#
|
61
|
-
# @
|
62
|
-
def size
|
63
|
-
@entries.size
|
64
|
-
end
|
65
|
-
|
66
|
-
##
|
67
|
-
# Is the list empty?
|
51
|
+
# @param [Date] date
|
68
52
|
#
|
69
|
-
# @return [
|
70
|
-
def
|
71
|
-
|
53
|
+
# @return [StandupMD::Entry]
|
54
|
+
def find(date)
|
55
|
+
entries.bsearch { |e| e.date == date }
|
72
56
|
end
|
73
57
|
|
74
58
|
##
|
@@ -124,24 +108,6 @@ module StandupMD
|
|
124
108
|
self
|
125
109
|
end
|
126
110
|
|
127
|
-
##
|
128
|
-
# The first entry in the list. This method assumes the list has
|
129
|
-
# already been sorted.
|
130
|
-
#
|
131
|
-
# @return [StandupMD::Entry]
|
132
|
-
def first
|
133
|
-
to_a.first
|
134
|
-
end
|
135
|
-
|
136
|
-
##
|
137
|
-
# The last entry in the list. This method assumes the list has
|
138
|
-
# already been sorted.
|
139
|
-
#
|
140
|
-
# @return [StandupMD::Entry]
|
141
|
-
def last
|
142
|
-
to_a.last
|
143
|
-
end
|
144
|
-
|
145
111
|
##
|
146
112
|
# The list as a hash, with the dates as keys.
|
147
113
|
#
|
@@ -162,5 +128,22 @@ module StandupMD
|
|
162
128
|
def to_json
|
163
129
|
to_h.to_json
|
164
130
|
end
|
131
|
+
|
132
|
+
# :section: Delegators
|
133
|
+
|
134
|
+
##
|
135
|
+
# The following are forwarded to @entries, which is the underly array of
|
136
|
+
# entries.
|
137
|
+
#
|
138
|
+
# +each+:: Iterate over each entry.
|
139
|
+
#
|
140
|
+
# +empty?+:: Is the list empty?
|
141
|
+
#
|
142
|
+
# +size+:: How many items are in the list?
|
143
|
+
#
|
144
|
+
# +first+:: The first record in the list.
|
145
|
+
#
|
146
|
+
# +last+:: The last record in the list.
|
147
|
+
def_delegators :@entries, :each, :empty?, :size, :first, :last
|
165
148
|
end
|
166
149
|
end
|
data/lib/standup_md/file.rb
CHANGED
@@ -5,7 +5,6 @@ require 'fileutils'
|
|
5
5
|
require_relative 'file/helpers'
|
6
6
|
|
7
7
|
module StandupMD
|
8
|
-
|
9
8
|
##
|
10
9
|
# Class for handling reading and writing standup files.
|
11
10
|
class File
|
@@ -19,15 +18,34 @@ module StandupMD
|
|
19
18
|
@config ||= StandupMD.config.file
|
20
19
|
end
|
21
20
|
|
21
|
+
##
|
22
|
+
# Convenience method for calling File.find(file_name).load
|
23
|
+
#
|
24
|
+
# @param [String] file_name
|
25
|
+
#
|
26
|
+
# @return [StandupMD::File]
|
27
|
+
def self.load(file_name)
|
28
|
+
unless ::File.directory?(config.directory)
|
29
|
+
raise "Dir #{config.directory} not found." unless config.create
|
30
|
+
|
31
|
+
FileUtils.mkdir_p(config.directory)
|
32
|
+
end
|
33
|
+
new(file_name).load
|
34
|
+
end
|
35
|
+
|
22
36
|
##
|
23
37
|
# Find standup file in directory by file name.
|
24
38
|
#
|
25
39
|
# @param [String] File_naem
|
26
40
|
def self.find(file_name)
|
27
|
-
|
28
|
-
|
29
|
-
|
41
|
+
unless ::File.directory?(config.directory)
|
42
|
+
raise "Dir #{config.directory} not found." unless config.create
|
43
|
+
|
44
|
+
FileUtils.mkdir_p(config.directory)
|
30
45
|
end
|
46
|
+
file = Dir.entries(config.directory).bsearch { |f| f == file_name }
|
47
|
+
raise "File #{file_name} not found." if file.nil? && !config.create
|
48
|
+
|
31
49
|
new(file_name)
|
32
50
|
end
|
33
51
|
|
@@ -36,8 +54,12 @@ module StandupMD
|
|
36
54
|
#
|
37
55
|
# @param [Date] date
|
38
56
|
def self.find_by_date(date)
|
39
|
-
unless date.is_a?(Date)
|
40
|
-
|
57
|
+
raise ArgumentError, 'Must be a Date object' unless date.is_a?(Date)
|
58
|
+
|
59
|
+
unless ::File.directory?(config.directory)
|
60
|
+
raise "Dir #{config.directory} not found." unless config.create
|
61
|
+
|
62
|
+
FileUtils.mkdir_p(config.directory)
|
41
63
|
end
|
42
64
|
find(date.strftime(config.name_format))
|
43
65
|
end
|
@@ -69,6 +91,7 @@ module StandupMD
|
|
69
91
|
|
70
92
|
unless ::File.directory?(@config.directory)
|
71
93
|
raise "Dir #{@config.directory} not found." unless @config.create
|
94
|
+
|
72
95
|
FileUtils.mkdir_p(@config.directory)
|
73
96
|
end
|
74
97
|
|
@@ -76,6 +99,7 @@ module StandupMD
|
|
76
99
|
|
77
100
|
unless ::File.file?(@name)
|
78
101
|
raise "File #{@name} not found." unless @config.create
|
102
|
+
|
79
103
|
FileUtils.touch(@name)
|
80
104
|
end
|
81
105
|
|
@@ -114,21 +138,23 @@ module StandupMD
|
|
114
138
|
# @return [StandupMD::FileList]
|
115
139
|
def load
|
116
140
|
raise "File #{name} does not exist." unless ::File.file?(name)
|
141
|
+
|
117
142
|
entry_list = EntryList.new
|
118
143
|
record = {}
|
119
144
|
section_type = ''
|
120
145
|
::File.foreach(name) do |line|
|
121
146
|
line.chomp!
|
122
147
|
next if line.strip.empty?
|
123
|
-
|
148
|
+
|
149
|
+
if header?(line)
|
124
150
|
unless record.empty?
|
125
151
|
entry_list << new_entry(record)
|
126
152
|
record = {}
|
127
153
|
end
|
128
|
-
record['header'] = line.sub(
|
129
|
-
|
130
|
-
|
131
|
-
elsif
|
154
|
+
record['header'] = line.sub(/^\#{#{@config.header_depth}}\s*/, '')
|
155
|
+
section_type = @config.notes_header
|
156
|
+
record[section_type] = []
|
157
|
+
elsif sub_header?(line)
|
132
158
|
section_type = determine_section_type(line)
|
133
159
|
record[section_type] = []
|
134
160
|
else
|
@@ -148,10 +174,10 @@ module StandupMD
|
|
148
174
|
# This method is destructive; if a file for entries in the date range
|
149
175
|
# already exists, it will be clobbered with the entries in the range.
|
150
176
|
#
|
151
|
-
# @param [Hash]
|
177
|
+
# @param [Hash] {start_date: Date, end_date: Date}
|
152
178
|
#
|
153
179
|
# @return [Boolean] true if successful
|
154
|
-
def write(dates
|
180
|
+
def write(**dates)
|
155
181
|
sorted_entries = entries.sort
|
156
182
|
start_date = dates.fetch(:start_date, sorted_entries.first.date)
|
157
183
|
end_date = dates.fetch(:end_date, sorted_entries.last.date)
|
@@ -159,9 +185,10 @@ module StandupMD
|
|
159
185
|
sorted_entries.filter(start_date, end_date).sort_reverse.each do |entry|
|
160
186
|
f.puts header(entry.date)
|
161
187
|
@config.sub_header_order.each do |attr|
|
162
|
-
tasks = entry.
|
188
|
+
tasks = entry.public_send(attr)
|
163
189
|
next if !tasks || tasks.empty?
|
164
|
-
|
190
|
+
|
191
|
+
f.puts sub_header(@config.public_send("#{attr}_header").capitalize)
|
165
192
|
tasks.each { |task| f.puts @config.bullet_character + ' ' + task }
|
166
193
|
end
|
167
194
|
f.puts
|
@@ -2,40 +2,38 @@
|
|
2
2
|
|
3
3
|
module StandupMD
|
4
4
|
class File
|
5
|
-
|
6
5
|
##
|
7
6
|
# Module responsible for reading and writing standup files.
|
8
7
|
module Helpers # :nodoc:
|
9
|
-
|
10
8
|
private
|
11
9
|
|
12
|
-
def
|
10
|
+
def header?(line) # :nodoc:
|
13
11
|
line.match(header_regex)
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
14
|
+
def sub_header?(line) # :nodoc:
|
17
15
|
line.match(sub_header_regex)
|
18
16
|
end
|
19
17
|
|
20
18
|
def header_regex # :nodoc:
|
21
|
-
|
19
|
+
/^#{'#' * StandupMD.config.file.header_depth}\s+/
|
22
20
|
end
|
23
21
|
|
24
22
|
def sub_header_regex # :nodoc:
|
25
|
-
|
23
|
+
/^#{'#' * StandupMD.config.file.sub_header_depth}\s+/
|
26
24
|
end
|
27
25
|
|
28
26
|
def bullet_character_regex # :nodoc:
|
29
|
-
|
27
|
+
/\s*#{StandupMD.config.file.bullet_character}\s*/
|
30
28
|
end
|
31
29
|
|
32
30
|
def determine_section_type(line) # :nodoc:
|
33
|
-
line = line.sub(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
line = line.sub(/^\#{#{StandupMD.config.file.sub_header_depth}}\s*/, '')
|
32
|
+
[
|
33
|
+
StandupMD.config.file.current_header,
|
34
|
+
StandupMD.config.file.previous_header,
|
35
|
+
StandupMD.config.file.impediments_header,
|
36
|
+
StandupMD.config.file.notes_header
|
39
37
|
].each { |header| return header if line.include?(header) }
|
40
38
|
raise "Unrecognized header [#{line}]"
|
41
39
|
end
|
@@ -54,8 +52,8 @@ module StandupMD
|
|
54
52
|
'#' * StandupMD.config.file.header_depth + ' ' + date.strftime(StandupMD.config.file.header_date_format)
|
55
53
|
end
|
56
54
|
|
57
|
-
def sub_header(
|
58
|
-
'#' * StandupMD.config.file.sub_header_depth + ' ' +
|
55
|
+
def sub_header(subhead)
|
56
|
+
'#' * StandupMD.config.file.sub_header_depth + ' ' + subhead
|
59
57
|
end
|
60
58
|
end
|
61
59
|
end
|
data/lib/standup_md/version.rb
CHANGED
@@ -1,11 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module StandupMD
|
4
|
+
|
4
5
|
##
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
# Module that contains all gem version information. Follows semantic
|
7
|
+
# versioning. Read: https://semver.org/
|
8
|
+
module Version
|
9
|
+
|
10
|
+
##
|
11
|
+
# Major version.
|
12
|
+
MAJOR = 0
|
13
|
+
|
14
|
+
##
|
15
|
+
# Minor version.
|
16
|
+
MINOR = 3
|
17
|
+
|
18
|
+
##
|
19
|
+
# Patch version.
|
20
|
+
PATCH = 6
|
21
|
+
|
22
|
+
##
|
23
|
+
# Version as +MAJOR.MINOR.PATCH+
|
24
|
+
def self.to_s
|
25
|
+
"#{MAJOR}.#{MINOR}.#{PATCH}"
|
26
|
+
end
|
27
|
+
end
|
11
28
|
end
|
data/standup_md.gemspec
CHANGED
@@ -2,7 +2,7 @@ require_relative 'lib/standup_md/version'
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = 'standup_md'
|
5
|
-
spec.version = StandupMD::
|
5
|
+
spec.version = StandupMD::Version.to_s
|
6
6
|
spec.authors = ['Evan Gray']
|
7
7
|
spec.email = 'evanthegrayt@vivaldi.net'
|
8
8
|
spec.license = 'MIT'
|
@@ -12,25 +12,21 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = %q{Generate and edit standups in markdown format}
|
13
13
|
spec.homepage = 'https://evanthegrayt.github.io/standup_md/'
|
14
14
|
|
15
|
-
|
16
|
-
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
17
|
-
if spec.respond_to?(:metadata)
|
18
|
-
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
19
|
-
|
20
|
-
spec.metadata['homepage_uri'] = spec.homepage
|
21
|
-
spec.metadata['source_code_uri'] = 'https://github.com/evanthegrayt/standup_md'
|
22
|
-
spec.metadata['documentation_uri'] = 'https://evanthegrayt.github.io/standup_md/doc/index.html'
|
23
|
-
else
|
15
|
+
unless spec.respond_to?(:metadata)
|
24
16
|
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
25
17
|
'public gem pushes.'
|
26
18
|
end
|
27
19
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
20
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
21
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
22
|
+
spec.metadata['source_code_uri'] =
|
23
|
+
'https://github.com/evanthegrayt/standup_md'
|
24
|
+
spec.metadata['documentation_uri'] =
|
25
|
+
'https://evanthegrayt.github.io/standup_md/doc/index.html'
|
26
|
+
|
27
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
28
|
+
f.match(%r{^(test|spec|features)/})
|
29
|
+
end
|
34
30
|
spec.bindir = 'bin'
|
35
31
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
36
32
|
spec.require_paths = ['lib']
|