pubid 2.0.0.pre.alpha.2 → 2.0.0.pre.alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (458) 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 +7 -39
  6. data/lib/pubid/amca/identifiers/base.rb +0 -26
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -17
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -13
  9. data/lib/pubid/amca/renderer.rb +82 -0
  10. data/lib/pubid/amca/single_identifier.rb +0 -23
  11. data/lib/pubid/amca/urn_parser.rb +28 -0
  12. data/lib/pubid/amca.rb +42 -1
  13. data/lib/pubid/ansi/builder.rb +5 -3
  14. data/lib/pubid/ansi/identifier.rb +1 -43
  15. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  16. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  17. data/lib/pubid/ansi/renderer.rb +53 -0
  18. data/lib/pubid/ansi/single_identifier.rb +2 -31
  19. data/lib/pubid/ansi/urn_generator.rb +3 -38
  20. data/lib/pubid/ansi/urn_parser.rb +23 -0
  21. data/lib/pubid/ansi.rb +38 -3
  22. data/lib/pubid/api/builder.rb +29 -74
  23. data/lib/pubid/api/identifier.rb +0 -51
  24. data/lib/pubid/api/identifiers/base.rb +0 -2
  25. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  26. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  27. data/lib/pubid/api/identifiers/mpms.rb +1 -17
  28. data/lib/pubid/api/identifiers/publication.rb +0 -2
  29. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  30. data/lib/pubid/api/identifiers/specification.rb +0 -2
  31. data/lib/pubid/api/identifiers/standard.rb +0 -2
  32. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  33. data/lib/pubid/api/identifiers/typeless_standard.rb +1 -14
  34. data/lib/pubid/api/identifiers.rb +18 -0
  35. data/lib/pubid/api/renderer.rb +89 -0
  36. data/lib/pubid/api/single_identifier.rb +1 -13
  37. data/lib/pubid/api/urn_generator.rb +0 -18
  38. data/lib/pubid/api/urn_parser.rb +35 -0
  39. data/lib/pubid/api.rb +51 -5
  40. data/lib/pubid/ashrae/builder.rb +3 -3
  41. data/lib/pubid/ashrae/identifier.rb +6 -39
  42. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  43. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  44. data/lib/pubid/ashrae/identifiers/base.rb +3 -0
  45. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  46. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  47. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  48. data/lib/pubid/ashrae/renderer.rb +117 -0
  49. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  50. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  51. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  52. data/lib/pubid/ashrae.rb +42 -1
  53. data/lib/pubid/asme/components/code.rb +10 -2
  54. data/lib/pubid/asme/identifier.rb +0 -46
  55. data/lib/pubid/asme/identifiers/base.rb +0 -60
  56. data/lib/pubid/asme/renderer.rb +66 -0
  57. data/lib/pubid/asme/urn_parser.rb +31 -0
  58. data/lib/pubid/asme.rb +42 -1
  59. data/lib/pubid/astm/components/code.rb +9 -0
  60. data/lib/pubid/{jis → astm}/components.rb +1 -1
  61. data/lib/pubid/astm/identifier.rb +0 -77
  62. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  63. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  64. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  65. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  66. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  67. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  68. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  69. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  70. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  71. data/lib/pubid/astm/identifiers.rb +18 -0
  72. data/lib/pubid/astm/renderer.rb +172 -0
  73. data/lib/pubid/astm/single_identifier.rb +0 -10
  74. data/lib/pubid/astm/urn_parser.rb +30 -0
  75. data/lib/pubid/astm.rb +39 -27
  76. data/lib/pubid/bsi/builder.rb +21 -12
  77. data/lib/pubid/bsi/identifier.rb +8 -62
  78. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  79. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  80. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  81. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  82. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  83. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  84. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  85. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  87. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  88. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  89. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  90. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  91. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  92. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  93. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  94. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  95. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  96. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  97. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  98. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  99. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  100. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  101. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  102. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  103. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  104. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  105. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  106. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  107. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  108. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  109. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  110. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  111. data/lib/pubid/bsi/identifiers.rb +0 -1
  112. data/lib/pubid/bsi/renderer.rb +1050 -0
  113. data/lib/pubid/bsi/single_identifier.rb +6 -70
  114. data/lib/pubid/bsi/urn_generator.rb +2 -3
  115. data/lib/pubid/bsi/urn_parser.rb +52 -0
  116. data/lib/pubid/bsi.rb +224 -1
  117. data/lib/pubid/builder/base.rb +57 -10
  118. data/lib/pubid/bundled_identifier.rb +0 -1
  119. data/lib/pubid/ccsds/builder.rb +4 -3
  120. data/lib/pubid/ccsds/identifier.rb +63 -66
  121. data/lib/pubid/ccsds/identifiers/base.rb +11 -61
  122. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  123. data/lib/pubid/ccsds/parser.rb +4 -2
  124. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  125. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  126. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  127. data/lib/pubid/ccsds.rb +39 -1
  128. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  129. data/lib/pubid/cen_cenelec/identifier.rb +7 -38
  130. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  131. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  132. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  133. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  135. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  136. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  137. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  138. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  139. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  140. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  141. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  143. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  144. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  145. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  146. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  147. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  148. data/lib/pubid/cen_cenelec.rb +168 -1
  149. data/lib/pubid/cie/components/code.rb +8 -0
  150. data/lib/pubid/cie/identifier.rb +6 -57
  151. data/lib/pubid/cie/urn_parser.rb +28 -0
  152. data/lib/pubid/cie.rb +43 -1
  153. data/lib/pubid/components/adoption.rb +104 -0
  154. data/lib/pubid/components/code.rb +22 -8
  155. data/lib/pubid/components/date.rb +23 -16
  156. data/lib/pubid/components/edition.rb +9 -6
  157. data/lib/pubid/components/iteration.rb +32 -0
  158. data/lib/pubid/components/language.rb +6 -4
  159. data/lib/pubid/components/locality.rb +10 -1
  160. data/lib/pubid/components/publisher.rb +9 -6
  161. data/lib/pubid/components/relationship.rb +151 -0
  162. data/lib/pubid/components/stage.rb +5 -14
  163. data/lib/pubid/components/supplement.rb +184 -0
  164. data/lib/pubid/components/type.rb +5 -15
  165. data/lib/pubid/components/typed_stage.rb +10 -11
  166. data/lib/pubid/components.rb +4 -1
  167. data/lib/pubid/core/update_codes.rb +28 -7
  168. data/lib/pubid/csa/identifier.rb +0 -59
  169. data/lib/pubid/csa/identifiers/base.rb +2 -122
  170. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  171. data/lib/pubid/csa/identifiers/series.rb +2 -102
  172. data/lib/pubid/csa/renderer.rb +292 -0
  173. data/lib/pubid/csa/urn_generator.rb +1 -1
  174. data/lib/pubid/csa/urn_parser.rb +33 -0
  175. data/lib/pubid/csa.rb +42 -1
  176. data/lib/pubid/etsi/components/code.rb +9 -2
  177. data/lib/pubid/etsi/identifier.rb +0 -43
  178. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  179. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  180. data/lib/pubid/etsi/renderer.rb +42 -0
  181. data/lib/pubid/etsi/urn_parser.rb +34 -0
  182. data/lib/pubid/etsi.rb +42 -1
  183. data/lib/pubid/export/exporter.rb +4 -46
  184. data/lib/pubid/export/flavor_exporter.rb +111 -278
  185. data/lib/pubid/export.rb +0 -6
  186. data/lib/pubid/identifier.rb +2 -17
  187. data/lib/pubid/identifier_facade.rb +114 -0
  188. data/lib/pubid/identifier_metadata.rb +1 -1
  189. data/lib/pubid/idf/builder.rb +3 -3
  190. data/lib/pubid/idf/identifier.rb +3 -66
  191. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  192. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  193. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  194. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  195. data/lib/pubid/idf/parser.rb +3 -2
  196. data/lib/pubid/idf/renderer.rb +84 -0
  197. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  198. data/lib/pubid/idf/urn_generator.rb +4 -39
  199. data/lib/pubid/idf/urn_parser.rb +25 -0
  200. data/lib/pubid/idf.rb +51 -1
  201. data/lib/pubid/iec/builder.rb +46 -64
  202. data/lib/pubid/iec/components/code.rb +8 -32
  203. data/lib/pubid/iec/components/publisher.rb +0 -1
  204. data/lib/pubid/iec/components.rb +14 -0
  205. data/lib/pubid/iec/identifier.rb +251 -213
  206. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  207. data/lib/pubid/iec/identifiers/base.rb +8 -32
  208. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  209. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  210. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -26
  211. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  212. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -22
  213. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  214. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  215. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  216. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  217. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  218. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -11
  219. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  220. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  222. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  223. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  224. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  225. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -19
  226. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  227. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  228. data/lib/pubid/iec/identifiers.rb +30 -0
  229. data/lib/pubid/iec/parser.rb +13 -12
  230. data/lib/pubid/iec/renderer.rb +254 -0
  231. data/lib/pubid/iec/single_identifier.rb +6 -12
  232. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  233. data/lib/pubid/iec/urn_generator.rb +3 -3
  234. data/lib/pubid/iec/urn_parser.rb +3 -3
  235. data/lib/pubid/iec.rb +40 -68
  236. data/lib/pubid/ieee/builder.rb +12 -12
  237. data/lib/pubid/ieee/components/code.rb +8 -0
  238. data/lib/pubid/ieee/components/draft.rb +14 -0
  239. data/lib/pubid/ieee/components/relationship.rb +5 -149
  240. data/lib/pubid/ieee/identifier.rb +6 -41
  241. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  242. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  243. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  245. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  246. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  247. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  248. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  249. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  250. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  251. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  252. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  253. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  254. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  255. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  256. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  257. data/lib/pubid/ieee/pre_parser.rb +301 -0
  258. data/lib/pubid/ieee/renderer.rb +307 -0
  259. data/lib/pubid/ieee/urn_parser.rb +34 -0
  260. data/lib/pubid/ieee.rb +62 -1
  261. data/lib/pubid/ieee_debug.rb +0 -1
  262. data/lib/pubid/iho/builder.rb +2 -2
  263. data/lib/pubid/iho/identifier.rb +8 -42
  264. data/lib/pubid/iho/identifiers/base.rb +49 -10
  265. data/lib/pubid/iho/parser.rb +3 -3
  266. data/lib/pubid/iho/renderer.rb +30 -0
  267. data/lib/pubid/iho/urn_generator.rb +2 -2
  268. data/lib/pubid/iho/urn_parser.rb +58 -0
  269. data/lib/pubid/iho.rb +50 -1
  270. data/lib/pubid/iso/builder.rb +55 -53
  271. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  272. data/lib/pubid/iso/components/code.rb +7 -19
  273. data/lib/pubid/iso/components/publisher.rb +10 -8
  274. data/lib/pubid/iso/components.rb +2 -4
  275. data/lib/pubid/iso/identifier.rb +218 -252
  276. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  277. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  278. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  279. data/lib/pubid/iso/identifiers/data.rb +0 -1
  280. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  281. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  282. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  283. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  284. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  285. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  286. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  287. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  288. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  289. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  290. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  291. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  292. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  293. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  294. data/lib/pubid/iso/identifiers.rb +0 -1
  295. data/lib/pubid/iso/normalizer.rb +89 -0
  296. data/lib/pubid/iso/parser.rb +22 -4
  297. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  298. data/lib/pubid/iso/urn_generator.rb +66 -182
  299. data/lib/pubid/iso/urn_parser.rb +12 -7
  300. data/lib/pubid/iso.rb +173 -2
  301. data/lib/pubid/itu/builder.rb +0 -12
  302. data/lib/pubid/itu/components/code.rb +8 -0
  303. data/lib/pubid/itu/components.rb +11 -0
  304. data/lib/pubid/itu/identifier.rb +6 -104
  305. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  306. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  307. data/lib/pubid/itu/identifiers/base.rb +0 -6
  308. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  309. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  310. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  311. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  312. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  313. data/lib/pubid/itu/urn_parser.rb +23 -0
  314. data/lib/pubid/itu.rb +42 -1
  315. data/lib/pubid/jcgm/builder.rb +16 -8
  316. data/lib/pubid/jcgm/identifier.rb +0 -43
  317. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  318. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  319. data/lib/pubid/jcgm/renderer.rb +68 -0
  320. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  321. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  322. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  323. data/lib/pubid/jcgm.rb +43 -2
  324. data/lib/pubid/jis/builder.rb +44 -52
  325. data/lib/pubid/jis/identifier.rb +132 -46
  326. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  327. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  328. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  329. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  330. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  331. data/lib/pubid/jis/identifiers.rb +1 -1
  332. data/lib/pubid/jis/parser.rb +31 -5
  333. data/lib/pubid/jis/renderer.rb +69 -0
  334. data/lib/pubid/jis/single_identifier.rb +6 -12
  335. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  336. data/lib/pubid/jis/urn_parser.rb +23 -0
  337. data/lib/pubid/jis.rb +42 -2
  338. data/lib/pubid/nist/builder.rb +63 -1871
  339. data/lib/pubid/nist/caster.rb +1272 -0
  340. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  341. data/lib/pubid/nist/components/code.rb +9 -20
  342. data/lib/pubid/nist/components/supplement.rb +2 -2
  343. data/lib/pubid/nist/components.rb +0 -1
  344. data/lib/pubid/nist/identifier.rb +11 -48
  345. data/lib/pubid/nist/identifiers/base.rb +110 -47
  346. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  347. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -1
  348. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  349. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  350. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  351. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -8
  352. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  353. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +15 -24
  354. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  355. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  356. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  357. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  358. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  359. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  360. data/lib/pubid/nist/identifiers/report.rb +4 -2
  361. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  362. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  363. data/lib/pubid/nist/identifiers.rb +1 -0
  364. data/lib/pubid/nist/parser.rb +62 -452
  365. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  366. data/lib/pubid/nist/preprocessor.rb +416 -0
  367. data/lib/pubid/nist/renderer.rb +43 -0
  368. data/lib/pubid/nist/router.rb +148 -0
  369. data/lib/pubid/nist/series/base.rb +58 -0
  370. data/lib/pubid/nist/series/crpl.rb +13 -0
  371. data/lib/pubid/nist/series/fips.rb +14 -0
  372. data/lib/pubid/nist/series/ir.rb +60 -0
  373. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  374. data/lib/pubid/nist/series/mono.rb +19 -0
  375. data/lib/pubid/nist/series/ncstar.rb +20 -0
  376. data/lib/pubid/nist/series.rb +49 -0
  377. data/lib/pubid/nist/supplement_identifier.rb +3 -1
  378. data/lib/pubid/nist/urn_parser.rb +67 -0
  379. data/lib/pubid/nist.rb +82 -4
  380. data/lib/pubid/oiml/components/code.rb +10 -0
  381. data/lib/pubid/oiml/identifier.rb +0 -50
  382. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  383. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  384. data/lib/pubid/oiml/renderer.rb +161 -0
  385. data/lib/pubid/oiml/single_identifier.rb +6 -45
  386. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  387. data/lib/pubid/oiml/urn_generator.rb +0 -8
  388. data/lib/pubid/oiml/urn_parser.rb +22 -0
  389. data/lib/pubid/oiml.rb +42 -1
  390. data/lib/pubid/plateau/identifier.rb +7 -41
  391. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  392. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  393. data/lib/pubid/plateau/renderer.rb +51 -0
  394. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  395. data/lib/pubid/plateau/urn_parser.rb +43 -0
  396. data/lib/pubid/plateau.rb +43 -1
  397. data/lib/pubid/renderers/directives_renderer.rb +22 -8
  398. data/lib/pubid/renderers/guide_renderer.rb +4 -2
  399. data/lib/pubid/renderers/human_readable.rb +18 -7
  400. data/lib/pubid/rendering/context.rb +28 -19
  401. data/lib/pubid/rendering.rb +0 -3
  402. data/lib/pubid/sae/components/date.rb +8 -0
  403. data/lib/pubid/sae/components/type.rb +5 -1
  404. data/lib/pubid/sae/identifier.rb +0 -23
  405. data/lib/pubid/sae/identifiers/base.rb +2 -16
  406. data/lib/pubid/sae/renderer.rb +36 -0
  407. data/lib/pubid/sae/urn_generator.rb +2 -10
  408. data/lib/pubid/sae/urn_parser.rb +36 -0
  409. data/lib/pubid/sae.rb +42 -1
  410. data/lib/pubid/urn_generator/base.rb +12 -12
  411. data/lib/pubid/urn_parser/base.rb +81 -0
  412. data/lib/pubid/urn_parser/errors.rb +9 -0
  413. data/lib/pubid/urn_parser.rb +14 -0
  414. data/lib/pubid/version.rb +1 -1
  415. data/lib/pubid.rb +29 -7
  416. data/lib/tasks/website-data.json +1940 -1882
  417. metadata +75 -44
  418. data/lib/pubid/amca/scheme.rb +0 -16
  419. data/lib/pubid/ansi/scheme.rb +0 -15
  420. data/lib/pubid/api/scheme.rb +0 -66
  421. data/lib/pubid/ashrae/scheme.rb +0 -53
  422. data/lib/pubid/asme/scheme.rb +0 -37
  423. data/lib/pubid/astm/scheme.rb +0 -55
  424. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  425. data/lib/pubid/bsi/scheme.rb +0 -243
  426. data/lib/pubid/ccsds/scheme.rb +0 -57
  427. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  428. data/lib/pubid/cie/scheme.rb +0 -64
  429. data/lib/pubid/components/factory.rb +0 -50
  430. data/lib/pubid/csa/scheme.rb +0 -44
  431. data/lib/pubid/etsi/scheme.rb +0 -42
  432. data/lib/pubid/export/data_class_exporter.rb +0 -59
  433. data/lib/pubid/export/ieee_exporter.rb +0 -78
  434. data/lib/pubid/export/itu_exporter.rb +0 -66
  435. data/lib/pubid/export/nist_exporter.rb +0 -64
  436. data/lib/pubid/export/registry_exporter.rb +0 -90
  437. data/lib/pubid/export/scheme_exporter.rb +0 -70
  438. data/lib/pubid/identifier_registry.rb +0 -198
  439. data/lib/pubid/idf/scheme.rb +0 -61
  440. data/lib/pubid/iec/scheme.rb +0 -71
  441. data/lib/pubid/ieee/scheme.rb +0 -90
  442. data/lib/pubid/iho/scheme.rb +0 -29
  443. data/lib/pubid/iso/identifiers/base.rb +0 -115
  444. data/lib/pubid/iso/scheme.rb +0 -193
  445. data/lib/pubid/itu/scheme.rb +0 -174
  446. data/lib/pubid/jcgm/scheme.rb +0 -60
  447. data/lib/pubid/jis/components/code.rb +0 -59
  448. data/lib/pubid/jis/identifiers/base.rb +0 -72
  449. data/lib/pubid/jis/scheme.rb +0 -49
  450. data/lib/pubid/nist/components/publisher.rb +0 -24
  451. data/lib/pubid/nist/scheme.rb +0 -199
  452. data/lib/pubid/oiml/scheme.rb +0 -46
  453. data/lib/pubid/plateau/scheme.rb +0 -45
  454. data/lib/pubid/rendering/base.rb +0 -73
  455. data/lib/pubid/rendering/common.rb +0 -211
  456. data/lib/pubid/rendering/format.rb +0 -25
  457. data/lib/pubid/sae/scheme.rb +0 -47
  458. data/lib/pubid/scheme.rb +0 -219
