pubid 2.0.0.pre.alpha.1 → 2.0.0.pre.alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +27 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +7 -0
  6. data/lib/pubid/amca/identifiers/base.rb +0 -26
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -17
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -13
  9. data/lib/pubid/amca/renderer.rb +82 -0
  10. data/lib/pubid/amca/single_identifier.rb +0 -23
  11. data/lib/pubid/amca/urn_parser.rb +28 -0
  12. data/lib/pubid/amca.rb +42 -1
  13. data/lib/pubid/ansi/builder.rb +5 -3
  14. data/lib/pubid/ansi/identifier.rb +1 -1
  15. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  16. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  17. data/lib/pubid/ansi/renderer.rb +53 -0
  18. data/lib/pubid/ansi/single_identifier.rb +2 -31
  19. data/lib/pubid/ansi/urn_generator.rb +3 -38
  20. data/lib/pubid/ansi/urn_parser.rb +23 -0
  21. data/lib/pubid/ansi.rb +38 -3
  22. data/lib/pubid/api/builder.rb +29 -74
  23. data/lib/pubid/api/identifier.rb +0 -4
  24. data/lib/pubid/api/identifiers/base.rb +0 -2
  25. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  26. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  27. data/lib/pubid/api/identifiers/mpms.rb +1 -17
  28. data/lib/pubid/api/identifiers/publication.rb +0 -2
  29. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  30. data/lib/pubid/api/identifiers/specification.rb +0 -2
  31. data/lib/pubid/api/identifiers/standard.rb +0 -2
  32. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  33. data/lib/pubid/api/identifiers/typeless_standard.rb +1 -14
  34. data/lib/pubid/api/identifiers.rb +18 -0
  35. data/lib/pubid/api/renderer.rb +89 -0
  36. data/lib/pubid/api/single_identifier.rb +1 -13
  37. data/lib/pubid/api/urn_generator.rb +0 -18
  38. data/lib/pubid/api/urn_parser.rb +35 -0
  39. data/lib/pubid/api.rb +51 -5
  40. data/lib/pubid/ashrae/builder.rb +3 -3
  41. data/lib/pubid/ashrae/identifier.rb +6 -0
  42. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  43. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  44. data/lib/pubid/ashrae/identifiers/base.rb +3 -0
  45. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  46. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  47. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  48. data/lib/pubid/ashrae/renderer.rb +117 -0
  49. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  50. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  51. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  52. data/lib/pubid/ashrae.rb +42 -1
  53. data/lib/pubid/asme/components/code.rb +10 -2
  54. data/lib/pubid/asme/identifiers/base.rb +0 -60
  55. data/lib/pubid/asme/renderer.rb +66 -0
  56. data/lib/pubid/asme/urn_parser.rb +31 -0
  57. data/lib/pubid/asme.rb +42 -1
  58. data/lib/pubid/astm/components/code.rb +9 -0
  59. data/lib/pubid/{jis → astm}/components.rb +1 -1
  60. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  61. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  62. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  63. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  64. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  65. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  66. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  67. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  68. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  69. data/lib/pubid/astm/identifiers.rb +18 -0
  70. data/lib/pubid/astm/renderer.rb +172 -0
  71. data/lib/pubid/astm/single_identifier.rb +0 -10
  72. data/lib/pubid/astm/urn_parser.rb +30 -0
  73. data/lib/pubid/astm.rb +39 -27
  74. data/lib/pubid/bsi/builder.rb +21 -12
  75. data/lib/pubid/bsi/identifier.rb +8 -2
  76. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  77. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  78. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  79. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  80. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  81. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  82. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  83. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  84. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  85. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  87. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  88. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  89. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  90. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  91. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  92. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  93. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  94. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  95. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  96. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  97. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  98. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  99. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  100. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  101. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  102. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  103. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  104. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  105. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  106. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  107. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  108. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  109. data/lib/pubid/bsi/identifiers.rb +0 -1
  110. data/lib/pubid/bsi/renderer.rb +1050 -0
  111. data/lib/pubid/bsi/single_identifier.rb +6 -70
  112. data/lib/pubid/bsi/urn_generator.rb +2 -3
  113. data/lib/pubid/bsi/urn_parser.rb +52 -0
  114. data/lib/pubid/bsi.rb +224 -1
  115. data/lib/pubid/builder/base.rb +57 -10
  116. data/lib/pubid/bundled_identifier.rb +0 -1
  117. data/lib/pubid/ccsds/builder.rb +4 -3
  118. data/lib/pubid/ccsds/identifier.rb +66 -1
  119. data/lib/pubid/ccsds/identifiers/base.rb +11 -50
  120. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  121. data/lib/pubid/ccsds/parser.rb +4 -2
  122. data/lib/pubid/ccsds/single_identifier.rb +4 -1
  123. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  124. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  125. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  126. data/lib/pubid/ccsds.rb +39 -1
  127. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  128. data/lib/pubid/cen_cenelec/identifier.rb +8 -2
  129. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  130. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  131. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  132. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  133. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  135. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  136. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  137. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  138. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  140. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  141. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  143. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  144. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  145. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  146. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  147. data/lib/pubid/cen_cenelec.rb +168 -1
  148. data/lib/pubid/cie/components/code.rb +8 -0
  149. data/lib/pubid/cie/identifier.rb +6 -4
  150. data/lib/pubid/cie/urn_parser.rb +28 -0
  151. data/lib/pubid/cie.rb +43 -1
  152. data/lib/pubid/components/adoption.rb +104 -0
  153. data/lib/pubid/components/code.rb +22 -8
  154. data/lib/pubid/components/date.rb +23 -16
  155. data/lib/pubid/components/edition.rb +9 -6
  156. data/lib/pubid/components/iteration.rb +32 -0
  157. data/lib/pubid/components/language.rb +6 -4
  158. data/lib/pubid/components/locality.rb +10 -1
  159. data/lib/pubid/components/publisher.rb +9 -6
  160. data/lib/pubid/components/relationship.rb +151 -0
  161. data/lib/pubid/components/stage.rb +5 -14
  162. data/lib/pubid/components/supplement.rb +184 -0
  163. data/lib/pubid/components/type.rb +5 -15
  164. data/lib/pubid/components/typed_stage.rb +11 -8
  165. data/lib/pubid/components.rb +4 -0
  166. data/lib/pubid/core/update_codes.rb +28 -7
  167. data/lib/pubid/csa/identifier.rb +0 -3
  168. data/lib/pubid/csa/identifiers/base.rb +2 -122
  169. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  170. data/lib/pubid/csa/identifiers/series.rb +2 -102
  171. data/lib/pubid/csa/renderer.rb +292 -0
  172. data/lib/pubid/csa/urn_generator.rb +1 -1
  173. data/lib/pubid/csa/urn_parser.rb +33 -0
  174. data/lib/pubid/csa.rb +42 -1
  175. data/lib/pubid/etsi/components/code.rb +9 -2
  176. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  177. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  178. data/lib/pubid/etsi/renderer.rb +42 -0
  179. data/lib/pubid/etsi/urn_parser.rb +34 -0
  180. data/lib/pubid/etsi.rb +42 -1
  181. data/lib/pubid/export/exporter.rb +4 -46
  182. data/lib/pubid/export/flavor_exporter.rb +111 -278
  183. data/lib/pubid/export.rb +0 -6
  184. data/lib/pubid/identifier.rb +10 -18
  185. data/lib/pubid/identifier_facade.rb +114 -0
  186. data/lib/pubid/identifier_metadata.rb +1 -1
  187. data/lib/pubid/idf/builder.rb +3 -3
  188. data/lib/pubid/idf/identifier.rb +3 -6
  189. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  190. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  191. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  192. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  193. data/lib/pubid/idf/parser.rb +3 -2
  194. data/lib/pubid/idf/renderer.rb +84 -0
  195. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  196. data/lib/pubid/idf/urn_generator.rb +4 -39
  197. data/lib/pubid/idf/urn_parser.rb +25 -0
  198. data/lib/pubid/idf.rb +51 -1
  199. data/lib/pubid/iec/builder.rb +48 -65
  200. data/lib/pubid/iec/components/code.rb +9 -32
  201. data/lib/pubid/iec/components/publisher.rb +1 -1
  202. data/lib/pubid/iec/components.rb +14 -0
  203. data/lib/pubid/iec/identifier.rb +276 -3
  204. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  205. data/lib/pubid/iec/identifiers/base.rb +8 -28
  206. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  207. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  208. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -30
  209. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  210. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -26
  211. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  212. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  213. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  214. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  215. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  216. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -15
  217. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  218. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  219. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  220. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  222. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  223. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -23
  224. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  225. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  226. data/lib/pubid/iec/identifiers.rb +30 -0
  227. data/lib/pubid/iec/parser.rb +20 -14
  228. data/lib/pubid/iec/renderer.rb +254 -0
  229. data/lib/pubid/iec/single_identifier.rb +6 -12
  230. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  231. data/lib/pubid/iec/urn_generator.rb +57 -171
  232. data/lib/pubid/iec/urn_parser.rb +53 -252
  233. data/lib/pubid/iec.rb +40 -68
  234. data/lib/pubid/ieee/builder.rb +12 -12
  235. data/lib/pubid/ieee/components/code.rb +8 -0
  236. data/lib/pubid/ieee/components/draft.rb +14 -0
  237. data/lib/pubid/ieee/components/relationship.rb +5 -149
  238. data/lib/pubid/ieee/identifier.rb +6 -0
  239. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  240. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  241. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  242. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  243. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  245. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  246. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  247. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  248. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  249. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  250. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  251. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  252. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  253. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  254. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  255. data/lib/pubid/ieee/pre_parser.rb +301 -0
  256. data/lib/pubid/ieee/renderer.rb +307 -0
  257. data/lib/pubid/ieee/urn_parser.rb +34 -0
  258. data/lib/pubid/ieee.rb +62 -1
  259. data/lib/pubid/ieee_debug.rb +0 -1
  260. data/lib/pubid/iho/builder.rb +2 -2
  261. data/lib/pubid/iho/identifier.rb +8 -0
  262. data/lib/pubid/iho/identifiers/base.rb +49 -10
  263. data/lib/pubid/iho/identifiers/bibliographic.rb +0 -4
  264. data/lib/pubid/iho/identifiers/circular_letter.rb +0 -4
  265. data/lib/pubid/iho/identifiers/miscellaneous.rb +0 -4
  266. data/lib/pubid/iho/identifiers/publication.rb +0 -4
  267. data/lib/pubid/iho/identifiers/standard.rb +0 -4
  268. data/lib/pubid/iho/parser.rb +3 -3
  269. data/lib/pubid/iho/renderer.rb +30 -0
  270. data/lib/pubid/iho/urn_generator.rb +3 -3
  271. data/lib/pubid/iho/urn_parser.rb +58 -0
  272. data/lib/pubid/iho.rb +50 -1
  273. data/lib/pubid/iso/builder.rb +59 -53
  274. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  275. data/lib/pubid/iso/components/code.rb +7 -19
  276. data/lib/pubid/iso/components/publisher.rb +10 -8
  277. data/lib/pubid/iso/components.rb +2 -4
  278. data/lib/pubid/iso/identifier.rb +233 -6
  279. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  280. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  281. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  282. data/lib/pubid/iso/identifiers/data.rb +0 -1
  283. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  284. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  285. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  286. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  287. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  288. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  289. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  290. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  291. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  292. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  293. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  294. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  295. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  296. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  297. data/lib/pubid/iso/identifiers.rb +0 -1
  298. data/lib/pubid/iso/normalizer.rb +89 -0
  299. data/lib/pubid/iso/parser.rb +26 -6
  300. data/lib/pubid/iso/single_identifier.rb +6 -3
  301. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  302. data/lib/pubid/iso/urn_generator.rb +74 -176
  303. data/lib/pubid/iso/urn_parser.rb +28 -9
  304. data/lib/pubid/iso.rb +173 -2
  305. data/lib/pubid/itu/builder.rb +0 -12
  306. data/lib/pubid/itu/components/code.rb +8 -0
  307. data/lib/pubid/itu/components.rb +11 -0
  308. data/lib/pubid/itu/identifier.rb +6 -39
  309. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  310. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  311. data/lib/pubid/itu/identifiers/base.rb +0 -6
  312. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  313. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  314. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  315. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  316. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  317. data/lib/pubid/itu/urn_parser.rb +23 -0
  318. data/lib/pubid/itu.rb +42 -1
  319. data/lib/pubid/jcgm/builder.rb +16 -8
  320. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  321. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  322. data/lib/pubid/jcgm/renderer.rb +68 -0
  323. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  324. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  325. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  326. data/lib/pubid/jcgm.rb +43 -2
  327. data/lib/pubid/jis/builder.rb +44 -52
  328. data/lib/pubid/jis/identifier.rb +132 -3
  329. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  330. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  331. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  332. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  333. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  334. data/lib/pubid/jis/identifiers.rb +1 -1
  335. data/lib/pubid/jis/parser.rb +31 -5
  336. data/lib/pubid/jis/renderer.rb +69 -0
  337. data/lib/pubid/jis/single_identifier.rb +6 -12
  338. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  339. data/lib/pubid/jis/urn_parser.rb +23 -0
  340. data/lib/pubid/jis.rb +42 -2
  341. data/lib/pubid/nist/builder.rb +122 -1761
  342. data/lib/pubid/nist/caster.rb +1272 -0
  343. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  344. data/lib/pubid/nist/components/code.rb +9 -20
  345. data/lib/pubid/nist/components/edition.rb +16 -0
  346. data/lib/pubid/nist/components/supplement.rb +88 -21
  347. data/lib/pubid/nist/components.rb +0 -1
  348. data/lib/pubid/nist/identifier.rb +25 -0
  349. data/lib/pubid/nist/identifiers/base.rb +206 -64
  350. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  351. data/lib/pubid/nist/identifiers/circular_supplement.rb +3 -2
  352. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  353. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  354. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  355. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -11
  356. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  357. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +17 -16
  358. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  359. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  360. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  361. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  362. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  363. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  364. data/lib/pubid/nist/identifiers/report.rb +4 -3
  365. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  366. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  367. data/lib/pubid/nist/identifiers.rb +1 -0
  368. data/lib/pubid/nist/parser.rb +67 -424
  369. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  370. data/lib/pubid/nist/preprocessor.rb +416 -0
  371. data/lib/pubid/nist/renderer.rb +43 -0
  372. data/lib/pubid/nist/router.rb +148 -0
  373. data/lib/pubid/nist/series/base.rb +58 -0
  374. data/lib/pubid/nist/series/crpl.rb +13 -0
  375. data/lib/pubid/nist/series/fips.rb +14 -0
  376. data/lib/pubid/nist/series/ir.rb +60 -0
  377. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  378. data/lib/pubid/nist/series/mono.rb +19 -0
  379. data/lib/pubid/nist/series/ncstar.rb +20 -0
  380. data/lib/pubid/nist/series.rb +49 -0
  381. data/lib/pubid/nist/supplement_identifier.rb +11 -25
  382. data/lib/pubid/nist/urn_generator.rb +14 -8
  383. data/lib/pubid/nist/urn_parser.rb +67 -0
  384. data/lib/pubid/nist.rb +83 -4
  385. data/lib/pubid/oiml/components/code.rb +10 -0
  386. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  387. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  388. data/lib/pubid/oiml/renderer.rb +161 -0
  389. data/lib/pubid/oiml/single_identifier.rb +6 -45
  390. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  391. data/lib/pubid/oiml/urn_generator.rb +0 -8
  392. data/lib/pubid/oiml/urn_parser.rb +22 -0
  393. data/lib/pubid/oiml.rb +42 -1
  394. data/lib/pubid/plateau/identifier.rb +23 -0
  395. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  396. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  397. data/lib/pubid/plateau/renderer.rb +51 -0
  398. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  399. data/lib/pubid/plateau/urn_parser.rb +43 -0
  400. data/lib/pubid/plateau.rb +44 -1
  401. data/lib/pubid/renderers/base.rb +34 -0
  402. data/lib/pubid/renderers/directives_renderer.rb +27 -14
  403. data/lib/pubid/renderers/guide_renderer.rb +7 -1
  404. data/lib/pubid/renderers/human_readable.rb +31 -8
  405. data/lib/pubid/renderers/iwa_renderer.rb +5 -1
  406. data/lib/pubid/renderers/supplement_renderer.rb +4 -1
  407. data/lib/pubid/rendering/context.rb +33 -21
  408. data/lib/pubid/rendering.rb +0 -3
  409. data/lib/pubid/sae/components/date.rb +8 -0
  410. data/lib/pubid/sae/components/type.rb +5 -1
  411. data/lib/pubid/sae/identifiers/base.rb +2 -16
  412. data/lib/pubid/sae/renderer.rb +36 -0
  413. data/lib/pubid/sae/urn_generator.rb +2 -10
  414. data/lib/pubid/sae/urn_parser.rb +36 -0
  415. data/lib/pubid/sae.rb +42 -1
  416. data/lib/pubid/urn_generator/base.rb +12 -12
  417. data/lib/pubid/urn_parser/base.rb +81 -0
  418. data/lib/pubid/urn_parser/errors.rb +9 -0
  419. data/lib/pubid/urn_parser.rb +14 -0
  420. data/lib/pubid/version.rb +1 -1
  421. data/lib/pubid.rb +29 -7
  422. data/lib/tasks/website-data.json +1940 -1882
  423. metadata +77 -43
  424. data/lib/pubid/amca/scheme.rb +0 -16
  425. data/lib/pubid/ansi/scheme.rb +0 -15
  426. data/lib/pubid/api/scheme.rb +0 -66
  427. data/lib/pubid/ashrae/scheme.rb +0 -53
  428. data/lib/pubid/asme/scheme.rb +0 -37
  429. data/lib/pubid/astm/scheme.rb +0 -55
  430. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  431. data/lib/pubid/bsi/scheme.rb +0 -243
  432. data/lib/pubid/ccsds/scheme.rb +0 -57
  433. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  434. data/lib/pubid/cie/scheme.rb +0 -64
  435. data/lib/pubid/csa/scheme.rb +0 -44
  436. data/lib/pubid/etsi/scheme.rb +0 -42
  437. data/lib/pubid/export/data_class_exporter.rb +0 -59
  438. data/lib/pubid/export/ieee_exporter.rb +0 -78
  439. data/lib/pubid/export/itu_exporter.rb +0 -66
  440. data/lib/pubid/export/nist_exporter.rb +0 -64
  441. data/lib/pubid/export/registry_exporter.rb +0 -90
  442. data/lib/pubid/export/scheme_exporter.rb +0 -70
  443. data/lib/pubid/identifier_registry.rb +0 -198
  444. data/lib/pubid/idf/scheme.rb +0 -61
  445. data/lib/pubid/iec/scheme.rb +0 -71
  446. data/lib/pubid/ieee/scheme.rb +0 -90
  447. data/lib/pubid/iho/scheme.rb +0 -29
  448. data/lib/pubid/iso/identifiers/base.rb +0 -115
  449. data/lib/pubid/iso/scheme.rb +0 -187
  450. data/lib/pubid/itu/scheme.rb +0 -174
  451. data/lib/pubid/jcgm/scheme.rb +0 -60
  452. data/lib/pubid/jis/components/code.rb +0 -59
  453. data/lib/pubid/jis/identifiers/base.rb +0 -72
  454. data/lib/pubid/jis/scheme.rb +0 -49
  455. data/lib/pubid/nist/components/publisher.rb +0 -24
  456. data/lib/pubid/nist/scheme.rb +0 -199
  457. data/lib/pubid/oiml/scheme.rb +0 -46
  458. data/lib/pubid/plateau/scheme.rb +0 -45
  459. data/lib/pubid/rendering/base.rb +0 -73
  460. data/lib/pubid/rendering/common.rb +0 -211
  461. data/lib/pubid/rendering/format.rb +0 -25
  462. data/lib/pubid/sae/scheme.rb +0 -47
  463. data/lib/pubid/scheme.rb +0 -207
