pubid 2.0.0.pre.alpha.1 → 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 (463) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +27 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +7 -0
  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 -1
  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 -4
  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 -0
  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/identifiers/base.rb +0 -60
  55. data/lib/pubid/asme/renderer.rb +66 -0
  56. data/lib/pubid/asme/urn_parser.rb +31 -0
  57. data/lib/pubid/asme.rb +42 -1
  58. data/lib/pubid/astm/components/code.rb +9 -0
  59. data/lib/pubid/{jis → astm}/components.rb +1 -1
  60. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  61. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  62. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  63. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  64. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  65. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  66. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  67. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  68. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  69. data/lib/pubid/astm/identifiers.rb +18 -0
  70. data/lib/pubid/astm/renderer.rb +172 -0
  71. data/lib/pubid/astm/single_identifier.rb +0 -10
  72. data/lib/pubid/astm/urn_parser.rb +30 -0
  73. data/lib/pubid/astm.rb +39 -27
  74. data/lib/pubid/bsi/builder.rb +21 -12
  75. data/lib/pubid/bsi/identifier.rb +8 -2
  76. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  77. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  78. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  79. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  80. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  81. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  82. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  83. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  84. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  85. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  87. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  88. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  89. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  90. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  91. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  92. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  93. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  94. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  95. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  96. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  97. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  98. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  99. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  100. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  101. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  102. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  103. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  104. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  105. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  106. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  107. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  108. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  109. data/lib/pubid/bsi/identifiers.rb +0 -1
  110. data/lib/pubid/bsi/renderer.rb +1050 -0
  111. data/lib/pubid/bsi/single_identifier.rb +6 -70
  112. data/lib/pubid/bsi/urn_generator.rb +2 -3
  113. data/lib/pubid/bsi/urn_parser.rb +52 -0
  114. data/lib/pubid/bsi.rb +224 -1
  115. data/lib/pubid/builder/base.rb +57 -10
  116. data/lib/pubid/bundled_identifier.rb +0 -1
  117. data/lib/pubid/ccsds/builder.rb +4 -3
  118. data/lib/pubid/ccsds/identifier.rb +66 -1
  119. data/lib/pubid/ccsds/identifiers/base.rb +11 -50
  120. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  121. data/lib/pubid/ccsds/parser.rb +4 -2
  122. data/lib/pubid/ccsds/single_identifier.rb +4 -1
  123. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  124. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  125. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  126. data/lib/pubid/ccsds.rb +39 -1
  127. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  128. data/lib/pubid/cen_cenelec/identifier.rb +8 -2
  129. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  130. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  131. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  132. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  133. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  135. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  136. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  137. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  138. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  140. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  141. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  143. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  144. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  145. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  146. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  147. data/lib/pubid/cen_cenelec.rb +168 -1
  148. data/lib/pubid/cie/components/code.rb +8 -0
  149. data/lib/pubid/cie/identifier.rb +6 -4
  150. data/lib/pubid/cie/urn_parser.rb +28 -0
  151. data/lib/pubid/cie.rb +43 -1
  152. data/lib/pubid/components/adoption.rb +104 -0
  153. data/lib/pubid/components/code.rb +22 -8
  154. data/lib/pubid/components/date.rb +23 -16
  155. data/lib/pubid/components/edition.rb +9 -6
  156. data/lib/pubid/components/iteration.rb +32 -0
  157. data/lib/pubid/components/language.rb +6 -4
  158. data/lib/pubid/components/locality.rb +10 -1
  159. data/lib/pubid/components/publisher.rb +9 -6
  160. data/lib/pubid/components/relationship.rb +151 -0
  161. data/lib/pubid/components/stage.rb +5 -14
  162. data/lib/pubid/components/supplement.rb +184 -0
  163. data/lib/pubid/components/type.rb +5 -15
  164. data/lib/pubid/components/typed_stage.rb +11 -8
  165. data/lib/pubid/components.rb +4 -0
  166. data/lib/pubid/core/update_codes.rb +28 -7
  167. data/lib/pubid/csa/identifier.rb +0 -3
  168. data/lib/pubid/csa/identifiers/base.rb +2 -122
  169. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  170. data/lib/pubid/csa/identifiers/series.rb +2 -102
  171. data/lib/pubid/csa/renderer.rb +292 -0
  172. data/lib/pubid/csa/urn_generator.rb +1 -1
  173. data/lib/pubid/csa/urn_parser.rb +33 -0
  174. data/lib/pubid/csa.rb +42 -1
  175. data/lib/pubid/etsi/components/code.rb +9 -2
  176. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  177. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  178. data/lib/pubid/etsi/renderer.rb +42 -0
  179. data/lib/pubid/etsi/urn_parser.rb +34 -0
  180. data/lib/pubid/etsi.rb +42 -1
  181. data/lib/pubid/export/exporter.rb +4 -46
  182. data/lib/pubid/export/flavor_exporter.rb +111 -278
  183. data/lib/pubid/export.rb +0 -6
  184. data/lib/pubid/identifier.rb +10 -18
  185. data/lib/pubid/identifier_facade.rb +114 -0
  186. data/lib/pubid/identifier_metadata.rb +1 -1
  187. data/lib/pubid/idf/builder.rb +3 -3
  188. data/lib/pubid/idf/identifier.rb +3 -6
  189. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  190. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  191. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  192. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  193. data/lib/pubid/idf/parser.rb +3 -2
  194. data/lib/pubid/idf/renderer.rb +84 -0
  195. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  196. data/lib/pubid/idf/urn_generator.rb +4 -39
  197. data/lib/pubid/idf/urn_parser.rb +25 -0
  198. data/lib/pubid/idf.rb +51 -1
  199. data/lib/pubid/iec/builder.rb +48 -65
  200. data/lib/pubid/iec/components/code.rb +9 -32
  201. data/lib/pubid/iec/components/publisher.rb +1 -1
  202. data/lib/pubid/iec/components.rb +14 -0
  203. data/lib/pubid/iec/identifier.rb +276 -3
  204. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  205. data/lib/pubid/iec/identifiers/base.rb +8 -28
  206. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  207. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  208. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -30
  209. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  210. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -26
  211. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  212. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  213. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  214. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  215. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  216. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -15
  217. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  218. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  219. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  220. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  222. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  223. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -23
  224. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  225. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  226. data/lib/pubid/iec/identifiers.rb +30 -0
  227. data/lib/pubid/iec/parser.rb +20 -14
  228. data/lib/pubid/iec/renderer.rb +254 -0
  229. data/lib/pubid/iec/single_identifier.rb +6 -12
  230. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  231. data/lib/pubid/iec/urn_generator.rb +57 -171
  232. data/lib/pubid/iec/urn_parser.rb +53 -252
  233. data/lib/pubid/iec.rb +40 -68
  234. data/lib/pubid/ieee/builder.rb +12 -12
  235. data/lib/pubid/ieee/components/code.rb +8 -0
  236. data/lib/pubid/ieee/components/draft.rb +14 -0
  237. data/lib/pubid/ieee/components/relationship.rb +5 -149
  238. data/lib/pubid/ieee/identifier.rb +6 -0
  239. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  240. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  241. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  242. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  243. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  245. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  246. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  247. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  248. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  249. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  250. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  251. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  252. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  253. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  254. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  255. data/lib/pubid/ieee/pre_parser.rb +301 -0
  256. data/lib/pubid/ieee/renderer.rb +307 -0
  257. data/lib/pubid/ieee/urn_parser.rb +34 -0
  258. data/lib/pubid/ieee.rb +62 -1
  259. data/lib/pubid/ieee_debug.rb +0 -1
  260. data/lib/pubid/iho/builder.rb +2 -2
  261. data/lib/pubid/iho/identifier.rb +8 -0
  262. data/lib/pubid/iho/identifiers/base.rb +49 -10
  263. data/lib/pubid/iho/identifiers/bibliographic.rb +0 -4
  264. data/lib/pubid/iho/identifiers/circular_letter.rb +0 -4
  265. data/lib/pubid/iho/identifiers/miscellaneous.rb +0 -4
  266. data/lib/pubid/iho/identifiers/publication.rb +0 -4
  267. data/lib/pubid/iho/identifiers/standard.rb +0 -4
  268. data/lib/pubid/iho/parser.rb +3 -3
  269. data/lib/pubid/iho/renderer.rb +30 -0
  270. data/lib/pubid/iho/urn_generator.rb +3 -3
  271. data/lib/pubid/iho/urn_parser.rb +58 -0
  272. data/lib/pubid/iho.rb +50 -1
  273. data/lib/pubid/iso/builder.rb +59 -53
  274. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  275. data/lib/pubid/iso/components/code.rb +7 -19
  276. data/lib/pubid/iso/components/publisher.rb +10 -8
  277. data/lib/pubid/iso/components.rb +2 -4
  278. data/lib/pubid/iso/identifier.rb +233 -6
  279. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  280. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  281. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  282. data/lib/pubid/iso/identifiers/data.rb +0 -1
  283. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  284. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  285. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  286. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  287. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  288. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  289. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  290. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  291. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  292. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  293. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  294. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  295. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  296. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  297. data/lib/pubid/iso/identifiers.rb +0 -1
  298. data/lib/pubid/iso/normalizer.rb +89 -0
  299. data/lib/pubid/iso/parser.rb +26 -6
  300. data/lib/pubid/iso/single_identifier.rb +6 -3
  301. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  302. data/lib/pubid/iso/urn_generator.rb +74 -176
  303. data/lib/pubid/iso/urn_parser.rb +28 -9
  304. data/lib/pubid/iso.rb +173 -2
  305. data/lib/pubid/itu/builder.rb +0 -12
  306. data/lib/pubid/itu/components/code.rb +8 -0
  307. data/lib/pubid/itu/components.rb +11 -0
  308. data/lib/pubid/itu/identifier.rb +6 -39
  309. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  310. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  311. data/lib/pubid/itu/identifiers/base.rb +0 -6
  312. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  313. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  314. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  315. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  316. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  317. data/lib/pubid/itu/urn_parser.rb +23 -0
  318. data/lib/pubid/itu.rb +42 -1
  319. data/lib/pubid/jcgm/builder.rb +16 -8
  320. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  321. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  322. data/lib/pubid/jcgm/renderer.rb +68 -0
  323. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  324. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  325. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  326. data/lib/pubid/jcgm.rb +43 -2
  327. data/lib/pubid/jis/builder.rb +44 -52
  328. data/lib/pubid/jis/identifier.rb +132 -3
  329. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  330. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  331. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  332. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  333. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  334. data/lib/pubid/jis/identifiers.rb +1 -1
  335. data/lib/pubid/jis/parser.rb +31 -5
  336. data/lib/pubid/jis/renderer.rb +69 -0
  337. data/lib/pubid/jis/single_identifier.rb +6 -12
  338. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  339. data/lib/pubid/jis/urn_parser.rb +23 -0
  340. data/lib/pubid/jis.rb +42 -2
  341. data/lib/pubid/nist/builder.rb +122 -1761
  342. data/lib/pubid/nist/caster.rb +1272 -0
  343. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  344. data/lib/pubid/nist/components/code.rb +9 -20
  345. data/lib/pubid/nist/components/edition.rb +16 -0
  346. data/lib/pubid/nist/components/supplement.rb +88 -21
  347. data/lib/pubid/nist/components.rb +0 -1
  348. data/lib/pubid/nist/identifier.rb +25 -0
  349. data/lib/pubid/nist/identifiers/base.rb +206 -64
  350. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  351. data/lib/pubid/nist/identifiers/circular_supplement.rb +3 -2
  352. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  353. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  354. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  355. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -11
  356. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  357. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +17 -16
  358. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  359. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  360. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  361. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  362. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  363. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  364. data/lib/pubid/nist/identifiers/report.rb +4 -3
  365. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  366. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  367. data/lib/pubid/nist/identifiers.rb +1 -0
  368. data/lib/pubid/nist/parser.rb +67 -424
  369. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  370. data/lib/pubid/nist/preprocessor.rb +416 -0
  371. data/lib/pubid/nist/renderer.rb +43 -0
  372. data/lib/pubid/nist/router.rb +148 -0
  373. data/lib/pubid/nist/series/base.rb +58 -0
  374. data/lib/pubid/nist/series/crpl.rb +13 -0
  375. data/lib/pubid/nist/series/fips.rb +14 -0
  376. data/lib/pubid/nist/series/ir.rb +60 -0
  377. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  378. data/lib/pubid/nist/series/mono.rb +19 -0
  379. data/lib/pubid/nist/series/ncstar.rb +20 -0
  380. data/lib/pubid/nist/series.rb +49 -0
  381. data/lib/pubid/nist/supplement_identifier.rb +11 -25
  382. data/lib/pubid/nist/urn_generator.rb +14 -8
  383. data/lib/pubid/nist/urn_parser.rb +67 -0
  384. data/lib/pubid/nist.rb +83 -4
  385. data/lib/pubid/oiml/components/code.rb +10 -0
  386. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  387. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  388. data/lib/pubid/oiml/renderer.rb +161 -0
  389. data/lib/pubid/oiml/single_identifier.rb +6 -45
  390. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  391. data/lib/pubid/oiml/urn_generator.rb +0 -8
  392. data/lib/pubid/oiml/urn_parser.rb +22 -0
  393. data/lib/pubid/oiml.rb +42 -1
  394. data/lib/pubid/plateau/identifier.rb +23 -0
  395. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  396. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  397. data/lib/pubid/plateau/renderer.rb +51 -0
  398. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  399. data/lib/pubid/plateau/urn_parser.rb +43 -0
  400. data/lib/pubid/plateau.rb +44 -1
  401. data/lib/pubid/renderers/base.rb +34 -0
  402. data/lib/pubid/renderers/directives_renderer.rb +27 -14
  403. data/lib/pubid/renderers/guide_renderer.rb +7 -1
  404. data/lib/pubid/renderers/human_readable.rb +31 -8
  405. data/lib/pubid/renderers/iwa_renderer.rb +5 -1
  406. data/lib/pubid/renderers/supplement_renderer.rb +4 -1
  407. data/lib/pubid/rendering/context.rb +33 -21
  408. data/lib/pubid/rendering.rb +0 -3
  409. data/lib/pubid/sae/components/date.rb +8 -0
  410. data/lib/pubid/sae/components/type.rb +5 -1
  411. data/lib/pubid/sae/identifiers/base.rb +2 -16
  412. data/lib/pubid/sae/renderer.rb +36 -0
  413. data/lib/pubid/sae/urn_generator.rb +2 -10
  414. data/lib/pubid/sae/urn_parser.rb +36 -0
  415. data/lib/pubid/sae.rb +42 -1
  416. data/lib/pubid/urn_generator/base.rb +12 -12
  417. data/lib/pubid/urn_parser/base.rb +81 -0
  418. data/lib/pubid/urn_parser/errors.rb +9 -0
  419. data/lib/pubid/urn_parser.rb +14 -0
  420. data/lib/pubid/version.rb +1 -1
  421. data/lib/pubid.rb +29 -7
  422. data/lib/tasks/website-data.json +1940 -1882
  423. metadata +77 -43
  424. data/lib/pubid/amca/scheme.rb +0 -16
  425. data/lib/pubid/ansi/scheme.rb +0 -15
  426. data/lib/pubid/api/scheme.rb +0 -66
  427. data/lib/pubid/ashrae/scheme.rb +0 -53
  428. data/lib/pubid/asme/scheme.rb +0 -37
  429. data/lib/pubid/astm/scheme.rb +0 -55
  430. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  431. data/lib/pubid/bsi/scheme.rb +0 -243
  432. data/lib/pubid/ccsds/scheme.rb +0 -57
  433. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  434. data/lib/pubid/cie/scheme.rb +0 -64
  435. data/lib/pubid/csa/scheme.rb +0 -44
  436. data/lib/pubid/etsi/scheme.rb +0 -42
  437. data/lib/pubid/export/data_class_exporter.rb +0 -59
  438. data/lib/pubid/export/ieee_exporter.rb +0 -78
  439. data/lib/pubid/export/itu_exporter.rb +0 -66
  440. data/lib/pubid/export/nist_exporter.rb +0 -64
  441. data/lib/pubid/export/registry_exporter.rb +0 -90
  442. data/lib/pubid/export/scheme_exporter.rb +0 -70
  443. data/lib/pubid/identifier_registry.rb +0 -198
  444. data/lib/pubid/idf/scheme.rb +0 -61
  445. data/lib/pubid/iec/scheme.rb +0 -71
  446. data/lib/pubid/ieee/scheme.rb +0 -90
  447. data/lib/pubid/iho/scheme.rb +0 -29
  448. data/lib/pubid/iso/identifiers/base.rb +0 -115
  449. data/lib/pubid/iso/scheme.rb +0 -187
  450. data/lib/pubid/itu/scheme.rb +0 -174
  451. data/lib/pubid/jcgm/scheme.rb +0 -60
  452. data/lib/pubid/jis/components/code.rb +0 -59
  453. data/lib/pubid/jis/identifiers/base.rb +0 -72
  454. data/lib/pubid/jis/scheme.rb +0 -49
  455. data/lib/pubid/nist/components/publisher.rb +0 -24
  456. data/lib/pubid/nist/scheme.rb +0 -199
  457. data/lib/pubid/oiml/scheme.rb +0 -46
  458. data/lib/pubid/plateau/scheme.rb +0 -45
  459. data/lib/pubid/rendering/base.rb +0 -73
  460. data/lib/pubid/rendering/common.rb +0 -211
  461. data/lib/pubid/rendering/format.rb +0 -25
  462. data/lib/pubid/sae/scheme.rb +0 -47
  463. data/lib/pubid/scheme.rb +0 -207
