pubid 2.0.0.pre.alpha.2 → 2.0.0.pre.alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +25 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +4 -55
  6. data/lib/pubid/amca/identifiers/base.rb +58 -47
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -21
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -17
  9. data/lib/pubid/amca/identifiers/standard.rb +0 -4
  10. data/lib/pubid/amca/renderer.rb +82 -0
  11. data/lib/pubid/amca/single_identifier.rb +0 -23
  12. data/lib/pubid/amca/urn_generator.rb +2 -1
  13. data/lib/pubid/amca/urn_parser.rb +28 -0
  14. data/lib/pubid/amca.rb +42 -1
  15. data/lib/pubid/ansi/builder.rb +5 -3
  16. data/lib/pubid/ansi/identifier.rb +1 -43
  17. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  18. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  19. data/lib/pubid/ansi/renderer.rb +53 -0
  20. data/lib/pubid/ansi/single_identifier.rb +2 -31
  21. data/lib/pubid/ansi/urn_generator.rb +3 -38
  22. data/lib/pubid/ansi/urn_parser.rb +23 -0
  23. data/lib/pubid/ansi.rb +38 -3
  24. data/lib/pubid/api/builder.rb +33 -74
  25. data/lib/pubid/api/identifier.rb +5 -52
  26. data/lib/pubid/api/identifiers/base.rb +2 -14
  27. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  28. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  29. data/lib/pubid/api/identifiers/mpms.rb +0 -20
  30. data/lib/pubid/api/identifiers/publication.rb +0 -2
  31. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  32. data/lib/pubid/api/identifiers/specification.rb +0 -2
  33. data/lib/pubid/api/identifiers/standard.rb +0 -2
  34. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  35. data/lib/pubid/api/identifiers/typeless_standard.rb +0 -16
  36. data/lib/pubid/api/identifiers.rb +18 -0
  37. data/lib/pubid/api/renderer.rb +89 -0
  38. data/lib/pubid/api/single_identifier.rb +5 -20
  39. data/lib/pubid/api/urn_generator.rb +0 -18
  40. data/lib/pubid/api/urn_parser.rb +35 -0
  41. data/lib/pubid/api.rb +51 -5
  42. data/lib/pubid/ashrae/builder.rb +3 -3
  43. data/lib/pubid/ashrae/identifier.rb +7 -55
  44. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  45. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  46. data/lib/pubid/ashrae/identifiers/base.rb +29 -15
  47. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  48. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  49. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  50. data/lib/pubid/ashrae/parser.rb +4 -0
  51. data/lib/pubid/ashrae/renderer.rb +117 -0
  52. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  53. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  54. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  55. data/lib/pubid/ashrae.rb +46 -1
  56. data/lib/pubid/asme/components/code.rb +10 -2
  57. data/lib/pubid/asme/identifier.rb +0 -46
  58. data/lib/pubid/asme/identifiers/base.rb +0 -60
  59. data/lib/pubid/asme/renderer.rb +66 -0
  60. data/lib/pubid/asme/single_identifier.rb +3 -1
  61. data/lib/pubid/asme/urn_parser.rb +31 -0
  62. data/lib/pubid/asme.rb +42 -1
  63. data/lib/pubid/astm/components/code.rb +9 -0
  64. data/lib/pubid/{jis → astm}/components.rb +1 -1
  65. data/lib/pubid/astm/identifier.rb +0 -77
  66. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  67. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  68. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  69. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  70. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  71. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  72. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  73. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  74. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  75. data/lib/pubid/astm/identifiers.rb +18 -0
  76. data/lib/pubid/astm/renderer.rb +172 -0
  77. data/lib/pubid/astm/single_identifier.rb +3 -11
  78. data/lib/pubid/astm/urn_parser.rb +30 -0
  79. data/lib/pubid/astm.rb +39 -27
  80. data/lib/pubid/bsi/builder.rb +21 -12
  81. data/lib/pubid/bsi/identifier.rb +5 -85
  82. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -36
  83. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +8 -48
  84. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +8 -39
  85. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +2 -55
  86. data/lib/pubid/bsi/identifiers/amendment.rb +2 -22
  87. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -6
  88. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  89. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -87
  90. data/lib/pubid/bsi/identifiers/committee_document.rb +0 -16
  91. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -87
  92. data/lib/pubid/bsi/identifiers/corrigendum.rb +2 -10
  93. data/lib/pubid/bsi/identifiers/detailed_specification.rb +0 -36
  94. data/lib/pubid/bsi/identifiers/disc.rb +0 -29
  95. data/lib/pubid/bsi/identifiers/draft_document.rb +2 -46
  96. data/lib/pubid/bsi/identifiers/electronic_book.rb +2 -38
  97. data/lib/pubid/bsi/identifiers/expert_commentary.rb +2 -18
  98. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +0 -47
  99. data/lib/pubid/bsi/identifiers/flex.rb +0 -35
  100. data/lib/pubid/bsi/identifiers/handbook.rb +1 -15
  101. data/lib/pubid/bsi/identifiers/index.rb +0 -32
  102. data/lib/pubid/bsi/identifiers/method.rb +0 -41
  103. data/lib/pubid/bsi/identifiers/national_annex.rb +4 -29
  104. data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -6
  105. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +2 -54
  106. data/lib/pubid/bsi/identifiers/published_document.rb +2 -54
  107. data/lib/pubid/bsi/identifiers/section.rb +0 -30
  108. data/lib/pubid/bsi/identifiers/set.rb +3 -20
  109. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +0 -9
  110. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -24
  111. data/lib/pubid/bsi/identifiers/supplementary_index.rb +0 -46
  112. data/lib/pubid/bsi/identifiers/technical_specification.rb +2 -47
  113. data/lib/pubid/bsi/identifiers/test_method.rb +0 -32
  114. data/lib/pubid/bsi/identifiers/value_added_publication.rb +2 -17
  115. data/lib/pubid/bsi/identifiers.rb +0 -1
  116. data/lib/pubid/bsi/renderer.rb +1050 -0
  117. data/lib/pubid/bsi/single_identifier.rb +33 -78
  118. data/lib/pubid/bsi/urn_generator.rb +2 -3
  119. data/lib/pubid/bsi/urn_parser.rb +52 -0
  120. data/lib/pubid/bsi.rb +232 -2
  121. data/lib/pubid/builder/base.rb +57 -10
  122. data/lib/pubid/bundled_identifier.rb +0 -1
  123. data/lib/pubid/ccsds/builder.rb +4 -3
  124. data/lib/pubid/ccsds/identifier.rb +53 -68
  125. data/lib/pubid/ccsds/identifiers/base.rb +11 -61
  126. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  127. data/lib/pubid/ccsds/parser.rb +4 -2
  128. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  129. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  130. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  131. data/lib/pubid/ccsds.rb +39 -1
  132. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  133. data/lib/pubid/cen_cenelec/identifier.rb +11 -40
  134. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +9 -4
  135. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +0 -10
  136. data/lib/pubid/cen_cenelec/identifiers/base.rb +2 -45
  137. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  138. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +0 -27
  140. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +0 -15
  141. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +2 -8
  143. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  144. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +0 -4
  145. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  146. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  147. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  148. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  149. data/lib/pubid/cen_cenelec/single_identifier.rb +9 -90
  150. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  151. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  152. data/lib/pubid/cen_cenelec.rb +172 -1
  153. data/lib/pubid/cie/components/code.rb +8 -0
  154. data/lib/pubid/cie/identifier.rb +10 -57
  155. data/lib/pubid/cie/single_identifier.rb +4 -4
  156. data/lib/pubid/cie/urn_parser.rb +28 -0
  157. data/lib/pubid/cie.rb +47 -1
  158. data/lib/pubid/components/adoption.rb +104 -0
  159. data/lib/pubid/components/code.rb +22 -8
  160. data/lib/pubid/components/date.rb +23 -16
  161. data/lib/pubid/components/edition.rb +9 -6
  162. data/lib/pubid/components/iteration.rb +32 -0
  163. data/lib/pubid/components/language.rb +6 -4
  164. data/lib/pubid/components/locality.rb +10 -1
  165. data/lib/pubid/components/publisher.rb +9 -6
  166. data/lib/pubid/components/relationship.rb +151 -0
  167. data/lib/pubid/components/stage.rb +5 -14
  168. data/lib/pubid/components/supplement.rb +184 -0
  169. data/lib/pubid/components/type.rb +5 -15
  170. data/lib/pubid/components/typed_stage.rb +10 -11
  171. data/lib/pubid/components.rb +4 -1
  172. data/lib/pubid/core/update_codes.rb +28 -7
  173. data/lib/pubid/csa/identifier.rb +9 -59
  174. data/lib/pubid/csa/identifiers/base.rb +0 -123
  175. data/lib/pubid/csa/identifiers/cec.rb +0 -103
  176. data/lib/pubid/csa/identifiers/series.rb +0 -104
  177. data/lib/pubid/csa/renderer.rb +292 -0
  178. data/lib/pubid/csa/single_identifier.rb +1 -1
  179. data/lib/pubid/csa/urn_generator.rb +1 -1
  180. data/lib/pubid/csa/urn_parser.rb +33 -0
  181. data/lib/pubid/csa.rb +46 -1
  182. data/lib/pubid/etsi/components/code.rb +10 -9
  183. data/lib/pubid/etsi/components/version.rb +0 -5
  184. data/lib/pubid/etsi/identifier.rb +4 -55
  185. data/lib/pubid/etsi/identifiers/base.rb +31 -27
  186. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +1 -11
  187. data/lib/pubid/etsi/renderer.rb +42 -0
  188. data/lib/pubid/etsi/urn_parser.rb +34 -0
  189. data/lib/pubid/etsi.rb +44 -1
  190. data/lib/pubid/export/exporter.rb +4 -46
  191. data/lib/pubid/export/flavor_exporter.rb +111 -278
  192. data/lib/pubid/export.rb +0 -6
  193. data/lib/pubid/identifier.rb +92 -18
  194. data/lib/pubid/identifier_metadata.rb +1 -1
  195. data/lib/pubid/idf/builder.rb +3 -3
  196. data/lib/pubid/idf/identifier.rb +7 -66
  197. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  198. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  199. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  200. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  201. data/lib/pubid/idf/parser.rb +3 -2
  202. data/lib/pubid/idf/renderer.rb +84 -0
  203. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  204. data/lib/pubid/idf/urn_generator.rb +4 -39
  205. data/lib/pubid/idf/urn_parser.rb +25 -0
  206. data/lib/pubid/idf.rb +55 -1
  207. data/lib/pubid/iec/builder.rb +46 -64
  208. data/lib/pubid/iec/components/code.rb +8 -32
  209. data/lib/pubid/iec/components/publisher.rb +0 -1
  210. data/lib/pubid/iec/components.rb +14 -0
  211. data/lib/pubid/iec/identifier.rb +251 -213
  212. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  213. data/lib/pubid/iec/identifiers/base.rb +5 -33
  214. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  215. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  216. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +23 -26
  217. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  218. data/lib/pubid/iec/identifiers/fragment_identifier.rb +35 -24
  219. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  220. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  221. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  222. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  223. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  224. data/lib/pubid/iec/identifiers/sheet_identifier.rb +17 -11
  225. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  226. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  227. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  228. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  229. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  230. data/lib/pubid/iec/identifiers/test_report_form.rb +3 -35
  231. data/lib/pubid/iec/identifiers/vap_identifier.rb +24 -21
  232. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  233. data/lib/pubid/iec/identifiers/working_document.rb +2 -50
  234. data/lib/pubid/iec/identifiers.rb +30 -0
  235. data/lib/pubid/iec/parser.rb +13 -12
  236. data/lib/pubid/iec/renderer.rb +254 -0
  237. data/lib/pubid/iec/single_identifier.rb +6 -12
  238. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  239. data/lib/pubid/iec/urn_generator.rb +3 -3
  240. data/lib/pubid/iec/urn_parser.rb +3 -3
  241. data/lib/pubid/iec.rb +43 -67
  242. data/lib/pubid/ieee/builder.rb +12 -12
  243. data/lib/pubid/ieee/components/code.rb +8 -0
  244. data/lib/pubid/ieee/components/draft.rb +14 -0
  245. data/lib/pubid/ieee/components/relationship.rb +5 -149
  246. data/lib/pubid/ieee/identifier.rb +5 -52
  247. data/lib/pubid/ieee/identifiers/adopted_standard.rb +0 -9
  248. data/lib/pubid/ieee/identifiers/base.rb +221 -556
  249. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +0 -10
  250. data/lib/pubid/ieee/identifiers/corrigendum.rb +0 -12
  251. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +0 -10
  252. data/lib/pubid/ieee/identifiers/dual_identifier.rb +0 -4
  253. data/lib/pubid/ieee/identifiers/dual_published.rb +0 -4
  254. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +0 -9
  255. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +0 -10
  256. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  257. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +0 -18
  258. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +0 -6
  259. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  260. data/lib/pubid/ieee/identifiers/redlined_standard.rb +0 -7
  261. data/lib/pubid/ieee/identifiers/si_standard.rb +0 -38
  262. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  263. data/lib/pubid/ieee/pre_parser.rb +301 -0
  264. data/lib/pubid/ieee/renderer.rb +307 -0
  265. data/lib/pubid/ieee/urn_parser.rb +34 -0
  266. data/lib/pubid/ieee.rb +66 -1
  267. data/lib/pubid/ieee_debug.rb +0 -1
  268. data/lib/pubid/iho/builder.rb +2 -2
  269. data/lib/pubid/iho/identifier.rb +7 -59
  270. data/lib/pubid/iho/identifiers/base.rb +64 -31
  271. data/lib/pubid/iho/parser.rb +3 -3
  272. data/lib/pubid/iho/renderer.rb +30 -0
  273. data/lib/pubid/iho/urn_generator.rb +2 -2
  274. data/lib/pubid/iho/urn_parser.rb +58 -0
  275. data/lib/pubid/iho.rb +52 -1
  276. data/lib/pubid/iso/builder.rb +55 -53
  277. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  278. data/lib/pubid/iso/components/code.rb +7 -19
  279. data/lib/pubid/iso/components/publisher.rb +10 -8
  280. data/lib/pubid/iso/components.rb +2 -4
  281. data/lib/pubid/iso/identifier.rb +219 -252
  282. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  283. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  284. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  285. data/lib/pubid/iso/identifiers/data.rb +0 -1
  286. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  287. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  288. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  289. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  290. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  291. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  292. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  293. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  294. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  295. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  296. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  297. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  298. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  299. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  300. data/lib/pubid/iso/identifiers.rb +0 -1
  301. data/lib/pubid/iso/normalizer.rb +89 -0
  302. data/lib/pubid/iso/parser.rb +22 -4
  303. data/lib/pubid/iso/single_identifier.rb +0 -4
  304. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  305. data/lib/pubid/iso/urn_generator.rb +66 -182
  306. data/lib/pubid/iso/urn_parser.rb +12 -7
  307. data/lib/pubid/iso.rb +177 -2
  308. data/lib/pubid/itu/builder.rb +0 -12
  309. data/lib/pubid/itu/components/code.rb +9 -7
  310. data/lib/pubid/itu/components/sector.rb +15 -4
  311. data/lib/pubid/itu/components/series.rb +0 -4
  312. data/lib/pubid/itu/components.rb +11 -0
  313. data/lib/pubid/itu/identifier.rb +4 -116
  314. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  315. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  316. data/lib/pubid/itu/identifiers/base.rb +124 -128
  317. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  318. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  319. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  320. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  321. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  322. data/lib/pubid/itu/urn_parser.rb +23 -0
  323. data/lib/pubid/itu.rb +44 -1
  324. data/lib/pubid/jcgm/builder.rb +16 -8
  325. data/lib/pubid/jcgm/identifier.rb +0 -43
  326. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -9
  327. data/lib/pubid/jcgm/identifiers/gum_guide.rb +0 -12
  328. data/lib/pubid/jcgm/renderer.rb +68 -0
  329. data/lib/pubid/jcgm/single_identifier.rb +0 -8
  330. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  331. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  332. data/lib/pubid/jcgm.rb +43 -2
  333. data/lib/pubid/jis/builder.rb +44 -52
  334. data/lib/pubid/jis/identifier.rb +120 -46
  335. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  336. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  337. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  338. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  339. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  340. data/lib/pubid/jis/identifiers.rb +1 -1
  341. data/lib/pubid/jis/parser.rb +31 -5
  342. data/lib/pubid/jis/renderer.rb +69 -0
  343. data/lib/pubid/jis/single_identifier.rb +6 -12
  344. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  345. data/lib/pubid/jis/urn_parser.rb +23 -0
  346. data/lib/pubid/jis.rb +42 -2
  347. data/lib/pubid/nist/builder.rb +63 -1871
  348. data/lib/pubid/nist/caster.rb +1272 -0
  349. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  350. data/lib/pubid/nist/components/code.rb +9 -20
  351. data/lib/pubid/nist/components/supplement.rb +2 -2
  352. data/lib/pubid/nist/components.rb +0 -1
  353. data/lib/pubid/nist/identifier.rb +8 -60
  354. data/lib/pubid/nist/identifiers/base.rb +564 -492
  355. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  356. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -1
  357. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  358. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  359. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  360. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -8
  361. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  362. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +15 -24
  363. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  364. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  365. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  366. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  367. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  368. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  369. data/lib/pubid/nist/identifiers/report.rb +4 -2
  370. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  371. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  372. data/lib/pubid/nist/identifiers.rb +1 -0
  373. data/lib/pubid/nist/parser.rb +62 -452
  374. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  375. data/lib/pubid/nist/preprocessor.rb +428 -0
  376. data/lib/pubid/nist/renderer.rb +43 -0
  377. data/lib/pubid/nist/router.rb +148 -0
  378. data/lib/pubid/nist/series/base.rb +58 -0
  379. data/lib/pubid/nist/series/crpl.rb +13 -0
  380. data/lib/pubid/nist/series/fips.rb +14 -0
  381. data/lib/pubid/nist/series/ir.rb +60 -0
  382. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  383. data/lib/pubid/nist/series/mono.rb +19 -0
  384. data/lib/pubid/nist/series/ncstar.rb +20 -0
  385. data/lib/pubid/nist/series.rb +49 -0
  386. data/lib/pubid/nist/supplement_identifier.rb +3 -1
  387. data/lib/pubid/nist/urn_parser.rb +67 -0
  388. data/lib/pubid/nist.rb +86 -4
  389. data/lib/pubid/oiml/builder.rb +21 -3
  390. data/lib/pubid/oiml/components/code.rb +17 -0
  391. data/lib/pubid/oiml/identifier.rb +40 -46
  392. data/lib/pubid/oiml/identifiers/annex.rb +13 -46
  393. data/lib/pubid/oiml/identifiers/errata.rb +15 -0
  394. data/lib/pubid/oiml/identifiers.rb +1 -1
  395. data/lib/pubid/oiml/parser.rb +59 -12
  396. data/lib/pubid/oiml/renderer.rb +171 -0
  397. data/lib/pubid/oiml/single_identifier.rb +61 -42
  398. data/lib/pubid/oiml/supplement_identifier.rb +31 -17
  399. data/lib/pubid/oiml/urn_generator.rb +0 -8
  400. data/lib/pubid/oiml/urn_parser.rb +22 -0
  401. data/lib/pubid/oiml.rb +42 -1
  402. data/lib/pubid/plateau/identifier.rb +4 -55
  403. data/lib/pubid/plateau/identifiers/base.rb +45 -36
  404. data/lib/pubid/plateau/identifiers/handbook.rb +0 -6
  405. data/lib/pubid/plateau/identifiers/technical_report.rb +0 -4
  406. data/lib/pubid/plateau/renderer.rb +51 -0
  407. data/lib/pubid/plateau/supplement_identifier.rb +0 -4
  408. data/lib/pubid/plateau/urn_parser.rb +43 -0
  409. data/lib/pubid/plateau.rb +43 -1
  410. data/lib/pubid/renderers/directives_renderer.rb +22 -8
  411. data/lib/pubid/renderers/guide_renderer.rb +4 -2
  412. data/lib/pubid/renderers/human_readable.rb +18 -7
  413. data/lib/pubid/rendering/context.rb +28 -19
  414. data/lib/pubid/rendering.rb +0 -3
  415. data/lib/pubid/sae/components/date.rb +8 -0
  416. data/lib/pubid/sae/components/type.rb +5 -1
  417. data/lib/pubid/sae/identifier.rb +4 -35
  418. data/lib/pubid/sae/identifiers/base.rb +26 -31
  419. data/lib/pubid/sae/renderer.rb +36 -0
  420. data/lib/pubid/sae/urn_generator.rb +2 -10
  421. data/lib/pubid/sae/urn_parser.rb +36 -0
  422. data/lib/pubid/sae.rb +42 -1
  423. data/lib/pubid/urn_generator/base.rb +12 -12
  424. data/lib/pubid/urn_parser/base.rb +81 -0
  425. data/lib/pubid/urn_parser/errors.rb +9 -0
  426. data/lib/pubid/urn_parser.rb +14 -0
  427. data/lib/pubid/version.rb +1 -1
  428. data/lib/pubid.rb +45 -7
  429. data/lib/tasks/export.rake +6 -5
  430. data/lib/tasks/website-data.json +1940 -1882
  431. metadata +75 -45
  432. data/lib/pubid/amca/scheme.rb +0 -16
  433. data/lib/pubid/ansi/scheme.rb +0 -15
  434. data/lib/pubid/api/scheme.rb +0 -66
  435. data/lib/pubid/ashrae/scheme.rb +0 -53
  436. data/lib/pubid/asme/scheme.rb +0 -37
  437. data/lib/pubid/astm/scheme.rb +0 -55
  438. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  439. data/lib/pubid/bsi/scheme.rb +0 -243
  440. data/lib/pubid/ccsds/scheme.rb +0 -57
  441. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  442. data/lib/pubid/cie/scheme.rb +0 -64
  443. data/lib/pubid/components/factory.rb +0 -50
  444. data/lib/pubid/csa/scheme.rb +0 -44
  445. data/lib/pubid/etsi/scheme.rb +0 -42
  446. data/lib/pubid/export/data_class_exporter.rb +0 -59
  447. data/lib/pubid/export/ieee_exporter.rb +0 -78
  448. data/lib/pubid/export/itu_exporter.rb +0 -66
  449. data/lib/pubid/export/nist_exporter.rb +0 -64
  450. data/lib/pubid/export/registry_exporter.rb +0 -90
  451. data/lib/pubid/export/scheme_exporter.rb +0 -70
  452. data/lib/pubid/identifier_registry.rb +0 -198
  453. data/lib/pubid/idf/scheme.rb +0 -61
  454. data/lib/pubid/iec/scheme.rb +0 -71
  455. data/lib/pubid/ieee/scheme.rb +0 -90
  456. data/lib/pubid/iho/scheme.rb +0 -29
  457. data/lib/pubid/iso/identifiers/base.rb +0 -115
  458. data/lib/pubid/iso/scheme.rb +0 -193
  459. data/lib/pubid/itu/scheme.rb +0 -174
  460. data/lib/pubid/jcgm/scheme.rb +0 -60
  461. data/lib/pubid/jis/components/code.rb +0 -59
  462. data/lib/pubid/jis/identifiers/base.rb +0 -72
  463. data/lib/pubid/jis/scheme.rb +0 -49
  464. data/lib/pubid/nist/components/publisher.rb +0 -24
  465. data/lib/pubid/nist/scheme.rb +0 -199
  466. data/lib/pubid/oiml/identifiers/base.rb +0 -36
  467. data/lib/pubid/oiml/scheme.rb +0 -46
  468. data/lib/pubid/plateau/scheme.rb +0 -45
  469. data/lib/pubid/rendering/base.rb +0 -73
  470. data/lib/pubid/rendering/common.rb +0 -211
  471. data/lib/pubid/rendering/format.rb +0 -25
  472. data/lib/pubid/sae/scheme.rb +0 -47
  473. data/lib/pubid/scheme.rb +0 -219