@@ -3,6 +3,11 @@
3
3
  module Pubid
4
4
  module Bsi
5
5
  class SingleIdentifier < Pubid::Identifier
6
+ # Identity for the Pubid::Bsi::Identifier facade: SingleIdentifier is the
7
+ # common ancestor of every concrete BSI identifier, so including the
8
+ # facade module here makes them all `is_a?(Pubid::Bsi::Identifier)`.
9
+ include Pubid::Bsi::Identifier
10
+
6
11
  # Generate URN for this identifier
7
12
  #
8
13
  # @return [String] URN representation
@@ -30,76 +35,7 @@ module Pubid
30
35
  attribute :space_separated_part, :boolean, default: -> { false }
31
36
 
32
37
  def to_s(lang: :en, lang_single: false)
33
- # Build string representation
34
- parts = []
35
-
36
- # For supplement/addendum base identifiers, flex_prefix replaces publisher+prefix
37
- parts << publisher.to_s if publisher
38
- if flex_prefix
39
- # Flex prefix is the full prefix including BS (e.g., "BS CECC" becomes "BS" + space + "CECC")
40
- parts << flex_prefix
41
- elsif prefix
42
- # Standard publisher
43
-
44
- # Prefix if present (specialized prefix like A, AU, C, etc.)
45
- parts << prefix.to_s
46
- end
47
-
48
- # Number with iteration, part, and subpart
49
- if number
50
- number_str = number.is_a?(Components::Code) ? number.value.to_s : number.to_s
51
-
52
- # Collection (second number with slash)
53
- if second_number
54
- second_val = second_number.is_a?(Components::Code) ? second_number.value : second_number
55
- number_str += "/#{second_val}"
56
- end
57
-
58
- # Part and subpart - check if space-separated
59
- space_separated = space_separated_part
60
- if part
61
- part_val = part.is_a?(Components::Code) ? part.value : part
62
- # Trim part value to remove leading/trailing spaces from parser
63
- part_str = part_val.to_s.strip
64
- # Use space for space-separated parts, dash otherwise
65
- separator = space_separated ? " " : "-"
66
- number_str += "#{separator}#{part_str}"
67
- end
68
- if subpart
69
- subpart_val = subpart.is_a?(Components::Code) ? subpart.value : subpart
70
- subpart_str = subpart_val.to_s.strip
71
- number_str += "-#{subpart_str}"
72
- end
73
-
74
- # Iteration (bracket notation like 1000[9])
75
- if iteration && !iteration.empty?
76
- number_str += "[#{iteration}]"
77
- end
78
-
79
- parts << number_str
80
- end
81
-
82
- result = parts.join(" ")
83
-
84
- # Date
85
- if date
86
- year_val = date.is_a?(Components::Date) ? date.year : date.to_i
87
- result += ":#{year_val}"
88
- # Month if present
89
- result += "-#{format('%02d', month)}" if month
90
- end
91
-
92
- # Edition
93
- result += " v#{edition}" if edition
94
-
95
- # Translation
96
- if translation_lang
97
- result += " (#{translation_lang})"
98
- elsif translation_upper
99
- result += " (#{translation_upper})"
100
- end
101
-
102
- result
38
+ render(format: :human, lang: lang, lang_single: lang_single)
103
39
  end
