metanorma-standoc 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5a2ad92a10730612ba26466f6508a0359c4a12ecd7f973618f0b01d80a83b83
4
- data.tar.gz: 395911c6e85240c42682d2a14e310162dd19fbe4a863478d0c90067e32aa6650
3
+ metadata.gz: c28586f6cbbdce97320f86d86391330303b318424fd94cdedd0a17d239633bd5
4
+ data.tar.gz: afcc7583ee3eaf02efa769fb9ff9820a752f48d65b99643d36f83c2c55989233
5
5
  SHA512:
6
- metadata.gz: 17a60dd786a93b4982d2c9408b3308af6b9b31bb852aae30143da11a62c8a35715a77cdbba3bc899445987e646a4a7550ab6942662522c744fb38e76661f9d0e
7
- data.tar.gz: 121aa21c43db0262c907b54b0e03f033a319f54756a7dbaca9d0da94fbd3fe85700d576327ab3d581329c4d6a606a2d76f0fefd6ad949db3fc10bad6116f2b05
6
+ metadata.gz: f35a328f0c079cdc665db0ea7c2b8dff76d83ad95db2964cde1a5e6c7d28527ab053a2f0396318edee9f56ef4c4af38c0435b858adb722b594024c6ea5826798
7
+ data.tar.gz: 51ae02a66b26288cfd206edac4d123cf1e2052a2e5fef3a966b506804b48ed21a8499eac4fe02be68753c7b160d15f4a6340b53de91738c578ea9a208bf3440b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- metanorma-standoc (1.1.3)
4
+ metanorma-standoc (1.1.4)
5
5
  asciidoctor (~> 1.5.7)
6
6
  concurrent-ruby
7
7
  html2doc (~> 0.8.0)
@@ -10,6 +10,7 @@ PATH
10
10
  relaton (~> 0.3.1)
11
11
  ruby-jing
12
12
  sterile (~> 1.0.14)
13
+ unicode2latex (~> 0.0.1)
13
14
 
14
15
  GEM
15
16
  remote: https://rubygems.org/
@@ -22,7 +23,7 @@ GEM
22
23
  asciidoctor (1.5.8)
23
24
  asciimath (1.0.8)
24
25
  ast (2.4.0)
25
- byebug (10.0.2)
26
+ byebug (11.0.0)
26
27
  cnccs (0.1.3)
27
28
  coderay (1.1.2)
28
29
  concurrent-ruby (1.1.4)
@@ -81,7 +82,7 @@ GEM
81
82
  algoliasearch
82
83
  iecbib (~> 0.2.1)
83
84
  iso-bib-item (~> 0.4.2)
84
- isodoc (0.9.17)
85
+ isodoc (0.9.18)
85
86
  asciimath
86
87
  html2doc (~> 0.8.6)
87
88
  htmlentities (~> 4.3.4)
@@ -95,15 +96,16 @@ GEM
95
96
  thread_safe
96
97
  uuidtools
97
98
  isoics (0.1.7)
98
- json (2.1.0)
99
+ json (2.2.0)
99
100
  liquid (4.0.1)
100
101
  listen (3.1.5)
101
102
  rb-fsevent (~> 0.9, >= 0.9.4)
102
103
  rb-inotify (~> 0.9, >= 0.9.7)
103
104
  ruby_dep (~> 1.2)
104
105
  lumberjack (1.0.13)
105
- metanorma (0.3.7)
106
+ metanorma (0.3.9)
106
107
  asciidoctor
108
+ htmlentities
107
109
  method_source (0.9.2)
108
110
  mime-types (3.2.2)
109
111
  mime-types-data (~> 3.2015)
@@ -116,7 +118,7 @@ GEM
116
118
  nenv (~> 0.1)
117
119
  shellany (~> 0.0)
118
120
  optout (0.0.2)
119
- parallel (1.13.0)
121
+ parallel (1.14.0)
120
122
  parser (2.6.0.0)
121
123
  ast (~> 2.4.0)
122
124
  powerpack (0.1.2)
@@ -163,7 +165,7 @@ GEM
163
165
  ruby-xslt (0.9.10)
164
166
  ruby_deep_clone (0.8.0)
165
167
  ruby_dep (1.5.0)
166
- safe_yaml (1.0.4)
168
+ safe_yaml (1.0.5)
167
169
  sass (3.7.3)
168
170
  sass-listen (~> 4.0.0)
169
171
  sass-listen (4.0.0)
@@ -183,7 +185,8 @@ GEM
183
185
  thor (0.20.3)
184
186
  thread_safe (0.3.6)
185
187
  timecop (0.9.1)
186
- unicode-display_width (1.4.1)
188
+ unicode-display_width (1.5.0)
189
+ unicode2latex (0.0.1)
187
190
  uuidtools (2.1.5)
188
191
  vcr (4.0.0)
189
192
  webmock (3.5.1)
data/README.adoc CHANGED
@@ -449,6 +449,158 @@ This generates the following ISO XML:
449
449
  </clause>
450
450
  --
451
451
 
