jekyll_aspec 1.0.0.pre.alpha → 1.0.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/Gemfile.lock +1 -1
- data/README.adoc +54 -0
- data/Rakefile +2 -2
- data/docs/inline-task.adoc +34 -0
- data/docs/requirement-block.adoc +56 -0
- data/docs/todo-block.adoc +48 -0
- data/jekyll_aspec.gemspec +7 -0
- data/lib/extensions/autoxrefs.rb +5 -102
- data/lib/extensions/html_postprocessor.rb +1 -0
- data/lib/extensions/inline_callout_macro.rb +3 -1
- data/lib/extensions/inline_cwiki_macro.rb +10 -4
- data/lib/extensions/inline_repo_macro.rb +19 -9
- data/lib/extensions/inline_task_macro.rb +11 -5
- data/lib/extensions/replace_regex.rb +2 -0
- data/lib/extensions/req_preprocessor.rb +2 -1
- data/lib/extensions/req_refs.rb +15 -6
- data/lib/extensions/requirement_block.rb +49 -44
- data/lib/extensions/requirement_block_macro.rb +28 -0
- data/lib/extensions/todo_block.rb +7 -0
- data/lib/extensions/utils/block.rb +9 -1
- data/lib/extensions/utils/labels.rb +5 -0
- data/lib/extensions/utils/req_macro_walker.rb +110 -0
- data/lib/extensions/utils/xref_helper.rb +122 -0
- data/lib/jekyll_aspec/version.rb +4 -1
- data/lib/jekyll_aspec.rb +4 -2
- metadata +17 -8
- data/README.md +0 -30
- data/lib/extensions/requirement_appendix.rb +0 -115
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7660532ed66dd03c81835079b3f1f2c57a495a7
|
4
|
+
data.tar.gz: 9fd9c8f89aad34a1498ea52cd3f04b021db3a564
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a13f2ee35c2a0082ecb6c11d4ddce5c76c6145ccc16113912fcad43bb4ca751d7560d4ed03b8465489be8a22f21d7533d384ecc3bdcc6cea59847e26bf248ef0
|
7
|
+
data.tar.gz: 141f495acb546d4ef8a8e0037b6e9d099fc4803d11455af2149e0ab3ec59b8fae1a9d9b1e14a68c42b57563602f1c3cf122693aafe05b83b74e2a0ec6ae454e0
|
data/Gemfile.lock
CHANGED
data/README.adoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= Jekyll Aspec
|
2
|
+
|
3
|
+
image:https://travis-ci.org/bsmith-n4/jekyll_aspec.svg?branch=master["Build Status", link="https://travis-ci.org/bsmith-n4/jekyll_aspec"]
|
4
|
+
|
5
|
+
A selection of Asciidoctor extensions designed to used to write some AsciiSpec with Jekyll.
|
6
|
+
|
7
|
+
These extensions add custom blocks for Requirements and attempts to smartly handle inter-document auto-linking functionality.
|
8
|
+
|
9
|
+
== Motivation
|
10
|
+
|
11
|
+
Jekyll is a very flexible and speedy tool for generating static HTML pages.
|
12
|
+
The `jekyl-asciidoc` gem adds Asciidoctor functionality but it lacks a few features due to the way it handles multiple source files. As each `.adoc` file is consumed individually, we lose the ability to automatically format inter-document cross-references. This plugin is a group of extensions that performs some directory walking, stores the location of titles and anchors so that cross references in a Jekyll project are resolved automatically.
|
13
|
+
|
14
|
+
Additional features are
|
15
|
+
|
16
|
+
* Custom block for ``TODO``s
|
17
|
+
* Requirements Block with versioning
|
18
|
+
* Requirements block macro that creates a Table of Contents of declared Requirements
|
19
|
+
* Inline Callout macro to arbitrarily add callouts
|
20
|
+
* Inline Task macro to link to Jira tickets or Github Issues
|
21
|
+
* Inline Repo Macro to link to specific files or lines on GitHub
|
22
|
+
* A HTML postprocessor to correct some minor fixes and invalid tags created by Asciidoctor
|
23
|
+
|
24
|
+
When these custom extensions are combined with other recommended gems such as `asciidoctor-bibtex` and `asciidoctor-latex`, you can achieve quite high quality, speedy HTML documentation for technical projects with the benefits of a Jekyll build. It's recommended to use the `html-proofer` gem which will validate all links created with these extensions.
|
25
|
+
|
26
|
+
== Installation
|
27
|
+
|
28
|
+
Add `jekyll_aspec` to your Jekyll Gemfile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
group :jekyll_plugins do
|
32
|
+
gem 'jekyll-asciidoc'
|
33
|
+
gem 'jekyll_aspec'
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
Or install it yourself as:
|
38
|
+
|
39
|
+
$ gem install jekyll_aspec
|
40
|
+
|
41
|
+
== Docs
|
42
|
+
|
43
|
+
Please refer to the `docs` directory for some basic documentation on extended Asciidoctor features:
|
44
|
+
|
45
|
+
*<<docs/requirement-block#,[req] - Requirement Block>>*: Add requirements with custom formatting. +
|
46
|
+
*<<docs/todo-block#,[TODO] - Todo Block>>*: Add a custom TODO admonition block. +
|
47
|
+
|
48
|
+
== Contributing
|
49
|
+
|
50
|
+
This gem is under heavy initial development and there are still many kinks to work out. The areas to be improved upon include performance enhancements, proper handling of file IO / directory walking and, of course, documentation. Bug reports and pull requests are welcome on GitHub at https://github.com/bsmith-n4/jekyll_aspec.
|
51
|
+
|
52
|
+
== License
|
53
|
+
|
54
|
+
The gem is available as open source under the terms of the https://opensource.org/licenses/MIT[MIT License].
|
data/Rakefile
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
= Inline Task Macro
|
2
|
+
:toc:
|
3
|
+
|
4
|
+
Usage::
|
5
|
+
[source,asciidoc]
|
6
|
+
task:target[title]
|
7
|
+
|
8
|
+
The `inline task macro` creates hyperlinks to Jira task management and GitHub issue-tracking systems.
|
9
|
+
Optionally, it will render the links differently to reflect the status of the tasks if a task info file is provided.
|
10
|
+
|
11
|
+
Note that in case two colons are given instead of only one after `task`, the task link will be moved to the sidebar.
|
12
|
+
|
13
|
+
Attributes::
|
14
|
+
* *target:* The project prefix followed by a hyphen and the task number or ID (e.g. `23`).
|
15
|
+
* *title:* (optional) The text that will be displayed as an anchor in the generated hyperlink.
|
16
|
+
|
17
|
+
== Configuration
|
18
|
+
|
19
|
+
The target pattern needs to be specified in a document attribute:
|
20
|
+
|
21
|
+
`:task-pattern: http://www.myorg.github.com/myrepo/issues/`
|
22
|
+
|
23
|
+
For a Jekyll build, this can be added in the Jekyll `pass:[_config.yml]` to be passed to all documents:
|
24
|
+
|
25
|
+
```yaml
|
26
|
+
asciidoctor:
|
27
|
+
attributes:
|
28
|
+
task-pattern: http://www.myorg.github.com/myrepo/issues/
|
29
|
+
```
|
30
|
+
|
31
|
+
== Examples
|
32
|
+
|
33
|
+
A bug has already ``+++task:35[]+++`` been filed...
|
34
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
= Requirements Block
|
2
|
+
|
3
|
+
Usage::
|
4
|
+
|
5
|
+
.title
|
6
|
+
[req,id=RSL-3,version=1]
|
7
|
+
--
|
8
|
+
Contents of the requirement
|
9
|
+
--
|
10
|
+
|
11
|
+
|
12
|
+
Attributes::
|
13
|
+
* *title* (required): An anchor is derived from the requirement title and embedded at the beginning of the rendered output.
|
14
|
+
* *ID:* (required) The ID in the form *<Prefix>-<Number>*, used to generate an anchor
|
15
|
+
* *version*: (required) value is a non-negative integer.
|
16
|
+
|
17
|
+
NOTE: Omitting any of the above attributes will print an error to the console and insert a warning text in the generated document.
|
18
|
+
* *delimiter*: Lines containing only two hyphens `--` delimit the block. This is required if the block contains empty lines or nested formatting.
|
19
|
+
|
20
|
+
== ID Pattern
|
21
|
+
|
22
|
+
The purpose of the `<Prefix>-<Number>` ID is to ensure that Requirements are both unique and easily referenceable.
|
23
|
+
Currently, the ID may be any string, but should conform to the following conventions:
|
24
|
+
|
25
|
+
*<Prefix>*: :: `R` (requirement) followed by the project prefix (i.e. `SL` for `stdlib`)
|
26
|
+
*<Number>*: :: The requirement number, currently not validated.
|
27
|
+
A validation stage for requirement IDs (detecting duplicates, for instance) is planned.
|
28
|
+
|
29
|
+
Example::
|
30
|
+
|
31
|
+
The following example demonstrates how to document Requirement pass:[#]3 for stdlib Version 1;
|
32
|
+
|
33
|
+
.This is the title
|
34
|
+
[req,id=RSL-3,version=1]
|
35
|
+
--
|
36
|
+
My Super Requirement
|
37
|
+
--
|
38
|
+
|
39
|
+
|
40
|
+
*Req. RSL-3: <<This_is_the_title,This is the title>> (ver. 1)* +
|
41
|
+
My Super Requirement
|
42
|
+
|
43
|
+
|
44
|
+
== Xrefs
|
45
|
+
|
46
|
+
Cross-referencing requirements is done using the syntax `\<<Req-ID,Optional Link Text>>`, e.g. for the following requirement:
|
47
|
+
|
48
|
+
[req,id=ROPR-14603,version=1]
|
49
|
+
--
|
50
|
+
...
|
51
|
+
--
|
52
|
+
|
53
|
+
|
54
|
+
can be cross-referenced using the following syntax
|
55
|
+
|
56
|
+
See <<Req-ROPR-14603>>, or see also <<Req-ROPR-14603,confirm the booking>>.
|
@@ -0,0 +1,48 @@
|
|
1
|
+
= TODO Block
|
2
|
+
|
3
|
+
== Usage
|
4
|
+
|
5
|
+
[source,asciidoc]
|
6
|
+
----
|
7
|
+
// Simple use
|
8
|
+
|
9
|
+
[TODO]
|
10
|
+
Don't forget
|
11
|
+
----
|
12
|
+
|
13
|
+
=== Delimiters
|
14
|
+
|
15
|
+
Delimiters are required if the block contains empty lines or nested blocks. +
|
16
|
+
The following delimiters may be used:
|
17
|
+
|
18
|
+
[source,subs=macros]
|
19
|
+
----
|
20
|
+
====
|
21
|
+
--
|
22
|
+
pass:[++++]
|
23
|
+
****
|
24
|
+
pass:[----]
|
25
|
+
----
|
26
|
+
|
27
|
+
Examples::
|
28
|
+
[source,asciidoc]
|
29
|
+
----
|
30
|
+
.Block Title (optional)
|
31
|
+
[TODO]
|
32
|
+
--
|
33
|
+
Don't Forget!
|
34
|
+
|
35
|
+
. Resolve an issue
|
36
|
+
.. Don't break anything
|
37
|
+
--
|
38
|
+
|
39
|
+
// or
|
40
|
+
|
41
|
+
[TODO]
|
42
|
+
++++
|
43
|
+
Don't divide by zero.
|
44
|
+
|
45
|
+
* Add 1 to infinity.
|
46
|
+
++++
|
47
|
+
|
48
|
+
----
|
data/jekyll_aspec.gemspec
CHANGED
@@ -10,9 +10,16 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["brian.smith@numberfour.eu"]
|
11
11
|
|
12
12
|
spec.summary = %q{Asciidoctor extensions for use as a Jekyll plugin}
|
13
|
+
spec.description = %q{This plugin is a group of Asciidoctor extensions that perform directory walking,
|
14
|
+
resolving the location of titles and anchors in all adoc files so that inter-document
|
15
|
+
cross-references in a Jekyll project are resolved automatically. Also included are some
|
16
|
+
custom macros and blocks that are useful for techinical writing.}
|
13
17
|
spec.homepage = "https://github.com/bsmith-n4/jekyll_aspec"
|
14
18
|
spec.license = "MIT"
|
15
19
|
|
20
|
+
# This gem will work with 2.0 or greater.
|
21
|
+
spec.required_ruby_version = '>= 2.0'
|
22
|
+
|
16
23
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
24
|
f.match(%r{^(test|spec|features)/})
|
18
25
|
end
|
data/lib/extensions/autoxrefs.rb
CHANGED
@@ -1,117 +1,23 @@
|
|
1
1
|
require 'asciidoctor/extensions'
|
2
2
|
require 'pathname'
|
3
|
+
require_relative 'utils/xref_helper'
|
3
4
|
|
4
5
|
include ::Asciidoctor
|
5
6
|
|
6
|
-
|
7
|
-
adoc_files = Dir.glob('**/*.adoc')
|
7
|
+
mismatches = Xrefs.list_xrefs
|
8
8
|
invoc = Dir.pwd
|
9
9
|
|
10
|
-
# Make some arrays available
|
11
|
-
titles = []
|
12
|
-
anchors = []
|
13
|
-
xrefs = []
|
14
|
-
mismatches = []
|
15
|
-
|
16
|
-
replacement = ''
|
17
|
-
|
18
|
-
def trim(s)
|
19
|
-
s.gsub!(/_docs\//, '')
|
20
|
-
s.gsub!(/(\.adoc|\.md|\.html)/, '')
|
21
|
-
end
|
22
|
-
|
23
|
-
def targetify(t)
|
24
|
-
# make all chars lowercase and substitute spaces with hyphens
|
25
|
-
t.downcase.gsub(/\s/, '-')
|
26
|
-
end
|
27
|
-
|
28
|
-
adoc_files.each do |file_name|
|
29
|
-
lc = 0
|
30
|
-
|
31
|
-
File.read(file_name).each_line do |li|
|
32
|
-
lc += 1
|
33
|
-
|
34
|
-
# Match all <<xrefs>> exluding Requirements
|
35
|
-
if li[/\<\<(?!Req)(.+?)\>\>/]
|
36
|
-
|
37
|
-
text = ''
|
38
|
-
target = ''
|
39
|
-
path = trim(file_name)
|
40
|
-
xref = li.chop.match(/\<\<(?!Req)(\S.+?)\>\>/i).captures[0].to_s
|
41
|
-
|
42
|
-
if xref[/,/]
|
43
|
-
target = xref.downcase.gsub(/,.+/, '').gsub(/\s/, '-')
|
44
|
-
text = xref.gsub(/.+,/, '').lstrip!
|
45
|
-
xref = xref.sub(/,.+/, '')
|
46
|
-
path = file_name
|
47
|
-
else
|
48
|
-
target = xref.downcase.gsub(/\s/, '-')
|
49
|
-
text = xref
|
50
|
-
end
|
51
|
-
|
52
|
-
item = [xref, path, file_name, text, target]
|
53
|
-
xrefs.push item
|
54
|
-
|
55
|
-
# Match .Titles and = Section Titles
|
56
|
-
elsif li[/(^(\.\S\w+)|^(\=+\s+?\S+.+))/]
|
57
|
-
|
58
|
-
# Add check if none found (captures nil)
|
59
|
-
title = li.chop.match(/(?!=+\s)(\S+.+?)$/i).captures[0]
|
60
|
-
title.sub!(/\.(?=\w+?)/, '') if title[/\.(?=\w+?)/]
|
61
|
-
path = trim(file_name)
|
62
|
-
item = [title, path, file_name]
|
63
|
-
titles.push item
|
64
|
-
|
65
|
-
# Match [[anchors]]
|
66
|
-
elsif li[/\[\[.+?\]\]/]
|
67
|
-
|
68
|
-
# Add check if none found (captures nil)
|
69
|
-
anchor = li.chop.match(/(?<=\[\[).+?(?=\]\])/).to_s
|
70
|
-
|
71
|
-
if anchor[/,/]
|
72
|
-
anchor = anchor.match(/(?<=\[\[)(?:|[\w+?_:][\w+?:.-]*)(?=,.+?\]\])/).to_s
|
73
|
-
text = anchor.sub(/.+?,/, '')
|
74
|
-
text = text.sub(/\]\]$/, '')
|
75
|
-
end
|
76
|
-
|
77
|
-
path = trim(file_name)
|
78
|
-
item = [anchor, path, file_name, text]
|
79
|
-
titles.push item
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Run through each xref and check for matching titles
|
86
|
-
xrefs.each do |xref, xpath, xfile, xtext, xtarget|
|
87
|
-
# check xrefs against titles
|
88
|
-
titles.each do |ttext, tpath, tfile, _tdisp|
|
89
|
-
# puts "checking #{ttext} against #{xref}"
|
90
|
-
next unless ttext == xref
|
91
|
-
tpath = 'index' if tpath.to_s.empty?
|
92
|
-
# If the paths are not the same (xref and title not the same document) do the following
|
93
|
-
next unless tpath != xpath
|
94
|
-
|
95
|
-
# puts "Title \"#{ttext}\" in #{tfile} - mismatched xref \"#{xref}\" to different doc - #{xpath}"
|
96
|
-
xtform = targetify(xtarget)
|
97
|
-
detail = [xref, xtarget, xtext, xpath, xfile, ttext, tpath, tfile, xtform]
|
98
|
-
mismatches.push detail
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
10
|
Extensions.register do
|
103
11
|
preprocessor do
|
104
12
|
process do |document, reader|
|
105
13
|
fixes = []
|
106
14
|
i = 0
|
107
15
|
|
108
|
-
#
|
109
|
-
# for each malformed xref
|
16
|
+
# TODO - remove unused elements (prepended with _) from the helper method in utils/xref_helper
|
110
17
|
mismatches.each do |_xref, _xtarget, xtext, _xpath, xfile, _ttext, _tpath, tfile, xtform|
|
111
|
-
# FIXME: This directory is empty in POSTS - breaks conversion
|
112
18
|
docfile = document.attributes['docfile'].sub(/^#{invoc}\//, '')
|
113
|
-
trim(docfile)
|
114
|
-
|
19
|
+
Xrefs.trim(docfile)
|
20
|
+
|
115
21
|
next unless docfile.to_s == xfile
|
116
22
|
|
117
23
|
# calculate the relative path between source and target
|
@@ -129,8 +35,6 @@ Extensions.register do
|
|
129
35
|
if li[/\<\<(?!Req)(.+?)\>\>/]
|
130
36
|
|
131
37
|
mismatches.each do |xref, xtarget, xtext, _xpath, _xfile, _ttext, _tpath, _tfile, _relpath|
|
132
|
-
# check if the line contains the original xref
|
133
|
-
|
134
38
|
next unless li[/\<\<#{xref}(,.+)?\>\>/]
|
135
39
|
fixes.each do |x|
|
136
40
|
if x[/#{xtarget}/]
|
@@ -140,7 +44,6 @@ Extensions.register do
|
|
140
44
|
end
|
141
45
|
i += 1
|
142
46
|
end
|
143
|
-
|
144
47
|
else
|
145
48
|
replacement = ''
|
146
49
|
end
|
@@ -2,6 +2,8 @@ require 'asciidoctor/extensions'
|
|
2
2
|
|
3
3
|
include ::Asciidoctor
|
4
4
|
|
5
|
+
# @example Basic Usage
|
6
|
+
# See call:1[] for details
|
5
7
|
Asciidoctor::Extensions.register do
|
6
8
|
inline_macro do
|
7
9
|
named :call
|
@@ -9,4 +11,4 @@ Asciidoctor::Extensions.register do
|
|
9
11
|
Asciidoctor::Inline.new(parent, :callout, target.to_i).convert
|
10
12
|
end
|
11
13
|
end
|
12
|
-
end
|
14
|
+
end
|
@@ -4,18 +4,24 @@ require_relative 'utils/block'
|
|
4
4
|
|
5
5
|
include ::Asciidoctor
|
6
6
|
|
7
|
+
# @example Basic Usage
|
8
|
+
# See cwiki:topic[] for details
|
9
|
+
# @example Block Use
|
10
|
+
# Already documented. cwiki::topic[]
|
7
11
|
Extensions.register do
|
8
12
|
inline_macro do
|
9
13
|
named :cwiki
|
10
14
|
|
11
15
|
process do |parent, target, attrs|
|
12
|
-
pattern =
|
13
|
-
|
14
|
-
'
|
16
|
+
pattern = parent.document.attr 'cwiki-pattern'
|
17
|
+
if pattern.nil?
|
18
|
+
warn "asciidoctor: WARNING: Attribue 'cwiki-pattern' for inline repo macro not defined"
|
19
|
+
pattern = "unknown"
|
20
|
+
end
|
15
21
|
url = pattern % target
|
16
22
|
|
17
23
|
label = Labels.getstatus(attrs)
|
18
|
-
html = Context.
|
24
|
+
html = Context.format(attrs, target, url, label)
|
19
25
|
(create_pass_block parent, html, attrs).render
|
20
26
|
end
|
21
27
|
end
|
@@ -2,29 +2,34 @@ require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'
|
|
2
2
|
|
3
3
|
include ::Asciidoctor
|
4
4
|
|
5
|
+
url = ''
|
6
|
+
file = ''
|
7
|
+
line = ''
|
8
|
+
formattedurl = ''
|
9
|
+
text = ''
|
10
|
+
|
5
11
|
# Link to a file on GitHub.
|
6
12
|
#
|
7
13
|
# repo:<repository>:<file>:<line>[]
|
8
14
|
#
|
9
|
-
#
|
15
|
+
# The target should be set using document attributes prefixed by 'repo_'.
|
10
16
|
#
|
17
|
+
# @example Attribute configuration
|
18
|
+
# :repo_dockerfiles: www.github.com/exampleuser/dockerfiles/issues
|
19
|
+
# @example Simple Use
|
11
20
|
# repo:dockerfiles:ansible/Dockerfile_template[]
|
21
|
+
# @example Link to repo and line number
|
12
22
|
# repo:dockerfiles:ansible/Dockerfile_template:2[]
|
23
|
+
# @example Link to repo, branch and line number
|
13
24
|
# repo:dockerfiles:ansible/Dockerfile_template:5[branch="AS_v0.0.10"]
|
25
|
+
# @example Link to repo and line number (alternate use)
|
14
26
|
# repo:dockerfiles:ansible/Dockerfile_template[line="5",branch="AS_v0.0.10"]
|
15
|
-
#
|
16
|
-
|
17
|
-
url = ''
|
18
|
-
file = ''
|
19
|
-
line = ''
|
20
|
-
formattedurl = ''
|
21
|
-
text = ''
|
22
|
-
|
23
27
|
Extensions.register do
|
24
28
|
inline_macro do
|
25
29
|
named :repo
|
26
30
|
|
27
31
|
process do |parent, target, attrs|
|
32
|
+
# @todo fix handling of use within cells. This is done using the context.
|
28
33
|
if parent.context.to_s == 'cell'
|
29
34
|
warn %([Hell in a cell] cell with repo link must have 'asciidoc format')
|
30
35
|
end
|
@@ -66,6 +71,11 @@ Extensions.register do
|
|
66
71
|
end
|
67
72
|
end
|
68
73
|
|
74
|
+
if formattedurl.nil?
|
75
|
+
warn "asciidoctor: WARNING: Attribue 'repo_...' for inline repo macro not defined"
|
76
|
+
pattern = "unknown"
|
77
|
+
end
|
78
|
+
|
69
79
|
html = %(<a href=\"#{formattedurl}\" style=\"padding-right:2px;\">
|
70
80
|
<span class=\"label label-#{label}\" style=\"font-weight: 400;
|
71
81
|
font-size:smaller;\">
|
@@ -4,18 +4,24 @@ require_relative 'utils/block'
|
|
4
4
|
|
5
5
|
include ::Asciidoctor
|
6
6
|
|
7
|
+
# @example Basic Usage
|
8
|
+
# See task:101[] for details
|
9
|
+
# @example Block Use
|
10
|
+
# Already completed. task::101[]
|
7
11
|
Extensions.register do
|
8
12
|
inline_macro do
|
9
13
|
named :task
|
10
14
|
|
11
15
|
process do |parent, target, attrs|
|
12
|
-
pattern =
|
13
|
-
|
14
|
-
'
|
16
|
+
pattern = parent.document.attr 'task-pattern'
|
17
|
+
if pattern.nil?
|
18
|
+
warn "asciidoctor: WARNING: Attribue 'task-pattern' for inline task macro not defined"
|
19
|
+
pattern = "unknown"
|
20
|
+
end
|
15
21
|
url = pattern % target
|
16
|
-
|
22
|
+
|
17
23
|
label = Labels.getstatus(attrs)
|
18
|
-
html = Context.
|
24
|
+
html = Context.format(attrs, target, url, label)
|
19
25
|
(create_pass_block parent, html, attrs).render
|
20
26
|
end
|
21
27
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# Used by Jekyll during conversion
|
1
2
|
module Jekyll
|
2
3
|
# A Liquid Template Filter for using regular expressions
|
3
4
|
module RegexFilter
|
5
|
+
# Simple replacement
|
4
6
|
def replace_regex(input, regex_string, replace_string)
|
5
7
|
regex = Regexp.new regex_string
|
6
8
|
input.gsub regex, replace_string
|
data/lib/extensions/req_refs.rb
CHANGED
@@ -2,26 +2,30 @@ require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'
|
|
2
2
|
|
3
3
|
include ::Asciidoctor
|
4
4
|
|
5
|
+
# @todo check if all code before the macro can be moved into util directory as helper methods
|
6
|
+
|
7
|
+
# @todo Don't do this
|
5
8
|
adoc_files = Dir.glob('**/*.adoc')
|
9
|
+
# @todo Retrieve these via document attributes, should not be hardcoded
|
10
|
+
docsdir = '_docs'
|
6
11
|
exts = '(\.adoc|\.md|\.html)'
|
7
12
|
|
8
13
|
rpath = nil
|
9
14
|
rtext = nil
|
15
|
+
orphan = false
|
16
|
+
|
10
17
|
reqs = []
|
11
18
|
inc_reqs = []
|
12
19
|
com_reqs = []
|
13
20
|
incs = []
|
14
21
|
xrefs = []
|
22
|
+
|
15
23
|
xref_base = ''
|
16
24
|
|
17
|
-
blockrx = %r
|
25
|
+
blockrx = %r{^\/{4,}$}
|
18
26
|
linerx = %r{^//(?=[^/]|$)}
|
19
27
|
|
20
|
-
|
21
|
-
|
22
|
-
# Retrieve this via document attribute
|
23
|
-
docsdir = '_docs'
|
24
|
-
|
28
|
+
# @todo called helper method here
|
25
29
|
def trim(s)
|
26
30
|
s.gsub!(/_docs\//, '')
|
27
31
|
s.gsub!(/(\.adoc|\.md|\.html)/, '')
|
@@ -90,11 +94,16 @@ end
|
|
90
94
|
# Sort (in-place) by numberic ID
|
91
95
|
reqs.sort_by!(&:first)
|
92
96
|
|
97
|
+
# @todo convert to formal
|
93
98
|
Extensions.register do
|
94
99
|
inline_macro do
|
95
100
|
named :requirement_autoxref
|
96
101
|
|
97
102
|
# Regex-based, will match "See Req-ROPR-123 for..."
|
103
|
+
# Will also match <<Req-ROPR-123>>
|
104
|
+
# @todo this is a heavy-handed approach to matching all
|
105
|
+
# xrefs. Find a better way to autolink xrefs that doesn't involved the
|
106
|
+
# use of the req-preprocessor
|
98
107
|
match /(Req-\w+-?\d+)/
|
99
108
|
|
100
109
|
# match id with Req-\w+-?(\d+)
|
@@ -2,50 +2,55 @@ require "asciidoctor/extensions" unless RUBY_ENGINE == "opal"
|
|
2
2
|
|
3
3
|
include ::Asciidoctor
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
<h3 class=\"panel-title\">
|
36
|
-
<a class=\"anchor\" href=\"##{id}\"></a>
|
37
|
-
<a class=\"link\" href=\"##{id}\"><emphasis role=\"strong\">Requirement: #{id}:</emphasis> #{san_title} </a> (ver. #{attrs['version']})
|
38
|
-
</h3>
|
39
|
-
</div>
|
40
|
-
<div class=\"panel-body\">)
|
41
|
-
|
42
|
-
close = "</div></div>"
|
43
|
-
|
44
|
-
# concatenate all generated lines and prepend before the original content
|
45
|
-
concat_lines = reader.lines.unshift(pass, alt, pass, nl)
|
46
|
-
concat_lines.push(nl, pass, close, pass)
|
47
|
-
|
48
|
-
create_block parent, :admonition, concat_lines, attrs, content_model: :compound
|
5
|
+
# @example Delimited Requirement Block with Title
|
6
|
+
# .My Requirement
|
7
|
+
# [req,id=RA-1,version=1]
|
8
|
+
# --
|
9
|
+
# Contents of the requirement
|
10
|
+
# --
|
11
|
+
class RequirementBlock < Extensions::BlockProcessor
|
12
|
+
use_dsl
|
13
|
+
named :req
|
14
|
+
on_contexts :open, :paragraph, :example, :listing, :sidebar, :pass
|
15
|
+
name_positional_attributes "number", "version"
|
16
|
+
|
17
|
+
# Read the parent attributes and create a Requirement Admonition block
|
18
|
+
def process parent, reader, attrs
|
19
|
+
# Add pass characters here to prevent html character replacements for < > tags
|
20
|
+
pass = "+++"
|
21
|
+
attrs["name"] = "requirement"
|
22
|
+
attrs["caption"] = "Requirement: "
|
23
|
+
id = attrs["id"]
|
24
|
+
nl = ""
|
25
|
+
|
26
|
+
begin
|
27
|
+
# downcase the title and replace spaces with underscores.
|
28
|
+
# @todo use utility methods here?
|
29
|
+
downcased_title = attrs["title"].downcase.tr(" ", "_").gsub('"', """)
|
30
|
+
san_title = attrs["title"].gsub(/&/, "&")
|
31
|
+
rescue Exception => msg
|
32
|
+
# puts msg
|
33
|
+
# If no title exists on the Req block, throw an exception
|
34
|
+
warn %(asciidoctor: WARNING: Requirement block title missing)
|
49
35
|
end
|
36
|
+
|
37
|
+
alt = %(
|
38
|
+
<div class=\"panel panel-primary\">
|
39
|
+
<div class=\"panel-heading\">
|
40
|
+
<h3 class=\"panel-title\">
|
41
|
+
<a class=\"anchor\" href=\"##{id}\"></a>
|
42
|
+
<a class=\"link\" href=\"##{id}\"><emphasis role=\"strong\">Requirement: #{id}:</emphasis> #{san_title} </a> (ver. #{attrs['version']})
|
43
|
+
</h3>
|
44
|
+
</div>
|
45
|
+
<div class=\"panel-body\">)
|
46
|
+
|
47
|
+
close = "</div></div>"
|
48
|
+
|
49
|
+
# concatenate all generated lines and prepend before the original content
|
50
|
+
concat_lines = reader.lines.unshift(pass, alt, pass, nl)
|
51
|
+
concat_lines.push(nl, pass, close, pass)
|
52
|
+
|
53
|
+
# @todo use a regular pass block in this instance
|
54
|
+
create_block parent, :admonition, concat_lines, attrs, content_model: :compound
|
50
55
|
end
|
51
56
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'asciidoctor'
|
2
|
+
require 'asciidoctor/extensions'
|
3
|
+
require_relative 'utils/req_macro_walker'
|
4
|
+
|
5
|
+
include ::Asciidoctor
|
6
|
+
|
7
|
+
# @example Requirement Block Macro Use
|
8
|
+
# requirements::[]
|
9
|
+
class RequirementsBlockMacro < Extensions::BlockMacroProcessor
|
10
|
+
use_dsl
|
11
|
+
named :requirements
|
12
|
+
|
13
|
+
# Read the parent attributes and create a list of requirements in an appendix style
|
14
|
+
def process(parent, target, attrs)
|
15
|
+
rows = Reqs.list_reqs
|
16
|
+
content = %(<h2 id="requirements"><a class="anchor" href="#requirements"></a><a class="link" href="#requirements">Requirements</a></h2>
|
17
|
+
<div class="panel panel-default"> <div class="panel-heading"><h4>Requirements</h4></div>
|
18
|
+
<table class="table"> <thead> <tr>
|
19
|
+
<th>#</th> <th>ID</th><th>Version</th> <th>Title</th> <th>Document</th>
|
20
|
+
</tr> </thead>
|
21
|
+
<tbody>
|
22
|
+
#{rows.join}
|
23
|
+
</tbody>
|
24
|
+
</table> </div>)
|
25
|
+
|
26
|
+
create_pass_block parent, content, {}
|
27
|
+
end
|
28
|
+
end
|
@@ -2,11 +2,18 @@ require "asciidoctor/extensions" unless RUBY_ENGINE == "opal"
|
|
2
2
|
|
3
3
|
include ::Asciidoctor
|
4
4
|
|
5
|
+
# @example A delimited TODO block
|
6
|
+
# [TODO]
|
7
|
+
# --
|
8
|
+
# Don't Forget!
|
9
|
+
# --
|
5
10
|
class TodoBlock < Extensions::BlockProcessor
|
6
11
|
use_dsl
|
7
12
|
named :TODO
|
8
13
|
on_contexts :open, :paragraph, :example, :listing, :sidebar, :pass
|
9
14
|
|
15
|
+
# Read the parent attributes and create a TODO
|
16
|
+
# admonition block
|
10
17
|
def process parent, reader, attrs
|
11
18
|
attrs['name'] = 'todo'
|
12
19
|
attrs['caption'] = 'Todo'
|
@@ -1,5 +1,13 @@
|
|
1
|
+
# Helper methods handling whether to output inline content or a block.
|
2
|
+
# Will read the attributes of the current macro and output a HTML string that is either
|
3
|
+
# inline or a block (float-right).
|
1
4
|
module Context
|
2
|
-
|
5
|
+
# @param attributes [Array] attributes passed by the inline macro
|
6
|
+
# @param target [String] the target text
|
7
|
+
# @param url [String] the target url
|
8
|
+
# @param label [String] an optional status label, used to display if a task/issue is open or closed
|
9
|
+
# @return [String] the raw HTML to be included in the target document
|
10
|
+
def self.format(attributes, target, url, label)
|
3
11
|
block = false
|
4
12
|
block = true if attributes.key? "block"
|
5
13
|
|
@@ -1,4 +1,9 @@
|
|
1
|
+
# A simple helper method handles the status of the target text.
|
2
|
+
# This is used to display whether a GitHub issue or a Jira ticket
|
3
|
+
# is open or closed etc.
|
1
4
|
module Labels
|
5
|
+
# @param attrs [Array] attributes passed by the inline macro
|
6
|
+
# @return [String] the status and/or label to be displayed
|
2
7
|
def self.getstatus(attrs)
|
3
8
|
status = attrs["status"]
|
4
9
|
if status == ("done" || "closed")
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# Special handling for linking to Requirements.
|
2
|
+
# These are mainly used by the Requirement Appendix (requirement_block_macro)
|
3
|
+
#
|
4
|
+
module Reqs
|
5
|
+
# Recursively globs all files with the .adoc extension and matches cross-references
|
6
|
+
# to Requirements. The special handling here is that we detect if the target
|
7
|
+
# requirement is commented, in a source block or included.
|
8
|
+
#
|
9
|
+
# @return [Array] An array of the IDs and paths to requirements in generated HTML files
|
10
|
+
def self.list_reqs
|
11
|
+
# @todo This should be configurable, or at least not hardcoded
|
12
|
+
exts = "(\.adoc|\.md|\.html)"
|
13
|
+
docsdir = '_docs'
|
14
|
+
|
15
|
+
title = nil
|
16
|
+
chapter = nil
|
17
|
+
doctitle = nil
|
18
|
+
|
19
|
+
reqs = []
|
20
|
+
rows = []
|
21
|
+
# For commented requirements
|
22
|
+
coms = []
|
23
|
+
# For includes
|
24
|
+
inc_reqs = []
|
25
|
+
incs = []
|
26
|
+
|
27
|
+
commentblockrx = '/^\/{4,}$/'
|
28
|
+
commentlinerx = '/^//(?=[^/]|$)/'
|
29
|
+
|
30
|
+
# @todo Already defined in Xref util?
|
31
|
+
def trim(s)
|
32
|
+
s.gsub!(/_docs\//, '')
|
33
|
+
s.gsub!(/(\.adoc|\.md|\.html)/, '')
|
34
|
+
end
|
35
|
+
|
36
|
+
# @todo Dont do this? Find a better way of handling all source adoc files.
|
37
|
+
adoc_files = Dir.glob('**/*.adoc')
|
38
|
+
|
39
|
+
adoc_files.each do |f|
|
40
|
+
inc = false
|
41
|
+
commented = false
|
42
|
+
|
43
|
+
File.read(f).each_line do |li|
|
44
|
+
incommentblock ^= true if li[commentblockrx]
|
45
|
+
commented = true if li[commentlinerx]
|
46
|
+
inc = true if li[/published: false/]
|
47
|
+
|
48
|
+
doctitle = /(?<=title:\s).+/.match(li) if li[/^title:\s+\w.+/]
|
49
|
+
chapter = /(?<=chapter:\s).+/.match(li) if li[/^chapter:\s+\w.+/]
|
50
|
+
|
51
|
+
if li[/^\[\s*req\s*,\s*id\s*=\s*\w+-?[0-9]+\s*,.*/]
|
52
|
+
title.sub!(/^\./, '')
|
53
|
+
req = [li.chop, f, title, chapter, doctitle]
|
54
|
+
|
55
|
+
if commented || incommentblock
|
56
|
+
coms.push(req)
|
57
|
+
elsif inc
|
58
|
+
inc_reqs.push(req)
|
59
|
+
else
|
60
|
+
reqs.push(req)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Collect all includes
|
64
|
+
elsif li[/^include::.+.adoc\[\]/]
|
65
|
+
|
66
|
+
inc_file = li.chop.match(/(?<=^include::).+.adoc(?=\[\])/i).to_s
|
67
|
+
path = inc_file.sub(/^#{docsdir}\//, '')
|
68
|
+
path = path.sub(/#{exts}/, '')
|
69
|
+
parent = f
|
70
|
+
item = [inc_file, path, parent]
|
71
|
+
incs.push item
|
72
|
+
|
73
|
+
end
|
74
|
+
title = li
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Sort included reqs and correct the path to the parent (including doc)
|
79
|
+
# Push this back into 'normal' requirements array for regular processing
|
80
|
+
inc_reqs.each do |l, f, title, chapter, doctitle|
|
81
|
+
incs.each do |incfile, _incpath, parent|
|
82
|
+
if f == incfile
|
83
|
+
item = [l, parent, title, chapter, doctitle]
|
84
|
+
reqs.push item
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Remove dupes
|
90
|
+
reqs.uniq!
|
91
|
+
|
92
|
+
i = 0
|
93
|
+
reqs.each do |req, f, title, chapter, doctitle|
|
94
|
+
i += 1
|
95
|
+
|
96
|
+
id = /[^,]*\s*id\s*=\s*(\w+-?[0-9]+)\s*,.*/.match(req)[1]
|
97
|
+
version = /(?<=version=)\d+/.match(req)
|
98
|
+
|
99
|
+
f.gsub!(/^_docs\//, '')
|
100
|
+
f.gsub!(/.adoc$/, '')
|
101
|
+
|
102
|
+
link = "#{f}/index##{id}"
|
103
|
+
ref = "<a class=\"link\" href=\"#{link}\"><emphasis role=\"strong\">#{title}</emphasis> </a>"
|
104
|
+
breadcrumb = "<a href=\"#{f}\">#{chapter} / #{doctitle}</a>"
|
105
|
+
row = "<tr> <th scope=\"row\">#{i}</th> <td>#{id}</td><td>#{version}</td> <td>#{ref}</td> <td>#{breadcrumb}</td> </tr>"
|
106
|
+
|
107
|
+
rows.push(row)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# Helper methods for common xref processing.
|
2
|
+
#
|
3
|
+
module Xrefs
|
4
|
+
# Trims a path of a given source document to exclude the docs directory
|
5
|
+
# and file extension. This is used to calculate the target directory
|
6
|
+
# of generated HTML files given default permalink settings.
|
7
|
+
#
|
8
|
+
# @param path [String] the path of the source document relative to the project root
|
9
|
+
# @return [String] the formatted path
|
10
|
+
def self.trim(path)
|
11
|
+
trimmed = path.gsub(/_docs\//, '')
|
12
|
+
trimmed.gsub(/(\.adoc|\.md|\.html)/, '')
|
13
|
+
end
|
14
|
+
|
15
|
+
# Formats a string to be permalink-friendly. This simply
|
16
|
+
# downcases the string an substitutes spaces with hyphens. This is
|
17
|
+
# typically used for section titles and document titles to generate
|
18
|
+
# a cross-reference to an anchor.
|
19
|
+
#
|
20
|
+
# @param path [String] the path of the source document relative to the project root
|
21
|
+
# @return [String] the formatted path
|
22
|
+
def self.targetify(path)
|
23
|
+
path.downcase.gsub(/\s/, '-')
|
24
|
+
end
|
25
|
+
|
26
|
+
# Recursively globs all files with the .adoc extension and matches cross-references,
|
27
|
+
# section titles and anchors. Cross-references to Requirements are excluded and handled
|
28
|
+
# in their own processor as they are a special case (i.e., there is no built-in support).
|
29
|
+
#
|
30
|
+
# @return [String] the formatted path
|
31
|
+
def self.list_xrefs
|
32
|
+
|
33
|
+
# @todo Maybe don't do this. Find a better way to process
|
34
|
+
# all .adoc files before extensions are loaded.
|
35
|
+
adoc_files = Dir.glob('**/*.adoc')
|
36
|
+
|
37
|
+
# Make some arrays available
|
38
|
+
titles = []
|
39
|
+
anchors = []
|
40
|
+
xrefs = []
|
41
|
+
mismatches = []
|
42
|
+
|
43
|
+
replacement = ''
|
44
|
+
|
45
|
+
adoc_files.each do |file_name|
|
46
|
+
lc = 0
|
47
|
+
|
48
|
+
File.read(file_name).each_line do |li|
|
49
|
+
lc += 1
|
50
|
+
|
51
|
+
# @note Matches all <<xrefs>> except Requirements
|
52
|
+
if li[/\<\<(?!Req)(.+?)\>\>/]
|
53
|
+
|
54
|
+
text = ''
|
55
|
+
target = ''
|
56
|
+
path = trim(file_name)
|
57
|
+
xref = li.chop.match(/\<\<(?!Req)(\S.+?)\>\>/i).captures[0].to_s
|
58
|
+
|
59
|
+
# @note Checks if the xref has display text, i.e. '<<title-1,Lovely Display Text>>'
|
60
|
+
if xref[/,/]
|
61
|
+
# @todo Use helper methods.
|
62
|
+
target = xref.downcase.gsub(/,.+/, '').gsub(/\s/, '-')
|
63
|
+
text = xref.gsub(/.+,/, '').lstrip!
|
64
|
+
xref = xref.sub(/,.+/, '')
|
65
|
+
path = file_name
|
66
|
+
else
|
67
|
+
# @todo Use helper methods.
|
68
|
+
target = xref.downcase.gsub(/\s/, '-')
|
69
|
+
text = xref
|
70
|
+
end
|
71
|
+
|
72
|
+
item = [xref, path, file_name, text, target]
|
73
|
+
xrefs.push item
|
74
|
+
|
75
|
+
# Match .Titles and = Section Titles
|
76
|
+
elsif li[/(^(\.\S\w+)|^(\=+\s+?\S+.+))/]
|
77
|
+
|
78
|
+
# Add check if none found (captures nil)
|
79
|
+
title = li.chop.match(/(?!=+\s)(\S+.+?)$/i).captures[0]
|
80
|
+
title.sub(/\.(?=\w+?)/, '') if title[/\.(?=\w+?)/]
|
81
|
+
path = trim(file_name)
|
82
|
+
item = [title, path, file_name]
|
83
|
+
titles.push item
|
84
|
+
|
85
|
+
# Match [[anchors]]
|
86
|
+
elsif li[/\[\[.+?\]\]/]
|
87
|
+
|
88
|
+
# Add check if none found (captures nil)
|
89
|
+
anchor = li.chop.match(/(?<=\[\[).+?(?=\]\])/).to_s
|
90
|
+
|
91
|
+
if anchor[/,/]
|
92
|
+
anchor = anchor.match(/(?<=\[\[)(?:|[\w+?_:][\w+?:.-]*)(?=,.+?\]\])/).to_s
|
93
|
+
text = anchor.sub(/.+?,/, '')
|
94
|
+
text = text.sub(/\]\]$/, '')
|
95
|
+
end
|
96
|
+
|
97
|
+
path = trim(file_name)
|
98
|
+
item = [anchor, path, file_name, text]
|
99
|
+
# for the moment, just handle anchors similar to titles
|
100
|
+
titles.push item
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Run through each xref and check for matching titles
|
107
|
+
xrefs.each do |xref, xpath, xfile, xtext, xtarget|
|
108
|
+
# check xrefs against titles
|
109
|
+
titles.each do |ttext, tpath, tfile, _tdisp|
|
110
|
+
|
111
|
+
next unless ttext == xref
|
112
|
+
tpath = 'index' if tpath.to_s.empty?
|
113
|
+
# If the paths are not the same (xref and title not the same document) do the following
|
114
|
+
next unless tpath != xpath
|
115
|
+
|
116
|
+
xtform = targetify(xtarget)
|
117
|
+
detail = [xref, xtarget, xtext, xpath, xfile, ttext, tpath, tfile, xtform]
|
118
|
+
mismatches.push detail
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/jekyll_aspec/version.rb
CHANGED
data/lib/jekyll_aspec.rb
CHANGED
@@ -6,12 +6,14 @@ require_relative "extensions/inline_repo_macro"
|
|
6
6
|
require_relative "extensions/inline_task_macro"
|
7
7
|
require_relative "extensions/req_preprocessor"
|
8
8
|
require_relative "extensions/req_refs"
|
9
|
-
require_relative "extensions/
|
10
|
-
require_relative "extensions/requirement_block"
|
9
|
+
require_relative "extensions/requirement_block_macro"
|
11
10
|
require_relative "extensions/todo_block"
|
12
11
|
|
13
12
|
require "jekyll_aspec/version"
|
14
13
|
|
14
|
+
# Load Asciidoctor extensions
|
15
15
|
Extensions.register do
|
16
16
|
block TodoBlock
|
17
|
+
block RequirementBlock
|
18
|
+
block_macro RequirementsBlockMacro
|
17
19
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll_aspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- bsmith-n4
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,7 +66,11 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.5.0
|
69
|
-
description:
|
69
|
+
description: "This plugin is a group of Asciidoctor extensions that perform directory
|
70
|
+
walking, \n resolving the location of titles and anchors
|
71
|
+
in all adoc files so that inter-document\n cross-references
|
72
|
+
in a Jekyll project are resolved automatically. Also included are some \n custom
|
73
|
+
macros and blocks that are useful for techinical writing."
|
70
74
|
email:
|
71
75
|
- brian.smith@numberfour.eu
|
72
76
|
executables: []
|
@@ -78,10 +82,13 @@ files:
|
|
78
82
|
- Gemfile
|
79
83
|
- Gemfile.lock
|
80
84
|
- LICENSE.txt
|
81
|
-
- README.
|
85
|
+
- README.adoc
|
82
86
|
- Rakefile
|
83
87
|
- bin/console
|
84
88
|
- bin/setup
|
89
|
+
- docs/inline-task.adoc
|
90
|
+
- docs/requirement-block.adoc
|
91
|
+
- docs/todo-block.adoc
|
85
92
|
- jekyll_aspec.gemspec
|
86
93
|
- lib/extensions/autoxrefs.rb
|
87
94
|
- lib/extensions/html_postprocessor.rb
|
@@ -92,11 +99,13 @@ files:
|
|
92
99
|
- lib/extensions/replace_regex.rb
|
93
100
|
- lib/extensions/req_preprocessor.rb
|
94
101
|
- lib/extensions/req_refs.rb
|
95
|
-
- lib/extensions/requirement_appendix.rb
|
96
102
|
- lib/extensions/requirement_block.rb
|
103
|
+
- lib/extensions/requirement_block_macro.rb
|
97
104
|
- lib/extensions/todo_block.rb
|
98
105
|
- lib/extensions/utils/block.rb
|
99
106
|
- lib/extensions/utils/labels.rb
|
107
|
+
- lib/extensions/utils/req_macro_walker.rb
|
108
|
+
- lib/extensions/utils/xref_helper.rb
|
100
109
|
- lib/jekyll_aspec.rb
|
101
110
|
- lib/jekyll_aspec/version.rb
|
102
111
|
homepage: https://github.com/bsmith-n4/jekyll_aspec
|
@@ -111,12 +120,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
120
|
requirements:
|
112
121
|
- - ">="
|
113
122
|
- !ruby/object:Gem::Version
|
114
|
-
version: '0'
|
123
|
+
version: '2.0'
|
115
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
125
|
requirements:
|
117
|
-
- - "
|
126
|
+
- - ">="
|
118
127
|
- !ruby/object:Gem::Version
|
119
|
-
version:
|
128
|
+
version: '0'
|
120
129
|
requirements: []
|
121
130
|
rubyforge_project:
|
122
131
|
rubygems_version: 2.6.12
|
data/README.md
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# Jekyll Aspec
|
2
|
-
|
3
|
-
[](https://travis-ci.org/bsmith-n4/jekyll_aspec)
|
4
|
-
|
5
|
-
A selection of Asciidoctor extensions designed to used with Jekyll.
|
6
|
-
|
7
|
-
These extensions add custom blocks for Requirements, Definitions and inter-document auto-linking functionality for these blocks.
|
8
|
-
|
9
|
-
## Installation
|
10
|
-
|
11
|
-
Add `jekyll_aspec` to your Jekyll Gemfile:
|
12
|
-
|
13
|
-
```ruby
|
14
|
-
group :jekyll_plugins do
|
15
|
-
gem 'jekyll-asciidoc'
|
16
|
-
gem 'jekyll_aspec'
|
17
|
-
end
|
18
|
-
```
|
19
|
-
|
20
|
-
Or install it yourself as:
|
21
|
-
|
22
|
-
$ gem install jekyll_aspec
|
23
|
-
|
24
|
-
## Contributing
|
25
|
-
|
26
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/bsmith-n4/jekyll_aspec.
|
27
|
-
|
28
|
-
## License
|
29
|
-
|
30
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -1,115 +0,0 @@
|
|
1
|
-
require 'asciidoctor'
|
2
|
-
require 'asciidoctor/extensions'
|
3
|
-
|
4
|
-
exts = "(\.adoc|\.md|\.html)"
|
5
|
-
docsdir = '_docs'
|
6
|
-
|
7
|
-
title = nil
|
8
|
-
chapter = nil
|
9
|
-
doctitle = nil
|
10
|
-
|
11
|
-
reqs = []
|
12
|
-
rows = []
|
13
|
-
# For commented requirements
|
14
|
-
coms = []
|
15
|
-
|
16
|
-
# For includes
|
17
|
-
inc_reqs = []
|
18
|
-
incs = []
|
19
|
-
|
20
|
-
CommentBlockRx = %r(^\/{4,}$)
|
21
|
-
CommentLineRx = %r{^//(?=[^/]|$)}
|
22
|
-
|
23
|
-
def trim(s)
|
24
|
-
s.gsub!(/_docs\//, '')
|
25
|
-
s.gsub!(/(\.adoc|\.md|\.html)/, '')
|
26
|
-
end
|
27
|
-
|
28
|
-
adoc_files = Dir.glob('**/*.adoc')
|
29
|
-
adoc_files.each do |f|
|
30
|
-
inc = false
|
31
|
-
commented = false
|
32
|
-
|
33
|
-
File.read(f).each_line do |li|
|
34
|
-
incommentblock ^= true if li[CommentBlockRx]
|
35
|
-
commented = true if li[CommentLineRx]
|
36
|
-
inc = true if li[/published: false/]
|
37
|
-
|
38
|
-
doctitle = /(?<=title:\s).+/.match(li) if li[/^title:\s+\w.+/]
|
39
|
-
chapter = /(?<=chapter:\s).+/.match(li) if li[/^chapter:\s+\w.+/]
|
40
|
-
|
41
|
-
if li[/\[\s*req\s*,\s*id\s*=\s*\w+-?[0-9]+\s*,.*/]
|
42
|
-
title.sub!(/^\./, '')
|
43
|
-
req = [li.chop, f, title, chapter, doctitle]
|
44
|
-
|
45
|
-
if commented || incommentblock
|
46
|
-
coms.push(req)
|
47
|
-
elsif inc
|
48
|
-
inc_reqs.push(req)
|
49
|
-
else
|
50
|
-
reqs.push(req)
|
51
|
-
end
|
52
|
-
|
53
|
-
# Collect all includes
|
54
|
-
elsif li[/^include::.+.adoc\[\]/]
|
55
|
-
|
56
|
-
inc_file = li.chop.match(/(?<=^include::).+.adoc(?=\[\])/i).to_s
|
57
|
-
path = inc_file.sub(/^#{docsdir}\//, '')
|
58
|
-
path = path.sub(/#{exts}/, '')
|
59
|
-
parent = f
|
60
|
-
item = [inc_file, path, parent]
|
61
|
-
incs.push item
|
62
|
-
|
63
|
-
end
|
64
|
-
title = li
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Sort included reqs and correct the path to the parent (including doc)
|
69
|
-
# Push this back into 'normal' requirements array for regular processing
|
70
|
-
inc_reqs.each do |l, f, title, chapter, doctitle|
|
71
|
-
incs.each do |incfile, _incpath, parent|
|
72
|
-
if f == incfile
|
73
|
-
item = [l, parent, title, chapter, doctitle]
|
74
|
-
reqs.push item
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
reqs.uniq!
|
80
|
-
|
81
|
-
i = 0
|
82
|
-
reqs.each do |req, f, title, chapter, doctitle|
|
83
|
-
i += 1
|
84
|
-
|
85
|
-
id = /[^,]*\s*id\s*=\s*(\w+-?[0-9]+)\s*,.*/.match(req)[1]
|
86
|
-
version = /(?<=version=)\d+/.match(req)
|
87
|
-
|
88
|
-
f.gsub!(/^_docs\//, '')
|
89
|
-
f.gsub!(/.adoc$/, '')
|
90
|
-
|
91
|
-
link = "#{f}/index##{id}"
|
92
|
-
ref = "<a class=\"link\" href=\"#{link}\"><emphasis role=\"strong\">#{title}</emphasis> </a>"
|
93
|
-
breadcrumb = "<a href=\"#{f}\">#{chapter} / #{doctitle}</a>"
|
94
|
-
row = "<tr> <th scope=\"row\">#{i}</th> <td>#{id}</td><td>#{version}</td> <td>#{ref}</td> <td>#{breadcrumb}</td> </tr>"
|
95
|
-
|
96
|
-
rows.push(row)
|
97
|
-
end
|
98
|
-
|
99
|
-
Asciidoctor::Extensions.register do
|
100
|
-
block_macro :requirements do
|
101
|
-
process do |parent, _target, _attrs|
|
102
|
-
content = %(<h2 id="requirements"><a class="anchor" href="#requirements"></a><a class="link" href="#requirements">Requirements</a></h2>
|
103
|
-
<div class="panel panel-default"> <div class="panel-heading"><h4>Requirements</h4></div>
|
104
|
-
<table class="table"> <thead> <tr>
|
105
|
-
<th>#</th> <th>ID</th><th>Version</th> <th>Title</th> <th>Document</th>
|
106
|
-
</tr> </thead>
|
107
|
-
<tbody>
|
108
|
-
#{rows.join}
|
109
|
-
</tbody>
|
110
|
-
</table> </div>)
|
111
|
-
|
112
|
-
create_pass_block parent, content, {}
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|