104
40
 
105
41
  def <=>(other)
@@ -44,9 +44,8 @@ module Pubid
44
44
  parts << "/#{second}"
45
45
  end
46
46
 
47
- if identifier.date
48
- year = identifier.date.year
49
- parts << year.to_s
47
+ if identifier.date&.is_a?(::Pubid::Components::Date) && identifier.date.present?
48
+ parts << identifier.date.render(context: URN_CONTEXT)
50
49
  elsif identifier.year
51
50
  parts << identifier.year.to_s
52
51
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Bsi
5
+ # Parses BSI URNs back into identifiers.
6
+ #
7
+ # UrnGenerator emits:
8
+ # urn:bsi:{publisher}:{number}:{year}[:{supp_type}:{supp_number}:{supp_year}]
9
+ #
10
+ # publisher is the lowercase publisher (e.g., "bs", "pd"). supplement
11
+ # triples (`amd`/`cor`/`add`) follow the base identifier.
12
+ #
13
+ # Examples:
14
+ # - urn:bsi:bs:9001:2015 → BS 9001:2015
15
+ # - urn:bsi:bs:9001:2015:amd:1:2020 → BS 9001:2015/A1:2020
16
+ class UrnParser < Pubid::UrnParser::Base
17
+ SUPPLEMENT_ABBR = {
18
+ "amd" => "Amd",
19
+ "cor" => "Cor",
20
+ "add" => "Add",
21
+ }.freeze
22
+
23
+ def parse_urn(urn)
24
+ body = strip_namespace(urn)
25
+ parts = split_parts(body)
26
+
27
+ publisher_token, number, year, *supplement_parts = parts
28
+ publisher = publisher_token.upcase
29
+ text = "#{publisher} #{number}"
30
+ text += ":#{year}" if year
31
+ text += build_supplements(supplement_parts)
32
+ flavor_parse(text)
33
+ end
34
+
35
+ private
36
+
37
+ def build_supplements(parts)
38
+ return "" if parts.empty?
39
+
40
+ chunks = parts.each_slice(3).to_a
41
+ chunks.map { |type, num, supp_year| render_supplement(type, num, supp_year) }.join
42
+ end
43
+
44
+ def render_supplement(type, num, supp_year)
45
+ label = SUPPLEMENT_ABBR.fetch(type.downcase) { type.capitalize }
46
+ suffix = num ? " #{num}" : ""
47
+ suffix += ":#{supp_year}" if supp_year
48
+ "/#{label}#{suffix}"
49
+ end
50
+ end
51
+ end
52
+ end
data/lib/pubid/bsi.rb CHANGED
@@ -14,9 +14,193 @@ module Pubid
14
14
  autoload :Identifiers, "#{__dir__}/bsi/identifiers"