@@ -1,25 +1,16 @@
1
- require_relative "../components/publisher"
2
1
  # frozen_string_literal: true
3
- require_relative "../components/code"
4
- require_relative "../components/date"
5
2
 
6
3
  module Pubid
7
4
  module Iec
8
5
  class Builder < Pubid::Builder::Base
9
- def initialize(scheme)
10
- @scheme = scheme
11
- end
12
-
13
6
  def locate_identifier_klass(parsed_hash)
14
7
  # Check for working programme
15
8
  if parsed_hash[:wp_stage]
16
- require_relative "identifiers/working_document"
17
9
  return Identifiers::WorkingDocument
18
10
  end
19
11
 
20
12
  # Check for working document
21
13
  if parsed_hash[:technical_committee] && parsed_hash[:wd_number]
22
- require_relative "identifiers/working_document"
23
14
  return Identifiers::WorkingDocument
24
15
  end
25
16
 
@@ -27,7 +18,8 @@ module Pubid
27
18
  # :type_with_stage will be nil if it is an IS.
28
19
  typed_stage = locate_typed_stage(parsed_hash[:type_with_stage])
29
20
 
30
- @scheme.locate_identifier_klass_by_type_code(typed_stage.type_code)
21
+ Pubid::Iec.locate_type(typed_stage.type_code) ||
22
+ raise(ArgumentError, "Unknown type code: #{typed_stage.type_code}")
31
23
  end