@@ -1,58 +1,34 @@
1
- require "lutaml/model"
2
- require_relative "../../components/code"
3
1
  # frozen_string_literal: true
4
2
 
5
3
  module Pubid
6
4
  module Iec
7
5
  module Components
6
+ # Code component for IEC identifiers.
7
+ #
8
+ # Inherits +value+ and +prefix+ from the shared Code; overrides
9
+ # rendering to place the prefix (e.g. "TR", "TS") before the value.
8
10
  class Code < ::Pubid::Components::Code
9
- attribute :prefix, :string, default: -> {}
10
- attribute :number, :string
11
- attribute :part, :string, default: -> {}
12
-
13
- def initialize(value: nil, number: nil, prefix: nil, part: nil)
14
- # Support both 'value' (for convenience) and 'number' (explicit)
15
- @number = value || number
16
- @prefix = prefix
17
- @part = part
18
- end
19
-
20
11
  def to_s
21
12
  result = ""
22
13
  result += "#{prefix} " if prefix
23
- result += number
24
- result += "-#{part}" if part
14
+ result += value.to_s
25
15
  result
26
16
  end
27
17
 
28
- def full_code
29
- to_s
30
- end
18
+ alias full_code to_s
31
19
 
32
20
  # Parse IEC code formats:
33
21
  # - "60034" (just number)
