mdtoc 0.2.0 → 0.3.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/lib/mdtoc/cli.rb +8 -8
- data/lib/mdtoc/markdown/fragment_generator.rb +50 -0
- data/lib/mdtoc/markdown/header.rb +17 -11
- data/lib/mdtoc/markdown/parser.rb +75 -16
- data/lib/mdtoc/node.rb +29 -20
- data/lib/mdtoc/version.rb +1 -1
- data/lib/mdtoc/writer.rb +18 -13
- data/lib/mdtoc.rb +5 -5
- metadata +20 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c01cef42824ceeae479dc235cbe2c7565c2d6ef045074c8d55b34a821ee719d
|
|
4
|
+
data.tar.gz: c25c67f2bf841dd9e1e3bb6a632035693299e7a53367b5dd255ecfbc125adab2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 603bec1ab105a7438bb2d0c2e4fb0c7eead9c63b57bfe33ca9354b05458d435805ce614cd11549527749092f2cffdc1289691a177b3c86161bac714f877c3eb7
|
|
7
|
+
data.tar.gz: 6bb0b63c4217f899d2277ba35baf7966cd97219e88f111c7a842b535108c698ac0260c0cc1f2c7e24858c9464a9cac333ea1fa4a7244104b051ba3184ed326bd
|
data/lib/mdtoc/cli.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
4
|
+
require 'optparse'
|
|
5
|
+
require 'sorbet-runtime'
|
|
6
|
+
require 'tempfile'
|
|
7
7
|
|
|
8
8
|
module Mdtoc
|
|
9
9
|
module CLI
|
|
@@ -14,19 +14,19 @@ module Mdtoc
|
|
|
14
14
|
def parse(args)
|
|
15
15
|
parser = OptionParser.new do |parser_|
|
|
16
16
|
parser_.banner = "Usage: #{parser_.program_name} [options] files or directories..."
|
|
17
|
-
parser_.on(
|
|
17
|
+
parser_.on('-h', '--help', 'Show this message') do
|
|
18
18
|
puts parser_
|
|
19
19
|
exit
|
|
20
20
|
end
|
|
21
|
-
parser_.on(
|
|
22
|
-
parser_.on(
|
|
23
|
-
parser_.on(
|
|
21
|
+
parser_.on('-o', '--output PATH', 'Update a table of contents in the file at PATH')
|
|
22
|
+
parser_.on('-a', '--[no-]append', "Append to the --output file if a <!-- mdtoc --> tag isn't found")
|
|
23
|
+
parser_.on('-c', '--[no-]create', 'Create the --output file if it does not exist')
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
options = Options.new
|
|
27
27
|
options.paths = parser.parse(args, into: options)
|
|
28
28
|
if options.paths.empty?
|
|
29
|
-
warn(
|
|
29
|
+
warn('Specify at least one file or directory to read')
|
|
30
30
|
exit(1)
|
|
31
31
|
end
|
|
32
32
|
options
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'sorbet-runtime'
|
|
5
|
+
|
|
6
|
+
module Mdtoc
|
|
7
|
+
module Markdown
|
|
8
|
+
module FragmentGenerator
|
|
9
|
+
extend T::Sig
|
|
10
|
+
extend T::Helpers
|
|
11
|
+
|
|
12
|
+
interface!
|
|
13
|
+
|
|
14
|
+
sig { abstract.params(label: String).returns(String) }
|
|
15
|
+
def generate(label); end
|
|
16
|
+
|
|
17
|
+
class GitHub
|
|
18
|
+
extend T::Sig
|
|
19
|
+
include FragmentGenerator
|
|
20
|
+
|
|
21
|
+
sig { void }
|
|
22
|
+
def initialize
|
|
23
|
+
@counts = T.let(Hash.new(0), T::Hash[String, Integer])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
sig { override.params(label: String).returns(String) }
|
|
27
|
+
def generate(label)
|
|
28
|
+
# GitHub's fragment generation:
|
|
29
|
+
# 1. Downcase
|
|
30
|
+
# 2. Replace spaces with dashes
|
|
31
|
+
# 3. Remove non-alphanumeric characters (keeping dashes, dots and underscores)
|
|
32
|
+
# 4. Collapse multiple dashes
|
|
33
|
+
# 5. Remove leading/trailing dashes and dots (common in many implementations)
|
|
34
|
+
fragment = label.downcase.tr(' ', '-').gsub(/[^\w.-]/, '')
|
|
35
|
+
fragment = fragment.gsub(/-+/, '-')
|
|
36
|
+
fragment = fragment.gsub(/^[.-]+|[.-]+$/, '')
|
|
37
|
+
|
|
38
|
+
count = @counts[fragment]
|
|
39
|
+
@counts[fragment] += 1
|
|
40
|
+
|
|
41
|
+
if count.positive?
|
|
42
|
+
"#{fragment}-#{count}"
|
|
43
|
+
else
|
|
44
|
+
fragment
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# typed: true
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require
|
|
4
|
+
require 'sorbet-runtime'
|
|
5
|
+
require_relative 'fragment_generator'
|
|
5
6
|
|
|
6
7
|
module Mdtoc
|
|
7
8
|
module Markdown
|
|
@@ -10,9 +11,7 @@ module Mdtoc
|
|
|
10
11
|
|
|
11
12
|
sig { params(depth: Integer, label: String, url: String).void }
|
|
12
13
|
def initialize(depth, label, url)
|
|
13
|
-
|
|
14
|
-
raise ArgumentError, "Header depth must be >= 0, but was #{depth}"
|
|
15
|
-
end
|
|
14
|
+
raise ArgumentError, "Header depth must be >= 0, but was #{depth}" if depth.negative?
|
|
16
15
|
|
|
17
16
|
@depth = depth
|
|
18
17
|
@label = normalize_label(label)
|
|
@@ -21,7 +20,7 @@ module Mdtoc
|
|
|
21
20
|
|
|
22
21
|
sig { returns(String) }
|
|
23
22
|
def to_s
|
|
24
|
-
prefix =
|
|
23
|
+
prefix = ' ' * 2 * @depth
|
|
25
24
|
"#{prefix}* [#{@label}](#{@url})"
|
|
26
25
|
end
|
|
27
26
|
|
|
@@ -33,16 +32,23 @@ module Mdtoc
|
|
|
33
32
|
private
|
|
34
33
|
|
|
35
34
|
def normalize_label(label)
|
|
36
|
-
label = label.strip.tr("\t\n\r",
|
|
37
|
-
label.gsub(/\[(
|
|
35
|
+
label = label.strip.tr("\t\n\r", '') # Remove whitespace characters other than spaces.
|
|
36
|
+
label.gsub(/\[(.*?)\]\(.*?\)/, '\1') # Remove links
|
|
38
37
|
end
|
|
39
38
|
end
|
|
40
39
|
|
|
41
40
|
class HeaderWithFragment < Header
|
|
42
|
-
sig
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
sig do
|
|
42
|
+
params(
|
|
43
|
+
depth: Integer,
|
|
44
|
+
label: String,
|
|
45
|
+
url: String,
|
|
46
|
+
generator: FragmentGenerator
|
|
47
|
+
).void
|
|
48
|
+
end
|
|
49
|
+
def initialize(depth, label, url, generator:)
|
|
50
|
+
super(depth, label, url)
|
|
51
|
+
@url += "##{generator.generate(@label)}"
|
|
46
52
|
end
|
|
47
53
|
end
|
|
48
54
|
end
|
|
@@ -1,45 +1,104 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require_relative
|
|
4
|
+
require 'sorbet-runtime'
|
|
5
|
+
require_relative 'header'
|
|
6
|
+
require_relative 'fragment_generator'
|
|
6
7
|
|
|
7
8
|
module Mdtoc
|
|
8
9
|
module Markdown
|
|
9
10
|
class Parser
|
|
10
11
|
extend T::Sig
|
|
11
12
|
|
|
12
|
-
sig
|
|
13
|
-
|
|
13
|
+
sig do
|
|
14
|
+
params(
|
|
15
|
+
depth: Integer,
|
|
16
|
+
url: String,
|
|
17
|
+
generator: FragmentGenerator
|
|
18
|
+
).void
|
|
19
|
+
end
|
|
20
|
+
def initialize(depth, url, generator: FragmentGenerator::GitHub.new)
|
|
14
21
|
@depth = depth
|
|
15
22
|
@url = url
|
|
23
|
+
@generator = generator
|
|
24
|
+
@in_code_block = T.let(false, T::Boolean)
|
|
25
|
+
@in_html_comment = T.let(false, T::Boolean)
|
|
16
26
|
end
|
|
17
27
|
|
|
18
28
|
sig { params(lines: T::Enumerable[String]).returns(T::Array[Header]) }
|
|
19
29
|
def headers(lines)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
@in_code_block = false
|
|
31
|
+
@in_html_comment = false
|
|
32
|
+
|
|
33
|
+
headers = T.let([], T::Array[Header])
|
|
34
|
+
prev_line = T.let(nil, T.nilable(String))
|
|
35
|
+
|
|
36
|
+
lines.each do |line|
|
|
37
|
+
stripped = line.strip
|
|
38
|
+
|
|
39
|
+
if skip_line?(line, stripped)
|
|
40
|
+
prev_line = line
|
|
41
|
+
next
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
if line.start_with?('#')
|
|
45
|
+
headers << header(line)
|
|
46
|
+
elsif (h = process_setext_header(stripped, prev_line))
|
|
47
|
+
headers << h
|
|
27
48
|
end
|
|
28
|
-
next if skip || !line.start_with?("#")
|
|
29
49
|
|
|
30
|
-
|
|
50
|
+
prev_line = line
|
|
31
51
|
end
|
|
52
|
+
|
|
53
|
+
headers
|
|
32
54
|
end
|
|
33
55
|
|
|
34
56
|
private
|
|
35
57
|
|
|
58
|
+
sig { params(line: String, stripped: String).returns(T::Boolean) }
|
|
59
|
+
def skip_line?(line, stripped)
|
|
60
|
+
html_comment?(stripped) || code_block?(line)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
sig { params(stripped: String).returns(T::Boolean) }
|
|
64
|
+
def html_comment?(stripped)
|
|
65
|
+
if stripped.start_with?('<!--')
|
|
66
|
+
@in_html_comment = true unless stripped.end_with?('-->')
|
|
67
|
+
return true
|
|
68
|
+
elsif @in_html_comment && stripped.end_with?('-->')
|
|
69
|
+
@in_html_comment = false
|
|
70
|
+
return true
|
|
71
|
+
end
|
|
72
|
+
@in_html_comment
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
sig { params(line: String).returns(T::Boolean) }
|
|
76
|
+
def code_block?(line)
|
|
77
|
+
if line.start_with?('```') && !T.must(line[3..]).strip.end_with?('```')
|
|
78
|
+
@in_code_block = !@in_code_block
|
|
79
|
+
return true
|
|
80
|
+
end
|
|
81
|
+
@in_code_block
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
sig { params(stripped: String, prev_line: T.nilable(String)).returns(T.nilable(Header)) }
|
|
85
|
+
def process_setext_header(stripped, prev_line)
|
|
86
|
+
return nil unless prev_line && !prev_line.strip.empty?
|
|
87
|
+
|
|
88
|
+
if stripped.match?(/^=+$/)
|
|
89
|
+
HeaderWithFragment.new(@depth, prev_line.strip, @url, generator: @generator)
|
|
90
|
+
elsif stripped.match?(/^-+$/)
|
|
91
|
+
HeaderWithFragment.new(@depth + 1, prev_line.strip, @url, generator: @generator)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
36
95
|
sig { params(line: String).returns(HeaderWithFragment) }
|
|
37
96
|
def header(line)
|
|
38
97
|
m = T.must(line.strip.match(/^(#+)\s*(.*)$/))
|
|
39
|
-
num_hashes = m[1]&.count(
|
|
98
|
+
num_hashes = m[1]&.count('#') || 1
|
|
40
99
|
depth = @depth + num_hashes - 1
|
|
41
|
-
label = m[2] ||
|
|
42
|
-
HeaderWithFragment.new(depth, label, @url)
|
|
100
|
+
label = m[2] || ''
|
|
101
|
+
HeaderWithFragment.new(depth, label, @url, generator: @generator)
|
|
43
102
|
end
|
|
44
103
|
end
|
|
45
104
|
end
|
data/lib/mdtoc/node.rb
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require_relative
|
|
7
|
-
require_relative
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require 'sorbet-runtime'
|
|
6
|
+
require_relative 'markdown/header'
|
|
7
|
+
require_relative 'markdown/parser'
|
|
8
8
|
|
|
9
9
|
module Mdtoc
|
|
10
10
|
class Node
|
|
11
11
|
extend T::Helpers
|
|
12
12
|
extend T::Sig
|
|
13
|
+
|
|
13
14
|
abstract!
|
|
14
15
|
|
|
15
16
|
class << self
|
|
@@ -18,10 +19,9 @@ module Mdtoc
|
|
|
18
19
|
sig { params(path: String, depth: Integer).returns(Node) }
|
|
19
20
|
def for_path(path, depth = 0)
|
|
20
21
|
# Ensure that `path` is a relative path, so that all links are relative and therefore portable.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
File.directory?(path) ? DirNode.new(path, depth) : FileNode.new(path, depth)
|
|
22
|
+
pathname = Pathname.new(path)
|
|
23
|
+
pathname = pathname.relative_path_from(Dir.pwd) if pathname.absolute?
|
|
24
|
+
pathname.directory? ? DirNode.new(pathname, depth) : FileNode.new(pathname, depth)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
sig { params(paths: T::Array[String]).returns(String) }
|
|
@@ -32,7 +32,7 @@ module Mdtoc
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
sig { params(path:
|
|
35
|
+
sig { params(path: Pathname, depth: Integer).void }
|
|
36
36
|
def initialize(path, depth)
|
|
37
37
|
@path = path
|
|
38
38
|
@depth = depth
|
|
@@ -43,22 +43,30 @@ module Mdtoc
|
|
|
43
43
|
|
|
44
44
|
sig { returns(String) }
|
|
45
45
|
def label
|
|
46
|
-
|
|
46
|
+
@path.basename(@path.extname).to_s.gsub(/_+/, ' ').gsub(/\s+/, ' ').capitalize
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
class DirNode < Node
|
|
50
50
|
sig { override.returns(T::Array[Mdtoc::Markdown::Header]) }
|
|
51
51
|
def headers
|
|
52
|
-
readme_path = T.let(nil, T.nilable(
|
|
53
|
-
|
|
54
|
-
.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
readme_path = T.let(nil, T.nilable(Pathname))
|
|
53
|
+
children = @path.children.reject do |child|
|
|
54
|
+
if child.basename.to_s.casecmp?('readme.md')
|
|
55
|
+
readme_path = child
|
|
56
|
+
true
|
|
57
|
+
else
|
|
58
|
+
false
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
child_headers = children.sort.flat_map do |child|
|
|
63
|
+
Node.for_path(child.to_s, @depth + 1).headers
|
|
64
|
+
end
|
|
65
|
+
|
|
58
66
|
return child_headers unless readme_path
|
|
59
67
|
|
|
60
68
|
# Include the headers from the README at the beginning.
|
|
61
|
-
readme_headers = FileNode.new(readme_path, @depth).headers
|
|
69
|
+
readme_headers = FileNode.new(T.must(readme_path), @depth).headers
|
|
62
70
|
readme_headers + child_headers
|
|
63
71
|
end
|
|
64
72
|
end
|
|
@@ -66,11 +74,12 @@ module Mdtoc
|
|
|
66
74
|
class FileNode < Node
|
|
67
75
|
sig { override.returns(T::Array[Mdtoc::Markdown::Header]) }
|
|
68
76
|
def headers
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
path_s = @path.to_s
|
|
78
|
+
parser = Markdown::Parser.new(@depth, path_s)
|
|
79
|
+
headers = parser.headers(@path.each_line)
|
|
71
80
|
return headers if headers[0]&.top_level?(@depth)
|
|
72
81
|
|
|
73
|
-
headers.unshift(Mdtoc::Markdown::Header.new(@depth, label,
|
|
82
|
+
headers.unshift(Mdtoc::Markdown::Header.new(@depth, label, path_s))
|
|
74
83
|
end
|
|
75
84
|
end
|
|
76
85
|
end
|
data/lib/mdtoc/version.rb
CHANGED
data/lib/mdtoc/writer.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: true
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'tempfile'
|
|
6
|
+
|
|
4
7
|
module Mdtoc
|
|
5
8
|
module Writer
|
|
6
|
-
COMMENT_BEGIN =
|
|
7
|
-
COMMENT_END =
|
|
9
|
+
COMMENT_BEGIN = '<!-- mdtoc -->'
|
|
10
|
+
COMMENT_END = '<!-- mdtoc-end -->'
|
|
8
11
|
|
|
9
12
|
class << self
|
|
10
13
|
extend T::Sig
|
|
@@ -13,8 +16,15 @@ module Mdtoc
|
|
|
13
16
|
def write(toc, path, append, create)
|
|
14
17
|
validate_path(path, create)
|
|
15
18
|
new_content = content(toc, path, append)
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
|
|
20
|
+
# Write to a temporary file and rename it to the target path to ensure atomic writing.
|
|
21
|
+
temp = Tempfile.new(File.basename(path), File.dirname(path))
|
|
22
|
+
begin
|
|
23
|
+
temp.write(new_content)
|
|
24
|
+
temp.close
|
|
25
|
+
FileUtils.mv(temp.path, path)
|
|
26
|
+
ensure
|
|
27
|
+
temp.close!
|
|
18
28
|
end
|
|
19
29
|
end
|
|
20
30
|
|
|
@@ -25,17 +35,12 @@ module Mdtoc
|
|
|
25
35
|
toc = "#{COMMENT_BEGIN}\n#{toc}\n#{COMMENT_END}"
|
|
26
36
|
|
|
27
37
|
begin
|
|
28
|
-
|
|
29
|
-
rescue
|
|
30
|
-
# If File.
|
|
38
|
+
old_content = File.read(path)
|
|
39
|
+
rescue StandardError
|
|
40
|
+
# If File.read failed because the file didn't exist, then we know that --create
|
|
31
41
|
# was specified due to the validation in validate_path.
|
|
32
42
|
return "#{toc}\n"
|
|
33
43
|
end
|
|
34
|
-
begin
|
|
35
|
-
old_content = T.must(f.read)
|
|
36
|
-
ensure
|
|
37
|
-
f.close
|
|
38
|
-
end
|
|
39
44
|
|
|
40
45
|
if Regexp.new(Regexp.escape(COMMENT_BEGIN), Regexp::IGNORECASE).match?(old_content)
|
|
41
46
|
return old_content.gsub(
|
data/lib/mdtoc.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# typed: strict
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require_relative
|
|
7
|
-
require_relative
|
|
8
|
-
require_relative
|
|
4
|
+
require 'optparse'
|
|
5
|
+
require 'tempfile'
|
|
6
|
+
require_relative 'mdtoc/cli'
|
|
7
|
+
require_relative 'mdtoc/node'
|
|
8
|
+
require_relative 'mdtoc/writer'
|
|
9
9
|
|
|
10
10
|
module Mdtoc
|
|
11
11
|
class << self
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mdtoc
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- andornaut
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -66,20 +66,6 @@ dependencies:
|
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '1.50'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: rubocop-shopify
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - ">="
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: 2.0.0
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - ">="
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: 2.0.0
|
|
83
69
|
- !ruby/object:Gem::Dependency
|
|
84
70
|
name: rubocop-sorbet
|
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -165,7 +151,7 @@ description: |
|
|
|
165
151
|
Create a `Rakefile` with the contents below, then run
|
|
166
152
|
[`rake`](https://github.com/ruby/rake) to:
|
|
167
153
|
|
|
168
|
-
* `git
|
|
154
|
+
* `git pullgem push pkg/mdtoc-0.2.0.gem`
|
|
169
155
|
* `git add` any *.md files
|
|
170
156
|
* Run `mdtoc` to update the generated table of contents in the ./README.md file
|
|
171
157
|
* Git commit and push any changes
|
|
@@ -204,10 +190,11 @@ description: |
|
|
|
204
190
|
Requirements:
|
|
205
191
|
|
|
206
192
|
* [Bundler](https://bundler.io/)
|
|
193
|
+
* [chruby](https://github.com/postmodern/chruby) (recommended)
|
|
207
194
|
|
|
208
195
|
```bash
|
|
209
|
-
#
|
|
210
|
-
|
|
196
|
+
# Setup development environment
|
|
197
|
+
bin/setup
|
|
211
198
|
```
|
|
212
199
|
|
|
213
200
|
### Tasks
|
|
@@ -215,23 +202,25 @@ description: |
|
|
|
215
202
|
```bash
|
|
216
203
|
# List rake tasks
|
|
217
204
|
$ rake -T
|
|
218
|
-
rake build # Build
|
|
219
|
-
rake default # Run the build, rubocop
|
|
220
|
-
rake install # Build and install
|
|
221
|
-
rake install:local # Build and install mdtoc-0.1.5.gem into system gems without network access
|
|
222
|
-
rake release[remote] # Create tag v0.1.5 and build and push mdtoc-0.1.5.gem to rubygems.org
|
|
205
|
+
rake build # Build gem into the pkg directory
|
|
206
|
+
rake default # Run the build, rubocop, sorbet and test tasks
|
|
207
|
+
rake install # Build and install gem into system gems
|
|
223
208
|
rake rubocop # Run RuboCop
|
|
224
|
-
rake rubocop:autocorrect # Autocorrect RuboCop offenses (only when it's safe)
|
|
225
|
-
rake rubocop:autocorrect_all # Autocorrect RuboCop offenses (safe and unsafe)
|
|
226
209
|
rake sorbet # Run the Sorbet type checker
|
|
227
210
|
rake test # Run tests
|
|
228
|
-
|
|
211
|
+
```
|
|
229
212
|
# Run mdtoc with test inputs
|
|
230
213
|
$ ruby -Ilib bin/mdtoc test/samples
|
|
231
214
|
|
|
232
215
|
# Run mdtoc with test inputs, and write to a newly created output file
|
|
233
216
|
$ f=$(mktemp) && ruby -Ilib bin/mdtoc -aco ${f} test/samples ; cat ${f}
|
|
234
217
|
```
|
|
218
|
+
|
|
219
|
+
### Publishing
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
rake release
|
|
223
|
+
```
|
|
235
224
|
email:
|
|
236
225
|
executables:
|
|
237
226
|
- mdtoc
|
|
@@ -241,6 +230,7 @@ files:
|
|
|
241
230
|
- bin/mdtoc
|
|
242
231
|
- lib/mdtoc.rb
|
|
243
232
|
- lib/mdtoc/cli.rb
|
|
233
|
+
- lib/mdtoc/markdown/fragment_generator.rb
|
|
244
234
|
- lib/mdtoc/markdown/header.rb
|
|
245
235
|
- lib/mdtoc/markdown/parser.rb
|
|
246
236
|
- lib/mdtoc/node.rb
|
|
@@ -249,7 +239,8 @@ files:
|
|
|
249
239
|
homepage: https://github.com/andornaut/mdtoc
|
|
250
240
|
licenses:
|
|
251
241
|
- MIT
|
|
252
|
-
metadata:
|
|
242
|
+
metadata:
|
|
243
|
+
rubygems_mfa_required: 'true'
|
|
253
244
|
post_install_message:
|
|
254
245
|
rdoc_options: []
|
|
255
246
|
require_paths:
|
|
@@ -265,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
265
256
|
- !ruby/object:Gem::Version
|
|
266
257
|
version: '0'
|
|
267
258
|
requirements: []
|
|
268
|
-
rubygems_version: 3.
|
|
259
|
+
rubygems_version: 3.4.10
|
|
269
260
|
signing_key:
|
|
270
261
|
specification_version: 4
|
|
271
262
|
summary: Read Markdown files and output a table of contents
|