@@ -1,256 +1,294 @@
1
- require_relative "../identifier"
2
1
  # frozen_string_literal: true
3
- require_relative "../components/typed_stage"
4
- require_relative "../components/factory"
5
2
 
6
3
  module Pubid
7
4
  module Iec
5
+ # Mixin for pure wrapper identifiers (Vap/Consolidated/Sheet) whose common
6
+ # ID fields are delegated to a wrapped base. lutaml merges a subclass's
7
+ # key_value block onto the parent's, so without this the delegated fields
8
+ # would serialize twice — once at the wrapper's top level and once inside
9
+ # "base". No-op the delegated maps so they serialize once. (Mirrors
10
+ # Iso::BundledIdentifier.) Fragment keeps its own stage/edition, so it
11
+ # suppresses a subset inline instead of including this.
12
+ module DelegatedFieldSuppression
13
+ def number_to_kv(_model, _doc); end
14
+ def part_to_kv(_model, _doc); end
15
+ def subpart_to_kv(_model, _doc); end
16
+ def stage_iteration_to_kv(_model, _doc); end
17
+ def year_to_kv(_model, _doc); end
18
+ def publisher_to_kv(_model, _doc); end
19
+ def copublishers_to_kv(_model, _doc); end
20
+ def stage_to_kv(_model, _doc); end
21
+ end
22
+
8
23
  class Identifier < ::Pubid::Identifier
