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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (458) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +25 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +7 -39
  6. data/lib/pubid/amca/identifiers/base.rb +0 -26
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -17
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -13
  9. data/lib/pubid/amca/renderer.rb +82 -0
  10. data/lib/pubid/amca/single_identifier.rb +0 -23
  11. data/lib/pubid/amca/urn_parser.rb +28 -0
  12. data/lib/pubid/amca.rb +42 -1
  13. data/lib/pubid/ansi/builder.rb +5 -3
  14. data/lib/pubid/ansi/identifier.rb +1 -43
  15. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  16. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  17. data/lib/pubid/ansi/renderer.rb +53 -0
  18. data/lib/pubid/ansi/single_identifier.rb +2 -31
  19. data/lib/pubid/ansi/urn_generator.rb +3 -38
  20. data/lib/pubid/ansi/urn_parser.rb +23 -0
  21. data/lib/pubid/ansi.rb +38 -3
  22. data/lib/pubid/api/builder.rb +29 -74
  23. data/lib/pubid/api/identifier.rb +0 -51
  24. data/lib/pubid/api/identifiers/base.rb +0 -2
  25. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  26. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  27. data/lib/pubid/api/identifiers/mpms.rb +1 -17
  28. data/lib/pubid/api/identifiers/publication.rb +0 -2
  29. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  30. data/lib/pubid/api/identifiers/specification.rb +0 -2
  31. data/lib/pubid/api/identifiers/standard.rb +0 -2
  32. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  33. data/lib/pubid/api/identifiers/typeless_standard.rb +1 -14
  34. data/lib/pubid/api/identifiers.rb +18 -0
  35. data/lib/pubid/api/renderer.rb +89 -0
  36. data/lib/pubid/api/single_identifier.rb +1 -13
  37. data/lib/pubid/api/urn_generator.rb +0 -18
  38. data/lib/pubid/api/urn_parser.rb +35 -0
  39. data/lib/pubid/api.rb +51 -5
  40. data/lib/pubid/ashrae/builder.rb +3 -3
  41. data/lib/pubid/ashrae/identifier.rb +6 -39
  42. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  43. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  44. data/lib/pubid/ashrae/identifiers/base.rb +3 -0
  45. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  46. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  47. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  48. data/lib/pubid/ashrae/renderer.rb +117 -0
  49. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  50. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  51. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  52. data/lib/pubid/ashrae.rb +42 -1
  53. data/lib/pubid/asme/components/code.rb +10 -2
  54. data/lib/pubid/asme/identifier.rb +0 -46
  55. data/lib/pubid/asme/identifiers/base.rb +0 -60
  56. data/lib/pubid/asme/renderer.rb +66 -0
  57. data/lib/pubid/asme/urn_parser.rb +31 -0
  58. data/lib/pubid/asme.rb +42 -1
  59. data/lib/pubid/astm/components/code.rb +9 -0
  60. data/lib/pubid/{jis → astm}/components.rb +1 -1
  61. data/lib/pubid/astm/identifier.rb +0 -77
  62. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  63. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  64. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  65. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  66. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  67. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  68. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  69. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  70. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  71. data/lib/pubid/astm/identifiers.rb +18 -0
  72. data/lib/pubid/astm/renderer.rb +172 -0
  73. data/lib/pubid/astm/single_identifier.rb +0 -10
  74. data/lib/pubid/astm/urn_parser.rb +30 -0
  75. data/lib/pubid/astm.rb +39 -27
  76. data/lib/pubid/bsi/builder.rb +21 -12
  77. data/lib/pubid/bsi/identifier.rb +8 -62
  78. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  79. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  80. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  81. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  82. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  83. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  84. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  85. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  87. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  88. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  89. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  90. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  91. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  92. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  93. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  94. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  95. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  96. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  97. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  98. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  99. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  100. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  101. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  102. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  103. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  104. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  105. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  106. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  107. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  108. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  109. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  110. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  111. data/lib/pubid/bsi/identifiers.rb +0 -1
  112. data/lib/pubid/bsi/renderer.rb +1050 -0
  113. data/lib/pubid/bsi/single_identifier.rb +6 -70
  114. data/lib/pubid/bsi/urn_generator.rb +2 -3
  115. data/lib/pubid/bsi/urn_parser.rb +52 -0
  116. data/lib/pubid/bsi.rb +224 -1
  117. data/lib/pubid/builder/base.rb +57 -10
  118. data/lib/pubid/bundled_identifier.rb +0 -1
  119. data/lib/pubid/ccsds/builder.rb +4 -3
  120. data/lib/pubid/ccsds/identifier.rb +63 -66
  121. data/lib/pubid/ccsds/identifiers/base.rb +11 -61
  122. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  123. data/lib/pubid/ccsds/parser.rb +4 -2
  124. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  125. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  126. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  127. data/lib/pubid/ccsds.rb +39 -1
  128. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  129. data/lib/pubid/cen_cenelec/identifier.rb +7 -38
  130. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  131. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  132. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  133. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  135. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  136. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  137. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  138. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  139. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  140. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  141. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  143. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  144. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  145. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  146. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  147. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  148. data/lib/pubid/cen_cenelec.rb +168 -1
  149. data/lib/pubid/cie/components/code.rb +8 -0
  150. data/lib/pubid/cie/identifier.rb +6 -57
  151. data/lib/pubid/cie/urn_parser.rb +28 -0
  152. data/lib/pubid/cie.rb +43 -1
  153. data/lib/pubid/components/adoption.rb +104 -0
  154. data/lib/pubid/components/code.rb +22 -8
  155. data/lib/pubid/components/date.rb +23 -16
  156. data/lib/pubid/components/edition.rb +9 -6
  157. data/lib/pubid/components/iteration.rb +32 -0
  158. data/lib/pubid/components/language.rb +6 -4
  159. data/lib/pubid/components/locality.rb +10 -1
  160. data/lib/pubid/components/publisher.rb +9 -6
  161. data/lib/pubid/components/relationship.rb +151 -0
  162. data/lib/pubid/components/stage.rb +5 -14
  163. data/lib/pubid/components/supplement.rb +184 -0
  164. data/lib/pubid/components/type.rb +5 -15
  165. data/lib/pubid/components/typed_stage.rb +10 -11
  166. data/lib/pubid/components.rb +4 -1
  167. data/lib/pubid/core/update_codes.rb +28 -7
  168. data/lib/pubid/csa/identifier.rb +0 -59
  169. data/lib/pubid/csa/identifiers/base.rb +2 -122
  170. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  171. data/lib/pubid/csa/identifiers/series.rb +2 -102
  172. data/lib/pubid/csa/renderer.rb +292 -0
  173. data/lib/pubid/csa/urn_generator.rb +1 -1
  174. data/lib/pubid/csa/urn_parser.rb +33 -0
  175. data/lib/pubid/csa.rb +42 -1
  176. data/lib/pubid/etsi/components/code.rb +9 -2
  177. data/lib/pubid/etsi/identifier.rb +0 -43
  178. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  179. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  180. data/lib/pubid/etsi/renderer.rb +42 -0
  181. data/lib/pubid/etsi/urn_parser.rb +34 -0
  182. data/lib/pubid/etsi.rb +42 -1
  183. data/lib/pubid/export/exporter.rb +4 -46
  184. data/lib/pubid/export/flavor_exporter.rb +111 -278
  185. data/lib/pubid/export.rb +0 -6
  186. data/lib/pubid/identifier.rb +2 -17
  187. data/lib/pubid/identifier_facade.rb +114 -0
  188. data/lib/pubid/identifier_metadata.rb +1 -1
  189. data/lib/pubid/idf/builder.rb +3 -3
  190. data/lib/pubid/idf/identifier.rb +3 -66
  191. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  192. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  193. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  194. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  195. data/lib/pubid/idf/parser.rb +3 -2
  196. data/lib/pubid/idf/renderer.rb +84 -0
  197. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  198. data/lib/pubid/idf/urn_generator.rb +4 -39
  199. data/lib/pubid/idf/urn_parser.rb +25 -0
  200. data/lib/pubid/idf.rb +51 -1
  201. data/lib/pubid/iec/builder.rb +46 -64
  202. data/lib/pubid/iec/components/code.rb +8 -32
  203. data/lib/pubid/iec/components/publisher.rb +0 -1
  204. data/lib/pubid/iec/components.rb +14 -0
  205. data/lib/pubid/iec/identifier.rb +251 -213
  206. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  207. data/lib/pubid/iec/identifiers/base.rb +8 -32
  208. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  209. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  210. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -26
  211. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  212. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -22
  213. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  214. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  215. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  216. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  217. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  218. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -11
  219. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  220. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  222. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  223. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  224. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  225. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -19
  226. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  227. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  228. data/lib/pubid/iec/identifiers.rb +30 -0
  229. data/lib/pubid/iec/parser.rb +13 -12
  230. data/lib/pubid/iec/renderer.rb +254 -0
  231. data/lib/pubid/iec/single_identifier.rb +6 -12
  232. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  233. data/lib/pubid/iec/urn_generator.rb +3 -3
  234. data/lib/pubid/iec/urn_parser.rb +3 -3
  235. data/lib/pubid/iec.rb +40 -68
  236. data/lib/pubid/ieee/builder.rb +12 -12
  237. data/lib/pubid/ieee/components/code.rb +8 -0
  238. data/lib/pubid/ieee/components/draft.rb +14 -0
  239. data/lib/pubid/ieee/components/relationship.rb +5 -149
  240. data/lib/pubid/ieee/identifier.rb +6 -41
  241. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  242. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  243. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  245. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  246. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  247. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  248. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  249. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  250. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  251. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  252. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  253. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  254. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  255. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  256. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  257. data/lib/pubid/ieee/pre_parser.rb +301 -0
  258. data/lib/pubid/ieee/renderer.rb +307 -0
  259. data/lib/pubid/ieee/urn_parser.rb +34 -0
  260. data/lib/pubid/ieee.rb +62 -1
  261. data/lib/pubid/ieee_debug.rb +0 -1
  262. data/lib/pubid/iho/builder.rb +2 -2
  263. data/lib/pubid/iho/identifier.rb +8 -42
  264. data/lib/pubid/iho/identifiers/base.rb +49 -10
  265. data/lib/pubid/iho/parser.rb +3 -3
  266. data/lib/pubid/iho/renderer.rb +30 -0
  267. data/lib/pubid/iho/urn_generator.rb +2 -2
  268. data/lib/pubid/iho/urn_parser.rb +58 -0
  269. data/lib/pubid/iho.rb +50 -1
  270. data/lib/pubid/iso/builder.rb +55 -53
  271. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  272. data/lib/pubid/iso/components/code.rb +7 -19
  273. data/lib/pubid/iso/components/publisher.rb +10 -8
  274. data/lib/pubid/iso/components.rb +2 -4
  275. data/lib/pubid/iso/identifier.rb +218 -252
  276. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  277. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  278. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  279. data/lib/pubid/iso/identifiers/data.rb +0 -1
  280. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  281. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  282. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  283. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  284. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  285. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  286. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  287. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  288. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  289. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  290. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  291. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  292. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  293. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  294. data/lib/pubid/iso/identifiers.rb +0 -1
  295. data/lib/pubid/iso/normalizer.rb +89 -0
  296. data/lib/pubid/iso/parser.rb +22 -4
  297. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  298. data/lib/pubid/iso/urn_generator.rb +66 -182
  299. data/lib/pubid/iso/urn_parser.rb +12 -7
  300. data/lib/pubid/iso.rb +173 -2
  301. data/lib/pubid/itu/builder.rb +0 -12
  302. data/lib/pubid/itu/components/code.rb +8 -0
  303. data/lib/pubid/itu/components.rb +11 -0
  304. data/lib/pubid/itu/identifier.rb +6 -104
  305. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  306. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  307. data/lib/pubid/itu/identifiers/base.rb +0 -6
  308. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  309. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  310. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  311. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  312. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  313. data/lib/pubid/itu/urn_parser.rb +23 -0
  314. data/lib/pubid/itu.rb +42 -1
  315. data/lib/pubid/jcgm/builder.rb +16 -8
  316. data/lib/pubid/jcgm/identifier.rb +0 -43
  317. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  318. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  319. data/lib/pubid/jcgm/renderer.rb +68 -0
  320. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  321. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  322. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  323. data/lib/pubid/jcgm.rb +43 -2
  324. data/lib/pubid/jis/builder.rb +44 -52
  325. data/lib/pubid/jis/identifier.rb +132 -46
  326. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  327. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  328. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  329. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  330. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  331. data/lib/pubid/jis/identifiers.rb +1 -1
  332. data/lib/pubid/jis/parser.rb +31 -5
  333. data/lib/pubid/jis/renderer.rb +69 -0
  334. data/lib/pubid/jis/single_identifier.rb +6 -12
  335. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  336. data/lib/pubid/jis/urn_parser.rb +23 -0
  337. data/lib/pubid/jis.rb +42 -2
  338. data/lib/pubid/nist/builder.rb +63 -1871
  339. data/lib/pubid/nist/caster.rb +1272 -0
  340. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  341. data/lib/pubid/nist/components/code.rb +9 -20
  342. data/lib/pubid/nist/components/supplement.rb +2 -2
  343. data/lib/pubid/nist/components.rb +0 -1
  344. data/lib/pubid/nist/identifier.rb +11 -48
  345. data/lib/pubid/nist/identifiers/base.rb +110 -47
  346. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  347. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -1
  348. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  349. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  350. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  351. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -8
  352. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  353. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +15 -24
  354. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  355. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  356. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  357. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  358. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  359. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  360. data/lib/pubid/nist/identifiers/report.rb +4 -2
  361. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  362. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  363. data/lib/pubid/nist/identifiers.rb +1 -0
  364. data/lib/pubid/nist/parser.rb +62 -452
  365. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  366. data/lib/pubid/nist/preprocessor.rb +416 -0
  367. data/lib/pubid/nist/renderer.rb +43 -0
  368. data/lib/pubid/nist/router.rb +148 -0
  369. data/lib/pubid/nist/series/base.rb +58 -0
  370. data/lib/pubid/nist/series/crpl.rb +13 -0
  371. data/lib/pubid/nist/series/fips.rb +14 -0
  372. data/lib/pubid/nist/series/ir.rb +60 -0
  373. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  374. data/lib/pubid/nist/series/mono.rb +19 -0
  375. data/lib/pubid/nist/series/ncstar.rb +20 -0
  376. data/lib/pubid/nist/series.rb +49 -0
  377. data/lib/pubid/nist/supplement_identifier.rb +3 -1
  378. data/lib/pubid/nist/urn_parser.rb +67 -0
  379. data/lib/pubid/nist.rb +82 -4
  380. data/lib/pubid/oiml/components/code.rb +10 -0
  381. data/lib/pubid/oiml/identifier.rb +0 -50
  382. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  383. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  384. data/lib/pubid/oiml/renderer.rb +161 -0
  385. data/lib/pubid/oiml/single_identifier.rb +6 -45
  386. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  387. data/lib/pubid/oiml/urn_generator.rb +0 -8
  388. data/lib/pubid/oiml/urn_parser.rb +22 -0
  389. data/lib/pubid/oiml.rb +42 -1
  390. data/lib/pubid/plateau/identifier.rb +7 -41
  391. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  392. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  393. data/lib/pubid/plateau/renderer.rb +51 -0
  394. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  395. data/lib/pubid/plateau/urn_parser.rb +43 -0
  396. data/lib/pubid/plateau.rb +43 -1
  397. data/lib/pubid/renderers/directives_renderer.rb +22 -8
  398. data/lib/pubid/renderers/guide_renderer.rb +4 -2
  399. data/lib/pubid/renderers/human_readable.rb +18 -7
  400. data/lib/pubid/rendering/context.rb +28 -19
  401. data/lib/pubid/rendering.rb +0 -3
  402. data/lib/pubid/sae/components/date.rb +8 -0
  403. data/lib/pubid/sae/components/type.rb +5 -1
  404. data/lib/pubid/sae/identifier.rb +0 -23
  405. data/lib/pubid/sae/identifiers/base.rb +2 -16
  406. data/lib/pubid/sae/renderer.rb +36 -0
  407. data/lib/pubid/sae/urn_generator.rb +2 -10
  408. data/lib/pubid/sae/urn_parser.rb +36 -0
  409. data/lib/pubid/sae.rb +42 -1
  410. data/lib/pubid/urn_generator/base.rb +12 -12
  411. data/lib/pubid/urn_parser/base.rb +81 -0
  412. data/lib/pubid/urn_parser/errors.rb +9 -0
  413. data/lib/pubid/urn_parser.rb +14 -0
  414. data/lib/pubid/version.rb +1 -1
  415. data/lib/pubid.rb +29 -7
  416. data/lib/tasks/website-data.json +1940 -1882
  417. metadata +75 -44
  418. data/lib/pubid/amca/scheme.rb +0 -16
  419. data/lib/pubid/ansi/scheme.rb +0 -15
  420. data/lib/pubid/api/scheme.rb +0 -66
  421. data/lib/pubid/ashrae/scheme.rb +0 -53
  422. data/lib/pubid/asme/scheme.rb +0 -37
  423. data/lib/pubid/astm/scheme.rb +0 -55
  424. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  425. data/lib/pubid/bsi/scheme.rb +0 -243
  426. data/lib/pubid/ccsds/scheme.rb +0 -57
  427. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  428. data/lib/pubid/cie/scheme.rb +0 -64
  429. data/lib/pubid/components/factory.rb +0 -50
  430. data/lib/pubid/csa/scheme.rb +0 -44
  431. data/lib/pubid/etsi/scheme.rb +0 -42
  432. data/lib/pubid/export/data_class_exporter.rb +0 -59
  433. data/lib/pubid/export/ieee_exporter.rb +0 -78
  434. data/lib/pubid/export/itu_exporter.rb +0 -66
  435. data/lib/pubid/export/nist_exporter.rb +0 -64
  436. data/lib/pubid/export/registry_exporter.rb +0 -90
  437. data/lib/pubid/export/scheme_exporter.rb +0 -70
  438. data/lib/pubid/identifier_registry.rb +0 -198
  439. data/lib/pubid/idf/scheme.rb +0 -61
  440. data/lib/pubid/iec/scheme.rb +0 -71
  441. data/lib/pubid/ieee/scheme.rb +0 -90
  442. data/lib/pubid/iho/scheme.rb +0 -29
  443. data/lib/pubid/iso/identifiers/base.rb +0 -115
  444. data/lib/pubid/iso/scheme.rb +0 -193
  445. data/lib/pubid/itu/scheme.rb +0 -174
  446. data/lib/pubid/jcgm/scheme.rb +0 -60
  447. data/lib/pubid/jis/components/code.rb +0 -59
  448. data/lib/pubid/jis/identifiers/base.rb +0 -72
  449. data/lib/pubid/jis/scheme.rb +0 -49
  450. data/lib/pubid/nist/components/publisher.rb +0 -24
  451. data/lib/pubid/nist/scheme.rb +0 -199
  452. data/lib/pubid/oiml/scheme.rb +0 -46
  453. data/lib/pubid/plateau/scheme.rb +0 -45
  454. data/lib/pubid/rendering/base.rb +0 -73
  455. data/lib/pubid/rendering/common.rb +0 -211
  456. data/lib/pubid/rendering/format.rb +0 -25
  457. data/lib/pubid/sae/scheme.rb +0 -47
  458. data/lib/pubid/scheme.rb +0 -219
