mdtoc 0.1.3 → 0.1.4
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.rb +2 -14
- data/lib/mdtoc/cli.rb +16 -14
- data/lib/mdtoc/markdown/header.rb +41 -0
- data/lib/mdtoc/{markdown.rb → markdown/parser.rb} +2 -34
- data/lib/mdtoc/node.rb +25 -15
- data/lib/mdtoc/version.rb +1 -1
- data/lib/mdtoc/writer.rb +7 -9
- metadata +99 -13
- data/test/samples/README.md +0 -18
- data/test/samples/a/c.md +0 -2
- data/test/samples/a/d/f.md +0 -1
- data/test/samples/a/e.md +0 -1
- data/test/samples/a/g/README.md +0 -1
- data/test/samples/a/g/h.md +0 -1
- data/test/samples/a/readme.md +0 -4
- data/test/test_markdown.rb +0 -127
- data/test/test_node.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b54718ab7b2f7bbc8e90ae473318895665986e0a7408674670db03294f12d6e
|
4
|
+
data.tar.gz: f1b251a78ba55942f8c85d82b99f614d3b9368541b7dcb1f144d1094e293d01f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 247816469ed9798906c93e6ca0c58bd4b863d379795d9f776b71fc6c7d3835d7eb4ee890372a408ee04981658336a5f924156d85456e66d90793e0d58b7bd9e2
|
7
|
+
data.tar.gz: 2c10991bfa7f4b95896d468f803bae94b44899fc695c1113bd6fa6d7d90c784f4303939a7c2637ed70cd6335bf51f66688d6c932b03a6c0d284f5060cc009646
|
data/lib/mdtoc.rb
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
require 'optparse'
|
5
5
|
require 'tempfile'
|
6
6
|
require_relative 'mdtoc/cli'
|
7
|
-
require_relative 'mdtoc/markdown'
|
8
7
|
require_relative 'mdtoc/node'
|
9
8
|
require_relative 'mdtoc/writer'
|
10
9
|
|
@@ -14,8 +13,8 @@ module Mdtoc
|
|
14
13
|
|
15
14
|
sig { params(args: T::Array[String]).void }
|
16
15
|
def main(args)
|
17
|
-
options = Mdtoc::CLI
|
18
|
-
toc =
|
16
|
+
options = Mdtoc::CLI.parse(args)
|
17
|
+
toc = Mdtoc::Node.render(options.paths)
|
19
18
|
unless options.output
|
20
19
|
puts toc
|
21
20
|
return
|
@@ -23,17 +22,6 @@ module Mdtoc
|
|
23
22
|
|
24
23
|
Mdtoc::Writer.write(toc, T.must(options.output), options.append, options.create)
|
25
24
|
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
sig { params(paths: T::Array[String]).returns(String) }
|
30
|
-
def render_toc(paths)
|
31
|
-
paths
|
32
|
-
.map { |path| Mdtoc::Node.for_path(path).headers }
|
33
|
-
.flatten(1)
|
34
|
-
.map(&:to_s)
|
35
|
-
.join("\n")
|
36
|
-
end
|
37
25
|
end
|
38
26
|
end
|
39
27
|
|
data/lib/mdtoc/cli.rb
CHANGED
@@ -4,26 +4,14 @@
|
|
4
4
|
require 'optparse'
|
5
5
|
require 'sorbet-runtime'
|
6
6
|
require 'tempfile'
|
7
|
-
require_relative 'markdown'
|
8
|
-
require_relative 'node'
|
9
|
-
require_relative 'writer'
|
10
7
|
|
11
8
|
module Mdtoc
|
12
9
|
module CLI
|
13
|
-
class
|
10
|
+
class << self
|
14
11
|
extend T::Sig
|
15
12
|
|
16
|
-
prop :append, T::Boolean, default: false
|
17
|
-
prop :create, T::Boolean, default: false
|
18
|
-
prop :output, T.nilable(String)
|
19
|
-
prop :paths, T::Array[String], default: []
|
20
|
-
|
21
|
-
def []=(key, val)
|
22
|
-
send("#{key}=", val)
|
23
|
-
end
|
24
|
-
|
25
13
|
sig { params(args: T::Array[String]).returns(Options) }
|
26
|
-
def
|
14
|
+
def parse(args)
|
27
15
|
parser = OptionParser.new do |parser_|
|
28
16
|
parser_.banner = "Usage: #{parser_.program_name} [options] files or directories..."
|
29
17
|
parser_.on('-h', '--help', 'Show this message') do
|
@@ -44,5 +32,19 @@ module Mdtoc
|
|
44
32
|
options
|
45
33
|
end
|
46
34
|
end
|
35
|
+
|
36
|
+
class Options < T::Struct
|
37
|
+
extend T::Sig
|
38
|
+
|
39
|
+
prop :append, T::Boolean, default: false
|
40
|
+
prop :create, T::Boolean, default: false
|
41
|
+
prop :output, T.nilable(String)
|
42
|
+
prop :paths, T::Array[String], default: []
|
43
|
+
|
44
|
+
sig { params(key: Symbol, val: T.untyped).returns(T.untyped) }
|
45
|
+
def []=(key, val)
|
46
|
+
send("#{key}=", val)
|
47
|
+
end
|
48
|
+
end
|
47
49
|
end
|
48
50
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'sorbet-runtime'
|
5
|
+
|
6
|
+
module Mdtoc
|
7
|
+
module Markdown
|
8
|
+
class Header
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig { params(depth: Integer, label: String, url: String).void }
|
12
|
+
def initialize(depth, label, url)
|
13
|
+
if depth < 0
|
14
|
+
raise ArgumentError, "Header depth must be >= 0, but was #{depth}"
|
15
|
+
end
|
16
|
+
@depth = depth
|
17
|
+
@label = label.strip.gsub(/\s+/, ' ')
|
18
|
+
@url = url
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { returns(String) }
|
22
|
+
def to_s
|
23
|
+
prefix = ' ' * 2 * @depth
|
24
|
+
"#{prefix}* [#{@label}](#{@url})"
|
25
|
+
end
|
26
|
+
|
27
|
+
sig { params(relative_to_depth: Integer).returns(T::Boolean) }
|
28
|
+
def top_level?(relative_to_depth)
|
29
|
+
@depth == relative_to_depth
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class HeaderWithFragment < Header
|
34
|
+
sig { params(depth: Integer, label: String, url: String).void }
|
35
|
+
def initialize(depth, label, url)
|
36
|
+
url = "#{url}##{label.strip.downcase.tr(' ', '-').gsub(/[^\w\-]/, '')}"
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -2,42 +2,10 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'sorbet-runtime'
|
5
|
+
require_relative 'header'
|
5
6
|
|
6
7
|
module Mdtoc
|
7
8
|
module Markdown
|
8
|
-
class Header
|
9
|
-
extend T::Sig
|
10
|
-
|
11
|
-
sig { params(depth: Integer, label: String, url: String).void }
|
12
|
-
def initialize(depth, label, url)
|
13
|
-
if depth < 0
|
14
|
-
raise ArgumentError, "Header depth must be >= 0, but was #{depth}"
|
15
|
-
end
|
16
|
-
@depth = depth
|
17
|
-
@label = label.strip.gsub(/\s+/, ' ')
|
18
|
-
@url = url
|
19
|
-
end
|
20
|
-
|
21
|
-
sig { params(relative_to_depth: Integer).returns(T::Boolean) }
|
22
|
-
def top_level?(relative_to_depth)
|
23
|
-
@depth == relative_to_depth
|
24
|
-
end
|
25
|
-
|
26
|
-
sig { returns(String) }
|
27
|
-
def to_s
|
28
|
-
prefix = ' ' * 2 * @depth
|
29
|
-
"#{prefix}* [#{@label}](#{@url})"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class HeaderWithFragment < Header
|
34
|
-
sig { params(depth: Integer, label: String, url: String).void }
|
35
|
-
def initialize(depth, label, url)
|
36
|
-
url = "#{url}##{label.downcase.strip.gsub(/ /, '-').gsub(/[^\w\-_ ]/, '')}"
|
37
|
-
super
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
9
|
class Parser
|
42
10
|
extend T::Sig
|
43
11
|
|
@@ -65,7 +33,7 @@ module Mdtoc
|
|
65
33
|
|
66
34
|
private
|
67
35
|
|
68
|
-
sig { params(line: String).returns(
|
36
|
+
sig { params(line: String).returns(HeaderWithFragment) }
|
69
37
|
def header(line)
|
70
38
|
m = T.must(line.strip.match(/^(#+)\s*(.*)$/))
|
71
39
|
num_hashes = m[1]&.count('#') || 1
|
data/lib/mdtoc/node.rb
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
|
4
4
|
require 'pathname'
|
5
5
|
require 'sorbet-runtime'
|
6
|
-
require_relative 'markdown'
|
6
|
+
require_relative 'markdown/header'
|
7
|
+
require_relative 'markdown/parser'
|
7
8
|
|
8
9
|
module Mdtoc
|
9
10
|
class Node
|
@@ -11,13 +12,24 @@ module Mdtoc
|
|
11
12
|
extend T::Sig
|
12
13
|
abstract!
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
path
|
18
|
-
path =
|
19
|
-
|
20
|
-
|
15
|
+
class << self
|
16
|
+
extend T::Sig
|
17
|
+
|
18
|
+
sig { params(path: String, depth: Integer).returns(Node) }
|
19
|
+
def for_path(path, depth = 0)
|
20
|
+
# Ensure that `path` is a relative path, so that all links are relative and therefore portable.
|
21
|
+
path = Pathname.new(path)
|
22
|
+
path = path.relative_path_from(Dir.pwd) if path.absolute?
|
23
|
+
path = path.to_s
|
24
|
+
File.directory?(path) ? DirNode.new(path, depth) : FileNode.new(path, depth)
|
25
|
+
end
|
26
|
+
|
27
|
+
sig { params(paths: T::Array[String]).returns(String) }
|
28
|
+
def render(paths)
|
29
|
+
paths
|
30
|
+
.flat_map { |path| for_path(path).headers }
|
31
|
+
.join("\n")
|
32
|
+
end
|
21
33
|
end
|
22
34
|
|
23
35
|
sig { params(path: String, depth: Integer).void }
|
@@ -26,13 +38,13 @@ module Mdtoc
|
|
26
38
|
@depth = depth
|
27
39
|
end
|
28
40
|
|
41
|
+
sig { abstract.returns(T::Array[Mdtoc::Markdown::Header]) }
|
42
|
+
def headers; end
|
43
|
+
|
29
44
|
sig { returns(String) }
|
30
45
|
def label
|
31
46
|
File.basename(@path, File.extname(@path)).gsub(/_+/, ' ').gsub(/\s+/, ' ').capitalize
|
32
47
|
end
|
33
|
-
|
34
|
-
sig { abstract.returns(T::Array[Mdtoc::Markdown::Header]) }
|
35
|
-
def headers; end
|
36
48
|
end
|
37
49
|
|
38
50
|
class DirNode < Node
|
@@ -41,11 +53,9 @@ module Mdtoc
|
|
41
53
|
readme_path = T.let(nil, T.nilable(String))
|
42
54
|
child_headers = Dir
|
43
55
|
.each_child(@path)
|
44
|
-
.
|
45
|
-
.reject { |path| readme_path = path if File.basename(path).downcase == 'readme.md' }
|
56
|
+
.reject { |path| readme_path = File.join(@path, path) if path.casecmp?('readme.md') }
|
46
57
|
.sort!
|
47
|
-
.
|
48
|
-
.flatten(1)
|
58
|
+
.flat_map { |path| Node.for_path(File.join(@path, path), @depth + 1).headers }
|
49
59
|
return child_headers unless readme_path
|
50
60
|
|
51
61
|
# Include the headers from the README at the beginning.
|
data/lib/mdtoc/version.rb
CHANGED
data/lib/mdtoc/writer.rb
CHANGED
@@ -28,7 +28,7 @@ module Mdtoc
|
|
28
28
|
f = File.open(path)
|
29
29
|
rescue
|
30
30
|
# If File.open failed because the file didn't exist, then we know that --create
|
31
|
-
# was specified due to the validation in
|
31
|
+
# was specified due to the validation in validate_path.
|
32
32
|
return "#{toc}\n"
|
33
33
|
end
|
34
34
|
begin
|
@@ -51,16 +51,14 @@ module Mdtoc
|
|
51
51
|
|
52
52
|
sig { params(path: String, create: T::Boolean).void }
|
53
53
|
def validate_path(path, create)
|
54
|
-
if path
|
55
|
-
|
56
|
-
|
57
|
-
warn("--output PATH \"#{path}\" is not a regular file")
|
58
|
-
exit
|
59
|
-
end
|
60
|
-
elsif !create
|
61
|
-
warn("--output PATH \"#{path}\" does not exist. Specify --create to create it.")
|
54
|
+
if File.exist?(path)
|
55
|
+
unless File.file?(path)
|
56
|
+
warn("--output PATH \"#{path}\" is not a regular file")
|
62
57
|
exit
|
63
58
|
end
|
59
|
+
elsif !create
|
60
|
+
warn("--output PATH \"#{path}\" does not exist. Specify --create to create it.")
|
61
|
+
exit
|
64
62
|
end
|
65
63
|
end
|
66
64
|
end
|
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.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- andornaut
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -122,7 +122,101 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
-
description:
|
125
|
+
description: |
|
126
|
+
# mdtoc - Markdown Table of Contents
|
127
|
+
|
128
|
+
Read Markdown files and output a table of contents.
|
129
|
+
|
130
|
+
## Installation
|
131
|
+
|
132
|
+
Requirements:
|
133
|
+
|
134
|
+
* [Ruby](https://www.ruby-lang.org/en/) (see [.ruby-version](./.ruby-version))
|
135
|
+
|
136
|
+
```
|
137
|
+
$ gem install mdtoc
|
138
|
+
```
|
139
|
+
|
140
|
+
## Usage
|
141
|
+
|
142
|
+
```
|
143
|
+
$ mdtoc --help
|
144
|
+
Usage: mdtoc [options] files or directories...
|
145
|
+
-h, --help Show this message
|
146
|
+
-o, --output PATH Update a table of contents in the file at PATH
|
147
|
+
-a, --[no-]append Append to the --output file if a <!-- mdtoc --> tag isn't found
|
148
|
+
-c, --[no-]create Create the --output file if it does not exist
|
149
|
+
```
|
150
|
+
|
151
|
+
1. Add a `<!-- mdtoc -->` tag to a Markdown file.
|
152
|
+
```
|
153
|
+
$ echo '<!-- mdtoc -->` >> README.md
|
154
|
+
```
|
155
|
+
2. Run `mdtoc` and specify input files or directories (eg. the "test/samples" directory) and an output file (eg. "README.md").
|
156
|
+
```
|
157
|
+
$ mdtoc -aco README.md test/samples
|
158
|
+
```
|
159
|
+
|
160
|
+
## Example Rakefile
|
161
|
+
|
162
|
+
Run the [rake](https://github.com/ruby/rake) "mdtoc" task to update a table of contents.
|
163
|
+
See [andornaut/til](https://github.com/andornaut/til) for an example.
|
164
|
+
|
165
|
+
```
|
166
|
+
task default: %w[mdtoc]
|
167
|
+
|
168
|
+
desc 'Update Markdown table of contents and push changes to the git repository'
|
169
|
+
task :mdtoc do |t|
|
170
|
+
command = <<~END
|
171
|
+
set -e
|
172
|
+
git pull
|
173
|
+
if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
|
174
|
+
echo 'Error: conflicts exist' >&2
|
175
|
+
exit 1
|
176
|
+
fi
|
177
|
+
mdtoc --append --create --output README.md docs/
|
178
|
+
git add *.md **/*.md
|
179
|
+
git commit -m 'Update TOC'
|
180
|
+
git push
|
181
|
+
END
|
182
|
+
%x|#{command}|
|
183
|
+
end
|
184
|
+
```
|
185
|
+
|
186
|
+
## Development
|
187
|
+
|
188
|
+
### Installation
|
189
|
+
|
190
|
+
Requirements:
|
191
|
+
|
192
|
+
* [Bundler](https://bundler.io/)
|
193
|
+
|
194
|
+
```
|
195
|
+
# Install dependencies
|
196
|
+
$ bundle
|
197
|
+
```
|
198
|
+
|
199
|
+
### Usage
|
200
|
+
|
201
|
+
```
|
202
|
+
# List rake tasks
|
203
|
+
$ rake -T
|
204
|
+
rake build # Build mdtoc-0.0.2.gem into the pkg directory
|
205
|
+
rake default # Run the build, rubocop:auto_correct, sorbet and test tasks
|
206
|
+
rake install # Build and install mdtoc-0.0.2.gem into system gems
|
207
|
+
rake install:local # Build and install mdtoc-0.0.2.gem into system gems without...
|
208
|
+
rake release[remote] # Create tag v0.0.2 and build and push mdtoc-0.0.2.gem to ru...
|
209
|
+
rake rubocop # Run RuboCop
|
210
|
+
rake rubocop:auto_correct # Auto-correct RuboCop offenses
|
211
|
+
rake sorbet # Run the Sorbet type checker
|
212
|
+
rake test # Run tests
|
213
|
+
|
214
|
+
# Run mdtoc with test inputs
|
215
|
+
$ ruby -Ilib bin/mdtoc test/samples
|
216
|
+
|
217
|
+
# Run mdtoc with test inputs, and write to a newly created output file
|
218
|
+
$ f=$(mktemp) && ruby -Ilib bin/mdtoc -aco ${f} test/samples ; cat ${f}
|
219
|
+
```
|
126
220
|
email:
|
127
221
|
executables:
|
128
222
|
- mdtoc
|
@@ -132,19 +226,11 @@ files:
|
|
132
226
|
- bin/mdtoc
|
133
227
|
- lib/mdtoc.rb
|
134
228
|
- lib/mdtoc/cli.rb
|
135
|
-
- lib/mdtoc/markdown.rb
|
229
|
+
- lib/mdtoc/markdown/header.rb
|
230
|
+
- lib/mdtoc/markdown/parser.rb
|
136
231
|
- lib/mdtoc/node.rb
|
137
232
|
- lib/mdtoc/version.rb
|
138
233
|
- lib/mdtoc/writer.rb
|
139
|
-
- test/samples/README.md
|
140
|
-
- test/samples/a/c.md
|
141
|
-
- test/samples/a/d/f.md
|
142
|
-
- test/samples/a/e.md
|
143
|
-
- test/samples/a/g/README.md
|
144
|
-
- test/samples/a/g/h.md
|
145
|
-
- test/samples/a/readme.md
|
146
|
-
- test/test_markdown.rb
|
147
|
-
- test/test_node.rb
|
148
234
|
homepage: https://github.com/andornaut/mdtoc
|
149
235
|
licenses:
|
150
236
|
- MIT
|
data/test/samples/README.md
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# Title
|
2
|
-
intro text
|
3
|
-
# Ignore this non-title
|
4
|
-
# ignore this non title
|
5
|
-
```
|
6
|
-
ignore this multi-line code block
|
7
|
-
```
|
8
|
-
```ignore this inline block```
|
9
|
-
<!-- ignore this comment -->
|
10
|
-
## 2
|
11
|
-
### 3
|
12
|
-
|
13
|
-
## 2
|
14
|
-
text
|
15
|
-
|
16
|
-
#### 4
|
17
|
-
text
|
18
|
-
## 2
|
data/test/samples/a/c.md
DELETED
data/test/samples/a/d/f.md
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
## f 2
|
data/test/samples/a/e.md
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# e 1
|
data/test/samples/a/g/README.md
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# README 1 for g
|
data/test/samples/a/g/h.md
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# h 1
|
data/test/samples/a/readme.md
DELETED
data/test/test_markdown.rb
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "minitest/autorun"
|
5
|
-
require "mdtoc/markdown"
|
6
|
-
|
7
|
-
class TestHeader < Minitest::Test
|
8
|
-
def test_fragment_normalization
|
9
|
-
sample = [
|
10
|
-
'Spaces 1 space',
|
11
|
-
'Spaces 2 spaces',
|
12
|
-
"Spaces\t1 tab",
|
13
|
-
"Spaces\t\t2 tabs",
|
14
|
-
' Spaces leading and trailing ',
|
15
|
-
'Numbers 1234567890',
|
16
|
-
'Symbols -=~!@#$%^&',
|
17
|
-
'Symbols *()_+',
|
18
|
-
'Symbols <>?:"{}|[]\;\',./',
|
19
|
-
]
|
20
|
-
expecteds = [
|
21
|
-
'/a#spaces-1-space',
|
22
|
-
'/a#spaces--2-spaces',
|
23
|
-
'/a#spaces1-tab',
|
24
|
-
'/a#spaces2-tabs',
|
25
|
-
'/a#spaces-leading-and-trailing',
|
26
|
-
'/a#numbers-1234567890',
|
27
|
-
'/a#symbols--',
|
28
|
-
'/a#symbols-_',
|
29
|
-
'/a#symbols-',
|
30
|
-
]
|
31
|
-
actuals = sample.map do |label|
|
32
|
-
Mdtoc::Markdown::HeaderWithFragment.new(1, label, '/a').instance_variable_get(:@url)
|
33
|
-
end
|
34
|
-
|
35
|
-
expecteds.zip(actuals).each { |expected, actual| assert_equal(expected, actual) }
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_invalid_depth
|
39
|
-
assert_raises(ArgumentError) do
|
40
|
-
Mdtoc::Markdown::Header.new(-1, 'a', '/a')
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_label_normalization
|
45
|
-
sample = [
|
46
|
-
' strip ',
|
47
|
-
"squeeze internal \t spaces",
|
48
|
-
'Don\'t change "#1?|!@#$%^&*()+ 2--',
|
49
|
-
]
|
50
|
-
expecteds = [
|
51
|
-
'strip',
|
52
|
-
"squeeze internal spaces",
|
53
|
-
'Don\'t change "#1?|!@#$%^&*()+ 2--',
|
54
|
-
]
|
55
|
-
actuals = sample.map { |label| Mdtoc::Markdown::Header.new(0, label, '/a').instance_variable_get(:@label) }
|
56
|
-
|
57
|
-
expecteds.zip(actuals).each { |expected, actual| assert_equal(expected, actual) }
|
58
|
-
end
|
59
|
-
|
60
|
-
def test_to_s_prefix
|
61
|
-
str = Mdtoc::Markdown::Header.new(3, 'a', '/a').to_s
|
62
|
-
|
63
|
-
assert_equal(' * [a](/a)', str)
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_to_s_with_fragment
|
67
|
-
str = Mdtoc::Markdown::HeaderWithFragment.new(0, 'a', '/a').to_s
|
68
|
-
|
69
|
-
assert_equal('* [a](/a#a)', str)
|
70
|
-
end
|
71
|
-
|
72
|
-
def test_to_s_without_fragment
|
73
|
-
str = Mdtoc::Markdown::Header.new(0, 'a', '/a').to_s
|
74
|
-
|
75
|
-
assert_equal('* [a](/a)', str)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
class TestParser < Minitest::Test
|
80
|
-
def test_skips_multiline_code_blocks
|
81
|
-
parser = Mdtoc::Markdown::Parser.new(0, '/')
|
82
|
-
sample = <<~END
|
83
|
-
# title
|
84
|
-
```
|
85
|
-
code
|
86
|
-
# code
|
87
|
-
```
|
88
|
-
END
|
89
|
-
|
90
|
-
headers = parser.headers(sample.each_line)
|
91
|
-
|
92
|
-
assert_equal(1, headers.size)
|
93
|
-
assert_equal('title', headers[0].instance_variable_get(:@label))
|
94
|
-
end
|
95
|
-
|
96
|
-
def test_skips_inline_code_blocks
|
97
|
-
parser = Mdtoc::Markdown::Parser.new(0, '/')
|
98
|
-
sample = <<~END
|
99
|
-
```code #```
|
100
|
-
# Title
|
101
|
-
```# code```
|
102
|
-
```code```#
|
103
|
-
END
|
104
|
-
|
105
|
-
headers = parser.headers(sample.each_line)
|
106
|
-
|
107
|
-
assert_equal(1, headers.size)
|
108
|
-
assert_equal(headers[0].instance_variable_get(:@label), 'Title')
|
109
|
-
end
|
110
|
-
|
111
|
-
def test_depth
|
112
|
-
parser = Mdtoc::Markdown::Parser.new(10, '/')
|
113
|
-
sample = <<~END
|
114
|
-
# 1
|
115
|
-
## 2
|
116
|
-
### 3
|
117
|
-
#### 4
|
118
|
-
END
|
119
|
-
|
120
|
-
headers = parser.headers(sample.each_line)
|
121
|
-
|
122
|
-
assert_equal(4, headers.size)
|
123
|
-
(0..3).each do |i|
|
124
|
-
assert_equal(10 + i, headers[i].instance_variable_get(:@depth))
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
data/test/test_node.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "minitest/autorun"
|
5
|
-
require "mdtoc/node"
|
6
|
-
|
7
|
-
class TestNode < Minitest::Test
|
8
|
-
SAMPLE_DIR = File.join(File.dirname(__FILE__), 'samples')
|
9
|
-
|
10
|
-
def test_dir
|
11
|
-
expected = <<~END
|
12
|
-
* [readme 1](test/samples/a/readme.md#readme-1)
|
13
|
-
* [readme 2](test/samples/a/readme.md#readme-2)
|
14
|
-
* [readme 3](test/samples/a/readme.md#readme-3)
|
15
|
-
* [readme 4](test/samples/a/readme.md#readme-4)
|
16
|
-
* [c 1](test/samples/a/c.md#c-1)
|
17
|
-
* [c 2](test/samples/a/c.md#c-2)
|
18
|
-
* [F](test/samples/a/d/f.md)
|
19
|
-
* [f 2](test/samples/a/d/f.md#f-2)
|
20
|
-
* [e 1](test/samples/a/e.md#e-1)
|
21
|
-
* [README 1 for g](test/samples/a/g/README.md#readme-1-for-g)
|
22
|
-
* [h 1](test/samples/a/g/h.md#h-1)
|
23
|
-
END
|
24
|
-
node = Mdtoc::Node.for_path(sample_path('a'))
|
25
|
-
actual = node.headers.join("\n") + "\n"
|
26
|
-
|
27
|
-
assert_equal(expected, actual)
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_file
|
31
|
-
expected = <<~END
|
32
|
-
* [Title](test/samples/README.md#title)
|
33
|
-
* [2](test/samples/README.md#2)
|
34
|
-
* [3](test/samples/README.md#3)
|
35
|
-
* [2](test/samples/README.md#2)
|
36
|
-
* [4](test/samples/README.md#4)
|
37
|
-
* [2](test/samples/README.md#2)
|
38
|
-
END
|
39
|
-
node = Mdtoc::Node.for_path(sample_path('README.md'))
|
40
|
-
actual = node.headers.join("\n") + "\n"
|
41
|
-
|
42
|
-
assert_equal(expected, actual)
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def sample_path(path)
|
48
|
-
File.join('test/samples', path)
|
49
|
-
end
|
50
|
-
end
|