32
24
 
33
25
  def build(parsed_hash)
@@ -55,7 +47,8 @@ module Pubid
55
47
 
56
48
  # Locate the supplement identifier class
57
49
  typed_stage = locate_typed_stage(supplement_type)
58
- identifier_class = @scheme.locate_identifier_klass_by_type_code(typed_stage.type_code)
50
+ identifier_class = Pubid::Iec.locate_type(typed_stage.type_code) ||
51
+ raise(ArgumentError, "Unknown type code: #{typed_stage.type_code}")
59
52
 
60
53
  # Create the supplement identifier
61
54
  supplement = identifier_class.new
@@ -96,14 +89,11 @@ module Pubid
96
89
 
97
90
  if is_fragment
98
91
  # For FRAG typed stages, look up the fragment's own typed stage
99
- begin
100
- fragment_typed_stage = @scheme.locate_typed_stage_by_abbr(
101
- parsed_hash[:type_with_stage].to_s,
102
- )
103
- rescue ArgumentError
104
- # FRAGC is a rendering notation, not a typed stage abbreviation
105
- fragment_typed_stage = @scheme.locate_typed_stage_by_abbr("FRAG")
106
- end
92
+ fragment_typed_stage = Pubid::Iec.locate_stage(parsed_hash[:type_with_stage])
93
+
94
+ # FRAGC is a rendering notation, not a typed stage abbreviation;
95
+ # fall back to the canonical "FRAG" typed stage
96
+ fragment_typed_stage ||= Pubid::Iec.locate_stage("FRAG")
107
97
 
