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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +25 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +4 -55
  6. data/lib/pubid/amca/identifiers/base.rb +58 -47
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -21
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -17
  9. data/lib/pubid/amca/identifiers/standard.rb +0 -4
  10. data/lib/pubid/amca/renderer.rb +82 -0
  11. data/lib/pubid/amca/single_identifier.rb +0 -23
  12. data/lib/pubid/amca/urn_generator.rb +2 -1
  13. data/lib/pubid/amca/urn_parser.rb +28 -0
  14. data/lib/pubid/amca.rb +42 -1
  15. data/lib/pubid/ansi/builder.rb +5 -3
  16. data/lib/pubid/ansi/identifier.rb +1 -43
  17. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  18. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  19. data/lib/pubid/ansi/renderer.rb +53 -0
  20. data/lib/pubid/ansi/single_identifier.rb +2 -31
  21. data/lib/pubid/ansi/urn_generator.rb +3 -38
  22. data/lib/pubid/ansi/urn_parser.rb +23 -0
  23. data/lib/pubid/ansi.rb +38 -3
  24. data/lib/pubid/api/builder.rb +33 -74
  25. data/lib/pubid/api/identifier.rb +5 -52
  26. data/lib/pubid/api/identifiers/base.rb +2 -14
  27. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  28. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  29. data/lib/pubid/api/identifiers/mpms.rb +0 -20
  30. data/lib/pubid/api/identifiers/publication.rb +0 -2
  31. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  32. data/lib/pubid/api/identifiers/specification.rb +0 -2
  33. data/lib/pubid/api/identifiers/standard.rb +0 -2
  34. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  35. data/lib/pubid/api/identifiers/typeless_standard.rb +0 -16
  36. data/lib/pubid/api/identifiers.rb +18 -0
  37. data/lib/pubid/api/renderer.rb +89 -0
  38. data/lib/pubid/api/single_identifier.rb +5 -20
  39. data/lib/pubid/api/urn_generator.rb +0 -18
  40. data/lib/pubid/api/urn_parser.rb +35 -0
  41. data/lib/pubid/api.rb +51 -5
  42. data/lib/pubid/ashrae/builder.rb +3 -3
  43. data/lib/pubid/ashrae/identifier.rb +7 -55
  44. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  45. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  46. data/lib/pubid/ashrae/identifiers/base.rb +29 -15
  47. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  48. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  49. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  50. data/lib/pubid/ashrae/parser.rb +4 -0
  51. data/lib/pubid/ashrae/renderer.rb +117 -0
  52. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  53. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  54. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  55. data/lib/pubid/ashrae.rb +46 -1
  56. data/lib/pubid/asme/components/code.rb +10 -2
  57. data/lib/pubid/asme/identifier.rb +0 -46
  58. data/lib/pubid/asme/identifiers/base.rb +0 -60
  59. data/lib/pubid/asme/renderer.rb +66 -0
  60. data/lib/pubid/asme/single_identifier.rb +3 -1
  61. data/lib/pubid/asme/urn_parser.rb +31 -0
  62. data/lib/pubid/asme.rb +42 -1
  63. data/lib/pubid/astm/components/code.rb +9 -0
  64. data/lib/pubid/{jis → astm}/components.rb +1 -1
  65. data/lib/pubid/astm/identifier.rb +0 -77
  66. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  67. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  68. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  69. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  70. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  71. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  72. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  73. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  74. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  75. data/lib/pubid/astm/identifiers.rb +18 -0
  76. data/lib/pubid/astm/renderer.rb +172 -0
  77. data/lib/pubid/astm/single_identifier.rb +3 -11
  78. data/lib/pubid/astm/urn_parser.rb +30 -0
  79. data/lib/pubid/astm.rb +39 -27
  80. data/lib/pubid/bsi/builder.rb +21 -12
  81. data/lib/pubid/bsi/identifier.rb +5 -85
  82. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -36
  83. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +8 -48
  84. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +8 -39
  85. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +2 -55
  86. data/lib/pubid/bsi/identifiers/amendment.rb +2 -22
  87. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -6
  88. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  89. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -87
  90. data/lib/pubid/bsi/identifiers/committee_document.rb +0 -16
  91. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -87
  92. data/lib/pubid/bsi/identifiers/corrigendum.rb +2 -10
  93. data/lib/pubid/bsi/identifiers/detailed_specification.rb +0 -36
  94. data/lib/pubid/bsi/identifiers/disc.rb +0 -29
  95. data/lib/pubid/bsi/identifiers/draft_document.rb +2 -46
  96. data/lib/pubid/bsi/identifiers/electronic_book.rb +2 -38
  97. data/lib/pubid/bsi/identifiers/expert_commentary.rb +2 -18
  98. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +0 -47
  99. data/lib/pubid/bsi/identifiers/flex.rb +0 -35
  100. data/lib/pubid/bsi/identifiers/handbook.rb +1 -15
  101. data/lib/pubid/bsi/identifiers/index.rb +0 -32
  102. data/lib/pubid/bsi/identifiers/method.rb +0 -41
  103. data/lib/pubid/bsi/identifiers/national_annex.rb +4 -29
  104. data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -6
  105. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +2 -54
  106. data/lib/pubid/bsi/identifiers/published_document.rb +2 -54
  107. data/lib/pubid/bsi/identifiers/section.rb +0 -30
  108. data/lib/pubid/bsi/identifiers/set.rb +3 -20
  109. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +0 -9
  110. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -24
  111. data/lib/pubid/bsi/identifiers/supplementary_index.rb +0 -46
  112. data/lib/pubid/bsi/identifiers/technical_specification.rb +2 -47
  113. data/lib/pubid/bsi/identifiers/test_method.rb +0 -32
  114. data/lib/pubid/bsi/identifiers/value_added_publication.rb +2 -17
  115. data/lib/pubid/bsi/identifiers.rb +0 -1
  116. data/lib/pubid/bsi/renderer.rb +1050 -0
  117. data/lib/pubid/bsi/single_identifier.rb +33 -78
  118. data/lib/pubid/bsi/urn_generator.rb +2 -3
  119. data/lib/pubid/bsi/urn_parser.rb +52 -0
  120. data/lib/pubid/bsi.rb +232 -2
  121. data/lib/pubid/builder/base.rb +57 -10
  122. data/lib/pubid/bundled_identifier.rb +0 -1
  123. data/lib/pubid/ccsds/builder.rb +4 -3
  124. data/lib/pubid/ccsds/identifier.rb +53 -68
  125. data/lib/pubid/ccsds/identifiers/base.rb +11 -61
  126. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  127. data/lib/pubid/ccsds/parser.rb +4 -2
  128. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  129. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  130. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  131. data/lib/pubid/ccsds.rb +39 -1
  132. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  133. data/lib/pubid/cen_cenelec/identifier.rb +11 -40
  134. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +9 -4
  135. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +0 -10
  136. data/lib/pubid/cen_cenelec/identifiers/base.rb +2 -45
  137. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  138. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +0 -27
  140. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +0 -15
  141. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +2 -8
  143. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  144. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +0 -4
  145. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  146. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  147. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  148. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  149. data/lib/pubid/cen_cenelec/single_identifier.rb +9 -90
  150. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  151. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  152. data/lib/pubid/cen_cenelec.rb +172 -1
  153. data/lib/pubid/cie/components/code.rb +8 -0
  154. data/lib/pubid/cie/identifier.rb +10 -57
  155. data/lib/pubid/cie/single_identifier.rb +4 -4
  156. data/lib/pubid/cie/urn_parser.rb +28 -0
  157. data/lib/pubid/cie.rb +47 -1
  158. data/lib/pubid/components/adoption.rb +104 -0
  159. data/lib/pubid/components/code.rb +22 -8
  160. data/lib/pubid/components/date.rb +23 -16
  161. data/lib/pubid/components/edition.rb +9 -6
  162. data/lib/pubid/components/iteration.rb +32 -0
  163. data/lib/pubid/components/language.rb +6 -4
  164. data/lib/pubid/components/locality.rb +10 -1
  165. data/lib/pubid/components/publisher.rb +9 -6
  166. data/lib/pubid/components/relationship.rb +151 -0
  167. data/lib/pubid/components/stage.rb +5 -14
  168. data/lib/pubid/components/supplement.rb +184 -0
  169. data/lib/pubid/components/type.rb +5 -15
  170. data/lib/pubid/components/typed_stage.rb +10 -11
  171. data/lib/pubid/components.rb +4 -1
  172. data/lib/pubid/core/update_codes.rb +28 -7
  173. data/lib/pubid/csa/identifier.rb +9 -59
  174. data/lib/pubid/csa/identifiers/base.rb +0 -123
  175. data/lib/pubid/csa/identifiers/cec.rb +0 -103
  176. data/lib/pubid/csa/identifiers/series.rb +0 -104
  177. data/lib/pubid/csa/renderer.rb +292 -0
  178. data/lib/pubid/csa/single_identifier.rb +1 -1
  179. data/lib/pubid/csa/urn_generator.rb +1 -1
  180. data/lib/pubid/csa/urn_parser.rb +33 -0
  181. data/lib/pubid/csa.rb +46 -1
  182. data/lib/pubid/etsi/components/code.rb +10 -9
  183. data/lib/pubid/etsi/components/version.rb +0 -5
  184. data/lib/pubid/etsi/identifier.rb +4 -55
  185. data/lib/pubid/etsi/identifiers/base.rb +31 -27
  186. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +1 -11
  187. data/lib/pubid/etsi/renderer.rb +42 -0
  188. data/lib/pubid/etsi/urn_parser.rb +34 -0
  189. data/lib/pubid/etsi.rb +44 -1
  190. data/lib/pubid/export/exporter.rb +4 -46
  191. data/lib/pubid/export/flavor_exporter.rb +111 -278
  192. data/lib/pubid/export.rb +0 -6
  193. data/lib/pubid/identifier.rb +92 -18
  194. data/lib/pubid/identifier_metadata.rb +1 -1
  195. data/lib/pubid/idf/builder.rb +3 -3
  196. data/lib/pubid/idf/identifier.rb +7 -66
  197. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  198. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  199. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  200. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  201. data/lib/pubid/idf/parser.rb +3 -2
  202. data/lib/pubid/idf/renderer.rb +84 -0
  203. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  204. data/lib/pubid/idf/urn_generator.rb +4 -39
  205. data/lib/pubid/idf/urn_parser.rb +25 -0
  206. data/lib/pubid/idf.rb +55 -1
  207. data/lib/pubid/iec/builder.rb +46 -64
  208. data/lib/pubid/iec/components/code.rb +8 -32
  209. data/lib/pubid/iec/components/publisher.rb +0 -1
  210. data/lib/pubid/iec/components.rb +14 -0
  211. data/lib/pubid/iec/identifier.rb +251 -213
  212. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  213. data/lib/pubid/iec/identifiers/base.rb +5 -33
  214. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  215. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  216. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +23 -26
  217. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  218. data/lib/pubid/iec/identifiers/fragment_identifier.rb +35 -24
  219. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  220. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  221. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  222. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  223. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  224. data/lib/pubid/iec/identifiers/sheet_identifier.rb +17 -11
  225. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  226. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  227. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  228. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  229. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  230. data/lib/pubid/iec/identifiers/test_report_form.rb +3 -35
  231. data/lib/pubid/iec/identifiers/vap_identifier.rb +24 -21
  232. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  233. data/lib/pubid/iec/identifiers/working_document.rb +2 -50
  234. data/lib/pubid/iec/identifiers.rb +30 -0
  235. data/lib/pubid/iec/parser.rb +13 -12
  236. data/lib/pubid/iec/renderer.rb +254 -0
  237. data/lib/pubid/iec/single_identifier.rb +6 -12
  238. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  239. data/lib/pubid/iec/urn_generator.rb +3 -3
  240. data/lib/pubid/iec/urn_parser.rb +3 -3
  241. data/lib/pubid/iec.rb +43 -67
  242. data/lib/pubid/ieee/builder.rb +12 -12
  243. data/lib/pubid/ieee/components/code.rb +8 -0
  244. data/lib/pubid/ieee/components/draft.rb +14 -0
  245. data/lib/pubid/ieee/components/relationship.rb +5 -149
  246. data/lib/pubid/ieee/identifier.rb +5 -52
  247. data/lib/pubid/ieee/identifiers/adopted_standard.rb +0 -9
  248. data/lib/pubid/ieee/identifiers/base.rb +221 -556
  249. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +0 -10
  250. data/lib/pubid/ieee/identifiers/corrigendum.rb +0 -12
  251. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +0 -10
  252. data/lib/pubid/ieee/identifiers/dual_identifier.rb +0 -4
  253. data/lib/pubid/ieee/identifiers/dual_published.rb +0 -4
  254. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +0 -9
  255. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +0 -10
  256. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  257. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +0 -18
  258. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +0 -6
  259. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  260. data/lib/pubid/ieee/identifiers/redlined_standard.rb +0 -7
  261. data/lib/pubid/ieee/identifiers/si_standard.rb +0 -38
  262. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  263. data/lib/pubid/ieee/pre_parser.rb +301 -0
  264. data/lib/pubid/ieee/renderer.rb +307 -0
  265. data/lib/pubid/ieee/urn_parser.rb +34 -0
  266. data/lib/pubid/ieee.rb +66 -1
  267. data/lib/pubid/ieee_debug.rb +0 -1
  268. data/lib/pubid/iho/builder.rb +2 -2
  269. data/lib/pubid/iho/identifier.rb +7 -59
  270. data/lib/pubid/iho/identifiers/base.rb +64 -31
  271. data/lib/pubid/iho/parser.rb +3 -3
  272. data/lib/pubid/iho/renderer.rb +30 -0
  273. data/lib/pubid/iho/urn_generator.rb +2 -2
  274. data/lib/pubid/iho/urn_parser.rb +58 -0
  275. data/lib/pubid/iho.rb +52 -1
  276. data/lib/pubid/iso/builder.rb +55 -53
  277. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  278. data/lib/pubid/iso/components/code.rb +7 -19
  279. data/lib/pubid/iso/components/publisher.rb +10 -8
  280. data/lib/pubid/iso/components.rb +2 -4
  281. data/lib/pubid/iso/identifier.rb +219 -252
  282. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  283. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  284. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  285. data/lib/pubid/iso/identifiers/data.rb +0 -1
  286. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  287. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  288. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  289. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  290. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  291. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  292. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  293. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  294. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  295. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  296. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  297. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  298. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  299. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  300. data/lib/pubid/iso/identifiers.rb +0 -1
  301. data/lib/pubid/iso/normalizer.rb +89 -0
  302. data/lib/pubid/iso/parser.rb +22 -4
  303. data/lib/pubid/iso/single_identifier.rb +0 -4
  304. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  305. data/lib/pubid/iso/urn_generator.rb +66 -182
  306. data/lib/pubid/iso/urn_parser.rb +12 -7
  307. data/lib/pubid/iso.rb +177 -2
  308. data/lib/pubid/itu/builder.rb +0 -12
  309. data/lib/pubid/itu/components/code.rb +9 -7
  310. data/lib/pubid/itu/components/sector.rb +15 -4
  311. data/lib/pubid/itu/components/series.rb +0 -4
  312. data/lib/pubid/itu/components.rb +11 -0
  313. data/lib/pubid/itu/identifier.rb +4 -116
  314. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  315. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  316. data/lib/pubid/itu/identifiers/base.rb +124 -128
  317. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  318. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  319. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  320. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  321. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  322. data/lib/pubid/itu/urn_parser.rb +23 -0
  323. data/lib/pubid/itu.rb +44 -1
  324. data/lib/pubid/jcgm/builder.rb +16 -8
  325. data/lib/pubid/jcgm/identifier.rb +0 -43
  326. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -9
  327. data/lib/pubid/jcgm/identifiers/gum_guide.rb +0 -12
  328. data/lib/pubid/jcgm/renderer.rb +68 -0
  329. data/lib/pubid/jcgm/single_identifier.rb +0 -8
  330. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  331. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  332. data/lib/pubid/jcgm.rb +43 -2
  333. data/lib/pubid/jis/builder.rb +44 -52
  334. data/lib/pubid/jis/identifier.rb +120 -46
  335. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  336. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  337. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  338. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  339. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  340. data/lib/pubid/jis/identifiers.rb +1 -1
  341. data/lib/pubid/jis/parser.rb +31 -5
  342. data/lib/pubid/jis/renderer.rb +69 -0
  343. data/lib/pubid/jis/single_identifier.rb +6 -12
  344. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  345. data/lib/pubid/jis/urn_parser.rb +23 -0
  346. data/lib/pubid/jis.rb +42 -2
  347. data/lib/pubid/nist/builder.rb +63 -1871
  348. data/lib/pubid/nist/caster.rb +1272 -0
  349. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  350. data/lib/pubid/nist/components/code.rb +9 -20
  351. data/lib/pubid/nist/components/supplement.rb +2 -2
  352. data/lib/pubid/nist/components.rb +0 -1
  353. data/lib/pubid/nist/identifier.rb +8 -60
  354. data/lib/pubid/nist/identifiers/base.rb +564 -492
  355. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  356. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -1
  357. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  358. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  359. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  360. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -8
  361. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  362. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +15 -24
  363. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  364. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  365. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  366. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  367. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  368. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  369. data/lib/pubid/nist/identifiers/report.rb +4 -2
  370. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  371. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  372. data/lib/pubid/nist/identifiers.rb +1 -0
  373. data/lib/pubid/nist/parser.rb +62 -452
  374. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  375. data/lib/pubid/nist/preprocessor.rb +428 -0
  376. data/lib/pubid/nist/renderer.rb +43 -0
  377. data/lib/pubid/nist/router.rb +148 -0
  378. data/lib/pubid/nist/series/base.rb +58 -0
  379. data/lib/pubid/nist/series/crpl.rb +13 -0
  380. data/lib/pubid/nist/series/fips.rb +14 -0
  381. data/lib/pubid/nist/series/ir.rb +60 -0
  382. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  383. data/lib/pubid/nist/series/mono.rb +19 -0
  384. data/lib/pubid/nist/series/ncstar.rb +20 -0
  385. data/lib/pubid/nist/series.rb +49 -0
  386. data/lib/pubid/nist/supplement_identifier.rb +3 -1
  387. data/lib/pubid/nist/urn_parser.rb +67 -0
  388. data/lib/pubid/nist.rb +86 -4
  389. data/lib/pubid/oiml/builder.rb +21 -3
  390. data/lib/pubid/oiml/components/code.rb +17 -0
  391. data/lib/pubid/oiml/identifier.rb +40 -46
  392. data/lib/pubid/oiml/identifiers/annex.rb +13 -46
  393. data/lib/pubid/oiml/identifiers/errata.rb +15 -0
  394. data/lib/pubid/oiml/identifiers.rb +1 -1
  395. data/lib/pubid/oiml/parser.rb +59 -12
  396. data/lib/pubid/oiml/renderer.rb +171 -0
  397. data/lib/pubid/oiml/single_identifier.rb +61 -42
  398. data/lib/pubid/oiml/supplement_identifier.rb +31 -17
  399. data/lib/pubid/oiml/urn_generator.rb +0 -8
  400. data/lib/pubid/oiml/urn_parser.rb +22 -0
  401. data/lib/pubid/oiml.rb +42 -1
  402. data/lib/pubid/plateau/identifier.rb +4 -55
  403. data/lib/pubid/plateau/identifiers/base.rb +45 -36
  404. data/lib/pubid/plateau/identifiers/handbook.rb +0 -6
  405. data/lib/pubid/plateau/identifiers/technical_report.rb +0 -4
  406. data/lib/pubid/plateau/renderer.rb +51 -0
  407. data/lib/pubid/plateau/supplement_identifier.rb +0 -4
  408. data/lib/pubid/plateau/urn_parser.rb +43 -0
  409. data/lib/pubid/plateau.rb +43 -1
  410. data/lib/pubid/renderers/directives_renderer.rb +22 -8
  411. data/lib/pubid/renderers/guide_renderer.rb +4 -2
  412. data/lib/pubid/renderers/human_readable.rb +18 -7
  413. data/lib/pubid/rendering/context.rb +28 -19
  414. data/lib/pubid/rendering.rb +0 -3
  415. data/lib/pubid/sae/components/date.rb +8 -0
  416. data/lib/pubid/sae/components/type.rb +5 -1
  417. data/lib/pubid/sae/identifier.rb +4 -35
  418. data/lib/pubid/sae/identifiers/base.rb +26 -31
  419. data/lib/pubid/sae/renderer.rb +36 -0
  420. data/lib/pubid/sae/urn_generator.rb +2 -10
  421. data/lib/pubid/sae/urn_parser.rb +36 -0
  422. data/lib/pubid/sae.rb +42 -1
  423. data/lib/pubid/urn_generator/base.rb +12 -12
  424. data/lib/pubid/urn_parser/base.rb +81 -0
  425. data/lib/pubid/urn_parser/errors.rb +9 -0
  426. data/lib/pubid/urn_parser.rb +14 -0
  427. data/lib/pubid/version.rb +1 -1
  428. data/lib/pubid.rb +45 -7
  429. data/lib/tasks/export.rake +6 -5
  430. data/lib/tasks/website-data.json +1940 -1882
  431. metadata +75 -45
  432. data/lib/pubid/amca/scheme.rb +0 -16
  433. data/lib/pubid/ansi/scheme.rb +0 -15
  434. data/lib/pubid/api/scheme.rb +0 -66
  435. data/lib/pubid/ashrae/scheme.rb +0 -53
  436. data/lib/pubid/asme/scheme.rb +0 -37
  437. data/lib/pubid/astm/scheme.rb +0 -55
  438. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  439. data/lib/pubid/bsi/scheme.rb +0 -243
  440. data/lib/pubid/ccsds/scheme.rb +0 -57
  441. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  442. data/lib/pubid/cie/scheme.rb +0 -64
  443. data/lib/pubid/components/factory.rb +0 -50
  444. data/lib/pubid/csa/scheme.rb +0 -44
  445. data/lib/pubid/etsi/scheme.rb +0 -42
  446. data/lib/pubid/export/data_class_exporter.rb +0 -59
  447. data/lib/pubid/export/ieee_exporter.rb +0 -78
  448. data/lib/pubid/export/itu_exporter.rb +0 -66
  449. data/lib/pubid/export/nist_exporter.rb +0 -64
  450. data/lib/pubid/export/registry_exporter.rb +0 -90
  451. data/lib/pubid/export/scheme_exporter.rb +0 -70
  452. data/lib/pubid/identifier_registry.rb +0 -198
  453. data/lib/pubid/idf/scheme.rb +0 -61
  454. data/lib/pubid/iec/scheme.rb +0 -71
  455. data/lib/pubid/ieee/scheme.rb +0 -90
  456. data/lib/pubid/iho/scheme.rb +0 -29
  457. data/lib/pubid/iso/identifiers/base.rb +0 -115
  458. data/lib/pubid/iso/scheme.rb +0 -193
  459. data/lib/pubid/itu/scheme.rb +0 -174
  460. data/lib/pubid/jcgm/scheme.rb +0 -60
  461. data/lib/pubid/jis/components/code.rb +0 -59
  462. data/lib/pubid/jis/identifiers/base.rb +0 -72
  463. data/lib/pubid/jis/scheme.rb +0 -49
  464. data/lib/pubid/nist/components/publisher.rb +0 -24
  465. data/lib/pubid/nist/scheme.rb +0 -199
  466. data/lib/pubid/oiml/identifiers/base.rb +0 -36
  467. data/lib/pubid/oiml/scheme.rb +0 -46
  468. data/lib/pubid/plateau/scheme.rb +0 -45
  469. data/lib/pubid/rendering/base.rb +0 -73
  470. data/lib/pubid/rendering/common.rb +0 -211
  471. data/lib/pubid/rendering/format.rb +0 -25
  472. data/lib/pubid/sae/scheme.rb +0 -47
  473. data/lib/pubid/scheme.rb +0 -219
