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
@@ -1,437 +1,14 @@
1
- require "parslet"
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Pubid
5
4
  module Iec
6
- class Parser < ::Pubid::Parser::Grammar
7
- include ::Pubid::Parser::CommonParseRules
8
- include ::Pubid::Parser::CommonParseMethods
9
-
5
+ class Parser
10
6
  DASH_CHARS = ["-", "‑", "‐"].freeze
11
7
 
12
- # We need to sort by length to match longest first because that's how Parslet works
13
- TYPED_STAGES = Pubid::Iec.all_typed_stages
14
- .map(&:abbr).flatten.sort_by(&:length).reverse
15
- TYPED_STAGES_SUPPLEMENTS = TYPED_STAGES
16
-
17
- root :identifier
18
-
19
- rule(:identifier) do
20
- working_programme |
21
- technical_group |
22
- working_document |
23
- sheet_supplement_identifier |
24
- sheet_identifier |
25
- supplement_supplement_identifier |
26
- standalone_supplement |
27
- supplement_identifier |
28
- joint_identifier |
29
- identifier_copublishers
30
- end
31
-
32
- # Technical Group identifier — names a committee rather than a document.
33
- # Examples: "IEC TC 1", "ISO/IEC JTC 1", "ISO/IEC JTC 1/SC 7",
34
- # "IEC SC 100A", "CISPR", "CIS/A".
35
- rule(:technical_group) do
36
- technical_group_with_publisher | technical_group_bare
37
- end
38
-
39
- rule(:technical_group_with_publisher) do
40
- prefix_sole_publisher >> copublishers.maybe >> space >>
41
- tc_body.as(:technical_committee) >>
42
- (str("/") >> space? >> sc_body).as(:subcommittee).maybe
43
- end
44
-
45
- rule(:technical_group_bare) do
46
- # CISPR / CIS-letter forms and bare TYPE NUMBER forms both default
47
- # publisher to "IEC" via the Base class default.
48
- tc_body.as(:technical_committee) >>
49
- (str("/") >> space? >> sc_body).as(:subcommittee).maybe
50
- end
51
-
52
- # Committee body forms accepted by the parser. Order matters: longer
53
- # or more specific patterns first so they win the ordered choice.
54
- rule(:tc_body) do
55
- str("CISPR") |
56
- (str("CIS") >> str("/") >> match("[A-Z]")) |
57
- (tc_type >> space >> digits >> match("[A-Z]").maybe)
58
- end
59
-
60
- rule(:sc_body) do
61
- str("SC") >> space >> digits >> match("[A-Z]").maybe
62
- end
63
-
64
- rule(:tc_type) do
65
- str("JTC") | str("JPC") | str("TC") | str("SC") | str("PC")
66
- end
67
-
68
- # Working Programme format: [PWI|PNW] [TR] number edition
69
- # Examples: "PWI TR 100-36 ED1", "PWI 100-44 ED1", "PNW 65-915 ED1"
70
- # TC-style names: "PWI TR SYCSMARTENERGY-1", "PWI SyCLVDC-1 ED1"
71
- rule(:working_programme) do
72
- (str("PWI") | str("PNW")).as(:wp_stage) >>
73
- space >>
74
- (
75
- (str("TR") >> space) |
76
- (str("TS") >> space) |
77
- (str("SRD") >> space)
78
- ).maybe.as(:wp_type) >>
79
- wp_number >>
80
- (space >> edition).maybe
81
- end
82
-
83
- # Working programme numbers can be digits or TC names
84
- rule(:wp_number) do
85
- # TC-style: SYCSMARTENERGY-1, SyCLVDC-125
86
- (match("[A-Za-z]").repeat(1) >> match('[A-Za-z\d]').repeat >> (dash >> match('\d').repeat(1)).maybe).as(:number_with_part) |
87
- # Regular numeric: 100-36
88
- number_with_part
89
- end
90
-
91
- # Working Document format: TC/number/stage
92
- # TC can be: slashes (CIS/D), hyphens (JTC1-SC41), simple (100, 86B, ACEA, SyCSmartEnergy)
93
- # Examples: "CIS/D/468A/CC", "JTC1-SC41/251/FDIS", "100/3705(F)/FDIS", "86B/4347A/CC"
94
- rule(:working_document) do
95
- # TC patterns: digits (100), letters (ACEA), letters/letters (CIS/D), or complex (JTC1-SC41)
96
- (
97
- # Try specific patterns first
98
- (str("JTC1-SC") >> match('\d').repeat(1)) | # JTC1-SC41
99
- (match("[A-Z]").repeat(1) >> str("/") >> match("[A-Z]").repeat(1)) | # CIS/D
100
- match('[A-Za-z\d]').repeat(1) # Simple: 100, 86B, ACEA, SyCSmartEnergy
101
- ).as(:technical_committee) >>
102
- str("/") >>
103
- match('[A-Za-z\d]').repeat(1).as(:wd_number) >>
104
- (str("(") >> match("[A-Z]").as(:wd_language) >> str(")")).maybe >>
105
- (str("/") >> match("[A-Z]").repeat(1).as(:wd_stage)).maybe
106
- end
107
-
108
- # IEC 60038:2009
109
- # ISO/IEC 17025:2017
110
- # CISPR 11:2015 (special IEC publisher)
111
- # IECQ 080000:2017 (special IEC publisher)
112
- # IECEE (IEC System for Conformity Assessment)
113
- # IECEx (IEC System for Certification to Standards)
114
- # IEC CA (IEC Conformity Assessment)
115
- # IECQ CS (IECQ Component Specifications)
116
- # IECQ OD (IECQ Operational Documents)
117
- rule(:prefix_sole_publisher) do
118
- (
119
- str("IECQ OD") |
120
- str("IECQ CS") |
121
- str("IEC CAB") |
122
- str("IEC CA") |
123
- str("IECRE") |
124
- str("CISPR") |
125
- str("IECEE") |
126
- str("IECEx") |
127
- str("IECQ") |
128
- str("IEC") |
129
- str("ISO")
130
- ).as(:publisher)
131
- end
132
-
133
- # ISO/IEC or IEC
134
- rule(:prefix_with_copublishers) do
135
- prefix_sole_publisher >> space? >> copublishers.maybe
136
- end
137
-
138
- ORGANIZATIONS = %w[
139
- IEC ISO IEEE CIW SAE CIE ASME ASTM OECD HL7 CEI UNDP
140
- ].freeze
141
- rule(:copublishers) do
142
- (str("/") >> space? >> array_to_str(ORGANIZATIONS).as(:copublisher)).repeat.as(:copublishers)
143
- end
144
-
145
- rule(:number_with_part) do
146
- (number >> part_and_subpart.maybe).as(:number_with_part)
147
- end
148
-
149
- # For TRF with organization prefix: "CISPR 14-1G" where CISPR is part of the number
150
- rule(:trf_org_number) do
151
- (str("CISPR") >> space).as(:trf_org) >> number_with_part
152
- end
153
-
154
- rule(:number) do
155
- # ISO/IEC Directives: "DIR", "DIR 1", "DIR 1 IEC SUP", "DIR 2 IEC", "DIR IEC SUP"
156
- # Captured as a flat number (no part/subpart) so it round-trips to the input
157
- # and class-matches the IEC index. Must come before the IECEE [A-Z]{2,4} branch,
158
- # which would otherwise match "DIR" alone and leave the trailing tokens unconsumed.
159
- (str("DIR") >> (space >> match('[A-Z\d]').repeat(1)).repeat) |
160
- # Special case for VIM publication
161
- str("VIM") |
162
- # Special case for SYMBOL publication
163
- str("SYMBOL") |
164
- # IECEx TRF version notation: 62784v1a_ds, 62784v1A
165
- (match('\d').repeat(1,
166
- 6) >> str("v") >> match('\d').repeat(1) >> match("[a-zA-Z]").repeat >> (str("_") >> match("[a-zA-Z]").repeat).maybe) |
167
- # IECEE letter-based numbers: AD-001, GD-2053, OD-1000, CAB-G01, 01-S
168
- # Pattern: 2-4 letter prefix followed by optional dash and number
169
- # The suffix uses [A-Z\d] but not space to properly separate from edition
170
- (match("[A-Z]").repeat(2, 4) >> (
171
- dash >> match('\d').repeat(1)
172
- ).maybe >> match('[A-Z\d]').repeat) |
173
- # Can be 5-6 digits for TRF: 60065, 610091
174
- # Can have letter suffix: 60065N, 610091A
175
- # Can have letter + underscore + letters: 61215F_SE
176
- (match('\d').repeat(1, 6) >> (
177
- match("[a-zA-Z]") >> (str("_") >> match("[a-zA-Z]").repeat).maybe
178
- ).maybe)
179
- end
180
-
181
- rule(:date) do
182
- # :2005-02 or :-- (undated reference — ISO/IEC undated-reference form,
183
- # e.g. IEC 60050:--, also accepted as the em-dash variant IEC 60050:—)
184
- (str(":") | dash) >>
185
- (
186
- (str("--") | str("—")).as(:undated_marker) |
187
- (year_digits >>
188
- (dash >> month_digits).maybe >>
189
- (dash >> day_digits).maybe
190
- ).as(:date)
191
- )
192
- end
193
-
194
- rule(:part_and_subpart) do
195
- # Parts can have:
196
- # - Dashes: 60038-1
197
- # - Complex: 29110-5-1-1
198
- # - TRF ampersand: 60086-1&2A
199
- # - TRF underscore: 60127-2-IA_I, 61215F_SE
200
- # - TRF lowercase: 60127-2-iD_I
201
- # - TRF commas: 60309-1,2G or 60335-1-14,15G
202
-
203
- # the "space?" needed to handle potential spaces
204
- (dash | str(",")) >> space? >>
205
- # matches a part with special TRF characters including commas
206
- match('[\w&_,]').repeat >>
207
- # matches subparts
208
- ((dash | str(",")) >> match('[\w&_,]').repeat).repeat.maybe
209
- end
210
-
211
- rule(:all_parts) do
212
- str("(all parts)").as(:all_parts)
213
- end
214
-
215
- rule(:type_with_stage) do
216
- # "DTR"
217
- # "TS"
218
- # "Guide"
219
- # Also includes supplement stages like "CDCor" for standalone draft corrigenda
220
- array_to_str(TYPED_STAGES + TYPED_STAGES_SUPPLEMENTS).as(:type_with_stage) >>
221
- (match('\d').as(:stage_iteration) >> space).maybe
222
- end
223
-
224
- rule(:language) do
225
- # IEC 60038:2009(en,fr)
226
- # IEC 60038:2009(en-fr) (house style, pubid#491)
227
- # IEC 60038:2009(E/F)
228
- str("(") >>
229
- (
230
- # parse 2-char language codes: ru,en,fr,de,ar,es
231
- (match["a-z"].repeat(1) >> (str(",") | str("-")).maybe) |
232
- # parse single language codes: R/E/F
233
- (match["EFARDS"] >> str("/").maybe)
234
- ).repeat.as(:languages) >>
235
- str(")")
236
- end
237
-
238
- EDITION_STRINGS = %w[Edition Ed. ED Ed].freeze
239
- rule(:edition) do
240
- # We ignore the case where there is "Ed" but no number
241
- # Handle decimal editions like ED1.2
242
- array_to_str(EDITION_STRINGS) >> space? >>
243
- (digits >> (str(".") >> digits).maybe).maybe.as(:edition)
244
- end
245
-
246
- rule(:stage_iteration) do
247
- # "IEC 11243.1"
248
- str(".") >> match('\d').as(:stage_iteration)
249
- end
250
-
251
- # Sheet notation: /1:1994 (sheet 1 from year 1994)
252
- # IEC 60695-2-1/1:1994
253
- rule(:sheet_notation) do
254
- str("/") >>
255
- match('\d').repeat(1).as(:sheet_number) >>
256
- str(":") >>
257
- year_digits.as(:sheet_year)
258
- end
259
-
260
- # Sheet notation without year: /1 (sheet 1 without year)
261
- # IEC 60695-2-1/1
262
- rule(:sheet_notation_no_year) do
263
- str("/") >>
264
- match('\d').repeat(1).as(:sheet_number)
265
- end
266
-
267
- # Fragment notation: /FRAG2 or /FRAGC1 (fragment of amendment/corrigendum)
268
- # IEC 60050-191/AMD2/FRAG2
269
- # IEC 60050-191/COR1/FRAGC1
270
- rule(:fragment_notation) do
271
- str("/") >>
272
- (str("FRAGC") | str("FRAG")).as(:fragment_type) >>
273
- match('\d').repeat(1).as(:fragment_number)
274
- end
275
-
276
- # Sheet identifier: base identifier followed by /N:YEAR
277
- # IEC 60695-2-1/1:1994 (sheet 1 from year 1994)
278
- # IEC 60695-2-1/1 (sheet 1 without year)
279
- rule(:sheet_identifier) do
280
- identifier_copublishers_no_third.as(:base) >>
281
- (sheet_notation | sheet_notation_no_year)
282
- end
283
-
284
- # Sheet identifier followed by supplement: base/sheet/supplement
285
- # IEC 60695-2-1/1:1994/COR1:1995
286
- rule(:sheet_supplement_identifier) do
287
- identifier_copublishers_no_third.as(:base) >>
288
- sheet_notation >>
289
- str("/") >> supplement_type_with_stage >>
290
- space? >> second_part >> third_part
291
- end
292
-
293
- # VAP suffix for consolidated/version types
294
- # CSV = Consolidated version (with Supplements)
295
- # CMV = Commented Version
296
- # RLV = Redline Version (shows changes)
297
- # SER = Serial version
298
- # EXV = Example version
299
- # PAC = Package
300
- # PRV = Preview version
301
- # Internal helper (no `.as`): a single VAP code. The capture key stays
302
- # :vap_suffix below; this rule just lets the suffix be one or more codes.
303
- rule(:vap_code) do
304
- str("CSV") |
305
- str("CMV") |
306
- str("RLV") |
307
- str("SER") |
308
- str("EXV") |
309
- str("PAC") |
310
- str("PRV")
311
- end
312
-
313
- # One or more VAP codes joined by "-", captured whole, e.g. "CSV" or
314
- # "EXV-CMV"; the builder splits it into the VapIdentifier `vap` array.
315
- rule(:vap_suffix) do
316
- space >> (vap_code >> (str("-") >> vap_code).repeat).as(:vap_suffix)
317
- end
318
-
319
- # Database suffix: " DB"
320
- # IEC 60617:2012 DB
321
- rule(:database_suffix) do
322
- space >> str("DB").as(:database)
323
- end
324
-
325
- # Consolidated amendments: +AMD1:2016+AMD2:2019
326
- # Also supports without dates: +AMD1+AMD2
327
- # Creates ConsolidatedIdentifier with array of amendments
328
- rule(:consolidated_supplement) do
329
- str("+") >>
330
- (str("AMD") | str("COR")).as(:supplement_type) >>
331
- match('\d').repeat(1).as(:supplement_number) >>
332
- (str(":") >> year_digits.as(:supplement_year)).maybe
333
- end
334
-
335
- rule(:consolidated_supplements) do
336
- consolidated_supplement.repeat(1).as(:consolidated_supplements)
337
- end
338
-
339
- rule(:second_part) do
340
- # Try TRF organization number first, fallback to regular number
341
- (trf_org_number | number_with_part) >>
342
- stage_iteration.maybe >>
343
- (space? >> date).maybe >>
344
- consolidated_supplements.maybe >>
345
- (vap_suffix | database_suffix).maybe
346
- end
347
-
348
- rule(:third_part_edition) do
349
- space? >> edition.maybe
350
- end
351
-
352
- rule(:third_part) do
353
- # End of the identifier, we can have language, edition, fragment, or all parts
354
- third_part_edition >> language.maybe >> fragment_notation.maybe >> all_parts.maybe
355
- end
356
-
357
- # prefix sole or copublishers with type and stage
358
- # IEC/TR 60038
359
- # ISO/IEC TS 20594-1
360
- # IEC/FDIS 60038
361
- rule(:identifier_copublishers) do
362
- identifier_copublishers_no_third >> third_part
363
- end
364
-
365
- rule(:guide_prefix) do
366
- str("Guide") | str("GUIDE")
367
- end
368
-
369
- rule(:identifier_copublishers_no_third) do
370
- # Guide IEC 51:1999
371
- (guide_prefix.as(:type_with_stage_fr) >> space).maybe >>
372
- prefix_with_copublishers.maybe >> space? >> str("/").maybe >>
373
- type_with_stage.maybe >>
374
- space.maybe >>
375
- second_part >> third_part_edition
376
- end
377
-
378
- # For joint identifiers (ISO/IEC)
379
- # ISO/IEC 17025:2017 handles copublisher in copublishers rule
380
- # We handle this in identifier_copublishers already
381
- rule(:joint_identifier) do
382
- identifier_copublishers_no_third.as(:base) >>
383
- space? >> str("|") >> space? >>
384
- scope { iso_identifier }.as(:joint_identifier)
385
- end
386
-
387
- rule(:iso_identifier) do
388
- Pubid::Iso.joint_grammar_atom(:identifier)
389
- end
390
-
391
- rule(:supplement_type_with_stage) do
392
- # "DAM"
393
- # "Amd"
394
- # "FRAG" (fragments of amendments)
395
- # "FRAGC" (fragments of corrigenda)
396
- (array_to_str(TYPED_STAGES_SUPPLEMENTS) | str("FRAGC") | str("FRAG")).as(:type_with_stage)
397
- end
398
-
399
- # Standalone draft supplement (no base identifier)
400
- # IEC/FDAM 60038-1
401
- # IEC/FDCOR 12345
402
- rule(:standalone_supplement) do
403
- prefix_with_copublishers >> str("/") >>
404
- supplement_type_with_stage >>
405
- space >> second_part >> third_part
406
- end
407
-
408
- # IEC 60038:2009/Amd 1:2011
409
- rule(:supplement_identifier_no_third) do
410
- identifier_copublishers_no_third.as(:base) >>
411
- str("/") >> supplement_type_with_stage >>
412
- space? >> second_part
413
- end
414
-
415
- rule(:supplement_identifier) do
416
- supplement_identifier_no_third >> third_part
417
- end
418
-
419
- # IEC 60038:2009/Amd 1:2011/Cor 1:2012
420
- rule(:supplement_supplement_identifier) do
421
- supplement_identifier_no_third.as(:base) >>
422
- str("/") >> supplement_type_with_stage >>
423
- space? >> second_part >> third_part
424
- end
425
-
426
- rule(:dash) do
427
- DASH_CHARS.map { |char| str(char) }.reduce(:|)
428
- end
429
-
430
8
  IEV_SHORTHAND = /\AIEV(?=\z|[\s-])/
