pubid 2.0.0.pre.alpha.8 → 2.0.0.pre.alpha.11

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 (672) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +33 -11
  3. data/conformance/pending.yaml +4 -0
  4. data/data/bipm/update_codes.yaml +9 -0
  5. data/data/iec/update_codes.yaml +3 -0
  6. data/data/ieee/update_codes.yaml +107 -1
  7. data/{archived-gems/pubid-nist → data/nist}/series.yaml +34 -0
  8. data/data/nist/update_codes.yaml +8 -0
  9. data/lib/pubid/adobe/builder.rb +52 -0
  10. data/lib/pubid/adobe/identifier.rb +47 -0
  11. data/lib/pubid/adobe/identifiers/publication.rb +31 -0
  12. data/lib/pubid/adobe/identifiers/tech_note.rb +32 -0
  13. data/lib/pubid/adobe/identifiers.rb +10 -0
  14. data/lib/pubid/adobe/parser.rb +136 -0
  15. data/lib/pubid/adobe/renderer.rb +39 -0
  16. data/lib/pubid/adobe/urn_generator.rb +42 -0
  17. data/lib/pubid/adobe/urn_parser.rb +69 -0
  18. data/lib/pubid/adobe.rb +61 -0
  19. data/lib/pubid/amca/builder.rb +4 -4
  20. data/lib/pubid/amca/identifier.rb +1 -3
  21. data/lib/pubid/amca/identifiers/base.rb +50 -33
  22. data/lib/pubid/amca/identifiers/interpretation.rb +18 -10
  23. data/lib/pubid/amca/identifiers/publication.rb +14 -10
  24. data/lib/pubid/amca/identifiers/standard.rb +3 -1
  25. data/lib/pubid/amca/identifiers.rb +0 -1
  26. data/lib/pubid/amca/parser.rb +1 -1
  27. data/lib/pubid/amca/renderer.rb +4 -4
  28. data/lib/pubid/amca/single_identifier.rb +1 -1
  29. data/lib/pubid/amca/urn_generator.rb +2 -2
  30. data/lib/pubid/amca.rb +5 -4
  31. data/lib/pubid/ansi/builder.rb +2 -2
  32. data/lib/pubid/ansi/identifier.rb +18 -0
  33. data/lib/pubid/ansi/parser.rb +1 -1
  34. data/lib/pubid/ansi/renderer.rb +2 -2
  35. data/lib/pubid/ansi.rb +5 -5
  36. data/lib/pubid/api/builder.rb +16 -2
  37. data/lib/pubid/api/identifier.rb +25 -4
  38. data/lib/pubid/api/identifiers/mpms.rb +10 -8
  39. data/lib/pubid/api/parser.rb +1 -1
  40. data/lib/pubid/api/renderer.rb +16 -7
  41. data/lib/pubid/api/single_identifier.rb +5 -12
  42. data/lib/pubid/api.rb +1 -0
  43. data/lib/pubid/ashrae/builder.rb +53 -32
  44. data/lib/pubid/ashrae/identifier.rb +3 -4
  45. data/lib/pubid/ashrae/identifiers/addenda_package.rb +7 -1
  46. data/lib/pubid/ashrae/identifiers/addendum.rb +9 -1
  47. data/lib/pubid/ashrae/identifiers/base.rb +94 -12
  48. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +8 -1
  49. data/lib/pubid/ashrae/identifiers/errata.rb +9 -0
  50. data/lib/pubid/ashrae/identifiers/guideline.rb +3 -0
  51. data/lib/pubid/ashrae/identifiers/interpretation.rb +16 -0
  52. data/lib/pubid/ashrae/identifiers/standard.rb +3 -0
  53. data/lib/pubid/ashrae/identifiers.rb +0 -1
  54. data/lib/pubid/ashrae/parser.rb +37 -17
  55. data/lib/pubid/ashrae/renderer.rb +20 -20
  56. data/lib/pubid/ashrae/single_identifier.rb +1 -1
  57. data/lib/pubid/ashrae/supplement_identifier.rb +21 -6
  58. data/lib/pubid/ashrae/urn_generator.rb +8 -2
  59. data/lib/pubid/ashrae.rb +10 -4
  60. data/lib/pubid/asme/builder.rb +11 -2
  61. data/lib/pubid/asme/identifier.rb +9 -0
  62. data/lib/pubid/asme/identifiers/standard.rb +86 -2
  63. data/lib/pubid/asme/parser.rb +1 -1
  64. data/lib/pubid/asme/renderer.rb +3 -3
  65. data/lib/pubid/asme/single_identifier.rb +8 -1
  66. data/lib/pubid/asme/urn_generator.rb +2 -2
  67. data/lib/pubid/asme.rb +1 -0
  68. data/lib/pubid/astm/builder.rb +10 -3
  69. data/lib/pubid/astm/identifier.rb +9 -0
  70. data/lib/pubid/astm/identifiers/adjunct.rb +16 -1
  71. data/lib/pubid/astm/identifiers/code_number.rb +81 -0
  72. data/lib/pubid/astm/identifiers/data_series.rb +2 -0
  73. data/lib/pubid/astm/identifiers/iso_dual_published.rb +16 -0
  74. data/lib/pubid/astm/identifiers/manual.rb +10 -0
  75. data/lib/pubid/astm/identifiers/monograph.rb +2 -0
  76. data/lib/pubid/astm/identifiers/research_report.rb +10 -0
  77. data/lib/pubid/astm/identifiers/standard.rb +10 -0
  78. data/lib/pubid/astm/identifiers/technical_report.rb +2 -0
  79. data/lib/pubid/astm/identifiers/work_in_progress.rb +2 -0
  80. data/lib/pubid/astm/identifiers.rb +1 -0
  81. data/lib/pubid/astm/parser.rb +1 -1
  82. data/lib/pubid/astm/renderer.rb +1 -1
  83. data/lib/pubid/astm/single_identifier.rb +31 -1
  84. data/lib/pubid/astm/urn_generator.rb +7 -5
  85. data/lib/pubid/astm.rb +1 -0
  86. data/lib/pubid/bipm/builder.rb +163 -0
  87. data/lib/pubid/bipm/identifier.rb +285 -0
  88. data/lib/pubid/bipm/identifiers/committee_document.rb +36 -0
  89. data/lib/pubid/bipm/identifiers/guide.rb +35 -0
  90. data/lib/pubid/bipm/identifiers/meeting.rb +53 -0
  91. data/lib/pubid/bipm/identifiers/mep.rb +33 -0
  92. data/lib/pubid/bipm/identifiers/metrologia_article.rb +48 -0
  93. data/lib/pubid/bipm/identifiers/si_brochure.rb +33 -0
  94. data/lib/pubid/bipm/identifiers.rb +15 -0
  95. data/lib/pubid/bipm/parser.rb +237 -0
  96. data/lib/pubid/bipm/renderer.rb +118 -0
  97. data/lib/pubid/bipm/urn_generator.rb +58 -0
  98. data/lib/pubid/bipm/urn_parser.rb +60 -0
  99. data/lib/pubid/bipm.rb +92 -0
  100. data/lib/pubid/bsi/builder.rb +62 -52
  101. data/lib/pubid/bsi/identifier.rb +0 -1
  102. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -2
  103. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +36 -7
  104. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +7 -6
  105. data/lib/pubid/bsi/identifiers/amendment.rb +4 -4
  106. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +0 -1
  107. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +10 -0
  108. data/lib/pubid/bsi/identifiers/committee_document.rb +10 -1
  109. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +6 -0
  110. data/lib/pubid/bsi/identifiers/corrigendum.rb +4 -4
  111. data/lib/pubid/bsi/identifiers/expert_commentary.rb +5 -5
  112. data/lib/pubid/bsi/identifiers/handbook.rb +0 -2
  113. data/lib/pubid/bsi/identifiers/practice_guide.rb +0 -1
  114. data/lib/pubid/bsi/identifiers/set.rb +11 -0
  115. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +10 -1
  116. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -2
  117. data/lib/pubid/bsi/identifiers/value_added_publication.rb +6 -6
  118. data/lib/pubid/bsi/parser.rb +1 -1
  119. data/lib/pubid/bsi/renderer.rb +71 -59
  120. data/lib/pubid/bsi/single_identifier.rb +64 -7
  121. data/lib/pubid/bsi/urn_generator.rb +11 -2
  122. data/lib/pubid/bsi.rb +7 -1
  123. data/lib/pubid/builder/base.rb +23 -11
  124. data/lib/pubid/bundled_identifier.rb +19 -9
  125. data/lib/pubid/calconnect/builder.rb +38 -0
  126. data/lib/pubid/calconnect/identifier.rb +121 -0
  127. data/lib/pubid/calconnect/identifiers/standard.rb +29 -0
  128. data/lib/pubid/calconnect/identifiers.rb +9 -0
  129. data/lib/pubid/calconnect/parser.rb +54 -0
  130. data/lib/pubid/calconnect/renderer.rb +36 -0
  131. data/lib/pubid/calconnect/urn_generator.rb +33 -0
  132. data/lib/pubid/calconnect/urn_parser.rb +34 -0
  133. data/lib/pubid/calconnect.rb +83 -0
  134. data/lib/pubid/ccsds/builder.rb +1 -1
  135. data/lib/pubid/ccsds/identifier.rb +10 -3
  136. data/lib/pubid/ccsds/identifiers/base.rb +4 -2
  137. data/lib/pubid/ccsds/identifiers/corrigendum.rb +4 -4
  138. data/lib/pubid/ccsds/parser.rb +1 -1
  139. data/lib/pubid/ccsds/single_identifier.rb +2 -2
  140. data/lib/pubid/ccsds/supplement_identifier.rb +6 -6
  141. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  142. data/lib/pubid/ccsds.rb +1 -0
  143. data/lib/pubid/cen_cenelec/builder.rb +131 -72
  144. data/lib/pubid/cen_cenelec/identifier.rb +115 -3
  145. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +27 -16
  146. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +46 -6
  147. data/lib/pubid/cen_cenelec/identifiers/base.rb +8 -9
  148. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +1 -1
  149. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +1 -1
  150. data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +1 -1
  151. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +29 -14
  152. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +47 -8
  153. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +60 -3
  154. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +27 -2
  155. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +1 -1
  156. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +15 -5
  157. data/lib/pubid/cen_cenelec/identifiers/guide.rb +1 -1
  158. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +1 -1
  159. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +1 -1
  160. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +1 -1
  161. data/lib/pubid/cen_cenelec/parser.rb +1 -1
  162. data/lib/pubid/cen_cenelec/renderer.rb +55 -60
  163. data/lib/pubid/cen_cenelec/single_identifier.rb +20 -2
  164. data/lib/pubid/cen_cenelec/urn_generator.rb +66 -44
  165. data/lib/pubid/cen_cenelec.rb +104 -82
  166. data/lib/pubid/cie/builder.rb +149 -24
  167. data/lib/pubid/cie/identifier.rb +13 -4
  168. data/lib/pubid/cie/identifiers/bundle.rb +35 -5
  169. data/lib/pubid/cie/identifiers/code_attributes.rb +52 -0
  170. data/lib/pubid/cie/identifiers/conference.rb +11 -6
  171. data/lib/pubid/cie/identifiers/corrigendum.rb +17 -23
  172. data/lib/pubid/cie/identifiers/dual_published.rb +6 -6
  173. data/lib/pubid/cie/identifiers/identical.rb +9 -9
  174. data/lib/pubid/cie/identifiers/joint_published.rb +10 -10
  175. data/lib/pubid/cie/identifiers/proceedings.rb +41 -0
  176. data/lib/pubid/cie/identifiers/standard.rb +43 -8
  177. data/lib/pubid/cie/identifiers/supplement.rb +27 -25
  178. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +7 -3
  179. data/lib/pubid/cie/identifiers.rb +2 -0
  180. data/lib/pubid/cie/parser.rb +55 -6
  181. data/lib/pubid/cie/single_identifier.rb +40 -1
  182. data/lib/pubid/cie/supplement_identifier.rb +29 -16
  183. data/lib/pubid/cie/urn_generator.rb +11 -8
  184. data/lib/pubid/cie.rb +7 -2
  185. data/lib/pubid/components/date.rb +21 -5
  186. data/lib/pubid/conformance/checks.rb +72 -0
  187. data/lib/pubid/conformance/corpus/case.rb +55 -0
  188. data/lib/pubid/conformance/corpus.rb +36 -0
  189. data/lib/pubid/conformance/generator.rb +212 -0
  190. data/lib/pubid/conformance/pending.rb +63 -0
  191. data/lib/pubid/conformance/runner.rb +153 -0
  192. data/lib/pubid/conformance.rb +55 -0
  193. data/lib/pubid/core.rb +2 -0
  194. data/lib/pubid/csa/builder.rb +48 -48
  195. data/lib/pubid/csa/composite_identifier.rb +18 -7
  196. data/lib/pubid/csa/identifier.rb +187 -80
  197. data/lib/pubid/csa/identifiers/bundled.rb +25 -9
  198. data/lib/pubid/csa/identifiers/canadian_adopted.rb +13 -13
  199. data/lib/pubid/csa/identifiers/cec.rb +44 -4
  200. data/lib/pubid/csa/identifiers/combined.rb +97 -69
  201. data/lib/pubid/csa/identifiers/csa_adopted.rb +4 -4
  202. data/lib/pubid/csa/identifiers/package.rb +4 -4
  203. data/lib/pubid/csa/parser.rb +12 -8
  204. data/lib/pubid/csa/renderer.rb +13 -5
  205. data/lib/pubid/csa/single_identifier.rb +93 -4
  206. data/lib/pubid/csa/urn_generator.rb +9 -2
  207. data/lib/pubid/csa/wrapper_identifier.rb +43 -10
  208. data/lib/pubid/csa.rb +7 -1
  209. data/lib/pubid/doi/builder.rb +18 -0
  210. data/lib/pubid/doi/identifier.rb +49 -0
  211. data/lib/pubid/doi/identifiers/resource.rb +30 -0
  212. data/lib/pubid/doi/identifiers.rb +9 -0
  213. data/lib/pubid/doi/parser.rb +52 -0
  214. data/lib/pubid/doi/renderer.rb +13 -0
  215. data/lib/pubid/doi.rb +56 -0
  216. data/lib/pubid/easc/builder.rb +55 -0
  217. data/lib/pubid/easc/identifier.rb +59 -0
  218. data/lib/pubid/easc/identifiers/pmg.rb +20 -0
  219. data/lib/pubid/easc/identifiers/rmg.rb +19 -0
  220. data/lib/pubid/easc/identifiers.rb +10 -0
  221. data/lib/pubid/easc/parser.rb +88 -0
  222. data/lib/pubid/easc/renderer.rb +48 -0
  223. data/lib/pubid/easc/urn_generator.rb +46 -0
  224. data/lib/pubid/easc/urn_parser.rb +57 -0
  225. data/lib/pubid/easc.rb +53 -0
  226. data/lib/pubid/ecma/builder.rb +45 -0
  227. data/lib/pubid/ecma/identifier.rb +147 -0
  228. data/lib/pubid/ecma/identifiers/memento.rb +30 -0
  229. data/lib/pubid/ecma/identifiers/standard.rb +31 -0
  230. data/lib/pubid/ecma/identifiers/technical_report.rb +31 -0
  231. data/lib/pubid/ecma/identifiers.rb +11 -0
  232. data/lib/pubid/ecma/parser.rb +76 -0
  233. data/lib/pubid/ecma/renderer.rb +67 -0
  234. data/lib/pubid/ecma/urn_generator.rb +46 -0
  235. data/lib/pubid/ecma/urn_parser.rb +51 -0
  236. data/lib/pubid/ecma.rb +68 -0
  237. data/lib/pubid/errors.rb +80 -0
  238. data/lib/pubid/etsi/builder.rb +13 -4
  239. data/lib/pubid/etsi/identifier.rb +1 -3
  240. data/lib/pubid/etsi/identifiers/base.rb +43 -11
  241. data/lib/pubid/etsi/identifiers/etsi_standard.rb +207 -4
  242. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +45 -3
  243. data/lib/pubid/etsi/identifiers.rb +0 -1
  244. data/lib/pubid/etsi/parser.rb +9 -3
  245. data/lib/pubid/etsi/renderer.rb +8 -2
  246. data/lib/pubid/etsi.rb +6 -5
  247. data/lib/pubid/evs/builder.rb +26 -0
  248. data/lib/pubid/evs/identifier.rb +37 -0
  249. data/lib/pubid/evs/identifiers/national_adoption.rb +17 -0
  250. data/lib/pubid/evs/identifiers.rb +9 -0
  251. data/lib/pubid/evs/parser.rb +27 -0
  252. data/lib/pubid/evs/renderer.rb +30 -0
  253. data/lib/pubid/evs/urn_generator.rb +30 -0
  254. data/lib/pubid/evs/urn_parser.rb +80 -0
  255. data/lib/pubid/evs.rb +90 -0
  256. data/lib/pubid/export/exporter.rb +2 -1
  257. data/lib/pubid/export/flavor_exporter.rb +18 -3
  258. data/lib/pubid/export.rb +1 -0
  259. data/lib/pubid/format_detector.rb +1 -0
  260. data/lib/pubid/gb/builder.rb +45 -0
  261. data/lib/pubid/gb/identifier.rb +67 -0
  262. data/lib/pubid/gb/identifiers/standard.rb +34 -0
  263. data/lib/pubid/gb/identifiers.rb +9 -0
  264. data/lib/pubid/gb/parser.rb +63 -0
  265. data/lib/pubid/gb/renderer.rb +35 -0
  266. data/lib/pubid/gb.rb +88 -0
  267. data/lib/pubid/gost/builder.rb +185 -0
  268. data/lib/pubid/gost/identifier.rb +47 -0
  269. data/lib/pubid/gost/identifiers/foreign_reference.rb +25 -0
  270. data/lib/pubid/gost/identifiers/harmonized.rb +39 -0
  271. data/lib/pubid/gost/identifiers/identical_adoption.rb +39 -0
  272. data/lib/pubid/gost/identifiers/interstate_standard.rb +20 -0
  273. data/lib/pubid/gost/identifiers/national_standard.rb +19 -0
  274. data/lib/pubid/gost/identifiers.rb +13 -0
  275. data/lib/pubid/gost/parser.rb +105 -0
  276. data/lib/pubid/gost/renderer.rb +48 -0
  277. data/lib/pubid/gost/urn_generator.rb +46 -0
  278. data/lib/pubid/gost/urn_parser.rb +52 -0
  279. data/lib/pubid/gost.rb +50 -0
  280. data/lib/pubid/iala/builder.rb +22 -27
  281. data/lib/pubid/iala/identifier.rb +36 -8
  282. data/lib/pubid/iala/identifiers/advice.rb +1 -1
  283. data/lib/pubid/iala/identifiers/annex.rb +10 -10
  284. data/lib/pubid/iala/identifiers/general_assembly.rb +5 -2
  285. data/lib/pubid/iala/identifiers/guideline.rb +3 -1
  286. data/lib/pubid/iala/identifiers/letter.rb +1 -1
  287. data/lib/pubid/iala/identifiers/manual.rb +3 -1
  288. data/lib/pubid/iala/identifiers/model_course.rb +3 -1
  289. data/lib/pubid/iala/identifiers/recommendation.rb +3 -1
  290. data/lib/pubid/iala/identifiers/report.rb +1 -1
  291. data/lib/pubid/iala/identifiers/resolution.rb +1 -1
  292. data/lib/pubid/iala/identifiers/standard.rb +3 -1
  293. data/lib/pubid/iala/identifiers.rb +0 -1
  294. data/lib/pubid/iala/parser.rb +10 -2
  295. data/lib/pubid/iala/renderer.rb +1 -1
  296. data/lib/pubid/iala/urn_generator.rb +1 -1
  297. data/lib/pubid/iala/urn_parser.rb +24 -3
  298. data/lib/pubid/iala.rb +5 -4
  299. data/lib/pubid/iana/builder.rb +22 -0
  300. data/lib/pubid/iana/identifier.rb +140 -0
  301. data/lib/pubid/iana/identifiers/registry.rb +69 -0
  302. data/lib/pubid/iana/identifiers.rb +9 -0
  303. data/lib/pubid/iana/parser.rb +38 -0
  304. data/lib/pubid/iana/renderer.rb +32 -0
  305. data/lib/pubid/iana/urn_generator.rb +19 -0
  306. data/lib/pubid/iana/urn_parser.rb +24 -0
  307. data/lib/pubid/iana.rb +70 -0
  308. data/lib/pubid/identifier.rb +797 -26
  309. data/lib/pubid/identifier_metadata.rb +1 -0
  310. data/lib/pubid/idf/builder.rb +4 -4
  311. data/lib/pubid/idf/identifier.rb +18 -9
  312. data/lib/pubid/idf/parser.rb +3 -3
  313. data/lib/pubid/idf/renderer.rb +5 -5
  314. data/lib/pubid/idf/supplement_identifier.rb +3 -3
  315. data/lib/pubid/idf/urn_generator.rb +1 -1
  316. data/lib/pubid/idf.rb +7 -1
  317. data/lib/pubid/iec/builder.rb +49 -32
  318. data/lib/pubid/iec/components.rb +0 -1
  319. data/lib/pubid/iec/identifier.rb +112 -77
  320. data/lib/pubid/iec/identifiers/amendment.rb +6 -2
  321. data/lib/pubid/iec/identifiers/base.rb +2 -2
  322. data/lib/pubid/iec/identifiers/component_specification.rb +0 -10
  323. data/lib/pubid/iec/identifiers/conformity_assessment.rb +0 -10
  324. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +6 -0
  325. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -2
  326. data/lib/pubid/iec/identifiers/fragment_identifier.rb +13 -15
  327. data/lib/pubid/iec/identifiers/guide.rb +0 -16
  328. data/lib/pubid/iec/identifiers/international_standard.rb +22 -6
  329. data/lib/pubid/iec/identifiers/operational_document.rb +0 -10
  330. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +0 -12
  331. data/lib/pubid/iec/identifiers/sheet_identifier.rb +12 -12
  332. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +0 -10
  333. data/lib/pubid/iec/identifiers/systems_reference_document.rb +0 -10
  334. data/lib/pubid/iec/identifiers/technical_group.rb +30 -0
  335. data/lib/pubid/iec/identifiers/technical_report.rb +1 -18
  336. data/lib/pubid/iec/identifiers/technical_specification.rb +1 -18
  337. data/lib/pubid/iec/identifiers/technology_report.rb +0 -10
  338. data/lib/pubid/iec/identifiers/test_report_form.rb +0 -11
  339. data/lib/pubid/iec/identifiers/vap_identifier.rb +12 -12
  340. data/lib/pubid/iec/identifiers/white_paper.rb +0 -10
  341. data/lib/pubid/iec/identifiers/working_document.rb +24 -10
  342. data/lib/pubid/iec/identifiers.rb +1 -0
  343. data/lib/pubid/iec/parser.rb +53 -28
  344. data/lib/pubid/iec/renderer.rb +31 -18
  345. data/lib/pubid/iec/single_identifier.rb +34 -11
  346. data/lib/pubid/iec/supplement_identifier.rb +32 -19
  347. data/lib/pubid/iec/urn_generator.rb +227 -61
  348. data/lib/pubid/iec/urn_parser.rb +42 -4
  349. data/lib/pubid/iec.rb +2 -6
  350. data/lib/pubid/ieee/aiee/builder.rb +17 -3
  351. data/lib/pubid/ieee/aiee/identifier.rb +46 -62
  352. data/lib/pubid/ieee/aiee/parser.rb +1 -1
  353. data/lib/pubid/ieee/builder.rb +386 -69
  354. data/lib/pubid/ieee/compaction.rb +121 -0
  355. data/lib/pubid/ieee/components/draft.rb +47 -7
  356. data/lib/pubid/ieee/identifier.rb +1 -3
  357. data/lib/pubid/ieee/identifiers/adopted_standard.rb +62 -5
  358. data/lib/pubid/ieee/identifiers/amendment.rb +40 -0
  359. data/lib/pubid/ieee/identifiers/base.rb +148 -18
  360. data/lib/pubid/ieee/identifiers/code_number.rb +82 -0
  361. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +6 -2
  362. data/lib/pubid/ieee/identifiers/corrigendum.rb +17 -2
  363. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +24 -3
  364. data/lib/pubid/ieee/identifiers/dual_identifier.rb +3 -3
  365. data/lib/pubid/ieee/identifiers/dual_published.rb +58 -3
  366. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +102 -5
  367. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +25 -1
  368. data/lib/pubid/ieee/identifiers/joint_development.rb +64 -15
  369. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +58 -6
  370. data/lib/pubid/ieee/identifiers/nesc/base.rb +90 -19
  371. data/lib/pubid/ieee/identifiers/nesc/draft.rb +20 -5
  372. data/lib/pubid/ieee/identifiers/nesc/edition.rb +32 -0
  373. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +16 -5
  374. data/lib/pubid/ieee/identifiers/nesc/redline.rb +11 -2
  375. data/lib/pubid/ieee/identifiers/nesc/standard.rb +18 -3
  376. data/lib/pubid/ieee/identifiers/nesc.rb +1 -0
  377. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +3 -3
  378. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +14 -6
  379. data/lib/pubid/ieee/identifiers/redlined_standard.rb +4 -4
  380. data/lib/pubid/ieee/identifiers/si_standard.rb +4 -1
  381. data/lib/pubid/ieee/identifiers/standard.rb +4 -1
  382. data/lib/pubid/ieee/identifiers/supplement_identifier.rb +26 -7
  383. data/lib/pubid/ieee/identifiers.rb +2 -1
  384. data/lib/pubid/ieee/ire/builder.rb +7 -6
  385. data/lib/pubid/ieee/ire/identifier.rb +48 -33
  386. data/lib/pubid/ieee/ire/parser.rb +1 -1
  387. data/lib/pubid/ieee/nesc/builder.rb +33 -20
  388. data/lib/pubid/ieee/nesc/parser.rb +16 -15
  389. data/lib/pubid/ieee/parser.rb +462 -44
  390. data/lib/pubid/ieee/pre_parser.rb +1 -1
  391. data/lib/pubid/ieee/renderer.rb +158 -57
  392. data/lib/pubid/ieee/typed_stages.rb +12 -1
  393. data/lib/pubid/ieee/urn_generator.rb +35 -8
  394. data/lib/pubid/ieee.rb +63 -4
  395. data/lib/pubid/ieee_debug.rb +1 -0
  396. data/lib/pubid/ietf/builder.rb +78 -0
  397. data/lib/pubid/ietf/identifier.rb +5 -0
  398. data/lib/pubid/ietf/identifiers/base.rb +72 -0
  399. data/lib/pubid/ietf/identifiers/bcp.rb +36 -0
  400. data/lib/pubid/ietf/identifiers/fyi.rb +36 -0
  401. data/lib/pubid/ietf/identifiers/internet_draft.rb +45 -0
  402. data/lib/pubid/ietf/identifiers/rfc.rb +27 -0
  403. data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
  404. data/lib/pubid/ietf/identifiers/std.rb +36 -0
  405. data/lib/pubid/ietf/identifiers.rb +14 -0
  406. data/lib/pubid/ietf/parser.rb +61 -0
  407. data/lib/pubid/ietf/renderer.rb +64 -0
  408. data/lib/pubid/ietf/urn_generator.rb +37 -0
  409. data/lib/pubid/ietf/urn_parser.rb +43 -0
  410. data/lib/pubid/ietf.rb +86 -0
  411. data/lib/pubid/iho/identifier.rb +1 -3
  412. data/lib/pubid/iho/identifiers/base.rb +11 -10
  413. data/lib/pubid/iho/identifiers/bibliographic.rb +1 -1
  414. data/lib/pubid/iho/identifiers/circular_letter.rb +1 -1
  415. data/lib/pubid/iho/identifiers/miscellaneous.rb +1 -1
  416. data/lib/pubid/iho/identifiers/publication.rb +1 -1
  417. data/lib/pubid/iho/identifiers/standard.rb +1 -1
  418. data/lib/pubid/iho/identifiers.rb +0 -1
  419. data/lib/pubid/iho/parser.rb +1 -1
  420. data/lib/pubid/iho.rb +8 -7
  421. data/lib/pubid/isbn/builder.rb +44 -0
  422. data/lib/pubid/isbn/check_digit.rb +53 -0
  423. data/lib/pubid/isbn/identifier.rb +81 -0
  424. data/lib/pubid/isbn/identifiers/book.rb +30 -0
  425. data/lib/pubid/isbn/identifiers.rb +9 -0
  426. data/lib/pubid/isbn/parser.rb +45 -0
  427. data/lib/pubid/isbn/renderer.rb +16 -0
  428. data/lib/pubid/isbn.rb +53 -0
  429. data/lib/pubid/iso/builder.rb +9 -4
  430. data/lib/pubid/iso/bundled_identifier.rb +5 -3
  431. data/lib/pubid/iso/combined_identifier.rb +6 -4
  432. data/lib/pubid/iso/identifier.rb +29 -8
  433. data/lib/pubid/iso/identifiers/directives_supplement.rb +12 -12
  434. data/lib/pubid/iso/normalizer.rb +2 -2
  435. data/lib/pubid/iso/parser.rb +17 -13
  436. data/lib/pubid/iso/supplement_identifier.rb +19 -6
  437. data/lib/pubid/iso/urn_generator.rb +4 -1
  438. data/lib/pubid/iso/urn_parser.rb +1 -1
  439. data/lib/pubid/iso.rb +7 -1
  440. data/lib/pubid/itu/builder.rb +230 -29
  441. data/lib/pubid/itu/components/code.rb +48 -5
  442. data/lib/pubid/itu/components/designation.rb +35 -0
  443. data/lib/pubid/itu/components.rb +1 -0
  444. data/lib/pubid/itu/identifier.rb +1 -3
  445. data/lib/pubid/itu/identifiers/addendum.rb +15 -0
  446. data/lib/pubid/itu/identifiers/amendment.rb +7 -29
  447. data/lib/pubid/itu/identifiers/annex.rb +13 -2
  448. data/lib/pubid/itu/identifiers/annex_of_recommendation.rb +87 -0
  449. data/lib/pubid/itu/identifiers/appendix_of_recommendation.rb +92 -0
  450. data/lib/pubid/itu/identifiers/base.rb +357 -25
  451. data/lib/pubid/itu/identifiers/combined_identifier.rb +99 -23
  452. data/lib/pubid/itu/identifiers/corrigendum.rb +16 -23
  453. data/lib/pubid/itu/identifiers/errata.rb +15 -0
  454. data/lib/pubid/itu/identifiers/handbook.rb +38 -0
  455. data/lib/pubid/itu/identifiers/question.rb +63 -0
  456. data/lib/pubid/itu/identifiers/recommendation.rb +3 -2
  457. data/lib/pubid/itu/identifiers/report.rb +39 -0
  458. data/lib/pubid/itu/identifiers/special_publication.rb +3 -1
  459. data/lib/pubid/itu/identifiers/standard_serialization.rb +58 -0
  460. data/lib/pubid/itu/identifiers/supplement.rb +119 -14
  461. data/lib/pubid/itu/identifiers.rb +10 -1
  462. data/lib/pubid/itu/model.rb +1 -1
  463. data/lib/pubid/itu/parser.rb +481 -27
  464. data/lib/pubid/itu/urn_generator.rb +36 -6
  465. data/lib/pubid/itu/urn_parser.rb +8 -0
  466. data/lib/pubid/itu.rb +12 -3
  467. data/lib/pubid/jcgm/builder.rb +24 -14
  468. data/lib/pubid/jcgm/identifier.rb +10 -0
  469. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -2
  470. data/lib/pubid/jcgm/identifiers/corrigendum.rb +34 -0
  471. data/lib/pubid/jcgm/identifiers/gum_guide.rb +3 -3
  472. data/lib/pubid/jcgm/identifiers/meeting.rb +47 -0
  473. data/lib/pubid/jcgm/identifiers.rb +2 -0
  474. data/lib/pubid/jcgm/parser.rb +74 -7
  475. data/lib/pubid/jcgm/renderer.rb +33 -12
  476. data/lib/pubid/jcgm/single_identifier.rb +84 -6
  477. data/lib/pubid/jcgm/supplement_identifier.rb +39 -4
  478. data/lib/pubid/jcgm/urn_generator.rb +21 -13
  479. data/lib/pubid/jcgm/urn_parser.rb +164 -10
  480. data/lib/pubid/jcgm.rb +10 -0
  481. data/lib/pubid/jis/identifier.rb +62 -3
  482. data/lib/pubid/jis/parser.rb +1 -1
  483. data/lib/pubid/jis.rb +1 -0
  484. data/lib/pubid/nist/builder.rb +29 -9
  485. data/lib/pubid/nist/caster.rb +7 -45
  486. data/lib/pubid/nist/circular_supplement_builder.rb +7 -5
  487. data/lib/pubid/nist/components/stage.rb +2 -2
  488. data/lib/pubid/nist/components/supplement.rb +5 -2
  489. data/lib/pubid/nist/configuration.rb +6 -2
  490. data/lib/pubid/nist/identifier.rb +1 -3
  491. data/lib/pubid/nist/identifiers/base.rb +133 -39
  492. data/lib/pubid/nist/identifiers/circular.rb +10 -3
  493. data/lib/pubid/nist/identifiers/circular_supplement.rb +14 -5
  494. data/lib/pubid/nist/identifiers/commercial_standard.rb +1 -1
  495. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
  496. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +8 -2
  497. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -2
  498. data/lib/pubid/nist/identifiers/dated_document.rb +1 -1
  499. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +1 -1
  500. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +1 -1
  501. data/lib/pubid/nist/identifiers/handbook.rb +10 -3
  502. data/lib/pubid/nist/identifiers/internal_report.rb +13 -6
  503. data/lib/pubid/nist/identifiers/letter_circular.rb +1 -1
  504. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +15 -7
  505. data/lib/pubid/nist/identifiers/monograph.rb +15 -8
  506. data/lib/pubid/nist/identifiers/ncstar.rb +2 -2
  507. data/lib/pubid/nist/identifiers/nsrds.rb +1 -1
  508. data/lib/pubid/nist/identifiers/owmwp.rb +1 -1
  509. data/lib/pubid/nist/identifiers/report.rb +15 -7
  510. data/lib/pubid/nist/identifiers/special_publication.rb +10 -1
  511. data/lib/pubid/nist/identifiers/technical_note.rb +1 -1
  512. data/lib/pubid/nist/identifiers.rb +0 -1
  513. data/lib/pubid/nist/parser.rb +27 -4
  514. data/lib/pubid/nist/preprocessor.rb +15 -0
  515. data/lib/pubid/nist/router.rb +2 -2
  516. data/lib/pubid/nist/series/ir.rb +0 -3
  517. data/lib/pubid/nist/supplement_identifier.rb +24 -9
  518. data/lib/pubid/nist.rb +19 -13
  519. data/lib/pubid/oasis/builder.rb +79 -0
  520. data/lib/pubid/oasis/identifier.rb +160 -0
  521. data/lib/pubid/oasis/identifiers/standard.rb +29 -0
  522. data/lib/pubid/oasis/identifiers.rb +9 -0
  523. data/lib/pubid/oasis/parser.rb +34 -0
  524. data/lib/pubid/oasis/renderer.rb +29 -0
  525. data/lib/pubid/oasis/urn_generator.rb +25 -0
  526. data/lib/pubid/oasis/urn_parser.rb +22 -0
  527. data/lib/pubid/oasis.rb +80 -0
  528. data/lib/pubid/ogc/builder.rb +33 -0
  529. data/lib/pubid/ogc/identifier.rb +81 -0
  530. data/lib/pubid/ogc/identifiers/document.rb +26 -0
  531. data/lib/pubid/ogc/identifiers.rb +10 -0
  532. data/lib/pubid/ogc/parser.rb +40 -0
  533. data/lib/pubid/ogc/renderer.rb +33 -0
  534. data/lib/pubid/ogc/urn_generator.rb +14 -0
  535. data/lib/pubid/ogc/urn_parser.rb +22 -0
  536. data/lib/pubid/ogc.rb +72 -0
  537. data/lib/pubid/oiml/builder.rb +36 -8
  538. data/lib/pubid/oiml/identifier.rb +9 -1
  539. data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
  540. data/lib/pubid/oiml/identifiers/bulletin.rb +36 -0
  541. data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
  542. data/lib/pubid/oiml/identifiers/document.rb +2 -0
  543. data/lib/pubid/oiml/identifiers/expert_report.rb +2 -0
  544. data/lib/pubid/oiml/identifiers/guide.rb +2 -0
  545. data/lib/pubid/oiml/identifiers/recommendation.rb +2 -0
  546. data/lib/pubid/oiml/identifiers/seminar_report.rb +2 -0
  547. data/lib/pubid/oiml/identifiers/vocabulary.rb +2 -0
  548. data/lib/pubid/oiml/identifiers.rb +1 -0
  549. data/lib/pubid/oiml/parser.rb +12 -13
  550. data/lib/pubid/oiml/renderer.rb +13 -13
  551. data/lib/pubid/oiml/single_identifier.rb +41 -37
  552. data/lib/pubid/oiml/supplement_identifier.rb +36 -9
  553. data/lib/pubid/oiml/urn_parser.rb +23 -6
  554. data/lib/pubid/oiml.rb +10 -0
  555. data/lib/pubid/omg/builder.rb +20 -0
  556. data/lib/pubid/omg/identifier.rb +61 -0
  557. data/lib/pubid/omg/identifiers/specification.rb +32 -0
  558. data/lib/pubid/omg/identifiers.rb +9 -0
  559. data/lib/pubid/omg/parser.rb +93 -0
  560. data/lib/pubid/omg/renderer.rb +31 -0
  561. data/lib/pubid/omg.rb +52 -0
  562. data/lib/pubid/parser/grammar.rb +74 -0
  563. data/lib/pubid/parser.rb +2 -0
  564. data/lib/pubid/parsers/mr_string.rb +120 -7
  565. data/lib/pubid/plateau/builder.rb +8 -4
  566. data/lib/pubid/plateau/identifier.rb +1 -3
  567. data/lib/pubid/plateau/identifiers/base.rb +1 -6
  568. data/lib/pubid/plateau/identifiers/handbook.rb +1 -1
  569. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  570. data/lib/pubid/plateau/identifiers.rb +0 -1
  571. data/lib/pubid/plateau/parser.rb +16 -6
  572. data/lib/pubid/plateau/renderer.rb +1 -1
  573. data/lib/pubid/plateau/supplement_identifier.rb +11 -11
  574. data/lib/pubid/plateau.rb +14 -4
  575. data/lib/pubid/prefixes_support.rb +1 -0
  576. data/lib/pubid/renderers/annotator.rb +233 -0
  577. data/lib/pubid/renderers/base.rb +13 -0
  578. data/lib/pubid/renderers/directives_renderer.rb +3 -3
  579. data/lib/pubid/renderers/human_readable.rb +6 -4
  580. data/lib/pubid/renderers/mr_string.rb +54 -6
  581. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  582. data/lib/pubid/renderers.rb +1 -0
  583. data/lib/pubid/rendering/numbering.rb +25 -7
  584. data/lib/pubid/rendering/supplement.rb +4 -4
  585. data/lib/pubid/rendering.rb +1 -0
  586. data/lib/pubid/sae/builder.rb +1 -1
  587. data/lib/pubid/sae/identifier.rb +1 -3
  588. data/lib/pubid/sae/identifiers/base.rb +19 -9
  589. data/lib/pubid/sae/identifiers.rb +0 -1
  590. data/lib/pubid/sae/parser.rb +1 -1
  591. data/lib/pubid/sae.rb +4 -3
  592. data/lib/pubid/schema/declaration.rb +33 -0
  593. data/lib/pubid/schema/error.rb +14 -0
  594. data/lib/pubid/schema/identifier_type.rb +23 -0
  595. data/lib/pubid/schema/loader.rb +117 -0
  596. data/lib/pubid/schema/typed_stage.rb +24 -0
  597. data/lib/pubid/schema.rb +25 -0
  598. data/lib/pubid/tgpp/builder.rb +41 -0
  599. data/lib/pubid/tgpp/identifier.rb +107 -0
  600. data/lib/pubid/tgpp/identifiers/technical_report.rb +32 -0
  601. data/lib/pubid/tgpp/identifiers/technical_specification.rb +33 -0
  602. data/lib/pubid/tgpp/identifiers.rb +11 -0
  603. data/lib/pubid/tgpp/parser.rb +78 -0
  604. data/lib/pubid/tgpp/renderer.rb +52 -0
  605. data/lib/pubid/tgpp/urn_generator.rb +39 -0
  606. data/lib/pubid/tgpp/urn_parser.rb +30 -0
  607. data/lib/pubid/tgpp.rb +84 -0
  608. data/lib/pubid/type_resolver.rb +74 -0
  609. data/lib/pubid/un/builder.rb +42 -0
  610. data/lib/pubid/un/identifier.rb +40 -0
  611. data/lib/pubid/un/identifiers/document.rb +24 -0
  612. data/lib/pubid/un/identifiers.rb +9 -0
  613. data/lib/pubid/un/parser.rb +25 -0
  614. data/lib/pubid/un/renderer.rb +11 -0
  615. data/lib/pubid/un.rb +47 -0
  616. data/lib/pubid/urn_parser/errors.rb +8 -1
  617. data/lib/pubid/urn_parser.rb +1 -0
  618. data/lib/pubid/utils.rb +1 -0
  619. data/lib/pubid/version.rb +1 -1
  620. data/lib/pubid/w3c/builder.rb +55 -0
  621. data/lib/pubid/w3c/identifier.rb +130 -0
  622. data/lib/pubid/w3c/identifiers/candidate_recommendation.rb +31 -0
  623. data/lib/pubid/w3c/identifiers/candidate_recommendation_draft.rb +31 -0
  624. data/lib/pubid/w3c/identifiers/draft_note.rb +31 -0
  625. data/lib/pubid/w3c/identifiers/note.rb +30 -0
  626. data/lib/pubid/w3c/identifiers/obsolete_recommendation.rb +31 -0
  627. data/lib/pubid/w3c/identifiers/proposed_edited_recommendation.rb +31 -0
  628. data/lib/pubid/w3c/identifiers/proposed_recommendation.rb +31 -0
  629. data/lib/pubid/w3c/identifiers/recommendation.rb +31 -0
  630. data/lib/pubid/w3c/identifiers/standard.rb +12 -0
  631. data/lib/pubid/w3c/identifiers/superseded_recommendation.rb +31 -0
  632. data/lib/pubid/w3c/identifiers/working_draft.rb +30 -0
  633. data/lib/pubid/w3c/identifiers.rb +25 -0
  634. data/lib/pubid/w3c/parser.rb +43 -0
  635. data/lib/pubid/w3c/renderer.rb +35 -0
  636. data/lib/pubid/w3c/urn_generator.rb +18 -0
  637. data/lib/pubid/w3c/urn_parser.rb +36 -0
  638. data/lib/pubid/w3c.rb +68 -0
  639. data/lib/pubid/xsf/builder.rb +17 -0
  640. data/lib/pubid/xsf/identifier.rb +66 -0
  641. data/lib/pubid/xsf/identifiers/xep.rb +31 -0
  642. data/lib/pubid/xsf/identifiers.rb +9 -0
  643. data/lib/pubid/xsf/parser.rb +38 -0
  644. data/lib/pubid/xsf/renderer.rb +23 -0
  645. data/lib/pubid/xsf/urn_generator.rb +13 -0
  646. data/lib/pubid/xsf/urn_parser.rb +18 -0
  647. data/lib/pubid/xsf.rb +82 -0
  648. data/lib/pubid.rb +424 -22
  649. data/lib/tasks/conformance.rake +34 -0
  650. data/lib/tasks/docs.rake +3 -3
  651. data/lib/tasks/schema.rake +88 -0
  652. data/schema/core/joint_prefixes.yaml +24 -0
  653. data/schema/iec.yaml +1017 -0
  654. data/schema/iso.yaml +1586 -0
  655. data/schema/schema.schema.yaml +96 -0
  656. metadata +241 -19
  657. data/archived-gems/pubid-ccsds/update_codes.yaml +0 -1
  658. data/archived-gems/pubid-iec/stages.yaml +0 -129
  659. data/archived-gems/pubid-iec/update_codes.yaml +0 -67
  660. data/archived-gems/pubid-ieee/update_codes.yaml +0 -104
  661. data/archived-gems/pubid-iso/stages.yaml +0 -106
  662. data/archived-gems/pubid-iso/update_codes.yaml +0 -4
  663. data/archived-gems/pubid-itu/i18n.yaml +0 -13
  664. data/archived-gems/pubid-itu/series.yaml +0 -42
  665. data/archived-gems/pubid-nist/publishers.yaml +0 -6
  666. data/archived-gems/pubid-nist/update_codes.yaml +0 -93
  667. data/archived-gems/pubid-plateau/update_codes.yaml +0 -6
  668. data/lib/pubid/cen_cenelec/supplement_identifier.rb +0 -48
  669. data/lib/pubid/cie/components/code.rb +0 -80
  670. data/lib/pubid/iala/identifiers/base.rb +0 -14
  671. data/lib/pubid/iec/components/code.rb +0 -36
  672. /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pubid"