15
15
  autoload :Model, "#{__dir__}/bsi/model"
16
16
  autoload :Parser, "#{__dir__}/bsi/parser"
17
- autoload :Scheme, "#{__dir__}/bsi/scheme"
17
+ autoload :Renderer, "#{__dir__}/bsi/renderer"
18
18
  autoload :SingleIdentifier, "#{__dir__}/bsi/single_identifier"
19
19
  autoload :UrnGenerator, "#{__dir__}/bsi/urn_generator"
20
+ autoload :UrnParser, "#{__dir__}/bsi/urn_parser"
21
+
22
+ # TYPED_STAGES_REGISTRY for native BSI types. Used by Pubid::Bsi.locate_stage
23
+ # to map abbreviations (e.g. "BS", "PD", "Handbook") to typed stages.
24
+ TYPED_STAGES_REGISTRY = [
25
+ # British Standard (BS)
26
+ Pubid::Components::TypedStage.new(
27
+ code: :pubbs,
28
+ stage_code: :published,
29
+ type_code: :bs,
30
+ abbr: ["BS"],
31
+ name: "British Standard",
32
+ harmonized_stages: %w[60.00 60.60],
33
+ ),
34
+ Pubid::Components::TypedStage.new(
35
+ code: :drbs,
36
+ stage_code: :draft,
37
+ type_code: :bs,
38
+ abbr: ["Draft BS", "DBS"],
39
+ name: "Draft British Standard",
40
+ harmonized_stages: %w[30.00 30.20 30.60 40.00 40.20 40.60],
41
+ ),
42
+
43
+ # Published Document (PD)
44
+ Pubid::Components::TypedStage.new(
45
+ code: :pubpd,
46
+ stage_code: :published,
47
+ type_code: :pd,
48
+ abbr: ["PD"],
49
+ name: "Published Document",
50
+ harmonized_stages: %w[60.00 60.60],
51
+ ),
52
+
53
+ # Publicly Available Specification (PAS)
54
+ Pubid::Components::TypedStage.new(
55
+ code: :pubpas,
56
+ stage_code: :published,
57
+ type_code: :pas,
58
+ abbr: ["PAS"],
59
+ name: "Publicly Available Specification",
60
+ harmonized_stages: %w[60.00 60.60],
61
+ ),
62
+
63
+ # National Annex (NA)
64
+ Pubid::Components::TypedStage.new(
65
+ code: :pubna,
66
+ stage_code: :published,
67
+ type_code: :na,
68
+ abbr: ["NA"],
69
+ name: "National Annex",
70
+ harmonized_stages: %w[60.00 60.60],
71
+ ),
72
+
73
+ # Draft Document (DD)
74
+ Pubid::Components::TypedStage.new(
75
+ code: :pubdd,
76
+ stage_code: :published,
77
+ type_code: :dd,
78
+ abbr: ["DD"],
79
+ name: "Draft Document",
80
+ harmonized_stages: %w[60.00 60.60],
81
+ ),
82
+
83
+ # Flex Document
84
+ Pubid::Components::TypedStage.new(
85
+ code: :pubflex,
86
+ stage_code: :published,
87
+ type_code: :flex,
88
+ abbr: ["Flex", "BSI Flex"],
89
+ name: "BSI Flex",
90
+ harmonized_stages: %w[60.00 60.60],
91
+ ),
92
+
93
+ # Handbook
94
+ Pubid::Components::TypedStage.new(
95
+ code: :pubhandbook,
96
+ stage_code: :published,
97
+ type_code: :handbook,
98
+ abbr: ["Handbook", "HB"],
99
+ name: "BSI Handbook",
100
+ harmonized_stages: %w[60.00 60.60],
101
+ ),
102
+
103
+ # Practice Guide (PP)
104
+ Pubid::Components::TypedStage.new(
105
+ code: :pubpp,
106
+ stage_code: :published,
107
+ type_code: :pp,
108
+ abbr: ["PP"],
109
+ name: "Published Practice",
110
+ harmonized_stages: %w[60.00 60.60],
111
+ ),
112
+
113
+ # British Industrial Practice (BIP)
114
+ Pubid::Components::TypedStage.new(
115
+ code: :pubbip,
116
+ stage_code: :published,
117
+ type_code: :bip,
118
+ abbr: ["BIP"],
119
+ name: "British Industrial Practice",
120
+ harmonized_stages: %w[60.00 60.60],
121
+ ),
122
+
123
+ # Aerospace/Specialized British Standard (with letter prefix)
124
+ Pubid::Components::TypedStage.new(
125
+ code: :pubaerospace,
126
+ stage_code: :published,
127
+ type_code: :aerospace,
128
+ abbr: ["BS A", "BS AU", "BS C", "BS M", "BS S", "BS L", "BS TA",
129
+ "BS MA", "BS PL", "BS QC", "BS G", "BS HC", "BS F", "BS X", "BS B"],
130
+ name: "Aerospace/Specialized British Standard",
131
+ harmonized_stages: %w[60.00 60.60],
132
+ ),
133
+
134
+ # Index
135
+ Pubid::Components::TypedStage.new(
136
+ code: :pubindex,
137
+ stage_code: :published,
138
+ type_code: :index,
139
+ abbr: ["Index"],
140
+ name: "BSI Index",
141
+ harmonized_stages: %w[60.00 60.60],
142
+ ),
143
+
144
+ # Method
145
+ Pubid::Components::TypedStage.new(
146
+ code: :pubmethod,
147
+ stage_code: :published,
148
+ type_code: :method,
149
+ abbr: ["Method", "Methods"],
150
+ name: "BSI Method",
151
+ harmonized_stages: %w[60.00 60.60],
152
+ ),
153
+
154
+ # Section
155
+ Pubid::Components::TypedStage.new(
156
+ code: :pubsection,
157
+ stage_code: :published,
158
+ type_code: :section,
159
+ abbr: ["Section"],
160
+ name: "BSI Section",
161
+ harmonized_stages: %w[60.00 60.60],
162
+ ),
163
+
164
+ # DISC (Delivering Information Solutions to Customers)
165
+ Pubid::Components::TypedStage.new(
166
+ code: :pubdisc,
167
+ stage_code: :published,
168
+ type_code: :disc,
169
+ abbr: ["DISC"],
170
+ name: "DISC",
171
+ harmonized_stages: %w[60.00 60.60],
172
+ ),
173
+
174
+ # Detailed Specification (with N or C notation)
175
+ Pubid::Components::TypedStage.new(
176
+ code: :pubdetailed_spec,
177
+ stage_code: :published,
178
+ type_code: :detailed_specification,
179
+ abbr: ["DETAILED SPEC"],
180
+ name: "Detailed Specification",
181
+ harmonized_stages: %w[60.00 60.60],
182
+ ),
183
+
184
+ # Standalone Amendment
185
+ Pubid::Components::TypedStage.new(
186
+ code: :standalone_amendment,
187
+ stage_code: :published,
188
+ type_code: :amendment,
189
+ abbr: ["AMD"],
190
+ name: "Amendment",
191
+ harmonized_stages: %w[60.00 60.60],
192
+ ),
193
+
194
+ # Technical Specification
195
+ Pubid::Components::TypedStage.new(
196
+ code: :pubts,
197
+ stage_code: :published,
198
+ type_code: :ts,
199
+ abbr: ["TS"],
200
+ name: "Technical Specification",
201
+ harmonized_stages: %w[60.00 60.60],
202
+ ),
203
+ ].freeze
20
204
 