452
+ === Requirements, Recommendations, and Permissions
453
+
454
+ Requirements, Recommendations, and Permissions are encoded as Asciidoctor examples,
455
+ with the style attribute value indicating that it is a Requirement, Recommendation, or Permission:
456
+
457
+ [source,asciidoctor]
458
+ --
459
+ [permission]
460
+ ====
461
+ I recommend this
462
+ ====
463
+ --
464
+
465
+ (In the following, "requirement" shall be used as the cover-all term.)
466
+
467
+ The named attributes `subject` and `label` may be used to indicate the subject of the
468
+ requirement, and the conventional label assigned to the requirement. The named attribute
469
+ `classification` may be used to give an arbitrary number of key-value pairs of tags describing
470
+ the requirement; key-value pairs are delimited by semicolon, key and value are delimited by
471
+ colon, multiple values are delimited by comma,
472
+ and key and value are both intended to be tokens (containing no punctuation). The `obligation`
473
+ attribute can contain one or more of "requirement", "permission", "recommendation", comma-delimited:
474
+ it can be used to override the obligation in the tag name. The `inherit`
475
+ attribute may be used to reference the label of a requirement that is imported or
476
+ presupposed by this requirement:
477
+
478
+ [source,asciidoctor]
479
+ --
480
+ [recommendation,label="/ogc/recommendation/wfs/2",subject="user",inherit="/ss/584/2015/level/1",classification="control-class:Technical;priority:P0;family:System and Communications Protection,System and Communications Protocols",obligation="permission,recommendation"]
481
+ ====
482
+ I recommend this
483
+ ====
484
+ --
485
+
486
+ Requirements can be nested, as is the case with any delimited block in Asciidoctor,
487
+ by adding one more delimiter symbol than its containing block:
488
+
489
+ [source,asciidoctor]
490
+ --
491
+ [permission]
492
+ ====
493
+ I permit this
494
+ =====
495
+ Example 2
496
+ =====
497
+ [permission]
498
+ =====
499
+ I also permit this
500
+ =====
501
+ ====
502
+ --
503
+
504
+ The internal structure of a requirement can also be marked up to make it machine-readable,
505
+ although this is not expected to be reflected in rendering.
506
+
507
+ Any text not wrapped in a named open block is considered to be part of a description.
508
+ Any text in a named open block allowed under Metanorma is considered to be a separate
509
+ subpart of the requirement: that includes the measurement target (for quantitative requirements),
510
+ the verification steps, imports (code stubs), and specifications (which may be considered
511
+ the object of the requirement). These blocks can have types, referring to the conventions
512
+ or computer frameworks that they follow.
513
+
514
+ Text in a named open block may be include or consist of machine readable code; any such
515
+ code needs to be wrapped in turn in a source code element, which is expected to
516
+ contain an attribute giving the computer language the block is expressed in.
517
+ (The notion of "language" may be expanded to include a particular computer framework
518
+ that the code is to be run under.)
519
+ `[sourcecode,text]` is taken as meaning that the block is still human readable.
520
+ The language of a source code block is likely to be distinct from the type of named block
521
+ it is contained in.
522
+
523
+ By default, both named blocks and descriptions will be included in the document output.
524
+ Often, though not always, the named blocks contain machine-readable code which is not
525
+ intended to be included in the document output, but is supplemental to the human-readable
526
+ description. That is signalled through the options attribute `exclude` on the named block.
527
+
528
+ The label attribute is always rendered if present. The subject attribute is never rendered.
529
+
530
+ [source,asciidoctor]
531
+ --
532
+ [recommendation,label="/ogc/recommendation/wfs/2",subject="user"]
533
+ ====
534
+ I recommend _this_.
535
+ [specification,type="tabular"]
536
+ ---
537
+ This is the object of the recommendation:
538
+ |===
539
+ |Object |Value
540
+ |Mission | Accomplished
541
+ |===
542
+ ---
543
+ As for the measurement targets,
544
+ [measurement-target]
545
+ ---
546
+ The measurement target shall be measured as:
547
+ [stem]
548
+ ++++
549
+ r/1 = 0
550
+ ++++
551
+ ---
552
+ [verification,type="comprehensive"]
553
+ ---
554
+ The following code will be run for verification:
555
+ [source,CoreRoot]
556
+ ----
557
+ CoreRoot(success): HttpResponse
558
+ if (success)
559
+ recommendation(label: success-response)
560
+ end
561
+ ----
562
+ ---
563
+
564
+ [import%exclude]
565
+ ---
566
+ [source,CoreRoot]
567
+ ----
568
+ success-response()
569
+ ----
570
+ ---
571
+ ====
572
+ --
573
+
574
+ === STEM expressions
575
+
576
+ Like Asciidoctor proper, Metanorma Asciidoctor accepts mathematical input
577
+ in either LaTeX or AsciiMath, following the conventions of Asciidoctor:
578
+
579
+ * The document attribute `:stem:` means any markup tagged as `[stem]`
580
+ (`stem:[...]`, or `[stem]` before a block delimited with `++++`)
581
+ is interpreted as AsciiMath.
582
+ * The document attribute `:stem: latexmath` means any markup tagged as `[stem]`
583
+ (`stem:[...]`, or `[stem]` before a block delimited with `++++`)
584
+ is interpreted as LaTeX.
585
+ * Any markup tagged as `[asciimath]`
586
+ (`asciimath:[...]`, or `[asciimath]` before a block delimited with `++++`)
587
+ is interpreted as AsciiMath.
588
+ * Any markup tagged as `[latexmath]`
589
+ (`latexmath:[...]`, or `[latexmath]` before a block delimited with `++++`)
590
+ is interpreted as LaTeX.
591
+
592
+ In addition, stem markup that contains MathML markup (as detected by an initial
593
+ `<math ... >`) is interpreted as MathML.
594
+
595
+ MathML is used as the internal representation of STEM expressions in Metanorma:
596
+ AsciiMath and LaTeX in Metanorma Asciidoctor are converted into MathML,
597
+ using the https://github.com/asciidoctor/asciimath[asciimath] gem and the
598
+ https://dlmf.nist.gov/LaTeXML/manual/commands/latexmlmath.html[latexmath]
599
+ processor of LaTeXML, respectively.
600
+
601
+ NOTE: latexmath is much slower than other available LaTeX to MathML converters,
602
+ but is also more accurate.
603
+
452
604
  === PlantUML
453
605
 
454
606
  The http://plantuml.com[PlantUML] diagramming tool is integrated with Asciidoctor
@@ -17,6 +17,8 @@ module Asciidoctor
17
17
  inline_macro Asciidoctor::Standoc::AltTermInlineMacro