108
98
  # For FRAG/FRAGC, we need to build the base Amendment/Corrigendum
109
99
  # then wrap it with FragmentIdentifier
@@ -158,7 +148,6 @@ module Pubid
158
148
 
159
149
  # Detect rendering style from parsed abbreviation
160
150
  if identifier.class.attributes.key?(:rendering_style) && identifier.typed_stage
161
- require_relative "rendering_style"
162
151
  ts = identifier.typed_stage
163
152
 
164
153
  # Detect IEC format from parsed abbreviation
@@ -179,7 +168,7 @@ module Pubid
179
168
  with_language_code = if langs&.any?
180
169
  # Check if original_code was single-char (E, F, R, A, S, D)
181
170
  first_lang = langs.first
182
- if first_lang.is_a?(Components::Language) && first_lang.original_code && first_lang.original_code.length == 1
171
+ if first_lang.is_a?(::Pubid::Components::Language) && first_lang.original_code && first_lang.original_code.length == 1
183
172
  :single
184
173
  else
185
174
  :iso # 2-char codes (en, fr, ru, ar, es, de)
@@ -202,7 +191,7 @@ module Pubid
202
191
 
203
192
  # After building base identifier, apply wrappers
204
193
  if fragment_type_data && fragment_number_data
205
- frag_ts = @scheme.locate_typed_stage_by_abbr("FRAG")
194
+ frag_ts = Pubid::Iec.locate_stage("FRAG")
206
195
  identifier = wrap_with_fragment(identifier, fragment_number_data.to_s,
207
196
  nil, frag_ts)