@@ -4,11 +4,14 @@ require "set"
4
4
 
5
5
  module Pubid
6
6
  module Export
7
- # Abstract base class for per-flavor metadata extraction.
8
- # Subclasses implement strategy for different Scheme patterns.
7
+ # Unified metadata extractor for all flavors.
9
8
  #
10
- # Open/Closed: New flavors add a subclass; no existing code changes.
11
- # Single Responsibility: Each subclass extracts data for one Scheme pattern.
9
+ # Uses the self-describing type interface (identifier_types, all_typed_stages,
10
+ # locate_type, locate_stage) on each flavor module. No Scheme dependency (Scheme class removed).
11
+ #
12
+ # Open/Closed: Adding a new flavor requires only adding it to Exporter::FLAVORS.
13
+ # Single Responsibility: Extracts metadata from flavor modules into value objects.
14
+ # Single Source of Truth: Each identifier class IS the type definition.
12
15
  class FlavorExporter
13
16
  attr_reader :flavor
14
17
 
@@ -22,300 +25,106 @@ module Pubid
22
25
  @flavor = flavor
23
26
  end
24
27
 
25
- # Subclasses must override
26
28
  def export
27
- raise NotImplementedError
28
- end
29
-
30
- protected
29
+ mod = flavor_module
30
+ return nil unless mod
31
31
 
