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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +25 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +4 -55
  6. data/lib/pubid/amca/identifiers/base.rb +58 -47
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -21
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -17
  9. data/lib/pubid/amca/identifiers/standard.rb +0 -4
  10. data/lib/pubid/amca/renderer.rb +82 -0
  11. data/lib/pubid/amca/single_identifier.rb +0 -23
  12. data/lib/pubid/amca/urn_generator.rb +2 -1
  13. data/lib/pubid/amca/urn_parser.rb +28 -0
  14. data/lib/pubid/amca.rb +42 -1
  15. data/lib/pubid/ansi/builder.rb +5 -3
  16. data/lib/pubid/ansi/identifier.rb +1 -43
  17. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  18. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  19. data/lib/pubid/ansi/renderer.rb +53 -0
  20. data/lib/pubid/ansi/single_identifier.rb +2 -31
  21. data/lib/pubid/ansi/urn_generator.rb +3 -38
  22. data/lib/pubid/ansi/urn_parser.rb +23 -0
  23. data/lib/pubid/ansi.rb +38 -3
  24. data/lib/pubid/api/builder.rb +33 -74
  25. data/lib/pubid/api/identifier.rb +5 -52
  26. data/lib/pubid/api/identifiers/base.rb +2 -14
  27. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  28. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  29. data/lib/pubid/api/identifiers/mpms.rb +0 -20
  30. data/lib/pubid/api/identifiers/publication.rb +0 -2
  31. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  32. data/lib/pubid/api/identifiers/specification.rb +0 -2
  33. data/lib/pubid/api/identifiers/standard.rb +0 -2
  34. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  35. data/lib/pubid/api/identifiers/typeless_standard.rb +0 -16
  36. data/lib/pubid/api/identifiers.rb +18 -0
  37. data/lib/pubid/api/renderer.rb +89 -0
  38. data/lib/pubid/api/single_identifier.rb +5 -20
  39. data/lib/pubid/api/urn_generator.rb +0 -18
  40. data/lib/pubid/api/urn_parser.rb +35 -0
  41. data/lib/pubid/api.rb +51 -5
  42. data/lib/pubid/ashrae/builder.rb +3 -3
  43. data/lib/pubid/ashrae/identifier.rb +7 -55
  44. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  45. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  46. data/lib/pubid/ashrae/identifiers/base.rb +29 -15
  47. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  48. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  49. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  50. data/lib/pubid/ashrae/parser.rb +4 -0
  51. data/lib/pubid/ashrae/renderer.rb +117 -0
  52. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  53. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  54. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  55. data/lib/pubid/ashrae.rb +46 -1
  56. data/lib/pubid/asme/components/code.rb +10 -2
  57. data/lib/pubid/asme/identifier.rb +0 -46
  58. data/lib/pubid/asme/identifiers/base.rb +0 -60
  59. data/lib/pubid/asme/renderer.rb +66 -0
  60. data/lib/pubid/asme/single_identifier.rb +3 -1
  61. data/lib/pubid/asme/urn_parser.rb +31 -0
  62. data/lib/pubid/asme.rb +42 -1
  63. data/lib/pubid/astm/components/code.rb +9 -0
  64. data/lib/pubid/{jis → astm}/components.rb +1 -1
  65. data/lib/pubid/astm/identifier.rb +0 -77
  66. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  67. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  68. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  69. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  70. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  71. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  72. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  73. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  74. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  75. data/lib/pubid/astm/identifiers.rb +18 -0
  76. data/lib/pubid/astm/renderer.rb +172 -0
  77. data/lib/pubid/astm/single_identifier.rb +3 -11
  78. data/lib/pubid/astm/urn_parser.rb +30 -0
  79. data/lib/pubid/astm.rb +39 -27
  80. data/lib/pubid/bsi/builder.rb +21 -12
  81. data/lib/pubid/bsi/identifier.rb +5 -85
  82. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -36
  83. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +8 -48
  84. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +8 -39
  85. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +2 -55
  86. data/lib/pubid/bsi/identifiers/amendment.rb +2 -22
  87. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -6
  88. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  89. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -87
  90. data/lib/pubid/bsi/identifiers/committee_document.rb +0 -16
  91. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -87
  92. data/lib/pubid/bsi/identifiers/corrigendum.rb +2 -10
  93. data/lib/pubid/bsi/identifiers/detailed_specification.rb +0 -36
  94. data/lib/pubid/bsi/identifiers/disc.rb +0 -29
  95. data/lib/pubid/bsi/identifiers/draft_document.rb +2 -46
  96. data/lib/pubid/bsi/identifiers/electronic_book.rb +2 -38
  97. data/lib/pubid/bsi/identifiers/expert_commentary.rb +2 -18
  98. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +0 -47
  99. data/lib/pubid/bsi/identifiers/flex.rb +0 -35
  100. data/lib/pubid/bsi/identifiers/handbook.rb +1 -15
  101. data/lib/pubid/bsi/identifiers/index.rb +0 -32
  102. data/lib/pubid/bsi/identifiers/method.rb +0 -41
  103. data/lib/pubid/bsi/identifiers/national_annex.rb +4 -29
  104. data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -6
  105. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +2 -54
  106. data/lib/pubid/bsi/identifiers/published_document.rb +2 -54
  107. data/lib/pubid/bsi/identifiers/section.rb +0 -30
  108. data/lib/pubid/bsi/identifiers/set.rb +3 -20
  109. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +0 -9
  110. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -24
  111. data/lib/pubid/bsi/identifiers/supplementary_index.rb +0 -46
  112. data/lib/pubid/bsi/identifiers/technical_specification.rb +2 -47
  113. data/lib/pubid/bsi/identifiers/test_method.rb +0 -32
  114. data/lib/pubid/bsi/identifiers/value_added_publication.rb +2 -17
  115. data/lib/pubid/bsi/identifiers.rb +0 -1
  116. data/lib/pubid/bsi/renderer.rb +1050 -0
  117. data/lib/pubid/bsi/single_identifier.rb +33 -78
  118. data/lib/pubid/bsi/urn_generator.rb +2 -3
  119. data/lib/pubid/bsi/urn_parser.rb +52 -0
  120. data/lib/pubid/bsi.rb +232 -2
  121. data/lib/pubid/builder/base.rb +57 -10
  122. data/lib/pubid/bundled_identifier.rb +0 -1
  123. data/lib/pubid/ccsds/builder.rb +4 -3
  124. data/lib/pubid/ccsds/identifier.rb +53 -68
  125. data/lib/pubid/ccsds/identifiers/base.rb +11 -61
  126. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  127. data/lib/pubid/ccsds/parser.rb +4 -2
  128. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  129. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  130. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  131. data/lib/pubid/ccsds.rb +39 -1
  132. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  133. data/lib/pubid/cen_cenelec/identifier.rb +11 -40
  134. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +9 -4
  135. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +0 -10
  136. data/lib/pubid/cen_cenelec/identifiers/base.rb +2 -45
  137. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  138. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +0 -27
  140. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +0 -15
  141. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +2 -8
  143. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  144. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +0 -4
  145. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  146. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  147. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  148. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  149. data/lib/pubid/cen_cenelec/single_identifier.rb +9 -90
  150. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  151. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  152. data/lib/pubid/cen_cenelec.rb +172 -1
  153. data/lib/pubid/cie/components/code.rb +8 -0
  154. data/lib/pubid/cie/identifier.rb +10 -57
  155. data/lib/pubid/cie/single_identifier.rb +4 -4
  156. data/lib/pubid/cie/urn_parser.rb +28 -0
  157. data/lib/pubid/cie.rb +47 -1
  158. data/lib/pubid/components/adoption.rb +104 -0
  159. data/lib/pubid/components/code.rb +22 -8
  160. data/lib/pubid/components/date.rb +23 -16
  161. data/lib/pubid/components/edition.rb +9 -6
  162. data/lib/pubid/components/iteration.rb +32 -0
  163. data/lib/pubid/components/language.rb +6 -4
  164. data/lib/pubid/components/locality.rb +10 -1
  165. data/lib/pubid/components/publisher.rb +9 -6
  166. data/lib/pubid/components/relationship.rb +151 -0
  167. data/lib/pubid/components/stage.rb +5 -14
  168. data/lib/pubid/components/supplement.rb +184 -0
  169. data/lib/pubid/components/type.rb +5 -15
  170. data/lib/pubid/components/typed_stage.rb +10 -11
  171. data/lib/pubid/components.rb +4 -1
  172. data/lib/pubid/core/update_codes.rb +28 -7
  173. data/lib/pubid/csa/identifier.rb +9 -59
  174. data/lib/pubid/csa/identifiers/base.rb +0 -123
  175. data/lib/pubid/csa/identifiers/cec.rb +0 -103
  176. data/lib/pubid/csa/identifiers/series.rb +0 -104
  177. data/lib/pubid/csa/renderer.rb +292 -0
  178. data/lib/pubid/csa/single_identifier.rb +1 -1
  179. data/lib/pubid/csa/urn_generator.rb +1 -1
  180. data/lib/pubid/csa/urn_parser.rb +33 -0
  181. data/lib/pubid/csa.rb +46 -1
  182. data/lib/pubid/etsi/components/code.rb +10 -9
  183. data/lib/pubid/etsi/components/version.rb +0 -5
  184. data/lib/pubid/etsi/identifier.rb +4 -55
  185. data/lib/pubid/etsi/identifiers/base.rb +31 -27
  186. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +1 -11
  187. data/lib/pubid/etsi/renderer.rb +42 -0
  188. data/lib/pubid/etsi/urn_parser.rb +34 -0
  189. data/lib/pubid/etsi.rb +44 -1
  190. data/lib/pubid/export/exporter.rb +4 -46
  191. data/lib/pubid/export/flavor_exporter.rb +111 -278
  192. data/lib/pubid/export.rb +0 -6
  193. data/lib/pubid/identifier.rb +92 -18
  194. data/lib/pubid/identifier_metadata.rb +1 -1
  195. data/lib/pubid/idf/builder.rb +3 -3
  196. data/lib/pubid/idf/identifier.rb +7 -66
  197. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  198. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  199. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  200. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  201. data/lib/pubid/idf/parser.rb +3 -2
  202. data/lib/pubid/idf/renderer.rb +84 -0
  203. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  204. data/lib/pubid/idf/urn_generator.rb +4 -39
  205. data/lib/pubid/idf/urn_parser.rb +25 -0
  206. data/lib/pubid/idf.rb +55 -1
  207. data/lib/pubid/iec/builder.rb +46 -64
  208. data/lib/pubid/iec/components/code.rb +8 -32
  209. data/lib/pubid/iec/components/publisher.rb +0 -1
  210. data/lib/pubid/iec/components.rb +14 -0
  211. data/lib/pubid/iec/identifier.rb +251 -213
  212. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  213. data/lib/pubid/iec/identifiers/base.rb +5 -33
  214. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  215. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  216. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +23 -26
  217. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  218. data/lib/pubid/iec/identifiers/fragment_identifier.rb +35 -24
  219. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  220. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  221. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  222. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  223. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  224. data/lib/pubid/iec/identifiers/sheet_identifier.rb +17 -11
  225. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  226. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  227. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  228. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  229. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  230. data/lib/pubid/iec/identifiers/test_report_form.rb +3 -35
  231. data/lib/pubid/iec/identifiers/vap_identifier.rb +24 -21
  232. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  233. data/lib/pubid/iec/identifiers/working_document.rb +2 -50
  234. data/lib/pubid/iec/identifiers.rb +30 -0
  235. data/lib/pubid/iec/parser.rb +13 -12
  236. data/lib/pubid/iec/renderer.rb +254 -0
  237. data/lib/pubid/iec/single_identifier.rb +6 -12
  238. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  239. data/lib/pubid/iec/urn_generator.rb +3 -3
  240. data/lib/pubid/iec/urn_parser.rb +3 -3
  241. data/lib/pubid/iec.rb +43 -67
  242. data/lib/pubid/ieee/builder.rb +12 -12
  243. data/lib/pubid/ieee/components/code.rb +8 -0
  244. data/lib/pubid/ieee/components/draft.rb +14 -0
  245. data/lib/pubid/ieee/components/relationship.rb +5 -149
  246. data/lib/pubid/ieee/identifier.rb +5 -52
  247. data/lib/pubid/ieee/identifiers/adopted_standard.rb +0 -9
  248. data/lib/pubid/ieee/identifiers/base.rb +221 -556
  249. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +0 -10
  250. data/lib/pubid/ieee/identifiers/corrigendum.rb +0 -12
  251. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +0 -10
  252. data/lib/pubid/ieee/identifiers/dual_identifier.rb +0 -4
  253. data/lib/pubid/ieee/identifiers/dual_published.rb +0 -4
  254. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +0 -9
  255. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +0 -10
  256. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  257. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +0 -18
  258. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +0 -6
  259. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  260. data/lib/pubid/ieee/identifiers/redlined_standard.rb +0 -7
  261. data/lib/pubid/ieee/identifiers/si_standard.rb +0 -38
  262. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  263. data/lib/pubid/ieee/pre_parser.rb +301 -0
  264. data/lib/pubid/ieee/renderer.rb +307 -0
  265. data/lib/pubid/ieee/urn_parser.rb +34 -0
  266. data/lib/pubid/ieee.rb +66 -1
  267. data/lib/pubid/ieee_debug.rb +0 -1
  268. data/lib/pubid/iho/builder.rb +2 -2
  269. data/lib/pubid/iho/identifier.rb +7 -59
  270. data/lib/pubid/iho/identifiers/base.rb +64 -31
  271. data/lib/pubid/iho/parser.rb +3 -3
  272. data/lib/pubid/iho/renderer.rb +30 -0
  273. data/lib/pubid/iho/urn_generator.rb +2 -2
  274. data/lib/pubid/iho/urn_parser.rb +58 -0
  275. data/lib/pubid/iho.rb +52 -1
  276. data/lib/pubid/iso/builder.rb +55 -53
  277. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  278. data/lib/pubid/iso/components/code.rb +7 -19
  279. data/lib/pubid/iso/components/publisher.rb +10 -8
  280. data/lib/pubid/iso/components.rb +2 -4
  281. data/lib/pubid/iso/identifier.rb +219 -252
  282. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  283. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  284. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  285. data/lib/pubid/iso/identifiers/data.rb +0 -1
  286. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  287. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  288. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  289. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  290. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  291. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  292. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  293. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  294. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  295. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  296. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  297. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  298. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  299. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  300. data/lib/pubid/iso/identifiers.rb +0 -1
  301. data/lib/pubid/iso/normalizer.rb +89 -0
  302. data/lib/pubid/iso/parser.rb +22 -4
  303. data/lib/pubid/iso/single_identifier.rb +0 -4
  304. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  305. data/lib/pubid/iso/urn_generator.rb +66 -182
  306. data/lib/pubid/iso/urn_parser.rb +12 -7
  307. data/lib/pubid/iso.rb +177 -2
  308. data/lib/pubid/itu/builder.rb +0 -12
  309. data/lib/pubid/itu/components/code.rb +9 -7
  310. data/lib/pubid/itu/components/sector.rb +15 -4
  311. data/lib/pubid/itu/components/series.rb +0 -4
  312. data/lib/pubid/itu/components.rb +11 -0
  313. data/lib/pubid/itu/identifier.rb +4 -116
  314. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  315. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  316. data/lib/pubid/itu/identifiers/base.rb +124 -128
  317. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  318. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  319. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  320. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  321. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  322. data/lib/pubid/itu/urn_parser.rb +23 -0
  323. data/lib/pubid/itu.rb +44 -1
  324. data/lib/pubid/jcgm/builder.rb +16 -8
  325. data/lib/pubid/jcgm/identifier.rb +0 -43
  326. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -9
  327. data/lib/pubid/jcgm/identifiers/gum_guide.rb +0 -12
  328. data/lib/pubid/jcgm/renderer.rb +68 -0
  329. data/lib/pubid/jcgm/single_identifier.rb +0 -8
  330. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  331. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  332. data/lib/pubid/jcgm.rb +43 -2
  333. data/lib/pubid/jis/builder.rb +44 -52
  334. data/lib/pubid/jis/identifier.rb +120 -46
  335. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  336. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  337. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  338. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  339. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  340. data/lib/pubid/jis/identifiers.rb +1 -1
  341. data/lib/pubid/jis/parser.rb +31 -5
  342. data/lib/pubid/jis/renderer.rb +69 -0
  343. data/lib/pubid/jis/single_identifier.rb +6 -12
  344. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  345. data/lib/pubid/jis/urn_parser.rb +23 -0
  346. data/lib/pubid/jis.rb +42 -2
  347. data/lib/pubid/nist/builder.rb +63 -1871
  348. data/lib/pubid/nist/caster.rb +1272 -0
  349. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  350. data/lib/pubid/nist/components/code.rb +9 -20
  351. data/lib/pubid/nist/components/supplement.rb +2 -2
  352. data/lib/pubid/nist/components.rb +0 -1
  353. data/lib/pubid/nist/identifier.rb +8 -60
  354. data/lib/pubid/nist/identifiers/base.rb +564 -492
  355. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  356. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -1
  357. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  358. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  359. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  360. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -8
  361. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  362. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +15 -24
  363. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  364. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  365. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  366. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  367. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  368. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  369. data/lib/pubid/nist/identifiers/report.rb +4 -2
  370. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  371. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  372. data/lib/pubid/nist/identifiers.rb +1 -0
  373. data/lib/pubid/nist/parser.rb +62 -452
  374. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  375. data/lib/pubid/nist/preprocessor.rb +428 -0
  376. data/lib/pubid/nist/renderer.rb +43 -0
  377. data/lib/pubid/nist/router.rb +148 -0
  378. data/lib/pubid/nist/series/base.rb +58 -0
  379. data/lib/pubid/nist/series/crpl.rb +13 -0
  380. data/lib/pubid/nist/series/fips.rb +14 -0
  381. data/lib/pubid/nist/series/ir.rb +60 -0
  382. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  383. data/lib/pubid/nist/series/mono.rb +19 -0
  384. data/lib/pubid/nist/series/ncstar.rb +20 -0
  385. data/lib/pubid/nist/series.rb +49 -0
  386. data/lib/pubid/nist/supplement_identifier.rb +3 -1
  387. data/lib/pubid/nist/urn_parser.rb +67 -0
  388. data/lib/pubid/nist.rb +86 -4
  389. data/lib/pubid/oiml/builder.rb +21 -3
  390. data/lib/pubid/oiml/components/code.rb +17 -0
  391. data/lib/pubid/oiml/identifier.rb +40 -46
  392. data/lib/pubid/oiml/identifiers/annex.rb +13 -46
  393. data/lib/pubid/oiml/identifiers/errata.rb +15 -0
  394. data/lib/pubid/oiml/identifiers.rb +1 -1
  395. data/lib/pubid/oiml/parser.rb +59 -12
  396. data/lib/pubid/oiml/renderer.rb +171 -0
  397. data/lib/pubid/oiml/single_identifier.rb +61 -42
  398. data/lib/pubid/oiml/supplement_identifier.rb +31 -17
  399. data/lib/pubid/oiml/urn_generator.rb +0 -8
  400. data/lib/pubid/oiml/urn_parser.rb +22 -0
  401. data/lib/pubid/oiml.rb +42 -1
  402. data/lib/pubid/plateau/identifier.rb +4 -55
  403. data/lib/pubid/plateau/identifiers/base.rb +45 -36
  404. data/lib/pubid/plateau/identifiers/handbook.rb +0 -6
  405. data/lib/pubid/plateau/identifiers/technical_report.rb +0 -4
  406. data/lib/pubid/plateau/renderer.rb +51 -0
  407. data/lib/pubid/plateau/supplement_identifier.rb +0 -4
  408. data/lib/pubid/plateau/urn_parser.rb +43 -0
  409. data/lib/pubid/plateau.rb +43 -1
  410. data/lib/pubid/renderers/directives_renderer.rb +22 -8
  411. data/lib/pubid/renderers/guide_renderer.rb +4 -2
  412. data/lib/pubid/renderers/human_readable.rb +18 -7
  413. data/lib/pubid/rendering/context.rb +28 -19
  414. data/lib/pubid/rendering.rb +0 -3
  415. data/lib/pubid/sae/components/date.rb +8 -0
  416. data/lib/pubid/sae/components/type.rb +5 -1
  417. data/lib/pubid/sae/identifier.rb +4 -35
  418. data/lib/pubid/sae/identifiers/base.rb +26 -31
  419. data/lib/pubid/sae/renderer.rb +36 -0
  420. data/lib/pubid/sae/urn_generator.rb +2 -10
  421. data/lib/pubid/sae/urn_parser.rb +36 -0
  422. data/lib/pubid/sae.rb +42 -1
  423. data/lib/pubid/urn_generator/base.rb +12 -12
  424. data/lib/pubid/urn_parser/base.rb +81 -0
  425. data/lib/pubid/urn_parser/errors.rb +9 -0
  426. data/lib/pubid/urn_parser.rb +14 -0
  427. data/lib/pubid/version.rb +1 -1
  428. data/lib/pubid.rb +45 -7
  429. data/lib/tasks/export.rake +6 -5
  430. data/lib/tasks/website-data.json +1940 -1882
  431. metadata +75 -45
  432. data/lib/pubid/amca/scheme.rb +0 -16
  433. data/lib/pubid/ansi/scheme.rb +0 -15
  434. data/lib/pubid/api/scheme.rb +0 -66
  435. data/lib/pubid/ashrae/scheme.rb +0 -53
  436. data/lib/pubid/asme/scheme.rb +0 -37
  437. data/lib/pubid/astm/scheme.rb +0 -55
  438. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  439. data/lib/pubid/bsi/scheme.rb +0 -243
  440. data/lib/pubid/ccsds/scheme.rb +0 -57
  441. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  442. data/lib/pubid/cie/scheme.rb +0 -64
  443. data/lib/pubid/components/factory.rb +0 -50
  444. data/lib/pubid/csa/scheme.rb +0 -44
  445. data/lib/pubid/etsi/scheme.rb +0 -42
  446. data/lib/pubid/export/data_class_exporter.rb +0 -59
  447. data/lib/pubid/export/ieee_exporter.rb +0 -78
  448. data/lib/pubid/export/itu_exporter.rb +0 -66
  449. data/lib/pubid/export/nist_exporter.rb +0 -64
  450. data/lib/pubid/export/registry_exporter.rb +0 -90
  451. data/lib/pubid/export/scheme_exporter.rb +0 -70
  452. data/lib/pubid/identifier_registry.rb +0 -198
  453. data/lib/pubid/idf/scheme.rb +0 -61
  454. data/lib/pubid/iec/scheme.rb +0 -71
  455. data/lib/pubid/ieee/scheme.rb +0 -90
  456. data/lib/pubid/iho/scheme.rb +0 -29
  457. data/lib/pubid/iso/identifiers/base.rb +0 -115
  458. data/lib/pubid/iso/scheme.rb +0 -193
  459. data/lib/pubid/itu/scheme.rb +0 -174
  460. data/lib/pubid/jcgm/scheme.rb +0 -60
  461. data/lib/pubid/jis/components/code.rb +0 -59
  462. data/lib/pubid/jis/identifiers/base.rb +0 -72
  463. data/lib/pubid/jis/scheme.rb +0 -49
  464. data/lib/pubid/nist/components/publisher.rb +0 -24
  465. data/lib/pubid/nist/scheme.rb +0 -199
  466. data/lib/pubid/oiml/identifiers/base.rb +0 -36
  467. data/lib/pubid/oiml/scheme.rb +0 -46
  468. data/lib/pubid/plateau/scheme.rb +0 -45
  469. data/lib/pubid/rendering/base.rb +0 -73
  470. data/lib/pubid/rendering/common.rb +0 -211
  471. data/lib/pubid/rendering/format.rb +0 -25
  472. data/lib/pubid/sae/scheme.rb +0 -47
  473. data/lib/pubid/scheme.rb +0 -219