34
- # - "60034-1" (number with part)
35
22
  # - "TR 61000" (with prefix)
36
23
  # - "TS 62443" (with prefix)
37
24
  def self.parse(string)
38
25
  parts = string.strip.split(" ", 2)
39
26
 
40
27
  if parts.size == 2
41
- # Has prefix: "TR 61000-1-2"
42
- prefix = parts[0]
43
- number_part = parts[1]
28
+ new(prefix: parts[0], value: parts[1])
44
29
  else
45
- # No prefix: "60034-1"
46
- prefix = nil
47
- number_part = parts[0]
30
+ new(value: parts[0])
48
31
  end
49
-
50
- # Split number and part
51
- number_parts = number_part.split("-", 2)
52
- number = number_parts[0]
53
- part = number_parts[1]
54
-
55
- new(prefix: prefix, number: number, part: part)
56
32
  end
57
33
  end
58
34
  end
@@ -1,5 +1,4 @@
1
1
  require "lutaml/model"
2
- require_relative "../../components/publisher"
3
2
  # frozen_string_literal: true
4
3
 
5
4
  module Pubid
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Iec
5
+ module Components
6
+ autoload :Code, "#{__dir__}/components/code"
7
+ autoload :ConsolidatedAmendment, "#{__dir__}/components/consolidated_amendment"
8
+ autoload :Publisher, "#{__dir__}/components/publisher"
9
+ autoload :Sheet, "#{__dir__}/components/sheet"
10
+ autoload :TrfInfo, "#{__dir__}/components/trf_info"
11
+ autoload :VapSuffix, "#{__dir__}/components/vap_suffix"
12
+ end
13
+ end
14
+ end
@@ -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
+ # Build the type map from the live class list, for the validation spec.
102
+ def self.build_type_map
103
+ types = Pubid::Iec.identifier_types
104
+ extra = [Identifiers::ConsolidatedIdentifier, Identifiers::VapIdentifier,
105
+ Identifiers::SheetIdentifier, Identifiers::Base, SingleIdentifier]
106
+ (types + extra).uniq.to_h { |klass| [klass.polymorphic_name, klass.name] }
75
107
  end
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
+ # The base Pubid::Identifier no longer auto-maps attributes, so each
110
+ # flavor's top class declares its own key_value mapping. Subclasses merge
111
+ # their own blocks on top of this one (e.g. SupplementIdentifier adds
112
+ # base; VapIdentifier adds vap), so list every base attribute IEC
113
+ # serializes here once. Code/Date are flattened to plain scalars; the
114
+ # verbose type/stage trees are not mapped (type/stage are recomputed from
115
+ # typed_stage, which serializes as just its code under "stage").
116
+ key_value do
117
+ map "_type", to: :_type, polymorphic_map: IEC_TYPE_MAP
118
+ # Code components serialize as their plain string value, not {value,...}.
119
+ map "number", with: { to: :number_to_kv, from: :number_from_kv }
120
+ map "part", with: { to: :part_to_kv, from: :part_from_kv }
121
+ map "subpart", with: { to: :subpart_to_kv, from: :subpart_from_kv }
122
+ map "stage_iteration",
123
+ with: { to: :stage_iteration_to_kv, from: :stage_iteration_from_kv }
124
+ # IEC dates are year-only, so flatten the Date component to a scalar year.
125
+ map "year", with: { to: :year_to_kv, from: :year_from_kv }
126
+ map "edition", to: :edition, render_default: false
127
+ map "languages", to: :languages, render_default: false
128
+ # publisher emitted only when the primary isn't the IEC default;
129
+ # copublishers (the other bodies) as an array, omitted when empty.
130
+ map "publisher", with: { to: :publisher_to_kv, from: :publisher_from_kv }
131
+ map "copublishers",
132
+ with: { to: :copublishers_to_kv, from: :copublishers_from_kv }
133
+ # `type` and generic `stage` are fully derived from `typed_stage`, so we
134
+ # serialize only the unique typed-stage code under "stage" and recompute
135
+ # the rest on load. _type already pins the document type.
136
+ map "stage", with: { to: :stage_to_kv, from: :stage_from_kv }
137
+ # Omit the `false` default; only the meaningful `true` is serialized.
138
+ map "all_parts", with: { to: :all_parts_to_kv, from: :all_parts_from_kv }
86
139
  end
