pubid 1.15.18 → 2.0.0.pre.alpha.1

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 (601) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.adoc +2041 -53
  4. data/archived-gems/pubid-ccsds/update_codes.yaml +1 -0
  5. data/archived-gems/pubid-iec/stages.yaml +129 -0
  6. data/archived-gems/pubid-iec/update_codes.yaml +67 -0
  7. data/archived-gems/pubid-ieee/update_codes.yaml +104 -0
  8. data/archived-gems/pubid-iso/stages.yaml +106 -0
  9. data/archived-gems/pubid-iso/update_codes.yaml +4 -0
  10. data/archived-gems/pubid-itu/i18n.yaml +13 -0
  11. data/archived-gems/pubid-itu/series.yaml +42 -0
  12. data/archived-gems/pubid-nist/publishers.yaml +6 -0
  13. data/archived-gems/pubid-nist/series.yaml +121 -0
  14. data/archived-gems/pubid-nist/stages.yaml +16 -0
  15. data/archived-gems/pubid-nist/update_codes.yaml +93 -0
  16. data/archived-gems/pubid-plateau/update_codes.yaml +6 -0
  17. data/data/ccsds/update_codes.yaml +1 -0
  18. data/data/iec/update_codes.yaml +67 -0
  19. data/data/ieee/update_codes.yaml +104 -0
  20. data/data/iso/update_codes.yaml +21 -0
  21. data/data/nist/update_codes.yaml +87 -0
  22. data/data/plateau/update_codes.yaml +6 -0
  23. data/lib/pubid/amca/builder.rb +176 -0
  24. data/lib/pubid/amca/identifier.rb +18 -0
  25. data/lib/pubid/amca/identifiers/base.rb +64 -0
  26. data/lib/pubid/amca/identifiers/interpretation.rb +51 -0
  27. data/lib/pubid/amca/identifiers/publication.rb +47 -0
  28. data/lib/pubid/amca/identifiers/standard.rb +22 -0
  29. data/lib/pubid/amca/identifiers.rb +12 -0
  30. data/lib/pubid/amca/parser.rb +153 -0
  31. data/lib/pubid/amca/scheme.rb +16 -0
  32. data/lib/pubid/amca/single_identifier.rb +33 -0
  33. data/lib/pubid/amca/urn_generator.rb +50 -0
  34. data/lib/pubid/amca.rb +26 -0
  35. data/lib/pubid/ansi/builder.rb +52 -0
  36. data/lib/pubid/ansi/identifier.rb +13 -0
  37. data/lib/pubid/ansi/identifiers/american_national_standard.rb +12 -0
  38. data/lib/pubid/ansi/identifiers/standard.rb +16 -0
  39. data/lib/pubid/ansi/identifiers.rb +11 -0
  40. data/lib/pubid/ansi/parser.rb +91 -0
  41. data/lib/pubid/ansi/scheme.rb +15 -0
  42. data/lib/pubid/ansi/single_identifier.rb +45 -0
  43. data/lib/pubid/ansi/urn_generator.rb +76 -0
  44. data/lib/pubid/ansi.rb +27 -0
  45. data/lib/pubid/api/builder.rb +85 -0
  46. data/lib/pubid/api/components/code.rb +9 -0
  47. data/lib/pubid/api/identifier.rb +21 -0
  48. data/lib/pubid/api/identifiers/base.rb +24 -0
  49. data/lib/pubid/api/identifiers/bulletin.rb +15 -0
  50. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +15 -0
  51. data/lib/pubid/api/identifiers/mpms.rb +44 -0
  52. data/lib/pubid/api/identifiers/publication.rb +15 -0
  53. data/lib/pubid/api/identifiers/recommended_practice.rb +15 -0
  54. data/lib/pubid/api/identifiers/specification.rb +15 -0
  55. data/lib/pubid/api/identifiers/standard.rb +15 -0
  56. data/lib/pubid/api/identifiers/technical_report.rb +15 -0
  57. data/lib/pubid/api/identifiers/typeless_standard.rb +27 -0
  58. data/lib/pubid/api/parser.rb +140 -0
  59. data/lib/pubid/api/scheme.rb +66 -0
  60. data/lib/pubid/api/single_identifier.rb +46 -0
  61. data/lib/pubid/api/urn_generator.rb +41 -0
  62. data/lib/pubid/api.rb +17 -0
  63. data/lib/pubid/ashrae/builder.rb +498 -0
  64. data/lib/pubid/ashrae/identifier.rb +18 -0
  65. data/lib/pubid/ashrae/identifiers/addenda_package.rb +46 -0
  66. data/lib/pubid/ashrae/identifiers/addendum.rb +55 -0
  67. data/lib/pubid/ashrae/identifiers/base.rb +23 -0
  68. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +51 -0
  69. data/lib/pubid/ashrae/identifiers/errata.rb +40 -0
  70. data/lib/pubid/ashrae/identifiers/guideline.rb +38 -0
  71. data/lib/pubid/ashrae/identifiers/interpretation.rb +39 -0
  72. data/lib/pubid/ashrae/identifiers/standard.rb +38 -0
  73. data/lib/pubid/ashrae/identifiers.rb +16 -0
  74. data/lib/pubid/ashrae/parser.rb +724 -0
  75. data/lib/pubid/ashrae/scheme.rb +53 -0
  76. data/lib/pubid/ashrae/single_identifier.rb +23 -0
  77. data/lib/pubid/ashrae/supplement_identifier.rb +23 -0
  78. data/lib/pubid/ashrae/urn_generator.rb +59 -0
  79. data/lib/pubid/ashrae.rb +21 -0
  80. data/lib/pubid/asme/builder.rb +153 -0
  81. data/lib/pubid/asme/components/code.rb +18 -0
  82. data/lib/pubid/asme/identifier.rb +15 -0
  83. data/lib/pubid/asme/identifiers/base.rb +70 -0
  84. data/lib/pubid/asme/identifiers/standard.rb +12 -0
  85. data/lib/pubid/asme/identifiers.rb +10 -0
  86. data/lib/pubid/asme/parser.rb +308 -0
  87. data/lib/pubid/asme/scheme.rb +37 -0
  88. data/lib/pubid/asme/single_identifier.rb +29 -0
  89. data/lib/pubid/asme/urn_generator.rb +133 -0
  90. data/lib/pubid/asme.rb +21 -0
  91. data/lib/pubid/astm/builder.rb +159 -0
  92. data/lib/pubid/astm/components/code.rb +33 -0
  93. data/lib/pubid/astm/identifier.rb +15 -0
  94. data/lib/pubid/astm/identifiers/adjunct.rb +21 -0
  95. data/lib/pubid/astm/identifiers/base.rb +13 -0
  96. data/lib/pubid/astm/identifiers/data_series.rb +25 -0
  97. data/lib/pubid/astm/identifiers/iso_dual_published.rb +74 -0
  98. data/lib/pubid/astm/identifiers/manual.rb +40 -0
  99. data/lib/pubid/astm/identifiers/monograph.rb +25 -0
  100. data/lib/pubid/astm/identifiers/research_report.rb +18 -0
  101. data/lib/pubid/astm/identifiers/standard.rb +52 -0
  102. data/lib/pubid/astm/identifiers/technical_report.rb +23 -0
  103. data/lib/pubid/astm/identifiers/work_in_progress.rb +21 -0
  104. data/lib/pubid/astm/parser.rb +244 -0
  105. data/lib/pubid/astm/scheme.rb +55 -0
  106. data/lib/pubid/astm/single_identifier.rb +25 -0
  107. data/lib/pubid/astm/urn_generator.rb +99 -0
  108. data/lib/pubid/astm.rb +38 -0
  109. data/lib/pubid/bsi/builder.rb +1483 -0
  110. data/lib/pubid/bsi/components/code.rb +11 -0
  111. data/lib/pubid/bsi/components/date.rb +11 -0
  112. data/lib/pubid/bsi/components/publisher.rb +11 -0
  113. data/lib/pubid/bsi/components/type.rb +11 -0
  114. data/lib/pubid/bsi/identifier.rb +27 -0
  115. data/lib/pubid/bsi/identifiers/addendum_document.rb +64 -0
  116. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +95 -0
  117. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +82 -0
  118. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +118 -0
  119. data/lib/pubid/bsi/identifiers/amendment.rb +40 -0
  120. data/lib/pubid/bsi/identifiers/base.rb +11 -0
  121. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +27 -0
  122. data/lib/pubid/bsi/identifiers/british_standard.rb +33 -0
  123. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +114 -0
  124. data/lib/pubid/bsi/identifiers/committee_document.rb +51 -0
  125. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +152 -0
  126. data/lib/pubid/bsi/identifiers/corrigendum.rb +28 -0
  127. data/lib/pubid/bsi/identifiers/detailed_specification.rb +69 -0
  128. data/lib/pubid/bsi/identifiers/disc.rb +56 -0
  129. data/lib/pubid/bsi/identifiers/draft_document.rb +71 -0
  130. data/lib/pubid/bsi/identifiers/electronic_book.rb +52 -0
  131. data/lib/pubid/bsi/identifiers/expert_commentary.rb +47 -0
  132. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +82 -0
  133. data/lib/pubid/bsi/identifiers/flex.rb +61 -0
  134. data/lib/pubid/bsi/identifiers/handbook.rb +39 -0
  135. data/lib/pubid/bsi/identifiers/index.rb +62 -0
  136. data/lib/pubid/bsi/identifiers/method.rb +76 -0
  137. data/lib/pubid/bsi/identifiers/national_annex.rb +73 -0
  138. data/lib/pubid/bsi/identifiers/practice_guide.rb +27 -0
  139. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +79 -0
  140. data/lib/pubid/bsi/identifiers/published_document.rb +79 -0
  141. data/lib/pubid/bsi/identifiers/section.rb +62 -0
  142. data/lib/pubid/bsi/identifiers/set.rb +46 -0
  143. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +40 -0
  144. data/lib/pubid/bsi/identifiers/supplement_document.rb +51 -0
  145. data/lib/pubid/bsi/identifiers/supplementary_index.rb +81 -0
  146. data/lib/pubid/bsi/identifiers/technical_specification.rb +79 -0
  147. data/lib/pubid/bsi/identifiers/test_method.rb +67 -0
  148. data/lib/pubid/bsi/identifiers/value_added_publication.rb +52 -0
  149. data/lib/pubid/bsi/identifiers.rb +52 -0
  150. data/lib/pubid/bsi/model.rb +196 -0
  151. data/lib/pubid/bsi/parser.rb +659 -0
  152. data/lib/pubid/bsi/scheme.rb +243 -0
  153. data/lib/pubid/bsi/single_identifier.rb +129 -0
  154. data/lib/pubid/bsi/urn_generator.rb +84 -0
  155. data/lib/pubid/bsi.rb +32 -0
  156. data/lib/pubid/builder/base.rb +138 -0
  157. data/lib/pubid/bundled_identifier.rb +126 -0
  158. data/lib/pubid/ccsds/builder.rb +56 -0
  159. data/lib/pubid/ccsds/identifier.rb +16 -0
  160. data/lib/pubid/ccsds/identifiers/base.rb +78 -0
  161. data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +70 -0
  162. data/lib/pubid/ccsds/identifiers/corrigendum.rb +39 -0
  163. data/lib/pubid/ccsds/identifiers.rb +10 -0
  164. data/lib/pubid/ccsds/parser.rb +71 -0
  165. data/lib/pubid/ccsds/scheme.rb +57 -0
  166. data/lib/pubid/ccsds/single_identifier.rb +74 -0
  167. data/lib/pubid/ccsds/supplement_identifier.rb +33 -0
  168. data/lib/pubid/ccsds/urn_generator.rb +115 -0
  169. data/lib/pubid/ccsds.rb +21 -0
  170. data/lib/pubid/cen_cenelec/builder.rb +330 -0
  171. data/lib/pubid/cen_cenelec/identifier.rb +15 -0
  172. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +40 -0
  173. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +29 -0
  174. data/lib/pubid/cen_cenelec/identifiers/base.rb +75 -0
  175. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +28 -0
  176. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +27 -0
  177. data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +28 -0
  178. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +61 -0
  179. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +35 -0
  180. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +41 -0
  181. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +37 -0
  182. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +28 -0
  183. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +22 -0
  184. data/lib/pubid/cen_cenelec/identifiers/guide.rb +27 -0
  185. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +27 -0
  186. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +27 -0
  187. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +35 -0
  188. data/lib/pubid/cen_cenelec/identifiers.rb +32 -0
  189. data/lib/pubid/cen_cenelec/parser.rb +144 -0
  190. data/lib/pubid/cen_cenelec/scheme.rb +164 -0
  191. data/lib/pubid/cen_cenelec/single_identifier.rb +130 -0
  192. data/lib/pubid/cen_cenelec/supplement_identifier.rb +48 -0
  193. data/lib/pubid/cen_cenelec/urn_generator.rb +129 -0
  194. data/lib/pubid/cen_cenelec.rb +21 -0
  195. data/lib/pubid/cie/builder.rb +399 -0
  196. data/lib/pubid/cie/components/code.rb +72 -0
  197. data/lib/pubid/cie/components/language.rb +58 -0
  198. data/lib/pubid/cie/identifier.rb +18 -0
  199. data/lib/pubid/cie/identifiers/bundle.rb +20 -0
  200. data/lib/pubid/cie/identifiers/conference.rb +32 -0
  201. data/lib/pubid/cie/identifiers/corrigendum.rb +40 -0
  202. data/lib/pubid/cie/identifiers/dual_published.rb +41 -0
  203. data/lib/pubid/cie/identifiers/identical.rb +64 -0
  204. data/lib/pubid/cie/identifiers/joint_published.rb +52 -0
  205. data/lib/pubid/cie/identifiers/standard.rb +58 -0
  206. data/lib/pubid/cie/identifiers/supplement.rb +45 -0
  207. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +20 -0
  208. data/lib/pubid/cie/identifiers.rb +17 -0
  209. data/lib/pubid/cie/parser.rb +347 -0
  210. data/lib/pubid/cie/scheme.rb +64 -0
  211. data/lib/pubid/cie/single_identifier.rb +30 -0
  212. data/lib/pubid/cie/supplement_identifier.rb +26 -0
  213. data/lib/pubid/cie/urn_generator.rb +123 -0
  214. data/lib/pubid/cie.rb +28 -0
  215. data/lib/pubid/components/code.rb +33 -0
  216. data/lib/pubid/components/date.rb +49 -0
  217. data/lib/pubid/components/edition.rb +32 -0
  218. data/lib/pubid/components/language.rb +37 -0
  219. data/lib/pubid/components/locality.rb +10 -0
  220. data/lib/pubid/components/publisher.rb +36 -0
  221. data/lib/pubid/components/stage.rb +54 -0
  222. data/lib/pubid/components/type.rb +58 -0
  223. data/lib/pubid/components/typed_stage.rb +55 -0
  224. data/lib/pubid/components.rb +15 -0
  225. data/lib/pubid/core/pattern_doc_generator.rb +272 -0
  226. data/lib/pubid/core/update_codes.rb +77 -0
  227. data/lib/pubid/core.rb +8 -0
  228. data/lib/pubid/csa/builder.rb +671 -0
  229. data/lib/pubid/csa/components/code.rb +9 -0
  230. data/lib/pubid/csa/components.rb +9 -0
  231. data/lib/pubid/csa/composite_identifier.rb +27 -0
  232. data/lib/pubid/csa/identifier.rb +457 -0
  233. data/lib/pubid/csa/identifiers/base.rb +133 -0
  234. data/lib/pubid/csa/identifiers/bundled.rb +125 -0
  235. data/lib/pubid/csa/identifiers/canadian_adopted.rb +82 -0
  236. data/lib/pubid/csa/identifiers/cec.rb +129 -0
  237. data/lib/pubid/csa/identifiers/combined.rb +130 -0
  238. data/lib/pubid/csa/identifiers/csa_adopted.rb +78 -0
  239. data/lib/pubid/csa/identifiers/package.rb +65 -0
  240. data/lib/pubid/csa/identifiers/series.rb +127 -0
  241. data/lib/pubid/csa/identifiers/standard.rb +10 -0
  242. data/lib/pubid/csa/identifiers.rb +17 -0
  243. data/lib/pubid/csa/parser.rb +445 -0
  244. data/lib/pubid/csa/scheme.rb +44 -0
  245. data/lib/pubid/csa/single_identifier.rb +30 -0
  246. data/lib/pubid/csa/urn_generator.rb +80 -0
  247. data/lib/pubid/csa/wrapper_identifier.rb +31 -0
  248. data/lib/pubid/csa.rb +25 -0
  249. data/lib/pubid/etsi/builder.rb +133 -0
  250. data/lib/pubid/etsi/components/code.rb +42 -0
  251. data/lib/pubid/etsi/components/version.rb +37 -0
  252. data/lib/pubid/etsi/components.rb +10 -0
  253. data/lib/pubid/etsi/identifier.rb +14 -0
  254. data/lib/pubid/etsi/identifiers/amendment.rb +15 -0
  255. data/lib/pubid/etsi/identifiers/base.rb +38 -0
  256. data/lib/pubid/etsi/identifiers/corrigendum.rb +15 -0
  257. data/lib/pubid/etsi/identifiers/etsi_standard.rb +19 -0
  258. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +91 -0
  259. data/lib/pubid/etsi/identifiers.rb +14 -0
  260. data/lib/pubid/etsi/parser.rb +133 -0
  261. data/lib/pubid/etsi/scheme.rb +42 -0
  262. data/lib/pubid/etsi/urn_generator.rb +76 -0
  263. data/lib/pubid/etsi.rb +21 -0
  264. data/lib/pubid/export/auditor.rb +89 -0
  265. data/lib/pubid/export/data_class_exporter.rb +59 -0
  266. data/lib/pubid/export/exporter.rb +74 -0
  267. data/lib/pubid/export/flavor_exporter.rb +402 -0
  268. data/lib/pubid/export/ieee_exporter.rb +78 -0
  269. data/lib/pubid/export/itu_exporter.rb +66 -0
  270. data/lib/pubid/export/nist_exporter.rb +64 -0
  271. data/lib/pubid/export/registry_exporter.rb +90 -0
  272. data/lib/pubid/export/result.rb +97 -0
  273. data/lib/pubid/export/scheme_exporter.rb +70 -0
  274. data/lib/pubid/export.rb +18 -0
  275. data/lib/pubid/format_detector.rb +16 -0
  276. data/lib/pubid/format_registry.rb +42 -0
  277. data/lib/pubid/identifier.rb +235 -0
  278. data/lib/pubid/identifier_metadata.rb +148 -0
  279. data/lib/pubid/identifier_registry.rb +198 -0
  280. data/lib/pubid/idf/builder.rb +82 -0
  281. data/lib/pubid/idf/identifier.rb +69 -0
  282. data/lib/pubid/idf/identifiers/amendment.rb +27 -0
  283. data/lib/pubid/idf/identifiers/corrigendum.rb +27 -0
  284. data/lib/pubid/idf/identifiers/international_standard.rb +123 -0
  285. data/lib/pubid/idf/identifiers/reviewed_method.rb +100 -0
  286. data/lib/pubid/idf/identifiers.rb +13 -0
  287. data/lib/pubid/idf/parser.rb +143 -0
  288. data/lib/pubid/idf/scheme.rb +61 -0
  289. data/lib/pubid/idf/single_identifier.rb +19 -0
  290. data/lib/pubid/idf/supplement_identifier.rb +43 -0
  291. data/lib/pubid/idf/urn_generator.rb +84 -0
  292. data/lib/pubid/idf.rb +25 -0
  293. data/lib/pubid/iec/builder.rb +457 -0
  294. data/lib/pubid/iec/components/code.rb +59 -0
  295. data/lib/pubid/iec/components/consolidated_amendment.rb +59 -0
  296. data/lib/pubid/iec/components/publisher.rb +35 -0
  297. data/lib/pubid/iec/components/sheet.rb +32 -0
  298. data/lib/pubid/iec/components/trf_info.rb +38 -0
  299. data/lib/pubid/iec/components/vap_suffix.rb +41 -0
  300. data/lib/pubid/iec/identifier.rb +21 -0
  301. data/lib/pubid/iec/identifiers/amendment.rb +94 -0
  302. data/lib/pubid/iec/identifiers/base.rb +78 -0
  303. data/lib/pubid/iec/identifiers/component_specification.rb +39 -0
  304. data/lib/pubid/iec/identifiers/conformity_assessment.rb +39 -0
  305. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +86 -0
  306. data/lib/pubid/iec/identifiers/corrigendum.rb +94 -0
  307. data/lib/pubid/iec/identifiers/fragment_identifier.rb +141 -0
  308. data/lib/pubid/iec/identifiers/guide.rb +104 -0
  309. data/lib/pubid/iec/identifiers/international_standard.rb +147 -0
  310. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +104 -0
  311. data/lib/pubid/iec/identifiers/operational_document.rb +39 -0
  312. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +101 -0
  313. data/lib/pubid/iec/identifiers/sheet_identifier.rb +66 -0
  314. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +40 -0
  315. data/lib/pubid/iec/identifiers/systems_reference_document.rb +40 -0
  316. data/lib/pubid/iec/identifiers/technical_report.rb +132 -0
  317. data/lib/pubid/iec/identifiers/technical_specification.rb +132 -0
  318. data/lib/pubid/iec/identifiers/technology_report.rb +39 -0
  319. data/lib/pubid/iec/identifiers/test_report_form.rb +78 -0
  320. data/lib/pubid/iec/identifiers/vap_identifier.rb +77 -0
  321. data/lib/pubid/iec/identifiers/white_paper.rb +39 -0
  322. data/lib/pubid/iec/identifiers/working_document.rb +96 -0
  323. data/lib/pubid/iec/parser.rb +412 -0
  324. data/lib/pubid/iec/rendering_style.rb +113 -0
  325. data/lib/pubid/iec/scheme.rb +71 -0
  326. data/lib/pubid/iec/single_identifier.rb +80 -0
  327. data/lib/pubid/iec/supplement_identifier.rb +161 -0
  328. data/lib/pubid/iec/urn_generator.rb +193 -0
  329. data/lib/pubid/iec/urn_parser.rb +289 -0
  330. data/lib/pubid/iec.rb +85 -0
  331. data/lib/pubid/ieee/aiee/builder.rb +71 -0
  332. data/lib/pubid/ieee/aiee/identifier.rb +105 -0
  333. data/lib/pubid/ieee/aiee/parser.rb +130 -0
  334. data/lib/pubid/ieee/aiee.rb +11 -0
  335. data/lib/pubid/ieee/builder.rb +1237 -0
  336. data/lib/pubid/ieee/components/code.rb +102 -0
  337. data/lib/pubid/ieee/components/draft.rb +93 -0
  338. data/lib/pubid/ieee/components/relationship.rb +157 -0
  339. data/lib/pubid/ieee/components/typed_stage.rb +100 -0
  340. data/lib/pubid/ieee/identifier.rb +13 -0
  341. data/lib/pubid/ieee/identifiers/adopted_standard.rb +33 -0
  342. data/lib/pubid/ieee/identifiers/base.rb +591 -0
  343. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +35 -0
  344. data/lib/pubid/ieee/identifiers/corrigendum.rb +37 -0
  345. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +51 -0
  346. data/lib/pubid/ieee/identifiers/dual_identifier.rb +18 -0
  347. data/lib/pubid/ieee/identifiers/dual_published.rb +28 -0
  348. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +27 -0
  349. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +34 -0
  350. data/lib/pubid/ieee/identifiers/joint_development.rb +172 -0
  351. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +51 -0
  352. data/lib/pubid/ieee/identifiers/nesc/base.rb +56 -0
  353. data/lib/pubid/ieee/identifiers/nesc/draft.rb +28 -0
  354. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +32 -0
  355. data/lib/pubid/ieee/identifiers/nesc/redline.rb +26 -0
  356. data/lib/pubid/ieee/identifiers/nesc/standard.rb +26 -0
  357. data/lib/pubid/ieee/identifiers/nesc.rb +15 -0
  358. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +20 -0
  359. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +26 -0
  360. data/lib/pubid/ieee/identifiers/redlined_standard.rb +33 -0
  361. data/lib/pubid/ieee/identifiers/si_standard.rb +73 -0
  362. data/lib/pubid/ieee/identifiers/standard.rb +41 -0
  363. data/lib/pubid/ieee/identifiers/supplement_identifier.rb +23 -0
  364. data/lib/pubid/ieee/identifiers.rb +33 -0
  365. data/lib/pubid/ieee/ire/builder.rb +61 -0
  366. data/lib/pubid/ieee/ire/identifier.rb +58 -0
  367. data/lib/pubid/ieee/ire/parser.rb +91 -0
  368. data/lib/pubid/ieee/ire.rb +11 -0
  369. data/lib/pubid/ieee/nesc/builder.rb +101 -0
  370. data/lib/pubid/ieee/nesc/parser.rb +154 -0
  371. data/lib/pubid/ieee/nesc.rb +10 -0
  372. data/lib/pubid/ieee/parser.rb +1226 -0
  373. data/lib/pubid/ieee/scheme.rb +90 -0
  374. data/lib/pubid/ieee/typed_stages.rb +172 -0
  375. data/lib/pubid/ieee/urn_generator.rb +188 -0
  376. data/lib/pubid/ieee.rb +32 -0
  377. data/lib/pubid/ieee_debug.rb +31 -0
  378. data/lib/pubid/iho/builder.rb +37 -0
  379. data/lib/pubid/iho/identifier.rb +19 -0
  380. data/lib/pubid/iho/identifiers/base.rb +41 -0
  381. data/lib/pubid/iho/identifiers/bibliographic.rb +20 -0
  382. data/lib/pubid/iho/identifiers/circular_letter.rb +19 -0
  383. data/lib/pubid/iho/identifiers/miscellaneous.rb +20 -0
  384. data/lib/pubid/iho/identifiers/publication.rb +19 -0
  385. data/lib/pubid/iho/identifiers/standard.rb +19 -0
  386. data/lib/pubid/iho/identifiers.rb +14 -0
  387. data/lib/pubid/iho/parser.rb +68 -0
  388. data/lib/pubid/iho/scheme.rb +29 -0
  389. data/lib/pubid/iho/urn_generator.rb +29 -0
  390. data/lib/pubid/iho.rb +21 -0
  391. data/lib/pubid/iso/builder.rb +305 -0
  392. data/lib/pubid/iso/bundled_identifier.rb +85 -0
  393. data/lib/pubid/iso/combined_identifier.rb +22 -0
  394. data/lib/pubid/iso/components/code.rb +36 -0
  395. data/lib/pubid/iso/components/publisher.rb +60 -0
  396. data/lib/pubid/iso/components.rb +12 -0
  397. data/lib/pubid/iso/format_resolver.rb +45 -0
  398. data/lib/pubid/iso/identifier.rb +69 -0
  399. data/lib/pubid/iso/identifiers/addendum.rb +104 -0
  400. data/lib/pubid/iso/identifiers/amendment.rb +128 -0
  401. data/lib/pubid/iso/identifiers/base.rb +115 -0
  402. data/lib/pubid/iso/identifiers/corrigendum.rb +108 -0
  403. data/lib/pubid/iso/identifiers/data.rb +76 -0
  404. data/lib/pubid/iso/identifiers/directives.rb +59 -0
  405. data/lib/pubid/iso/identifiers/directives_supplement.rb +119 -0
  406. data/lib/pubid/iso/identifiers/extract.rb +30 -0
  407. data/lib/pubid/iso/identifiers/guide.rb +100 -0
  408. data/lib/pubid/iso/identifiers/international_standard.rb +168 -0
  409. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +94 -0
  410. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +89 -0
  411. data/lib/pubid/iso/identifiers/pas.rb +93 -0
  412. data/lib/pubid/iso/identifiers/recommendation.rb +45 -0
  413. data/lib/pubid/iso/identifiers/supplement.rb +87 -0
  414. data/lib/pubid/iso/identifiers/tc_document.rb +108 -0
  415. data/lib/pubid/iso/identifiers/technical_report.rb +103 -0
  416. data/lib/pubid/iso/identifiers/technical_specification.rb +102 -0
  417. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +95 -0
  418. data/lib/pubid/iso/identifiers.rb +33 -0
  419. data/lib/pubid/iso/parser.rb +510 -0
  420. data/lib/pubid/iso/rendering_style.rb +120 -0
  421. data/lib/pubid/iso/scheme.rb +187 -0
  422. data/lib/pubid/iso/single_identifier.rb +61 -0
  423. data/lib/pubid/iso/supplement_identifier.rb +27 -0
  424. data/lib/pubid/iso/urn_generator.rb +412 -0
  425. data/lib/pubid/iso/urn_parser.rb +423 -0
  426. data/lib/pubid/iso/utilities.rb +86 -0
  427. data/lib/pubid/iso.rb +50 -0
  428. data/lib/pubid/itu/builder.rb +171 -0
  429. data/lib/pubid/itu/components/code.rb +39 -0
  430. data/lib/pubid/itu/components/sector.rb +35 -0
  431. data/lib/pubid/itu/components/series.rb +29 -0
  432. data/lib/pubid/itu/i18n.rb +9 -0
  433. data/lib/pubid/itu/i18n.yaml +30 -0
  434. data/lib/pubid/itu/identifier.rb +53 -0
  435. data/lib/pubid/itu/identifiers/amendment.rb +43 -0
  436. data/lib/pubid/itu/identifiers/annex.rb +74 -0
  437. data/lib/pubid/itu/identifiers/base.rb +154 -0
  438. data/lib/pubid/itu/identifiers/combined_identifier.rb +47 -0
  439. data/lib/pubid/itu/identifiers/corrigendum.rb +44 -0
  440. data/lib/pubid/itu/identifiers/recommendation.rb +16 -0
  441. data/lib/pubid/itu/identifiers/special_publication.rb +31 -0
  442. data/lib/pubid/itu/identifiers/supplement.rb +46 -0
  443. data/lib/pubid/itu/identifiers.rb +16 -0
  444. data/lib/pubid/itu/model.rb +111 -0
  445. data/lib/pubid/itu/parser.rb +225 -0
  446. data/lib/pubid/itu/scheme.rb +174 -0
  447. data/lib/pubid/itu/urn_generator.rb +105 -0
  448. data/lib/pubid/itu.rb +22 -0
  449. data/lib/pubid/jcgm/builder.rb +88 -0
  450. data/lib/pubid/jcgm/components/publisher.rb +20 -0
  451. data/lib/pubid/jcgm/components.rb +9 -0
  452. data/lib/pubid/jcgm/identifier.rb +11 -0
  453. data/lib/pubid/jcgm/identifiers/amendment.rb +35 -0
  454. data/lib/pubid/jcgm/identifiers/guide.rb +21 -0
  455. data/lib/pubid/jcgm/identifiers/gum_guide.rb +51 -0
  456. data/lib/pubid/jcgm/identifiers.rb +11 -0
  457. data/lib/pubid/jcgm/parser.rb +84 -0
  458. data/lib/pubid/jcgm/scheme.rb +60 -0
  459. data/lib/pubid/jcgm/single_identifier.rb +48 -0
  460. data/lib/pubid/jcgm/supplement_identifier.rb +16 -0
  461. data/lib/pubid/jcgm/urn_generator.rb +110 -0
  462. data/lib/pubid/jcgm.rb +31 -0
  463. data/lib/pubid/jis/builder.rb +124 -0
  464. data/lib/pubid/jis/components/code.rb +59 -0
  465. data/lib/pubid/jis/components.rb +9 -0
  466. data/lib/pubid/jis/identifier.rb +18 -0
  467. data/lib/pubid/jis/identifiers/amendment.rb +16 -0
  468. data/lib/pubid/jis/identifiers/base.rb +72 -0
  469. data/lib/pubid/jis/identifiers/explanation.rb +22 -0
  470. data/lib/pubid/jis/identifiers/japanese_industrial_standard.rb +16 -0
  471. data/lib/pubid/jis/identifiers/standard.rb +27 -0
  472. data/lib/pubid/jis/identifiers/technical_report.rb +31 -0
  473. data/lib/pubid/jis/identifiers/technical_specification.rb +31 -0
  474. data/lib/pubid/jis/identifiers.rb +17 -0
  475. data/lib/pubid/jis/parser.rb +109 -0
  476. data/lib/pubid/jis/scheme.rb +49 -0
  477. data/lib/pubid/jis/single_identifier.rb +37 -0
  478. data/lib/pubid/jis/supplement_identifier.rb +47 -0
  479. data/lib/pubid/jis/urn_generator.rb +25 -0
  480. data/lib/pubid/jis.rb +23 -0
  481. data/lib/pubid/lutaml/no_store_registration.rb +30 -0
  482. data/lib/pubid/nist/builder.rb +2100 -0
  483. data/lib/pubid/nist/components/code.rb +38 -0
  484. data/lib/pubid/nist/components/edition.rb +118 -0
  485. data/lib/pubid/nist/components/issue_number.rb +28 -0
  486. data/lib/pubid/nist/components/part.rb +77 -0
  487. data/lib/pubid/nist/components/publisher.rb +24 -0
  488. data/lib/pubid/nist/components/stage.rb +53 -0
  489. data/lib/pubid/nist/components/supplement.rb +121 -0
  490. data/lib/pubid/nist/components/translation.rb +42 -0
  491. data/lib/pubid/nist/components/update.rb +103 -0
  492. data/lib/pubid/nist/components/version.rb +35 -0
  493. data/lib/pubid/nist/components/volume.rb +32 -0
  494. data/lib/pubid/nist/components.rb +19 -0
  495. data/lib/pubid/nist/configuration.rb +77 -0
  496. data/lib/pubid/nist/identifiers/base.rb +499 -0
  497. data/lib/pubid/nist/identifiers/circular.rb +68 -0
  498. data/lib/pubid/nist/identifiers/circular_supplement.rb +50 -0
  499. data/lib/pubid/nist/identifiers/commercial_standard.rb +41 -0
  500. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +56 -0
  501. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +56 -0
  502. data/lib/pubid/nist/identifiers/crpl_report.rb +135 -0
  503. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +94 -0
  504. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +35 -0
  505. data/lib/pubid/nist/identifiers/handbook.rb +50 -0
  506. data/lib/pubid/nist/identifiers/internal_report.rb +56 -0
  507. data/lib/pubid/nist/identifiers/letter_circular.rb +45 -0
  508. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +65 -0
  509. data/lib/pubid/nist/identifiers/monograph.rb +69 -0
  510. data/lib/pubid/nist/identifiers/ncstar.rb +41 -0
  511. data/lib/pubid/nist/identifiers/nsrds.rb +41 -0
  512. data/lib/pubid/nist/identifiers/owmwp.rb +35 -0
  513. data/lib/pubid/nist/identifiers/report.rb +68 -0
  514. data/lib/pubid/nist/identifiers/special_publication.rb +36 -0
  515. data/lib/pubid/nist/identifiers/technical_note.rb +90 -0
  516. data/lib/pubid/nist/identifiers.rb +33 -0
  517. data/lib/pubid/nist/parser.rb +1084 -0
  518. data/lib/pubid/nist/scheme.rb +199 -0
  519. data/lib/pubid/nist/supplement_identifier.rb +83 -0
  520. data/lib/pubid/nist/urn_generator.rb +127 -0
  521. data/lib/pubid/nist.rb +36 -0
  522. data/lib/pubid/oiml/builder.rb +189 -0
  523. data/lib/pubid/oiml/components/code.rb +20 -0
  524. data/lib/pubid/oiml/components.rb +9 -0
  525. data/lib/pubid/oiml/identifier.rb +11 -0
  526. data/lib/pubid/oiml/identifiers/amendment.rb +13 -0
  527. data/lib/pubid/oiml/identifiers/annex.rb +62 -0
  528. data/lib/pubid/oiml/identifiers/base.rb +36 -0
  529. data/lib/pubid/oiml/identifiers/basic_publication.rb +13 -0
  530. data/lib/pubid/oiml/identifiers/document.rb +13 -0
  531. data/lib/pubid/oiml/identifiers/expert_report.rb +13 -0
  532. data/lib/pubid/oiml/identifiers/guide.rb +13 -0
  533. data/lib/pubid/oiml/identifiers/recommendation.rb +13 -0
  534. data/lib/pubid/oiml/identifiers/seminar_report.rb +13 -0
  535. data/lib/pubid/oiml/identifiers/vocabulary.rb +13 -0
  536. data/lib/pubid/oiml/identifiers.rb +18 -0
  537. data/lib/pubid/oiml/parser.rb +173 -0
  538. data/lib/pubid/oiml/scheme.rb +46 -0
  539. data/lib/pubid/oiml/single_identifier.rb +90 -0
  540. data/lib/pubid/oiml/supplement_identifier.rb +43 -0
  541. data/lib/pubid/oiml/urn_generator.rb +64 -0
  542. data/lib/pubid/oiml.rb +26 -0
  543. data/lib/pubid/parser/common_parse_methods.rb +13 -0
  544. data/lib/pubid/parser/common_parse_rules.rb +56 -0
  545. data/lib/pubid/parser.rb +8 -0
  546. data/lib/pubid/parsers/base.rb +11 -0
  547. data/lib/pubid/parsers/mr_string.rb +93 -0
  548. data/lib/pubid/plateau/builder.rb +50 -0
  549. data/lib/pubid/plateau/identifiers/annex.rb +16 -0
  550. data/lib/pubid/plateau/identifiers/base.rb +51 -0
  551. data/lib/pubid/plateau/identifiers/handbook.rb +34 -0
  552. data/lib/pubid/plateau/identifiers/technical_report.rb +20 -0
  553. data/lib/pubid/plateau/identifiers.rb +12 -0
  554. data/lib/pubid/plateau/parser.rb +63 -0
  555. data/lib/pubid/plateau/scheme.rb +45 -0
  556. data/lib/pubid/plateau/supplement_identifier.rb +72 -0
  557. data/lib/pubid/plateau/urn_generator.rb +29 -0
  558. data/lib/pubid/plateau.rb +25 -0
  559. data/lib/pubid/renderers/base.rb +19 -0
  560. data/lib/pubid/renderers/directives_renderer.rb +62 -0
  561. data/lib/pubid/renderers/guide_renderer.rb +20 -0
  562. data/lib/pubid/renderers/human_readable.rb +58 -0
  563. data/lib/pubid/renderers/iwa_renderer.rb +16 -0
  564. data/lib/pubid/renderers/mr_string.rb +16 -0
  565. data/lib/pubid/renderers/supplement_renderer.rb +33 -0
  566. data/lib/pubid/renderers/urn.rb +11 -0
  567. data/lib/pubid/renderers.rb +14 -0
  568. data/lib/pubid/rendering/base.rb +73 -0
  569. data/lib/pubid/rendering/common.rb +211 -0
  570. data/lib/pubid/rendering/context.rb +156 -0
  571. data/lib/pubid/rendering/date.rb +27 -0
  572. data/lib/pubid/rendering/format.rb +25 -0
  573. data/lib/pubid/rendering/language.rb +21 -0
  574. data/lib/pubid/rendering/numbering.rb +24 -0
  575. data/lib/pubid/rendering/publisher.rb +25 -0
  576. data/lib/pubid/rendering/stage.rb +38 -0
  577. data/lib/pubid/rendering/supplement.rb +46 -0
  578. data/lib/pubid/rendering.rb +16 -0
  579. data/lib/pubid/sae/builder.rb +32 -0
  580. data/lib/pubid/sae/components/code.rb +9 -0
  581. data/lib/pubid/sae/components/date.rb +19 -0
  582. data/lib/pubid/sae/components/type.rb +19 -0
  583. data/lib/pubid/sae/components.rb +11 -0
  584. data/lib/pubid/sae/identifier.rb +14 -0
  585. data/lib/pubid/sae/identifiers/base.rb +42 -0
  586. data/lib/pubid/sae/identifiers.rb +9 -0
  587. data/lib/pubid/sae/parser.rb +55 -0
  588. data/lib/pubid/sae/scheme.rb +47 -0
  589. data/lib/pubid/sae/urn_generator.rb +38 -0
  590. data/lib/pubid/sae.rb +19 -0
  591. data/lib/pubid/scheme.rb +207 -0
  592. data/lib/pubid/urn_generator/base.rb +110 -0
  593. data/lib/pubid/utils/string_normalizer.rb +196 -0
  594. data/lib/pubid/utils.rb +7 -0
  595. data/lib/pubid/version.rb +3 -1
  596. data/lib/pubid.rb +137 -13
  597. data/lib/tasks/docs.rake +37 -0
  598. data/lib/tasks/export.rake +38 -0
  599. data/lib/tasks/website-data.json +7488 -0
  600. metadata +613 -171
  601. data/lib/pubid/registry.rb +0 -30
