pubid 2.0.1 → 2.0.3

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 (216) hide show
  1. checksums.yaml +4 -4
  2. data/data/ieee/update_codes.yaml +2 -2
  3. data/data/parg/adobe.json +1 -1
  4. data/data/parg/aiee.json +1 -1
  5. data/data/parg/aiee.parg +99 -9
  6. data/data/parg/amca.json +1 -1
  7. data/data/parg/ansi.json +1 -1
  8. data/data/parg/api.json +1 -1
  9. data/data/parg/ashrae.json +1 -1
  10. data/data/parg/asme.json +1 -1
  11. data/data/parg/astm.json +1 -1
  12. data/data/parg/bipm.json +1 -1
  13. data/data/parg/bsi.json +1 -1
  14. data/data/parg/ccsds.json +1 -1
  15. data/data/parg/cen_cenelec.json +1 -1
  16. data/data/parg/cie.json +1 -1
  17. data/data/parg/csa.json +1 -1
  18. data/data/parg/ecma.json +1 -1
  19. data/data/parg/etsi.json +1 -1
  20. data/data/parg/evs.json +1 -1
  21. data/data/parg/gost.json +1 -1
  22. data/data/parg/iala.json +1 -1
  23. data/data/parg/iana.json +1 -1
  24. data/data/parg/idf.json +1 -1
  25. data/data/parg/iec.json +1 -1
  26. data/data/parg/ieee.json +1 -1
  27. data/data/parg/iho.json +1 -0
  28. data/data/parg/ire.json +1 -1
  29. data/data/parg/ire.parg +51 -12
  30. data/data/parg/isbn.json +1 -1
  31. data/data/parg/iso.json +1 -1
  32. data/data/parg/iso.parg +751 -0
  33. data/data/parg/itu.json +1 -1
  34. data/data/parg/jcgm.json +1 -1
  35. data/data/parg/jis.json +1 -1
  36. data/data/parg/nesc.json +1 -1
  37. data/data/parg/nesc.parg +97 -12
  38. data/data/parg/nist.json +1 -1
  39. data/data/parg/oiml.json +1 -1
  40. data/data/parg/omg.json +1 -1
  41. data/data/parg/parg.json +1 -1
  42. data/data/parg/plateau.json +1 -1
  43. data/data/parg/tgpp.json +1 -1
  44. data/data/parg/un.json +1 -1
  45. data/lib/pubid/adobe/identifier.rb +1 -1
  46. data/lib/pubid/adobe/parser.rb +2 -113
  47. data/lib/pubid/amca/identifiers/base.rb +1 -1
  48. data/lib/pubid/amca/parser.rb +1 -145
  49. data/lib/pubid/ansi/identifier.rb +1 -1
  50. data/lib/pubid/ansi/parser.rb +1 -82
  51. data/lib/pubid/api/builder.rb +32 -1
  52. data/lib/pubid/api/identifier.rb +1 -1
  53. data/lib/pubid/api/parser.rb +1 -131
  54. data/lib/pubid/ashrae/identifiers/base.rb +1 -1
  55. data/lib/pubid/ashrae/parser.rb +3 -710
  56. data/lib/pubid/asme/builder.rb +6 -4
  57. data/lib/pubid/asme/identifier.rb +1 -2
  58. data/lib/pubid/asme/parser.rb +1 -328
  59. data/lib/pubid/astm/builder.rb +12 -3
  60. data/lib/pubid/astm/identifier.rb +1 -2
  61. data/lib/pubid/astm/parser.rb +1 -227
  62. data/lib/pubid/bipm/identifier.rb +8 -1
  63. data/lib/pubid/bipm/parser.rb +2 -224
  64. data/lib/pubid/bsi/builder.rb +2 -4
  65. data/lib/pubid/bsi/parser.rb +1 -666
  66. data/lib/pubid/bsi/single_identifier.rb +38 -1
  67. data/lib/pubid/calconnect/parser.rb +2 -40
  68. data/lib/pubid/ccsds/identifier.rb +1 -1
  69. data/lib/pubid/ccsds/parser.rb +1 -66
  70. data/lib/pubid/cen_cenelec/identifier.rb +16 -1
  71. data/lib/pubid/cen_cenelec/parser.rb +3 -136
  72. data/lib/pubid/cie/identifier.rb +1 -1
  73. data/lib/pubid/cie/parser.rb +3 -378
  74. data/lib/pubid/conformance.rb +1 -1
  75. data/lib/pubid/csa/builder.rb +41 -18
  76. data/lib/pubid/csa/identifier.rb +12 -4
  77. data/lib/pubid/csa/identifiers/amendment.rb +28 -0
  78. data/lib/pubid/csa/identifiers.rb +1 -0
  79. data/lib/pubid/csa/parser.rb +16 -397
  80. data/lib/pubid/doi/parser.rb +2 -37
  81. data/lib/pubid/easc/builder.rb +1 -1
  82. data/lib/pubid/easc/parser.rb +2 -70
  83. data/lib/pubid/ecma/CLAUDE.md +8 -1
  84. data/lib/pubid/ecma/identifier.rb +13 -8
  85. data/lib/pubid/ecma/parser.rb +2 -54
  86. data/lib/pubid/ecma/renderer.rb +3 -7
  87. data/lib/pubid/errors.rb +18 -13
  88. data/lib/pubid/etsi/builder.rb +8 -5
  89. data/lib/pubid/etsi/identifiers/base.rb +1 -1
  90. data/lib/pubid/etsi/parser.rb +1 -132
  91. data/lib/pubid/evs/identifier.rb +7 -0
  92. data/lib/pubid/evs/parser.rb +1 -8
  93. data/lib/pubid/evs.rb +1 -1
  94. data/lib/pubid/gb/identifier.rb +6 -0
  95. data/lib/pubid/gb/parser.rb +2 -51
  96. data/lib/pubid/gost/identifier.rb +9 -1
  97. data/lib/pubid/gost/parser.rb +4 -81
  98. data/lib/pubid/iala/builder.rb +48 -39
  99. data/lib/pubid/iala/identifier.rb +1 -1
  100. data/lib/pubid/iala/parser.rb +2 -121
  101. data/lib/pubid/iana/identifier.rb +1 -1
  102. data/lib/pubid/iana/parser.rb +2 -24
  103. data/lib/pubid/identifier.rb +78 -1
  104. data/lib/pubid/idf/builder.rb +42 -0
  105. data/lib/pubid/idf/identifier.rb +1 -1
  106. data/lib/pubid/idf/parser.rb +1 -137
  107. data/lib/pubid/idf.rb +1 -2
  108. data/lib/pubid/iec/builder.rb +158 -50
  109. data/lib/pubid/iec/identifier.rb +1 -1
  110. data/lib/pubid/iec/parser.rb +3 -430
  111. data/lib/pubid/ieee/CLAUDE.md +2 -0
  112. data/lib/pubid/ieee/aiee/identifier.rb +2 -1
  113. data/lib/pubid/ieee/aiee.rb +0 -1
  114. data/lib/pubid/ieee/builder.rb +177 -30
  115. data/lib/pubid/ieee/components/code.rb +46 -7
  116. data/lib/pubid/ieee/identifiers/base.rb +5 -2
  117. data/lib/pubid/ieee/identifiers/joint_development.rb +7 -3
  118. data/lib/pubid/ieee/ire/identifier.rb +2 -1
  119. data/lib/pubid/ieee/ire.rb +0 -1
  120. data/lib/pubid/ieee/nesc/builder.rb +1 -1
  121. data/lib/pubid/ieee/nesc.rb +0 -1
  122. data/lib/pubid/ieee/parser.rb +1 -1257
  123. data/lib/pubid/ieee/project_renderer.rb +5 -1
  124. data/lib/pubid/ieee/renderer.rb +4 -2
  125. data/lib/pubid/ieee/urn_generator.rb +4 -1
  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 +98 -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 +14 -1
  134. data/lib/pubid/iho/urn_parser.rb +45 -32
  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/CLAUDE.md +66 -0
  139. data/lib/pubid/iso/builder.rb +229 -15
  140. data/lib/pubid/iso/identifier.rb +22 -12
  141. data/lib/pubid/iso/identifiers/directives.rb +6 -3
  142. data/lib/pubid/iso/identifiers/guide.rb +6 -3
  143. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
  144. data/lib/pubid/iso/normalizer.rb +5 -4
  145. data/lib/pubid/iso/parser.rb +1 -539
  146. data/lib/pubid/iso/supplement_identifier.rb +6 -3
  147. data/lib/pubid/iso/urn_parser.rb +13 -8
  148. data/lib/pubid/iso/utilities.rb +4 -5
  149. data/lib/pubid/iso.rb +1 -19
  150. data/lib/pubid/itu/builder.rb +36 -20
  151. data/lib/pubid/itu/identifiers/base.rb +15 -2
  152. data/lib/pubid/itu/parser.rb +1 -775
  153. data/lib/pubid/jcgm/builder.rb +35 -0
  154. data/lib/pubid/jcgm/parser.rb +1 -151
  155. data/lib/pubid/jcgm.rb +1 -2
  156. data/lib/pubid/jis/CLAUDE.md +36 -0
  157. data/lib/pubid/jis/builder.rb +30 -41
  158. data/lib/pubid/jis/identifier.rb +12 -2
  159. data/lib/pubid/jis/identifiers/welding_engineering_standard.rb +35 -0
  160. data/lib/pubid/jis/identifiers.rb +2 -0
  161. data/lib/pubid/jis/parser.rb +1 -128
  162. data/lib/pubid/jis/renderer.rb +1 -1
  163. data/lib/pubid/jis/supplement_identifier.rb +5 -5
  164. data/lib/pubid/jis/urn_parser.rb +2 -1
  165. data/lib/pubid/jis.rb +3 -2
  166. data/lib/pubid/nist/builder.rb +5 -1
  167. data/lib/pubid/nist/caster.rb +13 -3
  168. data/lib/pubid/nist/identifiers/base.rb +37 -2
  169. data/lib/pubid/nist/identifiers/circular.rb +2 -2
  170. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -2
  171. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +2 -2
  172. data/lib/pubid/nist/identifiers/crpl_report.rb +2 -2
  173. data/lib/pubid/nist/identifiers/handbook.rb +2 -2
  174. data/lib/pubid/nist/identifiers/internal_report.rb +2 -2
  175. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
  176. data/lib/pubid/nist/identifiers/monograph.rb +2 -2
  177. data/lib/pubid/nist/identifiers/report.rb +2 -2
  178. data/lib/pubid/nist/parser.rb +19 -775
  179. data/lib/pubid/nist/router.rb +4 -1
  180. data/lib/pubid/nist/supplement_identifier.rb +2 -2
  181. data/lib/pubid/oasis/parser.rb +2 -16
  182. data/lib/pubid/ogc/parser.rb +2 -26
  183. data/lib/pubid/oiml/identifiers/certification_system.rb +7 -0
  184. data/lib/pubid/oiml/identifiers/dual_published.rb +2 -2
  185. data/lib/pubid/oiml/parser.rb +1 -303
  186. data/lib/pubid/oiml.rb +1 -2
  187. data/lib/pubid/omg/identifier.rb +6 -1
  188. data/lib/pubid/omg/parser.rb +2 -76
  189. data/lib/pubid/parser.rb +5 -4
  190. data/lib/pubid/parsers/mr_string.rb +1 -1
  191. data/lib/pubid/plateau/parser.rb +1 -66
  192. data/lib/pubid/plateau.rb +1 -2
  193. data/lib/pubid/renderers/directives_renderer.rb +1 -1
  194. data/lib/pubid/renderers/iwa_renderer.rb +1 -1
  195. data/lib/pubid/renderers/publisher_stripper.rb +82 -0
  196. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  197. data/lib/pubid/renderers.rb +1 -0
  198. data/lib/pubid/sae/parser.rb +1 -48
  199. data/lib/pubid/tgpp/identifier.rb +1 -1
  200. data/lib/pubid/tgpp/parser.rb +2 -59
  201. data/lib/pubid/un/identifier.rb +1 -1
  202. data/lib/pubid/un/parser.rb +1 -18
  203. data/lib/pubid/version.rb +1 -1
  204. data/lib/pubid/w3c/parser.rb +2 -27
  205. data/lib/pubid/xsf/identifier.rb +10 -6
  206. data/lib/pubid/xsf/parser.rb +3 -31
  207. data/lib/pubid/xsf/renderer.rb +2 -4
  208. data/lib/pubid.rb +8 -9
  209. metadata +9 -23
  210. data/lib/pubid/ieee/aiee/parser.rb +0 -130
  211. data/lib/pubid/ieee/ire/parser.rb +0 -109
  212. data/lib/pubid/ieee/nesc/parser.rb +0 -155
  213. data/lib/pubid/iho/parser.rb +0 -68
  214. data/lib/pubid/parser/common_parse_methods.rb +0 -13
  215. data/lib/pubid/parser/common_parse_rules.rb +0 -56
  216. 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
  }
@@ -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