21
205
  def self.parse(string)
22
206
  Identifier.parse(string)
@@ -25,8 +209,47 @@ module Pubid
25
209
  def self.transform(data)
26
210
  Builder.build(data)
27
211
  end
212
+
213
+ # Auto-discover all identifier types from the Identifiers namespace.
214
+ # Includes classes with explicit type declarations (Hash or nil).
215
+ # @return [Array<Class>] identifier classes (Pubid::Identifier subclasses)
216
+ def self.identifier_types
217
+ @identifier_types ||= Identifiers.constants
218
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
219
+ .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
220
+ .select { |c| c.singleton_methods(false).include?(:type) }
221
+ .reject { |c| c.name&.split("::")&.last == "Base" }
222
+ end
223
+
224
+ # Build typed stage index from the module's TYPED_STAGES_REGISTRY
225
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
226
+ def self.all_typed_stages
227
+ @all_typed_stages ||= TYPED_STAGES_REGISTRY
228
+ end
229
+
230
+ # Lookup: type code -> identifier class
231
+ # @param code [String, Symbol] the type key to find
232
+ # @return [Class, nil] the matching identifier class
233
+ def self.locate_type(code)
234
+ identifier_types.find { |t| t.type&.dig(:key)&.to_s == code.to_s }
235
+ end
236
+
237
+ # Lookup: abbreviation -> typed stage
238
+ # @param abbr [String, Symbol] the abbreviation to find
239
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
240
+ def self.locate_stage(abbr)
241
+ abbr_str = abbr.to_s.upcase
242
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
243
+ end
28
244
  end
