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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +5 -1
  3. data/data/nist/update_codes.yaml +27 -0
  4. data/lib/pubid/amca/builder.rb +2 -2
  5. data/lib/pubid/amca/identifier.rb +7 -0
  6. data/lib/pubid/amca/identifiers/base.rb +0 -26
  7. data/lib/pubid/amca/identifiers/interpretation.rb +0 -17
  8. data/lib/pubid/amca/identifiers/publication.rb +0 -13
  9. data/lib/pubid/amca/renderer.rb +82 -0
  10. data/lib/pubid/amca/single_identifier.rb +0 -23
  11. data/lib/pubid/amca/urn_parser.rb +28 -0
  12. data/lib/pubid/amca.rb +42 -1
  13. data/lib/pubid/ansi/builder.rb +5 -3
  14. data/lib/pubid/ansi/identifier.rb +1 -1
  15. data/lib/pubid/ansi/identifiers/american_national_standard.rb +2 -1
  16. data/lib/pubid/ansi/identifiers/standard.rb +2 -3
  17. data/lib/pubid/ansi/renderer.rb +53 -0
  18. data/lib/pubid/ansi/single_identifier.rb +2 -31
  19. data/lib/pubid/ansi/urn_generator.rb +3 -38
  20. data/lib/pubid/ansi/urn_parser.rb +23 -0
  21. data/lib/pubid/ansi.rb +38 -3
  22. data/lib/pubid/api/builder.rb +29 -74
  23. data/lib/pubid/api/identifier.rb +0 -4
  24. data/lib/pubid/api/identifiers/base.rb +0 -2
  25. data/lib/pubid/api/identifiers/bulletin.rb +0 -2
  26. data/lib/pubid/api/identifiers/continuous_operations_standard.rb +0 -2
  27. data/lib/pubid/api/identifiers/mpms.rb +1 -17
  28. data/lib/pubid/api/identifiers/publication.rb +0 -2
  29. data/lib/pubid/api/identifiers/recommended_practice.rb +0 -2
  30. data/lib/pubid/api/identifiers/specification.rb +0 -2
  31. data/lib/pubid/api/identifiers/standard.rb +0 -2
  32. data/lib/pubid/api/identifiers/technical_report.rb +0 -2
  33. data/lib/pubid/api/identifiers/typeless_standard.rb +1 -14
  34. data/lib/pubid/api/identifiers.rb +18 -0
  35. data/lib/pubid/api/renderer.rb +89 -0
  36. data/lib/pubid/api/single_identifier.rb +1 -13
  37. data/lib/pubid/api/urn_generator.rb +0 -18
  38. data/lib/pubid/api/urn_parser.rb +35 -0
  39. data/lib/pubid/api.rb +51 -5
  40. data/lib/pubid/ashrae/builder.rb +3 -3
  41. data/lib/pubid/ashrae/identifier.rb +6 -0
  42. data/lib/pubid/ashrae/identifiers/addenda_package.rb +0 -10
  43. data/lib/pubid/ashrae/identifiers/addendum.rb +0 -19
  44. data/lib/pubid/ashrae/identifiers/base.rb +3 -0
  45. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +0 -15
  46. data/lib/pubid/ashrae/identifiers/errata.rb +0 -10
  47. data/lib/pubid/ashrae/identifiers/interpretation.rb +0 -10
  48. data/lib/pubid/ashrae/renderer.rb +117 -0
  49. data/lib/pubid/ashrae/single_identifier.rb +0 -13
  50. data/lib/pubid/ashrae/urn_generator.rb +0 -8
  51. data/lib/pubid/ashrae/urn_parser.rb +27 -0
  52. data/lib/pubid/ashrae.rb +42 -1
  53. data/lib/pubid/asme/components/code.rb +10 -2
  54. data/lib/pubid/asme/identifiers/base.rb +0 -60
  55. data/lib/pubid/asme/renderer.rb +66 -0
  56. data/lib/pubid/asme/urn_parser.rb +31 -0
  57. data/lib/pubid/asme.rb +42 -1
  58. data/lib/pubid/astm/components/code.rb +9 -0
  59. data/lib/pubid/{jis → astm}/components.rb +1 -1
  60. data/lib/pubid/astm/identifiers/adjunct.rb +0 -8
  61. data/lib/pubid/astm/identifiers/data_series.rb +0 -14
  62. data/lib/pubid/astm/identifiers/iso_dual_published.rb +9 -34
  63. data/lib/pubid/astm/identifiers/manual.rb +0 -27
  64. data/lib/pubid/astm/identifiers/monograph.rb +0 -14
  65. data/lib/pubid/astm/identifiers/research_report.rb +0 -7
  66. data/lib/pubid/astm/identifiers/standard.rb +0 -39
  67. data/lib/pubid/astm/identifiers/technical_report.rb +0 -13
  68. data/lib/pubid/astm/identifiers/work_in_progress.rb +0 -11
  69. data/lib/pubid/astm/identifiers.rb +18 -0
  70. data/lib/pubid/astm/renderer.rb +172 -0
  71. data/lib/pubid/astm/single_identifier.rb +0 -10
  72. data/lib/pubid/astm/urn_parser.rb +30 -0
  73. data/lib/pubid/astm.rb +39 -27
  74. data/lib/pubid/bsi/builder.rb +21 -12
  75. data/lib/pubid/bsi/identifier.rb +8 -2
  76. data/lib/pubid/bsi/identifiers/addendum_document.rb +3 -33
  77. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +11 -47
  78. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +11 -38
  79. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +3 -53
  80. data/lib/pubid/bsi/identifiers/amendment.rb +3 -19
  81. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +2 -4
  82. data/lib/pubid/bsi/identifiers/british_standard.rb +2 -1
  83. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +3 -84
  84. data/lib/pubid/bsi/identifiers/committee_document.rb +1 -14
  85. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +3 -84
  86. data/lib/pubid/bsi/identifiers/corrigendum.rb +3 -7
  87. data/lib/pubid/bsi/identifiers/detailed_specification.rb +1 -34
  88. data/lib/pubid/bsi/identifiers/disc.rb +1 -27
  89. data/lib/pubid/bsi/identifiers/draft_document.rb +3 -44
  90. data/lib/pubid/bsi/identifiers/electronic_book.rb +3 -36
  91. data/lib/pubid/bsi/identifiers/expert_commentary.rb +3 -15
  92. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +1 -45
  93. data/lib/pubid/bsi/identifiers/flex.rb +1 -33
  94. data/lib/pubid/bsi/identifiers/handbook.rb +2 -13
  95. data/lib/pubid/bsi/identifiers/index.rb +1 -30
  96. data/lib/pubid/bsi/identifiers/method.rb +1 -39
  97. data/lib/pubid/bsi/identifiers/national_annex.rb +5 -27
  98. data/lib/pubid/bsi/identifiers/practice_guide.rb +2 -4
  99. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +3 -52
  100. data/lib/pubid/bsi/identifiers/published_document.rb +3 -52
  101. data/lib/pubid/bsi/identifiers/section.rb +1 -28
  102. data/lib/pubid/bsi/identifiers/set.rb +3 -17
  103. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +1 -7
  104. data/lib/pubid/bsi/identifiers/supplement_document.rb +3 -21
  105. data/lib/pubid/bsi/identifiers/supplementary_index.rb +1 -44
  106. data/lib/pubid/bsi/identifiers/technical_specification.rb +3 -45
  107. data/lib/pubid/bsi/identifiers/test_method.rb +1 -30
  108. data/lib/pubid/bsi/identifiers/value_added_publication.rb +3 -14
  109. data/lib/pubid/bsi/identifiers.rb +0 -1
  110. data/lib/pubid/bsi/renderer.rb +1050 -0
  111. data/lib/pubid/bsi/single_identifier.rb +6 -70
  112. data/lib/pubid/bsi/urn_generator.rb +2 -3
  113. data/lib/pubid/bsi/urn_parser.rb +52 -0
  114. data/lib/pubid/bsi.rb +224 -1
  115. data/lib/pubid/builder/base.rb +57 -10
  116. data/lib/pubid/bundled_identifier.rb +0 -1
  117. data/lib/pubid/ccsds/builder.rb +4 -3
  118. data/lib/pubid/ccsds/identifier.rb +66 -1
  119. data/lib/pubid/ccsds/identifiers/base.rb +11 -50
  120. data/lib/pubid/ccsds/identifiers/corrigendum.rb +7 -6
  121. data/lib/pubid/ccsds/parser.rb +4 -2
  122. data/lib/pubid/ccsds/single_identifier.rb +4 -1
  123. data/lib/pubid/ccsds/supplement_identifier.rb +15 -11
  124. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  125. data/lib/pubid/ccsds/urn_parser.rb +20 -0
  126. data/lib/pubid/ccsds.rb +39 -1
  127. data/lib/pubid/cen_cenelec/builder.rb +12 -14
  128. data/lib/pubid/cen_cenelec/identifier.rb +8 -2
  129. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +13 -4
  130. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -8
  131. data/lib/pubid/cen_cenelec/identifiers/base.rb +5 -41
  132. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +2 -1
  133. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +2 -1
  134. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +2 -25
  135. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -13
  136. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +2 -1
  137. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +4 -7
  138. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +2 -1
  139. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  140. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +2 -1
  141. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +2 -1
  142. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +2 -1
  143. data/lib/pubid/cen_cenelec/renderer.rb +261 -0
  144. data/lib/pubid/cen_cenelec/single_identifier.rb +11 -89
  145. data/lib/pubid/cen_cenelec/urn_generator.rb +6 -6
  146. data/lib/pubid/cen_cenelec/urn_parser.rb +28 -0
  147. data/lib/pubid/cen_cenelec.rb +168 -1
  148. data/lib/pubid/cie/components/code.rb +8 -0
  149. data/lib/pubid/cie/identifier.rb +6 -4
  150. data/lib/pubid/cie/urn_parser.rb +28 -0
  151. data/lib/pubid/cie.rb +43 -1
  152. data/lib/pubid/components/adoption.rb +104 -0
  153. data/lib/pubid/components/code.rb +22 -8
  154. data/lib/pubid/components/date.rb +23 -16
  155. data/lib/pubid/components/edition.rb +9 -6
  156. data/lib/pubid/components/iteration.rb +32 -0
  157. data/lib/pubid/components/language.rb +6 -4
  158. data/lib/pubid/components/locality.rb +10 -1
  159. data/lib/pubid/components/publisher.rb +9 -6
  160. data/lib/pubid/components/relationship.rb +151 -0
  161. data/lib/pubid/components/stage.rb +5 -14
  162. data/lib/pubid/components/supplement.rb +184 -0
  163. data/lib/pubid/components/type.rb +5 -15
  164. data/lib/pubid/components/typed_stage.rb +11 -8
  165. data/lib/pubid/components.rb +4 -0
  166. data/lib/pubid/core/update_codes.rb +28 -7
  167. data/lib/pubid/csa/identifier.rb +0 -3
  168. data/lib/pubid/csa/identifiers/base.rb +2 -122
  169. data/lib/pubid/csa/identifiers/cec.rb +2 -101
  170. data/lib/pubid/csa/identifiers/series.rb +2 -102
  171. data/lib/pubid/csa/renderer.rb +292 -0
  172. data/lib/pubid/csa/urn_generator.rb +1 -1
  173. data/lib/pubid/csa/urn_parser.rb +33 -0
  174. data/lib/pubid/csa.rb +42 -1
  175. data/lib/pubid/etsi/components/code.rb +9 -2
  176. data/lib/pubid/etsi/identifiers/base.rb +1 -4
  177. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +2 -9
  178. data/lib/pubid/etsi/renderer.rb +42 -0
  179. data/lib/pubid/etsi/urn_parser.rb +34 -0
  180. data/lib/pubid/etsi.rb +42 -1
  181. data/lib/pubid/export/exporter.rb +4 -46
  182. data/lib/pubid/export/flavor_exporter.rb +111 -278
  183. data/lib/pubid/export.rb +0 -6
  184. data/lib/pubid/identifier.rb +10 -18
  185. data/lib/pubid/identifier_facade.rb +114 -0
  186. data/lib/pubid/identifier_metadata.rb +1 -1
  187. data/lib/pubid/idf/builder.rb +3 -3
  188. data/lib/pubid/idf/identifier.rb +3 -6
  189. data/lib/pubid/idf/identifiers/amendment.rb +2 -1
  190. data/lib/pubid/idf/identifiers/corrigendum.rb +2 -1
  191. data/lib/pubid/idf/identifiers/international_standard.rb +2 -1
  192. data/lib/pubid/idf/identifiers/reviewed_method.rb +2 -1
  193. data/lib/pubid/idf/parser.rb +3 -2
  194. data/lib/pubid/idf/renderer.rb +84 -0
  195. data/lib/pubid/idf/supplement_identifier.rb +2 -10
  196. data/lib/pubid/idf/urn_generator.rb +4 -39
  197. data/lib/pubid/idf/urn_parser.rb +25 -0
  198. data/lib/pubid/idf.rb +51 -1
  199. data/lib/pubid/iec/builder.rb +48 -65
  200. data/lib/pubid/iec/components/code.rb +9 -32
  201. data/lib/pubid/iec/components/publisher.rb +1 -1
  202. data/lib/pubid/iec/components.rb +14 -0
  203. data/lib/pubid/iec/identifier.rb +276 -3
  204. data/lib/pubid/iec/identifiers/amendment.rb +2 -3
  205. data/lib/pubid/iec/identifiers/base.rb +8 -28
  206. data/lib/pubid/iec/identifiers/component_specification.rb +3 -3
  207. data/lib/pubid/iec/identifiers/conformity_assessment.rb +1 -2
  208. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +27 -30
  209. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -3
  210. data/lib/pubid/iec/identifiers/fragment_identifier.rb +37 -26
  211. data/lib/pubid/iec/identifiers/guide.rb +0 -2
  212. data/lib/pubid/iec/identifiers/international_standard.rb +2 -3
  213. data/lib/pubid/iec/identifiers/interpretation_sheet.rb +2 -3
  214. data/lib/pubid/iec/identifiers/operational_document.rb +3 -3
  215. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +2 -3
  216. data/lib/pubid/iec/identifiers/sheet_identifier.rb +21 -15
  217. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +3 -3
  218. data/lib/pubid/iec/identifiers/systems_reference_document.rb +2 -3
  219. data/lib/pubid/iec/identifiers/technical_report.rb +2 -3
  220. data/lib/pubid/iec/identifiers/technical_specification.rb +2 -3
  221. data/lib/pubid/iec/identifiers/technology_report.rb +1 -2
  222. data/lib/pubid/iec/identifiers/test_report_form.rb +5 -34
  223. data/lib/pubid/iec/identifiers/vap_identifier.rb +26 -23
  224. data/lib/pubid/iec/identifiers/white_paper.rb +3 -3
  225. data/lib/pubid/iec/identifiers/working_document.rb +4 -48
  226. data/lib/pubid/iec/identifiers.rb +30 -0
  227. data/lib/pubid/iec/parser.rb +20 -14
  228. data/lib/pubid/iec/renderer.rb +254 -0
  229. data/lib/pubid/iec/single_identifier.rb +6 -12
  230. data/lib/pubid/iec/supplement_identifier.rb +58 -54
  231. data/lib/pubid/iec/urn_generator.rb +57 -171
  232. data/lib/pubid/iec/urn_parser.rb +53 -252
  233. data/lib/pubid/iec.rb +40 -68
  234. data/lib/pubid/ieee/builder.rb +12 -12
  235. data/lib/pubid/ieee/components/code.rb +8 -0
  236. data/lib/pubid/ieee/components/draft.rb +14 -0
  237. data/lib/pubid/ieee/components/relationship.rb +5 -149
  238. data/lib/pubid/ieee/identifier.rb +6 -0
  239. data/lib/pubid/ieee/identifiers/adopted_standard.rb +1 -6
  240. data/lib/pubid/ieee/identifiers/base.rb +101 -458
  241. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +1 -7
  242. data/lib/pubid/ieee/identifiers/corrigendum.rb +1 -9
  243. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +1 -7
  244. data/lib/pubid/ieee/identifiers/dual_identifier.rb +1 -1
  245. data/lib/pubid/ieee/identifiers/dual_published.rb +1 -1
  246. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +1 -6
  247. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +1 -7
  248. data/lib/pubid/ieee/identifiers/joint_development.rb +2 -0
  249. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -15
  250. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +1 -3
  251. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +15 -0
  252. data/lib/pubid/ieee/identifiers/redlined_standard.rb +1 -4
  253. data/lib/pubid/ieee/identifiers/si_standard.rb +1 -35
  254. data/lib/pubid/ieee/identifiers/standard.rb +1 -1
  255. data/lib/pubid/ieee/pre_parser.rb +301 -0
  256. data/lib/pubid/ieee/renderer.rb +307 -0
  257. data/lib/pubid/ieee/urn_parser.rb +34 -0
  258. data/lib/pubid/ieee.rb +62 -1
  259. data/lib/pubid/ieee_debug.rb +0 -1
  260. data/lib/pubid/iho/builder.rb +2 -2
  261. data/lib/pubid/iho/identifier.rb +8 -0
  262. data/lib/pubid/iho/identifiers/base.rb +49 -10
  263. data/lib/pubid/iho/identifiers/bibliographic.rb +0 -4
  264. data/lib/pubid/iho/identifiers/circular_letter.rb +0 -4
  265. data/lib/pubid/iho/identifiers/miscellaneous.rb +0 -4
  266. data/lib/pubid/iho/identifiers/publication.rb +0 -4
  267. data/lib/pubid/iho/identifiers/standard.rb +0 -4
  268. data/lib/pubid/iho/parser.rb +3 -3
  269. data/lib/pubid/iho/renderer.rb +30 -0
  270. data/lib/pubid/iho/urn_generator.rb +3 -3
  271. data/lib/pubid/iho/urn_parser.rb +58 -0
  272. data/lib/pubid/iho.rb +50 -1
  273. data/lib/pubid/iso/builder.rb +59 -53
  274. data/lib/pubid/iso/bundled_identifier.rb +51 -0
  275. data/lib/pubid/iso/components/code.rb +7 -19
  276. data/lib/pubid/iso/components/publisher.rb +10 -8
  277. data/lib/pubid/iso/components.rb +2 -4
  278. data/lib/pubid/iso/identifier.rb +233 -6
  279. data/lib/pubid/iso/identifiers/addendum.rb +9 -6
  280. data/lib/pubid/iso/identifiers/amendment.rb +8 -4
  281. data/lib/pubid/iso/identifiers/corrigendum.rb +4 -4
  282. data/lib/pubid/iso/identifiers/data.rb +0 -1
  283. data/lib/pubid/iso/identifiers/directives.rb +8 -2
  284. data/lib/pubid/iso/identifiers/directives_supplement.rb +43 -14
  285. data/lib/pubid/iso/identifiers/extract.rb +2 -2
  286. data/lib/pubid/iso/identifiers/guide.rb +0 -1
  287. data/lib/pubid/iso/identifiers/international_standard.rb +4 -4
  288. data/lib/pubid/iso/identifiers/international_standardized_profile.rb +4 -4
  289. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +10 -4
  290. data/lib/pubid/iso/identifiers/pas.rb +2 -2
  291. data/lib/pubid/iso/identifiers/recommendation.rb +2 -2
  292. data/lib/pubid/iso/identifiers/supplement.rb +11 -3
  293. data/lib/pubid/iso/identifiers/tc_document.rb +44 -15
  294. data/lib/pubid/iso/identifiers/technical_report.rb +4 -4
  295. data/lib/pubid/iso/identifiers/technical_specification.rb +2 -2
  296. data/lib/pubid/iso/identifiers/technology_trends_assessments.rb +2 -2
  297. data/lib/pubid/iso/identifiers.rb +0 -1
  298. data/lib/pubid/iso/normalizer.rb +89 -0
  299. data/lib/pubid/iso/parser.rb +26 -6
  300. data/lib/pubid/iso/single_identifier.rb +6 -3
  301. data/lib/pubid/iso/supplement_identifier.rb +15 -2
  302. data/lib/pubid/iso/urn_generator.rb +74 -176
  303. data/lib/pubid/iso/urn_parser.rb +28 -9
  304. data/lib/pubid/iso.rb +173 -2
  305. data/lib/pubid/itu/builder.rb +0 -12
  306. data/lib/pubid/itu/components/code.rb +8 -0
  307. data/lib/pubid/itu/components.rb +11 -0
  308. data/lib/pubid/itu/identifier.rb +6 -39
  309. data/lib/pubid/itu/identifiers/amendment.rb +0 -2
  310. data/lib/pubid/itu/identifiers/annex.rb +0 -2
  311. data/lib/pubid/itu/identifiers/base.rb +0 -6
  312. data/lib/pubid/itu/identifiers/combined_identifier.rb +0 -2
  313. data/lib/pubid/itu/identifiers/corrigendum.rb +0 -2
  314. data/lib/pubid/itu/identifiers/recommendation.rb +0 -2
  315. data/lib/pubid/itu/identifiers/special_publication.rb +0 -2
  316. data/lib/pubid/itu/identifiers/supplement.rb +0 -2
  317. data/lib/pubid/itu/urn_parser.rb +23 -0
  318. data/lib/pubid/itu.rb +42 -1
  319. data/lib/pubid/jcgm/builder.rb +16 -8
  320. data/lib/pubid/jcgm/identifiers/amendment.rb +2 -7
  321. data/lib/pubid/jcgm/identifiers/gum_guide.rb +2 -10
  322. data/lib/pubid/jcgm/renderer.rb +68 -0
  323. data/lib/pubid/jcgm/single_identifier.rb +1 -5
  324. data/lib/pubid/jcgm/urn_generator.rb +4 -6
  325. data/lib/pubid/jcgm/urn_parser.rb +23 -0
  326. data/lib/pubid/jcgm.rb +43 -2
  327. data/lib/pubid/jis/builder.rb +44 -52
  328. data/lib/pubid/jis/identifier.rb +132 -3
  329. data/lib/pubid/jis/identifiers/amendment.rb +1 -1
  330. data/lib/pubid/jis/identifiers/corrigendum.rb +16 -0
  331. data/lib/pubid/jis/identifiers/standard.rb +2 -1
  332. data/lib/pubid/jis/identifiers/technical_report.rb +2 -1
  333. data/lib/pubid/jis/identifiers/technical_specification.rb +2 -1
  334. data/lib/pubid/jis/identifiers.rb +1 -1
  335. data/lib/pubid/jis/parser.rb +31 -5
  336. data/lib/pubid/jis/renderer.rb +69 -0
  337. data/lib/pubid/jis/single_identifier.rb +6 -12
  338. data/lib/pubid/jis/supplement_identifier.rb +17 -14
  339. data/lib/pubid/jis/urn_parser.rb +23 -0
  340. data/lib/pubid/jis.rb +42 -2
  341. data/lib/pubid/nist/builder.rb +122 -1761
  342. data/lib/pubid/nist/caster.rb +1272 -0
  343. data/lib/pubid/nist/circular_supplement_builder.rb +291 -0
  344. data/lib/pubid/nist/components/code.rb +9 -20
  345. data/lib/pubid/nist/components/edition.rb +16 -0
  346. data/lib/pubid/nist/components/supplement.rb +88 -21
  347. data/lib/pubid/nist/components.rb +0 -1
  348. data/lib/pubid/nist/identifier.rb +25 -0
  349. data/lib/pubid/nist/identifiers/base.rb +206 -64
  350. data/lib/pubid/nist/identifiers/circular.rb +7 -2
  351. data/lib/pubid/nist/identifiers/circular_supplement.rb +3 -2
  352. data/lib/pubid/nist/identifiers/commercial_standard.rb +2 -1
  353. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +6 -4
  354. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +10 -3
  355. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -11
  356. data/lib/pubid/nist/identifiers/dated_document.rb +49 -0
  357. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +17 -16
  358. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +2 -1
  359. data/lib/pubid/nist/identifiers/handbook.rb +2 -1
  360. data/lib/pubid/nist/identifiers/internal_report.rb +2 -1
  361. data/lib/pubid/nist/identifiers/letter_circular.rb +2 -1
  362. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +5 -4
  363. data/lib/pubid/nist/identifiers/monograph.rb +7 -3
  364. data/lib/pubid/nist/identifiers/report.rb +4 -3
  365. data/lib/pubid/nist/identifiers/special_publication.rb +2 -1
  366. data/lib/pubid/nist/identifiers/technical_note.rb +3 -2
  367. data/lib/pubid/nist/identifiers.rb +1 -0
  368. data/lib/pubid/nist/parser.rb +67 -424
  369. data/lib/pubid/nist/parser_output_normalizer.rb +233 -0
  370. data/lib/pubid/nist/preprocessor.rb +416 -0
  371. data/lib/pubid/nist/renderer.rb +43 -0
  372. data/lib/pubid/nist/router.rb +148 -0
  373. data/lib/pubid/nist/series/base.rb +58 -0
  374. data/lib/pubid/nist/series/crpl.rb +13 -0
  375. data/lib/pubid/nist/series/fips.rb +14 -0
  376. data/lib/pubid/nist/series/ir.rb +60 -0
  377. data/lib/pubid/nist/series/letter_preserving.rb +15 -0
  378. data/lib/pubid/nist/series/mono.rb +19 -0
  379. data/lib/pubid/nist/series/ncstar.rb +20 -0
  380. data/lib/pubid/nist/series.rb +49 -0
  381. data/lib/pubid/nist/supplement_identifier.rb +11 -25
  382. data/lib/pubid/nist/urn_generator.rb +14 -8
  383. data/lib/pubid/nist/urn_parser.rb +67 -0
  384. data/lib/pubid/nist.rb +83 -4
  385. data/lib/pubid/oiml/components/code.rb +10 -0
  386. data/lib/pubid/oiml/identifiers/annex.rb +3 -45
  387. data/lib/pubid/oiml/identifiers/base.rb +2 -17
  388. data/lib/pubid/oiml/renderer.rb +161 -0
  389. data/lib/pubid/oiml/single_identifier.rb +6 -45
  390. data/lib/pubid/oiml/supplement_identifier.rb +4 -19
  391. data/lib/pubid/oiml/urn_generator.rb +0 -8
  392. data/lib/pubid/oiml/urn_parser.rb +22 -0
  393. data/lib/pubid/oiml.rb +42 -1
  394. data/lib/pubid/plateau/identifier.rb +23 -0
  395. data/lib/pubid/plateau/identifiers/handbook.rb +1 -3
  396. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  397. data/lib/pubid/plateau/renderer.rb +51 -0
  398. data/lib/pubid/plateau/supplement_identifier.rb +1 -1
  399. data/lib/pubid/plateau/urn_parser.rb +43 -0
  400. data/lib/pubid/plateau.rb +44 -1
  401. data/lib/pubid/renderers/base.rb +34 -0
  402. data/lib/pubid/renderers/directives_renderer.rb +27 -14
  403. data/lib/pubid/renderers/guide_renderer.rb +7 -1
  404. data/lib/pubid/renderers/human_readable.rb +31 -8
  405. data/lib/pubid/renderers/iwa_renderer.rb +5 -1
  406. data/lib/pubid/renderers/supplement_renderer.rb +4 -1
  407. data/lib/pubid/rendering/context.rb +33 -21
  408. data/lib/pubid/rendering.rb +0 -3
  409. data/lib/pubid/sae/components/date.rb +8 -0
  410. data/lib/pubid/sae/components/type.rb +5 -1
  411. data/lib/pubid/sae/identifiers/base.rb +2 -16
  412. data/lib/pubid/sae/renderer.rb +36 -0
  413. data/lib/pubid/sae/urn_generator.rb +2 -10
  414. data/lib/pubid/sae/urn_parser.rb +36 -0
  415. data/lib/pubid/sae.rb +42 -1
  416. data/lib/pubid/urn_generator/base.rb +12 -12
  417. data/lib/pubid/urn_parser/base.rb +81 -0
  418. data/lib/pubid/urn_parser/errors.rb +9 -0
  419. data/lib/pubid/urn_parser.rb +14 -0
  420. data/lib/pubid/version.rb +1 -1
  421. data/lib/pubid.rb +29 -7
  422. data/lib/tasks/website-data.json +1940 -1882
  423. metadata +77 -43
  424. data/lib/pubid/amca/scheme.rb +0 -16
  425. data/lib/pubid/ansi/scheme.rb +0 -15
  426. data/lib/pubid/api/scheme.rb +0 -66
  427. data/lib/pubid/ashrae/scheme.rb +0 -53
  428. data/lib/pubid/asme/scheme.rb +0 -37
  429. data/lib/pubid/astm/scheme.rb +0 -55
  430. data/lib/pubid/bsi/identifiers/base.rb +0 -11
  431. data/lib/pubid/bsi/scheme.rb +0 -243
  432. data/lib/pubid/ccsds/scheme.rb +0 -57
  433. data/lib/pubid/cen_cenelec/scheme.rb +0 -164
  434. data/lib/pubid/cie/scheme.rb +0 -64
  435. data/lib/pubid/csa/scheme.rb +0 -44
  436. data/lib/pubid/etsi/scheme.rb +0 -42
  437. data/lib/pubid/export/data_class_exporter.rb +0 -59
  438. data/lib/pubid/export/ieee_exporter.rb +0 -78
  439. data/lib/pubid/export/itu_exporter.rb +0 -66
  440. data/lib/pubid/export/nist_exporter.rb +0 -64
  441. data/lib/pubid/export/registry_exporter.rb +0 -90
  442. data/lib/pubid/export/scheme_exporter.rb +0 -70
  443. data/lib/pubid/identifier_registry.rb +0 -198
  444. data/lib/pubid/idf/scheme.rb +0 -61
  445. data/lib/pubid/iec/scheme.rb +0 -71
  446. data/lib/pubid/ieee/scheme.rb +0 -90
  447. data/lib/pubid/iho/scheme.rb +0 -29
  448. data/lib/pubid/iso/identifiers/base.rb +0 -115
  449. data/lib/pubid/iso/scheme.rb +0 -187
  450. data/lib/pubid/itu/scheme.rb +0 -174
  451. data/lib/pubid/jcgm/scheme.rb +0 -60
  452. data/lib/pubid/jis/components/code.rb +0 -59
  453. data/lib/pubid/jis/identifiers/base.rb +0 -72
  454. data/lib/pubid/jis/scheme.rb +0 -49
  455. data/lib/pubid/nist/components/publisher.rb +0 -24
  456. data/lib/pubid/nist/scheme.rb +0 -199
  457. data/lib/pubid/oiml/scheme.rb +0 -46
  458. data/lib/pubid/plateau/scheme.rb +0 -45
  459. data/lib/pubid/rendering/base.rb +0 -73
  460. data/lib/pubid/rendering/common.rb +0 -211
  461. data/lib/pubid/rendering/format.rb +0 -25
  462. data/lib/pubid/sae/scheme.rb +0 -47
  463. data/lib/pubid/scheme.rb +0 -207