4
+ require "parslet"
5
+
6
+ module Pubid
7
+ # Every failure pubid raises.
8
+ #
9
+ # The three classes below have three different superclasses, chosen so that
10
+ # code written against the old contract keeps working: relaton-cli rescues
11
+ # `Parslet::ParseFailed`, and the input guards have always raised
12
+ # `ArgumentError`. What unifies them is the marker module
13
+ # {Pubid::Errors::Error}, which every one of them includes, so a caller that
14
+ # wants "pubid could not do this" writes one rescue:
15
+ #
16
+ # begin
17
+ # Pubid::Iso.parse(reference)
18
+ # rescue Pubid::Errors::Error => e
19
+ # warn e.message
20
+ # end
21
+ #
22
+ # A URN failure deliberately does not inherit `Parslet::ParseFailed`: no
23
+ # grammar runs, so there is no parse failure to report.
24
+ module Errors
25
+ # Marker module included by every pubid error. Rescue this to catch all
26
+ # of them, whatever their superclass.
27
+ module Error; end
28
+
29
+ # A printed identifier could not be turned into an identifier object.
30
+ #
31
+ # Raised for a grammar rejection, and also for the few flavors that reject
32
+ # an input before the grammar runs (a CSA comment line, a bad ISBN check
33
+ # digit). Those synthetic failures carry no parslet cause, so
34
+ # {#parse_failure_cause} is nillable — check it before calling
35
+ # `ascii_tree` on it.
36
+ #
37
+ # v1's `Pubid::Core::Errors::ParseError` flattened the cause into the
38
+ # message and threw the object away. This one keeps it.
39
+ class ParseError < ::Parslet::ParseFailed
40
+ include Error
41
+
42
+ # The string that could not be parsed, when it is known.
43
+ # @return [String, nil]
44
+ attr_reader :input
45
+
46
+ # The flavor whose grammar rejected the input, lowercased ("iso").
47
+ #
48
+ # This is the flavor that actually ran, which is not always the one the
49
+ # caller named: `Pubid::Iso.parse("ITU-T G.711")` routes through the
50
+ # MR-string parser into ITU, and reports "itu".
51
+ # @return [String, nil]
52
+ attr_reader :flavor
53
+
54
+ # @param message [String]
55
+ # @param parse_failure_cause [Parslet::Cause, nil] parslet's structured
56
+ # cause, nil for a failure raised without running a grammar
57
+ # @param input [String, nil]
58
+ # @param flavor [String, nil]
59
+ def initialize(message, parse_failure_cause = nil, input: nil,
60
+ flavor: nil)
61
+ super(message, parse_failure_cause)
62
+ @input = input
63
+ @flavor = flavor
64
+ end
65
+ end
66
+
67
+ # A URN could not be turned into an identifier object.
68
+ class UrnParseError < ::StandardError
69
+ include Error
70
+ end
71
+
72
+ # The input was not a String, or was longer than {Pubid::MAX_INPUT_LENGTH}.
73
+ #
74
+ # Inherits `ArgumentError` because that is what the guards have always
75
+ # raised, and because the input is wrong in kind rather than unparseable.
76
+ class InvalidInputError < ::ArgumentError
77
+ include Error
78
+ end
79
+ end
80
+ end
@@ -52,9 +52,14 @@ module Pubid
52
52
  version = build_version(data)