29
245
  end
30
246
 
31
247
  # Register Ubsi flavor with the registry
32
248
  Pubid::Registry.register(:bsi, Pubid::Bsi)
249
+
250
+ # Per-flavor format registry: inherits global formats, overrides :human.
251
+ # SingleIdentifier is the abstract base for every concrete BSI identifier
252
+ # (including Amendment and Corrigendum), so wiring the registry here covers
253
+ # the whole flavor in one shot.
254
+ Pubid::Bsi::SingleIdentifier.format_registry = Pubid::FormatRegistry.new(parent: Pubid::Identifier.format_registry)
255
+ Pubid::Bsi::SingleIdentifier.format_registry.register(:human, renderer: Pubid::Bsi::Renderer)
@@ -5,31 +5,43 @@ module Pubid
5
5
  # Base class for all flavor-specific builders.
6
6
  #
7
7
  # Provides the shared build loop that converts parsed data into identifier
8
- # objects. Flavors subclass and override only `cast` and optionally
9
- # `default_identifier_class`.
8
+ # objects. Flavors subclass and override:
9
+ # - +select_class(data)+ to dispatch by data shape (default returns
10
+ # +default_identifier_class+).
11
+ # - +cast(key, value)+ to transform raw parsed values into components.
12
+ # - +handle_key(identifier, key, value)+ for non-attribute side effects.
10
13
  #