@@ -0,0 +1,291 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ # Builder dedicated to CIRC/LCIRC supplement identifier construction.
6
+ #
7
+ # Extracted from Builder.build_circular_supplement* methods to keep the
8
+ # main Builder focused on orchestration. The circular supplement
9
+ # construction pipeline is a self-contained sub-flow that:
10
+ #
11
+ # 1. Decides between the wrapper class (CircularSupplement) for V1-compat
12
+ # update forms (slash-year "118supp3/1926" -> ".../Upd1-192603";
13
+ # implicit revision "145r11/1925") and the normal Circular /
14
+ # LetterCircular classes for everything else.
15
+ # 2. Builds the base identifier recursively via Builder#build.
16
+ # 3. Attaches the supplement as either an isolated component on the normal
17
+ # class, or a structured edition/update on the wrapper.
18
+ #
19
+ # Single Responsibility: Construct CIRC/LCIRC supplement identifier
20
+ # objects from parsed data, calling back to the parent Builder for base
21
+ # identifier construction.
22
+ class CircularSupplementBuilder
23
+ # @param builder [Builder] the parent builder (for recursive base build)
24
+ def initialize(builder)
25
+ @builder = builder
26
+ end
27
+
28
+ # Build CircularSupplement with base_identifier wrapping
29
+ # @param parsed_hash [Hash] the parsed supplement data
30
+ # Build a CIRC/LCIRC supplement. Most forms collapse onto the base
31
+ # identifier's normal class (Circular / LetterCircular) with isolated
32
+ # supplement attributes, so they share one model with every other series
33
+ # and are queryable by part. The V1-compat update forms (slash-year
34
+ # "118supp3/1926" -> ".../Upd1-192603"; implicit revision "145r11/1925")
35
+ # render through an Update component the flat supplement model can't
36
+ # express, so they stay on the CircularSupplement wrapper for now.
37
+ def build_circular_supplement(parsed_hash)
38
+ if parsed_hash[:supplement_slash_year].is_a?(Hash) ||
39
+ parsed_hash[:implicit_supplement].is_a?(Hash)
40
+ return build_circular_supplement_wrapper(parsed_hash)
41
+ end
42
+
43
+ series_value = if parsed_hash[:circ_series].is_a?(Hash)
44
+ parsed_hash[:circ_series][:series]
45
+ else
46
+ parsed_hash[:series]
47
+ end
48
+
49
+ # Date-range supplement (no base document): a plain base identifier with
50
+ # no number, carrying the range. parsed_format is left at the default so
51
+ # a dotted MR input still normalizes to the spaced short form.
52
+ if parsed_hash[:supplement_date_range].is_a?(Hash)
53
+ range = parsed_hash[:supplement_date_range]
54
+ identifier = @builder.build({ series: series_value })
55
+ ms = range[:supp_month_start]&.to_s
56
+ ys = range[:supp_year_start]&.to_s
57
+ me = range[:supp_month_end]&.to_s
58
+ ye = range[:supp_year_end]&.to_s
59
+ identifier.supplement = @builder.supplement_from(
60
+ value: nil, has_revision: false,
61
+ range_start: (ms && ys ? "#{ms}#{ys}" : nil),
62
+ range_end: (me && ye ? "#{me}#{ye}" : nil)
63
+ )
64
+ return identifier
65
+ end
66
+
67
+ # Based supplement: build the base, then attach the supplement as an
68
+ # isolated component on that normal class.
69
+ identifier = build_circular_supplement_base(parsed_hash, series_value)
70
+ raw = if parsed_hash[:supplement_month_year]
71
+ parsed_hash[:supplement_month_year].to_s
72
+ elsif parsed_hash[:supplement_year]
73
+ parsed_hash[:supplement_year].to_s
74
+ else
75
+ "" # supplement_empty or bare marker
76
+ end
77
+ identifier.supplement = Components::Supplement.from_raw(raw)
78
+ identifier
79
+ end
80
+
81
+ # Build just the base identifier for a based CIRC/LCIRC supplement, from
82
+ # base_portion (number, optional edition "101e2" or letter suffix "378G")
83
+ # or the merged first_number fallback. Returns the normal class.
84
+ def build_circular_supplement_base(parsed_hash, series_value)
85
+ base_portion = parsed_hash[:base_portion]
86
+ unless base_portion
87
+ return @builder.build({
88
+ publisher: parsed_hash[:publisher],
89
+ series: series_value || parsed_hash[:series],
90
+ first_number: parsed_hash[:first_number],
91
+ parsed_format: parsed_hash[:parsed_format],
92
+ })
93
+ end
94
+
95
+ base_number = if base_portion.is_a?(Hash)
96
+ base_portion[:simple_number] || base_portion[:base_number]
97
+ else
98
+ base_portion
99
+ end
100
+
101
+ letter_suffix = nil
102
+ if base_portion.is_a?(Hash) && base_portion[:letter_suffix]
103
+ letter_suffix = base_portion[:letter_suffix].to_s.upcase
104
+ end
105
+
106
+ publisher_value = nil
107
+ if parsed_hash[:circ_series].is_a?(Hash) && parsed_hash[:circ_series][:series]
108
+ series_str = parsed_hash[:circ_series][:series].to_s
109
+ publisher_value = series_str.split.first if series_str.include?(" ")
110
+ end
111
+
112
+ has_edition = base_portion.is_a?(Hash) && base_portion[:edition_number]
113
+
114
+ base_number_with_suffix = base_number.to_s
115
+ base_number_with_suffix += letter_suffix if letter_suffix
116
+ if has_edition
117
+ base_number_with_suffix += "e#{base_portion[:edition_number]}"
118
+ end
119
+
120
+ base_hash = {
121
+ series: series_value,
122
+ first_number: base_number_with_suffix,
123
+ parsed_format: parsed_hash[:parsed_format],
124
+ }
125
+ base_hash[:publisher] = publisher_value if publisher_value
126
+ base_hash[:edition_e] =
127
+ { edition_id: base_portion[:edition_number] } if has_edition
128
+
129
+ @builder.build(base_hash)
130
+ end
131
+
132
+ # @return [Identifiers::CircularSupplement] the supplement identifier
133
+ def build_circular_supplement_wrapper(parsed_hash)
134
+ supplement = Identifiers::CircularSupplement.new
135
+
136
+ # Extract series from circ_series if present (nested structure from parser)
137
+ series_value = nil
138
+ if parsed_hash[:circ_series].is_a?(Hash)
139
+ series_value = parsed_hash[:circ_series][:series]
140
+ elsif parsed_hash[:series]
141
+ series_value = parsed_hash[:series]
142
+ end
143
+
144
+ # Handle date range supplement (no base)
145
+ if parsed_hash[:supplement_date_range].is_a?(Hash)
146
+ range = parsed_hash[:supplement_date_range]
147
+ month_start = range[:supp_month_start]&.to_s
148
+ year_start = range[:supp_year_start]&.to_s
149
+ month_end = range[:supp_month_end]&.to_s
150
+ year_end = range[:supp_year_end]&.to_s
151
+
152
+ supplement.supplement_date_range_start = "#{month_start}#{year_start}" if month_start && year_start
153
+ supplement.supplement_date_range_end = "#{month_end}#{year_end}" if month_end && year_end
154
+
155
+ return supplement
156
+ end
157
+
158
+ # Build base identifier from base_portion (if present)
159
+ # If not present (because it was merged during parsing), use first_number
160
+ if parsed_hash[:base_portion]
161
+ # Extract the actual number value from base_portion hash
162
+ # base_portion can be: {:simple_number=>"118"}, {:base_number=>"145", :revision_letter=>"r", :revision_number=>"11"}, etc.
163
+ base_portion = parsed_hash[:base_portion]
164
+ base_number = if base_portion.is_a?(Hash)
165
+ # Extract the value from whichever key is present
166
+ base_portion[:simple_number] || base_portion[:base_number]
167
+ else
168
+ base_portion
169
+ end
170
+
171
+ # Check for letter suffix in base_portion (e.g., "378G")
172
+ letter_suffix = nil
173
+ if base_portion.is_a?(Hash) && base_portion[:letter_suffix]
174
+ letter_suffix = base_portion[:letter_suffix].to_s.upcase
175
+ end
176
+
177
+ # Extract publisher from circ_series if present
178
+ publisher_value = nil
179
+ if parsed_hash[:circ_series].is_a?(Hash) && parsed_hash[:circ_series][:series]
180
+ series_str = parsed_hash[:circ_series][:series].to_s
181
+ # Extract publisher from series (e.g., "NBS LCIRC" -> "NBS")
182
+ publisher_value = series_str.split.first if series_str.include?(" ")
183
+ end
184
+
185
+ # Check if base_portion has revision (for patterns like "145r11/1925")
186
+ has_revision = base_portion.is_a?(Hash) && base_portion[:revision_letter] && base_portion[:revision_number]
187
+
188
+ # NEW: Check if base_portion has edition_number (for patterns like "101e2")
189
+ has_edition = base_portion.is_a?(Hash) && base_portion[:edition_number]
190
+
191
+ # Include letter suffix in base_number if present
192
+ # Also include edition_number if present (for "101e2" pattern)
193
+ base_number_with_suffix = base_number.to_s
194
+ if letter_suffix
195
+ base_number_with_suffix += letter_suffix
196
+ end
197
+ if has_edition
198
+ base_number_with_suffix += "e#{base_portion[:edition_number]}"
199
+ end
200
+
201
+ # Reconstruct parse hash for base identifier
202
+ base_hash = {
203
+ series: series_value,
204
+ first_number: base_number_with_suffix,
205
+ parsed_format: parsed_hash[:parsed_format],
206
+ }
207
+ base_hash[:publisher] = publisher_value if publisher_value
208
+
209
+ # NEW: Add edition_number to base_hash for patterns like "101e2"
210
+ # This will be processed by the normal build() logic to create Edition component
211
+ if has_edition
212
+ # Create edition_e hash that will be converted to Edition with type="e"
213
+ base_hash[:edition_e] =
214
+ { edition_id: base_portion[:edition_number] }
215
+ end
216
+
217
+ # Recursively build base identifier
218
+ # This will go through normal build() process which extracts edition from "101e2"
219
+ supplement.base_identifier = @builder.build(base_hash)
220
+
221
+ # NEW: Handle revision + implicit supplement pattern (e.g., "145r11/1925")
222
+ # Create update format: "Upd1-{year}{revision_number}"
223
+ if has_revision && parsed_hash[:implicit_supplement].is_a?(Hash)
224
+ revision_number = base_portion[:revision_number].to_s
225
+ supplement_year = parsed_hash[:implicit_supplement][:implicit_supplement_year].to_s
226
+
227
+ # Create Update component for revision+supplement pattern.
228
+ # Renders "/Upd1-{year}{revision_number}" via Update#to_s(:short).
229
+ # The year+revision are fused into the year field (month left nil) so
230
+ # the revision is NOT zero-padded (e.g. "145r6/1925" -> "Upd1-19256",
231
+ # not "192506"). Must be a Components::Update (not a String) so
232
+ # :update serializes.
233
+ supplement.update = Components::Update.new(
234
+ number: "1", year: "#{supplement_year}#{revision_number}",
235
+ prefix: "slash"
236
+ )
237
+ supplement.implicit_supplement = true # Mark as implicit supplement for rendering
238
+ end
239
+ elsif parsed_hash[:first_number]
240
+ # base_portion was lost during merge, use first_number to build base identifier
241
+ base_hash = {
242
+ publisher: parsed_hash[:publisher],
243
+ series: series_value || parsed_hash[:series],
244
+ first_number: parsed_hash[:first_number],
245
+ parsed_format: parsed_hash[:parsed_format],
246
+ }
247
+
248
+ # Recursively build base identifier
249
+ supplement.base_identifier = @builder.build(base_hash)
250
+ end
251
+
252
+ # Build supplement edition from captured data
253
+ if parsed_hash[:supplement_month_year]
254
+ # Parse month+year format like "Jan1924"
255
+ month_year = parsed_hash[:supplement_month_year].to_s
256
+ supplement.edition = Components::Edition.new(type: "s",
257
+ id: month_year)
258
+ elsif parsed_hash[:supplement_year]
259
+ # Just year: 1924
260
+ supplement.edition = Components::Edition.new(type: "s",
261
+ id: parsed_hash[:supplement_year].to_s)
262
+ elsif parsed_hash[:supplement_slash_year].is_a?(Hash)
263
+ # NEW: Handle supplement_slash_year pattern (e.g., "sup12/1926", "sup1/1927")
264
+ # V1 format: "Upd1-192612" where "1" is fixed and "192612" is year+number concatenated
265
+ # Single digit numbers are zero-padded: "sup1/1927" -> "Upd1-192701"
266
+ supp_hash = parsed_hash[:supplement_slash_year]
267
+ supp_number = supp_hash[:supp_number]&.to_s
268
+ supp_year = supp_hash[:supp_year]&.to_s
269
+
270
+ # Pad supplement number to 2 digits for single-digit numbers
271
+ supp_number_padded = supp_number.rjust(2, "0")
272
+
273
+ # Create Update component for supplement (V1 compatibility uses Update for supplements).
274
+ # Renders "/Upd1-{year}{padded_number}" via Update#to_s(:short). The
275
+ # year and already-padded number are fused into the year field (month
276
+ # left nil) so rendering reproduces the V1 string exactly. Must be a
277
+ # Components::Update (not a String) so :update serializes.
278
+ supplement.update = Components::Update.new(
279
+ number: "1", year: "#{supp_year}#{supp_number_padded}",
280
+ prefix: "slash"
281
+ )
282
+ elsif parsed_hash[:supplement_empty]
283
+ # Empty supplement - no edition
284
+ # supplement.edition remains nil
285
+ end
286
+
287
+ supplement
288
+ end
289
+ end
290
+ end
291
+ end
@@ -1,35 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "lutaml/model"
4
-
5
3
  module Pubid