208
197
  end
@@ -229,11 +218,25 @@ module Pubid
229
218
  end
230
219
  end
231
220
 
221
+ # The IEC builder's own `build` method drives identifier construction
222
+ # (it locates the right class per parsed hash), so the parent class's
223
+ # `@identifier_class` slot is never read. Provide a placeholder so
224
+ # `Builder.new` doesn't fail with NotImplementedError.
225
+ def default_identifier_class
226
+ Identifiers::InternationalStandard
227
+ end
228
+
229
+ # Look up a typed stage by abbreviation via the self-describing
230
+ # `Pubid::Iec` module instead of an injected scheme instance.
231
+ def locate_typed_stage(typed_stage_string)
232
+ typed_stage_string = "" if typed_stage_string.nil?
233
+ Pubid::Iec.locate_stage(typed_stage_string) ||
234
+ raise(ArgumentError, "Unknown type abbreviation: '#{typed_stage_string}'")
235
+ end
236
+
232
237
  # Wrap identifier with FragmentIdentifier for /FRAGN notation
233
238
  def wrap_with_fragment(base_identifier, fragment_number,
234
- edition_data = nil, typed_stage = nil)
235
- require_relative "identifiers/fragment_identifier"
236
-
239
+ edition_data = nil, typed_stage = nil)
237
240
  fragment = Identifiers::FragmentIdentifier.new(
238
241
  base_identifier: base_identifier,
239
242
  fragment_number: fragment_number,
@@ -252,8 +255,6 @@ edition_data = nil, typed_stage = nil)
252
255
 