@@ -3,17 +3,66 @@
3
3
  module Pubid
4
4
  module Iso
5
5
  class Identifier < ::Pubid::Identifier
6
- # Override base types with ISO-specific ones
7
- attribute :publisher, ::Pubid::Iso::Components::Publisher
6
+ # Override base types with ISO-specific ones.
7
+ # Defaults to the type's implied publisher (ISO for most; IWA has none),
8
+ # so an omitted publisher key reconstructs correctly on from_hash.
9
+ attribute :publisher, ::Pubid::Iso::Components::Publisher,
10
+ default: -> { self.class.default_publisher }
8
11
  attribute :copublishers, ::Pubid::Iso::Components::Publisher,
9
12
  collection: true
13
+
14
+ # The publisher implied when none is serialized. ISO for most types;
15
+ # publisher-less types (IWA) override this to nil.
16
+ def self.default_publisher
17
+ ::Pubid::Iso::Components::Publisher.new
18
+ end
19
+
20
+ # typed_stage is the single source of truth for stage (and, with the class,
21
+ # the doctype). Default to the class's published typed_stage, so an omitted
22
+ # "stage" key reconstructs the published state on from_hash.
23
+ attribute :typed_stage, ::Pubid::Components::TypedStage,
24
+ default: -> { self.class.published_typed_stage }
25
+
26
+ # The class's published typed_stage (canonical surface form), or nil for
27
+ # types with no stages (e.g. TC documents).
28
+ def self.published_typed_stage
29
+ return nil unless const_defined?(:TYPED_STAGES)
30
+
31
+ ts = self::TYPED_STAGES.find { |t| t.stage_code.to_s == "published" }
32
+ return nil unless ts
33
+
34
+ ts = ts.dup
35
+ ts.original_abbr = ts.canonical_abbreviation
36
+ ts
37
+ end
38
+
39
+ # type and stage are derived from typed_stage, never stored — so the
40
+ # doctype (fixed by the class / _type) can't be lost when "stage" is
41
+ # omitted for the published default.
42
+ def type
43
+ typed_stage&.to_type
44
+ end
45
+
46
+ def stage
47
+ typed_stage&.to_stage
48
+ end
49
+
50
+ # Return a copy with the lifecycle stage set from an ISO harmonized stage
51
+ # code (e.g. "90.92"). typed_stage is the single source of truth, so this
52
+ # is all that is needed to surface the stage in #to_s and #to_urn. Returns
53
+ # an unchanged copy if the code is not recognised.
54
+ def with_harmonized_stage(harmonized_code)
55
+ ts = Pubid::Iso.locate_stage_by_harmonized_code(harmonized_code)
56
+ ts ? dup.tap { |id| id.typed_stage = ts } : dup
57
+ end
58
+
10
59
  attribute :number, ::Pubid::Iso::Components::Code
