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

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