6
4
  module Nist
7
5
  module Components
8
- # Code component for NIST identifiers
9
- # Handles number codes like series, volume, etc.
10
- class Code < Lutaml::Model::Serializable
11
- attribute :number, :string
12
- attribute :subpart, :string
13
-
6
+ # Code component for NIST identifiers.
7
+ #
8
+ # Inherits +value+ and +subpart+ from the shared Code; overrides
9
+ # rendering to compose compound numbers like "1234.5" (subpart
10
+ # joined with "." per NIST convention).
11
+ class Code < ::Pubid::Components::Code
14
12
  def to_s
15
- result = number.to_s
13
+ result = value.to_s
16
14
  result += ".#{subpart}" if subpart
17
15
  result
18
16
  end
19
17
 
20
- # Alias for compatibility
21
- def value
22
- to_s
23
- end
24
-
25
- # Backward compatibility: extract part from compound numbers like "140-2"
26
- # Returns the part number if the value contains a dash, nil otherwise
27
18
  def part
28
- return nil unless number&.include?("-")
19
+ return nil unless value&.include?("-")
29
20
 
30
- # Split by last dash to handle patterns like "4-4" (just number-part)
31
- # and "4-M-5" (which would return "M-5" as part)
32
- parts = number.to_s.split("-")
21
+ parts = value.to_s.split("-")
33
22
  parts.last if parts.length > 1