9
- # Long-tail document types that `create` may build but which are not in
10
- # Scheme.identifiers (the parse/build candidate set). Loaded lazily (not
11
- # at require time) to avoid a circular load with identifiers/base.rb.
12
- EXTRA_CREATE_KLASS_FILES = %w[
13
- conformity_assessment technology_report white_paper
14
- societal_technology_trend_report systems_reference_document
15
- interpretation_sheet
16
- ].freeze
17
- def self.parse(string)
18
- # Route URN strings to the URN parser (mirrors Iso::Identifier.parse)
19
- if Pubid::FormatDetector.detect(string) == :urn
20
- return Pubid::Iec::UrnParser.parse(string)
21
- end
24
+ # Override base types with IEC-specific ones. publisher defaults to the
25
+ # type's implied publisher (IEC), so an omitted publisher key reconstructs
26
+ # correctly on from_hash. number/part/subpart are IEC codes.
27
+ attribute :publisher, ::Pubid::Iec::Components::Publisher,
28
+ default: -> { self.class.default_publisher }
29
+ attribute :copublishers, ::Pubid::Iec::Components::Publisher,
30
+ collection: true
31
+ attribute :number, ::Pubid::Iec::Components::Code
32
+ attribute :part, ::Pubid::Iec::Components::Code
33
+ attribute :subpart, ::Pubid::Iec::Components::Code
22
34
 