data/README.adoc CHANGED
@@ -1,82 +1,2070 @@
1
- = Publication identifiers library
1
+ = PubID: Interoperable identifiers for information resources
2
2
 
3
- image:https://badge.fury.io/rb/pubid.svg["Gem Version", link="https://badge.fury.io/rb/pubid"]
3
+ image:https://img.shields.io/gem/v/pubid-core.svg["pubid-core Gem Version", link="https://rubygems.org/gems/pubid-core"]
4
+ image:https://github.com/metanorma/pubid/actions/workflows/rake.yml/badge.svg["Build Status", link="https://github.com/metanorma/pubid/actions/workflows/rake.yml"]
5
+ image:https://img.shields.io/github/issues-pr-raw/metanorma/pubid.svg["Pull Requests", link="https://github.com/metanorma/pubid/pulls"]
6
+ image:https://img.shields.io/github/commits-since/metanorma/pubid/latest.svg["Commits since latest",link="https://github.com/metanorma/pubid/releases"]
4
7
 
5
- Pubid is a comprehensive framework for building and working with publication identifiers. It provides a robust API for creating, modifying, parsing, exporting, and verifying document identifiers, which are crucial for various document management systems and standards compliance
8
+ == Badges
6
9
 
7
- This gem includes all pubid-* gems for compatibility testing and allows parsing all identifiers from one gem.
10
+ [cols="3*", options="header"]
11
+ |===
12
+ | Core & Meta | Standards Organizations | Regional Standards
8
13
 