34
23
  end
35
24
  end
@@ -49,6 +49,22 @@ module Pubid
49
49
  end
50
50
  end
51
51
 
52
+ # Identity ignores original_prefix: it records how the edition was
53
+ # spelled in the source ("Rev. " vs "r") for round-trip rendering
54
+ # only. "r1" and "Rev. 1" are the same edition.
55
+ def ==(other)
56
+ return false unless other.is_a?(self.class)
57
+
58
+ type == other.type && id == other.id &&
59
+ additional_text == other.additional_text
60
+ end
61
+
62
+ alias eql? ==
63
+
64
+ def hash
65
+ [self.class, type, id, additional_text].hash
66
+ end
67
+
52
68
  private
53
69
 
54
70
  # Build short format: "e2", "e2.June1908", "e2.1908", "e2.50", "r1963", "-April1909", "r1a"
@@ -9,17 +9,19 @@ module Pubid
9
9
  # Represents supplement notation with number, year, month, or revision
10
10
  #
11
11
  # Examples:
12
- # Supplement.new(number: "2").to_s(:short) # => "supp2"
13
- # Supplement.new(year: "1925").to_s(:short) # => "supp-1925"
14
- # Supplement.new(number: "3", year: "1926").to_s(:short) # => "supp3/1926"
15
- # Supplement.new(month: "Jan", year: "1924").to_s(:short) # => "suppJan1924"
16
- # Supplement.new(has_revision: true).to_s(:short) # => "supprev"
12
+ # Supplement.new(number: "2").to_s(:short) # => "sup2"
13
+ # Supplement.new(year: "1925").to_s(:short) # => "sup1925"
14
+ # Supplement.new(number: "3", year: "1926").to_s(:short) # => "sup3/1926"
15
+ # Supplement.new(month: "Jan", year: "1924").to_s(:short) # => "supJan1924"
16
+ # Supplement.new(has_revision: true).to_s(:short) # => "suprev"
17
17
  class Supplement < Lutaml::Model::Serializable