23
- # Apply legacy update_codes normalization first, before any other preprocessing
24
- normalized = Core::UpdateCodes.apply(string, :iec)
25
- parsed = Pubid::Iec::Parser.new.parse(normalized)
26
- if parsed.nil? || parsed.empty?
27
- raise Pubid::Iec::Parser::ParseError,
28
- "Invalid identifier format"
29
- end
35
+ # The publisher implied when none is serialized (IEC for every type).
36
+ def self.default_publisher
37
+ ::Pubid::Iec::Components::Publisher.new(body: "IEC")
38
+ end
30
39
 
31
- Pubid::Iec::Builder.new(Pubid::Iec::Scheme).build(parsed)
40
+ # typed_stage is the single source of truth for stage (and, with the
41
+ # class, the doctype). Default to the class's published typed_stage so an
42
+ # omitted "stage" key reconstructs the published state on from_hash.
43
+ attribute :typed_stage, ::Pubid::Components::TypedStage,
44
+ default: -> { self.class.published_typed_stage }
45
+
46
+ # The class's published typed_stage (canonical surface form), or nil for
47
+ # types without a published stage.
48
+ def self.published_typed_stage
49
+ return nil unless const_defined?(:TYPED_STAGES)
50
+
51
+ ts = self::TYPED_STAGES.find { |t| t.stage_code.to_s == "published" }
52
+ return nil unless ts
53
+
54
+ ts = ts.dup
55
+ ts.original_abbr = ts.canonical_abbreviation
56
+ ts
32
57
  end