18
18
  inline_macro Asciidoctor::Standoc::DeprecatedTermInlineMacro
19
19
  inline_macro Asciidoctor::Standoc::DomainTermInlineMacro
20
+ block Asciidoctor::Standoc::ToDoAdmonitionBlock
21
+ treeprocessor Asciidoctor::Standoc::ToDoInlineAdmonitionBlock
20
22
  block Asciidoctor::Standoc::PlantUMLBlockMacro
21
23
  end
22
24
 
@@ -18,6 +18,21 @@
18
18
  of this.
19
19
  -->
20
20
  <grammar xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
21
+ <!--
22
+ https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/
23
+ iso8601date = xsd:string { pattern = "([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?" }
24
+ Somewhat dumbed down for XSD regex:
25
+ -->
26
+ <define name="ISO8601DateTime">
27
+ <data type="string">
28
+ <param name="pattern">([\+\-]?\d{4})((-?)((0[1-9]|1[0-2])((-?)([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+)?)?((:?)[0-5]\d([.,]\d+)?)?([zZ]|([\+\-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?</param>
29
+ </data>
30
+ </define>
31
+ <define name="ISO8601Date">
32
+ <data type="string">
33
+ <param name="pattern">([\+\-]?\d{4})((-?)((0[1-9]|1[0-2])((-?)([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6]))))?</param>
34
+ </data>
35
+ </define>
21
36
  <define name="status">
22
37
  <element name="status">
23
38
  <ref name="LocalizedString"/>
@@ -375,10 +390,7 @@
375
390
  </define>
376
391
  <define name="date">
377
392
  <element name="date">
378
- <choice>
379
- <data type="gYear"/>
380
- <data type="date"/>
381
- </choice>
393
+ <ref name="ISO8601Date"/>
382
394
  </element>
383
395
  </define>
384
396
  <define name="locality">
@@ -561,10 +573,7 @@
561
573
  </define>
562
574
  <define name="fetched">
563
575
  <element name="fetched">
564
- <choice>
565
- <data type="dateTime"/>
566
- <data type="date"/>
567
- </choice>
576
+ <ref name="ISO8601DateTime"/>
568
577
  </element>
569
578
  </define>
570
579
  <define name="validity">
@@ -582,26 +591,17 @@
582
591
  </define>
583
592
  <define name="validityBegins">
584
593
  <element name="validityBegins">
585
- <choice>
586
- <data type="dateTime"/>
587
- <data type="date"/>
588
- </choice>
594
+ <ref name="ISO8601DateTime"/>
589
595
  </element>
590
596
  </define>
591
597
  <define name="validityEnds">
592
598
  <element name="validityEnds">
593
- <choice>
594
- <data type="dateTime"/>
595
- <data type="date"/>
596
- </choice>
599
+ <ref name="ISO8601DateTime"/>
597
600
  </element>
598
601
  </define>
599
602
  <define name="validityRevision">
600
603
  <element name="revision">
601
- <choice>
602
- <data type="dateTime"/>
603
- <data type="date"/>
604
- </choice>
604
+ <ref name="ISO8601DateTime"/>
605
605
  </element>
606
606
  </define>
607
607
  <define name="TypedTitleString">
@@ -632,10 +632,7 @@
632
632
  <attribute name="text"/>
633
633
  </optional>
634
634
  <optional>
635
- <choice>
636
- <data type="gYear"/>
637
- <data type="date"/>
638
- </choice>
635
+ <ref name="ISO8601Date"/>
639
636
  </optional>
640
637
  </define>
641
638
  <define name="bdate">
@@ -660,25 +657,16 @@
660
657
  <choice>
661
658
  <group>
662
659
  <element name="from">
663
- <choice>
664
- <data type="gYear"/>
665
- <data type="date"/>
666
- </choice>
660
+ <ref name="ISO8601Date"/>
667
661
  </element>
668
662
  <optional>
669
663
  <element name="to">
670
- <choice>
671
- <data type="gYear"/>
672
- <data type="date"/>
673
- </choice>
664
+ <ref name="ISO8601Date"/>
674
665
  </element>
675
666
  </optional>
676
667
  </group>
677
668
  <element name="on">
678
- <choice>
679
- <data type="gYear"/>
680
- <data type="date"/>
681
- </choice>
669
+ <ref name="ISO8601Date"/>
682
670
  </element>
683
671
  </choice>
684
672
  </element>
@@ -791,20 +779,12 @@
791
779
  </define>
792
780
  <define name="seriesfrom">
793
781
  <element name="from">
794
- <choice>
795
- <data type="dateTime"/>
796
- <data type="date"/>
797
- <data type="gYear"/>
798
- </choice>
782
+ <ref name="ISO8601Date"/>
799
783
  </element>
800
784
  </define>
801
785
  <define name="seriesto">
802
786
  <element name="to">
803
- <choice>
804
- <data type="dateTime"/>
805
- <data type="date"/>
806
- <data type="gYear"/>
807
- </choice>
787
+ <ref name="ISO8601Date"/>
808
788
  </element>
809
789
  </define>
810
790
  <define name="seriesnumber">
@@ -899,7 +879,7 @@
899
879
  </define>
900
880
  <define name="revision-date">
901
881
  <element name="revision-date">
902
- <data type="date"/>
882
+ <ref name="ISO8601Date"/>
903
883
  </element>
904
884
  </define>
905
885
  <define name="draft">
@@ -922,10 +902,12 @@
922
902
  <define name="AnyElement">
923
903
  <element>
924
904
  <anyName/>
925
- <choice>
926
- <text/>
927
- <ref name="AnyElement"/>
928
- </choice>
905
+ <oneOrMore>
906
+ <choice>
907
+ <text/>
908
+ <ref name="AnyElement"/>
909
+ </choice>
910
+ </oneOrMore>
929
911
  </element>
930
912
  </define>
931
913
  </grammar>
@@ -14,6 +14,8 @@ module Asciidoctor
14
14
  # treated as a single block.
15
15
  # We append each contained block to its parent
16
16
  def open(node)
17
+ Utils::reqt_subpart(node.attr("style")) and
18
+ return requirement_subpart(node)
17
19
  result = []
18
20
  node.blocks.each do |b|
19
21
  result << send(b.context, b)
@@ -21,6 +23,16 @@ module Asciidoctor
21
23
  result
22
24
  end
23
25
 
26
+ def requirement_subpart(node)
27
+ name = node.attr("style")
28
+ noko do |xml|
29
+ xml.send name, **attr_code(exclude: node.option?("exclude"),
30
+ type: node.attr("type")) do |o|
31
+ o << node.content
32
+ end
33
+ end.join("\n")
34
+ end
35
+
24
36
  def literal(node)
25
37
  noko do |xml|
26
38
  xml.figure **id_attr(node) do |f|
@@ -35,7 +47,7 @@ module Asciidoctor
35
47
  stem_content = node.lines.join("\n")
36
48
  noko do |xml|
37
49
  xml.formula **id_attr(node) do |s|
38
- stem_parse(stem_content, s)
50
+ stem_parse(stem_content, s, node.style.to_sym)
39
51
  end
40
52
  end
41
53
  end
@@ -61,6 +73,24 @@ module Asciidoctor
61
73
  end
62
74
  end
63
75
 
76
+ def todo_attrs(node)
77
+ date = node.attr("date") || Date.today.iso8601.gsub(/\+.*$/, "")
78
+ date += "T00:00:00Z" unless /T/.match date
79
+ {
80
+ reviewer: node.attr("reviewer") || node.attr("source") || "(Unknown)",
81
+ id: Utils::anchor_or_uuid(node),
82
+ date: date,
83
+ }
84
+ end
85
+
86
+ def todo(node)
87
+ noko do |xml|
88
+ xml.review **attr_code(todo_attrs(node)) do |r|
89
+ wrap_in_para(node, r)
90
+ end
91
+ end
92
+ end
93
+
64
94
  def termnote(n)
65
95
  noko do |xml|
66
96
  xml.termnote **id_attr(n) do |ex|
@@ -95,6 +125,7 @@ module Asciidoctor
95
125
  def admonition(node)
96
126
  return termnote(node) if in_terms?
97
127
  return note(node) if node.attr("name") == "note"
128
+ return todo(node) if node.attr("name") == "todo"
98
129
  noko do |xml|
99
130
  xml.admonition **admonition_attrs(node) do |a|
100
131
  node.title.nil? or a.name { |name| name << node.title }
@@ -113,6 +144,9 @@ module Asciidoctor
113
144
 
114
145
  def example(node)
115
146
  return term_example(node) if in_terms?
147
+ return requirement(node, "recommendation") if node.attr("style") == "recommendation"
148
+ return requirement(node, "requirement") if node.attr("style") == "requirement"
149
+ return requirement(node, "permission") if node.attr("style") == "permission"
116
150
  noko do |xml|
117
151
  xml.example **id_attr(node) do |ex|
118
152
  wrap_in_para(node, ex)
@@ -120,6 +154,46 @@ module Asciidoctor
120
154
  end.join("\n")
121
155
  end
122
156
 
157
+ def req_classif_parse(classif)
158
+ ret = []
159
+ classif.split(/;\s*/).each do |c|
160
+ c1 = c.split(/:\s*/)
161
+ next unless c1.size == 2
162
+ c1[1].split(/,\s*/).each { |v| ret << [ c1[0], v ] }
163
+ end
164
+ ret
165
+ end
166
+
167
+ def requirement_classification(classif, ex)
168
+ req_classif_parse(classif).each do |r|
169
+ ex.classification do |c|
170
+ c.tag r[0]
171
+ c.value r[1]
172
+ end
173
+ end
174
+ end
175
+
176
+ def reqt_attributes(node)
177
+ {
178
+ id: Utils::anchor_or_uuid,
179
+ obligation: node.attr("obligation")
180
+ }
181
+ end
182
+
183
+ def requirement(node, obligation)
184
+ classif = node.attr("classification")
185
+ noko do |xml|
186
+ xml.send obligation, **attr_code(reqt_attributes(node)) do |ex|
187
+ ex.title node.title if node.title
188
+ ex.label node.attr("label") if node.attr("label")
189
+ ex.subject node.attr("subject") if node.attr("subject")
190
+ ex.inherit node.attr("inherit") if node.attr("inherit")
191
+ requirement_classification(classif, ex) if classif
192
+ wrap_in_para(node, ex)
193
+ end
194
+ end.join("\n")
195
+ end
196
+
123
197
  def preamble(node)
124
198
  noko do |xml|
125
199
  xml.foreword do |xml_abstract|
@@ -53,6 +53,7 @@ module Asciidoctor
53
53
  docidentifier_cleanup(xmldoc)
54
54
  bookmark_cleanup(xmldoc)
55
55
  smartquotes_cleanup(xmldoc)
56
+ requirement_cleanup(xmldoc)
56
57
  xmldoc
57
58
  end
58
59
 
@@ -153,7 +153,6 @@ module Asciidoctor
153
153
  end
154
154
 
155
155
  ELEMS_ALLOW_NOTES =
156
- # %w[p formula quote sourcecode example admonition ul ol dl figure]
157
156
  %w[p formula ul ol dl figure].freeze
158
157
 
159
158
  # if a note is at the end of a section, it is left alone
@@ -228,6 +227,30 @@ module Asciidoctor
228
227
  r["obligation"] = r.at("./ancestor::*/@obligation").text
229
228
  end
230
229
  end
230
+
231
+ def requirement_cleanup(x)
232
+ x.xpath("//requirement | //recommendation | //permission").each do |r|
233
+ r.children.each do |e|
234
+ unless e.element? && (Utils::reqt_subpart(e.name) ||
235
+ %w(requirement recommnedation permission).include?(e.name))
236
+ t = Nokogiri::XML::Element.new("description", x)
237
+ e.before(t)
238
+ t.children = e.remove
239
+ end
240
+ end
241
+ requirement_cleanup1(r)
242
+ end
243
+ end
244
+
245
+ def requirement_cleanup1(r)
246
+ while d = r.at("./description[following-sibling::*[1][self::description]]")
247
+ n = d.next.remove
248
+ d << n.children
249
+ end
250
+ r.xpath("./description[not(./*) and normalize-space(.)='']").each do |d|
251
+ d.replace("\n")
252
+ end
253
+ end
231
254
  end
232
255
  end
233
256
  end
@@ -1,5 +1,6 @@
1
1
  require "asciidoctor/extensions"
2
2
  require "htmlentities"
3
+ require "unicode2latex"
3
4
 
4
5
  module Asciidoctor
5
6
  module Standoc
@@ -92,13 +93,25 @@ module Asciidoctor
92
93
  noko { |xml| xml.hr }.join("\n")
93
94
  end
94
95
 
95
- def stem_parse(text, xml)
96
+ def xml_encode(text)
97
+ HTMLEntities.new.encode(text, :basic, :hexadecimal).
98
+ gsub(/&amp;gt;/, ">").gsub(/\&amp;lt;/, "<").gsub(/&amp;amp;/, "&").
99
+ gsub(/&gt;/, ">").gsub(/&lt;/, "<").gsub(/&amp;/, "&").
100
+ gsub(/&quot;/, '"').gsub(/&#xa;/, "\n")
101
+ end
102
+
103
+ def stem_parse(text, xml, style)
96
104
  if /&lt;([^:>&]+:)?math(\s+[^>&]+)?&gt; |
97
105
  <([^:>&]+:)?math(\s+[^>&]+)?>/x.match text
98
- math = HTMLEntities.new.encode(text, :basic, :hexadecimal).
99
- gsub(/&amp;gt;/, ">").gsub(/\&amp;lt;/, "<").gsub(/&amp;amp;/, "&").
100
- gsub(/&gt;/, ">").gsub(/&lt;/, "<").gsub(/&amp;/, "&")
106
+ math = xml_encode(text)
101
107
  xml.stem math, **{ type: "MathML" }
108
+ elsif style == :latexmath
109
+ out = Unicode2LaTeX::unicode2latex(text).gsub(/'/, '\\').gsub(/\n/, " ")
110
+ File.open(".tex", "w") { |file| file.write(out) }
111
+ latex = `cat .tex | latexmlmath --preload=amsmath -- -`
112
+ xml.stem **{ type: "MathML" } do |s|
113
+ s << latex.sub(/<\?[^>]+>/, "")
114
+ end
102
115
  else
103
116
  xml.stem text, **{ type: "AsciiMath" }
104
117
  end
@@ -114,7 +127,8 @@ module Asciidoctor
114
127
  when :single then xml << "'#{node.text}'"
115
128
  when :superscript then xml.sup { |s| s << node.text }
116
129
  when :subscript then xml.sub { |s| s << node.text }
117
- when :asciimath then stem_parse(node.text, xml)
130
+ when :asciimath then stem_parse(node.text, xml, :asciimath)
131
+ when :latexmath then stem_parse(node.text, xml, :latexmath)
118
132
  else
119
133
  case node.role
120
134
  # the following three are legacy, they are now handled by macros
@@ -927,7 +927,12 @@
927
927
  <value>AsciiMath</value>
928
928
  </choice>
929
929
  </attribute>
930
- <text/>
930
+ <oneOrMore>
931
+ <choice>
932
+ <text/>
933
+ <ref name="AnyElement"/>
934
+ </choice>
935
+ </oneOrMore>
931
936
  </element>
932
937
  </define>
933
938
  <define name="annotation">
@@ -40,6 +40,33 @@ module Asciidoctor
40
40
  end
41
41
  end
42
42
 
43
+ class ToDoAdmonitionBlock < Extensions::BlockProcessor
44
+ use_dsl
45
+ named :TODO
46
+ on_contexts :example, :paragraph
47
+
48
+ def process parent, reader, attrs
49
+ attrs['name'] = 'todo'
50
+ attrs['caption'] = 'TODO'
51
+ create_block parent, :admonition, reader.lines, attrs, content_model: :compound
52
+ end
53
+ end
54
+
55
+ class ToDoInlineAdmonitionBlock < Extensions::Treeprocessor
56
+ def process document
57
+ (document.find_by context: :paragraph).each do |para|
58
+ next unless /^TODO: /.match para.lines[0]
59
+ parent = para.parent
60
+ para.set_attr("name", "todo")
61
+ para.set_attr("caption", "TODO")
62
+ para.lines[0].sub!(/^TODO: /, "")
63
+ todo = Block.new parent, :admonition, attributes: para.attributes,
64
+ source: para.lines, content_model: :compound
65
+ parent.blocks[parent.blocks.index(para)] = todo
66
+ end
67
+ end
68
+ end
69
+
43
70
  class PlantUMLBlockMacroBackend
44
71
  # https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
45
72
  def self.plantuml_installed?
@@ -84,6 +84,11 @@ module Asciidoctor
84
84
  end
85
85
  result.reject(&:empty?)
86
86
  end
87
+
88
+ def reqt_subpart(x)
89
+ %w(specification measurement-target verification import label
90
+ subject inherit classification title).include? x
91
+ end
87
92
  end
88
93
 
89
94
  def convert(node, transform = nil, opts = {})
@@ -1,5 +1,5 @@
1
1
  module Metanorma
2
2
  module Standoc
3
- VERSION = "1.1.3".freeze
3
+ VERSION = "1.1.4".freeze
4
4
  end
5
5
  end
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency "sterile", "~> 1.0.14"
35
35
  spec.add_dependency "concurrent-ruby"
36
36
  spec.add_dependency "html2doc", "~> 0.8.0"
37
+ spec.add_dependency "unicode2latex", "~> 0.0.1"
37
38
 
38
39
  spec.add_development_dependency "bundler", "~> 2.0.1"
39
40
  spec.add_development_dependency "byebug"
@@ -49,6 +49,17 @@ RSpec.describe Asciidoctor::Standoc do
49
49
  ++++
50
50
  <mml:math><mml:msub xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"> <mml:mrow> <mml:mrow> <mml:mi mathvariant="bold-italic">F</mml:mi> </mml:mrow> </mml:mrow> <mml:mrow> <mml:mrow> <mml:mi mathvariant="bold-italic">&#x0391;</mml:mi> </mml:mrow> </mml:mrow> </mml:msub> </mml:math>
51
51
  ++++
52
+
53
+ [latexmath]
54
+ ++++
55
+ M =
56
+ \\begin{bmatrix}
57
+ -\\sin λ_0 & \\cos λ_0 & 0 \\\\
58
+ -\\sin φ_0 \\cos λ_0 & -\\sin φ_0 \\sin λ_0 & \\cos φ_0 \\\\
59
+ \\cos φ_0 \\cos λ_0 & \\cos φ_0 \\sin λ_0 & \\sin φ_0
60
+ \\end{bmatrix}
61
+ ++++
62
+
52
63
  INPUT
53
64
  #{BLANK_HDR}
54
65
  <sections>
@@ -59,8 +70,165 @@ RSpec.describe Asciidoctor::Standoc do
59
70
 
60
71
  <formula id="_">
61
72
  <stem type="MathML"><math xmlns="http://www.w3.org/1998/Math/MathML"><msub> <mrow> <mrow> <mi mathvariant="bold-italic">F</mi> </mrow> </mrow> <mrow> <mrow> <mi mathvariant="bold-italic">Α</mi> </mrow> </mrow> </msub> </math></stem>
62
- </stem>
63
73
  </formula>
74
+ <formula id="_">
75
+ <stem type="MathML">
76
+ <math xmlns="http://www.w3.org/1998/Math/MathML" alttext="M=\\begin{bmatrix}-\\sin\\lambda_{0}&amp;\\cos\\lambda_{0}&amp;0\\\\&#10;-\\sin\\varphi_{0}\\cos\\lambda_{0}&amp;-\\sin\\varphi_{0}\\sin\\lambda_{0}&amp;\\cos\\varphi_{0%&#10;}\\\\&#10;\\cos\\varphi_{0}\\cos\\lambda_{0}&amp;\\cos\\varphi_{0}\\sin\\lambda_{0}&amp;\\sin\\varphi_{0}%&#10;\\end{bmatrix}" display="block">
77
+ <mrow>
78
+ <mi>M</mi>
79
+ <mo>=</mo>
80
+ <mrow>
81
+ <mo>[</mo>
82
+ <mtable columnspacing="5pt" displaystyle="true" rowspacing="0pt">
83
+ <mtr>
84
+ <mtd columnalign="center">
85
+ <mrow>
86
+ <mo>-</mo>
87
+ <mrow>
88
+ <mi>sin</mi>
89
+ <mo>⁡</mo>
90
+ <msub>
91
+ <mi>λ</mi>
92
+ <mn>0</mn>
93
+ </msub>
94
+ </mrow>
95
+ </mrow>
96
+ </mtd>
97
+ <mtd columnalign="center">
98
+ <mrow>
99
+ <mi>cos</mi>
100
+ <mo>⁡</mo>
101
+ <msub>
102
+ <mi>λ</mi>
103
+ <mn>0</mn>
104
+ </msub>
105
+ </mrow>
106
+ </mtd>
107
+ <mtd columnalign="center">
108
+ <mn>0</mn>
109
+ </mtd>
110
+ </mtr>
111
+ <mtr>
112
+ <mtd columnalign="center">
113
+ <mrow>
114
+ <mo>-</mo>
115
+ <mrow>
116
+ <mrow>
117
+ <mi>sin</mi>
118
+ <mo>⁡</mo>
119
+ <msub>
120
+ <mi>φ</mi>
121
+ <mn>0</mn>
122
+ </msub>
123
+ </mrow>
124
+ <mo>⁢</mo>
125
+ <mrow>
126
+ <mi>cos</mi>
127
+ <mo>⁡</mo>
128
+ <msub>
129
+ <mi>λ</mi>
130
+ <mn>0</mn>
131
+ </msub>
132
+ </mrow>
133
+ </mrow>
134
+ </mrow>
135
+ </mtd>
136
+ <mtd columnalign="center">
137
+ <mrow>
138
+ <mo>-</mo>
139
+ <mrow>
140
+ <mrow>
141
+ <mi>sin</mi>
142
+ <mo>⁡</mo>
143
+ <msub>
144
+ <mi>φ</mi>
145
+ <mn>0</mn>
146
+ </msub>
147
+ </mrow>
148
+ <mo>⁢</mo>
149
+ <mrow>
150
+ <mi>sin</mi>
151
+ <mo>⁡</mo>
152
+ <msub>
153
+ <mi>λ</mi>
154
+ <mn>0</mn>
155
+ </msub>
156
+ </mrow>
157
+ </mrow>
158
+ </mrow>
159
+ </mtd>
160
+ <mtd columnalign="center">
161
+ <mrow>
162
+ <mi>cos</mi>
163
+ <mo>⁡</mo>
164
+ <msub>
165
+ <mi>φ</mi>
166
+ <mn>0</mn>
167
+ </msub>
168
+ </mrow>
169
+ </mtd>
170
+ </mtr>
171
+ <mtr>
172
+ <mtd columnalign="center">
173
+ <mrow>
174
+ <mrow>
175
+ <mi>cos</mi>
176
+ <mo>⁡</mo>
177
+ <msub>
178
+ <mi>φ</mi>
179
+ <mn>0</mn>
180
+ </msub>
181
+ </mrow>
182
+ <mo>⁢</mo>
183
+ <mrow>
184
+ <mi>cos</mi>
185
+ <mo>⁡</mo>
186
+ <msub>
187
+ <mi>λ</mi>
188
+ <mn>0</mn>
189
+ </msub>
190
+ </mrow>
191
+ </mrow>
192
+ </mtd>
193
+ <mtd columnalign="center">
194
+ <mrow>
195
+ <mrow>
196
+ <mi>cos</mi>
197
+ <mo>⁡</mo>
198
+ <msub>
199
+ <mi>φ</mi>
200
+ <mn>0</mn>
201
+ </msub>
202
+ </mrow>
203
+ <mo>⁢</mo>
204
+ <mrow>
205
+ <mi>sin</mi>
206
+ <mo>⁡</mo>
207
+ <msub>
208
+ <mi>λ</mi>
209
+ <mn>0</mn>
210
+ </msub>
211
+ </mrow>
212
+ </mrow>
213
+ </mtd>
214
+ <mtd columnalign="center">
215
+ <mrow>
216
+ <mi>sin</mi>
217
+ <mo>⁡</mo>
218
+ <msub>
219
+ <mi>φ</mi>
220
+ <mn>0</mn>
221
+ </msub>
222
+ </mrow>
223
+ </mtd>
224
+ </mtr>
225
+ </mtable>
226
+ <mo>]</mo>
227
+ </mrow>
228
+ </mrow>
229
+ </math></stem>
230
+ </formula>
231
+ </sections></standard-document>
64
232
  </sections>
65
233
  </standard-document>
66
234
  OUTPUT
@@ -651,5 +819,176 @@ RSpec.describe Asciidoctor::Standoc do
651
819
  OUTPUT
652
820
  end
653
821
 
822
+ it "processes recommendation" do
823
+ input = <<~"INPUT"
824
+ #{ASCIIDOC_BLANK_HDR}
825
+ [recommendation,label="/ogc/recommendation/wfs/2",subject="user",inherit="/ss/584/2015/level/1"]
826
+ ====
827
+ I recommend this
828
+ ====
829
+ INPUT
830
+ output = <<~"OUTPUT"
831
+ #{BLANK_HDR}
832
+ <sections>
833
+ <recommendation id="_">
834
+ <label>/ogc/recommendation/wfs/2</label>
835
+ <subject>user</subject>
836
+ <inherit>/ss/584/2015/level/1</inherit>
837
+ <description><p id="_">I recommend this</p></description>
838
+ </recommendation>
839
+ </sections>
840
+ </standard-document>
841
+ OUTPUT
842
+
843
+ expect(strip_guid(Asciidoctor.convert(input, backend: :standoc, header_footer: true))).to be_equivalent_to output
844
+ end
845
+
846
+ it "processes requirement" do
847
+ input = <<~"INPUT"
848
+ #{ASCIIDOC_BLANK_HDR}
849
+ [requirement]
850
+ .Title
851
+ ====
852
+ I recommend this
853
+ ====
854
+ INPUT
855
+ output = <<~"OUTPUT"
856
+ #{BLANK_HDR}
857
+ <sections>
858
+ <requirement id="_"><title>Title</title>
859
+ <description><p id="_">I recommend this</p></description>
860
+ </requirement>
861
+ </sections>
862
+ </standard-document>
863
+ OUTPUT
864
+
865
+ expect(strip_guid(Asciidoctor.convert(input, backend: :standoc, header_footer: true))).to be_equivalent_to output
866
+ end
867
+
868
+ it "processes permission" do
869
+ input = <<~"INPUT"
870
+ #{ASCIIDOC_BLANK_HDR}
871
+ [permission]
872
+ ====
873
+ I recommend this
874
+ ====
875
+ INPUT
876
+ output = <<~"OUTPUT"
877
+ #{BLANK_HDR}
878
+ <sections>
879
+ <permission id="_">
880
+ <description><p id="_">I recommend this</p></description>
881
+ </permission>
882
+ </sections>
883
+ </standard-document>
884
+ OUTPUT
885
+
886
+ expect(strip_guid(Asciidoctor.convert(input, backend: :standoc, header_footer: true))).to be_equivalent_to output
887
+ end
888
+
889
+
890
+ it "processes nested permissions" do
891
+ input = <<~"INPUT"
892
+ #{ASCIIDOC_BLANK_HDR}
893
+ [permission]
894
+ ====
895
+ I permit this
896
+
897
+ =====
898
+ Example 2
899
+ =====
900
+
901
+ [permission]
902
+ =====
903
+ I also permit this
904
+ =====
905
+ ====
906
+ INPUT
907
+ output = <<~"OUTPUT"
908
+ #{BLANK_HDR}
909
+ <sections>
910
+ <permission id="_"><description><p id="_">I permit this</p>
911
+ <example id="_">
912
+ <p id="_">Example 2</p>
913
+ </example></description>
914
+ <permission id="_">
915
+ <description><p id="_">I also permit this</p></description>
916
+ </permission></permission>
917
+ </sections>
918
+ </standard-document>
919
+ OUTPUT
920
+
921
+ expect(strip_guid(Asciidoctor.convert(input, backend: :standoc, header_footer: true))).to be_equivalent_to output
922
+ end
923
+
924
+ it "processes recommendation with internal markup of structure" do
925
+ input = <<~"INPUT"
926
+ #{ASCIIDOC_BLANK_HDR}
927
+ [recommendation,label="/ogc/recommendation/wfs/2",subject="user",classification="control-class:Technical;priority:P0;family:System and Communications Protection,System and Communications Protocols",obligation="permission,recommendation"]
928
+ ====
929
+ I recommend _this_.
930
+
931
+ [specification,type="tabular"]
932
+ --
933
+ This is the object of the recommendation:
934
+ |===
935
+ |Object |Value
936
+ |Mission | Accomplished
937
+ |===
938
+ --
939
+
940
+ As for the measurement targets,
941
+
942
+ [measurement-target]
943
+ --
944
+ The measurement target shall be measured as:
945
+ [stem]
946
+ ++++
947
+ r/1 = 0
948
+ ++++
949
+ --
950
+
951
+ [verification]
952
+ --
953
+ The following code will be run for verification:
954
+
955
+ [source,CoreRoot]
956
+ ----
957
+ CoreRoot(success): HttpResponse
958
+ if (success)
959
+ recommendation(label: success-response)
960
+ end
961
+ ----
962
+ --
963
+
964
+ [import%exclude]
965
+ --
966
+ [source,CoreRoot]
967
+ ----
968
+ success-response()
969
+ ----
970
+ --
971
+ ====
972
+ INPUT
973
+ output = <<~"OUTPUT"
974
+ #{BLANK_HDR}
975
+ <sections>
976
+ <recommendation id="_" obligation="permission,recommendation"><label>/ogc/recommendation/wfs/2</label><subject>user</subject>
977
+ <classification><tag>control-class</tag><value>Technical</value></classification><classification><tag>priority</tag><value>P0</value></classification><classification><tag>family</tag><value>System and Communications Protection</value></classification><classification><tag>family</tag><value>System and Communications Protocols</value></classification>
978
+ <description><p id="_">I recommend <em>this</em>.</p>
979
+ </description><specification exclude="false" type="tabular"><p id="_">This is the object of the recommendation:</p><table id="_"> <tbody> <tr> <td align="left">Object</td> <td align="left">Value</td> </tr> <tr> <td align="left">Mission</td> <td align="left">Accomplished</td> </tr> </tbody></table></specification><description>
980
+ <p id="_">As for the measurement targets,</p>
981
+ </description><measurement-target exclude="false"><p id="_">The measurement target shall be measured as:</p><formula id="_"> <stem type="MathML"><math xmlns="http://www.w3.org/1998/Math/MathML"><mfrac><mi>r</mi><mn>1</mn></mfrac><mo>=</mo><mn>0</mn></math></stem></formula></measurement-target>
982
+ <verification exclude="false"><p id="_">The following code will be run for verification:</p><sourcecode lang="CoreRoot" id="_">CoreRoot(success): HttpResponse
983
+ if (success)
984
+ recommendation(label: success-response)
985
+ end</sourcecode></verification>
986
+ <import exclude="true"> <sourcecode lang="CoreRoot" id="_">success-response()</sourcecode></import></recommendation>
987
+ </sections>
988
+ </standard-document>
989
+ OUTPUT
990
+
991
+ expect(strip_guid(Asciidoctor.convert(input, backend: :standoc, header_footer: true))).to be_equivalent_to output
992
+ end
654
993
 
655
994
  end
@@ -18,6 +18,33 @@ RSpec.describe Asciidoctor::Standoc do
18
18
  OUTPUT
19
19
  end
20
20
 
21
+ it "processes the TODO custom admonition" do
22
+ expect(strip_guid(Asciidoctor.convert(<<~"INPUT", backend: :standoc, header_footer: true))).to be_equivalent_to <<~"OUTPUT"
23
+ #{ASCIIDOC_BLANK_HDR}
24
+ TODO: Note1
25
+
26
+ [TODO]
27
+ ====
28
+ Note2
29
+ ====
30
+
31
+ [TODO]
32
+ Note3
33
+ INPUT
34
+ #{BLANK_HDR}
35
+ <sections><review reviewer="(Unknown)" id="_" date="#{Date.today}T00:00:00Z">
36
+ <p id="_"/>
37
+ </review>
38
+ <review reviewer="(Unknown)" id="_" date="#{Date.today}T00:00:00Z">
39
+ <p id="_">Note2</p>
40
+ </review>
41
+ <review reviewer="(Unknown)" id="_" date="#{Date.today}T00:00:00Z">
42
+ <p id="_">Note3</p>
43
+ </review></sections>
44
+ </standard-document>
45
+ OUTPUT
46
+ end
47
+
21
48
  it "processes the PlantUML macro" do
22
49
  expect(strip_guid(Asciidoctor.convert(<<~"INPUT", backend: :standoc, header_footer: true))).to be_equivalent_to <<~"OUTPUT"
23
50
  #{ASCIIDOC_BLANK_HDR}
@@ -115,7 +142,6 @@ Alice &lt;-- Bob: another authentication Response
115
142
  OUTPUT
116
143
  end
117
144
 
118
-
119
145
  private
120
146
 
121
147
  def mock_plantuml_disabled
@@ -60,7 +60,7 @@ RSpec.describe Metanorma::Standoc::Processor do
60
60
  <li> <p>IEC Electropedia: available at
61
61
  <a href="http://www.electropedia.org">http://www.electropedia.org</a>
62
62
  </p> </li> </ul>
63
- <h2 class="TermNum" id="J">1.1</h2>
63
+ <h2 class="TermNum" id="J">1.1.</h2>
64
64
  <p class="Terms" style="text-align:left;">Term2</p>
65
65
  </div>
66
66
  </main>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-standoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-24 00:00:00.000000000 Z
11
+ date: 2019-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.8.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: unicode2latex
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.0.1
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.0.1
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: bundler
127
141
  requirement: !ruby/object:Gem::Requirement