32
- def scheme_module
33
- # const_get doesn't trigger autoload; reference the constant directly
34
- @scheme_module ||= case flavor.to_s
35
- when "iso" then Pubid::Iso
36
- when "iec" then Pubid::Iec
37
- when "ieee" then Pubid::Ieee
38
- when "nist" then Pubid::Nist
39
- when "bsi" then Pubid::Bsi
40
- when "itu" then Pubid::Itu
41
- when "cen_cenelec" then Pubid::CenCenelec
42
- when "etsi" then Pubid::Etsi
43
- when "ansi" then Pubid::Ansi
44
- when "astm" then Pubid::Astm
45
- when "ashrae" then Pubid::Ashrae
46
- when "asme" then Pubid::Asme
47
- when "ccsds" then Pubid::Ccsds
48
- when "cie" then Pubid::Cie
49
- when "csa" then Pubid::Csa
50
- when "jis" then Pubid::Jis
51
- when "jcgm" then Pubid::Jcgm
52
- when "oiml" then Pubid::Oiml
53
- when "idf" then Pubid::Idf
54
- when "api" then Pubid::Api
55
- when "amca" then Pubid::Amca
56
- when "plateau" then Pubid::Plateau
57
- when "sae" then Pubid::Sae
58
- end
59
- end
60
-
61
- def scheme_class
62
- @scheme_class ||= begin
63
- mod = scheme_module
64
- mod&.const_get(:Scheme)
65
- rescue NameError
66
- nil
67
- end
68
- end
32
+ klasses = resolve_identifier_classes(mod)
33
+ return nil if klasses.empty?
69
34
 