87
140
 
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)
141
+ # --- Code components <-> plain string ---
142
+ def number_to_kv(model, doc) = emit_code(doc, "number", model.number)
143
+ def number_from_kv(model, value) = model.number = build_code(value)
144
+ def part_to_kv(model, doc) = emit_code(doc, "part", model.part)
145
+ def part_from_kv(model, value) = model.part = build_code(value)
146
+ def subpart_to_kv(model, doc) = emit_code(doc, "subpart", model.subpart)
147
+ def subpart_from_kv(model, value) = model.subpart = build_code(value)
148
+
149
+ def emit_code(doc, key, code)
150
+ v = code.is_a?(::Pubid::Components::Code) ? code.value : code
151
+ return if v.nil? || v.to_s.empty?
152
+
153
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, v.to_s))
105
154
  end
106
155
 
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)
156
+ def build_code(value)
157
+ return if value.nil? || value.to_s.empty?
158
+
159
+ ::Pubid::Iec::Components::Code.new(value: value.to_s)
124
160
  end
125
161
 
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
162
+ def stage_iteration_to_kv(model, doc)
163
+ iter = model.stage_iteration
164
+ v = iter.is_a?(::Pubid::Components::Iteration) ? iter.number : iter
165
+ return if v.nil? || v.to_s.empty?
166
+
167
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("stage_iteration",
168
+ v.to_s))
156
169
  end