53
53
  date = build_date(data)
54
54
 
55
+ # The code fields are stored as flat index columns on the leaf (see
56
+ # EtsiStandard) — `number` is what relaton-index keys on — so the Code
57
+ # object built above is unpacked rather than assigned.
55
58
  Identifiers::EtsiStandard.new(
56
59
  type: data[:type].to_s,
57
- code: code,
60
+ number: code.number,
61
+ minor: code.minor,
62
+ parts: code.parts || [],
58
63
  version: version,
59
64
  date: date,
60
65
  )
@@ -95,19 +100,23 @@ module Pubid
95
100
  end
96
101
 
97
102
  def build_version(data)
98
- # Handle both version and edition
103
+ # Handle both version and edition. A partial reference omits both, in
104
+ # which case version is left nil (not defaulted) so exclude/matches?
105
+ # treat it as a wildcard.
99
106
  if data[:version]
100
107
  Components::Version.new(version: data[:version].to_s,
101
108
  is_edition: false)
102
109
  elsif data[:edition]
103
110
  Components::Version.new(version: data[:edition].to_s,
104
111
  is_edition: true)
105
- else
106
- Components::Version.new(version: "1.0.0", is_edition: false)
107
112
  end
108
113
  end
109
114
 
110
115
  def build_date(data)