253
256
  # Wrap identifier with SheetIdentifier for /N:YEAR notation
254
257
  def wrap_with_sheet(base_identifier, sheet_number, sheet_year)
255
- require_relative "identifiers/sheet_identifier"
256
-
257
258
  # Only pass year if it's present
258
259
  year_value = sheet_year&.to_s
259
260
 
@@ -272,10 +273,6 @@ edition_data = nil, typed_stage = nil)
272
273
 
273
274
  # Wrap identifier with ConsolidatedIdentifier for +AMD chains
274
275
  def wrap_with_consolidated(base_identifier, supplements_data)
275
- require_relative "identifiers/consolidated_identifier"
276
- require_relative "identifiers/amendment"
277
- require_relative "identifiers/corrigendum"
278
-
279
276
  supplements = supplements_data.filter_map do |supp|
280
277
  type = supp[:supplement_type].to_s
281
278
  number = supp[:supplement_number].to_s
@@ -302,13 +299,10 @@ edition_data = nil, typed_stage = nil)
302
299
  )
303
300
  end
304
301
 
305
- # Wrap identifier with VapIdentifier for CSV/CMV/RLV/SER suffix
302
+ # Wrap identifier with VapIdentifier for one or more VAP codes
303
+ # (e.g. "CSV" or "EXV-CMV").
306
304
  def wrap_with_vap(base_identifier, vap_suffix_data)
