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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c77631b5967f60ae7f3f0ab335f0445b4c09e174
4
- data.tar.gz: 8eba5d605e5d4d1d2425cccb6495114f81669497
3
+ metadata.gz: a7660532ed66dd03c81835079b3f1f2c57a495a7
4
+ data.tar.gz: 9fd9c8f89aad34a1498ea52cd3f04b021db3a564
5
5
  SHA512:
6
- metadata.gz: cfc99e19a9cb848003dc84d99e2f5c5cc61f2702bcfdfd915f89db0bc0375e1737abe9bb9a04c6ecb1d711400ca93d4200c7779e2d5146e20e5fdf7027046ce0
7
- data.tar.gz: 48268e49f8269b28e5a449e17aa09f009145488a979cc5be4782ba565cfd290ecb020d48b3add72a25c32499a943293f2da8f40308128bc11f9d0e14d2740319
6
+ metadata.gz: a13f2ee35c2a0082ecb6c11d4ddce5c76c6145ccc16113912fcad43bb4ca751d7560d4ed03b8465489be8a22f21d7533d384ecc3bdcc6cea59847e26bf248ef0
7
+ data.tar.gz: 141f495acb546d4ef8a8e0037b6e9d099fc4803d11455af2149e0ab3ec59b8fae1a9d9b1e14a68c42b57563602f1c3cf122693aafe05b83b74e2a0ec6ae454e0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jekyll_aspec (1.0.0.pre.alpha)
4
+ jekyll_aspec (1.0.0)
5
5
  asciidoctor (>= 1.5.0)
6
6
 
7
7
  GEM
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
@@ -1,8 +1,8 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
2
  require 'test/unit'
3
3
 
4
4
  task :default => :test
5
5
 
6
6
  task :test do
7
- ruby "test/suite.rb"
7
+ ruby 'test/suite.rb'
8
8
  end
@@ -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
@@ -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
- # Find all Adoc Files
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
- # Block is loaded once per document!!!
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,7 @@ require 'asciidoctor/extensions'
2
2
 
3
3
  include ::Asciidoctor
4
4
 
5
+ # Strip bogus tags generated by Asciidoctor
5
6
  Extensions.register do
6
7
  postprocessor do
7
8
  process do |document, output|
@@ -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
- (parent.document.attr 'cwiki-pattern') ||
14
- 'https://confluence.numberfour.eu/display/%s'
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.form(attrs, target, url, label)
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
- # Examples:
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
- (parent.document.attr 'task-pattern') ||
14
- 'https://jira.numberfour.eu/browse/%s'
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
- # Some utility functions used by similar inline macros
22
+
17
23
  label = Labels.getstatus(attrs)
18
- html = Context.form(attrs, target, url, label)
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
@@ -1,8 +1,9 @@
1
1
  require 'asciidoctor/extensions'
2
2
 
3
3
  include ::Asciidoctor
4
+
4
5
  # Preprocessor that strips the << tags
5
- # FIXME: may break conversion if line ends with >>
6
+ # @todo may break conversion if line ends with >>
6
7
 
7
8
  req = '<<req-'
8
9
  brackets = /<<|>>/
@@ -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(^\/{4,}$)
25
+ blockrx = %r{^\/{4,}$}
18
26
  linerx = %r{^//(?=[^/]|$)}
19
27
 
20
- orphan = false
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
- Extensions.register do
6
- block do
7
- named :req
8
- on_contexts :open, :paragraph, :example, :listing, :sidebar, :pass
9
- name_positional_attributes "number", "version"
10
-
11
- process do |parent, reader, attrs|
12
- # Add pass characters here to prevent html character replacements for < > tags
13
- pass = "+++"
14
- attrs["name"] = "requirement"
15
- attrs["caption"] = "Requirement: "
16
- id = attrs["id"]
17
- nl = ""
18
-
19
- begin
20
- # downcase the title and replace spaces with underscores.
21
- # Also replacing special HTML entities:
22
- # &quot; = "
23
- # &amp; = &
24
- downcased_title = attrs["title"].downcase.tr(" ", "_").gsub('"', "&quot;")
25
- san_title = attrs["title"].gsub(/&/, "&amp;")
26
- rescue Exception => msg
27
- puts msg
28
- # If no title exists on the Req block, throw an exception
29
- puts "[ERROR] Requirement block title missing"
30
- end
31
-
32
- alt = %(
33
- <div class=\"panel panel-primary\">
34
- <div class=\"panel-heading\">
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('"', "&quot;")
30
+ san_title = attrs["title"].gsub(/&/, "&amp;")
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
- def self.form(attributes, target, url, label)
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
@@ -1,3 +1,6 @@
1
+ # Use this to set global versioning for the RubyGem
1
2
  module JekyllAspec
2
- VERSION = "1.0.0-alpha"
3
+ # After updating the version, publishing can be done by running
4
+ # rake release in the project root
5
+ VERSION = "1.0.0"
3
6
  end
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/requirement_appendix"
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.pre.alpha
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-25 00:00:00.000000000 Z
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.md
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: 1.3.1
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