70
- def identifier_classes
71
- resolve_identifier_classes
72
- end
35
+ fixture_data = fixture_examples
36
+ seen_keys = Set.new
73
37
 
74
- def resolve_identifier_classes
75
- scheme = scheme_class
76
- scheme_klasses = []
38
+ identifier_types = klasses.filter_map do |klass|
39
+ info = extract_type_info(klass)
40
+ next if seen_keys.include?(info[:key])
77
41
 
78
- # Pattern 1: Class methods (ISO, IEC, ASTM, etc.)
79
- begin
80
- scheme_klasses = scheme.identifiers if scheme
81
- rescue NoMethodError
82
- scheme_klasses = []
83
- end
42
+ seen_keys << info[:key]
84
43
 
85
- # Pattern 2: Instance-based (AMCA, BSI)
86
- if scheme_klasses.empty? && scheme
87
- instance = begin
88
- scheme.new
89
- rescue NoMethodError
90
- nil
91
- end
92
- if instance
93
- ids = begin
94
- instance.identifiers
95
- rescue NoMethodError
96
- nil
97
- end
98
- scheme_klasses = ids if ids && !ids.empty?
99
- end
100
- end
44
+ stages = extract_typed_stages(klass)
45
+ examples = match_examples(fixture_data, info[:key]&.to_s, klass)
101
46
 
102
- # Build set of website keys from Scheme classes to avoid duplicates
103
- known_website_keys = Set.new
104
- scheme_klasses.each do |klass|
105
- info = extract_type_info(klass)
106
- known_website_keys << info[:key].to_s if info[:key]
47
+ IdentifierTypeResult.new(
48
+ key: info[:key],
49
+ title: info[:title],
50
+ short: info[:short],
51
+ abbr: info[:abbr],
52
+ typed_stages: stages,
53
+ examples: examples,
54
+ )
107
55
  end
108
56
 
109
- # Supplement with any typed classes in the Identifiers module
110
- # that weren't returned by Scheme (e.g., supplements, fragments)
111
- additional = discover_additional_typed_classes(scheme_klasses,
112
- known_website_keys)
113
- scheme_klasses + additional
57
+ FlavorResult.new(
58
+ flavor: flavor,
59
+ identifier_types: identifier_types,
60
+ wrapper_types: extract_wrapper_types,
61
+ attributes: extract_attributes(klasses.first),
62
+ )
114
63
  end
