pubid 2.0.0 → 2.0.2

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.
Files changed (214) hide show
  1. checksums.yaml +4 -4
  2. data/data/parg/adobe.json +1 -1
  3. data/data/parg/aiee.json +1 -1
  4. data/data/parg/amca.json +1 -1
  5. data/data/parg/ansi.json +1 -1
  6. data/data/parg/api.json +1 -1
  7. data/data/parg/ashrae.json +1 -1
  8. data/data/parg/asme.json +1 -1
  9. data/data/parg/astm.json +1 -1
  10. data/data/parg/bipm.json +1 -1
  11. data/data/parg/bsi.json +1 -1
  12. data/data/parg/calconnect.json +1 -1
  13. data/data/parg/ccsds.json +1 -1
  14. data/data/parg/cen_cenelec.json +1 -1
  15. data/data/parg/cie.json +1 -1
  16. data/data/parg/csa.json +1 -1
  17. data/data/parg/doi.json +1 -1
  18. data/data/parg/easc.json +1 -1
  19. data/data/parg/ecma.json +1 -1
  20. data/data/parg/etsi.json +1 -1
  21. data/data/parg/evs.json +1 -1
  22. data/data/parg/gb.json +1 -1
  23. data/data/parg/gost.json +1 -1
  24. data/data/parg/iala.json +1 -1
  25. data/data/parg/iana.json +1 -1
  26. data/data/parg/idf.json +1 -1
  27. data/data/parg/iec.json +1 -1
  28. data/data/parg/ieee.json +1 -29571
  29. data/data/parg/ietf.json +1 -1
  30. data/data/parg/iho.json +1 -0
  31. data/data/parg/ire.json +1 -1
  32. data/data/parg/isbn.json +1 -1
  33. data/data/parg/iso.json +1 -8510
  34. data/data/parg/itu.json +1 -1
  35. data/data/parg/jcgm.json +1 -1
  36. data/data/parg/jis.json +1 -1
  37. data/data/parg/nesc.json +1 -1
  38. data/data/parg/nist.json +1 -9588
  39. data/data/parg/oasis.json +1 -1
  40. data/data/parg/ogc.json +1 -1
  41. data/data/parg/oiml.json +1 -1
  42. data/data/parg/omg.json +1 -1
  43. data/data/parg/parg.json +1 -1
  44. data/data/parg/plateau.json +1 -1
  45. data/data/parg/sae.json +1 -1
  46. data/data/parg/tables/typed_stages.yaml +1 -0
  47. data/data/parg/tgpp.json +1 -1
  48. data/data/parg/un.json +1 -1
  49. data/data/parg/w3c.json +1 -1
  50. data/data/parg/xsf.json +1 -1
  51. data/lib/pubid/adobe/identifier.rb +1 -1
  52. data/lib/pubid/adobe/parser.rb +2 -113
  53. data/lib/pubid/amca/identifiers/base.rb +1 -1
  54. data/lib/pubid/amca/parser.rb +1 -145
  55. data/lib/pubid/ansi/identifier.rb +1 -1
  56. data/lib/pubid/ansi/parser.rb +1 -82
  57. data/lib/pubid/api/builder.rb +32 -1
  58. data/lib/pubid/api/identifier.rb +1 -1
  59. data/lib/pubid/api/parser.rb +1 -131
  60. data/lib/pubid/ashrae/identifiers/base.rb +1 -1
  61. data/lib/pubid/ashrae/parser.rb +3 -710
  62. data/lib/pubid/asme/builder.rb +6 -4
  63. data/lib/pubid/asme/identifier.rb +1 -2
  64. data/lib/pubid/asme/parser.rb +1 -328
  65. data/lib/pubid/astm/builder.rb +12 -3
  66. data/lib/pubid/astm/identifier.rb +1 -2
  67. data/lib/pubid/astm/parser.rb +1 -227
  68. data/lib/pubid/bipm/identifier.rb +8 -1
  69. data/lib/pubid/bipm/parser.rb +2 -224
  70. data/lib/pubid/bsi/builder.rb +2 -4
  71. data/lib/pubid/bsi/parser.rb +1 -666
  72. data/lib/pubid/bsi/single_identifier.rb +38 -1
  73. data/lib/pubid/calconnect/identifier.rb +1 -1
  74. data/lib/pubid/calconnect/parser.rb +2 -40
  75. data/lib/pubid/ccsds/identifier.rb +1 -1
  76. data/lib/pubid/ccsds/parser.rb +1 -66
  77. data/lib/pubid/cen_cenelec/identifier.rb +16 -1
  78. data/lib/pubid/cen_cenelec/parser.rb +3 -136
  79. data/lib/pubid/cie/identifier.rb +1 -1
  80. data/lib/pubid/cie/parser.rb +3 -378
  81. data/lib/pubid/conformance.rb +1 -1
  82. data/lib/pubid/csa/builder.rb +41 -18
  83. data/lib/pubid/csa/identifier.rb +12 -4
  84. data/lib/pubid/csa/identifiers/amendment.rb +28 -0
  85. data/lib/pubid/csa/identifiers.rb +1 -0
  86. data/lib/pubid/csa/parser.rb +16 -397
  87. data/lib/pubid/doi/identifier.rb +1 -1
  88. data/lib/pubid/doi/parser.rb +2 -37
  89. data/lib/pubid/easc/builder.rb +1 -1
  90. data/lib/pubid/easc/identifier.rb +1 -1
  91. data/lib/pubid/easc/parser.rb +2 -70
  92. data/lib/pubid/ecma/CLAUDE.md +8 -1
  93. data/lib/pubid/ecma/identifier.rb +13 -8
  94. data/lib/pubid/ecma/parser.rb +2 -54
  95. data/lib/pubid/ecma/renderer.rb +3 -7
  96. data/lib/pubid/errors.rb +18 -13
  97. data/lib/pubid/etsi/builder.rb +8 -5
  98. data/lib/pubid/etsi/identifiers/base.rb +1 -1
  99. data/lib/pubid/etsi/parser.rb +1 -132
  100. data/lib/pubid/evs/identifier.rb +7 -0
  101. data/lib/pubid/evs/parser.rb +1 -8
  102. data/lib/pubid/evs.rb +1 -1
  103. data/lib/pubid/gb/identifier.rb +7 -1
  104. data/lib/pubid/gb/parser.rb +2 -51
  105. data/lib/pubid/gost/identifier.rb +9 -1
  106. data/lib/pubid/gost/parser.rb +4 -81
  107. data/lib/pubid/iala/parser.rb +2 -121
  108. data/lib/pubid/iana/identifier.rb +1 -1
  109. data/lib/pubid/iana/parser.rb +2 -24
  110. data/lib/pubid/identifier.rb +78 -1
  111. data/lib/pubid/idf/builder.rb +42 -0
  112. data/lib/pubid/idf/identifier.rb +1 -1
  113. data/lib/pubid/idf/parser.rb +1 -137
  114. data/lib/pubid/idf.rb +1 -2
  115. data/lib/pubid/iec/builder.rb +158 -50
  116. data/lib/pubid/iec/identifier.rb +1 -1
  117. data/lib/pubid/iec/parser.rb +3 -430
  118. data/lib/pubid/ieee/aiee/identifier.rb +2 -1
  119. data/lib/pubid/ieee/aiee.rb +0 -1
  120. data/lib/pubid/ieee/builder.rb +2 -2
  121. data/lib/pubid/ieee/identifiers/base.rb +1 -1
  122. data/lib/pubid/ieee/ire/identifier.rb +2 -1
  123. data/lib/pubid/ieee/ire.rb +0 -1
  124. data/lib/pubid/ieee/nesc.rb +0 -1
  125. data/lib/pubid/ieee/parser.rb +1 -1257
  126. data/lib/pubid/ietf/identifiers/base.rb +17 -1
  127. data/lib/pubid/ietf/parser.rb +2 -47
  128. data/lib/pubid/ietf/renderer.rb +17 -2
  129. data/lib/pubid/iho/CLAUDE.md +89 -0
  130. data/lib/pubid/iho/builder.rb +4 -1
  131. data/lib/pubid/iho/identifiers/base.rb +28 -2
  132. data/lib/pubid/iho/renderer.rb +8 -0
  133. data/lib/pubid/iho/urn_generator.rb +11 -1
  134. data/lib/pubid/iho/urn_parser.rb +21 -11
  135. data/lib/pubid/iho.rb +0 -1
  136. data/lib/pubid/isbn/identifier.rb +1 -1
  137. data/lib/pubid/isbn/parser.rb +2 -31
  138. data/lib/pubid/iso/builder.rb +1 -1
  139. data/lib/pubid/iso/identifiers/directives.rb +6 -3
  140. data/lib/pubid/iso/identifiers/guide.rb +6 -3
  141. data/lib/pubid/iso/identifiers/international_standard.rb +3 -1
  142. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
  143. data/lib/pubid/iso/normalizer.rb +1 -1
  144. data/lib/pubid/iso/parser.rb +1 -539
  145. data/lib/pubid/iso/supplement_identifier.rb +6 -3
  146. data/lib/pubid/iso/utilities.rb +4 -5
  147. data/lib/pubid/iso.rb +1 -19
  148. data/lib/pubid/itu/builder.rb +36 -20
  149. data/lib/pubid/itu/identifiers/base.rb +15 -2
  150. data/lib/pubid/itu/parser.rb +1 -775
  151. data/lib/pubid/jcgm/builder.rb +35 -0
  152. data/lib/pubid/jcgm/parser.rb +1 -151
  153. data/lib/pubid/jcgm.rb +1 -2
  154. data/lib/pubid/jis/builder.rb +18 -29
  155. data/lib/pubid/jis/identifier.rb +1 -1
  156. data/lib/pubid/jis/parser.rb +1 -128
  157. data/lib/pubid/nist/builder.rb +5 -1
  158. data/lib/pubid/nist/caster.rb +13 -3
  159. data/lib/pubid/nist/identifiers/base.rb +37 -2
  160. data/lib/pubid/nist/identifiers/circular.rb +2 -2
  161. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -2
  162. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +2 -2
  163. data/lib/pubid/nist/identifiers/crpl_report.rb +2 -2
  164. data/lib/pubid/nist/identifiers/handbook.rb +2 -2
  165. data/lib/pubid/nist/identifiers/internal_report.rb +2 -2
  166. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
  167. data/lib/pubid/nist/identifiers/monograph.rb +2 -2
  168. data/lib/pubid/nist/identifiers/report.rb +2 -2
  169. data/lib/pubid/nist/parser.rb +19 -775
  170. data/lib/pubid/nist/router.rb +4 -1
  171. data/lib/pubid/nist/supplement_identifier.rb +2 -2
  172. data/lib/pubid/oasis/identifier.rb +1 -1
  173. data/lib/pubid/oasis/parser.rb +2 -16
  174. data/lib/pubid/ogc/identifier.rb +1 -1
  175. data/lib/pubid/ogc/parser.rb +2 -26
  176. data/lib/pubid/oiml/identifiers/certification_system.rb +7 -0
  177. data/lib/pubid/oiml/identifiers/dual_published.rb +2 -2
  178. data/lib/pubid/oiml/parser.rb +1 -303
  179. data/lib/pubid/oiml.rb +1 -2
  180. data/lib/pubid/omg/identifier.rb +6 -1
  181. data/lib/pubid/omg/parser.rb +2 -76
  182. data/lib/pubid/parg/artifact.rb +22 -3
  183. data/lib/pubid/parg/model.rb +98 -0
  184. data/lib/pubid/parg.rb +1 -0
  185. data/lib/pubid/parser.rb +5 -4
  186. data/lib/pubid/parsers/mr_string.rb +1 -1
  187. data/lib/pubid/plateau/parser.rb +1 -66
  188. data/lib/pubid/plateau.rb +1 -2
  189. data/lib/pubid/renderers/directives_renderer.rb +1 -1
  190. data/lib/pubid/renderers/iwa_renderer.rb +1 -1
  191. data/lib/pubid/renderers/publisher_stripper.rb +82 -0
  192. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  193. data/lib/pubid/renderers.rb +1 -0
  194. data/lib/pubid/sae/identifiers/base.rb +1 -1
  195. data/lib/pubid/sae/parser.rb +1 -48
  196. data/lib/pubid/tgpp/identifier.rb +1 -1
  197. data/lib/pubid/tgpp/parser.rb +2 -59
  198. data/lib/pubid/un/identifier.rb +1 -1
  199. data/lib/pubid/un/parser.rb +1 -18
  200. data/lib/pubid/version.rb +1 -1
  201. data/lib/pubid/w3c/identifier.rb +1 -1
  202. data/lib/pubid/w3c/parser.rb +2 -27
  203. data/lib/pubid/xsf/identifier.rb +11 -7
  204. data/lib/pubid/xsf/parser.rb +3 -31
  205. data/lib/pubid/xsf/renderer.rb +2 -4
  206. data/lib/pubid.rb +8 -9
  207. metadata +15 -25
  208. data/lib/pubid/ieee/aiee/parser.rb +0 -130
  209. data/lib/pubid/ieee/ire/parser.rb +0 -109
  210. data/lib/pubid/ieee/nesc/parser.rb +0 -155
  211. data/lib/pubid/iho/parser.rb +0 -68
  212. data/lib/pubid/parser/common_parse_methods.rb +0 -13
  213. data/lib/pubid/parser/common_parse_rules.rb +0 -56
  214. data/lib/pubid/parser/grammar.rb +0 -96