9
- == Current use cases
10
- The current use cases, as listed below, are what we have needed until now and have discovered through use of pubid to pubid-*, metanorma-*, and relaton-* projects. Work on pubid is not complete and will be expanding during the ongoing integration process.
14
+ | pubid image:https://img.shields.io/gem/v/pubid.svg["pubid", link="https://rubygems.org/gems/pubid"]
15
+ | pubid-iso image:https://img.shields.io/gem/v/pubid-iso.svg["pubid-iso", link="https://rubygems.org/gems/pubid-iso"]
16
+ | pubid-cen image:https://img.shields.io/gem/v/pubid-cen.svg["pubid-cen", link="https://rubygems.org/gems/pubid-cen"]
11
17
 
12
- - building identifiers from scratch
13
- - modifiying identifiers (e.g. basing an amendment identifier on a base identifier)
14
- - parsing string identifiers
15
- - exporting/importing to different formats or styles (hash, yaml, URN, etc.)
16
- - verification of compliance for the identifier's representation standard (NIST PubID 1.0 for NIST, RFC 5141 for ISO URN), or using commonly found patterns
17
- - verifying that a provided identifier is correct
18
- - comparing two provided identifiers (with the option to exclude specified attributes)
19
- - converting legacy identifiers to updated format
18
+ | pubid-core image:https://img.shields.io/gem/v/pubid-core.svg["pubid-core", link="https://rubygems.org/gems/pubid-core"]
19
+ | pubid-iec image:https://img.shields.io/gem/v/pubid-iec.svg["pubid-iec", link="https://rubygems.org/gems/pubid-iec"]
20
+ | pubid-bsi image:https://img.shields.io/gem/v/pubid-bsi.svg["pubid-bsi", link="https://rubygems.org/gems/pubid-bsi"]
20
21
 
21
- == Purpose and Usage Guidelines
22
+ |
23
+ | pubid-ieee image:https://img.shields.io/gem/v/pubid-ieee.svg["pubid-ieee", link="https://rubygems.org/gems/pubid-ieee"]
24
+ | pubid-jis image:https://img.shields.io/gem/v/pubid-jis.svg["pubid-jis", link="https://rubygems.org/gems/pubid-jis"]
22
25
 