115
64
 
116
- # Classes to skip when discovering additional identifier types
117
- SKIP_CLASSES = %w[Base].freeze
118
-
119
- def discover_additional_typed_classes(known_classes,
120
- known_website_keys = Set.new)
121
- mod = scheme_module
122
- return [] unless mod
123
-
124
- idents_mod = mod.const_get(:Identifiers)
125
- known_set = Set.new(known_classes)
126
-
127
- idents_mod.constants.filter_map do |c|
128
- klass = idents_mod.const_get(c)
129
- rescue NameError
130
- next
131
- else
132
- next unless klass.is_a?(Class)
133
- next if known_set.include?(klass)
134
- next if klass <= Exception
135
- next if SKIP_CLASSES.include?(klass.name&.split("::")&.last)
65
+ protected
136
66
 
137
- # Check if this class produces a duplicate website key
138
- info = extract_type_info(klass)
139
- wkey = info[:key]&.to_s
140
- next if wkey && known_website_keys.include?(wkey)
67
+ # Resolve identifier classes from the flavor module.
68
+ # Primary: use the module's self-describing identifier_types method.
69
+ # Fallback: scan the Identifiers namespace directly for Pubid::Identifier
70
+ # subclasses (handles ETSI, ITU, and other non-standard patterns).
71
+ def resolve_identifier_classes(mod)
72
+ klasses = mod.identifier_types
73
+ return klasses if klasses && !klasses.empty?
141
74
 
142
- known_website_keys << wkey if wkey
143
- klass
144
- end
75
+ discover_from_namespace(mod)
145
76
  end
146
77
 
147
- # Explicit overrides mapping (flavor, library_key) website key
148
- # for cases where derived key doesn't match the website convention.
149
- WEBSITE_KEY_OVERRIDES = {
150
- # ISO
151
- [%i[iso], :is] => :international_standard,
152
- [%i[iso], :tr] => :technical_report,
153
- [%i[iso], :ts] => :technical_specification,
154
- [%i[iso], :pas] => :publicly_available_specification,
155
- [%i[iso], :tta] => :technology_trends_assessments,
156
- [%i[iso], :iwa] => :international_workshop_agreement,
157
- [%i[iso], :isp] => :international_standardized_profile,
158
- [%i[iso], :rec] => :recommendation,
159
- [%i[iso], :dir] => :directives,
160
- [%i[iso], :"dir-sup"] => :directives_supplement,
161
- [%i[iso], :amd] => :amendment,
162
- [%i[iso], :cor] => :corrigendum,
163
- [%i[iso], :suppl] => :supplement,
164
- [%i[iso], :ext] => :extract,
165
- [%i[iso], :add] => :addendum,
166
- [%i[iso], :tc] => :tc_document,
167
- # IEC
168
- [%i[iec], :is] => :international_standard,
169
- [%i[iec], :tr] => :technical_report,
170
- [%i[iec], :ts] => :technical_specification,
171
- [%i[iec], :pas] => :publicly_available_specification,
172
- [%i[iec], :trf] => :test_report_form,
173
- [%i[iec], :ish] => :interpretation_sheet,
174
- [%i[iec], :srd] => :systems_reference_document,
175
- [%i[iec], :wd] => :working_document,
176
- [%i[iec], :frag] => :fragment_identifier,
177
- [%i[iec], :amd] => :amendment,
178
- [%i[iec], :cor] => :corrigendum,
179
- [%i[iec], :cs] => :component_specification,
180
- [%i[iec], :od] => :operational_document,
181
- [%i[iec], :sttr] => :societal_technology_trend_report,
182
- [%i[iec], :wp] => :white_paper,
183
- # IEEE
184
- [%i[ieee], :std] => :standard,
185
- # NIST
186
- [%i[nist], :sp] => :special_publication,
187
- [%i[nist], :fips] => :federal_information_processing_standards,
188
- [%i[nist], :ir] => :interagency_report,
189
- [%i[nist], :hb] => :handbook,
190
- [%i[nist], :tn] => :technical_note,
191
- [%i[nist], :circ] => :circular,
192
- [%i[nist], :circ_supp] => :circular_supplement,
193
- [%i[nist], :crpl] => :crpl_report,
194
- [%i[nist], :rpt] => :report,
195
- [%i[nist], :mono] => :monograph,
196
- [%i[nist], :mp] => :miscellaneous_publication,
197
- [%i[nist], :gcr] => :grant_contractor_report,
198
- [%i[nist], :lc] => :letter_circular,
199
- [%i[nist], :cs] => :commercial_standard,
200
- [%i[nist], :cse] => :commercial_standard_emergency,
201
- [%i[nist], :csm] => :commercial_standards_monthly,
202
- # BSI — adopted types share keys with base types, need unique mappings
203
- [%i[bsi], :bs] => :british_standard,
204
- [%i[bsi], :pd] => :published_document,
205
- [%i[bsi], :pas] => :publicly_available_specification,
206
- [%i[bsi], :na] => :national_annex,
207
- [%i[bsi], :dd] => :draft_document,
208
- [%i[bsi], :ep] => :electronic_book,
209
- [%i[bsi], :ts] => :technical_specification,
210
- [%i[bsi], :handbook] => :handbook,
211
- [%i[bsi], :aerospace] => :aerospace_standard,
212
- # CEN-CENELEC
213
- [%i[cen_cenelec], :en] => :european_norm,
214
- [%i[cen_cenelec], :ts] => :technical_specification,
215
- [%i[cen_cenelec], :tr] => :technical_report,
216
- [%i[cen_cenelec], :cwa] => :cen_workshop_agreement,
217
- [%i[cen_cenelec], :hd] => :harmonization_document,
218
- [%i[cen_cenelec], :es] => :european_specification,
219
- [%i[cen_cenelec], :cr] => :cen_report,
220
- [%i[cen_cenelec], :env] => :european_prestandard,
221
- # IDF
222
- [%i[idf], :is] => :international_standard,
223
- [%i[idf], :rm] => :reviewed_method,
224
- [%i[idf], :amd] => :amendment,
225
- [%i[idf], :cor] => :corrigendum,
226
- # CCSDS
227
- [%i[ccsds], :base] => :base,
228
- [%i[ccsds], :cor] => :corrigendum,
229
- # JIS
230
- [%i[jis], :jis] => :japanese_industrial_standard,
231
- [%i[jis], :tr] => :technical_report,
232
- [%i[jis], :ts] => :technical_specification,
233
- # SAE
234
- [%i[sae], :base] => :standard,
235
- # ANSI
236
- [%i[ansi], :ans] => :american_national_standard,
237
- }.freeze
78
+ # Scan Identifiers namespace for all Pubid::Identifier subclasses,
79
+ # excluding structural base classes.
80
+ def discover_from_namespace(mod)
81
+ return [] unless mod.const_defined?(:Identifiers)
238
82
 