11
60
  attribute :part, ::Pubid::Iso::Components::Code
12
61
  attribute :subpart, ::Pubid::Iso::Components::Code
13
62
 
14
63
  # Polymorphic type map for lutaml::Model key_value serialization
15
64
  # Maps polymorphic_name → class name for deserialization
16
- # Validated by spec to stay in sync with Scheme.identifiers
65
+ # Validated by spec to stay in sync with identifier_types
17
66
  ISO_TYPE_MAP = {
18
67
  "pubid:iso:international-standard" => "Pubid::Iso::Identifiers::InternationalStandard",
19
68
  "pubid:iso:international-standardized-profile" => "Pubid::Iso::Identifiers::InternationalStandardizedProfile",
@@ -33,298 +82,216 @@ module Pubid
33
82
  "pubid:iso:data" => "Pubid::Iso::Identifiers::Data",
34
83
  "pubid:iso:tc-document" => "Pubid::Iso::Identifiers::TcDocument",
35
84
  "pubid:iso:technology-trends-assessments" => "Pubid::Iso::Identifiers::TechnologyTrendsAssessments",
85
+ "pubid:iso:bundled-identifier" => "Pubid::Iso::BundledIdentifier",
36
86
  }.freeze
37
87
 
38
- # Build type map from Scheme.identifiers for validation
88
+ # BundledIdentifier lives outside Pubid::Iso::Identifiers but carries a
89
+ # polymorphic `_type`, so the shared polymorphic_type_map needs it
90
+ # explicitly (see Pubid::Identifier#additional_identifier_classes).
91
+ def self.additional_identifier_classes
92
+ [Pubid::Iso::BundledIdentifier]
93
+ end
94
+ private_class_method :additional_identifier_classes
95
+
96
+ # Build type map from Pubid::Iso.identifier_types for validation
39
97
  def self.build_type_map