18
18
  attribute :number, :string # Supplement number (e.g., "2" in "supp2")
19
- attribute :year, :string # Year (4 digits)
20
- attribute :month, :string # Month abbreviation (Jan, Feb, etc.)
21
- attribute :month_start, :string # Date range start month
22
- attribute :year_start, :string # Date range start year
19
+ attribute :year, :string # Year (4 digits); range START year
20
+ attribute :month, :string # Month abbreviation; range START month
21
+ # Date ranges reuse :month/:year as the start and add the end below. A
22
+ # present :month_end/:year_end is what marks a value as a range, so a
23
+ # lone month-year supplement is just a range with no end — and :year is
24
+ # the single field to filter on for both.
23
25
  attribute :month_end, :string # Date range end month
24
26
  attribute :year_end, :string # Date range end year
25
27
  attribute :has_revision, :boolean, default: -> {
@@ -27,12 +29,36 @@ module Pubid
27
29
  } # "supprev" pattern
28
30
  attribute :suffix, :string # General suffix for other patterns
29
31
 
32
+ # Build a Supplement from the flat string the parser/builder produces
33
+ # ("1924" year, "Jan1924" month+year, "1" number, "A" suffix, "" bare).
34
+ # has_revision is supplied separately. Returns a present-but-empty
35
+ # Supplement for an empty/nil value so callers can distinguish a bare
36
+ # supplement ("sup") from no supplement (nil).
37
+ def self.from_raw(value, has_revision: false)
38
+ supp = new
39
+ if has_revision
40
+ supp.has_revision = true
41
+ elsif value.nil? || value.to_s.empty?
42
+ # bare marker: present but no isolated parts
43
+ elsif (m = value.to_s.match(/\A([A-Za-z]{3,9})(\d{4})\z/))
44
+ supp.month = m[1]
45
+ supp.year = m[2]
46
+ elsif value.to_s.match?(/\A(?:18|19|20)\d{2}\z/)
47
+ supp.year = value.to_s
48
+ elsif value.to_s.match?(/\A\d+\z/)
49
+ supp.number = value.to_s
50
+ else
51
+ supp.suffix = value.to_s
52
+ end
53
+ supp
54
+ end
55
+
30
56
  # Render supplement in specified format