@@ -28,10 +28,47 @@ module Pubid
28
28
  return Pubid::Iec.parse(string)
29
29
  end
30
30
 
31
- parsed = Pubid::Parg::Backend.parse(:bsi, string)
31
+ parsed = Pubid::Parg::Model.bound(:bsi, strip_bsi_prefix(string))
32
32
  Builder.build(parsed)
33
33
  end
34
34
 
35
+ # The document series that BSI cites with its `BSI` publisher prefix
36
+ # in front (`BSI PAS 2031:2019`). `BS` is the British Standard series
37
+ # itself and is never preceded by it.
38
+ BSI_PREFIXED_SERIES = %w[PAS PD DD BIP].freeze
39
+
40
+ BSI_PREFIX = /\ABSI\s+(?=(?:#{BSI_PREFIXED_SERIES.join('|')})\b)/
41
+
42
+ # `BSI PAS 2031:2019` is the external spelling of `PAS 2031:2019`. The
43
+ # prefix is not part of the identity, so it is dropped before the baked
44
+ # grammar runs, and `to_s(with_publisher: true)` puts it back.
45
+ def self.strip_bsi_prefix(string)
46
+ string.sub(BSI_PREFIX, "")
47
+ end
48
+
49
+ # `with_publisher: false` drops only a real `BSI` prefix
50
+ # (`BSI Flex 1888` -> `Flex 1888`). `BS` in `BS 8611:2016` is the
51
+ # British Standard series, part of the designation, and stays.
52
+ def publisher_prefixes
53
+ ["BSI"]
54
+ end
55
+
56
+ # `with_publisher: true` renders the external form of a PAS / PD / DD /
57
+ # BIP document, with the `BSI` prefix in front. Every other form already
58
+ # starts with its publisher (`BS`, `BSI Flex`), or with a token that
59
+ # BSI does not prefix, and is left as it is.
60
+ def to_s(**opts)
61
+ rendered = super
62
+ return rendered unless opts[:with_publisher] == true
63
+
64
+ plain = rendered.gsub(%r{</?span[^>]*>}, "")
65
+ return rendered unless BSI_PREFIXED_SERIES.include?(plain[/\A\S+/])
66
+
67
+ prefix = "BSI"
68
+ prefix = %(<span class="publisher">#{prefix}</span>) if opts[:annotated]
69
+ "#{prefix} #{rendered}"
70
+ end
71
+
35
72
  attribute :publisher, Bsi::Components::Publisher, default: -> {
36
73
  Bsi::Components::Publisher.new(body: "BS")
37
74
  }
@@ -118,7 +118,7 @@ module Pubid
118
118
  raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
119
119
  end
120
120
 
121
- Builder.build(Pubid::Parg::Backend.parse(:calconnect, identifier))
121
+ Pubid::Parg::Model.parse(:calconnect, Identifiers::Standard, identifier)
122
122
  end
123
123
  end
124
124
  end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "parslet"
4
-
5
3
  module Pubid
6
4
  module Calconnect
7
- # Parslet grammar for CalConnect identifiers.
5
+ # Grammar for CalConnect identifiers.
8
6
  #
9
7
  # Shape: CC[/<series>] <number>:<date>
10
8
  # CC 18011:2018
@@ -12,43 +10,7 @@ module Pubid
12
10
  # CC/Adv 0707.1:2007 (dot sub-part)
13
11
  # CC/A 0812-1:2008 (dash sub-part)
14
12
  # CC/WD 51017:2024-07-23 (full ISO date)
15
- class Parser < ::Pubid::Parser::Grammar
16
- rule(:digit) { match["0-9"] }
17
- rule(:digits) { digit.repeat(1) }
18
-
19
- # Publisher token
20
- rule(:publisher) { str("CC") }
21
-
22
- # Series token — an open [A-Za-z]+ set (A, WD, R, S, CD, DIR, Adv, FDS, …)
23
- rule(:series) { match["A-Za-z"].repeat(1).as(:series) }
24
-
25
- # Number — digits, preserving leading zeros, with at most one dot- or
26
- # dash-delimited sub-part ("0707.1", "0812-1"). Kept as a string.
27
- rule(:number) do
28
- (digits >> ((str(".") | str("-")) >> digits).maybe).as(:number)
29
- end
30
-
31
- # Date after the colon: a year, optionally a full "YYYY-MM-DD". The colon
32
- # hard-delimits number from date, and month+day only appear together, so
33
- # the split is unambiguous.
34
- rule(:date) do
35
- digits.as(:year) >>
36
- (str("-") >> digits.as(:month) >> str("-") >> digits.as(:day)).maybe
37
- end
38
-
39
- rule(:identifier) do
40
- publisher >>
41
- (str("/") >> series).maybe >>
42
- str(" ") >>
43
- number >>
44
- (str(":") >> date).maybe
45
- end
46
-
47
- rule(:root) { identifier }
48
-
49
- def self.parse(input)
50
- new.parse(input)
51
- end
13
+ class Parser
52
14
  end
53
15
  end
54
16
  end
@@ -77,7 +77,7 @@ module Pubid
77
77
 
78
78
  # Apply legacy update_codes normalization first
79
79
  normalized = Core::UpdateCodes.apply(identifier, :ccsds)
80
- parsed = Pubid::Parg::Backend.parse(:ccsds, normalized)
80
+ parsed = Pubid::Parg::Model.bound(:ccsds, normalized)
81
81
  Pubid::Ccsds::Builder.build(parsed)
82
82
  end
83
83
 
@@ -1,73 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "parslet"
4
-
5
3
  module Pubid
6
4
  module Ccsds
7
- class Parser < ::Pubid::Parser::Grammar
8
- rule(:digit) { match["0-9"] }
9
- rule(:digits) { digit.repeat(1) }
10
- rule(:alnum) { match["A-Za-z0-9"] }
11
- rule(:alnums) { alnum.repeat(1) }
12
- rule(:space) { str(" ") }
13
- rule(:dash) { str("-") }
14
- rule(:dot) { str(".") }
15
-
16
- # CCSDS prefix
17
- rule(:ccsds_prefix) { str("CCSDS") >> space }
18
-
19
- # Number (can be alphanumeric like A02)
20
- rule(:number) { alnums.as(:number) }
21
-
22
- # Part (can be multi-digit like .21 or alphanumeric like .1)
23
- rule(:part) { dot >> alnums.as(:part) }
24
-
25
- # Type (all possible type letters)
26
- rule(:type) { dash >> match["A-Z"].as(:type) }
27
-
28
- # Edition (can have dots like 4.1, and a trailing draft letter like 1.99h)
29
- rule(:edition) do
30
- dash >> (match["0-9."].repeat(1) >> match["A-Za-z"].maybe).as(:edition)
31
- end
32
-
33
- # Suffix (like -S)
34
- rule(:suffix) { dash >> match["A-Z"].as(:suffix) }
35
-
36
- # Corrigendum
37
- rule(:corrigendum) do
38
- space >> str("Cor.") >> space >> digits.as(:cor_number)
39
- end
40
-
41
- rule(:corrigenda) { corrigendum.repeat(0).as(:corrigenda) }
42
-
43
- # Language metadata (e.g., " - French Translated", " - Russian Translated")
44
- rule(:language_metadata) do
45
- space >> dash >> space >>
46
- (
47
- (str("French") | str("Russian") | str("English") |
48
- str("German") | str("Spanish") | str("Italian") |
49
- str("Portuguese") | str("Chinese") | str("Japanese")).as(:language) >>
50
- (space >> str("Translated")).maybe
51
- )
52
- end
53
-
54
- # Main identifier
55
- rule(:identifier) do
56
- ccsds_prefix >>
57
- number >>
58
- part.maybe >>
59
- type.maybe >>
60
- edition.maybe >>
61
- suffix.maybe >>
62
- corrigenda >>
63
- language_metadata.maybe
64
- end
65
-
66
- rule(:root) { identifier }
67
-
68
- def self.parse(input)
69
- new.parse(input)
70
- end
5
+ class Parser
71
6
  end
72
7
  end
73
8
  end
@@ -28,6 +28,21 @@ module Pubid
28
28
  # repeat one entry of the stage registry, so they move together.
29
29
  subset_strict :type, :stage, :typed_stage
30
30
 
31
+ # The bodies that print as a publisher prefix (`CEN/TS 16931-3-1`,
32
+ # `CLC/TR 50600`, `CEN ISO/TS 12180-1`). The `publisher` attribute also
33
+ # holds the deliverable types `EN`, `HD`, `CR`, `CWA`, `ES` and `ENV`,
34
+ # which are the designation itself (`EN 13256:2000`): those stay under
35
+ # `with_publisher: false`, as `BS` does for BSI. The test reads the
36
+ # first token only, so a joint group drops whole
37
+ # (`CEN/CLC/ETSI/TR 101551` -> `TR 101551`).
38
+ PUBLISHER_PREFIXES = %w[CEN CLC CENELEC].freeze
39
+
40
+ def publisher_prefixes
41
+ super.select do |prefix|
42
+ PUBLISHER_PREFIXES.include?(prefix.split("/").first)
43
+ end
44
+ end
45
+
31
46
  # The publisher serializes as a bare string ("publisher" => "CEN"), and
32
47
  # the copublishers as a list of strings. The shared table does not do
33
48
  # this for every flavor, because IEEE has a published index whose rows
@@ -105,7 +120,7 @@ module Pubid
105
120
  end
106
121
 
107
122
  normalized = Parser.normalize_input(identifier)
108
- parsed = Pubid::Parg::Backend.parse(:cen_cenelec, normalized)
123
+ parsed = Pubid::Parg::Model.bound(:cen_cenelec, normalized)
109
124
  Builder.new.build(parsed)
110
125
  end
111
126
 
@@ -1,139 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "parslet"
4
-
5
3
  module Pubid
6
4
  module CenCenelec
7
- class Parser < ::Pubid::Parser::Grammar
8
- rule(:digit) { match["0-9"] }
9
- rule(:digits) { digit.repeat(1) }
10
- rule(:space) { str(" ") }
11
- rule(:dash) { str("-") }
12
- rule(:slash) { str("/") }
13
- rule(:plus) { str("+") }
14
- rule(:colon) { str(":") }
15
-
16
- # Publishers
17
- rule(:en) { str("EN") }
18
- rule(:cen) { str("CEN") }
19
- rule(:clc) { str("CLC") }
20
- rule(:cwa) { str("CWA") }
21
- rule(:hd) { str("HD") }
22
- rule(:es) { str("ES") }
23
- rule(:cr) { str("CR") }
24
- rule(:env) { str("ENV") }
25
-
26
- # Adopted organizations (ISO, IEC)
27
- rule(:iso) { str("ISO") }
28
- rule(:iec) { str("IEC") }
29
- rule(:cispr) { str("CISPR") }
30
-
31
- # Publisher (can be combined like EN/CLC or CEN/CLC)
32
- rule(:publisher) do
33
- (cwa | hd | es | cr | env).as(:publisher) |
34
- (en.as(:publisher) >> (slash >> clc.as(:copublisher)).maybe) |
35
- (cen.as(:publisher) >> (slash >> clc.as(:copublisher)).maybe) |
36
- (clc.as(:publisher) >> (slash >> cen.as(:copublisher)).maybe) |
37
- en.as(:publisher)
38
- end
39
-
40
- # Stage prefixes captured as type_with_stage for proper lookup
41
- rule(:stage_prefix) { (str("FprEN") | str("prEN")).as(:type_with_stage) }
42
-
43
- # Type
44
- rule(:type) do
45
- (str("Guide") | str("GUIDE") | str("TR") | str("TS")).as(:type)
46
- end
47
-
48
- # Number
49
- rule(:number) { digits.as(:number) }
50
-
51
- # Part (can be multi-level like 1-2 or 80-12)
52
- rule(:part) { dash >> match["0-9-"].repeat(1).as(:part) }
53
- rule(:parts) { part.repeat(0).as(:parts) }
54
-
55
- # Year
56
- rule(:year) { colon >> digit.repeat(4, 4).as(:year) }
57
-
58
- # Month support for dates like 2016-11
59
- rule(:month_digits) do
60
- (
61
- str("01") | str("02") | str("03") | str("04") |
62
- str("05") | str("06") | str("07") | str("08") |
63
- str("09") | str("10") | str("11") | str("12")
64
- ).as(:month)
65
- end
66
-
67
- rule(:year_with_month) do
68
- colon >> digit.repeat(4, 4).as(:year) >> dash >> month_digits
69
- end
70
-
71
- rule(:date) { year_with_month | year }
72
-
73
- # Amendment (+A1:2008 or +A11:2020 or /A2:2019 or /A1 without year)
74
- rule(:amendment) do
75
- (plus.as(:amd_sep_plus) | slash.as(:amd_sep_slash)) >>
76
- str("A") >> digits.as(:amd_number) >>
77
- (colon >> digit.repeat(4, 4).as(:amd_year)).maybe
78
- end
79
-
80
- # Corrigendum (+AC:2009 or +AC1:2008 or +AC2:2009 or /AC1:2005 or /AC:2016-11 with month)
81
- rule(:corrigendum) do
82
- (plus.as(:amd_sep_plus) | slash.as(:amd_sep_slash)) >>
83
- str("AC") >> digits.maybe.as(:cor_number) >>
84
- (year_with_month | (colon >> digit.repeat(4, 4).as(:year))).maybe
85
- end
86
-
87
- # Supplements (amendments and corrigenda)
88
- rule(:supplement) { (amendment | corrigendum).as(:supplement) }
89
- rule(:supplements) { supplement.repeat(0).as(:supplements) }
90
-
91
- # Edition (ED2, ED3, etc.)
92
- rule(:edition) { space >> str("ED") >> digits.as(:edition) }
93
-
94
- # Fragment identifier (EN 60038 AMD1 FRAG2, EN 60038/A1 FRAG2)
95
- rule(:fragment_identifier) do
96
- ((stage_prefix | publisher) >>
97
- space >> number >> parts >>
98
- space >> str("AMD") >> digits.as(:amendment_number) >>
99
- space >> str("FRAG") >> digits.as(:fragment_number)) |
100
- # Compact supplement notation: the base may carry a year, the
101
- # amendment uses the /A1 or +A1 join (with an optional year of
102
- # its own) instead of the spelled-out "AMD1" keyword.
103
- ((stage_prefix | publisher) >>
104
- space >> number >> parts >> year.maybe >>
105
- (plus | slash) >> str("A") >> digits.as(:amendment_number) >>
106
- (colon >> digit.repeat(4, 4).as(:amendment_year)).maybe >>
107
- space >> str("FRAG") >> digits.as(:fragment_number))
108
- end
109
-
110
- # Adopted standard as opaque string - must start with org name
111
- rule(:adopted_org_prefix) do
112
- str("ISO") | str("IEC") | str("CISPR")
113
- end
114
-
115
- rule(:adopted_string) do
116
- # Must start with organization name
117
- (adopted_org_prefix >> (supplement.absent? >> edition.absent? >> match("[^\n]")).repeat(0)).as(:adopted_string)
118
- end
119
-
120
- # Identifier
121
- rule(:identifier) do
122
- fragment_identifier |
123
- ((stage_prefix | publisher) >>
124
- (space >> adopted_string).maybe >>
125
- ((space >> type) | (slash >> type)).maybe >>
126
- (space >> number >> parts >>
127
- year.maybe).maybe >>
128
- supplements >>
129
- edition.maybe)
130
- end
131
-
132
- rule(:root) { identifier }
133
-
134
- # Pre-parse ingestion normalizations (R2): every parse path —
135
- # parslet and PG artifact alike — feeds the grammar the same
136
- # normalized string.
5
+ class Parser
6
+ # Pre-parse ingestion normalizations (R2): every parse path feeds
7
+ # the grammar the same normalized string.
137
8
  def self.normalize_input(input)
138
9
  # Normalize special dash characters
139
10
  normalized = input.gsub(/[\u2011\u00AD]/, "-")
@@ -150,10 +21,6 @@ module Pubid
150
21
  .gsub("GUIDE", "Guide")
151
22
  normalized
152
23
  end
153
-
154
- def self.parse(input)
155
- new.parse(normalize_input(input))
156
- end
157
24
  end
158
25
  end
159
26
  end
@@ -24,7 +24,7 @@ module Pubid
24
24
  raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
25
25
  end
26
26
 
27
- parsed = Pubid::Parg::Backend.parse(:cie, Parser.normalize_input(input))
27
+ parsed = Pubid::Parg::Model.bound(:cie, Parser.normalize_input(input))
28
28
  builder = Builder.new
29
29
  builder.build(parsed, original_string: input)
30
30
  end