40
- Scheme.identifiers.to_h do |klass|
98
+ Pubid::Iso.identifier_types.to_h do |klass|
41
99
  [klass.polymorphic_name, klass.name]
42
100
  end
43
101
  end
44
102
 
103
+ # The base Pubid::Identifier no longer auto-maps attributes, so each
104
+ # flavor's top class must declare its own key_value mapping. Subclasses
105
+ # merge their own blocks on top of this one (e.g. SupplementIdentifier
106
+ # adds base_identifier; Directives adds subgroup), so list every base
107
+ # attribute ISO serializes here once.
45
108
  key_value do
46
109
  map "_type", to: :_type, polymorphic_map: ISO_TYPE_MAP
110
+ # Code components serialize as their plain string value, not {value,number}.
111
+ map "number", with: { to: :number_to_kv, from: :number_from_kv }
112
+ map "part", with: { to: :part_to_kv, from: :part_from_kv }
113
+ map "subpart", with: { to: :subpart_to_kv, from: :subpart_from_kv }
114
+ map "stage_iteration",
115
+ with: { to: :stage_iteration_to_kv, from: :stage_iteration_from_kv }
116
+ # date serialized flat as year/month/day, nils omitted.
117
+ map "year", with: { to: :year_to_kv, from: :year_from_kv }
118
+ map "month", with: { to: :month_to_kv, from: :month_from_kv }
119
+ map "day", with: { to: :day_to_kv, from: :day_from_kv }
120
+ map "edition", to: :edition
121
+ map "languages", to: :languages
122
+ # publisher emitted only when the primary isn't the type default;
123
+ # copublishers (the other bodies) as an array, omitted when empty.
124
+ map "publisher", with: { to: :publisher_to_kv, from: :publisher_from_kv }
125
+ map "copublishers", with: { to: :copublishers_to_kv, from: :copublishers_from_kv }
126
+ map "locality", to: :locality
127
+ # `type` and generic `stage` are fully derived from `typed_stage`
128
+ # (builder sets them via to_type/to_stage), so we serialize only the
129
+ # unique typed-stage `code` under "stage" and recompute the rest on
130
+ # load. _type already pins the document type.
131
+ map "stage", with: { to: :stage_to_kv, from: :stage_from_kv }
132
+ # Omit the `false` default; only the meaningful `true` is serialized.
133
+ map "all_parts", with: { to: :all_parts_to_kv, from: :all_parts_from_kv }
47
134
  end