11
14
  # The build loop:
12
15
  # 1. Flattens array-of-hashes input (from Parslet transforms)
13
- # 2. Iterates each key-value pair
14
- # 3. Calls `cast(key, value)` to convert raw values to component objects
15
- # 4. Assigns the result to the identifier via `send`
16
- # 5. Silently skips unknown attributes (rescue NoMethodError)
16
+ # 2. Asks +select_class(data)+ for the identifier class
17
+ # 3. Iterates each key-value pair
18
+ # 4. Calls +cast(key, value)+ to convert raw values to component objects
19
+ # 5. Assigns the result to the identifier via setter
20
+ # 6. Silently skips unknown attributes
17
21
  class Base
18
22
  attr_reader :identifier
19
23
 
20
- def initialize(identifier_class = default_identifier_class)
24
+ def initialize(identifier_class = nil)
21
25
  @identifier_class = identifier_class
22
26
  end
23
27
 
24
28
  def build(data)
25
29
  data = flatten_array(data) if data.is_a?(Array)
26
- identifier = @identifier_class.new
30
+ identifier_class = @identifier_class || select_class(data)
31
+ identifier = identifier_class.new
27
32
  assign_attributes(identifier, data)
28
33
  identifier
29
34
  end
30
35
 
31
36
  private
32
37
 
38
+ # Override in subclasses to dispatch to a specific identifier class
39
+ # based on the shape of the parsed data (type code, supplement marker,
40
+ # etc.). Defaults to +default_identifier_class+.
41
+ def select_class(_data)
42
+ default_identifier_class
43
+ end
44
+
33
45
  # Override in subclasses to convert raw parsed values to component objects.
34
46
  # Return a Hash to assign multiple attributes, or a single value.
35
47
  # Return nil to skip the assignment.
@@ -87,8 +99,9 @@ module Pubid
87
99
  }.freeze
88
100
 
89
101
  def locate_typed_stage(typed_stage_string)
90
- typed_stage_string = "" if typed_stage_string.nil?
91
- @scheme.locate_typed_stage_by_abbr(typed_stage_string)
102
+ raise NotImplementedError,
103
+ "#{self.class} must implement locate_typed_stage " \
104
+ "(rely on the flavor module's locate_stage method)"
92
105
  end
93
106
 
94
107
  def convert_roman_to_integer(roman_numeral)
@@ -122,6 +135,40 @@ module Pubid
122
135
  end
123
136
  end
124
137
 
138
+ # Splits a compound document number ("1234", "1234-1", "1234-1-2")
139
+ # into number/part/subpart Code components. Flavor-specific dash/slash
140
+ # normalization lives in +normalize_number_with_part+; legacy year
141
+ # extraction (e.g. ISO "4037-1979") lives in +extract_legacy_year+.
142
+ def parse_number_with_part(value, code_class:)
143
+ normalized = normalize_number_with_part(value)
144
+ parts = normalized.split("-").reject(&:empty?)
145
+ number = parts.shift
146
+ part = parts.shift&.strip
147
+ subpart = parts.any? ? parts.join("-") : nil
148
+
149
+ legacy = extract_legacy_year(number, part, code_class)
150
+ return legacy if legacy
151
+
152
+ part = convert_roman_to_integer(part) if part
153
+
154
+ code_hash = { number: code_class.new(value: number) }
155
+ code_hash[:part] = code_class.new(value: part) if part
156
+ code_hash[:subpart] = code_class.new(value: subpart) if subpart
157
+ code_hash
158
+ end
159
+
160
+ # Hook: normalize the raw number_with_part string before splitting.
161
+ # Override in subclasses for flavor-specific dash/slash/space handling.
162
+ def normalize_number_with_part(value)
163
+ value.to_s
164
+ end
165
+
166
+ # Hook: detect a year masquerading as a part (e.g. "4037-1979") and
167
+ # return a number+date hash, or nil to continue normal splitting.
168
+ def extract_legacy_year(_number, _part, _code_class)
169
+ nil
170
+ end
171
+
125
172
  def parse_languages(value)