@@ -2,10 +2,34 @@
2
2
 
3
3
  module Pubid
4
4
  module Bsi
5
- class SingleIdentifier < Pubid::Identifier
6
- # Generate URN for this identifier
7
- #
8
- # @return [String] URN representation
5
+ # BSI base class. Canonical name Pubid::Bsi::Identifier; SingleIdentifier is a
6
+ # back-compat alias (BSI's common ancestor — there is no Identifiers::Base).
7
+ # Every concrete BSI identifier descends from it, so they are all
8
+ # `is_a?(Pubid::Bsi::Identifier)` natively and get the shared polymorphic
9
+ # `from_hash` (no facade needed).
10
+ class Identifier < ::Pubid::Identifier
11
+ def self.parse(string)
12
+ if string.length > Pubid::MAX_INPUT_LENGTH
13
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
14
+ end
15
+
16
+ # Delegate to IEC for bare IEC identifiers. This handles IEC-specific
17
+ # features like VAP suffixes (CSV, RLV, etc.) and consolidated
18
+ # supplements (+AMD1:2001).
19
+ if string.match?(/\bIEC\b/) &&
20
+ (string.match?(/\s+(CSV|CMV|RLV|SER|EXV|PAC|PRV)\b/) ||
21
+ string.match?(/\+AMD\d+:/) ||
22
+ string.match?(/\+COR\d+:/))
23
+ return Pubid::Iec.parse(string)
24
+ end
25
+
26
+ parser = Parser.new
27
+
28
+ parsed = parser.parse(string)
29
+ Builder.build(parsed)
30
+ rescue Parslet::ParseFailed => e
31
+ raise StandardError, "Failed to parse '#{string}': #{e.message}"
32
+ end
9
33
 