431
9
 
432
- # Pre-parse ingestion normalizations (R2): every parse path —
433
- # parslet and PG artifact alike — feeds the grammar the same
434
- # normalized string.
10
+ # Pre-parse ingestion normalizations (R2): every parse path feeds
11
+ # the grammar the same normalized string.
435
12
  def self.normalize_input(input)
436
13
  # Normalize tab-separated editions: "IECEE AD-001\tED1.6" -> "IECEE AD-001 ED1.6"
437
14
  normalized = input.gsub("\t", " ")
@@ -440,10 +17,6 @@ module Pubid
440
17
  # Expand IEV shorthand: "IEV" / "IEV-351" -> "IEC 60050" / "IEC 60050-351"
441
18
  normalized.sub(IEV_SHORTHAND, "IEC 60050")
442
19
  end
443
-
444
- def parse(input)
445
- super(self.class.normalize_input(input))
446
- end
447
20
  end
448
21
  end
449
22
  end
@@ -97,3 +97,5 @@ The lesson BSI paid for: a wrapper's hand-written `#number` delegation makes the
97
97
  - **The project designator format, and the bare-P parse that dropped it (pubid#18).** IEEE's own draft documents are cited by their short designator — "P1201/D0.3", "P10000/D1.2" — and metanorma-ieee had to post-process the full rendering to produce it. Two edits. **(1) `format: :project`** registers `Pubid::Ieee::ProjectRenderer` in the IEEE format registry: the code (with parts), a PREPENDED "P" when the identifier is a project but the code does not already carry it, and "/D<draft>"; no publisher, no type word, no date. "Project" is detected in all three places a marker can live depending on the building path — `code_obj.prefix` (the bare spelling), the "P" type code, or a `typed_stage` with `project_status` (D1-D6). **(2) The bare-P data loss**: `ieee_p_identifier` consumed its leading "P" with a bare `str("P")`, so "P1201/D0.3" parsed WITHOUT its P anywhere (the number was "1201", prefix nil) — the issue's complaint verbatim. The rule now lets `number` capture the P (the #318 pattern), so `code.prefix` survives and the designator has something to read. The DEFAULT rendering is unchanged — the corpus keeps the P in every unapproved-draft canonical, and #318's idempotence work locked that; the issue's suggestion that the default drop the P predates the corpus and is not adopted. A published (non-project) id renders its bare number under `:project` — the format is a draft-designator view.
98
98
 
99
99
  - **Joint stage-first forms are lead ISO, and the ISO face is lossless (pubid#477)**: a stage word printed in the ISO position (`IEEE FCD 15026.3:2010`, `IEEE/IEC CD2 P62582-2017-05`) parses as printed (#469): `Builder#build_joint_development` sets `lead_party "ISO"` whatever the publisher order, so `canonical_format` is `:iso`. PR #472 had made the lead the first printed publisher and rendered an IEEE-first form in the `D=` face — but the grammar artifact cannot parse most of those renders (`D=FCD`, `D=CD.2`, a non-P number, a month), and `D=CD-2020` parses into a *different* id (`ieee_draft`, no `iso_stage`), so 19 published `relaton-data-ieee` rows stopped matching themselves. The `D=` face now prints only for an id that carries a `D=` designator, or on an explicit `to_s(format: :ieee)`. `JointDevelopment#to_iso_format` prints `iso_stage` as stored (`DIS2`, `CD4` — #472's bare `CD` lost the iteration) and the date in the spelling that parses back (`#iso_date_suffix`: `:2018`, `-2018-05`, `, April 2019`). **The test is `parse(to_s) == id`, not a stable `to_s`**: a lossy render reaches a fixed point and round-trips its *hash* (`iso_stage_spellings_spec` held both while dropping `CD4`→`CD`), yet the reparse is a different identifier. Measured over the 118 joint stage rows of `relaton-data-ieee`: `to_s` stable 100 → 118, `==` 51 → 106; the other 12 carry an `ieee_draft` or an edition that the ISO face still drops. **PARG separator-in-capture, again (#471)**: the draft `revision` capture is `".12"`, and `Draft#to_s` adds its own dot, so `handle_draft` strips the leading dot (`D2022.10.12` rendered `D2022.10..12`). Check every capture a renderer re-joins with a separator. Locked by `spec/pubid/ieee/joint_stage_roundtrip_spec.rb` (stored index hashes → `parse(to_s) == row`).
100
+
101
+ - **IEEE parses through the edition-2 artifact's typed model bindings (the last converter wave)**: the three `Backend.parse` sites (`identifiers/base.rb` `parse_single`, `Aiee::Identifier.parse`, `Ire::Identifier.parse`) route through `Pubid::Parg::Model.bound` — the grammar's `bindings` block produces the builder-ready hash at the engine, replacing the tree normalization. The grammar side (pubid-grammar `grammars/{ieee,nesc}.parg` edition 2 + bindings, plus a class-ref inlining pass over the merged `aiee.parg`/`ire.parg`) keeps every capture the builder reads: leaf scalars bind `(string)`; the branch/wrapper captures the builder dispatches on (`draft`, `parameters`, `publishers`, `base`, `relationship_type`, `related_ids`, the aiee/ire/nesc wrappers, …) bind `(raw)` — raw subtrees carry `Parsanol::Slice` leaves whose `to_s`/`==` behave like strings, so `extract_value` and the `.is_a?(Hash)` probes are unchanged. **Load-bearing grammar deviations** (documented in the `.parg` headers): the zero-width markers are re-spelled as real-token captures (`printed_dash_year`/`printed_month_year` capture their branch's leading separator, `iec_label_dash` the dash, `iso_published` the whole joint head choice — every read sits behind a nil-`iso_stage` gate, so the wider presence set is inert exactly where v1's was narrow); the `([dash]) as draft_dash` / `([rev_sep] as rev_sep)` capture-over-OPTIONAL landmines are `[ (x) as y ]` (parsanol-ruby#394); nested-only captures that collide with a top-level name rename with the builder (`draft_date_month/year/day`, `draft_version_dash_*`, `fdraft_month/year`, and `reaffirmed_year` — unbound, because binding it would have surfaced the reaffirmation year v1 kept absent). **Class RULE refs (`digit`/`lower`/`upper`, and multi-char ones like `alnum_char`/`identifier_string`'s `non_nl`) materialize per-token named nodes inside captures when the runtime recompiles the `use`-importing source — the vendored `data/parg/{aiee,ire,nesc}.parg` copies are the live import sources, so they must be re-vendored together with the artifacts** (a stale `.parg` beside a fresh `.json` silently parses through the old grammar). **Builder accommodations** (all dual-key with the v1 spellings as fallback, so HEAD trees and bound maps read alike): the renamed nested keys; and the multi-segment draft-version normalization at the top of `build_single_identifier` — edition-2 trees materialize a "D2.1.1" designator as per-token nodes with no `:draft_version`, where v1 degraded to a whole-clause leaf (reconstructed: the leaf string → `Draft.parse` inverse) or to a date-only hash when a draft date follows (no draft built). **Measured**: fixture-corpus parity (old artifact + tree backend + builder vs new artifact + bound + builder) over all 9,054 pass-fixture inputs → 1 diff, and standalone aiee/ire/nesc sweeps → 0 diffs each. **The one residue is an engine wall, documented not chased**: `IEC/IEEE PC37.60/P62271-111_D6.1` (testsuite case `ieee.project_draft_identifier.0946`, one corpus input, one `draft_compact_convergence` example) — v1's edition-1 tree degraded its whole draft clause ("DP62271-111_D6.1, Aug 2016", two P-numbers plus date) into a single leaf, and edition-2's fully-named trees cannot reproduce that collapse at any binding spelling (isolated rule probes + programmatic branch bisect); the row is one of the two-P-number joint one-offs already recorded as deferred above. The conversion also **fixed** two testsuite rows (`ieee.project_draft_identifier.9263` "ISO/IEC/IEEE P42010.2019/D4" / "P42010.WD4:2019(E)" — the lettered `draft_iso_iteration` capture now binds, so the D= face composes), at the cost of the 0946 residue above.
@@ -35,7 +35,8 @@ module Pubid
35
35
 
36
36
  # Parse AIEE identifier string
37
37
  def self.parse(input)
38
- parsed = Parser.new.parse(input)
38
+ parsed = Pubid::Parg::Model.bound(:aiee, input,
39
+ entry: "aiee_identifier")
39
40
  Builder.new.build(parsed)
40
41
  end
41
42
 
@@ -5,7 +5,6 @@ module Pubid
5
5
  module Aiee
6
6
  autoload :Builder, "#{__dir__}/aiee/builder"
7
7
  autoload :Identifier, "#{__dir__}/aiee/identifier"
8
- autoload :Parser, "#{__dir__}/aiee/parser"
9
8
  end
10
9
  end
11
10
  end