157
170
 
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
171
+ def stage_iteration_from_kv(model, value)
172
+ return if value.nil? || value.to_s.empty?
173
+
174
+ model.stage_iteration =
175
+ ::Pubid::Components::Iteration.new(number: value.to_s)
167
176
  end
168
177
 
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
178
+ # --- date <-> scalar year (IEC dates are year-only) ---
179
+ def year_to_kv(model, doc)
180
+ y = model.date&.year
181
+ return if y.nil? || y.to_s.empty?
178
182
 
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
183
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("year", y.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
+ def year_from_kv(model, value)
187
+ return if value.nil? || value.to_s.empty?
188
+
189
+ (model.date ||= ::Pubid::Components::Date.new).year = value.to_s
197
190
  end
198
191
 
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 }
192
+ # --- publisher: primary only when non-default; copublishers as a list ---
193
+ def publisher_to_kv(model, doc)
194
+ pub = model.publisher&.body
195
+ return if pub.nil? || pub == model.class.default_publisher&.body
196
+
197
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("publisher", pub))
209
198
  end
210
199
 
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
200
+ def publisher_from_kv(model, value)
201
+ return if value.nil? || value.to_s.empty?
202
+
203
+ model.publisher = ::Pubid::Iec::Components::Publisher.new(body: value.to_s)
204
+ end
205
+
206
+ def copublishers_to_kv(model, doc)
207
+ cp = model.copublishers
208
+ return unless cp&.any?
209
+
210
+ doc.add_child(
211
+ Lutaml::KeyValue::DataModel::Element.new("copublishers", cp.map(&:body)),
212
+ )
213
+ end
214
+
215
+ def copublishers_from_kv(model, value)
216
+ list = Array(value).map(&:to_s)
217
+ return unless list.any?
218
+
219
+ model.copublishers = list.map do |cp|
220
+ ::Pubid::Iec::Components::Publisher.new(body: cp)
222
221
  end
