metanorma-standoc 1.1.3 → 1.1.4

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
  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