307
- require_relative "identifiers/vap_identifier"
308
- require_relative "identifiers/consolidated_identifier"
309
- require_relative "components/vap_suffix"
310
-
311
- vap_suffix = Components::VapSuffix.new(code: vap_suffix_data.to_s)
305
+ vap = vap_suffix_data.to_s.split("-")
312
306
 
313
307
  # Extract edition - need to go deep for ConsolidatedIdentifier
314
308
  edition = nil
@@ -326,7 +320,7 @@ edition_data = nil, typed_stage = nil)
326
320
 
327
321
  Identifiers::VapIdentifier.new(
328
322
  base_identifier: base_identifier,
329
- vap_suffix: vap_suffix,
323
+ vap: vap,
330
324
  edition: edition,
331
325
  )
332
326
  end
@@ -337,6 +331,12 @@ edition_data = nil, typed_stage = nil)
337
331
  super
338
332
  end
339
333
 
334
+ # IEC normalizes em/en dashes to hyphens but preserves slashes and
335
+ # spaces, which can be semantically meaningful in IEC identifiers.
336
+ def normalize_number_with_part(value)
337
+ value.to_s.tr(Parser::DASH_CHARS.join, "-")
338
+ end
339
+
340
340
  def cast(type, value)
341
341
  case type
342
342
  when :base_identifier
@@ -374,28 +374,7 @@ edition_data = nil, typed_stage = nil)
374
374
  # or "60038-1" ('1' is part)
375
375
  # or "60038-1-2" ('1' is part, '2' is subpart)
376
376
  # or "29110-5-1-1" ('5' is part, '1-1' is subpart)
377
-
378
- # Split the number into parts
379
- normalized_value = value.to_s.tr(Parser::DASH_CHARS.join, "-")
380
-
381
- parts = normalized_value.split("-")
382
- number = parts.shift # The first part is always the number
383
- part = parts.shift # The second part is the part, if present
384
- subpart = parts.any? ? parts.join("-") : nil # The remaining parts form the subpart, if present
385
-
386
- part = convert_roman_to_integer(part)
387
-
388
- code_hash = { number: Components::Code.new(value: number) }
389
-
390
- if part
391
- code_hash[:part] = Components::Code.new(value: part)
392
- end
393
-
394
- if subpart
395
- code_hash[:subpart] = Components::Code.new(value: subpart)
396
- end
397
-
398
- code_hash
377
+ parse_number_with_part(value, code_class: Components::Code)
399
378
 
400
379
  when :type_with_stage
401
380
  # "WD"
@@ -416,13 +395,17 @@ edition_data = nil, typed_stage = nil)
416
395
  }
417
396
  when :stage_iteration
418
397
  # "1" or "2"
419
- Components::Code.new(value: value.to_s)
398
+ Pubid::Components::Iteration.new(number: value.to_s)
420
399
 
421
400
  when :date
422
401
  parse_date(value)
423
402
 
424
403
  when :edition
425
- Pubid::Components::Edition.new(number: value)
404
+ # Coerce to String: the parsed value may be a Parslet::Slice, which
405
+ # Edition.number (Type::Value) would store verbatim and serialize as a
406
+ # !ruby/object:Parslet::Slice node — unloadable by the index reader's
407
+ # YAML.safe_load(permitted_classes: [Symbol]).
408
+ Pubid::Components::Edition.new(number: value&.to_s)
426
409
 
427
410
  when :sheet_number
428
411
  value.to_s
@@ -434,7 +417,8 @@ edition_data = nil, typed_stage = nil)
434
417
  parse_languages(value)
435
418
 
436
419
  when :all_parts
437
- Pubid::Components::Locality.new(all_parts: true)
420
+ # Set all_parts boolean attribute directly on identifier (matches ISO builder)
421
+ true
438
422
 
439
423
  when :database
440
424
  # Database flag - return true if DB suffix present
@@ -444,8 +428,7 @@ edition_data = nil, typed_stage = nil)
444
428
  when :joint_identifier