33
58
 
34
- # Factory mirroring pubid 1.x's `Pubid::Iec::Identifier.create` API.
35
- # See {Pubid::Iso::Identifier.create} for the shared design. Builds the
36
- # IEC `Components::*` subclasses (not the base ones) and populates
37
- # type/stage from the resolved TypedStage, so that a created identifier
38
- # round-trips `==` against the same identifier produced by `parse`.
39
- def self.create(type: nil, stage: nil, **opts)
40
- # A VAP suffix (CSV/RLV/…) is the outermost wrapper around the base
41
- # document (which may itself be amended); rebuild it first.
42
- if (vap = opts.delete(:vap))
43
- base = create(type: type, stage: stage, **opts)
44
- return Identifiers::VapIdentifier.new(
45
- base_identifier: base,
46
- vap_suffix: Components::VapSuffix.new(code: Array(vap).first.to_s),
47
- )
48
- end
59
+ # type and generic stage are derived from typed_stage, never stored — so
60
+ # the doctype (fixed by the class / _type) can't be lost when "stage" is
61
+ # omitted for the published default.
62
+ def type
63
+ typed_stage&.to_type
64
+ end
49
65
 
50
- # Structured index rows carry amendments/corrigendums as a flat list
51
- # alongside the base document's keys; rebuild the supplement wrapping
52
- # the recursively-created base, mirroring what parse produces.
53
- if (supp = extract_supplement(opts))
54
- return build_supplement(supp, type: type, stage: stage, opts: opts)
55
- end
66
+ def stage
67
+ typed_stage&.to_stage
68
+ end
56
69
 
57
- # A nested base: holds the base document of a supplement whose own
58
- # number/year sit at the top level (e.g. an Interpretation Sheet).
59
- if (base_hash = opts.delete(:base))
60
- return build_based_supplement(type: type, base_hash: base_hash,
61
- opts: opts)
62
- end
70
+ # Polymorphic type map for lutaml::Model key_value serialization. Maps
71
+ # polymorphic_name -> class name for from_hash dispatch. Includes the
72
+ # compound wrappers (Consolidated/Vap/Sheet) and the synthetic
73
+ # SingleIdentifier base, which appear as nested `_type` values even though
74
+ # they aren't identifier_types. Validated against build_type_map by spec.
75
+ IEC_TYPE_MAP = {
76
+ "pubid:iec:international-standard" => "Pubid::Iec::Identifiers::InternationalStandard",
77
+ "pubid:iec:technical-specification" => "Pubid::Iec::Identifiers::TechnicalSpecification",
78
+ "pubid:iec:technical-report" => "Pubid::Iec::Identifiers::TechnicalReport",
79
+ "pubid:iec:publicly-available-specification" => "Pubid::Iec::Identifiers::PubliclyAvailableSpecification",
80
+ "pubid:iec:guide" => "Pubid::Iec::Identifiers::Guide",
81
+ "pubid:iec:operational-document" => "Pubid::Iec::Identifiers::OperationalDocument",
82
+ "pubid:iec:component-specification" => "Pubid::Iec::Identifiers::ComponentSpecification",
83
+ "pubid:iec:conformity-assessment" => "Pubid::Iec::Identifiers::ConformityAssessment",
84
+ "pubid:iec:societal-technology-trend-report" => "Pubid::Iec::Identifiers::SocietalTechnologyTrendReport",
85
+ "pubid:iec:systems-reference-document" => "Pubid::Iec::Identifiers::SystemsReferenceDocument",
86
+ "pubid:iec:technology-report" => "Pubid::Iec::Identifiers::TechnologyReport",
87
+ "pubid:iec:test-report-form" => "Pubid::Iec::Identifiers::TestReportForm",
88
+ "pubid:iec:white-paper" => "Pubid::Iec::Identifiers::WhitePaper",
89
+ "pubid:iec:working-document" => "Pubid::Iec::Identifiers::WorkingDocument",
90
+ "pubid:iec:amendment" => "Pubid::Iec::Identifiers::Amendment",
91
+ "pubid:iec:corrigendum" => "Pubid::Iec::Identifiers::Corrigendum",
92
+ "pubid:iec:interpretation-sheet" => "Pubid::Iec::Identifiers::InterpretationSheet",
93
+ "pubid:iec:fragment-identifier" => "Pubid::Iec::Identifiers::FragmentIdentifier",
94
+ "pubid:iec:consolidated-identifier" => "Pubid::Iec::Identifiers::ConsolidatedIdentifier",
95
+ "pubid:iec:vap-identifier" => "Pubid::Iec::Identifiers::VapIdentifier",
96
+ "pubid:iec:sheet-identifier" => "Pubid::Iec::Identifiers::SheetIdentifier",
97
+ "pubid:iec:base" => "Pubid::Iec::Identifiers::Base",
98
+ "pubid:iec:single-identifier" => "Pubid::Iec::SingleIdentifier",
99
+ }.freeze
63
100
 
64
- klass = resolve_create_class(type: type, stage: stage)
65
- attrs = coerce_create_attrs(opts)
66
- ts = resolve_create_typed_stage(klass, stage)
67
- if ts
68
- attrs[:typed_stage] = ts
69
- # Parse derives `type` and `stage` from the TypedStage (see
70
- # Builder#cast for :type_with_stage); mirror that here.
71
- attrs[:type] ||= ts.to_type
72
- attrs[:stage] ||= ts.to_stage
73
- end
74
- klass.new(**attrs)
101
+ # SingleIdentifier lives outside Pubid::Iec::Identifiers but appears as a
102
+ # nested `_type`, so the shared polymorphic_type_map needs it explicitly
103
+ # (see Pubid::Identifier#additional_identifier_classes).
104
+ def self.additional_identifier_classes
105
+ [Pubid::Iec::SingleIdentifier]
75
106
  end
