jekyll_outline 1.2.6 → 1.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/.rubocop.yml +7 -1
- data/CHANGELOG.md +10 -0
- data/README.md +7 -6
- data/jekyll_outline.gemspec +3 -3
- data/lib/jekyll_outline/version.rb +1 -1
- data/lib/outline_tag.rb +38 -225
- data/lib/structure/a_page_enrichment.rb +46 -0
- data/lib/structure/outline.rb +156 -0
- data/lib/structure/section.rb +38 -0
- data/lib/structure/yaml_parser.rb +58 -0
- data/spec/outline_spec.rb +148 -6
- data/spec/spec_helper.rb +17 -4
- data/spec/status_persistence.txt +3 -3
- data/spec/yaml_parser_spec.rb +84 -0
- metadata +15 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88b2d41ecbd19787d53682b396bd2bbf9eabccf2ffa366026f4792079c3f827e
|
4
|
+
data.tar.gz: 44b1fbda200ea5c9a836538fc2f8e3565bef880b1dec9a77bedec513ef15f028
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d432be906fbe832e4db55e2333c969b7b9beda06b7c391a5f43b6cd13771646cd285847d13510678adc548db642fa3f3eb3d7521737d9e0b1f48f28eaffd991
|
7
|
+
data.tar.gz: 056b5a89bdbb45d9f56016f1fd17be96c7d7a6e000c5cefbfecad28c496e540c60bcf712a024107aa34e789f59dbefdcd09d9a096077e7955ea852ae3176c41d
|
data/.rubocop.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
plugins:
|
2
2
|
# - rubocop-jekyll
|
3
3
|
- rubocop-md
|
4
4
|
- rubocop-performance
|
@@ -37,12 +37,18 @@ Metrics/BlockLength:
|
|
37
37
|
- jekyll_plugin_support.gemspec
|
38
38
|
Max: 30
|
39
39
|
|
40
|
+
Metrics/ClassLength:
|
41
|
+
Max: 150
|
42
|
+
|
40
43
|
Metrics/CyclomaticComplexity:
|
41
44
|
Max: 25
|
42
45
|
|
43
46
|
Metrics/MethodLength:
|
44
47
|
Max: 50
|
45
48
|
|
49
|
+
Metrics/ParameterLists:
|
50
|
+
Enabled: false
|
51
|
+
|
46
52
|
Metrics/PerceivedComplexity:
|
47
53
|
Max: 25
|
48
54
|
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 1.3.0 / 2025-06-04
|
4
|
+
|
5
|
+
* Now relies on `jekyll_plugin_support` v3.1.0.
|
6
|
+
* Fixed missing </div>s.
|
7
|
+
* Reimplemented using nested classes, concluding with a call `to_s`
|
8
|
+
instead of implementing crazy nesting tracking.
|
9
|
+
* The `fields` parameter was renamed to `pattern`, however for compatibility, both parameter names are accepted.
|
10
|
+
If both are provided, `pattern` has priority.
|
11
|
+
|
12
|
+
|
3
13
|
## 1.2.6 / 2025-01-03
|
4
14
|
|
5
15
|
* Added `exclude_from_outline` optional front matter YAML element.
|
data/README.md
CHANGED
@@ -41,6 +41,7 @@ This is the simplest possible outline, without images.
|
|
41
41
|
800: Digging Deeper
|
42
42
|
1900: Debugging
|
43
43
|
2700: Production
|
44
|
+
{% endoutline %}
|
44
45
|
```
|
45
46
|
|
46
47
|
### [A/V Studio Technology](https://mslinn.com/av_studio/index.html)
|
@@ -189,7 +190,7 @@ The following examples are taken from [`demo/index.html`](demo/index.html).
|
|
189
190
|
Sort by the `order` field:
|
190
191
|
|
191
192
|
```html
|
192
|
-
{% outline attribution
|
193
|
+
{% outline attribution pattern="<b> title </b> – <i> description </i>" stuff %}
|
193
194
|
000: A Topic 0..19
|
194
195
|
020: A Topic 20..39
|
195
196
|
040: A Topic 40..
|
@@ -199,7 +200,7 @@ Sort by the `order` field:
|
|
199
200
|
Sort by `title` field:
|
200
201
|
|
201
202
|
```html
|
202
|
-
{% outline attribution sort_by_title
|
203
|
+
{% outline attribution sort_by_title pattern="<b> title </b> – <i> description </i>" stuff %}
|
203
204
|
000: B Topic 0..19
|
204
205
|
020: B Topic 20..39
|
205
206
|
040: B Topic 40..
|
@@ -230,21 +231,21 @@ By default, each displayed entry consists of a document title,
|
|
230
231
|
wrapped within an <a href> HTML tag that links to the page for that entry,
|
231
232
|
followed by an indication of whether the document is visible (a draft) or not.
|
232
233
|
|
233
|
-
Entry can also include following
|
234
|
+
Entry can also include following pattern:
|
234
235
|
`draft`, `categories`, `description`, `date`, `last_modified` or `last_modified_at`, `layout`, `order`, `title`, `slug`,
|
235
236
|
`ext`, and `tags`.
|
236
237
|
|
237
|
-
Specify the
|
238
|
+
Specify the pattern like this:
|
238
239
|
|
239
240
|
```html
|
240
|
-
{% outline
|
241
|
+
{% outline pattern="title – <i> description </i>" %}
|
241
242
|
000: Topic 0..19
|
242
243
|
020: Topic 20..39
|
243
244
|
040: Topic 40..
|
244
245
|
{% endoutline %}
|
245
246
|
```
|
246
247
|
|
247
|
-
Words in the `
|
248
|
+
Words in the `pattern` argument that are not recognized as a field are transcribed into the output.
|
248
249
|
|
249
250
|
In the above example, notice that the HTML is space delimited from the field names.
|
250
251
|
The parser is simple and stupid: each token is matched against the known keywords.
|
data/jekyll_outline.gemspec
CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
36
36
|
spec.version = JekyllOutlineVersion::VERSION
|
37
37
|
|
38
|
-
spec.add_dependency 'jekyll', '>=
|
39
|
-
spec.add_dependency 'jekyll_draft', '>=
|
40
|
-
spec.add_dependency 'jekyll_plugin_support', '>= 1.0
|
38
|
+
spec.add_dependency 'jekyll', '>= 4.4.0'
|
39
|
+
spec.add_dependency 'jekyll_draft', '>= 3.0.0'
|
40
|
+
spec.add_dependency 'jekyll_plugin_support', '>= 3.1.0'
|
41
41
|
end
|
data/lib/outline_tag.rb
CHANGED
@@ -1,79 +1,51 @@
|
|
1
|
-
# @author Copyright 2022 {https://www.mslinn.com Michael Slinn}
|
2
|
-
|
3
1
|
require 'jekyll_draft'
|
4
2
|
require 'jekyll_plugin_logger'
|
5
3
|
require 'jekyll_plugin_support'
|
6
|
-
require 'yaml'
|
7
4
|
require_relative 'jekyll_outline/version'
|
5
|
+
require_relative 'structure/outline'
|
6
|
+
require_relative 'structure/yaml_parser'
|
8
7
|
|
9
|
-
#
|
10
|
-
# <div class="outer_posts">
|
11
|
-
# <h3 class="post_title clear" id="title_0">Django / Oscar Evaluation</h3>
|
12
|
-
# <div id="posts_wrapper_0" class="clearfix">
|
13
|
-
# <div id="posts_0" class="posts">
|
14
|
-
# <span>2021-02-11</span> <span><a href="/collection/page1.html">Title 1</a></span>
|
15
|
-
# <span>2023-12-09</span> <span><a href="/collection/page2.html">Title 2</a></span>
|
16
|
-
# </div>
|
17
|
-
# <h3 class="post_title clear" id="title_NNN">Notes</h3>
|
18
|
-
# <div id="posts_wrapper_NNN" class="clearfix">
|
19
|
-
# <div id="posts_400" class="posts">
|
20
|
-
# <span>2021-04-14</span> <span><a href="/collection/page3.html">Title 3</a></span>
|
21
|
-
# <span>2021-03-29</span> <span><a href="/collection/page4.html">Title 4</a></span>
|
22
|
-
# </div>
|
23
|
-
# </div>
|
24
|
-
# <div id="jps_attribute_570007" class="jps_attribute">
|
25
|
-
# <div>
|
26
|
-
# <a href="https://www.mslinn.com/jekyll_plugins/jekyll_outline.html" target="_blank" rel="nofollow">
|
27
|
-
# Generated by the jekyll_outline v1.2.1 Jekyll plugin, written by Mike Slinn 2024-01-09.
|
28
|
-
# </a>
|
29
|
-
# </div>
|
30
|
-
# </div>
|
31
|
-
# </div>
|
32
|
-
# </div>
|
33
|
-
#
|
34
|
-
# Subclasses, such as jekyll_toc.rb, might generate other output.
|
35
|
-
|
8
|
+
# See spec/outline_spec for an example of HTML output.
|
36
9
|
module JekyllSupport
|
37
10
|
PLUGIN_NAME = 'outline'.freeze
|
38
|
-
OutlineError = JekyllSupport.define_error
|
39
|
-
|
40
|
-
# Interleaves with docs
|
41
|
-
# Duck type compatible with Jekyll doc
|
42
|
-
class Header
|
43
|
-
attr_accessor :order, :title
|
44
|
-
|
45
|
-
def initialize(yaml)
|
46
|
-
@order = yaml[0]
|
47
|
-
@published = true
|
48
|
-
@title = yaml[1]
|
49
|
-
end
|
50
11
|
|
51
|
-
|
52
|
-
" <h3 class='post_title clear' id=\"title_#{@order}\">#{@title}</h3>"
|
53
|
-
end
|
54
|
-
end
|
12
|
+
OutlineError = JekyllSupport.define_error
|
55
13
|
|
56
|
-
class OutlineTag < JekyllBlock
|
14
|
+
class OutlineTag < JekyllBlock
|
57
15
|
include JekyllOutlineVersion
|
58
16
|
|
59
|
-
FIXNUM_MAX = (2**((0.size * 8) - 2)) - 1
|
60
|
-
|
61
17
|
def render_impl(text)
|
62
|
-
|
18
|
+
block_content = super # Process the block content.
|
63
19
|
|
64
|
-
@helper.gem_file __FILE__
|
20
|
+
@helper.gem_file __FILE__ # For attribution
|
65
21
|
|
66
22
|
@die_on_outline_error = @tag_config['die_on_outline_error'] == true if @tag_config
|
67
23
|
@pry_on_outline_error = @tag_config['pry_on_outline_error'] == true if @tag_config
|
68
24
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
25
|
+
pattern = @helper.parameter_specified?('pattern')&.split ||
|
26
|
+
@helper.parameter_specified?('fields')&.split ||
|
27
|
+
['title']
|
28
|
+
sort_by = @helper.parameter_specified?('sort_by_title') ? :title : :order
|
29
|
+
collection_name = @helper.remaining_markup
|
30
|
+
raise OutlineError, 'collection_name was not specified' unless collection_name
|
31
|
+
|
32
|
+
outline_options = OutlineOptions.new(
|
33
|
+
attribution: @attribution,
|
34
|
+
collection_name: collection_name,
|
35
|
+
enable_attribution: @attribution,
|
36
|
+
pattern: pattern,
|
37
|
+
sort_by: sort_by
|
38
|
+
)
|
39
|
+
yaml_parser = YamlParser.new outline_options, block_content
|
40
|
+
outline = Outline.new(outline_options: outline_options)
|
41
|
+
outline.add_sections yaml_parser.sections
|
42
|
+
|
43
|
+
abort "#{collection_name} is not a valid collection." unless @site.collections&.key?(collection_name)
|
44
|
+
docs = @site
|
45
|
+
.collections[collection_name]
|
46
|
+
.docs
|
47
|
+
outline.add_entries(collection_apages(docs))
|
48
|
+
outline.to_s
|
77
49
|
rescue OutlineError => e # jekyll_plugin_support handles StandardError
|
78
50
|
@logger.error { JekyllPluginHelper.remove_html_tags e.logger_message }
|
79
51
|
binding.pry if @pry_on_outline_error # rubocop:disable Lint/Debugger
|
@@ -82,175 +54,16 @@ module JekyllSupport
|
|
82
54
|
e.html_message
|
83
55
|
end
|
84
56
|
|
85
|
-
# Overload this for a subclass
|
86
|
-
def render_outline(collection)
|
87
|
-
<<~HEREDOC
|
88
|
-
<div class="outer_posts">
|
89
|
-
#{make_entries collection}
|
90
|
-
</div>
|
91
|
-
#{@helper.attribute if @helper.attribution}
|
92
|
-
HEREDOC
|
93
|
-
end
|
94
|
-
|
95
|
-
def open_head; end
|
96
|
-
|
97
57
|
private
|
98
58
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
def
|
104
|
-
|
105
|
-
yaml = YAML.safe_load content
|
106
|
-
yaml.map { |entry| Header.new entry }
|
107
|
-
rescue NoMethodError => e
|
108
|
-
raise OutlineError, <<~END_MSG
|
109
|
-
Invalid YAML within {% outline %} tag. The offending content was:
|
110
|
-
|
111
|
-
<pre>#{content}</pre>
|
112
|
-
END_MSG
|
113
|
-
rescue Psych::SyntaxError => e
|
114
|
-
msg = <<~END_MSG
|
115
|
-
Invalid YAML found within {% outline %} tag:<br>
|
116
|
-
<pre>#{e.message}</pre>
|
117
|
-
END_MSG
|
118
|
-
@logger.error { e.message }
|
119
|
-
raise OutlineError, msg
|
120
|
-
end
|
121
|
-
|
122
|
-
# @section_state can have values: :head, :in_body
|
123
|
-
# @param collection Array of Jekyll::Document and JekyllSupport::Header
|
124
|
-
# @return Array of String
|
125
|
-
def make_entries(collection)
|
126
|
-
sorted = if @sort_by == 'order'
|
127
|
-
collection.sort_by(&obtain_order)
|
128
|
-
else
|
129
|
-
collection.sort_by(&obtain_field)
|
130
|
-
end
|
131
|
-
pruned = remove_empty_headers sorted
|
132
|
-
@section_state = :head
|
133
|
-
@section_id = 0
|
134
|
-
result = pruned.map do |entry|
|
135
|
-
handle entry
|
136
|
-
end
|
137
|
-
result << " </div>\n </div>" if @section_state == :in_body # Modify this for TOC
|
138
|
-
result&.join("\n")
|
139
|
-
end
|
140
|
-
|
141
|
-
KNOWN_FIELDS = %w[draft categories description date last_modified_at layout order title slug ext tags excerpt].freeze
|
142
|
-
|
143
|
-
def handle(entry)
|
144
|
-
if entry.instance_of? Header
|
145
|
-
@header_order = entry.order
|
146
|
-
section_end = " </div>\n" if @section_state == :in_body
|
147
|
-
@section_state = :head
|
148
|
-
entry = section_end + entry.to_s if section_end
|
149
|
-
entry
|
150
|
-
else
|
151
|
-
if @section_state == :head
|
152
|
-
section_start = <<~ENDTEXT # Modify this for TOC
|
153
|
-
<div id="posts_wrapper_#{@header_order}" class='clearfix'>
|
154
|
-
<div id="posts_#{@header_order}" class='posts'>
|
155
|
-
ENDTEXT
|
156
|
-
end
|
157
|
-
@section_state = :in_body
|
158
|
-
date = entry.data['last_modified_at'] # "%Y-%m-%d"
|
159
|
-
draft = Jekyll::Draft.draft_html(entry)
|
160
|
-
visible_line = handle_entry entry
|
161
|
-
result = " <span>#{date}</span> <span><a href='#{entry.url}'>#{visible_line.strip}</a>#{draft}</span>" # Modify this for TOC
|
162
|
-
result = section_start + result if section_start
|
163
|
-
result
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def handle_entry(entry)
|
168
|
-
result = ''
|
169
|
-
@fields.each do |field|
|
170
|
-
if KNOWN_FIELDS.include? field
|
171
|
-
if entry.data.key? field
|
172
|
-
result += "#{entry.data[field]} "
|
173
|
-
else
|
174
|
-
@logger.warn { "#{field} is a known field, but it was not present in entry #{entry}" }
|
175
|
-
end
|
176
|
-
else
|
177
|
-
result += "#{field} "
|
178
|
-
end
|
179
|
-
end
|
180
|
-
result
|
181
|
-
end
|
182
|
-
|
183
|
-
# Find the given document
|
184
|
-
def obtain_doc(doc_name)
|
185
|
-
abort "#{@collection_name} is not a valid collection." unless @site.collections.key? @collection_name
|
186
|
-
@site
|
187
|
-
.collections[@collection_name]
|
188
|
-
.docs
|
189
|
-
.reject { |doc| doc.data['exclude_from_outline'] }
|
190
|
-
.find { |doc| doc.url.match(/#{doc_name}(.\w*)?$/) }
|
191
|
-
end
|
192
|
-
|
193
|
-
# Ignores files whose name starts with `index`, and those with the following in their front matter:
|
194
|
-
# exclude_from_outline: true
|
195
|
-
def obtain_docs(collection_name)
|
196
|
-
abort "#{@collection_name} is not a valid collection." unless @site.collections.key? @collection_name
|
197
|
-
@site
|
198
|
-
.collections[collection_name]
|
199
|
-
.docs
|
59
|
+
# Returns an APage for each document in the collection with the given named.
|
60
|
+
# Ignores files whose name starts with `index`,
|
61
|
+
# and those with the following in their front matter:
|
62
|
+
# exclude_from_outline: true
|
63
|
+
def collection_apages(pages)
|
64
|
+
pages
|
200
65
|
.reject { |doc| doc.url.match(/index(.\w*)?$/) || doc.data['exclude_from_outline'] }
|
201
|
-
|
202
|
-
|
203
|
-
# Sort entries within the outline tag which do not have the property specified by @sort_by at the end
|
204
|
-
def obtain_field
|
205
|
-
sort_by = @sort_by.to_s
|
206
|
-
proc do |entry|
|
207
|
-
if entry.respond_to? :data # page
|
208
|
-
entry.data.key?(sort_by) ? entry.data[sort_by] || 'zzz' : 'zzz'
|
209
|
-
else # heading
|
210
|
-
entry.respond_to?(sort_by) ? entry.send(sort_by) || 'zzz' : 'zzz'
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
# Sort entries within the outline tag which do not have an order property at the end
|
216
|
-
def obtain_order
|
217
|
-
proc do |entry|
|
218
|
-
if entry.respond_to? :data # page
|
219
|
-
entry.data.key?('order') ? entry.data['order'] || FIXNUM_MAX : FIXNUM_MAX
|
220
|
-
else # heading
|
221
|
-
entry.order || FIXNUM_MAX
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def remove_empty_headers(array)
|
227
|
-
i = 0
|
228
|
-
while i < array.length - 1
|
229
|
-
if header?(array[i]) && header?(array[i + 1])
|
230
|
-
array.delete_at(i)
|
231
|
-
else
|
232
|
-
i += 1
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
array.delete_at(array.length - 1) if header?(array.last)
|
237
|
-
array
|
238
|
-
end
|
239
|
-
|
240
|
-
def remove_leading_spaces(multiline)
|
241
|
-
multiline
|
242
|
-
.strip
|
243
|
-
.split("\n")
|
244
|
-
.map { |x| x.gsub(/\A\s+/, '') }
|
245
|
-
.join("\n")
|
246
|
-
end
|
247
|
-
|
248
|
-
def remove_leading_zeros(multiline)
|
249
|
-
multiline
|
250
|
-
.strip
|
251
|
-
.split("\n")
|
252
|
-
.map { |x| x.gsub(/(?<= |\A)0+(?=\d)/, '') }
|
253
|
-
.join("\n")
|
66
|
+
.map { |x| ::JekyllSupport::APage.new(x, 'collection') if x }
|
254
67
|
end
|
255
68
|
|
256
69
|
JekyllPluginHelper.register(self, PLUGIN_NAME)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Enriches JekyllSupport.APage
|
2
|
+
module JekyllSupport
|
3
|
+
KNOWN_FIELDS = %w[draft categories description date last_modified_at layout order title slug ext tags excerpt].freeze
|
4
|
+
|
5
|
+
# Overrides definition from `jekyll_plugin_support`
|
6
|
+
class APage
|
7
|
+
def render_outline_apage(pattern)
|
8
|
+
<<~END_ENTRY
|
9
|
+
<span>#{@last_modified.strftime('%Y-%m-%d')}</span>
|
10
|
+
<span><a href='#{@url}'>#{render_entry_details pattern}</a>#{@draft}</span>
|
11
|
+
END_ENTRY
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param pattern can either be a String or [String]
|
15
|
+
# Renders a section entry as a string
|
16
|
+
# Recognized tokens are looked up, otherwise they are incorporated into the output
|
17
|
+
# Currently spaces are the only valid delimiters; HTML tags should be tokenized even when not delimited by spaces
|
18
|
+
def render_entry_details(pattern)
|
19
|
+
result = ''
|
20
|
+
fields = case pattern
|
21
|
+
when String
|
22
|
+
pattern.split
|
23
|
+
when Array
|
24
|
+
pattern
|
25
|
+
else
|
26
|
+
@logger.error { "Pattern is neither a String nor an Array (#{pattern})" }
|
27
|
+
end
|
28
|
+
fields.each do |field|
|
29
|
+
if KNOWN_FIELDS.include? field
|
30
|
+
if respond_to? field
|
31
|
+
value = send field
|
32
|
+
result += "#{value} "
|
33
|
+
elsif data.key?(field.to_sym) || data.key?(field.to_s)
|
34
|
+
value = data[field.to_sym] || data[field.to_s]
|
35
|
+
result += "#{value} "
|
36
|
+
else
|
37
|
+
@logger.warn { "'#{field}' is a known field, but it was not present in apage with url '#{@url}'." }
|
38
|
+
end
|
39
|
+
else
|
40
|
+
result += "#{field} "
|
41
|
+
end
|
42
|
+
end
|
43
|
+
result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'jekyll_plugin_support'
|
2
|
+
require_relative 'section'
|
3
|
+
|
4
|
+
module JekyllSupport
|
5
|
+
# @param attribution sets the attribution message
|
6
|
+
# @param enable_attribution causes the attribution message to be displayed if truthy
|
7
|
+
# @param collection_name Name of the Jekyll collection the outline is organizing
|
8
|
+
# @param pattern String containing keyswords and literals; interpreted and displayed when an APage is rendered as a topic entry
|
9
|
+
# @param sort_by Either has value :order or :title
|
10
|
+
class OutlineOptions
|
11
|
+
attr_accessor :attribution, :enable_attribution, :collection_name, :logger, :pattern, :sort_by
|
12
|
+
|
13
|
+
def initialize(
|
14
|
+
collection_name: '_posts',
|
15
|
+
attribution: '',
|
16
|
+
enable_attribution: false,
|
17
|
+
logger: PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config),
|
18
|
+
pattern: '<b> title </b> – <i> description </i>',
|
19
|
+
sort_by: :order
|
20
|
+
)
|
21
|
+
@attribution = attribution
|
22
|
+
@enable_attribution = enable_attribution
|
23
|
+
@collection_name = collection_name
|
24
|
+
@logger = logger
|
25
|
+
@pattern = pattern
|
26
|
+
@sort_by = sort_by
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Outline
|
31
|
+
attr_reader :logger, :options, :sections
|
32
|
+
|
33
|
+
# Sort all entries first so they are iteratable according to the desired order.
|
34
|
+
# This presorts the entries for each section.
|
35
|
+
#
|
36
|
+
# If options[:sort_by] == :order then place each APage into it's appropriate section.
|
37
|
+
# Otherwise place all entries into one section.
|
38
|
+
#
|
39
|
+
# options[:pattern] defaults to ['title'], but might be something like
|
40
|
+
# ["<b>", "title", "</b>", "–", "<i>", "description", "</i>"]
|
41
|
+
def initialize(outline_options: OutlineOptions.new)
|
42
|
+
@add_sections_called = false
|
43
|
+
@options = outline_options
|
44
|
+
|
45
|
+
@logger = @options.logger
|
46
|
+
@sections = @options.sort_by == :order ? [] : [Section.new(@options, [0, ''])]
|
47
|
+
rescue StandardError => e
|
48
|
+
error_short_trace @logger, e
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_entries(apages)
|
52
|
+
sorted_apages = make_entries sort apages
|
53
|
+
sorted_apages.each { |apage| add_apage apage }
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_section(section)
|
58
|
+
return unless @options.sort_by == :order
|
59
|
+
|
60
|
+
@sections << section
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_sections(sections)
|
65
|
+
sections.each { |x| add_section x }
|
66
|
+
@add_sections_called = true
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def make_entries(docs)
|
71
|
+
docs.map do |doc|
|
72
|
+
draft = Jekyll::Draft.draft_html doc
|
73
|
+
JekyllSupport.apage_from(
|
74
|
+
date: doc.date,
|
75
|
+
description: doc.description,
|
76
|
+
draft: draft,
|
77
|
+
last_modified: doc.last_modified,
|
78
|
+
order: doc.order,
|
79
|
+
title: doc.title,
|
80
|
+
url: doc.url
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param apages [APage]
|
86
|
+
# @return muliline String
|
87
|
+
def sort(apages)
|
88
|
+
if @options.sort_by == :order
|
89
|
+
apages.sort_by(&:order)
|
90
|
+
else
|
91
|
+
apages.sort_by { |apage| sort_property_value apage }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s
|
96
|
+
return '' unless @sections&.count&.positive?
|
97
|
+
|
98
|
+
result = []
|
99
|
+
result << "<div class='outer_posts'>"
|
100
|
+
result << (@sections.map { |section| " #{section}" })
|
101
|
+
result << '</div>'
|
102
|
+
result << @options.attribution if @options.enable_attribution
|
103
|
+
result.join "\n"
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def add_apage(apage)
|
109
|
+
unless apage
|
110
|
+
raise ::OutlineError, 'add_apage called with nil apage'
|
111
|
+
puts
|
112
|
+
end
|
113
|
+
raise ::OutlineError, 'add_apage called without first calling add_sections' unless @add_sections_called
|
114
|
+
|
115
|
+
section = section_for apage
|
116
|
+
section.add_child apage
|
117
|
+
end
|
118
|
+
|
119
|
+
def default_sort_value(sort_by)
|
120
|
+
case sort_by
|
121
|
+
when :date, :last_modified, :last_modified_at
|
122
|
+
Date.today
|
123
|
+
else
|
124
|
+
''
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Obtain sort property value from APage instance, or return a default value
|
129
|
+
def sort_property_value(apage)
|
130
|
+
sort_by = @options.sort_by.to_s
|
131
|
+
if apage.data.key?(sort_by)
|
132
|
+
apage.data[sort_by] || default_sort_value(sort_by)
|
133
|
+
else
|
134
|
+
default_sort_value(sort_by)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Only called when entries are organized into multiple sections
|
139
|
+
# @param apage must have a property called `order`
|
140
|
+
def section_for(apage)
|
141
|
+
return @sections.first if @sections.count == 1
|
142
|
+
|
143
|
+
last = @sections.length - 1
|
144
|
+
(0..last).each do |i|
|
145
|
+
return @sections.last if i == last
|
146
|
+
|
147
|
+
page_order = apage.order
|
148
|
+
this_section = @sections[i]
|
149
|
+
next_section = @sections[i + 1]
|
150
|
+
return this_section if (page_order >= this_section.order) && (page_order < next_section.order)
|
151
|
+
end
|
152
|
+
@sections.last
|
153
|
+
# raise OutlineError, "No Section found for APage #{apage}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'a_page_enrichment'
|
2
|
+
|
3
|
+
module JekyllSupport
|
4
|
+
class Section
|
5
|
+
attr_accessor :children, :title, :order
|
6
|
+
|
7
|
+
def initialize(outline_options, parameter_array)
|
8
|
+
@outline_options = outline_options
|
9
|
+
@order = parameter_array[0].to_i
|
10
|
+
@title = parameter_array[1]
|
11
|
+
@children = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_child(child)
|
15
|
+
@children << child
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
return '' if @children.count.zero?
|
20
|
+
|
21
|
+
unless @children.first.instance_of?(JekyllSupport::APage)
|
22
|
+
raise "First child of Section was a #{@children.first.class}, not an APage"
|
23
|
+
end
|
24
|
+
apages = @children
|
25
|
+
.map { |x| x.render_outline_apage @outline_options.pattern }
|
26
|
+
.join("\n ")
|
27
|
+
|
28
|
+
<<~END_SECTION
|
29
|
+
<h3 class='post_title clear' id="title_#{@order}">#{@title}</h3>
|
30
|
+
<div id='posts_wrapper_#{@order}' class='clearfix'>
|
31
|
+
<div id="posts_#{@order}" class='posts'>
|
32
|
+
#{apages}
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
END_SECTION
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require_relative 'section'
|
3
|
+
|
4
|
+
class OutlineError < StandardError; end
|
5
|
+
|
6
|
+
module JekyllSupport
|
7
|
+
class YamlParser
|
8
|
+
attr_reader :sections
|
9
|
+
|
10
|
+
# @return array of empty Sections
|
11
|
+
def initialize(outline_options, content = '')
|
12
|
+
@logger = outline_options.logger
|
13
|
+
@sections = if content && !content.strip.empty?
|
14
|
+
parse_sections outline_options, content
|
15
|
+
else
|
16
|
+
[]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return Array of Sections that do not contain children
|
21
|
+
def parse_sections(outline_options, content)
|
22
|
+
content = remove_leading_zeros remove_leading_spaces content
|
23
|
+
yaml = YAML.safe_load content
|
24
|
+
yaml.map { |entry| Section.new outline_options, entry }
|
25
|
+
rescue NoMethodError => e
|
26
|
+
raise OutlineError, <<~END_MSG
|
27
|
+
Invalid YAML within {% outline %} tag. The offending content was:
|
28
|
+
|
29
|
+
<pre>#{content}</pre>
|
30
|
+
END_MSG
|
31
|
+
rescue Psych::SyntaxError => e
|
32
|
+
msg = <<~END_MSG
|
33
|
+
Invalid YAML found within {% outline %} tag:<br>
|
34
|
+
<pre>#{e.message}</pre>
|
35
|
+
END_MSG
|
36
|
+
@logger.error { e.message }
|
37
|
+
raise OutlineError, msg
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def remove_leading_spaces(multiline)
|
43
|
+
multiline
|
44
|
+
.strip
|
45
|
+
.split("\n")
|
46
|
+
.map { |x| x.gsub(/\A\s+/, '') }
|
47
|
+
.join("\n")
|
48
|
+
end
|
49
|
+
|
50
|
+
def remove_leading_zeros(multiline)
|
51
|
+
multiline
|
52
|
+
.strip
|
53
|
+
.split("\n")
|
54
|
+
.map { |x| x.gsub(/(?<= |\A)0+(?=\d)/, '') }
|
55
|
+
.join("\n")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/outline_spec.rb
CHANGED
@@ -1,10 +1,152 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'jekyll_plugin_support'
|
2
|
+
require 'rspec/match_ignoring_whitespace'
|
3
|
+
require_relative 'spec_helper'
|
4
|
+
require_relative '../lib/structure/outline'
|
3
5
|
|
4
|
-
RSpec.describe(
|
5
|
-
|
6
|
+
RSpec.describe(JekyllSupport) do
|
7
|
+
outline_options = JekyllSupport::OutlineOptions.new(pattern: '<b> title </b> – <i> description </i>')
|
8
|
+
section1 = described_class::Section.new(outline_options, [0, 'Section 1'])
|
9
|
+
section2 = described_class::Section.new(outline_options, [3, 'Section 2'])
|
6
10
|
|
7
|
-
|
8
|
-
|
11
|
+
apages = [
|
12
|
+
described_class.apage_from(
|
13
|
+
collection_name: '_posts',
|
14
|
+
date: '2023-01-01',
|
15
|
+
description: 'This is the entry1 description.',
|
16
|
+
draft: true,
|
17
|
+
last_modified: '2023-01-01',
|
18
|
+
order: 1,
|
19
|
+
title: 'Entry 1',
|
20
|
+
url: 'https://example.com/entry1'
|
21
|
+
),
|
22
|
+
described_class.apage_from(
|
23
|
+
collection_name: '_posts',
|
24
|
+
date: '2023-01-02',
|
25
|
+
description: 'This is the entry2 description.',
|
26
|
+
last_modified: '2023-01-02',
|
27
|
+
order: 2,
|
28
|
+
title: 'Entry 2',
|
29
|
+
url: 'https://example.com/entry2'
|
30
|
+
),
|
31
|
+
described_class.apage_from(
|
32
|
+
collection_name: '_posts',
|
33
|
+
date: '2023-10-03',
|
34
|
+
description: 'This is the entry3 description.',
|
35
|
+
last_modified: '2024-10-03',
|
36
|
+
order: 3,
|
37
|
+
title: 'Entry 3',
|
38
|
+
url: 'https://example.com/entry3'
|
39
|
+
),
|
40
|
+
described_class.apage_from(
|
41
|
+
collection_name: '_posts',
|
42
|
+
date: '2023-10-04',
|
43
|
+
description: 'This is the entry4 description.',
|
44
|
+
draft: true,
|
45
|
+
last_modified: '2024-10-04',
|
46
|
+
order: 4,
|
47
|
+
title: 'Entry 4',
|
48
|
+
url: 'https://example.com/entry4'
|
49
|
+
),
|
50
|
+
described_class.apage_from(
|
51
|
+
collection_name: '_posts',
|
52
|
+
date: '2023-10-05',
|
53
|
+
description: 'This is the entry5 description.',
|
54
|
+
last_modified: '2024-10-05',
|
55
|
+
order: 5,
|
56
|
+
title: 'Entry 5',
|
57
|
+
url: 'https://example.com/entry5'
|
58
|
+
),
|
59
|
+
described_class.apage_from(
|
60
|
+
collection_name: '_posts',
|
61
|
+
date: '2023-10-06',
|
62
|
+
description: 'This is the entry6 description.',
|
63
|
+
last_modified: '2024-10-06',
|
64
|
+
order: 6,
|
65
|
+
title: 'Entry 6',
|
66
|
+
url: 'https://example.com/entry6'
|
67
|
+
)
|
68
|
+
]
|
69
|
+
|
70
|
+
outline = described_class::Outline.new
|
71
|
+
outline.add_sections [section1, section2]
|
72
|
+
outline.add_entries apages
|
73
|
+
|
74
|
+
_attribution = <<~END_ATT
|
75
|
+
<div id="jps_attribute_570007" class="jps_attribute">
|
76
|
+
<div>
|
77
|
+
<a href="https://www.mslinn.com/jekyll_plugins/jekyll_outline.html" target="_blank" rel="nofollow">
|
78
|
+
Generated by the jekyll_outline v1.2.1 Jekyll plugin, written by Mike Slinn 2024-01-09.
|
79
|
+
</a>
|
80
|
+
</div>
|
81
|
+
</div>
|
82
|
+
END_ATT
|
83
|
+
|
84
|
+
expected_section1 = <<~END_EXPECTED
|
85
|
+
<h3 class='post_title clear' id="title_0">Section 1</h3>
|
86
|
+
<div id='posts_wrapper_0' class='clearfix'>
|
87
|
+
<div id="posts_0" class='posts'>
|
88
|
+
<span>2023-01-01</span>
|
89
|
+
<span><a href='https://example.com/entry1'><b> Entry 1 </b> – <i> This is the entry1 description. </i> </a> <i class='jekyll_draft'>Draft</i></span>
|
90
|
+
|
91
|
+
<span>2023-01-02</span>
|
92
|
+
<span><a href='https://example.com/entry2'><b> Entry 2 </b> – <i> This is the entry2 description. </i> </a></span>
|
93
|
+
</div>
|
94
|
+
</div>
|
95
|
+
END_EXPECTED
|
96
|
+
|
97
|
+
expected_section2 = <<~END_EXPECTED
|
98
|
+
<h3 class='post_title clear' id="title_3">Section 2</h3>
|
99
|
+
<div id='posts_wrapper_3' class='clearfix'>
|
100
|
+
<div id="posts_3" class='posts'>
|
101
|
+
<span>2024-10-03</span>
|
102
|
+
<span><a href='https://example.com/entry3'><b> Entry 3 </b> – <i> This is the entry3 description. </i> </a></span>
|
103
|
+
|
104
|
+
<span>2024-10-04</span>
|
105
|
+
<span><a href='https://example.com/entry4'><b> Entry 4 </b> – <i> This is the entry4 description. </i> </a> <i class='jekyll_draft'>Draft</i></span>
|
106
|
+
|
107
|
+
<span>2024-10-05</span>
|
108
|
+
<span><a href='https://example.com/entry5'><b> Entry 5 </b> – <i> This is the entry5 description. </i> </a></span>
|
109
|
+
|
110
|
+
<span>2024-10-06</span>
|
111
|
+
<span><a href='https://example.com/entry6'><b> Entry 6 </b> – <i> This is the entry6 description. </i> </a></span>
|
112
|
+
</div>
|
113
|
+
</div>
|
114
|
+
END_EXPECTED
|
115
|
+
|
116
|
+
it 'verifies initial values' do
|
117
|
+
expect(outline.options.sort_by).to eq(:order)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'sorts by :order' do
|
121
|
+
expect(outline.sort(apages)).to eq(apages)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'checks html shape' do
|
125
|
+
expect(outline.sections.count).to eq(2)
|
126
|
+
expect(outline.sections[0].children.count).to eq(2)
|
127
|
+
expect(outline.sections[1].children.count).to eq(4)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'verifies html for first section' do
|
131
|
+
actual = outline.sections[0].to_s
|
132
|
+
expect(expected_section1).to match_ignoring_whitespace(actual)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'verifies html for second section' do
|
136
|
+
actual = outline.sections[1].to_s
|
137
|
+
expect(expected_section2).to match_ignoring_whitespace(actual)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'verifies generated html' do
|
141
|
+
actual = outline.to_s
|
142
|
+
|
143
|
+
expected = <<~END_EXPECTED
|
144
|
+
<div class='outer_posts'>
|
145
|
+
#{expected_section1}
|
146
|
+
#{expected_section2}
|
147
|
+
</div>
|
148
|
+
END_EXPECTED
|
149
|
+
|
150
|
+
expect(expected).to match_ignoring_whitespace(actual)
|
9
151
|
end
|
10
152
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,23 @@
|
|
1
1
|
require 'jekyll'
|
2
|
-
require_relative '../lib/jekyll_outline'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
# For testing Jekyll plugins based on jekyll_plugin_support:
|
4
|
+
require 'jekyll_plugin_logger'
|
5
|
+
require 'jekyll_plugin_support'
|
7
6
|
|
7
|
+
RSpec.configure do |config|
|
8
8
|
# See https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures
|
9
9
|
config.example_status_persistence_file_path = 'spec/status_persistence.txt'
|
10
|
+
|
11
|
+
# See https://rspec.info/features/3-12/rspec-core/filtering/filter-run-when-matching/
|
12
|
+
# and https://github.com/rspec/rspec/issues/221
|
13
|
+
config.filter_run_when_matching :focus
|
14
|
+
|
15
|
+
# Other values: :progress, :html, :json, CustomFormatterClass
|
16
|
+
config.formatter = :documentation
|
17
|
+
|
18
|
+
# See https://rspec.info/features/3-12/rspec-core/command-line/order/
|
19
|
+
config.order = :defined
|
20
|
+
|
21
|
+
# See https://www.rubydoc.info/github/rspec/rspec-core/RSpec%2FCore%2FConfiguration:pending_failure_output
|
22
|
+
config.pending_failure_output = :skip
|
10
23
|
end
|
data/spec/status_persistence.txt
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
example_id
|
2
|
-
|
3
|
-
./spec/
|
1
|
+
example_id | status | run_time |
|
2
|
+
---------------------------------- | ------ | --------------- |
|
3
|
+
./spec/jekyll_outline_spec.rb[1:1] | passed | 0.00023 seconds |
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rspec/match_ignoring_whitespace'
|
3
|
+
require_relative '../lib/structure/outline'
|
4
|
+
require_relative '../lib/structure/yaml_parser'
|
5
|
+
|
6
|
+
module JekyllSupport
|
7
|
+
logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
|
8
|
+
outline_options = OutlineOptions.new
|
9
|
+
|
10
|
+
# includes leading zeros and leading spaces, which are invalid in YAML
|
11
|
+
yaml_parser_big = YamlParser.new outline_options, <<~END_DATA
|
12
|
+
0: Production Infrastructure
|
13
|
+
0015000: Audio
|
14
|
+
20000: Video
|
15
|
+
30000: RME
|
16
|
+
40000: OBS Studio
|
17
|
+
50000: Pro Tools
|
18
|
+
55000: Ableton Live & Push
|
19
|
+
60000: Other Music Software
|
20
|
+
70000: MIDI Hardware & Software
|
21
|
+
80000: Davinci Resolve
|
22
|
+
100000: Computer Analysis
|
23
|
+
200000: Music Theory
|
24
|
+
300000: Business
|
25
|
+
400000: General
|
26
|
+
END_DATA
|
27
|
+
|
28
|
+
RSpec.describe(YamlParser) do
|
29
|
+
it 'handles no section headings' do
|
30
|
+
yaml_parser = described_class.new outline_options
|
31
|
+
sections = yaml_parser.sections
|
32
|
+
expect(sections.count).to equal(0)
|
33
|
+
|
34
|
+
yaml_parser = described_class.new outline_options, ''
|
35
|
+
sections = yaml_parser.sections
|
36
|
+
expect(sections.count).to equal(0)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'finds only 1 section heading' do
|
40
|
+
yaml_parser = described_class.new outline_options, '0: General'
|
41
|
+
sections = yaml_parser.sections
|
42
|
+
expect(sections.count).to equal(1)
|
43
|
+
# expect(sections.first)
|
44
|
+
|
45
|
+
yaml_parser = described_class.new outline_options, <<~END_DATA
|
46
|
+
0: General
|
47
|
+
END_DATA
|
48
|
+
sections = yaml_parser.sections
|
49
|
+
expect(sections.count).to equal(1)
|
50
|
+
|
51
|
+
# Handle leading space (this is invalid YAML) and the lack of an end of line character
|
52
|
+
yaml_parser = described_class.new outline_options, ' 0: General'
|
53
|
+
sections = yaml_parser.sections
|
54
|
+
expect(sections.count).to equal(1)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'finds matching sections' do
|
58
|
+
sections = yaml_parser_big.sections
|
59
|
+
expect(sections.count).to equal(14)
|
60
|
+
|
61
|
+
section1 = sections.first
|
62
|
+
expect(section1.order).to eq(0)
|
63
|
+
expect(section1.title).to eq('Production Infrastructure')
|
64
|
+
|
65
|
+
outline = Outline.new.add_sections sections
|
66
|
+
|
67
|
+
apage0 = JekyllSupport.apage_from(date: Time.now, logger: logger, order: 0)
|
68
|
+
actual_section = outline.send :section_for, apage0
|
69
|
+
expect(actual_section.order).to eq(0)
|
70
|
+
|
71
|
+
apage1000 = JekyllSupport.apage_from(date: Time.now, logger: logger, order: 1000)
|
72
|
+
actual_section = outline.send :section_for, apage1000
|
73
|
+
expect(actual_section.order).to eq(0)
|
74
|
+
|
75
|
+
apage16000 = JekyllSupport.apage_from(date: Time.now, logger: logger, order: 16_000)
|
76
|
+
actual_section = outline.send :section_for, apage16000
|
77
|
+
expect(actual_section.order).to eq(15_000)
|
78
|
+
|
79
|
+
apage25000 = JekyllSupport.apage_from(date: Time.now, logger: logger, order: 25_000)
|
80
|
+
actual_section = outline.send :section_for, apage25000
|
81
|
+
expect(actual_section.order).to eq(20_000)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll_outline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Slinn
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: jekyll
|
@@ -15,42 +15,42 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
18
|
+
version: 4.4.0
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version:
|
25
|
+
version: 4.4.0
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: jekyll_draft
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: 3.0.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
39
|
+
version: 3.0.0
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: jekyll_plugin_support
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 1.0
|
46
|
+
version: 3.1.0
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 1.0
|
53
|
+
version: 3.1.0
|
54
54
|
description: 'Jekyll tag plugin that creates a clickable table of contents.
|
55
55
|
|
56
56
|
'
|
@@ -71,9 +71,14 @@ files:
|
|
71
71
|
- lib/jekyll_outline/version.rb
|
72
72
|
- lib/outline_js.rb
|
73
73
|
- lib/outline_tag.rb
|
74
|
+
- lib/structure/a_page_enrichment.rb
|
75
|
+
- lib/structure/outline.rb
|
76
|
+
- lib/structure/section.rb
|
77
|
+
- lib/structure/yaml_parser.rb
|
74
78
|
- spec/outline_spec.rb
|
75
79
|
- spec/spec_helper.rb
|
76
80
|
- spec/status_persistence.txt
|
81
|
+
- spec/yaml_parser_spec.rb
|
77
82
|
homepage: https://www.mslinn.com/jekyll_plugins/jekyll_outline.html
|
78
83
|
licenses:
|
79
84
|
- MIT
|
@@ -101,11 +106,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
106
|
- !ruby/object:Gem::Version
|
102
107
|
version: '0'
|
103
108
|
requirements: []
|
104
|
-
rubygems_version: 3.6.
|
109
|
+
rubygems_version: 3.6.9
|
105
110
|
specification_version: 4
|
106
111
|
summary: Jekyll tag plugin that creates a clickable table of contents.
|
107
112
|
test_files:
|
108
113
|
- spec/outline_spec.rb
|
109
114
|
- spec/spec_helper.rb
|
110
115
|
- spec/status_persistence.txt
|
116
|
+
- spec/yaml_parser_spec.rb
|
111
117
|
...
|