445
429
  case value[:publisher]
446
430
  when "ISO"
447
- require_relative "../iso/builder"
448
- Iso::Builder.new(Iso::Scheme).build(value)
431
+ Pubid::Iso.build_from_parse(value)
449
432
  end
450
433
 
451
434
  else
@@ -1,57 +1,34 @@
1
- require "lutaml/model"
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Pubid
5
4
  module Iec
6
5
  module Components
7
- class Code < Lutaml::Model::Serializable
8
- attribute :prefix, :string, default: -> {}
9
- attribute :number, :string
10
- attribute :part, :string, default: -> {}
11
-
12
- def initialize(value: nil, number: nil, prefix: nil, part: nil)
13
- # Support both 'value' (for convenience) and 'number' (explicit)
14
- @number = value || number
15
- @prefix = prefix
16
- @part = part
17
- end
18
-
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.
10
+ class Code < ::Pubid::Components::Code
19
11
  def to_s
20
12
  result = ""
21
13
  result += "#{prefix} " if prefix
22
- result += number
23
- result += "-#{part}" if part
14
+ result += value.to_s
24
15
  result
25
16
  end
26
17
 
27
- def full_code
28
- to_s
29
- end
18
+ alias full_code to_s
30
19
 
31
20
  # Parse IEC code formats:
32
21
  # - "60034" (just number)
33
- # - "60034-1" (number with part)
34
22
  # - "TR 61000" (with prefix)
35
23
  # - "TS 62443" (with prefix)
36
24
  def self.parse(string)
37
25
  parts = string.strip.split(" ", 2)
38
26
 
39
27
  if parts.size == 2
40
- # Has prefix: "TR 61000-1-2"
41
- prefix = parts[0]
42
- number_part = parts[1]
28
+ new(prefix: parts[0], value: parts[1])
43
29
  else
44
- # No prefix: "60034-1"
45
- prefix = nil
46
- number_part = parts[0]
30
+ new(value: parts[0])
47
31
  end
48
-
49
- # Split number and part
50
- number_parts = number_part.split("-", 2)
51
- number = number_parts[0]
52
- part = number_parts[1]
53
-
54
- new(prefix: prefix, number: number, part: part)
55
32
  end
56
33
  end
57
34
  end
@@ -4,7 +4,7 @@ require "lutaml/model"
4
4
  module Pubid
5
5
  module Iec
6
6
  module Components
7
- class Publisher < Lutaml::Model::Serializable
7
+ class Publisher < ::Pubid::Components::Publisher
8
8
  PUBLISHERS = {
9
9
  "IEC" => "International Electrotechnical Commission",
10
10
  "ISO/IEC" => "ISO/IEC Joint Technical Committee",
@@ -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,11 +1,269 @@
1
- require_relative "../identifier"
2
1
  # frozen_string_literal: true
3
- require_relative "../components/typed_stage"
4
2
 
5
3
  module Pubid
6
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
+
7
23
  class Identifier < ::Pubid::Identifier
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
34
+
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
39
+
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
57
+ end
58
+
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
65
+
66
+ def stage
67
+ typed_stage&.to_stage
68
+ end
69
+
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
100
+
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] }
107
+ end
108
+
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 }
139
+ end
140
+
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))
154
+ end
155
+
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)
160
+ end
161
+
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))
169
+ end
170
+
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)
176
+ end
177
+
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?
182
+
183
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("year", y.to_s))
184
+ end
185
+
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
190
+ end
191
+
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))
198
+ end
199
+
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)
221
+ end
222
+ end
223
+
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
+ )
245
+ end
246
+
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
+
8
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
+
9
267
  # Apply legacy update_codes normalization first, before any other preprocessing
10
268
  normalized = Core::UpdateCodes.apply(string, :iec)
11
269
  parsed = Pubid::Iec::Parser.new.parse(normalized)
@@ -14,7 +272,22 @@ module Pubid
14
272
  "Invalid identifier format"
15
273
  end
16
274
 
17
- Pubid::Iec::Builder.new(Pubid::Iec::Scheme).build(parsed)
275
+ Pubid::Iec::Builder.new.build(parsed)
276
+ end
277
+
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
289
+ end
290
+ super
18
291
  end
19
292
  end
20
293
  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