48
135
 
49
- def self.parse(string, format: :auto)
50
- format = Pubid::FormatDetector.detect(string) if format == :auto
136
+ def all_parts_to_kv(model, doc)
137
+ return unless model.all_parts
51
138
 
52
- case format
53
- when :urn
54
- Pubid::Iso::UrnParser.parse(string)
55
- when :mr_string
56
- Pubid::Parsers::MrString.parse(string)
57
- else
58
- parsed = Pubid::Iso::Parser.new.parse(string)
59
- if parsed.nil? || parsed.empty?
60
- raise Pubid::Iso::Parser::ParseError,
61
- "Invalid identifier format"
62
- end
139
+ doc.add_child(
140
+ Lutaml::KeyValue::DataModel::Element.new("all_parts", true),
141
+ )
142
+ end
63
143
 
64
- Pubid::Iso::Builder.new(Pubid::Iso::Scheme).build(parsed)
65
- end
144
+ def all_parts_from_kv(model, value)
145
+ model.all_parts = value
66
146
  end
67
147
 
68
- # Factory mirroring pubid 1.x's `Pubid::Iso::Identifier.create` API.
69
- #
70
- # Accepts 1.x-style primitive kwargs and dispatches to the correct
71
- # 2.x `Identifiers::*` subclass via {Pubid::Iso::Scheme}. Coerces
72
- # primitives into ISO-specific Component objects.
73
- #
74
- # Dispatch rules:
75
- # * `type:` (e.g. `:tr`, `:amd`) → lookup via Scheme
76
- # * else `stage:` (e.g. `"DIS"`, `"AMD"`) → lookup via Scheme
77
- # * else → InternationalStandard
78
- #
79
- # @param type [Symbol, String, nil] type key (`:is`, `:tr`, `:amd`, …)
80
- # @param stage [String, Symbol, nil] typed-stage abbreviation
81
- # @param opts [Hash] remaining attribute primitives:
82
- # :publisher (String), :number, :part, :subpart, :year, :edition,
83
- # :language
84
- # @return [Pubid::Iso::Identifier]
85
- def self.create(type: nil, stage: nil, base: nil, **opts)
86
- # A bundled directive (e.g. "ISO/IEC DIR 1 + IEC SUP") is stored by the
87
- # 1.x index as the base document's fields plus a nested joint_document
88
- # (or a supplements array). The 2.x model is a separate
89
- # BundledIdentifier; build that so .create round-trips parse.
90
- if opts[:joint_document] || opts[:supplements]
91
- return build_bundled(type: type, stage: stage, base: base, **opts)
92
- end
148
+ # Serialize typed_stage as just its unique code (e.g. "is", "dis",
149
+ # "committee_draft_amd"). type/stage are recomputed from it on load.
150
+ def stage_to_kv(model, doc)
151
+ ts = model.typed_stage
152
+ return unless ts&.code
153
+ # Omit the published default (recomputed from the class on load).
154
+ return if ts.stage_code.to_s == "published"
93
155
 