31
57
  # @param format [:short, :mr, :long] The output format
32
58
  # @return [String] The formatted supplement representation
33
59
  def to_s(format = :short)
34
- return "" if number.nil? && year.nil? && !has_revision && suffix.nil? &&
35
- month_start.nil? && year_start.nil? && month_end.nil? && year_end.nil?
60
+ return "" if number.nil? && year.nil? && month.nil? && !has_revision &&
61
+ suffix.nil? && month_end.nil? && year_end.nil?
36
62
 
37
63
  case format
38
64
  when :short, :mr
@@ -44,12 +70,52 @@ module Pubid
44
70
  end
45
71
  end
46
72
 
73
+ # True when this supplement is a date range (start reuses month/year).
74
+ def range?
75
+ date_range?
76
+ end
77
+
78
+ # The text after the "sup" marker for the simple (non-range, non-rev)
79
+ # forms: "1924" / "Jan1924" / "1" / "A"; "" for a bare supplement. Used
80
+ # by URN rendering, which handles range/revision separately.
81
+ def value_string
82
+ return "" if has_revision || date_range?
83
+ return suffix.to_s if suffix
84
+ return "#{month}#{year}" if month && year
85
+ return "#{number}/#{year}" if number && year
86
+ return year.to_s if year
87
+ return number.to_s if number
88
+
89
+ ""
90
+ end
91
+
92
+ # Value equality over the isolated parts, so a structured supplement
93
+ # participates correctly in Identifier#== and #matches? (two supplements
94
+ # with the same number/year/month/range/revision are the same).
95
+ IDENTITY_FIELDS = %i[
96
+ number year month month_end year_end has_revision suffix
97
+ ].freeze
98
+
99
+ def ==(other)
100
+ return false unless other.is_a?(self.class)
101
+
102
+ IDENTITY_FIELDS.all? { |f| public_send(f) == other.public_send(f) }
103
+ end
104
+
105
+ alias eql? ==
106
+
107
+ def hash
108
+ [self.class, *IDENTITY_FIELDS.map { |f| public_send(f) }].hash
109
+ end
110
+
47
111
  private