107
+ private_class_method :additional_identifier_classes
76
108
 
77
- # Pop a supplement spec off the flat opts hash, if present. Returns
78
- # { klass:, entry: } or nil. Amendments take precedence over
79
- # corrigendums for the (rare) consolidated rows that carry both.
80
- def self.extract_supplement(opts)
81
- if (amds = opts.delete(:amendments))
82
- { klass: Identifiers::Amendment, entry: Array(amds).first }
83
- elsif (cors = opts.delete(:corrigendums))
84
- { klass: Identifiers::Corrigendum, entry: Array(cors).first }
85
- end
109
+ # Build the type map from the live class list, for the validation spec.
110
+ def self.build_type_map
111
+ types = Pubid::Iec.identifier_types
112
+ extra = [Identifiers::ConsolidatedIdentifier, Identifiers::VapIdentifier,
113
+ Identifiers::SheetIdentifier, Identifiers::Base, SingleIdentifier]
114
+ (types + extra).uniq.to_h { |klass| [klass.polymorphic_name, klass.name] }
86
115
  end
87
116
 
88
- # Build an Amendment/Corrigendum from { number:, year: } wrapping a base
89
- # identifier created from the remaining opts (which may themselves carry
90
- # a type, e.g. an amendment to a TR).
91
- def self.build_supplement(supp, type:, stage:, opts:)
92
- base = create(type: type, stage: stage, **opts)
93
- klass = supp[:klass]
94
- entry = supp[:entry] || {}
95
- ts = klass::TYPED_STAGES.find { |t| t.stage_code.to_sym == :published }
96
- attrs = { base_identifier: base, typed_stage: ts,
97
- type: ts.to_type, stage: ts.to_stage }
98
- if (n = entry[:number])
99
- attrs[:number] = Components::Code.new(number: n.to_s)
100
- end
101
- if (y = entry[:year])
102
- attrs[:date] = ::Pubid::Components::Date.new(year: y.to_s)
103
- end
104
- klass.new(**attrs)
117
+ # The base Pubid::Identifier no longer auto-maps attributes, so each
118
+ # flavor's top class declares its own key_value mapping. Subclasses merge
119
+ # their own blocks on top of this one (e.g. SupplementIdentifier adds
120
+ # base; VapIdentifier adds vap), so list every base attribute IEC
121
+ # serializes here once. Code/Date are flattened to plain scalars; the
122
+ # verbose type/stage trees are not mapped (type/stage are recomputed from
123
+ # typed_stage, which serializes as just its code under "stage").
124
+ key_value do
125
+ map "_type", to: :_type, polymorphic_map: IEC_TYPE_MAP
126
+ # Code components serialize as their plain string value, not {value,...}.
127
+ map "number", with: { to: :number_to_kv, from: :number_from_kv }
128
+ map "part", with: { to: :part_to_kv, from: :part_from_kv }
129
+ map "subpart", with: { to: :subpart_to_kv, from: :subpart_from_kv }
130
+ map "stage_iteration",
131
+ with: { to: :stage_iteration_to_kv, from: :stage_iteration_from_kv }
132
+ # IEC dates are year-only, so flatten the Date component to a scalar year.
133
+ map "year", with: { to: :year_to_kv, from: :year_from_kv }
134
+ map "edition", to: :edition, render_default: false
135
+ map "languages", to: :languages, render_default: false
136
+ # publisher emitted only when the primary isn't the IEC default;
137
+ # copublishers (the other bodies) as an array, omitted when empty.
138
+ map "publisher", with: { to: :publisher_to_kv, from: :publisher_from_kv }
139
+ map "copublishers",
140
+ with: { to: :copublishers_to_kv, from: :copublishers_from_kv }
141
+ # `type` and generic `stage` are fully derived from `typed_stage`, so we
142
+ # serialize only the unique typed-stage code under "stage" and recompute
143
+ # the rest on load. _type already pins the document type.
144
+ map "stage", with: { to: :stage_to_kv, from: :stage_from_kv }
145
+ # Omit the `false` default; only the meaningful `true` is serialized.
146
+ map "all_parts", with: { to: :all_parts_to_kv, from: :all_parts_from_kv }
105
147
  end
106
148
 
107
- # Build a supplement whose base document is carried in a nested base:
108
- # hash (e.g. type: "ISH"); the supplement's own number/year are the
109
- # remaining top-level keys.
110
- def self.build_based_supplement(type:, base_hash:, opts:)
111
- klass = (type && locate_klass_by_type_or_short(type)) ||
112
- Identifiers::InternationalStandard
113
- base = create(**base_hash.transform_keys(&:to_sym))
114
- attrs = coerce_create_attrs(opts)
115
- .slice(:number, :part, :subpart, :date, :publisher, :copublishers)
116
- attrs[:base_identifier] = base
117
- if klass.const_defined?(:TYPED_STAGES) &&
118
- (ts = klass::TYPED_STAGES.find { |t| t.stage_code.to_sym == :published })
119
- attrs[:typed_stage] = ts
120
- attrs[:type] ||= ts.to_type
121
- attrs[:stage] ||= ts.to_stage
122
- end
123
- klass.new(**attrs)
149
+ # --- Code components <-> plain string ---
150
+ def number_to_kv(model, doc) = emit_code(doc, "number", model.number)
151
+ def number_from_kv(model, value) = model.number = build_code(value)
152
+ def part_to_kv(model, doc) = emit_code(doc, "part", model.part)
153
+ def part_from_kv(model, value) = model.part = build_code(value)
154
+ def subpart_to_kv(model, doc) = emit_code(doc, "subpart", model.subpart)
155
+ def subpart_from_kv(model, value) = model.subpart = build_code(value)
156
+
157
+ def emit_code(doc, key, code)
158
+ v = code.is_a?(::Pubid::Components::Code) ? code.value : code
159
+ return if v.nil? || v.to_s.empty?
160
+
161
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, v.to_s))
124
162
  end
125
163
 