223
222
  end
224
223
 
225
- def self.camelize_klass_file(file)
226
- file.split("_").map(&:capitalize).join
224
+ # --- all_parts: omit the false default ---
225
+ def all_parts_to_kv(model, doc)
226
+ return unless model.all_parts
227
+
228
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("all_parts", true))
229
+ end
230
+
231
+ def all_parts_from_kv(model, value)
232
+ model.all_parts = value
233
+ end
234
+
235
+ # Serialize typed_stage as just its unique code (e.g. "cd", "fdis"); the
236
+ # published default is omitted (recomputed from the class on load).
237
+ def stage_to_kv(model, doc)
238
+ ts = model.typed_stage
239
+ return unless ts&.code
240
+ return if ts.stage_code.to_s == "published"
241
+
242
+ doc.add_child(
243
+ Lutaml::KeyValue::DataModel::Element.new("stage", ts.code.to_s),
244
+ )
227
245
  end
228
246
 
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
247
+ # Resolve the typed-stage code back within this identifier's class.
248
+ def stage_from_kv(model, value)
249
+ return if value.nil? || value.to_s.empty?
250
+
251
+ ts = (model.class.const_defined?(:TYPED_STAGES) &&
252
+ model.class::TYPED_STAGES.find { |t| t.code.to_s == value.to_s }) ||
253
+ Pubid::Iec.all_typed_stages.find { |t| t.code.to_s == value.to_s }
254
+ return unless ts
255
+
256
+ ts = ts.dup
257
+ ts.original_abbr = ts.canonical_abbreviation
258
+ model.typed_stage = ts
259
+ end
260
+
261
+ def self.parse(string)
262
+ # Route URN strings to the URN parser (mirrors Iso::Identifier.parse)
263
+ if Pubid::FormatDetector.detect(string) == :urn
264
+ return Pubid::Iec::UrnParser.parse(string)
265
+ end
266
+
267
+ # Apply legacy update_codes normalization first, before any other preprocessing
268
+ normalized = Core::UpdateCodes.apply(string, :iec)
269
+ parsed = Pubid::Iec::Parser.new.parse(normalized)
270
+ if parsed.nil? || parsed.empty?
271
+ raise Pubid::Iec::Parser::ParseError,
272
+ "Invalid identifier format"
273
+ end
274
+
275
+ Pubid::Iec::Builder.new.build(parsed)
235
276
  end
236
277
 
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
278
+ # lutaml's polymorphic key_value mapping reads `_type` only to validate; it
279
+ # does not re-instantiate the concrete subclass on root deserialization. So
280
+ # `Identifier.from_hash(amendment_hash)` would return a bare Identifier and
281
+ # drop base_identifier. Route by `_type` to the right subclass and let its
282
+ # (inherited) from_hash do the real work, mirroring ISO/JIS.
283
+ def self.from_hash(data, options = {})
284
+ type = data["_type"] || data[:_type]
285
+ klass_name = IEC_TYPE_MAP[type]
286
+ if klass_name
287
+ klass = Object.const_get(klass_name)
288
+ return klass.from_hash(data, options) unless klass == self
244
289
  end
290
+ super
245
291
  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
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