94
- klass = resolve_create_class(type: type, stage: stage, base: base)
95
- attrs = coerce_create_attrs(opts)
96
- ts = resolve_create_typed_stage(klass, stage)
97
- if ts
98
- # dup the (shared) TYPED_STAGES element before tweaking, and set
99
- # original_abbr to the canonical abbr so rendering matches a
100
- # parsed identifier (parse records the spelled abbr, e.g. "Amd"
101
- # not the upcased short_abbr "AMD").
102
- ts = ts.dup
103
- ts.original_abbr ||= Array(ts.abbr).first&.to_s
104
- attrs[:typed_stage] = ts
105
- # Parse fills `type` and `stage` Components derived from
106
- # typed_stage; mirror that here so .create round-trips through
107
- # Pubid::Identifier#== with a parsed identifier.
108
- attrs[:type] ||= ::Pubid::Components::Type.new(
109
- name: ts.name,
110
- abbr: Array(ts.abbr).first.to_s,
111
- type_code: ts.type_code&.to_s,
112
- )
113
- attrs[:stage] ||= ::Pubid::Components::Stage.new(
114
- name: ts.name,
115
- stage_code: ts.stage_code&.to_s,
116
- abbr: Array(ts.abbr).first.to_s,
117
- harmonized_stages: Array(ts.harmonized_stages),
118
- )
119
- end
120
- # Build the base_identifier whenever a `base:` is supplied, regardless
121
- # of whether the resolved class is registered as a supplement (e.g.
122
- # DirectivesSupplement holds a base but is not in
123
- # Scheme#supplement_identifiers). Only classes that *require* a base
124
- # and were given none raise.
125
- if base
126
- attrs[:base_identifier] = build_base_identifier(base)
127
- elsif supplement_klass?(klass)
128
- raise ArgumentError, "#{klass} requires a base: identifier"
129
- end
130
- # For a DirectivesSupplement the top-level `publisher:` names the
131
- # supplement's own publisher ("… ISO SUP"), not the document's — the
132
- # document publisher lives on the base. Mirror parse, which records it
133
- # as `supplement_publisher`.
134
- if klass <= Identifiers::DirectivesSupplement && attrs.key?(:publisher)
135
- attrs[:supplement_publisher] = attrs.delete(:publisher)
136
- attrs.delete(:copublishers)
137
- end
138
- klass.new(**attrs)
156
+ doc.add_child(
157
+ Lutaml::KeyValue::DataModel::Element.new("stage", ts.code.to_s),
158
+ )
159
+ end
160
+
161
+ # Resolve the typed-stage code back to the full TypedStage within this
162
+ # identifier's class, then derive type/stage from it.
163
+ def stage_from_kv(model, value)
164
+ return if value.nil? || value.to_s.empty?
165
+
166
+ ts = (model.class.const_defined?(:TYPED_STAGES) &&
167
+ model.class::TYPED_STAGES.find { |t| t.code.to_s == value.to_s }) ||
168
+ Pubid::Iso::Scheme.locate_typed_stage_by_code(value)
169
+ return unless ts
170
+
171
+ # The renderer prefers `original_abbr` (the parsed surface form); without
172
+ # it the supplement renderer falls back to `short_abbr` (e.g. "AMD").
173
+ # Resolving from a code has no surface form, so render the canonical
174
+ # abbreviation (`abbr.first`, e.g. "Amd").
175
+ ts = ts.dup
176
+ ts.original_abbr = ts.canonical_abbreviation
177
+ model.typed_stage = ts
139
178
  end
140
179
 
141
- # Build a BundledIdentifier (base document + supplements) from the 1.x
142
- # index shape: the top-level fields are the base document, and each
143
- # joint_document/supplements entry is a joined supplement.
144
- def self.build_bundled(type:, stage:, base:, **opts)
145
- raw = opts.delete(:joint_document) || opts.delete(:supplements)
146
- entries = raw.is_a?(Array) ? raw : [raw]
147
- base_document = create(type: type, stage: stage, base: base, **opts)
148
- supplements = entries.map { |j| build_joint_supplement(j) }
149
- BundledIdentifier.new(base_document: base_document,
150
- supplements: supplements)
180
+ # --- Code components <-> plain string ---
181
+ def number_to_kv(model, doc) = emit_code(doc, "number", model.number)
182
+ def number_from_kv(model, value) = model.number = build_code(value)
183
+ def part_to_kv(model, doc) = emit_code(doc, "part", model.part)
184
+ def part_from_kv(model, value) = model.part = build_code(value)
185
+ def subpart_to_kv(model, doc) = emit_code(doc, "subpart", model.subpart)
186
+ def subpart_from_kv(model, value) = model.subpart = build_code(value)
187
+
188
+ def stage_iteration_to_kv(model, doc)
189
+ iter = model.stage_iteration
190
+ v = iter.is_a?(::Pubid::Components::Iteration) ? iter.number : iter
191
+ return if v.nil? || v.to_s.empty?
192
+
193
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("stage_iteration",
194
+ v.to_s))
151
195
  end
152
196
 
153
- # Map a 1.x joint_document hash to a 2.x supplement matching parse. The
154
- # index nests the supplement's publisher under joint_document.base.publisher
155
- # (e.g. "IEC" for "+ IEC SUP"), while parse records it as the supplement's
156
- # own publisher; move it and drop the nested base + empty top publisher.
157
- def self.build_joint_supplement(joint)
158
- j = joint.transform_keys(&:to_sym)
159
- b = (j[:base] || {}).transform_keys(&:to_sym)
160
- publisher = b[:publisher].to_s.empty? ? j[:publisher] : b[:publisher]
161
- create(
162
- type: j[:type],
163
- publisher: publisher,
164
- copublisher: b[:copublisher] || j[:copublisher],
165
- number: (j[:number] unless j[:number].to_s.empty?),
166
- year: j[:year],
167
- )
197
+ def stage_iteration_from_kv(model, value)
198
+ model.stage_iteration = ::Pubid::Components::Iteration.new(number: value.to_s)
168
199
  end
169
200
 
170
- # Build the base_identifier for a supplement from either an already
171
- # constructed identifier or a 1.x-style attribute hash (the nested
172
- # `:base` entry in a structured index). Recurses so supplement-of-
173
- # supplement chains (e.g. a Corrigendum to an Amendment) build cleanly.
174
- def self.build_base_identifier(base)
175
- return base if base.is_a?(::Pubid::Identifier)
201
+ def emit_code(doc, key, code)
202
+ v = code.is_a?(::Pubid::Components::Code) ? code.value : code
203
+ return if v.nil? || v.to_s.empty?
176
204
 
177
- create(**base.transform_keys(&:to_sym))
205
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, v.to_s))
178
206
  end
179
207
 
180
- # When `stage:` is explicit, look up the matching TypedStage via
181
- # Scheme. Otherwise default to the chosen class's "published"
182
- # TypedStage (so e.g. TR renders the "/TR" prefix). Returns nil if
183
- # neither is available; the renderer then omits the stage prefix.
184
- def self.resolve_create_typed_stage(klass, stage)
185
- if stage
186
- ts = locate_create_typed_stage(stage)
187
- ts && retype_stage_for_class(klass, ts)
188
- elsif klass.const_defined?(:TYPED_STAGES)
189
- klass.const_get(:TYPED_STAGES).find do |ts|
190
- ts.stage_code.to_sym == :published
191
- end
192
- end
208
+ def build_code(value)
209
+ ::Pubid::Iso::Components::Code.new(value: value.to_s)
193
210
  end
194
211
 