126
- # Coerce a 1.x-style attribute hash into IEC Component instances,
127
- # matching what the parser/builder produces. Unknown keys are dropped.
128
- def self.coerce_create_attrs(opts)
129
- out = {}
130
- if (v = opts[:publisher])
131
- out[:publisher] = Components::Publisher.new(body: v.to_s)
132
- end
133
- if (copubs = opts[:copublishers] || opts[:copublisher])
134
- out[:copublishers] =
135
- Array(copubs).map { |c| Components::Publisher.new(body: c.to_s) }
136
- end
137
- if (v = opts[:number])
138
- out[:number] = Components::Code.new(number: v.to_s)
139
- end
140
- # Indexes fold the subpart into a single "2-4" part string; parse
141
- # keeps part and subpart separate, so split to match.
142
- part, subpart = split_part(opts[:part], opts[:subpart])
143
- out[:part] = Components::Code.new(number: part.to_s) unless part.nil?
144
- out[:subpart] = Components::Code.new(number: subpart.to_s) unless subpart.nil?
145
- if (v = opts[:year])
146
- out[:date] = ::Pubid::Components::Date.new(year: v.to_s)
147
- end
148
- if (v = opts[:edition])
149
- out[:edition] = ::Pubid::Components::Edition.new(number: v)
150
- end
151
- if (v = opts[:language])
152
- out[:languages] = [::Pubid::Components::Language.new(code: v.to_s)]
153
- end
154
- out[:database] = true if opts[:database]
155
- out
164
+ def build_code(value)
165
+ return if value.nil? || value.to_s.empty?
166
+
167
+ ::Pubid::Iec::Components::Code.new(value: value.to_s)
156
168
  end
157
169
 
158
- # Split a folded "2-4" part into [part, subpart], matching parse. A part
159
- # without a dash (or an explicit subpart already supplied) is untouched.
160
- def self.split_part(part, subpart)
161
- return [nil, subpart] if part.nil?
162
- if subpart.nil? && part.to_s.include?("-")
163
- part.to_s.split("-", 2)
164
- else
165
- [part, subpart]
166
- end
170
+ def stage_iteration_to_kv(model, doc)
171
+ iter = model.stage_iteration
172
+ v = iter.is_a?(::Pubid::Components::Iteration) ? iter.number : iter
173
+ return if v.nil? || v.to_s.empty?
174
+
175
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("stage_iteration",
176
+ v.to_s))
167
177
  end
168
178
 
169
- def self.resolve_create_class(type:, stage:)
170
- if type && supplement_type?(type)
171
- # Supplements are built from amendments:/corrigendums: data (which
172
- # carry the supplement number/year); an explicit supplement `type:`
173
- # alone has no base to wrap.
174
- raise ArgumentError,
175
- "#{type} requires a base_identifier; pass amendments:/" \
176
- "corrigendums: instead of type:"
177
- end
179
+ def stage_iteration_from_kv(model, value)
180
+ return if value.nil? || value.to_s.empty?
178
181
 
179
- klass =
180
- if type
181
- locate_klass_by_type_or_short(type)
182
- elsif stage
183
- ts = safe_locate_typed_stage(stage)
184
- ts && locate_klass_by_type_or_short(ts.type_code)
185
- end
186
- klass || Identifiers::InternationalStandard
182
+ model.stage_iteration =
183
+ ::Pubid::Components::Iteration.new(number: value.to_s)
187
184
  end
188
185
 
189
- # True when `type` names a supplement identifier (Amendment/Corrigendum/
190
- # Fragment) by key, downcased key, or short abbreviation.
191
- def self.supplement_type?(type)
192
- t = type.to_s
193
- Scheme.supplement_identifiers.any? do |k|
194
- k.type[:key].to_s == t || k.type[:key].to_s == t.downcase ||
195
- Array(k.type[:short]).map(&:to_s).include?(t)
196
- end
186
+ # --- date <-> scalar year (IEC dates are year-only) ---
187
+ def year_to_kv(model, doc)
188
+ y = model.date&.year
189
+ return if y.nil? || y.to_s.empty?
190
+
191
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("year", y.to_s))
192
+ end
193
+
194
+ def year_from_kv(model, value)
195
+ return if value.nil? || value.to_s.empty?
196
+
197
+ (model.date ||= ::Pubid::Components::Date.new).year = value.to_s
197
198
  end
198
199
 
199
- # Structured indexes store `type:` as the registry key (:tr), an
200
- # upper-cased abbreviation ("TR"), or a title ("Technology Report").
201
- # Try each spelling, across every IEC identifier class (the create
202
- # candidate set is wider than Scheme.identifiers).
203
- def self.locate_klass_by_type_or_short(type)
204
- t = type.to_s
205
- all_create_klasses.detect { |k| k.type[:key].to_s == t } ||
206
- all_create_klasses.detect { |k| k.type[:key].to_s == t.downcase } ||
207
- all_create_klasses.detect { |k| Array(k.type[:short]).map(&:to_s).include?(t) } ||
208
- all_create_klasses.detect { |k| k.type[:title].to_s == t }
200
+ # --- publisher: primary only when non-default; copublishers as a list ---
201
+ def publisher_to_kv(model, doc)
202
+ pub = model.publisher&.body
203
+ return if pub.nil? || pub == model.class.default_publisher&.body
204
+
205
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("publisher", pub))
206
+ end
207
+
208
+ def publisher_from_kv(model, value)
209
+ return if value.nil? || value.to_s.empty?
210
+
211
+ model.publisher = ::Pubid::Iec::Components::Publisher.new(body: value.to_s)
209
212
  end
210
213
 
211
- # All IEC identifier classes that `create` may build, including the
212
- # long-tail document types absent from Scheme.identifiers. Memoized;
213
- # the extra classes are required here (not at load time) to dodge the
214
- # circular require with identifiers/base.rb.
215
- def self.all_create_klasses
216
- @all_create_klasses ||= begin
217
- extra = EXTRA_CREATE_KLASS_FILES.map do |f|
218
- require_relative "identifiers/#{f}"
219
- Identifiers.const_get(camelize_klass_file(f))
220
- end
221
- Scheme.identifiers + extra
214
+ def copublishers_to_kv(model, doc)
215
+ cp = model.copublishers
216
+ return unless cp&.any?
217
+
218
+ doc.add_child(
219
+ Lutaml::KeyValue::DataModel::Element.new("copublishers", cp.map(&:body)),
220
+ )
221
+ end
222
+
223
+ def copublishers_from_kv(model, value)
224
+ list = Array(value).map(&:to_s)
225
+ return unless list.any?
226
+
227
+ model.copublishers = list.map do |cp|
228
+ ::Pubid::Iec::Components::Publisher.new(body: cp)
222
229
  end
223
230
  end
224
231
 
225
- def self.camelize_klass_file(file)
226
- file.split("_").map(&:capitalize).join
232
+ # --- all_parts: omit the false default ---
233
+ def all_parts_to_kv(model, doc)
234
+ return unless model.all_parts
235
+
236
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("all_parts", true))
237
+ end
238
+
239
+ def all_parts_from_kv(model, value)
240
+ model.all_parts = value
241
+ end
242
+
243
+ # Serialize typed_stage as just its unique code (e.g. "cd", "fdis"); the
244
+ # published default is omitted (recomputed from the class on load).
245
+ def stage_to_kv(model, doc)
246
+ ts = model.typed_stage
247
+ return unless ts&.code
248
+ return if ts.stage_code.to_s == "published"
249
+
250
+ doc.add_child(
251
+ Lutaml::KeyValue::DataModel::Element.new("stage", ts.code.to_s),
252
+ )
227
253
  end