239
- # Per-class overrides keyed by class name (for classes that share type keys)
240
- CLASS_KEY_OVERRIDES = {
241
- "Pubid::Bsi::Identifiers::AdoptedEuropeanNorm" => "adopted_european_norm",
242
- "Pubid::Bsi::Identifiers::AdoptedInternationalStandard" => "adopted_international_standard",
243
- "Pubid::CenCenelec::Identifiers::AdoptedEuropeanNorm" => "adopted_european_norm",
244
- "Pubid::Ansi::Identifiers::Standard" => "standard",
245
- "Pubid::Ansi::Identifiers::AmericanNationalStandard" => "american_national_standard",
246
- "Pubid::Jis::Identifiers::Standard" => "standard",
247
- "Pubid::Ieee::Identifiers::Nesc::Standard" => "nesc",
248
- "Pubid::Ieee::Identifiers::Nesc::Draft" => "nesc",
249
- "Pubid::Ieee::Identifiers::Nesc::Handbook" => "nesc",
250
- "Pubid::Ieee::Identifiers::Nesc::Redline" => "nesc",
251
- }.freeze
83
+ idents_mod = mod.const_get(:Identifiers)
84
+ collect_identifier_classes(idents_mod)
85
+ end
252
86
 
253
- def extract_type_info(klass)
254
- # Per-class override takes highest priority
255
- class_key = CLASS_KEY_OVERRIDES[klass.name]
256
- if class_key
257
- type_info = begin
258
- klass.type
259
- rescue NoMethodError, NotImplementedError
260
- nil
261
- end
262
- metadata = begin
263
- klass.metadata
264
- rescue NoMethodError
265
- nil
87
+ # Recursively collect all Pubid::Identifier subclasses from a module,
88
+ # descending into submodules (e.g., IEEE's Nesc namespace).
89
+ def collect_identifier_classes(mod)
90
+ result = []
91
+ mod.constants.each do |c|
92
+ const = begin; mod.const_get(c); rescue NameError; next; end
93
+ if const.is_a?(Module) && !const.is_a?(Class)
94
+ result.concat(collect_identifier_classes(const))
95
+ elsif const.is_a?(Class) && const < Pubid::Identifier
96
+ result << const
266
97
  end
267
- return {
268
- key: class_key,
269
- title: type_info&.dig(:title) || metadata&.title || class_key.tr(
270
- "_", " "
271
- ).capitalize,
272
- short: type_info&.dig(:short) || metadata&.short,
273
- abbr: metadata&.abbr || [],
274
- }
275
98
  end
99
+ result
100
+ end
276
101
 
277
- type_info = begin
278
- klass.type
279
- rescue NoMethodError, NotImplementedError
280
- nil
281
- end
282
- metadata = begin
283
- klass.metadata
284
- rescue NoMethodError
102
+ # Map flavor symbol to the flavor module.
103
+ def flavor_module
104
+ @flavor_module ||= begin
105
+ mod_name = flavor.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }
106
+ Pubid.const_get(mod_name)
107
+ rescue NameError
285
108
  nil
286
109
  end
110
+ end
111
+
112
+ def extract_type_info(klass)
113
+ type_info = safe_type(klass)
114
+ metadata = safe_metadata(klass)
287
115
 
288
- lib_key = type_info&.dig(:key)
116
+ key = type_info&.dig(:web) || type_info&.dig(:key)
289
117
  title = type_info&.dig(:title) || metadata&.title
290
118
  short = type_info&.dig(:short) || metadata&.short
291
119
  abbr = metadata&.abbr || []
292
120
 
293
- # Derive from class name when def self.type is missing
294
- unless lib_key
121
+ unless key
295
122
  class_name = klass.name&.split("::")&.last
296
- lib_key = class_name&.gsub(/([A-Z])/, '_\1')&.downcase&.sub(/^_/,
297
- "")&.to_sym
123
+ key = class_name&.gsub(/([A-Z])/, '_\1')&.downcase&.sub(/^_/, "")
298
124
  title ||= class_name&.gsub(/([A-Z])/, ' \1')&.strip
299
125
  end
300
126
 
301
- # Map library key to website-compatible key
302
- website_key = resolve_website_key(lib_key)
303
-
304
- {
305
- key: website_key,
306
- title: title,
307
- short: short,
308
- abbr: abbr,
309
- }
310
- end
311
-
312
- def resolve_website_key(lib_key)
313
- key_str = lib_key.to_s
314
- WEBSITE_KEY_OVERRIDES.each do |(flavors, from_key), to_key|
315
- next unless flavors.include?(flavor)
316
- return to_key.to_s if from_key.to_s == key_str
317
- end
318
- key_str
127
+ { key: key&.to_s, title: title, short: short, abbr: abbr }
319
128
  end
320
129
 
321
130
  def extract_typed_stages(klass)
@@ -326,14 +135,10 @@ known_website_keys = Set.new)
326
135
  []
327
136
  end
328
137
 
329
- # Map flavor keys to fixture directory names when they differ
330
- FIXTURE_DIR_ALIASES = {}.freeze
331
-
138
+ # Fixture example extraction
332
139
  def fixture_examples
333
- # __dir__ = lib/pubid/export → go up 3 levels to gem root, then spec/fixtures
334
140
  gem_root = File.expand_path("../../..", __dir__)
335
- dir_name = FIXTURE_DIR_ALIASES[flavor] || flavor.to_s
336
- base = File.join(gem_root, "spec", "fixtures", dir_name, "identifiers",
141
+ base = File.join(gem_root, "spec", "fixtures", flavor.to_s, "identifiers",
337
142
  "pass")
338
143
  return {} unless Dir.exist?(base)
339
144
 
@@ -351,10 +156,8 @@ known_website_keys = Set.new)
351
156
  File.readlines(path, chomp: true).each do |line|