116
+ # A partial reference omits the date; leave it nil rather than building
117
+ # an empty Date, so the canonical to_hash drops it entirely.
118
+ return nil unless data[:year]
119
+
111
120
  Pubid::Components::Date.new(
112
121
  year: data[:year].to_s,
113
122
  month: data[:month].to_s,
@@ -1,6 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Pubid::Etsi::Identifier is the ETSI base class (a real Pubid::Identifier
4
- # subclass); its body, `.parse`, and the Identifiers::Base back-compat alias
5
- # live in identifiers/base.rb. This file just ensures it is loaded.
6
- require_relative "identifiers/base"
4
+ # subclass); its body and `.parse` live in identifiers/base.rb. This file just ensures it is loaded.
@@ -2,19 +2,27 @@
2
2
 
3
3
  module Pubid
4
4
  module Etsi
5
- # Base class for all ETSI identifiers. Canonical name Pubid::Etsi::Identifier
6
- # (Identifiers::Base is a back-compat alias); every concrete ETSI identifier
7
- # descends from it.
5
+ # Base class for all ETSI identifiers. Canonical name Pubid::Etsi::Identifier;
6
+ # every concrete ETSI identifier descends from it.
8
7
  class Identifier < ::Pubid::Identifier
8
+ # Let Parslet::ParseFailed propagate on a bad reference (matching ISO), so
9
+ # relaton-cli's `rescue Parslet::ParseFailed` fetch handler catches it
10
+ # instead of a bare RuntimeError.
9
11
  def self.parse(identifier)
12
+ unless identifier.is_a?(String)
13
+ raise Pubid::Errors::InvalidInputError,
14
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
15
+ end
16
+
17
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
18
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
19
+ end
20
+
10
21
  parsed = Parser.parse(identifier)
11
22
  Builder.build(parsed)
12
- rescue Parslet::ParseFailed => e
13
- raise "Failed to parse ETSI identifier '#{identifier}': #{e.message}"
14
23
  end
15
24
 
16
25
  attribute :type, :string
17
- attribute :code, Pubid::Etsi::Components::Code
18
26
  attribute :version, Pubid::Etsi::Components::Version
19
27
  attribute :date, Pubid::Components::Date
20
28
  # Stored as a plain string (always "ETSI") so it round-trips through
@@ -31,12 +39,36 @@ module Pubid
31
39
  version == other.version &&
32
40
  date == other.date
33
41
  end
34
- end
35
42
 
36
- module Identifiers
37
- # Backward-compatible alias: ETSI's base class used to be
38
- # Pubid::Etsi::Identifiers::Base. It is now Pubid::Etsi::Identifier.
39
- Base = Pubid::Etsi::Identifier
43
+ # The document code is composed from the split index columns declared on
44
+ # EtsiStandard (`number`/`minor`/`parts`). Returning nil here keeps `==`
45
+ # and the URN generator total for the abstract base and for a supplement
46
+ # whose own base is missing; EtsiStandard composes the real value and
47
+ # SupplementIdentifier delegates to its base.
48
+ def code
49
+ nil
50
+ end
51
+
52
+ # `parts` is a plain collection attribute on the leaf, so the base
53
+ # #exclude reaches it directly and nils it. It must come back as an EMPTY
54
+ # ARRAY instead: a part-less reference parses with `parts` defaulting to
55
+ # [], so a nil here would make `==` — and therefore #matches? — fail
56
+ # against exactly the reference this exclusion exists to match. Same
57
+ # "reset the whole cluster" rule recorded for CSA's year and IEEE's
58
+ # year/month/day in CLAUDE.md.
59
+ #
60
+ # This also covers supplements: the base #exclude recurses into the
61
+ # nested `base` identifier through exclude_from_nested, which re-enters
62
+ # this method on the inner EtsiStandard.
63
+ def exclude(*args)
64
+ result = super
65
+ part_keys = args & %i[part parts]
66
+ if !part_keys.empty? && result.respond_to?(:parts=)
67
+ result.parts = []
68
+ end
69
+ result
70
+ end
40
71
  end
72
+
41
73
  end
42
74
  end
@@ -4,15 +4,218 @@ module Pubid
4
4
  module Etsi
5
5
  module Identifiers
6
6
  # Single class for all ETSI standard types
7
- # Type is passed as parameter: EN, ES, EG, TS, ETR, ETS, I-ETS, TBR, TCRTR, NET, GR, GS, SR, TR, GTS
7
+ # Type is passed as parameter: EN, ES, EG, TS, ETR, ETS, I-ETS, TBR,
8
+ # TCRTR, NET, GR, GS, SR, TR, GTS
8
9
  # Format: ETSI TYPE CODE VERSION (DATE)
9
10
  # Examples:
10
11
  # ETSI GS ZSM 012 V1.1.1 (2022-12)
11
12
  # ETSI GR ZSM 009-3 V1.1.1 (2023-08)
12
13
  # ETSI GTS GSM 02.01 V5.5.0 (1999-01)
13
- class EtsiStandard < Base
14
- # Type is stored in @type attribute from Base
15
- # All rendering handled by Base class
14
+ class EtsiStandard < Identifier
15
+ # Type is stored in @type attribute from Identifier
16
+ # All rendering handled by Identifier class
17
+
18
+ # --- Index columns -------------------------------------------------
19
+ #
20
+ # relaton-index sorts and bsearches every row on `id.root.number.to_s`,
21
+ # so the document number must be reachable as `number`. ETSI used to
22
+ # keep it inside an Etsi::Components::Code under a `code` attribute,
23
+ # leaving the inherited `number` nil and every index row keyed "".
24
+ #
25
+ # The three Code fields are now plain sibling attributes, which is the
26
+ # shape the serialized hash ALREADY had — the converters below merely
27
+ # read them directly instead of reaching through `code`, so the wire
28
+ # format is byte-identical and relaton-data-etsi's published index-v2
29
+ # needs no regeneration.
30
+ #
31
+ # `number` holds the BARE number ("300 175"), never the part, so all
32
+ # parts of a document share one index bucket and a part-less reference
33
+ # finds them all — the IEEE/ISO semantics documented in CLAUDE.md.
34
+ #
35
+ # LANDMINE: these redeclare attributes inherited from ::Pubid::Identifier
36
+ # (`number` is a Components::Code there, and Etsi::Components::Code is
37
+ # NOT a subclass of it). That resolves nondeterministically under
38
+ # multi-flavor load when declared on a class others inherit from, so it
39
+ # is confined to this LEAF — EtsiStandard has no subclasses, while the
40
+ # shared Pubid::Etsi::Identifier is also SupplementIdentifier's parent
41
+ # and must stay untouched. spec/pubid/etsi/root_number_spec.rb carries
42
+ # the tripwire and is only meaningful under the full `rake` suite.
43
+ attribute :number, :string
44
+ attribute :minor, :string
45
+ attribute :parts, :string, collection: true, default: -> { [] }
46
+
47
+ # Compact serialization (mirrors ISO/JCGM/OIML): the code fields are
48
+ # bare scalars (`number`, a `parts` array and, rarely, a `minor`);
49
+ # Version flattens to a scalar `version` string with an `is_edition`
50
+ # boolean flag (omitted when false); Date flattens to top-level
51
+ # year/month/day. The constant `publisher` ("ETSI") is intentionally
52
+ # NOT mapped — it is reconstructed on load from its attribute default,
53
+ # keeping the hash compact.
54
+ #
55
+ # This block lives on EtsiStandard (a leaf) rather than the shared Identifier:
56
+ # SupplementIdentifier is a sibling that DELEGATES type/code/version and
57
+ # date to its inner `base`, so a block on Identifier would be inherited-and-
58
+ # merged by the supplement and re-emit every delegated field at the top.
59
+ key_value do
60
+ map "_type", to: :_type
61
+ map "type", to: :type
62
+ map "number", to: :number
63
+ map "parts", to: :parts
64
+ map "minor", to: :minor
65
+ map "version", with: { to: :version_to_kv, from: :version_from_kv }
66
+ map "is_edition", with: { to: :edition_to_kv, from: :edition_from_kv }
67
+ map "year", with: { to: :year_to_kv, from: :year_from_kv }
68
+ map "month", with: { to: :month_to_kv, from: :month_from_kv }
69
+ map "day", with: { to: :day_to_kv, from: :day_from_kv }
70
+ end
71
+
72
+ # The composed document code, rebuilt on demand from the split columns
73
+ # so the renderer, the URN generator and #== keep one place to ask for
74
+ # the printed form ("300 175-1"). Deliberately NOT an attribute and NOT
75
+ # memoised: `number`/`parts` are writable (the base #exclude rebuilds
76
+ # through them), so a cached Code would go stale.
77
+ #
78
+ # nil when there is no number, preserving the old nil-`code` semantics
79
+ # the URN generator branches on.
80
+ def code
81
+ return nil if number.nil?
82
+
83
+ Pubid::Etsi::Components::Code.new(
84
+ number: number,
85
+ minor: minor,
86
+ parts: parts || [],
87
+ )
88
+ end
89
+
90
+ # MR slug number segment.
91
+ #
92
+ # The base hook reads the inherited `number` and `part`; ETSI kept
93
+ # neither, so before the index columns landed every ETSI slug was just
94
+ # `etsi.<date>` — 454 distinct slugs for 24,724 documents, and
95
+ # `to_slug` is what consumers use as an output FILENAME.
96
+ #
97
+ # Two things the base hook cannot do for ETSI:
98
+ # * the parts live in the `parts` collection, not the inherited
99
+ # scalar `part`, so they must be appended here or every part of a
100
+ # document collapses onto one slug;
101
+ # * an ETSI number legitimately contains a SPACE ("300 175", "GSM
102
+ # 02.01"), which is outside the [a-z0-9.-] charset Renderers::MrString
103
+ # documents and guarantees. Sanitize BY CHARSET rather than by an
104
+ # enumerated escape list (the BIPM `mr_slug` precedent in
105
+ # CLAUDE.md), so a character added later cannot reach a filename.
106
+ # `minor` is included because it is identity-bearing everywhere else —
107
+ # Code#== compares it, Code#to_s renders it and the URN carries it — so
108
+ # omitting it here would let two distinct documents share one filename.
109
+ # No fixture populates it today; it is in the grammar, so it is here.
110
+ def mr_number_with_part
111
+ return nil if number.nil?
112
+
113
+ mr_sanitize([number, minor, *Array(parts)].compact.join("-"))
114
+ end
115
+
116
+ # ETSI's identity is type + code + version + date (see
117
+ # Pubid::Etsi::Identifier#==), so all four must reach the slug —
118
+ # CLAUDE.md's rule that an identity-bearing marker has to appear on
119
+ # every identity surface, not just in `==`. The base hooks find
120
+ # neither: `mr_type` reads `typed_stage` (ETSI has none) and
121
+ # `mr_edition` reads `edition.number` (ETSI models the edition as
122
+ # `version`). Without these, "ETSI EN 300 729 V6.1.1 (2000-04)",
123
+ # "…V7.1.1 (2000-04)" and "ETSI ETS 300 729 ed.2 (2000-04)" all share
124
+ # one slug — i.e. one output filename.
125
+ def mr_type
126
+ type&.to_s&.downcase
127
+ end
128
+
129
+ def mr_edition
130
+ mr_sanitize(version&.version)
131
+ end
132
+
133
+ # Segment sanitizer. Renderers::MrString joins SEGMENTS with ".", so a
134
+ # dot inside one would break that structure — hence "." is replaced
135
+ # here even though it is inside the renderer's overall charset (the
136
+ # BIPM `bipm.si-brochure.9e-v3-01.e` precedent in CLAUDE.md). Filtering
137
+ # by charset rather than by an enumerated escape list keeps a character
138
+ # introduced later from leaking into a filename.
139
+ #
140
+ # Public purely to keep this file's surface flat, next to the
141
+ # lutaml-invoked converters below — it has no external callers and
142
+ # would work as well private.
143
+ #
144
+ # The emptiness check is on the OUTPUT, not just the input: a value
145
+ # made entirely of characters outside the charset collapses to "-" and
146
+ # then to "", and an empty string is truthy in Ruby, so it would reach
147
+ # Renderers::MrString as a blank segment and produce a double dot in
148
+ # the joined slug. Unreachable from today's grammar, which only feeds
149
+ # digit/alnum captures here — but not structurally prevented.
150
+ def mr_sanitize(value)
151
+ return nil if value.nil? || value.to_s.empty?
152
+
153
+ sanitized = value.to_s.downcase
154
+ .gsub(/[^a-z0-9-]+/, "-").gsub(/\A-+|-+\z/, "")
155
+ sanitized.empty? ? nil : sanitized
156
+ end
157
+
158
+ # --- Version flattened to scalar version + is_edition flag ---
159
+ def version_to_kv(model, doc)
160
+ emit_kv(doc, "version", model.version&.version)
161
+ end
162
+
163
+ def version_from_kv(model, value)
164
+ version_for(model).version = value.to_s
165
+ end
166
+
167
+ def edition_to_kv(model, doc)
168
+ return unless model.version&.is_edition
169
+
170
+ doc.add_child(
171
+ Lutaml::KeyValue::DataModel::Element.new("is_edition", true),
172
+ )
173
+ end
174
+
175
+ def edition_from_kv(model, value)
176
+ version_for(model).is_edition = value
177
+ end
178
+
179
+ # --- Date flattened to top-level year/month/day scalars ---
180
+ def year_to_kv(model, doc)
181
+ emit_kv(doc, "year", model.date&.year)
182
+ end
183
+
184
+ def month_to_kv(model, doc)
185
+ emit_kv(doc, "month", model.date&.month)
186
+ end
187
+
188
+ def day_to_kv(model, doc)
189
+ emit_kv(doc, "day", model.date&.day)
190
+ end
191
+
192
+ def year_from_kv(model, value)
193
+ date_for(model).year = value.to_s
194
+ end
195
+
196
+ def month_from_kv(model, value)
197
+ date_for(model).month = value.to_s
198
+ end
199
+
200
+ def day_from_kv(model, value)
201
+ date_for(model).day = value.to_s
202
+ end
203
+
204
+ def emit_kv(doc, key, value)
205
+ return if value.nil? || value.to_s.empty?
206
+
207
+ doc.add_child(
208
+ Lutaml::KeyValue::DataModel::Element.new(key, value.to_s),
209
+ )
210
+ end
211
+
212
+ def version_for(model)
213
+ model.version ||= Pubid::Etsi::Components::Version.new
214
+ end
215
+
216
+ def date_for(model)
217
+ model.date ||= Pubid::Components::Date.new
218
+ end
16
219
  end
17
220
  end
18
221
  end
@@ -3,11 +3,43 @@
3
3
  module Pubid
4
4
  module Etsi
5
5
  module Identifiers
6
- # Base class for ETSI supplements (Amendment, Corrigendum)
7
- class SupplementIdentifier < Base
8
- attribute :base, Pubid::Etsi::Identifiers::Base
6
+ # Identifier class for ETSI supplements (Amendment, Corrigendum)
7
+ class SupplementIdentifier < Identifier
8
+ attribute :base, Pubid::Etsi::Identifier
9
9
  attribute :number, :integer
10
10
 
11
+ # Compact serialization: a supplement carries only its own ordinal
12
+ # `number` (A1 -> 1) and the nested base standard under the compact key
13
+ # `base`. type/code/version/date are delegated to `base` (methods below)
14
+ # and NOT re-emitted here, so the old redundant duplication is gone.
15
+ # This block is inherited unchanged by Amendment/Corrigendum.
16
+ key_value do
17
+ map "_type", to: :_type
18
+ map "number", to: :number
19
+ map "base", with: { to: :base_to_kv, from: :base_from_kv }
20
+ end
21
+
22
+ # Serialize the base via its own to_hash so it collapses to the compact
23
+ # EtsiStandard shape.
24
+ def base_to_kv(model, doc)
25
+ return unless model.base
26
+
27
+ doc.add_child(
28
+ Lutaml::KeyValue::DataModel::Element.new(
29
+ "base", model.base.to_hash
30
+ ),
31
+ )
32
+ end
33
+
34
+ # Re-dispatch through the flavor base so `_type` resolves to the
35
+ # concrete EtsiStandard; a bare polymorphic cast would rebuild a plain
36
+ # Identifier and lose the subclass (and its custom mappings). Mirrors JCGM.
37
+ def base_from_kv(model, value)
38
+ return unless value
39
+
40
+ model.base = Pubid::Etsi::Identifier.from_hash(value)
41
+ end
42
+
11
43
  # Inherit attributes from base
12
44
  def type
13
45
  base.type
@@ -56,6 +88,16 @@ module Pubid
56
88
  raise NotImplementedError
57
89
  end
58
90
 
91
+ # Make Renderers::MrString recurse into `base` instead of slugging the
92
+ # supplement flat. Without this the flat path reads the supplement's own
93
+ # `number` — its ordinal, 1 — and the base document is dropped entirely,
94
+ # so every "/C1" corrigendum published in one month shared the slug
95
+ # `etsi.1.<date>`. `to_slug` is an output FILENAME, so that is an
96
+ # overwrite. Same fix as ITU's AnnexOfRecommendation (see CLAUDE.md).
97
+ def mr_supplement_suffix
98
+ [supplement_notation.to_s.downcase, number].compact.join(".")
99
+ end
100
+
59
101
  def ==(other)
60
102
  return false unless other.is_a?(SupplementIdentifier)
61
103
  return false unless other.class == self.class
@@ -4,7 +4,6 @@ module Pubid
4
4
  module Etsi
5
5
  module Identifiers
6
6
  autoload :Amendment, "#{__dir__}/identifiers/amendment"
7
- autoload :Base, "#{__dir__}/identifiers/base"
8
7
  autoload :Corrigendum, "#{__dir__}/identifiers/corrigendum"
9
8
  autoload :EtsiStandard, "#{__dir__}/identifiers/etsi_standard"
10
9
  autoload :SupplementIdentifier,
@@ -4,7 +4,7 @@ require "parslet"
4
4
 
5
5
  module Pubid
6
6
  module Etsi
7
- class Parser < Parslet::Parser
7
+ class Parser < ::Pubid::Parser::Grammar
8
8
  # Basic elements
9
9
  rule(:digit) { match["0-9"] }
10
10
  rule(:digits) { digit.repeat(1) }
@@ -114,13 +114,19 @@ module Pubid
114
114
  end
115
115
 
116
116
  # Main identifier
117
+ #
118
+ # The mandatory core is `etsi_prefix type number` (+ optional
119
+ # minor/parts/supplements), mirroring ISO. The version/edition and date
120
+ # suffixes are optional so a partial reference (e.g. "ETSI GS ZSM 012")
121
+ # parses with version/date left nil. Each `.maybe` guards its own leading
122
+ # space so no trailing space is demanded when the suffix is absent.
117
123
  rule(:identifier) do
118
124
  etsi_prefix >>
119
125
  type >> space >>
120
126
  number >> minor.maybe >> parts >>
121
127
  supplements.maybe >>
122
- space >> version_or_edition >>
123
- space >> date_part
128
+ (space >> version_or_edition).maybe >>
129
+ (space >> date_part).maybe
124
130
  end
125
131
 
126
132
  rule(:root) { identifier }
@@ -27,7 +27,10 @@ module Pubid
27
27
 
28
28
  def render_base(id)
29
29
  result = "#{id.publisher} #{id.type} #{id.code}"
30
- result += " #{id.version} (#{id.date.render})"
30
+ # version/date are optional on partial references; append each only when
31
+ # present so a partial id renders without a stray " V… ()" suffix.
32
+ result += " #{id.version}" if id.version
33
+ result += " (#{id.date.render})" if id.date
31
34
  result
32
35
  end
33
36
 
@@ -35,7 +38,10 @@ module Pubid
35
38
  supplement_notations = id.collect_supplement_notations(id, [])
36
39
  actual_base = id.find_actual_base(id.base)
37
40
  code_with_supplements = "#{actual_base.code}#{supplement_notations.join}"
38
- "#{actual_base.publisher} #{actual_base.type} #{code_with_supplements} #{actual_base.version} (#{actual_base.date.render})"
41
+ result = "#{actual_base.publisher} #{actual_base.type} #{code_with_supplements}"
42
+ result += " #{actual_base.version}" if actual_base.version
43
+ result += " (#{actual_base.date.render})" if actual_base.date
44
+ result
39
45
  end
40
46
  end
41
47
  end
data/lib/pubid/etsi.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  require "lutaml/model"
4
5
 
5
6
  module Pubid
@@ -13,7 +14,7 @@ module Pubid
13
14
 
14
15
  autoload :Builder, "#{__dir__}/etsi/builder"
15
16
  autoload :Components, "#{__dir__}/etsi/components"
16
- autoload :Identifier, "#{__dir__}/etsi/identifier"
17
+ autoload :Identifier, "#{__dir__}/etsi/identifiers/base"
17
18
  autoload :Identifiers, "#{__dir__}/etsi/identifiers"
18
19
  autoload :Parser, "#{__dir__}/etsi/parser"
19
20
  autoload :Renderer, "#{__dir__}/etsi/renderer"
@@ -25,8 +26,8 @@ module Pubid
25
26
  end
26
27
 
27
28
  # Per-flavor format registry: inherits global formats, overrides :human
28
- Identifiers::Base.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
29
- Identifiers::Base.format_registry.register(:human, renderer: Etsi::Renderer)
29
+ Identifier.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
30
+ Identifier.format_registry.register(:human, renderer: Etsi::Renderer)
30
31
 
31
32
  # Auto-discover all identifier types from the Identifiers namespace
32
33
  # @return [Array<Class>] identifier classes (Pubid::Identifier subclasses)
@@ -34,9 +35,9 @@ module Pubid
34
35
  @identifier_types ||= Identifiers.constants
35
36
  .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
36
37
  .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
37
- # Exclude the flavor base itself by identity (Identifiers::Base is now an
38
+ # Exclude the flavor base itself by identity (Identifier is now an
38
39
  # alias for Pubid::Etsi::Identifier, so name-based matching misses it).
39
- .reject { |c| c == Identifiers::Base }
40
+ .reject { |c| c == Identifier }
40
41
  end
41
42
 
42
43
  # Build typed stage index from identifier types
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Evs
5
+ # Builds an EVS national adoption from the composed parse tree: the
6
+ # structured :adopted subtree (produced by the embedded CEN grammar) goes
7
+ # straight to the CEN/CENELEC builder as data — no string
8
+ # re-serialization anywhere.
9
+ class Builder < Pubid::Builder::Base
10
+ def self.build(parsed_data)
11
+ new.build(parsed_data)
12
+ end
13
+
14
+ def build(data)
15
+ data = flatten_array(data) if data.is_a?(Array)
16
+
17
+ adopted = Pubid::CenCenelec::Builder.build(data[:adopted])
18
+
19
+ Identifiers::NationalAdoption.new(
20
+ adopted_identifier: adopted,
21
+ separator: data[:evs_separator] || "-",
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Evs
5
+ # An EVS national adoption wraps a CEN identifier the same way BSI's
6
+ # AdoptedEuropeanNorm does — polymorphic `adopted_identifier` so the
7
+ # wrapped object stays a real Pubid::CenCenelec identifier.
8
+ #
9
+ # Examples:
10
+ # "EVS-EN 18216:2026" (adopted_identifier: EN 18216:2026)
11
+ # "EVS-EN ISO 14001:2026" (adopted_identifier: EN ISO 14001:2026)
12
+ # "EVS-EN ISO/IEC 27017:2026" (adopted_identifier: EN ISO/IEC 27017:2026)
13
+ # "EVS-EN ISO 9001:2015/A1:2024" (adopted_identifier: EN ISO 9001:2015/A1:2024)
14
+ class Identifier < ::Pubid::Identifier
15
+ attribute :adopted_identifier, ::Pubid::Identifier, polymorphic: true
16
+ # "-" or " " — preserves the printed separator ("EVS-EN" vs "EVS EN")
17
+ attribute :separator, :string, default: -> { "-" }
18
+
19
+ def to_s(**opts)
20
+ render(format: :human, **opts)
21
+ end
22
+
23
+ def self.parse(string)
24
+ unless string.is_a?(String)
25
+ raise Pubid::Errors::InvalidInputError,
26
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
27
+ end
28
+
29
+ if string.length > Pubid::MAX_INPUT_LENGTH
30
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
31
+ end
32
+
33
+ Pubid::Evs.parse(string)
34
+ end
35
+ end
36
+ end
37
+ end