48
112
 
49
- # Build short format: "supp2", "supp-1925", "supp3/1926", "suppJan1924", "supprev"
113
+ # Build short format: "sup2", "sup1925", "sup3/1926", "supJan1924", "suprev"
114
+ # NIST/NBS canonical short form is single-p "sup" with the suffix
115
+ # attached directly (relaton-data-nist uses "sup2", "sup1940", "supA").
50
116
  def build_short_format
51
- return "supprev" if has_revision
52
- return "supp#{suffix}" if suffix
117
+ return "suprev" if has_revision
118
+ return "sup#{suffix}" if suffix
53
119
  return build_date_range_format if date_range?
54
120
  return build_month_year_format if month && year
55
121
  return build_number_year_format if number && year
@@ -72,32 +138,33 @@ module Pubid
72
138
  ""
73
139
  end
74
140
 
141
+ # A range is marked by the presence of an END; START reuses month/year.
75
142
  def date_range?
76
- month_start && year_start && month_end && year_end
143
+ month && year && month_end && year_end
77
144
  end
78
145
 
79
146
  def build_date_range_format
80
- "supp#{month_start}#{year_start}-#{month_end}#{year_end}"
147
+ "sup#{month}#{year}-#{month_end}#{year_end}"
81
148
  end
82
149
 