195
- # Indexes store a supplement's stage as the bare review-stage abbr
196
- # ("CD", "WD", "AWI") plus a separate type ("AMD"), so the global lookup
197
- # resolves the stage to the IS-typed variant (cdis) rather than the
198
- # amendment-typed one (committee_draft_amd). When the resolved stage's
199
- # type differs from the class chosen via `type:`, re-pick the equivalent
200
- # stage from the class's own TYPED_STAGES. harmonized_stages is the
201
- # stable cross-type key (stage_code/abbr diverge between IS and amd:
202
- # IS "WD" is :working_draft, the amendment is :wd_amd).
203
- def self.retype_stage_for_class(klass, ts)
204
- return ts unless klass.const_defined?(:TYPED_STAGES)
205
- return ts unless klass.respond_to?(:type) && klass.type
206
- return ts if ts.type_code.to_s == klass.type[:key].to_s
207
-
208
- harmonized = Array(ts.harmonized_stages)
209
- return ts if harmonized.empty?
210
-
211
- klass.const_get(:TYPED_STAGES).find do |s|
212
- (Array(s.harmonized_stages) & harmonized).any?
213
- end || ts
212
+ # --- date serialized flat as year/month/day ---
213
+ def year_to_kv(model, doc) = emit_date_part(doc, "year", model.date&.year)
214
+ def year_from_kv(model, value) = date_for(model).year = value.to_s
215
+ def month_to_kv(model, doc) = emit_date_part(doc, "month", model.date&.month)
216
+ def month_from_kv(model, value) = date_for(model).month = value.to_s
217
+ def day_to_kv(model, doc) = emit_date_part(doc, "day", model.date&.day)
218
+ def day_from_kv(model, value) = date_for(model).day = value.to_s
219
+
220
+ def emit_date_part(doc, key, val)
221
+ return if val.nil? || val.to_s.empty?
222
+
223
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new(key, val.to_s))
214
224
  end
215
225
 
216
- # Resolve a TypedStage from a create() :stage value. The index may
217
- # supply it as an abbreviation ("DIS"), a generic stage_code (:dis),
218
- # or a unique per-typed-stage code (:dtr, :fdisp). Try each in turn.
219
- def self.locate_create_typed_stage(stage)
220
- Scheme.locate_typed_stage_by_abbr(stage.to_s) ||
221
- Scheme.locate_typed_stage_by_stage_code(stage) ||
222
- Scheme.locate_typed_stage_by_code(stage)
226
+ def date_for(model)
227
+ model.date ||= ::Pubid::Components::Date.new
223
228
  end
224
229
 
225
- def self.resolve_create_class(type:, stage:, base: nil)
226
- klass =
227
- if type
228
- located = locate_klass_by_type_or_short(type)
229
- raise ArgumentError, "Unknown ISO type: #{type.inspect}" unless located
230
+ # --- publisher: primary only when non-default; copublishers as a list ---
231
+ def publisher_to_kv(model, doc)
232
+ pub = model.publisher&.publisher
233
+ return if pub.nil? || pub == model.class.default_publisher&.publisher
230
234
 
231
- located
232
- elsif stage
233
- ts = locate_create_typed_stage(stage)
234
- ts && Scheme.locate_identifier_klass_by_type_code(ts.type_code)
235
- end
236
- # A bare `base:` with no type/stage is still a supplement; fall back to
237
- # the generic Supplement (which can hold a base) rather than
238
- # InternationalStandard (which cannot).
239
- klass ||= Identifiers::Supplement if base
240
- klass || Identifiers::InternationalStandard
235
+ doc.add_child(Lutaml::KeyValue::DataModel::Element.new("publisher", pub))
241
236
  end
242
237
 
243
- # Try direct key lookup, then a case-insensitive key lookup (indexes
244
- # store e.g. "DATA" but the registry key is :data), then fall back to
245
- # matching the class's :short letter (e.g. type "R" → Recommendation,
246
- # whose key is :rec and short is "R"). Indexes and legacy data carry
247
- # either the key, an upper-cased key, or the short form.
248
- def self.locate_klass_by_type_or_short(type)
249
- Scheme.locate_identifier_klass_by_type_code(type) ||
250
- Scheme.locate_identifier_klass_by_type_code(type.to_s.downcase) ||
251
- Scheme.identifiers.detect { |k| k.type&.dig(:short)&.to_s == type.to_s }
238
+ def publisher_from_kv(model, value)
239
+ publisher_for(model).publisher = value.to_s
252
240
  end
253
241
 
254
- def self.supplement_klass?(klass)
255
- Array(Scheme.instance.supplement_identifiers).include?(klass)
242
+ def copublishers_to_kv(model, doc)
243
+ cp = model.publisher&.copublisher
244
+ return unless cp&.any?
245
+
246
+ doc.add_child(
247
+ Lutaml::KeyValue::DataModel::Element.new("copublishers", cp.map(&:to_s)),
248
+ )
256
249
  end
257
250
 
258
- def self.coerce_create_attrs(opts)
259
- out = {}
260
- if (v = opts[:publisher])
261
- # Mirror parse: the publisher carries its copublishers in its own
262
- # copublisher list, and each copublisher is also a standalone entry
263
- # in the copublishers collection. No copublisher [] (parity with
264
- # parsed plain-ISO identifiers).
265
- cops = Array(opts[:copublisher]).map(&:to_s)
266
- out[:publisher] = Components::Publisher.new(
267
- publisher: v.to_s, copublisher: cops,
268
- )
269
- end
270
- if opts[:copublisher]
271
- out[:copublishers] = Array(opts[:copublisher]).map do |c|
272
- Components::Publisher.new(publisher: c.to_s)
273
- end
274
- end
275
- %i[number part subpart].each do |k|
276
- v = opts[k]
277
- out[k] = Components::Code.new(number: v.to_s) unless v.nil?
251
+ def copublishers_from_kv(model, value)
252
+ list = Array(value).map(&:to_s)
253
+ return unless list.any?
254
+
255
+ # Mirror Builder#parse: copublishers live both on the primary
256
+ # publisher (as strings) and as the top-level `copublishers`
257
+ # collection of Publisher objects. `==` compares the latter, so
258
+ # populate both or a deserialized id never equals a parsed one.
259
+ publisher_for(model).copublisher = list
260
+ model.copublishers = list.map do |cp|
261
+ ::Pubid::Iso::Components::Publisher.new(publisher: cp)
278
262
  end
279
- if (v = opts[:year])
280
- out[:date] = ::Pubid::Components::Date.new(year: v.to_s)
263
+ end
264
+
265
+ def publisher_for(model)
266
+ model.publisher ||= ::Pubid::Iso::Components::Publisher.new
267
+ end
268
+
269
+ def self.parse(string, format: :auto)
270
+ if string.length > Pubid::MAX_INPUT_LENGTH
271
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
281
272
  end