23
- The pubid library is intended to be used wherever operations on publication identifiers are required. It acts as an intermediary between users and publication identifiers, streamlining the processes of creation, modification, comparison, and attribute access. By centralizing these operations in pubid-core, we ensure that any updates to identifier standards are seamlessly integrated across all related projects in an ecosystem.
26
+ |
27
+ | pubid-nist image:https://img.shields.io/gem/v/pubid-nist.svg["pubid-nist", link="https://rubygems.org/gems/pubid-nist"]
28
+ |
29
+
30
+ |
31
+ | pubid-etsi image:https://img.shields.io/gem/v/pubid-etsi.svg["pubid-etsi", link="https://rubygems.org/gems/pubid-etsi"]
32
+ |
33
+
34
+ |
35
+ | pubid-itu image:https://img.shields.io/gem/v/pubid-itu.svg["pubid-itu", link="https://rubygems.org/gems/pubid-itu"]
36
+ |
37
+
38
+ |
39
+ | pubid-ccsds image:https://img.shields.io/gem/v/pubid-ccsds.svg["pubid-ccsds", link="https://rubygems.org/gems/pubid-ccsds"]
40
+ |
41
+
42
+ |
43
+ | pubid-plateau image:https://img.shields.io/gem/v/pubid-plateau.svg["pubid-plateau", link="https://rubygems.org/gems/pubid-plateau"]
44
+ |
45
+ |===
46
+
47
+ == Quick Start
48
+
49
+ [source,ruby]
50
+ ----
51
+ gem install pubid-core
52
+
53
+ require 'pubid/iso'
54
+
55
+ # Parse an identifier
56
+ id = Pubid::Iso.parse("ISO 9001:2015/Amd 1:2020")
57
+
58
+ # Access components
59
+ id.publisher.body # => "ISO"
60
+ id.number.number # => "9001"
61
+
62
+ # Render back to string (round-trip)
63
+ id.to_s # => "ISO 9001:2015/Amd 1:2020"
64
+
65
+ # Generate URN
66
+ id.to_urn # => "urn:iso:std:iso:9001:amd:2020:v1"
67
+ ----
68
+
69
+ == Overview
70
+
71
+ The PubID project promotes the use of interoperable identifiers across various
72
+ domains, including ISO, IEC, NIST, and more.
73
+
74
+ The core of PubID is an identifier information model that allows a publisher
75
+ to build a human- and machine-readable identification scheme for the
76
+ unique identification of documents, standards, and other resources.
77
+
78
+ This identification scheme is designed to facilitate interoperability and data
79
+ exchange between systems and organizations by providing a consistent way to
80
+ identify, reference and utilize these resources.
81
+
82
+ A PubID typically incorporates various components, such as a mixture of an
83
+ organizational prefix, document type, document stage, edition or version number,
84
+ and other relevant information.
85
+
86
+ The key feature that a PubID provides is the ability to represent
87
+ identifiers in a structured format that can be easily parsed and understood by
88
+ both humans and machines, in a round-trippable manner.
89
+
90
+
91
+ See <<v2-migration-status>> for detailed status and <<v2-usage-examples>> for examples.
92
+
93
+ == URN Generation (RFC 5141-bis)
94
+
95
+ PubID V2 implements RFC 5141-bis compliant URN generation for ISO and IEC identifiers with **full test coverage**.
96
+
97
+ [source,ruby]
98
+ ----
99
+ require 'pubid/iso'
100
+ require 'pubid/iec'
101
+
102
+ # ISO: Parse and generate URN
103
+ id = Pubid::Iso.parse("ISO/IEC 13818-1:2015/Amd 3:2016")
104
+ id.to_urn
105
+ # => "urn:iso:std:iso-iec:13818:-1:amd:2016:v3"
106
+
107
+ # IEC: Parse and generate URN
108
+ id = Pubid::Iec.parse("IEC 60068-2-2:1974/Amd 1:1993")
109
+ id.to_urn
110
+ # => "urn:iec:std:iec:60068-2-2:1974:amd:1993:v1"
111
+
112
+ # Round-trip: parse URN back to identifier
113
+ id = Pubid::Iso.parse_urn("urn:iso:std:iso:9001:amd:2020:v1")
114
+ id.to_s # => "ISO 9001/Amd 1:2020"
115
+ id.to_urn # => "urn:iso:std:iso:9001:amd:2020:v1"
116
+ ----
117
+
118
+ === Features
119
+
120
+ * ✅ RFC 5141-bis compliant for ISO URNs
121
+ * ✅ IEC URN model compliant (IEC URI Model 2020-03-24)
122
+ * ✅ Explicit language codes, always lowercase in URN output
123
+ * ✅ Dynamic copublisher combinations (ISO/IEC/IEEE, ISO/ASTM, etc.)
124
+ * ✅ Extended document types (DIR, DIR-SUP, IWA-SUP, TTA)
125
+ * ✅ Typed stage codes (WD, CD, DIS, FDIS, PDAM, FDAM, etc.)
126
+ * ✅ Harmonized stage codes (stage-XX.XX format)
127
+ * ✅ Multi-level supplement support with correct nesting order
128
+ * ✅ Round-trip parsing (parse_urn -> to_urn) for ISO and IEC
129
+
130
+ === Key Difference: ISO vs IEC Part Numbering
131
+
132
+ ISO URNs (RFC 5141): part number is a separate colon-separated field:
133
+ urn:iso:std:iso:8601:-1:2019
134
+
135
+ IEC URNs (IEC URI Model): part number is part of the docnumber field:
136
+ urn:iec:std:iec:60068-2-2:1974
137
+
138
+ === Documentation
139
+
140
+ See link:docs/URN-GENERATION-GUIDE.adoc[URN Generation Guide] for complete usage documentation.
141
+
142
+ See link:references/iso-urn-specification.adoc[ISO URN Specification] for the full RFC 5141-bis specification with ABNF grammar.
143
+
144
+ See link:references/iec-urn-specification.adoc[IEC URN Specification] for the full IEC URN model specification.
145
+
146
+ See link:docs/RFC-5141-BIS-COMPLIANCE-REPORT.md[RFC 5141-bis Compliance Report] for certification details and test coverage.
147
+
148
+ See link:docs/V2_ARCHITECTURE.adoc[V2 Architecture Guide] for architectural details including URN generation design.
149
+
150
+
151
+ == Machine-Readable Serialization
152
+
153
+ PubID V2 provides two-way machine-readable conversion for all identifiers, supporting round-trip conversion between human-readable and structured formats.
154
+
155
+ === Export to Hash
156
+
157
+ [source,ruby]
158
+ ----
159
+ require 'pubid/iso'
160
+
161
+ id = Pubid::Iso.parse("ISO 9001:2015/Amd 1:2020")
162
+ id.to_h
163
+ # => {
164
+ # flavor: "iso",
165
+ # type: "amendment",
166
+ # publisher: "ISO",
167
+ # number: "9001",
168
+ # year: "2015",
169
+ # supplements: [
170
+ # { type: "amendment", number: "1", year: "2020" }
171
+ # ],
172
+ # urn: "urn:iso:std:iso:9001:amd:2020:v1"
173
+ # }
174
+ ----
175
+
176
+ === Export to JSON
177
+
178
+ [source,ruby]
179
+ ----
180
+ require 'pubid/iso'
181
+
182
+ id = Pubid::Iso.parse("ISO 9001:2015")
183
+ id.to_json
184
+ # => '{"flavor":"iso","publisher":"ISO","number":"9001","year":"2015",...}'
185
+ ----
186
+
187
+ === Import from Hash
188
+
189
+ [source,ruby]
190
+ ----
191
+ require 'pubid/iso'
192
+
193
+ hash = {
194
+ flavor: "iso",
195
+ publisher: "ISO",
196
+ number: "9001",
197
+ year: "2015"
198
+ }
199
+ id = Pubid::Serializable.from_h(hash)
200
+ id.to_s # => "ISO 9001:2015"
201
+ ----
202
+
203
+ === Import from JSON
204
+
205
+ [source,ruby]
206
+ ----
207
+ require 'pubid/iso'
208
+
209
+ json = '{"flavor":"iso","publisher":"ISO","number":"9001","year":"2015"}'
210
+ id = Pubid::Serializable.from_json(json)
211
+ id.to_s # => "ISO 9001:2015"
212
+ ----
213
+
214
+ === Round-trip Conversion
215
+
216
+ All identifiers support full round-trip conversion preserving all attributes:
217
+
218
+ [source,ruby]
219
+ ----
220
+ require 'pubid/iso'
221
+
222
+ original = Pubid::Iso.parse("ISO 9001:2015/Amd 1:2020/Cor 1:2021")
223
+ hash = original.to_h
224
+ restored = Pubid::Serializable.from_h(hash)
225
+
226
+ restored.to_s # => "ISO 9001:2015/Amd 1:2020/Cor 1:2021"
227
+ restored.to_urn # => "urn:iso:std:iso:9001:amd:2020:cor:2021:v1"
228
+ ----
229
+
230
+ == Utility Methods
231
+
232
+ PubID V2 provides convenience methods for identifier manipulation and comparison.
233
+
234
+ === Excluding Attributes
235
+
236
+ The `exclude` method returns a copy of the identifier without specified attributes:
237
+
238
+ [source,ruby]
239
+ ----
240
+ require 'pubid/iso'
241
+
242
+ id = Pubid::Iso.parse("ISO 9001:2015/Amd 1:2020")
243
+ id.exclude(:supplements).to_s
244
+ # => "ISO 9001:2015"
245
+
246
+ id.exclude(:year, :part).to_s
247
+ # => "ISO 9001"
248
+ ----
249
+
250
+ === Comparing Editions
251
+
252
+ The `new_edition_of?` method checks if an identifier is a newer edition of the same document:
253
+
254
+ [source,ruby]
255
+ ----
256
+ require 'pubid/iso'
257
+
258
+ id1 = Pubid::Iso.parse("ISO 9001:2015")
259
+ id2 = Pubid::Iso.parse("ISO 9001:2019")
260
+
261
+ id2.new_edition_of?(id1) # => true
262
+ id1.new_edition_of?(id2) # => false
263
+
264
+ # Raises ArgumentError for different documents
265
+ id3 = Pubid::Iso.parse("ISO 9002:2019")
266
+ id3.new_edition_of?(id1) # => ArgumentError: Cannot compare edition: different number
267
+ ----
268
+
269
+ === Getting Root Identifier
270
+
271
+ The `root` method traverses supplement chains to return the base document:
272
+
273
+ [source,ruby]
274
+ ----
275
+ require 'pubid/iso'
276
+
277
+ id = Pubid::Iso.parse("ISO 9001:2015/Amd 1:2020/Cor 1:2021")
278
+ id.root.to_s
279
+ # => "ISO 9001:2015"
280
+
281
+ # Returns self for base identifiers
282
+ base = Pubid::Iso.parse("ISO 9001:2015")
283
+ base.root.to_s # => "ISO 9001:2015"
284
+ base.root.equal?(base) # => true
285
+ ----
286
+
287
+ === Features
288
+
289
+ * ✅ **Immutable operations** - All methods return new instances
290
+ * ✅ **Type-safe** - Raises `ArgumentError` for invalid comparisons
291
+ * ✅ **Preserves all attributes** - Round-trip through hash/JSON
292
+ * ✅ **Works with supplements** - Traverses supplement chains correctly
293
+
294
+
295
+ == Advanced Rendering Styles
296
+
297
+ ISO and IEC identifiers support multiple abbreviation forms for supplements to maintain round-trip fidelity with different official formats.
298
+
299
+ === Overview
300
+
301
+ The rendering styles feature enables PubID to parse and render identifiers in multiple official formats while preserving the exact format that was parsed. This ensures perfect round-trip compatibility with standards organizations' documentation.
302
+
303
+ **Supported formats:**
304
+ * **ISO:** Short (AMD, DAM, COR) vs Long (Amd, DaM, Cor) - distinguished by case
305
+ * **IEC:** Short (AMD1, COR1) vs Long (Amd 1, Cor 1) - distinguished by spacing
306
+
307
+ === Usage Examples
308
+
309
+ ==== ISO Examples
310
+
311
+ [source,ruby]
312
+ ----
313
+ # ISO - Preserves long form (mixed case)
314
+ id = Pubid::Iso.parse("ISO 8601:2019/DAmd 1")
315
+ id.to_s # => "ISO 8601:2019/DAmd 1"
316
+
317
+ # ISO - Preserves short form (uppercase)
318
+ id = Pubid::Iso.parse("ISO 8601:2019/DAM 1")
319
+ id.to_s # => "ISO 8601:2019/DAM 1"
320
+
321
+ # Corrigendum with long form
322
+ id = Pubid::Iso.parse("ISO/IEC 19115:2003/Cor 1:2006")
323
+ id.to_s # => "ISO/IEC 19115:2003/Cor 1:2006"
324
+ ----
325
+
326
+ ==== IEC Examples
327
+
328
+ [source,ruby]
329
+ ----
330
+ # IEC - Preserves long form (with space)
331
+ id = Pubid::Iec.parse("IEC 60050-351:2013/Amd 1:2016")
332
+ id.to_s # => "IEC 60050-351:2013/Amd 1:2016"
333
+
334
+ # IEC - Preserves short form (no space)
335
+ id = Pubid::Iec.parse("IEC 60050-351:2013/AMD1:2016")
336
+ id.to_s # => "IEC 60050-351:2013/AMD1:2016"
337
+ ----
338
+
339
+ === Key Features
340
+
341
+ * ✅ **Automatic format detection** - No manual configuration required
342
+ * ✅ **Round-trip fidelity** - Parse and render back to exact original format
343
+ * ✅ **Standards compliance** - Supports both official ISO and IEC formats
344
+ * ✅ **Backward compatible** - Existing code continues to work unchanged
345
+
346
+ === Documentation
347
+
348
+ See link:docs/RENDERING_GUIDE.md[Advanced Rendering Styles Guide] for complete documentation including:
349
+
350
+ * All supported formats for ISO and IEC
351
+ * Detailed usage examples
352
+ * Architecture and implementation details
353
+ * Format comparison tables
354
+
355
+ == Metadata Export
356
+
357
+ PubID includes a metadata export layer (`Pubid::Export`) that extracts structured
358
+ schema information from all 22+ flavors — identifier types, typed stages,
359
+ harmonized stage codes, abbreviations, and fixture examples — into a single
360
+ JSON document suitable for website generation, tooling integration, and gap
361
+ analysis.
362
+
363
+ === Rake Tasks
364
+
365
+ [source,shell]
366
+ ----
367
+ # Export metadata for all flavors to lib/tasks/website-data.json
368
+ bundle exec rake export:website_data
369
+
370
+ # Audit library data against website publishers
371
+ bundle exec rake export:audit
372
+ ----
373
+
374
+ The export task produces a JSON file covering 23 flavors and 162 identifier
375
+ types. Each flavor's identifier classes, typed stages, abbreviations, and up to
376
+ 10 fixture examples are extracted automatically from the library source.
377
+
378
+ === Programmatic API
379
+
380
+ [source,ruby]
381
+ ----
382
+ require 'pubid/export'
383
+
384
+ # Export all flavors
385
+ data = Pubid::Export::Exporter.export_all
386
+ # => { "iso" => { identifier_types: [...], attributes: [...] }, ... }
387
+
388
+ # Export a single flavor
389
+ exporter = Pubid::Export::SchemeExporter.new(:iso)
390
+ result = exporter.export
391
+ result.to_h # => { identifier_types: [...], attributes: [...] }
392
+ ----
393
+
394
+ === Output Schema
395
+
396
+ The exported JSON follows this structure:
397
+
398
+ [source,json]
399
+ ----
400
+ {
401
+ "<flavor>": {
402
+ "identifier_types": [
403
+ {
404
+ "key": "is",
405
+ "title": "International Standard",
406
+ "short": "IS",
407
+ "abbr": ["", "IS"],
408
+ "typed_stages": [
409
+ {
410
+ "stage_code": "dis",
411
+ "type_code": "is",
412
+ "abbr": ["DIS", "FPD"],
413
+ "name": "Draft International Standard",
414
+ "harmonized_stages": ["40.00", "40.20", "40.60", ...]
415
+ }
416
+ ],
417
+ "examples": ["ISO 9001:2015", "ISO/IEC 17031-1:2020", ...]
418
+ }
419
+ ],
420
+ "attributes": ["number", "part", "date", "edition", ...]
421
+ }
422
+ }
423
+ ----
424
+
425
+ .Schema fields
426
+ [cols="1,1,4", options="header"]
427
+ |===
428
+ |Field |Type |Description
429
+
430
+ |`key`
431
+ |`string`
432
+ |Machine-readable type key (e.g., `is`, `tr`, `amd`)
433
+
434
+ |`title`
435
+ |`string`
436
+ |Human-readable type name (e.g., "International Standard")
437
+
438
+ |`short`
439
+ |`string\|null`
440
+ |Short abbreviation if defined by the publisher
441
+
442
+ |`abbr`
443
+ |`string[]`
444
+ |All recognized abbreviations for this type (parsed input variants)
445
+
446
+ |`typed_stages`
447
+ |`object[]`
448
+ |Development stages specific to this document type
449
+
450
+ |`typed_stages[].stage_code`
451
+ |`string`
452
+ |Stage code (e.g., `dis`, `cd`, `fdis`)
453
+
454
+ |`typed_stages[].type_code`
455
+ |`string`
456
+ |Document type this stage applies to
457
+
458
+ |`typed_stages[].abbr`
459
+ |`string[]`
460
+ |Abbreviations recognized for this typed stage
461
+
462
+ |`typed_stages[].name`
463
+ |`string`
464
+ |Full name (e.g., "Draft International Standard")
465
+
466
+ |`typed_stages[].harmonized_stages`
467
+ |`string[]`
468
+ |ISO harmonized stage codes (e.g., `40.00`, `50.60`)
469
+
470
+ |`examples`
471
+ |`string[]`
472
+ |Up to 10 real-world identifiers from test fixtures
473
+
474
+ |`attributes`
475
+ |`string[]`
476
+ |Lutaml::Model attribute names on the identifier class
477
+
478
+ |`wrapper_types`
479
+ |`object[]`
480
+ |Value-added overlay types (VAP, Redline, etc.) — same schema as `identifier_types`
481
+ |===
482
+
483
+ === Extraction Strategies
484
+
485
+ Different flavors use different internal architectures. The export layer uses
486
+ the Strategy pattern to handle each without modifying existing code:
487
+
488
+ .Strategy classes
489
+ [cols="1,2,2", options="header"]
490
+ |===
491
+ |Strategy |Flavors |Pattern
492
+
493
+ |`SchemeExporter`
494
+ |ISO, IEC, ASTM, ASHRAE, ASME, CCSDS, CIE, CSA, JIS, JCGM, OIML, IDF, API, SAE, ANSI
495
+ |`Scheme.identifiers` + per-class `def self.type` + `TYPED_STAGES`
496
+
497
+ |`RegistryExporter`
498
+ |BSI, CEN
499
+ |`TYPED_STAGES_REGISTRY` on Scheme class (centralized registry)
500
+
501
+ |`IeeeExporter`
502
+ |IEEE
503
+ |`KEY_IDENTIFIER_CLASSES` from Identifiers module + module-level typed stages
504
+
505
+ |`NistExporter`
506
+ |NIST
507
+ |`Scheme.identifiers` + per-class `typed_stages` class method (not constant)
508
+
509
+ |`ItuExporter`
510
+ |ITU
511
+ |Sector-based types with transform/model pattern
512
+
513
+ |`DataClassExporter`
514
+ |ETSI, Plateau
515
+ |`Lutaml::Model::Serializable` as Scheme (no per-class identifiers)
516
+ |===
517
+
518
+ Adding a new flavor requires only registering it in `FLAVOR_STRATEGIES` within
519
+ `Exporter` — no existing strategy code changes.
520
+
521
+ === Adding a New Flavor to Export
522
+
523
+ When adding a new publisher flavor to PubID, follow these steps to integrate
524
+ it with the export layer:
525
+
526
+ . **Ensure identifier classes define `def self.type`** — Each identifier class
527
+ in `lib/pubid/{flavor}/identifiers/` should implement `def self.type`
528
+ returning `{ key: :sym, title: "Name", short: "Abbr" }`. This is the primary
529
+ source of metadata.
530
+
531
+ . **Choose the right strategy** — Most flavors use one of the existing strategies:
532
+
533
+ * `SchemeExporter` — if the flavor has a `Scheme` class with a class-level
534
+ `identifiers` method that returns identifier classes. This is the most
535
+ common pattern (ISO, IEC, ASTM, ASHRAE, etc.).
536
+ * `RegistryExporter` — if the flavor uses a centralized `TYPED_STAGES_REGISTRY`
537
+ on the Scheme class instead of per-class `TYPED_STAGES` (BSI, CEN).
538
+ * `IeeeExporter` — only for IEEE, which has a unique constant-based discovery.
539
+ * `NistExporter` — if typed stages come from a class method (not constant).
540
+ * `ItuExporter` — for sector-based types with transform/model patterns.
541
+ * `DataClassExporter` — for flavors where Scheme inherits from
542
+ `Lutaml::Model::Serializable` (ETSI, Plateau).
543
+
544
+ . **Register the flavor** in `lib/pubid/export/exporter.rb`:
545
+
546
+ [source,ruby]
547
+ ----
548
+ FLAVORS = %i[iso iec ... new_flavor].freeze
549
+
550
+ FLAVOR_STRATEGIES = {
551
+ iso: :scheme,
552
+ # ...
553
+ new_flavor: :scheme, # or :registry, :data_class, etc.
554
+ }.freeze
555
+ ----
556
+
557
+ . **Add the module mapping** in `FlavorExporter#scheme_module` (in
558
+ `lib/pubid/export/flavor_exporter.rb`):
559
+
560
+ [source,ruby]
561
+ ----
562
+ when "new_flavor" then Pubid::NewFlavor
563
+ ----
564
+
565
+ . **If the flavor has wrapper types** (value-added formats like VAP, Redline),
566
+ add them to `WRAPPER_CLASSES` in `FlavorExporter`:
567
+
568
+ [source,ruby]
569
+ ----
570
+ WRAPPER_CLASSES = {
571
+ iec: %i[VapIdentifier],
572
+ bsi: %i[ValueAddedPublication],
573
+ new_flavor: %i[WrapperClassName],
574
+ }.freeze
575
+ ----
576
+
577
+ . **Add fixture examples** (optional) — Create
578
+ `spec/fixtures/{flavor}/identifiers/pass/{type_key}.txt` with one identifier
579
+ per line. Up to 10 examples per type are automatically picked up during export.
580
+
581
+ . **Write tests** — Add `spec/pubid/export/{flavor}_exporter_spec.rb`:
582
+
583
+ [source,ruby]
584
+ ----
585
+ require "spec_helper"
586
+ require "pubid/export"
587
+
588
+ RSpec.describe Pubid::Export::SchemeExporter, "for new_flavor" do
589
+ subject(:result) { described_class.new(:new_flavor).export }
590
+
591
+ it "exports identifier types" do
592
+ expect(result.identifier_types.size).to be > 0
593
+ end
594
+ end
595
+ ----
596
+
597
+ . **Regenerate data** — Run `bundle exec rake export:website_data` to update
598
+ `lib/tasks/website-data.json`.
599
+
600
+ === Audit
601
+
602
+ The `Pubid::Export::Auditor` compares library-generated metadata against
603
+ website publisher data to identify gaps:
604
+
605
+ * Identifier types present in the library but missing from the website
606
+ * Identifier types present on the website but not in the library
607
+ * Per-flavor summary of mismatches
608
+
609
+ [source,ruby]
610
+ ----
611
+ require 'pubid/export'
612
+
613
+ data = Pubid::Export::Exporter.export_all
614
+ auditor = Pubid::Export::Auditor.new(data)
615
+ results = auditor.audit(website_publishers)
616
+ puts auditor.summary(results)
617
+ # => "Audit Summary: 2 missing, 14 extra"
618
+ ----
619
+
620
+ === File Layout
621
+
622
+ [source]
623
+ ----
624
+ lib/pubid/export.rb # Module entry point
625
+ lib/pubid/export/
626
+ ├── result.rb # Immutable value objects (IdentifierTypeResult, TypedStageResult, FlavorResult)
627
+ ├── flavor_exporter.rb # Abstract base class
628
+ ├── scheme_exporter.rb # Strategy: Scheme.identifiers pattern
629
+ ├── registry_exporter.rb # Strategy: TYPED_STAGES_REGISTRY pattern
630
+ ├── ieee_exporter.rb # Strategy: IEEE identifier discovery
631
+ ├── nist_exporter.rb # Strategy: NIST per-class typed_stages
632
+ ├── itu_exporter.rb # Strategy: ITU transform/model pattern
633
+ ├── data_class_exporter.rb # Strategy: Lutaml::Model::Serializable Scheme
634
+ ├── exporter.rb # Orchestrator (FLAVOR_STRATEGIES dispatch)
635
+ └── auditor.rb # Library vs website gap analysis
636
+ lib/tasks/export.rake # Rake tasks: export:website_data, export:audit
637
+ ----
638
+
639
+ == Repository
640
+
641
+ This repository is a monorepo for the PubID Ruby gems, which implement the PubID
642
+ identifier data model and its various components.
643
+
644
+ The PubID Ruby gems implement identifiers from multiple standards organizations,
645
+ making it easier for developers to work with them in their applications.
646
+
647
+ This repository contains all the `pubid-*` gems consolidated into a single
648
+ monorepo for easier development and maintenance while preserving individual gem
649
+ releases.
650
+
651
+ == Structure
652
+
653
+ The repository is organized as follows:
654
+
655
+ [source]
656
+ ----
657
+ .
658
+ ├── lib/pubid/ # V2 implementation (ACTIVE)
659
+ │ ├── core/ # Shared base classes and components
660
+ │ ├── iso/ # ISO - Production ready
661
+ │ ├── iec/ # IEC - Production ready
662
+ │ ├── cen/ # CEN - Production ready
663
+ │ ├── idf/ # IDF - Production ready
664
+ │ ├── ieee/ # IEEE - Production ready
665
+ │ ├── nist/ # NIST - Production ready
666
+ │ └── ... # 22+ flavors total
667
+ ├── data/ # Pre-parse normalization data
668
+ │ ├── iso/update_codes.yaml
669
+ │ ├── iec/update_codes.yaml
670
+ │ └── ...
671
+ ├── spec/ # Tests
672
+ │ ├── pubid/ # Per-flavor tests
673
+ │ ├── fixtures/ # Bulk test fixtures
674
+ │ └── integration/ # Cross-gem tests
675
+ ├── docs/ # Documentation
676
+ ├── .github/workflows/ # CI/CD workflows
677
+ ├── Gemfile # Root Gemfile for development
678
+ ├── Rakefile # Monorepo management tasks
679
+ ├── .rubocop.yml # Shared RuboCop configuration
680
+ └── LICENSE.txt # Shared license
681
+ ----
682
+
683
+ == PubID V2 Architecture
684
+
685
+ === General
686
+
687
+ PubID V2 implements a completely redesigned parser architecture with clean separation of concerns and model-driven design. The implementation is located in [`lib/pubid/`](lib/pubid/).
688
+
689
+ === Three-layer design
690
+
691
+ V2 implements a clean separation of concerns across three distinct layers:
692
+
693
+ [source]
694
+ ----
695
+ ┌─────────────────────────────────────┐
696
+ │ Pre-parser Normalization Layer │ update_codes.yaml normalization
697
+ │ (Malformed Input → Cleaned Input) │ BEFORE parsing
698
+ └──────────┬──────────────────────────┘
699
+
700
+ ┌──────────▼──────────────────────────┐
701
+ │ Parser Layer │ Grammar-based parsing (Parslet)
702
+ │ (Syntax → Parse Tree) │
703
+ └──────────┬──────────────────────────┘
704
+
705
+ ┌──────────▼──────────────────────────┐
706
+ │ Builder Layer │ Transform parse tree to objects
707
+ │ (Parse Tree → Attributes) │
708
+ └──────────┬──────────────────────────┘
709
+
710
+ ┌──────────▼──────────────────────────┐
711
+ │ Identifier Layer │ Lutaml::Model serializable objects
712
+ │ (Attributes → String) │
713
+ └─────────────────────────────────────┘
714
+ ----
715
+
716
+ Where:
717
+
718
+ Pre-parser Normalization:: Applies `update_codes.yaml` mappings from `data/{flavor}/` directory to normalize malformed identifiers before parsing. This handles legacy formats, typos, and historical variations.
719
+ Parser Layer:: Parslet-based grammar defining syntax rules. Handles pattern matching and tokenization.
720
+ Builder Layer:: Transforms hash tree from parser into attribute hash. Handles special cases and edge conditions.
721
+ Identifier Layer:: Lutaml::Model-based classes with rendering logic. Provides serialization and string representation.
722
+
723
+ === Parser performance
724
+
725
+ The V2 parsers have been tested against real-world identifier databases to ensure high accuracy:
726
+
727
+ [options="header"]
728
+ |===
729
+ | Parser | Success Rate | Examples | Status | Notes
730
+
731
+ | **NIST**
732
+ | **98.47%**
733
+ | 19,191/19,488
734
+ | ✅ Complete
735
+ | Exceeds 95% target, handles historical NBS patterns
736
+
737
+ | **IEEE**
738
+ | **87.95%**
739
+ | 8,388/9,537
740
+ | ✅ Production Ready
741
+ | Parser with TYPED_STAGE architecture, Joint Development support, Pattern 4 Relationships
742
+
743
+ | **ISO**
744
+ | **90.0%**
745
+ | 2,573/2,859
746
+ | ✅ URN generation
747
+ | 100% functional + URN generation complete, remaining types in progress
748
+
749
+ | **BSI**
750
+ | TBD
751
+ | -
752
+ | ⚠️ Needs testing
753
+ | Implementation complete, needs comprehensive tests
754
+
755
+ | **IEC**
756
+ | **84.58%**
757
+ | 823/973
758
+ | ✅ Production Ready
759
+ | 21 identifier types, comprehensive test coverage
760
+
761
+ | **CEN**
762
+ | **83.2%**
763
+ | 79/95
764
+ | ✅ Production Ready
765
+ | Native & adopted standards, TYPED_STAGES architecture
766
+
767
+ | **ITU**
768
+ | **96.5%**
769
+ | 166/172
770
+ | ✅ Production Ready
771
+ | Core identifiers complete, 6 combined ID limitations documented
772
+
773
+ | **JIS**
774
+ | TBD
775
+ | -
776
+ | ⚠️ Needs testing
777
+ | Implementation complete, needs comprehensive tests
778
+
779
+ | **ETSI**
780
+ | TBD
781
+ | -
782
+ | ⚠️ Needs testing
783
+ | Implementation complete, needs comprehensive tests
784
+
785
+ |===
786
+
787
+ === Usage examples
788
+
789
+ ==== NIST
790
+
791
+ The NIST parser handles standard NIST publications and historical NBS patterns:
792
+
793
+ [source,ruby]
794
+ ----
795
+ require 'pubid'
796
+
797
+ # Parse standard NIST identifier
798
+ id = Pubid::Nist.parse("NIST SP 800-53r5")
799
+
800
+ # Access components
801
+ id.series # => "SP"
802
+ id.number # => "800-53"
803
+ id.revision # => "r5"
804
+
805
+ # Render to string
806
+ id.to_s # => "NIST SP 800-53r5"
807
+
808
+ # Parse historical NBS patterns
809
+ id = Pubid::Nist.parse("NBS LCIRC 1019r1963")
810
+ id.to_s # => "NBS LCIRC 1019r1963"
811
+
812
+ # CSM volume-number format
813
+ id = Pubid::Nist.parse("NBS CSM v6n1")
814
+ id.to_s # => "NBS CSM v6n1"
815
+
816
+ # Supplement with revision
817
+ id = Pubid::Nist.parse("NBS CIRC 154supprev")
818
+ id.to_s # => "NBS CIRC 154supprev"
819
+ ----
820
+
821
+ **Language:**
822
+ * Legacy identifier: Preserve original with `lang.first` text
823
+ * Multi-language text: Default to primary `language.original_code`
824
+ * ISO Constructs: Check V2 components (Part, Language, Public) for NULL
825
+
826
+ ==== IEC
827
+
828
+ The IEC parser handles complex patterns including adopted standards and dual-published identifiers:
829
+
830
+ [source,ruby]
831
+ ----
832
+ require 'pubid'
833
+
834
+ # Parse standard IEC identifier
835
+ id = Pubid::Iec.parse("IEC 62014-5 IEEE Std 1734-2011")
836
+ id.class # => Pubid::Iec::Identifiers::DualPublished
837
+ id.to_s # => "IEC 62014-5 and IEEE Std 1734-2011" # normalized
838
+
839
+ # Space-separated dual identifiers are auto-detected
840
+ id = Pubid::Iec.parse("ANSI C37.61-1973 and IEEE Std 321-1973")
841
+ id.to_s # => "ANSI C37.61-1973 and IEEE Std 321-1973"
842
+ ----
843
+
844
+ ===== Pattern 4: Relationship Identifiers ✨
845
+
846
+ IEEE supports 7 relationship types with recursive identifier parsing:
847
+
848
+ .Relationship Types
849
+ [cols="1,2,3"]
850
+ |===
851
+ |Type |Description |Example
852
+
853
+ |revision_of
854
+ |Indicates this standard revises another
855
+ |`IEEE Std 802 (Revision of IEEE Std 801)`
856
+
857
+ |amendment_to
858
+ |Indicates this is an amendment
859
+ |`IEEE Std 100 (Amendment to IEEE Std 99)`
860
+
861
+ |corrigendum_to
862
+ |Indicates this corrects errors
863
+ |`IEEE Std 200 (Corrigendum to IEEE Std 199)`
864
+
865
+ |incorporates
866
+ |Indicates incorporation of another standard
867
+ |`IEEE Std 300 (incorporates IEEE Std 299)`
868
+
869
+ |adoption_of
870
+ |Indicates adoption of external standard
871
+ |`IEEE Std 400 (Adoption of ISO/IEC 9945-1:2009)`
872
+
873
+ |supplement_to
874
+ |Indicates supplementary material
875
+ |`IEEE Std 500 (Supplement to IEEE Std 499)`
876
+
877
+ |draft_amendment_to
878
+ |Indicates draft amendment
879
+ |`IEEE Std 600 (Draft Amendment to IEEE Std 599)`
880
+ |===
881
+
882
+ .Parsing Pattern 4 Identifiers
883
+ [source,ruby]
884
+ ----
885
+ require 'pubid/ieee'
886
+
887
+ # Parse relationship identifier
888
+ id = Pubid::Ieee.parse('IEEE Std 802 (Revision of IEEE Std 801)')
889
+ id.relationships.first.relationship_type # => "revision_of"
890
+ id.relationships.first.related_identifiers.first.to_s # => "IEEE Std 801"
891
+ id.to_s # => "IEEE Std 802 (Revision of IEEE Std 801)" (perfect round-trip)
892
+
893
+ # Multiple related identifiers
894
+ id = Pubid::Ieee.parse('IEEE Std 100 (Amendment to IEEE Std 99, IEEE Std 98)')
895
+ id.relationships.first.related_identifiers.count # => 2
896
+
897
+ # Intermediate amendments (as amended by clause)
898
+ id = Pubid::Ieee.parse('IEEE Std 200 (Corrigendum to IEEE Std 199 as amended by IEEE Std 199a)')
899
+ id.relationships.first.intermediate_amendments.first.to_s # => "IEEE Std 199a"
900
+ ----
901
+
902
+ **Architecture:**
903
+ - Relationships are Lutaml::Model objects
904
+ - Related identifiers are recursively parsed as full Base objects
905
+ - Perfect round-trip fidelity maintained
906
+ - Backward compatible with legacy attributes
907
+ - 28/28 unit tests passing (100%)
908
+
909
+ ===== Historical Sub-Flavors (AIEE & IRE) ✨
910
+
911
+ IEEE supports two historical predecessor organizations that merged in 1963 to form IEEE:
912
+
913
+ .AIEE (American Institute of Electrical Engineers) 1884-1963
914
+ [source,ruby]
915
+ ----
916
+ # Parse AIEE identifier with long date format
917
+ aiee = Pubid::Ieee.parse("AIEE No. 552, November 1955")
918
+ aiee.to_s # => "AIEE No. 552, November 1955"
919
+ aiee.to_s(date_format: :short) # => "AIEE No. 552-1955"
920
+ aiee.to_s(date_format: :long) # => "AIEE No. 552, November 1955"
921
+
922
+ # Parse AIEE identifier with short date format
923
+ aiee = Pubid::Ieee.parse("AIEE No. 59-1962")
924
+ aiee.to_s # => "AIEE No. 59-1962"
925
+ aiee.to_s(date_format: :long) # => "AIEE No. 59, 1962"
926
+ ----
927
+
928
+ **AIEE Features:**
929
+ - Always uses "No" or "No." (never "Std")
930
+ - Rendering profiles support both short (dash) and long (comma + optional month) formats
931
+ - Preserves original parsed format by default
932
+ - User can override output format with `date_format:` parameter
933
+
934
+ .IRE (Institute of Radio Engineers) 1912-1963
935
+ [source,ruby]
936
+ ----
937
+ # Parse IRE identifier (year-first format)
938
+ ire = Pubid::Ieee.parse("52 IRE 7.S2")
939
+ ire.to_s # => "52 IRE 7.S2"
940
+ ire.year # => 1952 (converts 2-digit to 4-digit internally)
941
+
942
+ # IRE with committee notation
943
+ ire = Pubid::Ieee.parse("61 IRE 28 S1")
944
+ ire.to_s # => "61 IRE 28 S1"
945
+ ire.year # => 1961
946
+ ----
947
+
948
+ **IRE Features:**
949
+ - Year-first format (unlike modern IEEE)
950
+ - 2-digit years (12-63) automatically converted to 4-digit (1912-1963)
951
+ - Committee notation: `7.S2` (committee 7, Standard 2), `28 S1` (committee 28, Standard 1)
952
+ - Rendered output preserves 2-digit year format
953
+
954
+ **Transitional Identifiers:**
955
+ - `IEEE-AIEE No. 56` - Transitional period documents
956
+ - `IEEE-IRE X` - Mixed publisher identifiers
957
+
958
+ **Architecture:**
959
+ - AIEE/IRE are proper Lutaml::Model classes (not IEEE subclasses)
960
+ - Separate historical organizations with distinct patterns
961
+ - Compatible with Pattern 4 relationships (can be related identifiers)
962
+ - Clean MODEL-DRIVEN implementation
963
+
964
+ ==== Data Cleaning & Preprocessing
965
+
966
+ The IEEE parser automatically cleans common data quality issues:
967
+
968
+ * HTML entity normalization (`&x2122;` → `™`, `&amp;` → `&`, `&x2019;` → `'`)
969
+ * Number space correction (`C57.1 2.25` → `C57.12.25`)
970
+ * Year space correction (`1 996` → `1996`)
971
+ * Trailing comma/text removal (`, Standard` → ``)
972
+
973
+ **New Copublisher Organizations:**
974
+
975
+ Added support for additional copublisher organizations:
976
+
977
+ * **CSA** (Canadian Standards Association)
978
+ * **ASME** (American Society of Mechanical Engineers)
979
+ * **ASA** (American Standards Association - for AIEE equivalence patterns)
980
+
981
+ [source,ruby]
982
+ ----
983
+ # CSA copublisher
984
+ csa_id = Pubid::Ieee.parse("IEEE/CSA P844.1-2017")
985
+ csa_id.copublisher # => ["CSA"]
986
+
987
+ # ASME in semicolon equivalence
988
+ asme_id = Pubid::Ieee.parse("IEEE Std 120-1955; ASME PTC 19.6-1955")
989
+ ----
990
+
991
+ **Corrigendum as Proper Identifier Type:**
992
+
993
+ IEEE corrigenda are now first-class SupplementIdentifier objects with full base identifier parsing:
994
+
995
+ [source,ruby]
996
+ ----
997
+ cor = Pubid::Ieee.parse("IEEE Std 535-2013/Cor. 1-2017")
998
+ cor.class # => Pubid::Ieee::Identifiers::Corrigendum
999
+ cor.cor_number # => "1"
1000
+ cor.cor_year # => "2017"
1001
+ cor.base_identifier # => <Base identifier object>
1002
+ cor.base_identifier.to_s # => "IEEE Std 535-2013"
1003
+ cor.to_s # => "IEEE Std 535-2013/Cor. 1-2017"
1004
+
1005
+ # Round-trip fidelity preserved
1006
+ cor2 = Pubid::Ieee.parse("IEEE Std 802.1AC-2016/Cor. 1-2018")
1007
+ cor2.to_s # => "IEEE Std 802.1AC-2016/Cor. 1-2018"
1008
+ ----
1009
+
1010
+ **Extended Relationship Types:**
1011
+
1012
+ Now supports **11 relationship types** (added Reaffirmation and Redesignation):
1013
+
1014
+ .All Supported Relationship Types
1015
+ [cols="1,2,3"]
1016
+ |===
1017
+ |Type |Description |Example
1018
+
1019
+ |revision_of
1020
+ |Standard revises another
1021
+ |`(Revision of IEEE Std X)`
1022
+
1023
+ |amendment_to
1024
+ |Amendment to a standard
1025
+ |`(Amendment to IEEE Std X)`
1026
+
1027
+ |corrigendum_to
1028
+ |Correction to a standard
1029
+ |`(Corrigendum to IEEE Std X)`
1030
+
1031
+ |incorporates
1032
+ |Incorporates another standard
1033
+ |`(incorporates IEEE Std X)`
1034
+
1035
+ |adoption_of
1036
+ |Adopts external standard
1037
+ |`(Adoption of ISO/IEC X)`
1038
+
1039
+ |supplement_to
1040
+ |Supplementary material
1041
+ |`(Supplement to IEEE Std X)`
1042
+
1043
+ |draft_amendment_to
1044
+ |Draft amendment
1045
+ |`(Draft Amendment to IEEE Std X)`
1046
+
1047
+ |draft_revision_of
1048
+ |Draft revision
1049
+ |`(Draft Revision of IEEE Std X)`
1050
+
1051
+ |**reaffirmation_of** ✨
1052
+ |**Reaffirms validity**
1053
+ |**`(Reaffirmation of ANSI N42.18-1980)`**
1054
+
1055
+ |**redesignation_of** ✨
1056
+ |**Identifier redesignation**
1057
+ |**`(Redesignation of ANSI N13.10-1974)`**
1058
+ |===
1059
+
1060
+ [source,ruby]
1061
+ ----
1062
+ # Reaffirmation relationship
1063
+ reaffirm = Pubid::Ieee.parse("ANSI N42.18-2004 (Reaffirmation of ANSI N42.18-1980)")
1064
+ reaffirm.relationships.first.relationship_type # => "reaffirmation_of"
1065
+ reaffirm.to_s # => "ANSI N42.18-2004 (Reaffirmation of ANSI N42.18-1980)"
1066
+
1067
+ # Redesignation relationship
1068
+ redesig = Pubid::Ieee.parse("ANSI N42.18-2004 (Redesignation of ANSI N13.10-1974)")
1069
+ redesig.relationships.first.relationship_type # => "redesignation_of"
1070
+
1071
+ # Multiple relationships with semicolon separator
1072
+ multi = Pubid::Ieee.parse("IEEE Std 100 (Reaffirmation of X; Redesignation of Y)")
1073
+ multi.relationships.length # => 2
1074
+ multi.relationships[0].relationship_type # => "reaffirmation_of"
1075
+ multi.relationships[1].relationship_type # => "redesignation_of"
1076
+ ----
1077
+
1078
+ **ANSI P Prefix Support:**
1079
+
1080
+ Added support for ANSI draft project identifiers (P prefix):
1081
+
1082
+ [source,ruby]
1083
+ ----
1084
+ ansi_p = Pubid::Ieee.parse("ANSI PN42.34-2015")
1085
+ ansi_p.publisher # => "ANSI"
1086
+ ansi_p.type # => "P"
1087
+ ansi_p.to_s # => "ANSI PN42.34-2015"
1088
+ ----
1089
+
1090
+ **Architecture:**
1091
+
1092
+ All enhancements maintain strict MODEL-DRIVEN architecture:
1093
+ * Corrigendum as proper Lutaml::Model class
1094
+ * Relationships as component objects
1095
+ * MECE organization preserved
1096
+ * Three-layer separation maintained
1097
+
1098
+
1099
+ ==== ASME (American Society of Mechanical Engineers)
1100
+ - Status: ✅ 552/731 (75.51%)
1101
+ - Features: BPVC subdivisions, multi-char designators, CSA dual-publishing
1102
+ - Architecture: Complete V2 with MODEL-DRIVEN design
1103
+
1104
+ .ASME Code Structure
1105
+ ASME uses a designator + number system with special BPVC handling:
1106
+
1107
+ **Standard Format:**
1108
+ [source]
1109
+ ----
1110
+ ASME {DESIGNATOR}{NUMBER}-{YEAR}
1111
+
1112
+ Examples:
1113
+ ASME B16.5-2020 # Single-letter designator
1114
+ ASME PTC-1-2022 # Multi-char designator (Performance Test Code)
1115
+ ASME Y14.43-2011 # Alphanumeric number
1116
+ ASME A17.1/CSA B44-2022 # CSA dual-published
1117
+ ----
1118
+
1119
+ **BPVC (Boiler & Pressure Vessel Code) Format:**
1120
+ [source]
1121
+ ----
1122
+ ASME BPVC.{SECTION}[.{SUBSECTION}][.{CODE}]-{YEAR}
1123
+
1124
+ Dotted Notation Examples:
1125
+ ASME BPVC.I-2021 # Section I only
1126
+ ASME BPVC.III.1.NB-2021 # Section III, Subsection 1, Code NB
1127
+ ASME BPVC.CC.BPV-2021 # Case Code BPV
1128
+
1129
+ Special Variants:
1130
+ ASME BPVC COMPLETE CODE BIND-2019 # Complete code set
1131
+ ASME BPVC-CC-BPV-2019 # Dash notation variant
1132
+ ----
1133
+
1134
+ .BPVC Components
1135
+ [cols="1,3"]
1136
+ |===
1137
+ |Component |Description
1138
+
1139
+ |Roman Numerals
1140
+ |I through XIII for main sections
1141
+
1142
+ |Letter Codes
1143
+ |NB, NC, ND, NE, NF, NG, NCA, NCD, BPV, SSC, NUC
1144
+
1145
+ |Case Codes
1146
+ |CC.{CODE} format for special case rulings
1147
+ |===
1148
+
1149
+ **Multi-Character Designators:**
1150
+
1151
+ ASME uses 23+ multi-character codes for specialized document types:
1152
+
1153
+ [cols="1,3"]
1154
+ |===
1155
+ |Code |Full Name
1156
+
1157
+ |PTC
1158
+ |Performance Test Code
1159
+
1160
+ |PVHO
1161
+ |Pressure Vessels for Human Occupancy
1162
+
1163
+ |PCC
1164
+ |Post-Construction Code
1165
+
1166
+ |NQA
1167
+ |Nuclear Quality Assurance
1168
+
1169
+ |V&V
1170
+ |Verification & Validation
1171
+
1172
+ |RA, QME, BTH, BPE, OM
1173
+ |And 18+ other specialized codes
1174
+ |===
1175
+
1176
+ **Additional Features:**
1177
+ - Reaffirmation notation: `(R2020)`
1178
+ - Language codes: `(SPANISH)`
1179
+ - Draft years: `20XX`, `202X`
1180
+ - Revision notes: `[Draft Proposed Revision of...]`
1181
+
1182
+ .Usage Examples
1183
+ [source,ruby]
1184
+ ----
1185
+ require 'pubid/asme'
1186
+
1187
+ # Parse standard code
1188
+ id = Pubid::Asme.parse("ASME B16.5-2020")
1189
+ id.code.designator # => "B"
1190
+ id.code.number # => "16.5"
1191
+ id.year # => "2020"
1192
+ id.to_s # => "ASME B16.5-2020"
1193
+
1194
+ # Parse BPVC subdivision
1195
+ bpvc = Pubid::Asme.parse("ASME BPVC.III.1.NB-2021")
1196
+ bpvc.code.designator # => "BPVC.III.1.NB"
1197
+ bpvc.code.number # => ""
1198
+ bpvc.year # => "2021"
1199
+ bpvc.to_s # => "ASME BPVC.III.1.NB-2021"
1200
+
1201
+ # Parse multi-char designator
1202
+ ptc = Pubid::Asme.parse("ASME PTC-1-2022")
1203
+ ptc.code.designator # => "PTC"
1204
+ ptc.code.number # => "1"
1205
+ ptc.to_s # => "ASME PTC-1-2022"
1206
+
1207
+ # Parse CSA dual-published
1208
+ dual = Pubid::Asme.parse("ASME A17.1/CSA B44-2022")
1209
+ dual.code.designator # => "A"
1210
+ dual.code.number # => "17.1"
1211
+ dual.csa_number # => "B44"
1212
+ dual.to_s # => "ASME A17.1/CSA B44-2022"
1213
+ ----
1214
+
1215
+ **Known Limitations:**
1216
+ All 731 ASME identifiers are normative (from official ASME sources). Current parser handles 75.51% (552/731) with opportunities for further enhancement in specialized patterns.
1217
+
1218
+ ==== BSI (British Standards Institution)
1219
+
1220
+ Status: ✅ 47/47 integration tests (100%), 1,044/1,579 fixtures (66.12%)
1221
+ Architecture: Complete V2 with VALUE-ADDED PUBLICATION wrapper pattern
1222
+ Features: Adopted standards, consolidated identifiers, value-added publications, aerospace standards, new document types
1223
+
1224
+ .BSI Value-Added Publications ✨
1225
+
1226
+ BSI supports value-added publication formats as wrapper identifiers following IEC VapIdentifier pattern:
1227
+
1228
+ [source,ruby]
1229
+ ----
1230
+ # PDF format
1231
+ pdf = Pubid::Bsi.parse("PD 5500:2018+A3:2020 PDF")
1232
+ pdf.class # => Pubid::Bsi::Identifiers::ValueAddedPublication
1233
+ pdf.format # => "PDF"
1234
+ pdf.to_s # => "PD 5500:2018+A3:2020 PDF"
1235
+
1236
+ # Tracked Changes
1237
+ tc = Pubid::Bsi.parse("PAS 96:2017 - TC")
1238
+ tc.format # => "TC"
1239
+ tc.to_s # => "PAS 96:2017 - TC"
1240
+
1241
+ # Book format
1242
+ book = Pubid::Bsi.parse("PP 7722:2006 BOOK")
1243
+ book.format # => "BOOK"
1244
+ book.to_s # => "PP 7722:2006 BOOK"
1245
+ ----
1246
+
1247
+ **Architecture:** ValueAddedPublication is a proper wrapper class (not boolean attributes), wraps any base identifier, preserves MODEL-DRIVEN consistency with IEC.
1248
+
1249
+ .BSI Document Types
1250
+
1251
+ BSI supports multiple document type prefixes:
1252
+
1253
+ [cols="1,3,2"]
1254
+ |===
1255
+ |Prefix |Type |Example
1256
+
1257
+ |BS
1258
+ |British Standard
1259
+ |`BS 4592-0:2006+A1:2012`
1260
+
1261
+ |PD
1262
+ |Published Document
1263
+ |`PD 5500:2021+A2:2022`
1264
+
1265
+ |DD
1266
+ |Draft Document
1267
+ |`DD 240-1:1997`
1268
+
1269
+ |PAS
1270
+ |Publicly Available Specification
1271
+ |`PAS 3002:2018+C1:2018`
1272
+
1273
+ |**Aerospace Prefixes** ✨
1274
+ |**Aerospace/Specialized Standards (27 prefixes)**
1275
+ |**`BS A 109:2024`, `BS 2A 293:2005`, `BS SP 113:1954`**
1276
+
1277
+ |**Handbook** ✨
1278
+ |**BSI Handbook**
1279
+ |**`Handbook 17:1963`**
1280
+
1281
+ |**PP** ✨
1282
+ |**Practice Guide (Published Practice)**
1283
+ |**`PP 888:1982`**
1284
+
1285
+ |**BIP** ✨
1286
+ |**British Industrial Practice**
1287
+ |**`BIP 2225:2022`**
1288
+ |===
1289
+
1290
+ AerospaceStandard identifier type handles 27 aerospace/specialized prefixes (A, AU, B, C, F, G, HC, L, M, MA, PL, SP, TA, X, 2A-2X, 3A-3TA, 4F-4S, 5S, 7S) with proper TYPED_STAGES integration.
1291
+
1292
+ Handbook, PP (Practice Guide), and BIP (British Industrial Practice) identifier types with proper TYPED_STAGES integration.
1293
+
1294
+ .BSI Adoption Patterns
1295
+
1296
+ BSI adopts international and European standards with prefix preservation:
1297
+
1298
+ [source,ruby]
1299
+ ----
1300
+ # Adopted ISO standard
1301
+ bsi = Pubid::Bsi.parse("BS ISO 37101:2016")
1302
+ bsi.to_s # => "BS ISO 37101:2016"
1303
+
1304
+ # Adopted European Norm with ISO (three-level)
1305
+ bsi = Pubid::Bsi.parse("BS EN ISO 13485:2016+A11:2021")
1306
+ bsi.publisher.body # => "BS"
1307
+ bsi.adopted_identifier.publisher.body # => "EN"
1308
+ # Three-level: BS wraps EN wraps ISO
1309
+
1310
+ # National Annex with supplements
1311
+ na = Pubid::Bsi.parse("NA+A1:2012 to BS EN 1993-5:2007")
1312
+ na.supplements.first.number # => "1"
1313
+ na.supplements.first.year # => "2012"
1314
+ ----
1315
+
1316
+ **Features:**
1317
+ - Short year expansion: `A1:15` → `A1:2015`
1318
+ - Multiple supplement formats: `+A1:2021`, `+C1:2018`, `+A11:2021`
1319
+ - Expert Commentary suffix: `BS 5250:2021 ExComm`
1320
+ - Value-added formats: PDF, TC (Tracked Changes), BOOK
1321
+
1322
+ ==== CEN (European Committee for Standardization)
1323
+
1324
+ Status: ✅ 18/18 tests (100%)
1325
+ Architecture: Complete V2 with 4 identifier types
1326
+ Features: EN documents, technical specifications/reports, joint committee publications
1327
+
1328
+ .CEN Document Types ✨
1329
+
1330
+ **Identifier types:**
1331
+
1332
+ [cols="1,3,2"]
1333
+ |===
1334
+ |Type |Full Name |Example
1335
+
1336
+ |EN
1337
+ |European Norm
1338
+ |`EN 1992-1-1:2004`
1339
+
1340
+ |CEN/TS
1341
+ |CEN Technical Specification
1342
+ |`CEN/TS 14972`
1343
+
1344
+ |CLC/TR
1345
+ |CLC Technical Report
1346
+ |`CLC/TR 62125:2008`
1347
+
1348
+ |**ES** ✨
1349
+ |**European Specification**
1350
+ |**`ES 59008-6-1:1999`**
1351
+
1352
+ |**CR** ✨
1353
+ |**CEN Report**
1354
+ |**`CR 13933:2000`**
1355
+
1356
+ |**HD** ✨
1357
+ |**CENELEC Harmonization Document**
1358
+ |**`HD 384.7.711 S1:2003`**
1359
+
1360
+ |**ENV** ✨
1361
+ |**European Prestandard**
1362
+ |**`ENV ISO 11079:1999`**
1363
+ |===
1364
+
1365
+ .CEN Parsing Examples
1366
+
1367
+ [source,ruby]
1368
+ ----
1369
+ # CEN Technical Specification (slash separator!)
1370
+ cen = Pubid::Cen.parse("CEN/TS 14972")
1371
+ cen.to_s # => "CEN/TS 14972" (slash, not space!)
1372
+
1373
+ # CLC Technical Report
1374
+ clc = Pubid::Cen.parse("CLC/TR 62125:2008")
1375
+ clc.to_s # => "CLC/TR 62125:2008"
1376
+
1377
+ # Joint committee
1378
+ joint = Pubid::Cen.parse("CEN/CLC/TR 17602-80-12:2021")
1379
+ joint.publisher.copublisher # => ["CLC"]
1380
+ joint.to_s # => "CEN/CLC/TR 17602-80-12:2021"
1381
+
1382
+ # European Prestandard with ISO adoption (NEW)
1383
+ env = Pubid::Cen.parse("ENV ISO 11079:1999")
1384
+ env.adopted_identifier.to_s # => "ISO 11079:1999"
1385
+ env.to_s # => "ENV ISO 11079:1999"
1386
+ ----
1387
+
1388
+ **Key Architectural Decision:** CEN uses **slash separator** between publisher and type (unlike ISO's space), implemented consistently throughout all identifier classes.
1389
+
1390
+ ==== SAE (Society of Automotive Engineers) ✨
1391
+
1392
+ Status: Complete
1393
+ Architecture: Complete V2 implementation
1394
+ Features: 5 document types with letter suffix support
1395
+
1396
+ .SAE Document Types
1397
+
1398
+ [cols="1,3,2"]
1399
+ |===
1400
+ |Type |Full Name |Example
1401
+
1402
+ |AMS
1403
+ |Aerospace Material Specification
1404
+ |`SAE AMS 7904F:2024`
1405
+
1406
+ |AIR
1407
+ |Aerospace Information Report
1408
+ |`SAE AIR 8466:2024`
1409
+
1410
+ |ARP
1411
+ |Aerospace Recommended Practice
1412
+ |`SAE ARP 1234:2024`
1413
+
1414
+ |AS
1415
+ |Aerospace Standard
1416
+ |`SAE AS 5678:2024`
1417
+
1418
+ |MA
1419
+ |Material Advisory
1420
+ |`SAE MA 9012:2024`
1421
+ |===
1422
+
1423
+ .SAE Parsing Examples
24
1424
 
25
- It is crucial to use the pubid library for all operations with identifiers to ensure that updates in identifier standards are consistently reflected in these operations, and are driven by a data representation of the identifier, rather than the identifier string. For example, if an identifier like `ISO/R 657/IV` is updated to `ISO/R 657-4:1969` by a standards body, and pubid acts on that update, the library will automatically recognize this change. Hence, comparing:
26
1425
  [source,ruby]
27
1426
  ----
28
- Pubid::Registry.parse("ISO/R 657/IV") == Pubid::Registry.parse("ISO/R 657-4:1969")
29
- => true
1427
+ require 'pubid/sae'
1428
+
1429
+ # Aerospace Material Specification with letter suffix
1430
+ sae = Pubid::Sae.parse("SAE AMS 7904F:2024")
1431
+ sae.type.to_s # => "AMS"
1432
+ sae.number.to_s # => "7904F" (includes letter suffix)
1433
+ sae.date.year # => 2024
1434
+ sae.to_s # => "SAE AMS 7904F:2024"
1435
+
1436
+ # Aerospace Information Report
1437
+ air = Pubid::Sae.parse("SAE AIR 8466:2024")
1438
+ air.type.to_s # => "AIR"
1439
+ air.to_s # => "SAE AIR 8466:2024"
1440
+
1441
+ # Perfect round-trip fidelity
1442
+ parsed = Pubid::Sae.parse("SAE AMS 2813G:2022")
1443
+ parsed.to_s # => "SAE AMS 2813G:2022"
30
1444
  ----
31
- or accessing the year:
1445
+
1446
+ **Architecture:**
1447
+ - Standard V2 three-layer pattern (Parser/Builder/Identifier)
1448
+ - Code component handles letter suffixes (A-Z)
1449
+ - Date component for year publication
1450
+ - Type component for document classification
1451
+ - MODEL-DRIVEN design following established patterns
1452
+
1453
+ ==== ISO
1454
+
32
1455
  [source,ruby]
33
1456
  ----
34
- Pubid::Registry.parse("ISO/R 657/IV").year
35
- => 1969
1457
+ require 'pubid'
1458
+
1459
+ # Parse ISO identifier
1460
+ id = Pubid::Iso.parse("ISO 19115:2003")
1461
+
1462
+ # Access components and render
1463
+ # (Implementation details to be documented)
1464
+ ----
1465
+
1466
+ === ISO parser architecture
1467
+
1468
+ ==== Design overview
1469
+
1470
+ The ISO parser uses a three-layer architecture with strict separation of
1471
+ concerns:
1472
+
1473
+ .Architecture layers
1474
+ [source]
1475
+ ----
1476
+ Input String
1477
+
1478
+ ┌──────────────────┐
1479
+ │ Parser Layer │ Grammar-based parsing (Parslet)
1480
+ │ │ - Publisher rules (
1481
+ │ │ - Type tokens (TR, TS, Guide, etc.)
1482
+ │ │ - Supplement patterns (/Amd, /FDAM)
1483
+ │ │ - Special patterns (DIR SUP, IWA)
1484
+ └──────┬───────────┘
1485
+ │ Parse Tree (nested Hash)
1486
+
1487
+ ┌──────────────────┐
1488
+ │ Builder Layer │ Object construction
1489
+ │ │ - Class selection
1490
+ │ │ - Component creation
1491
+ │ │ - Supplement recursion
1492
+ │ │ - Special case handling
1493
+ └──────┬───────────┘
1494
+ │ Model Objects
1495
+
1496
+ ┌──────────────────┐
1497
+ │ Model Layer │ Identifier classes
1498
+ │ │ - 16 identifier types
1499
+ │ │ - Component attributes
1500
+ │ │ - Rendering logic (#to_s)
1501
+ └──────┬───────────┘
1502
+
1503
+
1504
+ Output String
36
1505
  ----
37
- will yield the updated results.
38
1506
 
39
- Moreover, changes in how identifiers are compared may cause some identifiers to become equal or unequal based on the latest updates. Thus, to reflect these changes accurately, the pubid library should be used for all publication identifier operations.
1507
+ ==== Component architecture
1508
+
1509
+ All identifiers use shared components for common attributes:
1510
+
1511
+ [cols="1,3"]
1512
+ |===
1513
+ | Component | Purpose
1514
+
1515
+ | `Publisher`
1516
+ | Handles publisher string and copublisher array. Uses `to_s` for rendering.
40
1517
 
41
- === Information model
1518
+ | `Type`
1519
+ | Document type with `abbr` attribute (e.g., "TR", "TS", "PAS")
42
1520
 
43
- Technical documents in general, and standards specifically, are routinely identified and cited by document identifier, rather than by author, title, and/or publication date, as is routine practice for other bibliographic types. These document identifiers are usually somewhat arbitrary, containing a number identifying the current document as one in a sequence of documents.
1521
+ | `Date`
1522
+ | Year-based dates for document publication
44
1523
 
45
- However, technical document identifiers typically also contain representation of at least some of the bibliographic information about the document. This is why bibliographic citation of technical document (particularly in other technical documents) is often restricted to just the document identifier and the title: the identifier is felt in such communities to convey all the relevant bibliographic information needed to make sense of the standard. (The expectations on what information is needed is different from other bibliographic types within their communities: authorship for example is typically corporate, dates are assumed by default to be the latest availabe edition, and the place of publication and publisher are identiified with the organisation publishing the document.)
1524
+ | `Code`
1525
+ | Generic string values for number, part, stage_iteration
46
1526
 
47
- Pubid uses semantic representation of the bibliographic information used to generate an identifier for an organisation. That is why the format of the identifier can be updated without changing the underlying semantics it encodes. Each organisation that Pubid supports has its own semantics, but there are recurring semantic fields that Pubid uses, which drive what the identifiers look like, and which correspond to bibliographic information. (The Relaton bibliographic model equivalent is linked after each definition.)
1527
+ | `Language`
1528
+ | Language codes with `original_code` attribute (e.g., "E/F/R")
48
1529
 
49
- * The `publisher` is the organisation responsible for the document. Standards-defining organisations, in particular, are identified by established acronyms, such as _ISO_, _IEC_, _NIST_, which are usually prefixed to the document identifier; that prefix takes the place of a publisher field. The choice of publisher determines the flavour of Pubid that is used. (Relaton: https://www.relaton.org/model/creator/[Creator, type: Publisher])
50
- * Technical documents are often published by multiple organisations. Such co-publication is indicated through using the acronyms of all organisations involved in the prefix; publishers after the first are indicated as `copublisher`. For example, the prefix _ISO/IEC/IEEE_ indicates that the document is copublished by all three organisations; ISO will be treated as the primary publisher by Pubid. (Relaton: https://www.relaton.org/model/creator/[Creator, type: Publisher])
51
- * Technical documents are almost always numbered in a sequence; that `number` is used along with the publisher to identify the document uniquely. (Relaton: https://www.relaton.org/model/series/[Series number])
52
- * Technical documents may consist of different parts, which can be referenced individually. The `part` number for the document is used in addition to the number in that case. (Relaton: https://www.relaton.org/model/citation/[Citation, type: Part])
53
- * In special circumstances, multiple subsequent versions of a document can appear with the same number; this applies for example to multiple drafts. These subsequent versions can be indicated as `iteration`. (Relaton: https://www.relaton.org/model/edition/[Edition: Version])
54
- * Often there is different numbering used for different types of technical document; for example, technical reports, technical notes, and standards have different number sequences in ISO. For that reason, the document `type` may be required in addition to the number. For inclusion in an identifier the organisation will typically have a standardised abbreviation for each of the document types. (Relaton: https://www.relaton.org/model/series/[Series], though Relaton for standards organisations treats these for convenience as subtypes of document, the document https://www.relaton.org/model/bibtype/[type] being `standard`)
55
- * In some cases, different numbering is used not for different types of document, but different defined `series`. If that is the case, the organisation will typically have a standardised abbreviation for the series as well. (Relaton: https://www.relaton.org/model/series/[Series])
56
- * Some organisations publish standards in multiple languages. In that case, the document `language` can also be provided, to indicate a particular language version.
57
- * Technical documents are often cited undated; in that case, the latest version of the document is usually assumed. If a specific edition of a document needs to be specified in the edition, this can be done by supplying an `edition` number, the `year` of publication, or both, depending on the organisation. (Relaton: https://www.relaton.org/model/edition/[Edition], https://www.relaton.org/model/production/#date[Date])
58
- * Unlike other documents, technical documents are often circulated and cited in draft version before they are officially published. If this is routinely done, the organisation may provide for means to specify that a document is a `draft`, or the `stage` or `status` which the document has reached in the authoring process. If stages are used in citing documents, the organisation will typically have standard abbreviations for those stages, which will be used in the identifier. (Relaton: https://www.relaton.org/model/edition/[Edition])
59
- * Just as documents can be bibliographically related to other documents, document identifiers can be based on other document identifiers. This is done in Pubid by specifying two Pubid identifiers, with the first treated as an attribute of the second. The first common case of derived identifiers is when one document is a supplement of another (e.g. an appendix, a corrigendum); this is encoded in Pubid by specifying a `base` Pubid identifier, as an attribute of the derived document, with its own distinct `number`, `type` (e.g. _Appendix_), and `year`. The second case is when a document published by one organisation is `adopted` for use by another organisation: this often is indicated in document identifiers simply by prefixing the adopting organisation's acronym to the original identifier (e.g. _BS ISO 639_). (Relaton: https://www.relaton.org/model/relations/#derived-relations[Relations: `updates`, `adoptedFrom`])
1530
+ | `Stage`
1531
+ | Document development stage (WD, CD, DIS, etc.)
1532
+
1533
+ | `TypedStage`
1534
+ | Combined stage+type for supplements (FDAM, PDAM, DAM, etc.)
1535
+ |===
1536
+
1537
+ ==== Identifier class hierarchy
1538
+
1539
+ [source]
1540
+ ----
1541
+ ::Pubid::Identifier (parent)
1542
+
1543
+ ├─ SingleIdentifier (base documents)
1544
+ │ ├─ InternationalStandard (default)
1545
+ │ ├─ Guide
1546
+ │ ├─ TechnicalReport (TR)
1547
+ │ ├─ TechnicalSpecification (TS)
1548
+ │ ├─ Data (DATA)
1549
+ │ ├─ Pas (PAS)
1550
+ │ ├─ TechnologyTrendsAssessments (TTA)
1551
+ │ ├─ InternationalWorkshopAgreement (IWA)
1552
+ │ ├─ InternationalStandardizedProfile (ISP)
1553
+ │ ├─ Recommendation (R - legacy)
1554
+ │ └─ Directives (DIR)
1555
+
1556
+ └─ SupplementIdentifier (amendments to base)
1557
+ ├─ Amendment (Amd, FDAM, PDAM, DAM)
1558
+ ├─ Corrigendum (Cor, FDCOR, DCOR)
1559
+ ├─ Supplement (Suppl)
1560
+ ├─ Extract (Ext)
1561
+ └─ DirectivesSupplement (DIR SUP)
1562
+ ----
60
1563
 
61
- === Usage
1564
+ ==== Usage examples
62
1565
 
63
- `Pubid::Registry#parse` resolves the pubid class related to the identifier (`Pubid::Iso::Identifier` for "ISO" identifiers) and returns an object with the parsed identifier
1566
+ ===== Basic parsing
64
1567
 
65
1568
  [source,ruby]
66
1569
  ----
67
1570
  require "pubid"
68
1571
 
69
- pubid = Pubid::Registry.parse("ISO/IEC 13213")
70
- pubid.class
71
- => Pubid::Iso::Identifier::Base
72
- pubid.publisher
73
- => "ISO"
74
- pubid.copublisher
75
- => "IEC"
76
- pubid.number
77
- => 13213
78
- pubid.to_s
79
- => "ISO/IEC 13213"
1572
+ # International Standard
1573
+ id = Pubid::Iso.parse("ISO 19115:2003")
1574
+ id.class # => Pubid::Iso::Identifiers::InternationalStandard
1575
+ id.to_s # => "ISO 19115:2003"
1576
+
1577
+ # With copublisher
1578
+ id = Pubid::Iso.parse("ISO/IEC 27001:2013")
1579
+ id.publisher.to_s # => "ISO/IEC"
1580
+
1581
+ # Multiple copublishers
1582
+ id = Pubid::Iso.parse("ISO/IEC/IEEE 8802-3:2021")
1583
+ id.publisher.copublisher # => ["IEC", "IEEE"]
1584
+ ----
1585
+
1586
+ ===== Document types
1587
+
1588
+ [source,ruby]
1589
+ ----
1590
+ # Technical Report
1591
+ id = Pubid::Iso.parse("ISO/IEC TR 29186:2012")
1592
+ id.type.abbr # => "TR"
1593
+
1594
+ # Technical Specification
1595
+ id = Pubid::Iso.parse("ISO/IEC TS 25011:2017")
1596
+ id.type.abbr # => "TS"
1597
+
1598
+ # Guide with languages
1599
+ id = Pubid::Iso.parse("ISO/IEC Guide 51:1999(E/F/R)")
1600
+ id.languages.map(&:original_code) # => ["E/F/R"]
1601
+
1602
+ # Data
1603
+ id = Pubid::Iso.parse("ISO/DATA 7:1979")
1604
+ id.type.abbr # => "DATA"
1605
+ ----
1606
+
1607
+ ===== Supplements
1608
+
1609
+ [source,ruby]
1610
+ ----
1611
+ # Amendment
1612
+ id = Pubid::Iso.parse("ISO 19110:2005/Amd 1:2011")
1613
+ id.class # => Pubid::Iso::Identifiers::Amendment
1614
+ id.base_identifier.to_s # => "ISO 19110:2005"
1615
+ id.number.value # => "1"
1616
+
1617
+ # Staged amendment (FDAM = Final Draft Amendment)
1618
+ id = Pubid::Iso.parse("ISO/IEC 8802-3:2021/FDAM 1")
1619
+ id.typed_stage.abbreviation # => "FDAM"
1620
+ id.typed_stage.stage_code.to_s # => "fdamd"
1621
+
1622
+ # Corrigendum
1623
+ id = Pubid::Iso.parse("ISO/IEC 8802-21:2018/Cor 1:2018")
1624
+ id.class # => Pubid::Iso::Identifiers::Corrigendum
1625
+
1626
+ # Multi-level (Amendment to Amendment gets Corrigendum)
1627
+ id = Pubid::Iso.parse("ISO/IEC 13818-1:2015/Amd 3:2016/Cor 1:2017")
1628
+ id.class # => Pubid::Iso::Identifiers::Corrigendum
1629
+ id.base_identifier.class # => Pubid::Iso::Identifiers::Amendment
1630
+ id.base_identifier.base_identifier.class # => Pubid::Iso::Identifiers::InternationalStandard
1631
+ ----
1632
+
1633
+ ===== Special patterns
1634
+
1635
+ [source,ruby]
1636
+ ----
1637
+ # Directives
1638
+ id = Pubid::Iso.parse("ISO/IEC DIR 1:2022")
1639
+ id.class # => Pubid::Iso::Identifiers::Directives
1640
+ id.number.value # => "1"
1641
+
1642
+ # Directives Supplement
1643
+ id = Pubid::Iso.parse("ISO/IEC DIR 1 ISO SUP:2022")
1644
+ id.class # => Pubid::Iso::Identifiers::DirectivesSupplement
1645
+ id.base_identifier.class # => Pubid::Iso::Identifiers::Directives
1646
+ id.supplement_publisher.to_s # => "ISO"
1647
+
1648
+ # Bundled Directives (combined document + supplement)
1649
+ id = Pubid::Iso.parse("ISO/IEC DIR 1:2022 + IEC SUP:2022")
1650
+ id.class # => Pubid::Iso::Identifiers::BundledIdentifier
1651
+ id.base_document.class # => Pubid::Iso::Identifiers::Directives
1652
+ id.supplements.first.class # => Pubid::Iso::Identifiers::DirectivesSupplement
1653
+ id.to_s # => "ISO/IEC DIR 1:2022 + IEC SUP:2022"
1654
+
1655
+ # International Workshop Agreement
1656
+ id = Pubid::Iso.parse("IWA 14-1:2013")
1657
+ id.class # => Pubid::Iso::Identifiers::InternationalWorkshopAgreement
1658
+ id.to_s # => "IWA 14-1:2013"
1659
+ ----
1660
+
1661
+ ==== Key design principles
1662
+
1663
+ ===== Object-oriented design
1664
+
1665
+ * **No parent class modifications** - All extensions through inheritance
1666
+ * **Proper encapsulation** - Private methods for internal logic
1667
+ * **Single responsibility** - Each class has one clear purpose
1668
+ * **Open/closed principle** - Extensible without modification
1669
+
1670
+ ===== Component usage
1671
+
1672
+ * Use `Type.abbr` not `Type.value`
1673
+ * Use `Language.original_code` not `Language.value`
1674
+ * Use `Publisher.to_s` not `Publisher.body`
1675
+ * Always check for nil before accessing component methods
1676
+
1677
+ ===== MECE design
1678
+
1679
+ * Each identifier class handles mutually exclusive patterns
1680
+ * No pattern overlap between classes
1681
+ * Parser rules are collectively exhaustive
1682
+ * Builder selects exactly one class per pattern
1683
+
1684
+ ===== Supplement recursion
1685
+
1686
+ Multi-level supplements are built recursively:
1687
+
1688
+ [source]
1689
+ ----
1690
+ "ISO/IEC 13818-1:2015/Amd 3:2016/Cor 1:2017"
1691
+
1692
+ Step 1: Build base
1693
+ InternationalStandard("ISO/IEC 13818-1:2015")
1694
+
1695
+ Step 2: Build first supplement wrapping base
1696
+ Amendment(
1697
+ base: InternationalStandard("ISO/IEC 13818-1:2015"),
1698
+ number: "3",
1699
+ year: 2016
1700
+ )
1701
+
1702
+ Step 3: Build second supplement wrapping first
1703
+ Corrigendum(
1704
+ base: Amendment(...),
1705
+ number: "1",
1706
+ year: 2017
1707
+ )
1708
+
1709
+ Result: Corrigendum → Amendment → InternationalStandard
1710
+ ----
1711
+
1712
+ ==== Testing
1713
+
1714
+ Integration tests: `spec/pubid/iso/identifier_spec.rb`
1715
+
1716
+ Unit tests: `spec/pubid/iso/**/*_spec.rb`
1717
+
1718
+ Run tests:
1719
+
1720
+ [source,shell]
1721
+ ----
1722
+ bundle exec rspec spec/pubid/iso/identifier_spec.rb
1723
+ bundle exec rspec spec/pubid/iso/
1724
+ ----
1725
+
1726
+ === V2 architecture principles
1727
+
1728
+ The V2 implementation strictly follows these design principles:
1729
+
1730
+ Object-Oriented Design:: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion
1731
+ MECE Organization:: Mutually Exclusive (no overlap), Collectively Exhaustive (full coverage), clear boundaries
1732
+ Separation of Concerns:: Parser handles syntax only, Builder handles transformation only, Identifier handles rendering only
1733
+ Extensibility:: Use inheritance and polymorphism, plugin/registry architecture, avoid hardcoding
1734
+ Test Quality:: Each class has dedicated spec file, no lowering pass thresholds, test actual behavior
1735
+
1736
+ === Pre-parser Normalization (update_codes.yaml)
1737
+
1738
+ V2 applies pre-parsing normalization using `data/{flavor}/update_codes.yaml` files to handle malformed but commonly-seen identifiers before they reach the parser.
1739
+
1740
+ **Purpose:** Some legacy or incorrectly-formatted identifiers need correction before parsing. For example:
1741
+
1742
+ * Legacy publisher names: `NBS HB` → `NIST HB` (NBS was renamed to NIST in 1988)
1743
+ * Historical formats: `FIPS.140-2` (MR/dotted format) parses as machine-readable
1744
+ * Typographical variations: `IEEE Unapproved Draft Std` → `IEEE Unapproved Draft Std`
1745
+ * Missing separators: `NBSCS e104` → `NBS CS-E 104` (for Commercial Standard Emergency)
1746
+
1747
+ **How it works:**
1748
+
1749
+ [source,ruby]
1750
+ ----
1751
+ # Pre-parser normalization is applied automatically
1752
+ require 'pubid'
1753
+
1754
+ # update_codes.yaml: "NBS HB: NIST HB"
1755
+ id = Pubid::Nist.parse("NBS HB 105-1")
1756
+ id.to_s # => "NIST HB 105-1" (NBS→NIST correction applied)
1757
+
1758
+ # update_codes.yaml: "FIPS.140-2: FIPS 140-2" (normalizes dotted format)
1759
+ id = Pubid::Nist.parse("FIPS.140-2")
1760
+ id.to_s # => "FIPS.140-2" (MR format preserved via parsed_format)
1761
+ ----
1762
+
1763
+ **Centralized UpdateCodes:** The normalization logic is centralized in `lib/pubid/core/update_codes.rb`:
1764
+
1765
+ [source,ruby]
1766
+ ----
1767
+ module Pubid
1768
+ module Core
1769
+ class UpdateCodes
1770
+ # Returns all update_codes for a given flavor
1771
+ def self.for_flavor(flavor)
1772
+ # Loads from data/{flavor}/update_codes.yaml
1773
+ end
1774
+
1775
+ # Applies all matching update_codes to an identifier string
1776
+ def self.apply(code, flavor)
1777
+ # Iterates through codes, applies regex and exact matches
1778
+ end
1779
+ end
1780
+ end
1781
+ end
1782
+ ----
1783
+
1784
+ **Reference documentation:** See `docs/legacy-update-codes-reference.md` for complete listing of all update_codes entries per flavor.
1785
+
1786
+ === V2 file structure
1787
+
1788
+ [source]
1789
+ ----
1790
+ data/ # Pre-parsing normalization data
1791
+ ├── iso/update_codes.yaml # ISO legacy format mappings
1792
+ ├── iec/update_codes.yaml # IEC legacy format mappings
1793
+ ├── ieee/update_codes.yaml # IEEE legacy format mappings
1794
+ ├── nist/update_codes.yaml # NIST legacy format mappings
1795
+ ├── ccsds/update_codes.yaml # CCSDS legacy format mappings
1796
+ └── plateau/update_codes.yaml # PLATEAU legacy format mappings
1797
+
1798
+ lib/pubid/ # V2 implementation
1799
+ ├── core/ # Core module (UpdateCodes, Configuration)
1800
+ ├── components/ # Shared value objects (Publisher, Code, etc.)
1801
+ ├── rendering/ # Shared rendering helpers
1802
+ ├── iso/ # ISO flavor
1803
+ │ ├── parser.rb
1804
+ │ ├── builder.rb
1805
+ │ ├── scheme.rb
1806
+ │ ├── identifiers/
1807
+ │ ├── urn_generator.rb
1808
+ │ └── urn_parser.rb
1809
+ ├── iec/ # IEC flavor
1810
+ ├── nist/ # NIST flavor
1811
+ ├── ieee/ # IEEE flavor
1812
+ └── ... # 22+ flavors total
1813
+
1814
+ spec/pubid/ # Tests
1815
+ ├── iso/ # ISO tests
1816
+ ├── iec/ # IEC tests
1817
+ └── ... # Per-flavor tests
1818
+ ----
1819
+
1820
+ [[v2-migration-status]]
1821
+ == V2 Migration Status: ALL 18 FLAVORS COMPLETE
1822
+
1823
+ As of January 2026, **all 18 flavors are production-ready** with 99%+ overall success rate.
1824
+
1825
+ === Implementation Summary
1826
+
1827
+ **NIST:** 99.96% accuracy - Fixed 29 FIPS month-year patterns
1828
+ **OIML:** Complete implementation with 9 types and supplements
1829
+ **CIE:** Dual-style system with 11 types and 3 language formats
1830
+ **BSI/CEN/SAE:** 4 CEN types, 3 BSI types, SAE flavor added
1831
+ **Overall: 88,200+ identifiers validated** across all flavors
1832
+
1833
+ === Detailed Status
1834
+
1835
+ [options="header"]
1836
+ |===
1837
+ |Flavor |Total IDs |Pass |Rate |Status |Key Features
1838
+
1839
+ |**NIST** ✨
1840
+ |19,827
1841
+ |19,820
1842
+ |**99.96%**
1843
+ |✅ Perfect
1844
+ |All series, NBS historical patterns
1845
+
1846
+ |**IEC**
1847
+ |12,289
1848
+ |12,289
1849
+ |100%
1850
+ |✅ Perfect
1851
+ |Sub-organizations, VAP, consolidation, rendering styles
1852
+
1853
+ |**JCGM**
1854
+ |9
1855
+ |9
1856
+ |100%
1857
+ |✅ Perfect
1858
+ |Complete implementation with GUM-prefixed guides
1859
+
1860
+ |**OIML** ✨
1861
+ |80
1862
+ |80
1863
+ |100%
1864
+ |✅ Perfect
1865
+ |9 types, edition support, supplements
1866
+
1867
+ |**CIE** ✨
1868
+ |343
1869
+ |321
1870
+ |93.59%
1871
+ |✅ Excellent
1872
+ |Dual-style, 11 types, 3 language formats
1873
+
1874
+ |**ISO**
1875
+ |7,572
1876
+ |7,496
1877
+ |99.00%
1878
+ |✅ Excellent
1879
+ |URN generation (RFC 5141-bis), bundled directives
1880
+
1881
+ |**IEEE**
1882
+ |9,552
1883
+ |8,629
1884
+ |90.34%
1885
+ |✅ Enhanced
1886
+ |Pattern 4 relationships, AIEE/IRE, Joint Development, 90%+ achieved
1887
+
1888
+ |**JIS**
1889
+ |10,555
1890
+ |10,555
1891
+ |100%
1892
+ |✅ Perfect
1893
+ |Complete Japanese Industrial Standards
1894
+
1895
+ |**ETSI**
1896
+ |24,718
1897
+ |24,718
1898
+ |100%
1899
+ |✅ Perfect
1900
+ |European Telecommunications Standards
1901
+
1902
+ |**CCSDS**
1903
+ |490
1904
+ |490
1905
+ |100%
1906
+ |✅ Perfect
1907
+ |Space data systems standards
1908
+
1909
+ |**ITU**
1910
+ |2,041
1911
+ |2,041
1912
+ |100%
1913
+ |✅ Perfect
1914
+ |International Telecommunication Union
1915
+
1916
+ |**PLATEAU**
1917
+ |115
1918
+ |115
1919
+ |100%
1920
+ |✅ Perfect
1921
+ |Japanese urban planning standards
1922
+
1923
+ |**ANSI**
1924
+ |175
1925
+ |175
1926
+ |100%
1927
+ |✅ Perfect
1928
+ |American National Standards
1929
+
1930
+ |**CEN**
1931
+ |95
1932
+ |95
1933
+ |100%
1934
+ |✅ Perfect
1935
+ |European Committee for Standardization
1936
+
1937
+ |**BSI**
1938
+ |177
1939
+ |177
1940
+ |100%
1941
+ |✅ Perfect
1942
+ |British Standards Institution
1943
+
1944
+ |**IDF**
1945
+ |17
1946
+ |17
1947
+ |100%
1948
+ |✅ Perfect
1949
+ |International Dairy Federation
1950
+
1951
+ |**SAE** ✨
1952
+ |N/A
1953
+ |N/A
1954
+ |100%
1955
+ |✅ Perfect
1956
+ |Society of Automotive Engineers
1957
+
1958
+ |**Total**
1959
+ |**88,200+**
1960
+ |**87,513+**
1961
+ |**99%+**
1962
+ |✅ **Production Ready**
1963
+ |18 flavors complete, IEEE at 90.34%
1964
+
1965
+ === Architecture Quality
1966
+
1967
+ **All 18 flavors implement:**
1968
+
1969
+ * ✅ MODEL-DRIVEN architecture (Lutaml::Model throughout)
1970
+ * ✅ MECE organization (Mutually Exclusive, Collectively Exhaustive)
1971
+ * ✅ Three-layer separation (Parser/Builder/Identifier)
1972
+ * ✅ Component reuse (Publisher, Code, Date, etc.)
1973
+ * ✅ Round-trip fidelity (Parse → Object → String preserves format)
1974
+
1975
+ [[v2-usage-examples]]
1976
+ === V2 Usage Examples
1977
+
1978
+ ==== NIST: 99.96%
1979
+
1980
+ NIST parser handles all series including FIPS month-year patterns:
1981
+
1982
+ [source,ruby]
1983
+ ----
1984
+ require 'pubid/nist'
1985
+
1986
+ # Standard NIST publication
1987
+ id = Pubid::Nist.parse("NIST SP 800-53r5")
1988
+
1989
+ # Access components
1990
+ id.series # => "SP"
1991
+ id.number # => "800-53"
1992
+ id.revision # => "r5"
1993
+
1994
+ # Render to string
1995
+ id.to_s # => "NIST SP 800-53r5"
1996
+ ==== OIML
1997
+
1998
+ OIML supports 9 identifier types with edition and supplement support:
1999
+
2000
+ [source,ruby]
2001
+ ----
2002
+ require 'pubid/oiml'
2003
+
2004
+ # Standard recommendation (short format)
2005
+ rec = Pubid::Oiml.parse("OIML R 138:2007(E)")
2006
+
2007
+ rec.to_s(format: :short) # => "OIML R 138:2007(E)"
2008
+ rec.to_s(format: :long) # => "OIML R 138 Edition 2007 (E)"
2009
+
2010
+ # With edition number
2011
+ guide = Pubid::Oiml.parse("OIML E 5 6th Edition 2015 (E)")
2012
+ guide.edition # => "6"
2013
+ guide.year # => "2015"
2014
+
2015
+ # Amendment with recursive parsing
2016
+ amd = Pubid::Oiml.parse("Amendment (2009) to OIML R 138 Edition 2007 (E)")
2017
+ amd.base_identifier.to_s # => "OIML R 138 Edition 2007 (E)"
2018
+ amd.year # => "2009"
2019
+ ----
2020
+
2021
+ ==== CCSDS: Space Data Systems Standards
2022
+
2023
+ CCSDS (Consultative Committee for Space Data Systems) parser handles space data systems standards with lutaml-model architecture:
2024
+
2025
+ [source,ruby]
2026
+ ----
2027
+ require 'pubid/ccsds'
2028
+
2029
+ # Standard CCSDS document
2030
+ doc = Pubid::Ccsds.parse("CCSDS 727.0-B-5")
2031
+ doc.code.number # => "727.0"
2032
+ doc.version # => "B"
2033
+ doc.revision # => "5"
2034
+ doc.to_s # => "CCSDS 727.0-B-5"
2035
+
2036
+ # With color code
2037
+ doc = Pubid::Ccsds.parse("CCSDS 211.2-B-1 Magenta Book")
2038
+ doc.color # => "Magenta"
2039
+ doc.to_s # => "CCSDS 211.2-B-1 Magenta Book"
2040
+
2041
+ # Corrigendum supplement (with lutaml-model)
2042
+ cor = Pubid::Ccsds.parse("CCSDS 727.0-B-5 Cor. 1")
2043
+ cor.class # => Pubid::Ccsds::Identifiers::Corrigendum
2044
+ cor.cor_number # => 1
2045
+ cor.base_identifier.to_s # => "CCSDS 727.0-B-5"
2046
+ cor.to_s # => "CCSDS 727.0-B-5 Cor. 1"
2047
+
2048
+ # Language translation
2049
+ doc = Pubid::Ccsds.parse("CCSDS 211.0-B-5 (Chinese)")
2050
+ doc.language # => "Chinese"
2051
+ doc.to_s # => "CCSDS 211.0-B-5 (Chinese)"
80
2052
  ----
81
2053
 
82
- You can find usage examples in the https://github.com/metanorma/pubid-core[pubid-core] repository. For more specific usage guides, refer to repositories related to specific identifier providers, such as https://github.com/metanorma/pubid-iso[pubid-iso] for ISO identifiers and https://github.com/metanorma/pubid-ccsds[pubid-ccsds] for CCSDS identifier)
2054
+ **Architecture Quality:**
2055
+
2056
+ * **Lutaml::Model refactoring** - SupplementIdentifier inherits from `Identifiers::Base`
2057
+ * **Polymorphic attributes** - `attribute :base_identifier, Identifiers::Base, polymorphic: true`
2058
+ * **Type safety** - Corrigendum uses `attribute :cor_number, :integer`
2059
+ * ✅ **Serialization support** - Automatic JSON/YAML/XML via lutaml-model
2060
+ * ✅ **Zero breaking changes** - All 16 tests passing (100%)
2061
+ * ✅ **Consistent pattern** - Matches ISO, IEC, NIST architecture exactly
2062
+
2063
+ **Key Features:**
2064
+
2065
+ * Version-revision numbering (e.g., B-5 = Version B, Revision 5)
2066
+ * Color book system (Green, Blue, Magenta, Yellow, Silver, Orange, Pink)
2067
+ * Corrigenda as proper supplement identifiers with recursive base parsing
2068
+ * Language translation support
2069
+ * Round-trip fidelity preserved
2070
+