228
254
 
229
- # IEC Scheme raises ArgumentError on miss instead of returning nil;
230
- # wrap so the same control flow works as in the ISO factory.
231
- def self.safe_locate_typed_stage(abbr)
232
- Scheme.locate_typed_stage_by_abbr(abbr.to_s)
233
- rescue ArgumentError
234
- nil
255
+ # Resolve the typed-stage code back within this identifier's class.
256
+ def stage_from_kv(model, value)
257
+ return if value.nil? || value.to_s.empty?
258
+
259
+ ts = (model.class.const_defined?(:TYPED_STAGES) &&
260
+ model.class::TYPED_STAGES.find { |t| t.code.to_s == value.to_s }) ||
261
+ Pubid::Iec.all_typed_stages.find { |t| t.code.to_s == value.to_s }
262
+ return unless ts
263
+
264
+ ts = ts.dup
265
+ ts.original_abbr = ts.canonical_abbreviation
266
+ model.typed_stage = ts
235
267
  end
236
268
 
237
- def self.resolve_create_typed_stage(klass, stage)
238
- if stage
239
- safe_locate_typed_stage(stage)
240
- elsif klass.const_defined?(:TYPED_STAGES)
241
- klass.const_get(:TYPED_STAGES).find do |ts|
242
- ts.stage_code.to_sym == :published
243
- end
269
+ def self.parse(string)
270
+ if string.length > Pubid::MAX_INPUT_LENGTH
271
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
272
+ end
273
+
274
+ # Route URN strings to the URN parser (mirrors Iso::Identifier.parse)
275
+ if Pubid::FormatDetector.detect(string) == :urn
276
+ return Pubid::Iec::UrnParser.parse(string)
244
277
  end
278
+
279
+ # Apply legacy update_codes normalization first, before any other preprocessing
280
+ normalized = Core::UpdateCodes.apply(string, :iec)
281
+ parsed = Pubid::Iec::Parser.new.parse(normalized)
282
+ if parsed.nil? || parsed.empty?
283
+ raise Pubid::Iec::Parser::ParseError,
284
+ "Invalid identifier format"
285
+ end
286
+
287
+ Pubid::Iec::Builder.new.build(parsed)
245
288
  end
246
- private_class_method :resolve_create_class,
247
- :safe_locate_typed_stage,
248
- :resolve_create_typed_stage, :coerce_create_attrs,
249
- :extract_supplement, :build_supplement,
250
- :build_based_supplement,
251
- :locate_klass_by_type_or_short, :all_create_klasses,
252
- :camelize_klass_file, :supplement_type?,
253
- :split_part
289
+
290
+ # from_hash is the shared polymorphic dispatch on Pubid::Identifier.
291
+ # IEC_TYPE_MAP remains as the key_value polymorphic_map.
254
292
  end
255
293
  end
256
294
  end
@@ -1,6 +1,4 @@
1
- require_relative "../supplement_identifier"
2
1
  # frozen_string_literal: true
3
- require_relative "../../components/typed_stage"
4
2
 
5
3
  module Pubid
6
4
  module Iec
@@ -86,7 +84,8 @@ module Pubid
86
84
  ].freeze
87
85
 
88
86
  def self.type
89
- { key: :amd, title: "Amendment", short: "AMD" }
87
+ { key: :amd,
88
+ web: :amendment, title: "Amendment", short: "AMD" }
90
89
  end
91
90
  end
92
91
  end
@@ -1,9 +1,4 @@
1
- require_relative "../single_identifier"
2
1
  # frozen_string_literal: true
3
- require_relative "../components/publisher"
4
- require_relative "../components/code"
5
- require_relative "../components/vap_suffix"
6
- require_relative "../components/trf_info"
7
2
 
8
3
  module Pubid
9
4
  module Iec
@@ -12,37 +7,17 @@ module Pubid
12
7
  # Inherits from SingleIdentifier to get common functionality
13
8
  # Single Responsibility: Common IEC identifier attributes and behavior
14
9
  class Base < SingleIdentifier
15
- # IEC-specific attributes
16
- attribute :vap_suffix, Components::VapSuffix, default: -> {}
10
+ # IEC-specific attributes. VAP codes live on VapIdentifier, not here.
17
11
  attribute :trf_info, Components::TrfInfo, default: -> {}
18
12
  attribute :database, :boolean, default: -> { false }
19
13
  attribute :fragment, :string, default: -> {}
20
14
  attribute :version, :string, default: -> {}
21
15
  attribute :decision_sheet, :string, default: -> {}
22
16
 
23
- def to_s(_format = :short)
24
- parts = []
25
-
26
- # Publisher and type portion (from typed_stage) - uses inherited method
27
- parts << publisher_portion
28
-
29
- # Number portion (number with part/subpart)
30
- parts << number_portion
31
-
32
- # Edition if present - add space before edition
33
- parts << " #{edition}" if edition&.number
34
-
35
- # VAP suffix
36
- parts << vap_suffix.render_with_space if vap_suffix
37
-
38
- # Database flag
39
- parts << " DB" if database
40
-
41
- # All-parts marker — rendered the same as the generic
42
- # HumanReadable renderer for parity (see Pubid::Renderers::HumanReadable#render).
43
- parts << " (all parts)" if all_parts
44
-
45
- parts.compact.join
17
+ # database is the only Base-specific serialized key (emitted when set);
18
+ # merged onto the common map inherited from Identifier.
19
+ key_value do
20
+ map "database", to: :database, render_default: false
46
21
  end
47
22
 
48
23
  def number_portion
@@ -70,9 +45,6 @@ module Pubid
70
45
  def validate!
71
46
  super if defined?(super)
72
47
 
73
- # Validate VAP suffix if present
74
- vap_suffix&.validate!
75
-
76
48
  # Validate TRF info if present
77
49
  trf_info&.validate! if trf_info && !trf_info.empty?
78
50
  end
@@ -1,5 +1,4 @@
1
- require_relative "base"
2
- require_relative "../../components/typed_stage"
1
+ # frozen_string_literal: true
3
2
 
4
3
  module Pubid
5
4
  module Iec
@@ -20,7 +19,8 @@ module Pubid
20
19
  ].freeze
21
20
 
22
21
  def self.type
23
- { key: :cs, title: "Component Specification", short: "CS" }
22
+ { key: :cs,
23
+ web: :component_specification, title: "Component Specification", short: "CS" }
24
24
  end
25
25
 
26
26
  # Override publisher_portion to add CS
@@ -1,5 +1,4 @@
1
- require_relative "base"
2
- require_relative "../../components/typed_stage"
1
+ # frozen_string_literal: true
3
2
 
4
3
  module Pubid
5
4
  module Iec