282
- if (v = opts[:edition])
283
- if v.is_a?(Hash)
284
- # 1.x stored a directive org-variant ("ISO/IEC DIR 2 ISO" /
285
- # "ISO/IEC DIR 1 IEC:2023") as edition: {publisher:, year:}; parse
286
- # models the org as `part` and the year as `date`. Map it so create
287
- # round-trips parse.
288
- eh = v.transform_keys(&:to_sym)
289
- out[:part] ||= Components::Code.new(number: eh[:publisher].to_s) if eh[:publisher]
290
- out[:date] ||= ::Pubid::Components::Date.new(year: eh[:year].to_s) if eh[:year]
291
- else
292
- out[:edition] = ::Pubid::Components::Edition.new(number: v)
273
+
274
+ format = Pubid::FormatDetector.detect(string) if format == :auto
275
+
276
+ case format
277
+ when :urn
278
+ Pubid::Iso::UrnParser.parse(string)
279
+ when :mr_string
280
+ Pubid::Parsers::MrString.parse(string)
281
+ else
282
+ parsed = Pubid::Iso::Parser.new.parse(string)
283
+ if parsed.nil? || parsed.empty?
284
+ raise Pubid::Iso::Parser::ParseError,
285
+ "Invalid identifier format"
293
286
  end
287
+
288
+ Pubid::Iso::Builder.new.build(parsed)
294
289
  end
295
- if (v = opts[:language])
296
- out[:languages] =
297
- [::Pubid::Components::Language.new(code: v.to_s)]
298
- end
299
- # TcDocument committee fields: the 1.x/index shape is the flat
300
- # tctype/tcnumber/… keys, but the 2.x model stores underscored Code
301
- # components (mirrors the parser's builder). Without this mapping a
302
- # TC document round-trips to a bare "ISO N <num>".
303
- { tctype: :tc_type, tcnumber: :tc_number,
304
- sctype: :sc_type, scnumber: :sc_number,
305
- wgtype: :wg_type, wgnumber: :wg_number }.each do |src, dest|
306
- v = opts[src]
307
- out[dest] = Components::Code.new(number: v.to_s) unless v.nil?
308
- end
309
- # Directives subgroup (e.g. "ISO/IEC JTC 1 DIR"): the 1.x/index shape
310
- # is dirtype: "JTC", jtc_dir: "DIR", number: "1"; the 2.x model folds
311
- # the subgroup into a single `subgroup` Code ("JTC 1") with no
312
- # directive number, mirroring parse. Without this, .create drops the
313
- # subgroup and collapses the id into a plain "DIR 1".
314
- if opts[:dirtype]
315
- out[:subgroup] = Components::Code.new(
316
- number: [opts[:dirtype], opts[:number]].compact.join(" "),
317
- )
318
- out.delete(:number)
319
- end
320
- # TODO(create-shim): 1.x also accepted iteration, amendments,
321
- # corrigendums, addendum, month, dir. Add as relaton call sites
322
- # require them.
323
- out
324
290
  end
325
- private_class_method :resolve_create_class, :supplement_klass?,
326
- :resolve_create_typed_stage, :coerce_create_attrs,
327
- :build_bundled, :build_joint_supplement
291
+
292
+ # from_hash is the shared polymorphic dispatch on Pubid::Identifier, which
293
+ # routes `_type` through polymorphic_type_map (ISO_TYPE_MAP's dynamic
294
+ # equivalent). ISO_TYPE_MAP remains as the key_value polymorphic_map.
328
295
  end
329
296
  end
330
297
  end
@@ -4,7 +4,6 @@ module Pubid
4
4
  module Iso
5
5
  module Identifiers
6
6
  class Addendum < SupplementIdentifier
7
- attribute :type, ::Pubid::Components::Type, default: -> { self.class.type[:key] }
8
7
 
9
8
  # Override URN supplement type to use generic "sup" instead of "add"
10
9
  # This matches the ISO URN specification where addendums use "sup"
@@ -65,9 +64,11 @@ module Pubid
65
64
  ),
66
65
  ::Pubid::Components::TypedStage.new(
67
66
  code: :dad,
68
- abbr: ["DAD", "DAdd", "D ADD", "Dad"],
67
+ abbr: ["DAD", "DAdd", "D ADD", "Dad", "DIS Add"],
69
68
  short_abbr: "DAD",
70
- long_abbr: "DAdd",
69
+ # "DAdd" stays in `abbr` so it still parses, but render the canonical
70
+ # "DAD" (pubid v1 legacy_abbr parity). No long_abbr → no long render.
71
+ long_abbr: nil,
71
72
  type_code: :add,
72
73
  stage_code: :dad,
73
74
  name: "Draft Addendum",
@@ -75,9 +76,10 @@ module Pubid
75
76
  ),
76
77
  ::Pubid::Components::TypedStage.new(
77
78
  code: :fdad,
78
- abbr: ["FDAD", "FDAdd", "FD ADD", "FDad"],
79
+ abbr: ["FDAD", "FDAdd", "FD ADD", "FDad", "FDIS Add"],
79
80
  short_abbr: "FDAD",
80
- long_abbr: "FDAdd",
81
+ # See :dad — parse "FDAdd", render canonical "FDAD" (v1 parity).
82
+ long_abbr: nil,
81
83
  type_code: :add,
82
84
  stage_code: :fdad,
83
85
  name: "Final Draft Addendum",
@@ -96,7 +98,8 @@ module Pubid
96
98
  ].freeze
97
99
 
98
100
  def self.type
99
- { key: :add, title: "Addendum", short: "ADD" }
101
+ { key: :add,
102
+ web: :addendum, title: "Addendum", short: "ADD" }
100
103
  end
101
104
  end
102
105
  end
@@ -4,7 +4,6 @@ module Pubid
4
4
  module Iso
5
5
  module Identifiers
6
6
  class Amendment < SupplementIdentifier
7
- attribute :type, ::Pubid::Components::Type, default: -> { self.class.type[:key] }
8
7
 
9
8
  TYPED_STAGES = [
10
9
  ::Pubid::Components::TypedStage.new(
@@ -71,7 +70,10 @@ module Pubid
71
70
  code: :damd,
72
71
  abbr: ["DAM", "DAmd"],
73
72
  short_abbr: "DAM",
74
- long_abbr: "DAmd",
73
+ # "DAmd" stays in `abbr` so it still parses, but render the canonical
74
+ # "DAM" (matches pubid v1's legacy_abbr semantics: parse the long
75
+ # spelling, emit the short one). No long_abbr → no long rendering.
76
+ long_abbr: nil,
75
77
  type_code: :amd,
76
78
  stage_code: :damd,
77
79
  name: "Draft Amendment",
@@ -81,7 +83,8 @@ module Pubid
81
83
  code: :fdamd,
82
84
  abbr: ["FDAM", "FDAmd"],
83
85
  short_abbr: "FDAM",
84
- long_abbr: "FDAmd",
86
+ # See :damd — parse "FDAmd", render canonical "FDAM" (v1 parity).
87
+ long_abbr: nil,
85
88
  type_code: :amd,
86
89
  stage_code: :fdamd,
87
90
  name: "Final Draft Amendment",
@@ -120,7 +123,8 @@ module Pubid
120
123
  ].freeze
121
124
 
122
125
  def self.type
123
- { key: :amd, title: "Amendment", short: "AMD" }
126
+ { key: :amd,
127
+ web: :amendment, title: "Amendment", short: "AMD" }
124
128
  end
125
129
  end
126
130
  end