352
157
  next if line.start_with?("#") || line.strip.empty?
353
158
 
354
- # Format: "!Type input!expected" or just "input"
355
159
  if line.start_with?("!")
356
160
  parts = line.split("!")
357
- # ["", "Type", "input", "expected"] or ["", "Type", "input"]
358
161
  input = parts[2]&.strip
359
162
  identifiers << input if input && !input.empty?
360
163
  else
@@ -364,8 +167,24 @@ known_website_keys = Set.new)
364
167
  identifiers.uniq.first(10)
365
168
  end
366
169
 
367
- def map_fixture_key_to_type_key(fixture_key)
368
- fixture_key
170
+ def match_examples(fixture_data, type_key, klass)
171
+ return [] unless type_key
172
+
173
+ # Try direct type key match first
174
+ examples = fixture_data[type_key] ||
175
+ fixture_data[type_key.gsub("_", "")] ||
176
+ []
177
+
178
+ return examples if examples.any?
179
+
180
+ # Try class name match
181
+ class_name = klass.name&.split("::")&.last
182
+ snake_name = class_name&.gsub(/([A-Z])/, '_\1')&.downcase&.sub(/^_/, "")
183
+ if snake_name && fixture_data.key?(snake_name)
184
+ fixture_data[snake_name]
185
+ else
186
+ []
187
+ end
369
188
  end
370
189
 
371
190
  def extract_attributes(klass)
@@ -378,7 +197,7 @@ known_website_keys = Set.new)
378
197
  names = WRAPPER_CLASSES[flavor]
379
198
  return [] unless names
380
199
 
381
- mod = scheme_module
200
+ mod = flavor_module
382
201
  return [] unless mod
383
202
 
384
203
  identifiers_mod = mod.const_get(:Identifiers)
@@ -397,6 +216,20 @@ known_website_keys = Set.new)
397
216
  nil
398
217
  end
399
218
  end
219
+
220
+ private
221
+
222
+ def safe_type(klass)
223
+ klass.type
224
+ rescue NoMethodError, NotImplementedError
225
+ nil
226
+ end
227
+
228
+ def safe_metadata(klass)
229
+ klass.metadata
230
+ rescue NoMethodError
231
+ nil
232
+ end
400
233
  end
401
234
  end
402
235
  end
data/lib/pubid/export.rb CHANGED
@@ -6,12 +6,6 @@ module Pubid
6
6
  autoload :TypedStageResult, "#{__dir__}/export/result"
7
7
  autoload :FlavorResult, "#{__dir__}/export/result"
8
8
  autoload :FlavorExporter, "#{__dir__}/export/flavor_exporter"
9
- autoload :SchemeExporter, "#{__dir__}/export/scheme_exporter"
10
- autoload :IeeeExporter, "#{__dir__}/export/ieee_exporter"
11
- autoload :RegistryExporter, "#{__dir__}/export/registry_exporter"
12
- autoload :DataClassExporter, "#{__dir__}/export/data_class_exporter"
13
- autoload :NistExporter, "#{__dir__}/export/nist_exporter"
14
- autoload :ItuExporter, "#{__dir__}/export/itu_exporter"
15
9
  autoload :Auditor, "#{__dir__}/export/auditor"
16
10
  autoload :Exporter, "#{__dir__}/export/exporter"
17
11
  end
@@ -1,14 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "components/code"
4
- require_relative "components/date"
5
- require_relative "components/edition"
6
- require_relative "components/language"
7
- require_relative "components/locality"
8
- require_relative "components/publisher"
9
- require_relative "components/stage"
10
- require_relative "components/type"
11
-
12
3
  module Pubid
13
4
  class Identifier < Lutaml::Model::Serializable
14
5
  class << self
@@ -23,7 +14,7 @@ module Pubid
23
14
  attribute :number, Components::Code
24
15
  attribute :part, Components::Code
25
16
  attribute :subpart, Components::Code
26
- attribute :stage_iteration, Components::Code
17
+ attribute :stage_iteration, Components::Iteration
27
18
  attribute :date, Components::Date
28
19
  attribute :edition, Components::Edition
29
20
  attribute :languages, Components::Language, collection: true
@@ -62,12 +53,6 @@ module Pubid
62
53
  "pubid:#{flavor}:#{type_kebab}"
63
54
  end
64
55
 
65
- klass_ref = self
66
- key_value do
67
- klass_ref.attributes.each_key do |name|
68
- map name.to_s, to: name.to_sym
69
- end
70
- end
71
56
 
72
57
  def root
73
58
  return base_identifier.root if base_identifier
@@ -165,7 +150,7 @@ module Pubid
165
150
  excluded_args << :date if excluded_args.delete(:year)
166
151
 
167
152
  attrs = self.class.attributes.each_with_object({}) do |(name, _), h|
168
- h[name] = excluded_args.include?(name) ? nil : send(name)
153
+ h[name] = excluded_args.include?(name) ? nil : public_send(name)
169
154
  end
170
155
  self.class.new(attrs)
171
156
  end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ # Mixin for the per-flavor `Identifier` *module* facades (NIST, IHO, BSI,