83
150
  def build_month_year_format
84
- "supp#{month}#{year}"
151
+ "sup#{month}#{year}"
85
152
  end
86
153
 
87
154
  def build_number_year_format
88
- "supp#{number}/#{year}"
155
+ "sup#{number}/#{year}"
89
156
  end
90
157
 
91
158
  def build_year_format
92
- "supp-#{year}"
159
+ "sup#{year}"
93
160
  end
94
161
 
95
162
  def build_number_format
96
- "supp#{number}"
163
+ "sup#{number}"
97
164
  end
98
165
 
99
166
  def build_long_date_range_format
100
- "Supplement #{month_start} #{year_start}-#{month_end} #{year_end}"
167
+ "Supplement #{month} #{year}-#{month_end} #{year_end}"
101
168
  end
102
169
 
103
170
  def build_long_month_year_format
@@ -7,7 +7,6 @@ module Pubid
7
7
  autoload :Edition, "#{__dir__}/components/edition"
8
8
  autoload :IssueNumber, "#{__dir__}/components/issue_number"
9
9
  autoload :Part, "#{__dir__}/components/part"
10
- autoload :Publisher, "#{__dir__}/components/publisher"
11
10
  autoload :Stage, "#{__dir__}/components/stage"
12
11
  autoload :Supplement, "#{__dir__}/components/supplement"
13
12
  autoload :Translation, "#{__dir__}/components/translation"
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Nist
5
+ # NIST factory entry point. `.parse` lives on `Pubid::Nist` itself for
6
+ # historical reasons; this module hosts the rest of the flavor-facade API
7
+ # (`from_hash`, identity) for consistency with the other pubid flavors.
8
+ #
9
+ # `extend Pubid::IdentifierFacade` adds polymorphic `from_hash` dispatch
10
+ # over the NIST `_type` registry; the matching `include Pubid::Nist::
11
+ # Identifier` in Identifiers::Base makes every concrete NIST identifier
12
+ # `is_a?(Pubid::Nist::Identifier)` (and `=== id`), so a consumer handed this
13
+ # module (e.g. relaton-index's `pubid_class`) can both deserialize and
14
+ # identity-check NIST ids through it.
15
+ module Identifier
16
+ extend Pubid::IdentifierFacade
17
+
18
+ # Delegate to the flavor module so callers can use
19
+ # `Pubid::Nist::Identifier.parse` consistently with other flavors.
20
+ def self.parse(identifier)
21
+ Pubid::Nist.parse(identifier)
22
+ end
23
+ end
24
+ end
25
+ end