jekyll_aspec 1.0.0.pre.alpha → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://travis-ci.org/bsmith-n4/jekyll_aspec.svg?branch=master)](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
|