5
+ # CEN/CENELEC, ASHRAE). The class-pattern flavors (ISO, IEC, JIS, …) expose
6
+ # their root identifier as a real class, so `id.is_a?(Pubid::Iso::Identifier)`
7
+ # and `Pubid::Iso::Identifier.from_hash` already work natively. The
8
+ # module-pattern flavors keep `Identifier` as a thin parse/factory module;
9
+ # this mixin gives that module the same two capabilities a consumer relies on
10
+ # when it is handed the module as its identifier class (e.g. relaton-index's
11
+ # `pubid_class`):
12
+ #
13
+ # * `from_hash` — polymorphic deserialization that dispatches on the
14
+ # `_type` discriminator to the correct concrete `Identifiers::*` class,
15
+ # reusing the flavor's own `identifier_types` registry rather than a
16
+ # hand-maintained map.
17
+ # * identity — `extend`ing this mixin into the `Identifier` module is paired
18
+ # with `include`-ing that module into the flavor's `Identifiers::Base`, so
19
+ # every concrete identifier descends from it. That makes
20
+ # `id.is_a?(Pubid::Nist::Identifier)` and `Pubid::Nist::Identifier === id`
21
+ # both true (`Module#===` delegates to `is_a?`) — the test a consumer
22
+ # holding the module needs to ask "is this one of my identifiers?".
23
+ #
24
+ # The flavor namespace, the `Identifiers` namespace, and the fallback `Base`
25
+ # class are all derived from the extending module's own name by convention
26
+ # (`Pubid::<Flavor>::Identifier`), so a flavor opts in with a single
27
+ # `extend Pubid::IdentifierFacade`.
28
+ #
29
+ # Opt-in is deliberately GATED to flavors whose `to_hash`/`from_hash`
30
+ # round-trips cleanly. Some module-pattern flavors (AMCA, ITU, PLATEAU, IEEE)
31
+ # have a broken `to_hash` (publisher stored as a String) or a lossy
32
+ # `from_hash`; for those the facade's identity check would route ids through a
33
+ # consumer's `to_hash` and crash or silently corrupt them, so they
34
+ # intentionally do not opt in (see the NOTE in each of their identifier.rb).
35
+ module IdentifierFacade
36
+ # Reconstruct a concrete identifier from its serialized key_value hash by
37
+ # dispatching on the `_type` discriminator. Falls back to the flavor's
38
+ # `Identifiers::Base` for an absent/unknown type, matching lutaml's own
39
+ # non-polymorphic default.
40
+ #
41
+ # @param data [Hash] the serialized identifier hash (string or symbol keys)
42
+ # @return [Pubid::Identifier] the concrete identifier instance
43
+ def from_hash(data, options = {})
44
+ type = data && (data["_type"] || data[:_type])
45
+ klass = polymorphic_type_map[type] || identifier_base_class
46
+ klass.from_hash(data, options)
47
+ end
48
+
49
+ # Map of polymorphic_name ("pubid:nist:interagency-report") => concrete
50
+ # class, built once from the flavor's identifier-type registry so it tracks
51
+ # newly registered types automatically.
52
+ # @return [Hash{String => Class}]
53
+ def polymorphic_type_map
54
+ @polymorphic_type_map ||=
55
+ (identifier_registry_classes + [identifier_base_class]).uniq
56
+ .each_with_object({}) do |klass, map|
57
+ poly_name = klass.polymorphic_name
58
+ map[poly_name] = klass if poly_name
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ # The flavor module that namespaces this facade, e.g. Pubid::Nist for
65
+ # Pubid::Nist::Identifier.
66
+ def facade_flavor_module
67
+ @facade_flavor_module ||=
68
+ Object.const_get(name.split("::")[0...-1].join("::"))
69
+ end
70
+
71
+ def facade_identifiers_namespace
72
+ @facade_identifiers_namespace ||=
73
+ facade_flavor_module.const_get(:Identifiers)
74
+ end
75
+
76
+ # Fallback class for an absent/unknown `_type`. Most flavors expose a
77
+ # concrete `Identifiers::Base`; flavors without one (e.g. BSI, whose common
78
+ # ancestor is SingleIdentifier) fall back to the shared root, which is only
79
+ # ever reached for an unrecognized `_type`.
80
+ def identifier_base_class
81
+ if facade_identifiers_namespace.const_defined?(:Base, false)
82
+ facade_identifiers_namespace.const_get(:Base)
83
+ else
84
+ ::Pubid::Identifier
85
+ end
86
+ end
87
+
88
+ # Every concrete identifier class whose `_type` may appear in a serialized
89
+ # hash. Scans the `Identifiers` namespace for descendants of
90
+ # Pubid::Identifier (the complete set, independent of whatever filtering the
91
+ # flavor's `identifier_types` applies) and unions in `identifier_types`,
92
+ # which may register classes living outside that namespace.
93
+ def identifier_registry_classes
94
+ (scanned_identifier_classes + registered_identifier_classes).uniq
95
+ end
96
+
97
+ # Concrete identifier classes found directly in the `Identifiers` namespace.
98
+ def scanned_identifier_classes
99
+ facade_identifiers_namespace.constants.filter_map do |const|
100
+ klass = facade_identifiers_namespace.const_get(const)
101
+ klass if klass.is_a?(Class) && klass < ::Pubid::Identifier
102
+ rescue NameError
103
+ nil
104
+ end
105
+ end
106
+
107
+ # Classes the flavor explicitly registers via `identifier_types`, if any.
108
+ def registered_identifier_classes
109
+ return [] unless facade_flavor_module.respond_to?(:identifier_types)
110
+
111
+ Array(facade_flavor_module.identifier_types)
112
+ end
113
+ end
114
+ end
@@ -102,7 +102,7 @@ module Pubid
102
102
  # Get the metadata for this class
103
103
  # @return [Metadata, nil]
104
104
  def metadata
105
- @metadata ||= if superclass.is_a?(Class) && superclass.respond_to?(:metadata)
105
+ @metadata ||= if superclass.is_a?(Class) && superclass.ancestors.include?(Pubid::IdentifierMetadata)
106
106
  superclass.metadata
107
107
  end
108
108
  end
@@ -13,8 +13,8 @@ module Pubid
13
13
  }.freeze
14
14
 
15
15
  def build(parsed_hash)
16
- typed_stage = Scheme.locate_typed_stage_by_abbr(parsed_hash[:type_with_stage])
17
- identifier = Scheme.locate_identifier_klass_by_type_code(typed_stage.type_code).new
16
+ typed_stage = Pubid::Idf.locate_stage(parsed_hash[:type_with_stage])
17
+ identifier = Pubid::Idf.locate_type(typed_stage.type_code).new
18
18
 
19
19
  if type_with_stage_fr = parsed_hash.delete(:type_with_stage_fr)
20
20
  parsed_hash[:type_with_stage] = type_with_stage_fr
@@ -48,7 +48,7 @@ module Pubid
48
48
  when :type_with_stage
49
49
  iteration = value.to_s.match(/(\d+)$/)
50
50
  value = value.to_s.sub(iteration.to_s, "")
51
- typed_stage = Scheme.locate_typed_stage_by_abbr(value || "")
51
+ typed_stage = Pubid::Idf.locate_stage(value || "")
52
52
  {
53
53
  stage: typed_stage.to_stage,
54
54
  type: typed_stage.to_type,