10
34
  attribute :publisher, Bsi::Components::Publisher, default: -> {
11
35
  Bsi::Components::Publisher.new(body: "BS")
@@ -29,81 +53,8 @@ module Pubid
29
53
  attribute :explicit_publisher, :boolean, default: -> { false }
30
54
  attribute :space_separated_part, :boolean, default: -> { false }
31
55
 
32
- 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
103
- end
104
-
105
56
  def <=>(other)
106
- return nil unless other.is_a?(SingleIdentifier)
57
+ return nil unless other.is_a?(Pubid::Bsi::Identifier)
107
58
 
108
59
  # Compare by number first
109
60
  num_cmp = number.to_s <=> other.number.to_s
@@ -125,5 +76,9 @@ module Pubid
125
76
  end
126
77
  end
127
78
  end
79
+
80
+ # Backward-compatible alias: BSI's base class is Pubid::Bsi::Identifier.
81
+ # Concrete types declared as `< SingleIdentifier` continue to work.
82
+ SingleIdentifier = Identifier
128
83
  end
129
84
  end
@@ -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
@@ -12,21 +12,251 @@ module Pubid
12
12
  autoload :Builder, "#{__dir__}/bsi/builder"
13
13
  autoload :Identifier, "#{__dir__}/bsi/identifier"
14
14
  autoload :Identifiers, "#{__dir__}/bsi/identifiers"
15
- autoload :Model, "#{__dir__}/bsi/model"
15
+ # NOTE: bsi/model.rb is legacy/unused (nothing references Pubid::Bsi::Model)
16
+ # and defines a conflicting `class Identifier < Lutaml::Model::Serializable`.
17
+ # It is intentionally NOT autoloaded so it can never clash with the real
18
+ # Pubid::Bsi::Identifier (single_identifier.rb).
16
19
  autoload :Parser, "#{__dir__}/bsi/parser"
17
- autoload :Scheme, "#{__dir__}/bsi/scheme"
20
+ autoload :Renderer, "#{__dir__}/bsi/renderer"
18
21
  autoload :SingleIdentifier, "#{__dir__}/bsi/single_identifier"
19
22
  autoload :UrnGenerator, "#{__dir__}/bsi/urn_generator"
23
+ autoload :UrnParser, "#{__dir__}/bsi/urn_parser"
24
+
25
+ # TYPED_STAGES_REGISTRY for native BSI types. Used by Pubid::Bsi.locate_stage
26
+ # to map abbreviations (e.g. "BS", "PD", "Handbook") to typed stages.
27
+ TYPED_STAGES_REGISTRY = [
28
+ # British Standard (BS)
29
+ Pubid::Components::TypedStage.new(
30
+ code: :pubbs,
31
+ stage_code: :published,
32
+ type_code: :bs,
33
+ abbr: ["BS"],
34
+ name: "British Standard",
35
+ harmonized_stages: %w[60.00 60.60],
36
+ ),
37
+ Pubid::Components::TypedStage.new(
38
+ code: :drbs,
39
+ stage_code: :draft,
40
+ type_code: :bs,
41
+ abbr: ["Draft BS", "DBS"],
42
+ name: "Draft British Standard",
43
+ harmonized_stages: %w[30.00 30.20 30.60 40.00 40.20 40.60],
44
+ ),
45
+
46
+ # Published Document (PD)
47
+ Pubid::Components::TypedStage.new(
48
+ code: :pubpd,
49
+ stage_code: :published,
50
+ type_code: :pd,
51
+ abbr: ["PD"],
52
+ name: "Published Document",
53
+ harmonized_stages: %w[60.00 60.60],
54
+ ),
55
+
56
+ # Publicly Available Specification (PAS)
57
+ Pubid::Components::TypedStage.new(
58
+ code: :pubpas,
59
+ stage_code: :published,
60
+ type_code: :pas,
61
+ abbr: ["PAS"],
62
+ name: "Publicly Available Specification",
63
+ harmonized_stages: %w[60.00 60.60],
64
+ ),
65
+
66
+ # National Annex (NA)
67
+ Pubid::Components::TypedStage.new(
68
+ code: :pubna,
69
+ stage_code: :published,
70
+ type_code: :na,
71
+ abbr: ["NA"],
72
+ name: "National Annex",
73
+ harmonized_stages: %w[60.00 60.60],
74
+ ),
75
+
76
+ # Draft Document (DD)
77
+ Pubid::Components::TypedStage.new(
78
+ code: :pubdd,
79
+ stage_code: :published,
80
+ type_code: :dd,
81
+ abbr: ["DD"],
82
+ name: "Draft Document",
83
+ harmonized_stages: %w[60.00 60.60],
84
+ ),
85
+
86
+ # Flex Document
87
+ Pubid::Components::TypedStage.new(
88
+ code: :pubflex,
89
+ stage_code: :published,
90
+ type_code: :flex,
91
+ abbr: ["Flex", "BSI Flex"],
92
+ name: "BSI Flex",
93
+ harmonized_stages: %w[60.00 60.60],
94
+ ),
95
+
96
+ # Handbook
97
+ Pubid::Components::TypedStage.new(
98
+ code: :pubhandbook,
99
+ stage_code: :published,
100
+ type_code: :handbook,
101
+ abbr: ["Handbook", "HB"],
102
+ name: "BSI Handbook",
103
+ harmonized_stages: %w[60.00 60.60],
104
+ ),
105
+
106
+ # Practice Guide (PP)
107
+ Pubid::Components::TypedStage.new(
108
+ code: :pubpp,
109
+ stage_code: :published,
110
+ type_code: :pp,
111
+ abbr: ["PP"],
112
+ name: "Published Practice",
113
+ harmonized_stages: %w[60.00 60.60],
114
+ ),
115
+
116
+ # British Industrial Practice (BIP)
117
+ Pubid::Components::TypedStage.new(
118
+ code: :pubbip,
119
+ stage_code: :published,
120
+ type_code: :bip,
121
+ abbr: ["BIP"],
122
+ name: "British Industrial Practice",
123
+ harmonized_stages: %w[60.00 60.60],
124
+ ),
125
+
126
+ # Aerospace/Specialized British Standard (with letter prefix)
127
+ Pubid::Components::TypedStage.new(
128
+ code: :pubaerospace,
129
+ stage_code: :published,
130
+ type_code: :aerospace,
131
+ abbr: ["BS A", "BS AU", "BS C", "BS M", "BS S", "BS L", "BS TA",
132
+ "BS MA", "BS PL", "BS QC", "BS G", "BS HC", "BS F", "BS X", "BS B"],
133
+ name: "Aerospace/Specialized British Standard",
134
+ harmonized_stages: %w[60.00 60.60],
135
+ ),
136
+
137
+ # Index
138
+ Pubid::Components::TypedStage.new(
139
+ code: :pubindex,
140
+ stage_code: :published,
141
+ type_code: :index,
142
+ abbr: ["Index"],
143
+ name: "BSI Index",
144
+ harmonized_stages: %w[60.00 60.60],
145
+ ),
146
+
147
+ # Method
148
+ Pubid::Components::TypedStage.new(
149
+ code: :pubmethod,
150
+ stage_code: :published,
151
+ type_code: :method,
152
+ abbr: ["Method", "Methods"],
153
+ name: "BSI Method",
154
+ harmonized_stages: %w[60.00 60.60],
155
+ ),
156
+
157
+ # Section
158
+ Pubid::Components::TypedStage.new(
159
+ code: :pubsection,
160
+ stage_code: :published,
161
+ type_code: :section,
162
+ abbr: ["Section"],
163
+ name: "BSI Section",
164
+ harmonized_stages: %w[60.00 60.60],
165
+ ),
166
+
167
+ # DISC (Delivering Information Solutions to Customers)
168
+ Pubid::Components::TypedStage.new(
169
+ code: :pubdisc,
170
+ stage_code: :published,
171
+ type_code: :disc,
172
+ abbr: ["DISC"],
173
+ name: "DISC",
174
+ harmonized_stages: %w[60.00 60.60],
175
+ ),
176
+
177
+ # Detailed Specification (with N or C notation)
178
+ Pubid::Components::TypedStage.new(
179
+ code: :pubdetailed_spec,
180
+ stage_code: :published,
181
+ type_code: :detailed_specification,
182
+ abbr: ["DETAILED SPEC"],
183
+ name: "Detailed Specification",
184
+ harmonized_stages: %w[60.00 60.60],
185
+ ),
186
+
187
+ # Standalone Amendment
188
+ Pubid::Components::TypedStage.new(
189
+ code: :standalone_amendment,
190
+ stage_code: :published,
191
+ type_code: :amendment,
192
+ abbr: ["AMD"],
193
+ name: "Amendment",
194
+ harmonized_stages: %w[60.00 60.60],
195
+ ),
196
+
197
+ # Technical Specification
198
+ Pubid::Components::TypedStage.new(
199
+ code: :pubts,
200
+ stage_code: :published,
201
+ type_code: :ts,
202
+ abbr: ["TS"],
203
+ name: "Technical Specification",
204
+ harmonized_stages: %w[60.00 60.60],
205
+ ),
206
+ ].freeze
20
207
 
21
208
  def self.parse(string)
209
+ if string.length > Pubid::MAX_INPUT_LENGTH
210
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
211
+ end
212
+
22
213
  Identifier.parse(string)
23
214
  end
24
215
 
25
216
  def self.transform(data)
26
217
  Builder.build(data)
27
218
  end
219
+
220
+ # Auto-discover all identifier types from the Identifiers namespace.
221
+ # Includes classes with explicit type declarations (Hash or nil).
222
+ # @return [Array<Class>] identifier classes (Pubid::Identifier subclasses)
223
+ def self.identifier_types
224
+ @identifier_types ||= Identifiers.constants
225
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
226
+ .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
227
+ .select { |c| c.singleton_methods(false).include?(:type) }
228
+ .reject { |c| c.name&.split("::")&.last == "Base" }
229
+ end
230
+
231
+ # Build typed stage index from the module's TYPED_STAGES_REGISTRY
232
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
233
+ def self.all_typed_stages
234
+ @all_typed_stages ||= TYPED_STAGES_REGISTRY
235
+ end
236
+
237
+ # Lookup: type code -> identifier class
238
+ # @param code [String, Symbol] the type key to find
239
+ # @return [Class, nil] the matching identifier class
240
+ def self.locate_type(code)
241
+ identifier_types.find { |t| t.type&.dig(:key)&.to_s == code.to_s }
242
+ end
243
+
244
+ # Lookup: abbreviation -> typed stage
245
+ # @param abbr [String, Symbol] the abbreviation to find
246
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
247
+ def self.locate_stage(abbr)
248
+ abbr_str = abbr.to_s.upcase
249
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
250
+ end
28
251
  end
29
252
  end
30
253
 
31
254
  # Register Ubsi flavor with the registry
32
255
  Pubid::Registry.register(:bsi, Pubid::Bsi)
256
+
257
+ # Per-flavor format registry: inherits global formats, overrides :human.
258
+ # SingleIdentifier is the abstract base for every concrete BSI identifier
259
+ # (including Amendment and Corrigendum), so wiring the registry here covers
260
+ # the whole flavor in one shot.
261
+ Pubid::Bsi::SingleIdentifier.format_registry = Pubid::FormatRegistry.new(parent: Pubid::Identifier.format_registry)
262
+ 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