126
173
  original_value = value.to_s
127
174
  normalized_value = original_value.gsub("/", ",")
@@ -1,4 +1,3 @@
1
- require_relative "identifier"
2
1
  # frozen_string_literal: true
3
2
 
4
3
  module Pubid
@@ -34,20 +34,21 @@ module Pubid
34
34
  # Extract corrigenda numbers
35
35
  corr_array = data[:corrigenda]
36
36
  corr_array = [corr_array] unless corr_array.is_a?(Array)
37
- corr_numbers = corr_array.map { |c| c[:cor_number].to_i }
37
+ corr_numbers = corr_array.map { |c| c[:cor_number].to_s }
38
38
 
39
39
  # Build base identifier (without corrigenda)
40
40
  base_data = data.dup
41
41
  base_data.delete(:corrigenda)
42
42
  base = build_base(base_data)
43
43
 
44
- # Build Corrigendum object for each corrigendum number
44
+ # Build Corrigendum object for each corrigendum number. The corrigendum
45
+ # sequence is stored in the inherited `number` attribute (mirroring ISO).
45
46
  # Note: CCSDS uses "Cor. 1" format (single corrigendum per identifier)
46
47
  # If multiple corrigenda exist, we build the last one wrapping the base
47
48
  corr_numbers.reduce(base) do |current_base, cor_num|
48
49
  Identifiers::Corrigendum.new(
49
50
  base_identifier: current_base,
50
- cor_number: cor_num,
51
+ number: cor_num,
51
52
  )
52
53
  end
53
54
  end
@@ -2,7 +2,57 @@
2
2
 
3
3
  module Pubid
4
4
  module Ccsds
5
- module Identifier
5
+ # Abstract root for every CCSDS identifier AND the flavor's parse entry
6
+ # point — mirrors Pubid::Iso::Identifier / Pubid::Jis::Identifier. Concrete
7
+ # identifiers (Identifiers::Base, Identifiers::Corrigendum) descend from this
8
+ # class, so a parsed CCSDS id is an instance of Pubid::Ccsds::Identifier and
9
+ # relaton-index can pass this class as `pubid_class` for from_hash/to_hash.
10
+ #
11
+ # Keeping the root abstract (it is never itself a serialized type, so it is
12
+ # absent from CCSDS_TYPE_MAP) is what breaks the polymorphic recursion a
13
+ # supplement's `base_identifier` would otherwise hit if it pointed at a
14
+ # concrete type that is also its own superclass.
15
+ class Identifier < ::Pubid::Identifier
16
+ # CCSDS stores every code component as a plain string (the Builder passes
17
+ # strings, never Components::Code/Edition objects), so override the
18
+ # inherited Components::Code/Edition attribute types with :string. This
19
+ # both matches the runtime values and yields a lean, round-trippable
20
+ # key_value (`to_hash`) serialization instead of nested component hashes.
21
+ # `type` (single book-color letter B/G/M/R/Y/O), `suffix`, and `language`
22
+ # are likewise CCSDS-specific plain strings.
23
+ attribute :number, :string
24
+ attribute :part, :string
25
+ attribute :edition, :string
26
+ attribute :type, :string
27
+ attribute :suffix, :string
28
+ attribute :language, :string
29
+
30
+ # Polymorphic type map for lutaml::Model key_value (de)serialization,
31
+ # mapping each concrete class's polymorphic_name to its class name.
32
+ CCSDS_TYPE_MAP = {
33
+ "pubid:ccsds:base" => "Pubid::Ccsds::Identifiers::Base",
34
+ "pubid:ccsds:corrigendum" => "Pubid::Ccsds::Identifiers::Corrigendum",
35
+ }.freeze
36
+
37
+ # The shared Pubid::Identifier no longer auto-maps attributes, so the
38
+ # flavor's root declares the full key_value mapping; subclasses
39
+ # (SupplementIdentifier/Corrigendum) merge their own blocks on top. Every
40
+ # value is a plain string, so a direct `to:` map round-trips.
41
+ key_value do
42
+ map "_type", to: :_type, polymorphic_map: CCSDS_TYPE_MAP
43
+ map "number", to: :number
44
+ map "part", to: :part
45
+ map "edition", to: :edition
46
+ map "type", to: :type
47
+ map "suffix", to: :suffix
48
+ map "language", to: :language
49
+ end
50
+
51
+ def publisher
52
+ "CCSDS"
53
+ end
54
+
55
+ # Parse a CCSDS identifier string into the appropriate identifier object.
6
56
  def self.parse(identifier)
7
57
  # Apply legacy update_codes normalization first
8
58
  normalized = Core::UpdateCodes.apply(identifier, :ccsds)
@@ -11,6 +61,21 @@ module Pubid
11
61
  rescue Parslet::ParseFailed => e
12
62
  raise "Failed to parse CCSDS identifier '#{identifier}': #{e.message}"
13
63
  end
64
+
65
+ # Dispatch deserialization to the concrete class named by the stored
66
+ # `_type`, so `from_hash` rebuilds a Corrigendum rather than a bare root
67
+ # (lutaml resolves `_type` only for validation, not instantiation).
68
+ # Mirrors Pubid::Jis::Identifier.from_hash. The `klass == self` guard lets
69
+ # the matched subclass fall through to lutaml's inherited from_hash.
70
+ def self.from_hash(data, options = {})
71
+ type = data["_type"] || data[:_type]
72
+ klass_name = CCSDS_TYPE_MAP[type]
73
+ if klass_name
74
+ klass = Object.const_get(klass_name)
75
+ return klass.from_hash(data, options) unless klass == self
76
+ end
77
+ super
78
+ end
14
79
  end
15
80
  end
16
81
  end