pubid 2.0.0.pre.alpha.7 → 2.0.0.pre.alpha.9

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 (485) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +9 -50
  3. data/data/bipm/update_codes.yaml +9 -0
  4. data/data/iec/update_codes.yaml +3 -0
  5. data/data/ieee/update_codes.yaml +107 -1
  6. data/data/nist/series.yaml +155 -0
  7. data/data/nist/update_codes.yaml +8 -0
  8. data/lib/pubid/adobe/builder.rb +52 -0
  9. data/lib/pubid/adobe/identifier.rb +49 -0
  10. data/lib/pubid/adobe/identifiers/publication.rb +31 -0
  11. data/lib/pubid/adobe/identifiers/tech_note.rb +32 -0
  12. data/lib/pubid/adobe/identifiers.rb +10 -0
  13. data/lib/pubid/adobe/parser.rb +128 -0
  14. data/lib/pubid/adobe/renderer.rb +39 -0
  15. data/lib/pubid/adobe/urn_generator.rb +42 -0
  16. data/lib/pubid/adobe/urn_parser.rb +69 -0
  17. data/lib/pubid/adobe.rb +60 -0
  18. data/lib/pubid/amca/builder.rb +2 -2
  19. data/lib/pubid/amca/identifier.rb +1 -3
  20. data/lib/pubid/amca/identifiers/base.rb +1 -6
  21. data/lib/pubid/amca/identifiers/interpretation.rb +1 -1
  22. data/lib/pubid/amca/identifiers/publication.rb +1 -1
  23. data/lib/pubid/amca/identifiers/standard.rb +1 -1
  24. data/lib/pubid/amca/identifiers.rb +0 -1
  25. data/lib/pubid/amca/single_identifier.rb +1 -1
  26. data/lib/pubid/amca.rb +3 -3
  27. data/lib/pubid/ashrae/builder.rb +22 -22
  28. data/lib/pubid/ashrae/identifier.rb +3 -4
  29. data/lib/pubid/ashrae/identifiers/addenda_package.rb +1 -1
  30. data/lib/pubid/ashrae/identifiers/addendum.rb +1 -1
  31. data/lib/pubid/ashrae/identifiers/base.rb +14 -8
  32. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +1 -1
  33. data/lib/pubid/ashrae/identifiers.rb +0 -1
  34. data/lib/pubid/ashrae/parser.rb +14 -9
  35. data/lib/pubid/ashrae/renderer.rb +19 -19
  36. data/lib/pubid/ashrae/single_identifier.rb +1 -1
  37. data/lib/pubid/ashrae/supplement_identifier.rb +6 -6
  38. data/lib/pubid/ashrae.rb +3 -3
  39. data/lib/pubid/bipm/builder.rb +107 -0
  40. data/lib/pubid/bipm/identifier.rb +160 -0
  41. data/lib/pubid/bipm/identifiers/committee_document.rb +24 -0
  42. data/lib/pubid/bipm/identifiers/guide.rb +24 -0
  43. data/lib/pubid/bipm/identifiers/meeting.rb +41 -0
  44. data/lib/pubid/bipm/identifiers/mep.rb +21 -0
  45. data/lib/pubid/bipm/identifiers/metrologia_article.rb +24 -0
  46. data/lib/pubid/bipm/identifiers/si_brochure.rb +20 -0
  47. data/lib/pubid/bipm/identifiers.rb +15 -0
  48. data/lib/pubid/bipm/parser.rb +184 -0
  49. data/lib/pubid/bipm/renderer.rb +110 -0
  50. data/lib/pubid/bipm/urn_generator.rb +58 -0
  51. data/lib/pubid/bipm/urn_parser.rb +52 -0
  52. data/lib/pubid/bipm.rb +86 -0
  53. data/lib/pubid/bsi/builder.rb +14 -14
  54. data/lib/pubid/bsi/identifier.rb +0 -1
  55. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -2
  56. data/lib/pubid/bsi/identifiers/amendment.rb +4 -4
  57. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +6 -0
  58. data/lib/pubid/bsi/identifiers/corrigendum.rb +4 -4
  59. data/lib/pubid/bsi/identifiers/expert_commentary.rb +5 -5
  60. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -2
  61. data/lib/pubid/bsi/identifiers/value_added_publication.rb +6 -6
  62. data/lib/pubid/bsi/renderer.rb +8 -8
  63. data/lib/pubid/bsi/single_identifier.rb +48 -0
  64. data/lib/pubid/builder/base.rb +5 -3
  65. data/lib/pubid/bundled_identifier.rb +3 -3
  66. data/lib/pubid/calconnect/builder.rb +38 -0
  67. data/lib/pubid/calconnect/identifier.rb +117 -0
  68. data/lib/pubid/calconnect/identifiers/standard.rb +29 -0
  69. data/lib/pubid/calconnect/identifiers.rb +9 -0
  70. data/lib/pubid/calconnect/parser.rb +54 -0
  71. data/lib/pubid/calconnect/renderer.rb +36 -0
  72. data/lib/pubid/calconnect/urn_generator.rb +33 -0
  73. data/lib/pubid/calconnect/urn_parser.rb +34 -0
  74. data/lib/pubid/calconnect.rb +77 -0
  75. data/lib/pubid/ccsds/builder.rb +1 -1
  76. data/lib/pubid/ccsds/identifier.rb +1 -1
  77. data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
  78. data/lib/pubid/ccsds/supplement_identifier.rb +6 -6
  79. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  80. data/lib/pubid/cen_cenelec/builder.rb +46 -12
  81. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +2 -2
  82. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +6 -0
  83. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +2 -2
  84. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +60 -3
  85. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +2 -2
  86. data/lib/pubid/cen_cenelec/renderer.rb +5 -5
  87. data/lib/pubid/cen_cenelec/supplement_identifier.rb +5 -5
  88. data/lib/pubid/cen_cenelec/urn_generator.rb +1 -1
  89. data/lib/pubid/cen_cenelec.rb +76 -72
  90. data/lib/pubid/cie/builder.rb +139 -24
  91. data/lib/pubid/cie/identifier.rb +7 -3
  92. data/lib/pubid/cie/identifiers/bundle.rb +32 -4
  93. data/lib/pubid/cie/identifiers/code_attributes.rb +52 -0
  94. data/lib/pubid/cie/identifiers/conference.rb +9 -4
  95. data/lib/pubid/cie/identifiers/corrigendum.rb +17 -23
  96. data/lib/pubid/cie/identifiers/dual_published.rb +4 -4
  97. data/lib/pubid/cie/identifiers/identical.rb +7 -7
  98. data/lib/pubid/cie/identifiers/joint_published.rb +8 -8
  99. data/lib/pubid/cie/identifiers/proceedings.rb +39 -0
  100. data/lib/pubid/cie/identifiers/standard.rb +33 -7
  101. data/lib/pubid/cie/identifiers/supplement.rb +24 -22
  102. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +6 -2
  103. data/lib/pubid/cie/identifiers.rb +2 -0
  104. data/lib/pubid/cie/parser.rb +54 -5
  105. data/lib/pubid/cie/single_identifier.rb +40 -1
  106. data/lib/pubid/cie/supplement_identifier.rb +29 -16
  107. data/lib/pubid/cie/urn_generator.rb +11 -8
  108. data/lib/pubid/cie.rb +0 -1
  109. data/lib/pubid/components/date.rb +21 -5
  110. data/lib/pubid/csa/builder.rb +1 -1
  111. data/lib/pubid/csa/composite_identifier.rb +17 -1
  112. data/lib/pubid/csa/identifier.rb +48 -3
  113. data/lib/pubid/csa/identifiers/bundled.rb +6 -0
  114. data/lib/pubid/csa/identifiers/combined.rb +6 -0
  115. data/lib/pubid/csa/identifiers/package.rb +2 -2
  116. data/lib/pubid/csa/parser.rb +6 -6
  117. data/lib/pubid/csa/wrapper_identifier.rb +17 -0
  118. data/lib/pubid/doi/builder.rb +18 -0
  119. data/lib/pubid/doi/identifier.rb +46 -0
  120. data/lib/pubid/doi/identifiers/resource.rb +30 -0
  121. data/lib/pubid/doi/identifiers.rb +9 -0
  122. data/lib/pubid/doi/parser.rb +52 -0
  123. data/lib/pubid/doi/renderer.rb +13 -0
  124. data/lib/pubid/doi.rb +55 -0
  125. data/lib/pubid/easc/builder.rb +55 -0
  126. data/lib/pubid/easc/identifier.rb +61 -0
  127. data/lib/pubid/easc/identifiers/pmg.rb +20 -0
  128. data/lib/pubid/easc/identifiers/rmg.rb +19 -0
  129. data/lib/pubid/easc/identifiers.rb +10 -0
  130. data/lib/pubid/easc/parser.rb +80 -0
  131. data/lib/pubid/easc/renderer.rb +48 -0
  132. data/lib/pubid/easc/urn_generator.rb +46 -0
  133. data/lib/pubid/easc/urn_parser.rb +57 -0
  134. data/lib/pubid/easc.rb +52 -0
  135. data/lib/pubid/ecma/builder.rb +31 -0
  136. data/lib/pubid/ecma/identifier.rb +76 -0
  137. data/lib/pubid/ecma/identifiers/memento.rb +30 -0
  138. data/lib/pubid/ecma/identifiers/standard.rb +31 -0
  139. data/lib/pubid/ecma/identifiers/technical_report.rb +31 -0
  140. data/lib/pubid/ecma/identifiers.rb +11 -0
  141. data/lib/pubid/ecma/parser.rb +41 -0
  142. data/lib/pubid/ecma/renderer.rb +46 -0
  143. data/lib/pubid/ecma/urn_generator.rb +25 -0
  144. data/lib/pubid/ecma/urn_parser.rb +35 -0
  145. data/lib/pubid/ecma.rb +67 -0
  146. data/lib/pubid/etsi/builder.rb +7 -3
  147. data/lib/pubid/etsi/identifier.rb +1 -3
  148. data/lib/pubid/etsi/identifiers/base.rb +28 -10
  149. data/lib/pubid/etsi/identifiers/etsi_standard.rb +128 -4
  150. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +35 -3
  151. data/lib/pubid/etsi/identifiers.rb +0 -1
  152. data/lib/pubid/etsi/parser.rb +8 -2
  153. data/lib/pubid/etsi/renderer.rb +8 -2
  154. data/lib/pubid/etsi.rb +5 -5
  155. data/lib/pubid/export/exporter.rb +2 -1
  156. data/lib/pubid/export/flavor_exporter.rb +18 -3
  157. data/lib/pubid/gb/builder.rb +45 -0
  158. data/lib/pubid/gb/identifier.rb +64 -0
  159. data/lib/pubid/gb/identifiers/standard.rb +34 -0
  160. data/lib/pubid/gb/identifiers.rb +9 -0
  161. data/lib/pubid/gb/parser.rb +63 -0
  162. data/lib/pubid/gb/renderer.rb +35 -0
  163. data/lib/pubid/gb.rb +87 -0
  164. data/lib/pubid/gost/builder.rb +148 -0
  165. data/lib/pubid/gost/identifier.rb +49 -0
  166. data/lib/pubid/gost/identifiers/foreign_reference.rb +25 -0
  167. data/lib/pubid/gost/identifiers/harmonized.rb +39 -0
  168. data/lib/pubid/gost/identifiers/identical_adoption.rb +39 -0
  169. data/lib/pubid/gost/identifiers/interstate_standard.rb +20 -0
  170. data/lib/pubid/gost/identifiers/national_standard.rb +19 -0
  171. data/lib/pubid/gost/identifiers.rb +13 -0
  172. data/lib/pubid/gost/parser.rb +97 -0
  173. data/lib/pubid/gost/renderer.rb +48 -0
  174. data/lib/pubid/gost/urn_generator.rb +46 -0
  175. data/lib/pubid/gost/urn_parser.rb +52 -0
  176. data/lib/pubid/gost.rb +49 -0
  177. data/lib/pubid/iala/builder.rb +22 -27
  178. data/lib/pubid/iala/identifier.rb +27 -2
  179. data/lib/pubid/iala/identifiers/advice.rb +1 -1
  180. data/lib/pubid/iala/identifiers/annex.rb +14 -12
  181. data/lib/pubid/iala/identifiers/general_assembly.rb +5 -2
  182. data/lib/pubid/iala/identifiers/guideline.rb +3 -1
  183. data/lib/pubid/iala/identifiers/letter.rb +1 -1
  184. data/lib/pubid/iala/identifiers/manual.rb +3 -1
  185. data/lib/pubid/iala/identifiers/model_course.rb +3 -1
  186. data/lib/pubid/iala/identifiers/recommendation.rb +3 -1
  187. data/lib/pubid/iala/identifiers/report.rb +1 -1
  188. data/lib/pubid/iala/identifiers/resolution.rb +1 -1
  189. data/lib/pubid/iala/identifiers/standard.rb +3 -1
  190. data/lib/pubid/iala/identifiers.rb +0 -1
  191. data/lib/pubid/iala/renderer.rb +1 -1
  192. data/lib/pubid/iala/urn_generator.rb +1 -1
  193. data/lib/pubid/iala/urn_parser.rb +19 -2
  194. data/lib/pubid/iala.rb +4 -4
  195. data/lib/pubid/iana/builder.rb +20 -0
  196. data/lib/pubid/iana/identifier.rb +72 -0
  197. data/lib/pubid/iana/identifiers/registry.rb +33 -0
  198. data/lib/pubid/iana/identifiers.rb +9 -0
  199. data/lib/pubid/iana/parser.rb +38 -0
  200. data/lib/pubid/iana/renderer.rb +29 -0
  201. data/lib/pubid/iana/urn_generator.rb +15 -0
  202. data/lib/pubid/iana/urn_parser.rb +24 -0
  203. data/lib/pubid/iana.rb +69 -0
  204. data/lib/pubid/identifier.rb +210 -23
  205. data/lib/pubid/idf/builder.rb +1 -1
  206. data/lib/pubid/idf/parser.rb +2 -2
  207. data/lib/pubid/idf/renderer.rb +1 -1
  208. data/lib/pubid/idf/supplement_identifier.rb +3 -3
  209. data/lib/pubid/iec/builder.rb +35 -25
  210. data/lib/pubid/iec/identifier.rb +47 -2
  211. data/lib/pubid/iec/identifiers/base.rb +2 -2
  212. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +6 -0
  213. data/lib/pubid/iec/identifiers/fragment_identifier.rb +11 -11
  214. data/lib/pubid/iec/identifiers/international_standard.rb +8 -5
  215. data/lib/pubid/iec/identifiers/sheet_identifier.rb +12 -12
  216. data/lib/pubid/iec/identifiers/technical_group.rb +30 -0
  217. data/lib/pubid/iec/identifiers/technical_report.rb +1 -1
  218. data/lib/pubid/iec/identifiers/technical_specification.rb +1 -1
  219. data/lib/pubid/iec/identifiers/vap_identifier.rb +12 -12
  220. data/lib/pubid/iec/identifiers.rb +1 -0
  221. data/lib/pubid/iec/parser.rb +51 -10
  222. data/lib/pubid/iec/renderer.rb +18 -8
  223. data/lib/pubid/iec/single_identifier.rb +1 -1
  224. data/lib/pubid/iec/supplement_identifier.rb +32 -19
  225. data/lib/pubid/iec.rb +1 -6
  226. data/lib/pubid/ieee/aiee/builder.rb +17 -3
  227. data/lib/pubid/ieee/aiee/identifier.rb +45 -61
  228. data/lib/pubid/ieee/builder.rb +341 -68
  229. data/lib/pubid/ieee/compaction.rb +121 -0
  230. data/lib/pubid/ieee/components/draft.rb +47 -7
  231. data/lib/pubid/ieee/identifier.rb +1 -3
  232. data/lib/pubid/ieee/identifiers/adopted_standard.rb +30 -5
  233. data/lib/pubid/ieee/identifiers/amendment.rb +40 -0
  234. data/lib/pubid/ieee/identifiers/base.rb +106 -13
  235. data/lib/pubid/ieee/identifiers/code_number.rb +82 -0
  236. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +6 -2
  237. data/lib/pubid/ieee/identifiers/corrigendum.rb +17 -2
  238. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +3 -3
  239. data/lib/pubid/ieee/identifiers/dual_identifier.rb +3 -3
  240. data/lib/pubid/ieee/identifiers/dual_published.rb +3 -3
  241. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +102 -5
  242. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +2 -1
  243. data/lib/pubid/ieee/identifiers/joint_development.rb +56 -11
  244. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +1 -1
  245. data/lib/pubid/ieee/identifiers/nesc/base.rb +90 -19
  246. data/lib/pubid/ieee/identifiers/nesc/draft.rb +20 -5
  247. data/lib/pubid/ieee/identifiers/nesc/edition.rb +32 -0
  248. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +16 -5
  249. data/lib/pubid/ieee/identifiers/nesc/redline.rb +11 -2
  250. data/lib/pubid/ieee/identifiers/nesc/standard.rb +18 -3
  251. data/lib/pubid/ieee/identifiers/nesc.rb +1 -0
  252. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +3 -3
  253. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +14 -6
  254. data/lib/pubid/ieee/identifiers/redlined_standard.rb +4 -4
  255. data/lib/pubid/ieee/identifiers/si_standard.rb +4 -1
  256. data/lib/pubid/ieee/identifiers/standard.rb +4 -1
  257. data/lib/pubid/ieee/identifiers/supplement_identifier.rb +26 -7
  258. data/lib/pubid/ieee/identifiers.rb +2 -1
  259. data/lib/pubid/ieee/ire/builder.rb +7 -6
  260. data/lib/pubid/ieee/ire/identifier.rb +48 -33
  261. data/lib/pubid/ieee/nesc/builder.rb +33 -20
  262. data/lib/pubid/ieee/nesc/parser.rb +15 -14
  263. data/lib/pubid/ieee/parser.rb +461 -43
  264. data/lib/pubid/ieee/pre_parser.rb +1 -1
  265. data/lib/pubid/ieee/renderer.rb +154 -57
  266. data/lib/pubid/ieee/typed_stages.rb +12 -1
  267. data/lib/pubid/ieee/urn_generator.rb +3 -5
  268. data/lib/pubid/ieee.rb +56 -3
  269. data/lib/pubid/ietf/builder.rb +62 -0
  270. data/lib/pubid/ietf/identifier.rb +5 -0
  271. data/lib/pubid/ietf/identifiers/base.rb +75 -0
  272. data/lib/pubid/ietf/identifiers/bcp.rb +25 -0
  273. data/lib/pubid/ietf/identifiers/fyi.rb +25 -0
  274. data/lib/pubid/ietf/identifiers/internet_draft.rb +29 -0
  275. data/lib/pubid/ietf/identifiers/rfc.rb +25 -0
  276. data/lib/pubid/ietf/identifiers/std.rb +25 -0
  277. data/lib/pubid/ietf/identifiers.rb +13 -0
  278. data/lib/pubid/ietf/parser.rb +43 -0
  279. data/lib/pubid/ietf/renderer.rb +26 -0
  280. data/lib/pubid/ietf/urn_generator.rb +23 -0
  281. data/lib/pubid/ietf/urn_parser.rb +35 -0
  282. data/lib/pubid/ietf.rb +76 -0
  283. data/lib/pubid/iho/identifier.rb +1 -3
  284. data/lib/pubid/iho/identifiers/base.rb +1 -7
  285. data/lib/pubid/iho/identifiers/bibliographic.rb +1 -1
  286. data/lib/pubid/iho/identifiers/circular_letter.rb +1 -1
  287. data/lib/pubid/iho/identifiers/miscellaneous.rb +1 -1
  288. data/lib/pubid/iho/identifiers/publication.rb +1 -1
  289. data/lib/pubid/iho/identifiers/standard.rb +1 -1
  290. data/lib/pubid/iho/identifiers.rb +0 -1
  291. data/lib/pubid/iho.rb +7 -7
  292. data/lib/pubid/isbn/builder.rb +44 -0
  293. data/lib/pubid/isbn/check_digit.rb +53 -0
  294. data/lib/pubid/isbn/identifier.rb +63 -0
  295. data/lib/pubid/isbn/identifiers/book.rb +30 -0
  296. data/lib/pubid/isbn/identifiers.rb +9 -0
  297. data/lib/pubid/isbn/parser.rb +45 -0
  298. data/lib/pubid/isbn/renderer.rb +16 -0
  299. data/lib/pubid/isbn.rb +52 -0
  300. data/lib/pubid/iso/builder.rb +9 -4
  301. data/lib/pubid/iso/combined_identifier.rb +2 -2
  302. data/lib/pubid/iso/identifier.rb +17 -1
  303. data/lib/pubid/iso/identifiers/directives_supplement.rb +8 -8
  304. data/lib/pubid/iso/normalizer.rb +2 -2
  305. data/lib/pubid/iso/parser.rb +16 -12
  306. data/lib/pubid/iso/supplement_identifier.rb +19 -6
  307. data/lib/pubid/iso/urn_generator.rb +4 -1
  308. data/lib/pubid/iso/urn_parser.rb +1 -1
  309. data/lib/pubid/itu/builder.rb +230 -29
  310. data/lib/pubid/itu/components/code.rb +48 -5
  311. data/lib/pubid/itu/components/designation.rb +35 -0
  312. data/lib/pubid/itu/components.rb +1 -0
  313. data/lib/pubid/itu/identifier.rb +1 -3
  314. data/lib/pubid/itu/identifiers/addendum.rb +15 -0
  315. data/lib/pubid/itu/identifiers/amendment.rb +6 -28
  316. data/lib/pubid/itu/identifiers/annex.rb +13 -2
  317. data/lib/pubid/itu/identifiers/annex_of_recommendation.rb +87 -0
  318. data/lib/pubid/itu/identifiers/appendix_of_recommendation.rb +92 -0
  319. data/lib/pubid/itu/identifiers/base.rb +341 -23
  320. data/lib/pubid/itu/identifiers/combined_identifier.rb +99 -23
  321. data/lib/pubid/itu/identifiers/corrigendum.rb +16 -23
  322. data/lib/pubid/itu/identifiers/errata.rb +15 -0
  323. data/lib/pubid/itu/identifiers/handbook.rb +38 -0
  324. data/lib/pubid/itu/identifiers/question.rb +63 -0
  325. data/lib/pubid/itu/identifiers/recommendation.rb +3 -2
  326. data/lib/pubid/itu/identifiers/report.rb +39 -0
  327. data/lib/pubid/itu/identifiers/special_publication.rb +3 -1
  328. data/lib/pubid/itu/identifiers/standard_serialization.rb +58 -0
  329. data/lib/pubid/itu/identifiers/supplement.rb +119 -14
  330. data/lib/pubid/itu/identifiers.rb +10 -1
  331. data/lib/pubid/itu/model.rb +1 -1
  332. data/lib/pubid/itu/parser.rb +480 -26
  333. data/lib/pubid/itu/urn_generator.rb +36 -6
  334. data/lib/pubid/itu/urn_parser.rb +8 -0
  335. data/lib/pubid/itu.rb +11 -3
  336. data/lib/pubid/jcgm/builder.rb +23 -13
  337. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -2
  338. data/lib/pubid/jcgm/identifiers/corrigendum.rb +34 -0
  339. data/lib/pubid/jcgm/identifiers/gum_guide.rb +3 -3
  340. data/lib/pubid/jcgm/identifiers/meeting.rb +47 -0
  341. data/lib/pubid/jcgm/identifiers.rb +2 -0
  342. data/lib/pubid/jcgm/parser.rb +66 -6
  343. data/lib/pubid/jcgm/renderer.rb +26 -12
  344. data/lib/pubid/jcgm/single_identifier.rb +74 -5
  345. data/lib/pubid/jcgm/supplement_identifier.rb +39 -4
  346. data/lib/pubid/jcgm/urn_generator.rb +21 -13
  347. data/lib/pubid/jcgm/urn_parser.rb +15 -3
  348. data/lib/pubid/jis/identifier.rb +52 -0
  349. data/lib/pubid/nist/builder.rb +29 -9
  350. data/lib/pubid/nist/caster.rb +7 -45
  351. data/lib/pubid/nist/circular_supplement_builder.rb +7 -5
  352. data/lib/pubid/nist/components/supplement.rb +5 -2
  353. data/lib/pubid/nist/configuration.rb +7 -1
  354. data/lib/pubid/nist/identifier.rb +1 -3
  355. data/lib/pubid/nist/identifiers/base.rb +121 -37
  356. data/lib/pubid/nist/identifiers/circular.rb +1 -1
  357. data/lib/pubid/nist/identifiers/commercial_standard.rb +1 -1
  358. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
  359. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +1 -1
  360. data/lib/pubid/nist/identifiers/crpl_report.rb +1 -1
  361. data/lib/pubid/nist/identifiers/dated_document.rb +1 -1
  362. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +1 -1
  363. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +1 -1
  364. data/lib/pubid/nist/identifiers/handbook.rb +1 -1
  365. data/lib/pubid/nist/identifiers/internal_report.rb +1 -1
  366. data/lib/pubid/nist/identifiers/letter_circular.rb +1 -1
  367. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +1 -1
  368. data/lib/pubid/nist/identifiers/monograph.rb +1 -1
  369. data/lib/pubid/nist/identifiers/ncstar.rb +2 -2
  370. data/lib/pubid/nist/identifiers/nsrds.rb +1 -1
  371. data/lib/pubid/nist/identifiers/owmwp.rb +1 -1
  372. data/lib/pubid/nist/identifiers/report.rb +1 -1
  373. data/lib/pubid/nist/identifiers/special_publication.rb +10 -1
  374. data/lib/pubid/nist/identifiers/technical_note.rb +1 -1
  375. data/lib/pubid/nist/identifiers.rb +0 -1
  376. data/lib/pubid/nist/parser.rb +29 -4
  377. data/lib/pubid/nist/preprocessor.rb +15 -0
  378. data/lib/pubid/nist/router.rb +3 -2
  379. data/lib/pubid/nist/series/ir.rb +0 -3
  380. data/lib/pubid/nist/supplement_identifier.rb +9 -9
  381. data/lib/pubid/nist.rb +13 -12
  382. data/lib/pubid/oasis/builder.rb +77 -0
  383. data/lib/pubid/oasis/identifier.rb +82 -0
  384. data/lib/pubid/oasis/identifiers/standard.rb +29 -0
  385. data/lib/pubid/oasis/identifiers.rb +9 -0
  386. data/lib/pubid/oasis/parser.rb +34 -0
  387. data/lib/pubid/oasis/renderer.rb +29 -0
  388. data/lib/pubid/oasis/urn_generator.rb +25 -0
  389. data/lib/pubid/oasis/urn_parser.rb +22 -0
  390. data/lib/pubid/oasis.rb +74 -0
  391. data/lib/pubid/ogc/builder.rb +33 -0
  392. data/lib/pubid/ogc/identifier.rb +77 -0
  393. data/lib/pubid/ogc/identifiers/document.rb +26 -0
  394. data/lib/pubid/ogc/identifiers.rb +10 -0
  395. data/lib/pubid/ogc/parser.rb +40 -0
  396. data/lib/pubid/ogc/renderer.rb +33 -0
  397. data/lib/pubid/ogc/urn_generator.rb +14 -0
  398. data/lib/pubid/ogc/urn_parser.rb +22 -0
  399. data/lib/pubid/ogc.rb +71 -0
  400. data/lib/pubid/oiml/builder.rb +31 -7
  401. data/lib/pubid/oiml/identifier.rb +9 -1
  402. data/lib/pubid/oiml/parser.rb +11 -12
  403. data/lib/pubid/oiml/renderer.rb +13 -13
  404. data/lib/pubid/oiml/single_identifier.rb +20 -0
  405. data/lib/pubid/oiml/supplement_identifier.rb +9 -9
  406. data/lib/pubid/oiml/urn_parser.rb +23 -6
  407. data/lib/pubid/oiml.rb +4 -0
  408. data/lib/pubid/omg/builder.rb +19 -0
  409. data/lib/pubid/omg/identifier.rb +44 -0
  410. data/lib/pubid/omg/identifiers/specification.rb +32 -0
  411. data/lib/pubid/omg/identifiers.rb +9 -0
  412. data/lib/pubid/omg/parser.rb +40 -0
  413. data/lib/pubid/omg/renderer.rb +19 -0
  414. data/lib/pubid/omg.rb +51 -0
  415. data/lib/pubid/parsers/mr_string.rb +101 -7
  416. data/lib/pubid/plateau/builder.rb +8 -4
  417. data/lib/pubid/plateau/identifier.rb +1 -3
  418. data/lib/pubid/plateau/identifiers/base.rb +1 -6
  419. data/lib/pubid/plateau/identifiers/handbook.rb +1 -1
  420. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  421. data/lib/pubid/plateau/identifiers.rb +0 -1
  422. data/lib/pubid/plateau/parser.rb +15 -5
  423. data/lib/pubid/plateau/renderer.rb +1 -1
  424. data/lib/pubid/plateau/supplement_identifier.rb +11 -11
  425. data/lib/pubid/plateau.rb +4 -4
  426. data/lib/pubid/renderers/human_readable.rb +3 -1
  427. data/lib/pubid/renderers/mr_string.rb +46 -4
  428. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  429. data/lib/pubid/rendering/supplement.rb +4 -4
  430. data/lib/pubid/sae/builder.rb +1 -1
  431. data/lib/pubid/sae/identifier.rb +1 -3
  432. data/lib/pubid/sae/identifiers/base.rb +10 -7
  433. data/lib/pubid/sae/identifiers.rb +0 -1
  434. data/lib/pubid/sae.rb +3 -3
  435. data/lib/pubid/tgpp/builder.rb +41 -0
  436. data/lib/pubid/tgpp/identifier.rb +91 -0
  437. data/lib/pubid/tgpp/identifiers/technical_report.rb +32 -0
  438. data/lib/pubid/tgpp/identifiers/technical_specification.rb +33 -0
  439. data/lib/pubid/tgpp/identifiers.rb +11 -0
  440. data/lib/pubid/tgpp/parser.rb +62 -0
  441. data/lib/pubid/tgpp/renderer.rb +36 -0
  442. data/lib/pubid/tgpp/urn_generator.rb +20 -0
  443. data/lib/pubid/tgpp/urn_parser.rb +28 -0
  444. data/lib/pubid/tgpp.rb +78 -0
  445. data/lib/pubid/type_resolver.rb +59 -0
  446. data/lib/pubid/un/builder.rb +42 -0
  447. data/lib/pubid/un/identifier.rb +37 -0
  448. data/lib/pubid/un/identifiers/document.rb +24 -0
  449. data/lib/pubid/un/identifiers.rb +9 -0
  450. data/lib/pubid/un/parser.rb +25 -0
  451. data/lib/pubid/un/renderer.rb +11 -0
  452. data/lib/pubid/un.rb +46 -0
  453. data/lib/pubid/version.rb +1 -1
  454. data/lib/pubid/w3c/builder.rb +55 -0
  455. data/lib/pubid/w3c/identifier.rb +101 -0
  456. data/lib/pubid/w3c/identifiers/candidate_recommendation.rb +31 -0
  457. data/lib/pubid/w3c/identifiers/candidate_recommendation_draft.rb +31 -0
  458. data/lib/pubid/w3c/identifiers/draft_note.rb +31 -0
  459. data/lib/pubid/w3c/identifiers/note.rb +30 -0
  460. data/lib/pubid/w3c/identifiers/obsolete_recommendation.rb +31 -0
  461. data/lib/pubid/w3c/identifiers/proposed_edited_recommendation.rb +31 -0
  462. data/lib/pubid/w3c/identifiers/proposed_recommendation.rb +31 -0
  463. data/lib/pubid/w3c/identifiers/recommendation.rb +31 -0
  464. data/lib/pubid/w3c/identifiers/standard.rb +12 -0
  465. data/lib/pubid/w3c/identifiers/superseded_recommendation.rb +31 -0
  466. data/lib/pubid/w3c/identifiers/working_draft.rb +30 -0
  467. data/lib/pubid/w3c/identifiers.rb +25 -0
  468. data/lib/pubid/w3c/parser.rb +43 -0
  469. data/lib/pubid/w3c/renderer.rb +35 -0
  470. data/lib/pubid/w3c/urn_generator.rb +18 -0
  471. data/lib/pubid/w3c/urn_parser.rb +36 -0
  472. data/lib/pubid/w3c.rb +67 -0
  473. data/lib/pubid/xsf/builder.rb +17 -0
  474. data/lib/pubid/xsf/identifier.rb +62 -0
  475. data/lib/pubid/xsf/identifiers/xep.rb +31 -0
  476. data/lib/pubid/xsf/identifiers.rb +9 -0
  477. data/lib/pubid/xsf/parser.rb +25 -0
  478. data/lib/pubid/xsf/renderer.rb +23 -0
  479. data/lib/pubid/xsf/urn_generator.rb +13 -0
  480. data/lib/pubid/xsf/urn_parser.rb +18 -0
  481. data/lib/pubid/xsf.rb +76 -0
  482. data/lib/pubid.rb +25 -1
  483. metadata +205 -4
  484. data/lib/pubid/cie/components/code.rb +0 -80
  485. data/lib/pubid/iala/identifiers/base.rb +0 -14
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ module Identifiers
6
+ # An FYI (For Your Information) sub-series id, e.g. "FYI 1".
7
+ class Fyi < Identifier
8
+ TYPED_STAGES = [
9
+ Pubid::Components::TypedStage.new(
10
+ code: :fyi,
11
+ stage_code: :published,
12
+ type_code: :fyi,
13
+ abbr: ["FYI"],
14
+ name: "For Your Information",
15
+ harmonized_stages: [],
16
+ ),
17
+ ].freeze
18
+
19
+ def self.type
20
+ { key: :fyi, web: :fyi, title: "For Your Information", short: "FYI" }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ module Identifiers
6
+ # An Internet-Draft, e.g. "draft-giuliano-treedn-02" (versioned) or
7
+ # "draft-giuliano-treedn" (the unversioned "latest" sibling). The full
8
+ # slug (including the leading "draft-") is stored in `name`; the optional
9
+ # trailing two-digit version in `version`.
10
+ class InternetDraft < Identifier
11
+ TYPED_STAGES = [
12
+ Pubid::Components::TypedStage.new(
13
+ code: :internet_draft,
14
+ stage_code: :draft,
15
+ type_code: :internet_draft,
16
+ abbr: ["I-D", "Internet-Draft"],
17
+ name: "Internet-Draft",
18
+ harmonized_stages: [],
19
+ ),
20
+ ].freeze
21
+
22
+ def self.type
23
+ { key: :internet_draft, web: :internet_draft,
24
+ title: "Internet-Draft", short: "I-D" }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ module Identifiers
6
+ # An RFC (Request for Comments), e.g. "RFC 2119".
7
+ class Rfc < Identifier
8
+ TYPED_STAGES = [
9
+ Pubid::Components::TypedStage.new(
10
+ code: :rfc,
11
+ stage_code: :published,
12
+ type_code: :rfc,
13
+ abbr: ["RFC"],
14
+ name: "Request for Comments",
15
+ harmonized_stages: [],
16
+ ),
17
+ ].freeze
18
+
19
+ def self.type
20
+ { key: :rfc, web: :rfc, title: "Request for Comments", short: "RFC" }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ module Identifiers
6
+ # An STD (Internet Standard) sub-series id, e.g. "STD 66".
7
+ class Std < Identifier
8
+ TYPED_STAGES = [
9
+ Pubid::Components::TypedStage.new(
10
+ code: :std,
11
+ stage_code: :published,
12
+ type_code: :std,
13
+ abbr: ["STD"],
14
+ name: "Internet Standard",
15
+ harmonized_stages: [],
16
+ ),
17
+ ].freeze
18
+
19
+ def self.type
20
+ { key: :std, web: :std, title: "Internet Standard", short: "STD" }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ module Identifiers
6
+ autoload :Rfc, "#{__dir__}/identifiers/rfc"
7
+ autoload :Bcp, "#{__dir__}/identifiers/bcp"
8
+ autoload :Std, "#{__dir__}/identifiers/std"
9
+ autoload :Fyi, "#{__dir__}/identifiers/fyi"
10
+ autoload :InternetDraft, "#{__dir__}/identifiers/internet_draft"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parslet"
4
+
5
+ module Pubid
6
+ module Ietf
7
+ # Parslet grammar for the three IETF families. The top-level alternation is
8
+ # keyed by leading token, and each alternative captures the raw fields the
9
+ # Builder needs:
10
+ # * RFC -> { number: }
11
+ # * sub-series -> { series:, number: }
12
+ # * draft -> { draft_rest: } (everything after "draft-"; the version
13
+ # split is done in the Builder to keep the digit-tail
14
+ # heuristic in one place)
15
+ class Parser < Parslet::Parser
16
+ rule(:space) { str(" ") }
17
+ rule(:digit) { match["0-9"] }
18
+ rule(:digits) { digit.repeat(1) }
19
+
20
+ # "RFC 2119"
21
+ rule(:rfc) { str("RFC") >> space >> digits.as(:number) }
22
+
23
+ # "BCP 3" / "STD 66" / "FYI 1"
24
+ rule(:subseries) do
25
+ (str("BCP") | str("STD") | str("FYI")).as(:series) >>
26
+ space >> digits.as(:number)
27
+ end
28
+
29
+ # Internet-Draft slug characters (lowercase, digits, and the "-", "+", "_"
30
+ # separators seen in the corpus). The whole remainder after "draft-" is
31
+ # captured; the Builder anchors the optional trailing "-NN" version.
32
+ rule(:draft_rest) { match['a-z0-9+_\-'].repeat(1).as(:draft_rest) }
33
+ rule(:draft) { str("draft-") >> draft_rest }
34
+
35
+ rule(:identifier) { rfc | subseries | draft }
36
+ rule(:root) { identifier }
37
+
38
+ def self.parse(input)
39
+ new.parse(input)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ # Human-readable renderer for IETF identifiers.
6
+ #
7
+ # Produces strings like:
8
+ # "RFC 2119"
9
+ # "BCP 3" / "STD 66" / "FYI 1"
10
+ # "draft-giuliano-treedn-02" / "draft-giuliano-treedn"
11
+ class Renderer < ::Pubid::Renderers::Base
12
+ def render(context: nil, **_opts)
13
+ id = @id
14
+
15
+ case id
16
+ when Identifiers::Rfc
17
+ "RFC #{id.number}"
18
+ when Identifiers::InternetDraft
19
+ id.version ? "#{id.name}-#{id.version}" : id.name
20
+ else # Bcp/Std/Fyi sub-series
21
+ "#{id.series} #{id.number}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ # Emits the canonical IETF URNs:
6
+ # RFC -> urn:ietf:rfc:2119
7
+ # BCP/STD/FYI -> urn:ietf:bcp:3 / urn:ietf:std:66 / urn:ietf:fyi:1
8
+ # Internet-Draft -> urn:ietf:id:draft-giuliano-treedn[:02]
9
+ class UrnGenerator < Pubid::UrnGenerator::Base
10
+ def generate
11
+ case identifier
12
+ when Identifiers::Rfc
13
+ "urn:ietf:rfc:#{identifier.number}"
14
+ when Identifiers::InternetDraft
15
+ base = "urn:ietf:id:#{identifier.name}"
16
+ identifier.version ? "#{base}:#{identifier.version}" : base
17
+ else # Bcp/Std/Fyi sub-series
18
+ "urn:ietf:#{identifier.series.downcase}:#{identifier.number}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Ietf
5
+ # Parses IETF URNs back into identifiers by reconstructing the printed form
6
+ # and delegating to the flavor's text parser. Inverts UrnGenerator:
7
+ # urn:ietf:rfc:2119 -> "RFC 2119"
8
+ # urn:ietf:bcp:3 -> "BCP 3"
9
+ # urn:ietf:id:draft-giuliano-treedn:02 -> "draft-giuliano-treedn-02"
10
+ # urn:ietf:id:draft-giuliano-treedn -> "draft-giuliano-treedn"
11
+ class UrnParser < Pubid::UrnParser::Base
12
+ def parse_urn(urn)
13
+ parts = split_parts(strip_namespace(urn))
14
+ flavor_parse(human_text(parts.shift, parts))
15
+ end
16
+
17
+ private
18
+
19
+ def human_text(type, parts)
20
+ case type
21
+ when "rfc" then "RFC #{parts[0]}"
22
+ when "bcp", "std", "fyi" then "#{type.upcase} #{parts[0]}"
23
+ when "id" then draft_text(parts)
24
+ else
25
+ raise Errors::ParseError, "Invalid IETF URN type: #{type.inspect}"
26
+ end
27
+ end
28
+
29
+ def draft_text(parts)
30
+ name, version = parts
31
+ version ? "#{name}-#{version}" : name
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/pubid/ietf.rb ADDED
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ # IETF flavor: one module covering the three IETF document families that share
5
+ # the IETF publisher and the `urn:ietf:` namespace —
6
+ # * RFC (e.g. "RFC 2119") -> Identifiers::Rfc
7
+ # * RFC sub-series (BCP/STD/FYI) -> Identifiers::Bcp/Std/Fyi
8
+ # * Internet-Drafts (e.g. "draft-...-02") -> Identifiers::InternetDraft
9
+ module Ietf
10
+ extend Pubid::PrefixesSupport
11
+
12
+ # Leading tokens a printed IETF id can begin with. "draft" covers the
13
+ # "draft-<slug>" Internet-Draft form. No joint/co-publication prefixes.
14
+ PREFIXES = ["RFC", "BCP", "STD", "FYI", "draft"].freeze
15
+
16
+ autoload :Builder, "#{__dir__}/ietf/builder"
17
+ autoload :Identifier, "#{__dir__}/ietf/identifiers/base"
18
+ autoload :Identifiers, "#{__dir__}/ietf/identifiers"
19
+ autoload :Parser, "#{__dir__}/ietf/parser"
20
+ autoload :Renderer, "#{__dir__}/ietf/renderer"
21
+ autoload :UrnGenerator, "#{__dir__}/ietf/urn_generator"
22
+ autoload :UrnParser, "#{__dir__}/ietf/urn_parser"
23
+
24
+ # Parse an IETF identifier string
25
+ def self.parse(identifier)
26
+ # Inline length guard (CodeQL rb/polynomial-redos barrier) before the
27
+ # normalization/parse path — must be the first statement.
28
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE if identifier.length > Pubid::MAX_INPUT_LENGTH
29
+
30
+ Identifier.parse(identifier)
31
+ end
32
+
33
+ # Per-flavor format registry: inherits global formats, overrides :human
34
+ Identifier.format_registry = FormatRegistry.new(parent: Identifier.format_registry)
35
+ Identifier.format_registry.register(:human, renderer: Ietf::Renderer)
36
+
37
+ # Auto-discover all identifier types from the Identifiers namespace
38
+ # @return [Array<Class>] identifier classes that define a self.type Hash
39
+ def self.identifier_types
40
+ @identifier_types ||= Identifiers.constants
41
+ .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
42
+ .select { |c| c.is_a?(Class) && c.singleton_methods(false).include?(:type) }
43
+ .select { |c| c.type.is_a?(Hash) }
44
+ end
45
+
46
+ # Build typed stage index from identifier types
47
+ # @return [Array<Pubid::Components::TypedStage>] all typed stages
48
+ def self.all_typed_stages
49
+ @all_typed_stages ||= identifier_types.flat_map do |klass|
50
+ if klass.const_defined?(:TYPED_STAGES)
51
+ klass.const_get(:TYPED_STAGES)
52
+ else
53
+ []
54
+ end
55
+ end
56
+ end
57
+
58
+ # Lookup: type code -> identifier class
59
+ # @param code [String, Symbol] the type key to find
60
+ # @return [Class, nil] the matching identifier class
61
+ def self.locate_type(code)
62
+ identifier_types.find { |t| t.type[:key].to_s == code.to_s }
63
+ end
64
+
65
+ # Lookup: abbreviation -> typed stage
66
+ # @param abbr [String, Symbol] the abbreviation to find
67
+ # @return [Pubid::Components::TypedStage, nil] the matching typed stage
68
+ def self.locate_stage(abbr)
69
+ abbr_str = abbr.to_s.upcase
70
+ all_typed_stages.find { |s| s.abbr.any? { |a| a.to_s.upcase == abbr_str } }
71
+ end
72
+ end
73
+ end
74
+
75
+ # Register IETF flavor with the registry
76
+ Pubid::Registry.register(:ietf, Pubid::Ietf)
@@ -3,7 +3,5 @@
3
3
  # The IHO flavor base class is Pubid::Iho::Identifier — a real Pubid::Identifier
4
4
  # subclass that every concrete IHO identifier descends from, so `is_a?` identity
5
5
  # and the shared polymorphic `from_hash` work natively (no facade needed). Its
6
- # body, `.parse`, and the Identifiers::Base back-compat alias live in
7
- # identifiers/base.rb; this file just ensures it is loaded when a consumer
6
+ # body and `.parse` live in identifiers/base.rb; this file just ensures it is loaded when a consumer
8
7
  # references Pubid::Iho::Identifier directly.
9
- require_relative "identifiers/base"
@@ -3,8 +3,7 @@
3
3
  module Pubid
4
4
  module Iho
5
5
  # Base class for all IHO identifiers. Canonical name Pubid::Iho::Identifier;
6
- # every concrete IHO identifier (Identifiers::*) descends from it, and
7
- # Identifiers::Base — aliased at the foot of this file — points back to it.
6
+ # every concrete IHO identifier (Identifiers::*) descends from it.
8
7
  #
9
8
  # IHO identifiers have the form:
10
9
  # IHO {S|P|M|B|C}-{number}[ Ap. {appendix}][ Part {part}][ Annex {annex}][ Suppl {supplement}][ {version}]
@@ -65,10 +64,5 @@ module Pubid
65
64
  # IHO_TYPE_MAP remains as the key_value polymorphic_map.
66
65
  end
67
66
 
68
- module Identifiers
69
- # Backward-compatible alias: IHO's base class used to be
70
- # Pubid::Iho::Identifiers::Base. It is now Pubid::Iho::Identifier.
71
- Base = Pubid::Iho::Identifier
72
- end
73
67
  end
74
68
  end
@@ -5,7 +5,7 @@ module Pubid
5
5
  module Identifiers
6
6
  # IHO Bibliographic Publication (B series).
7
7
  # Example: IHO B-4 2.19.0.
8
- class Bibliographic < Base
8
+ class Bibliographic < Identifier
9
9
  def self.type
10
10
  { key: :bibliographic, title: "Bibliographic Publication",
11
11
  short: "B" }
@@ -5,7 +5,7 @@ module Pubid
5
5
  module Identifiers
6
6
  # IHO Circular Letter (C series).
7
7
  # Example: IHO C-13 1.0.0.
8
- class CircularLetter < Base
8
+ class CircularLetter < Identifier
9
9
  def self.type
10
10
  { key: :circular_letter, title: "Circular Letter", short: "C" }
11
11
  end
@@ -5,7 +5,7 @@ module Pubid
5
5
  module Identifiers
6
6
  # IHO Miscellaneous Publication (M series).
7
7
  # Example: IHO M-3 2.0.0.
8
- class Miscellaneous < Base
8
+ class Miscellaneous < Identifier
9
9
  def self.type
10
10
  { key: :miscellaneous, title: "Miscellaneous Publication",
11
11
  short: "M" }
@@ -5,7 +5,7 @@ module Pubid
5
5
  module Identifiers
6
6
  # IHO Publication (P series).
7
7
  # Examples: IHO P-1 1.0.0, IHO P-1/21 1.0.0, IHO P-6-3 1.0.0.
8
- class Publication < Base
8
+ class Publication < Identifier
9
9
  def self.type
10
10
  { key: :publication, title: "Publication", short: "P" }
11
11
  end
@@ -5,7 +5,7 @@ module Pubid
5
5
  module Identifiers
6
6
  # IHO Standards and Specifications (S series).
7
7
  # Examples: IHO S-44 5.0.0, IHO S-100 Part 4a 1.0.0, IHO S-65 Ap. A 1.0.0.
8
- class Standard < Base
8
+ class Standard < Identifier
9
9
  def self.type
10
10
  { key: :standard, title: "Standards and Specifications", short: "S" }
11
11
  end
@@ -3,7 +3,6 @@
3
3
  module Pubid
4
4
  module Iho
5
5
  module Identifiers
6
- autoload :Base, "#{__dir__}/identifiers/base"
7
6
  autoload :Bibliographic, "#{__dir__}/identifiers/bibliographic"
8
7
  autoload :CircularLetter, "#{__dir__}/identifiers/circular_letter"
9
8
  autoload :Miscellaneous, "#{__dir__}/identifiers/miscellaneous"
data/lib/pubid/iho.rb CHANGED
@@ -8,7 +8,7 @@ module Pubid
8
8
  PREFIXES = ["IHO"].freeze
9
9
 
10
10
  autoload :Builder, "#{__dir__}/iho/builder"
11
- autoload :Identifier, "#{__dir__}/iho/identifier"
11
+ autoload :Identifier, "#{__dir__}/iho/identifiers/base"
12
12
  autoload :Identifiers, "#{__dir__}/iho/identifiers"
13
13
  autoload :Parser, "#{__dir__}/iho/parser"
14
14
  autoload :Renderer, "#{__dir__}/iho/renderer"
@@ -17,14 +17,14 @@ module Pubid
17
17
 
18
18
  # Parse an IHO identifier string into an identifier object
19
19
  # @param identifier [String] The IHO identifier string to parse
20
- # @return [Pubid::Iho::Identifiers::Base] The appropriate identifier object
20
+ # @return [Pubid::Iho::Identifier] The appropriate identifier object
21
21
  def self.parse(identifier)
22
22
  Identifier.parse(identifier)
23
23
  end
24
24
 
25
25
  # Per-flavor format registry: inherits global formats, overrides :human
26
- Identifiers::Base.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
27
- Identifiers::Base.format_registry.register(:human, renderer: Iho::Renderer)
26
+ Identifier.format_registry = FormatRegistry.new(parent: ::Pubid::Identifier.format_registry)
27
+ Identifier.format_registry.register(:human, renderer: Iho::Renderer)
28
28
 
29
29
  # Auto-discover all identifier types from the Identifiers namespace.
30
30
  # @return [Array<Class>] identifier classes (Pubid::Identifier subclasses)
@@ -32,9 +32,9 @@ module Pubid
32
32
  @identifier_types ||= Identifiers.constants
33
33
  .filter_map { |c| begin; Identifiers.const_get(c); rescue NameError; nil; end }
34
34
  .select { |c| c.is_a?(Class) && c < Pubid::Identifier }
35
- # Exclude the flavor base itself by identity (Identifiers::Base is now an
35
+ # Exclude the flavor base itself by identity (Identifier is now an
36
36
  # alias for Pubid::Iho::Identifier, so name-based matching misses it).
37
- .reject { |c| c == Identifiers::Base }
37
+ .reject { |c| c == Identifier }
38
38
  end
39
39
 
40
40
  # Build typed stage index from identifier types
@@ -66,7 +66,7 @@ module Pubid
66
66
 
67
67
  # Look up an identifier class by its IHO series letter (S/P/M/B/C).
68
68
  # @param letter [String]
69
- # @return [Class<Identifiers::Base>]
69
+ # @return [Class<Identifier>]
70
70
  def self.identifier_klass_for_type_letter(letter)
71
71
  @by_letter ||= identifier_types.to_h { |klass| [klass.type[:short], klass] }
72
72
  @by_letter.fetch(letter.to_s)
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Isbn
5
+ # Builds a Pubid::Isbn::Identifier from a parse tree.
6
+ #
7
+ # Validates the check digit; raises if invalid. Stores both the
8
+ # hyphenated form (for round-trip rendering) and the bare digits
9
+ # (for queries).
10
+ class Builder
11
+ INVALID_LENGTH = /^(?:\d{9}[\dX]|\d{13})$/.freeze
12
+
13
+ def self.build(parsed_data)
14
+ new.build(parsed_data)
15
+ end
16
+
17
+ def build(data)
18
+ hyphenated = data[:body].to_s
19
+ raw = hyphenated.delete("-")
20
+
21
+ validate_length!(raw)
22
+ validate_check_digit!(raw)
23
+
24
+ Identifiers::Book.new(raw: raw, hyphenated: hyphenated.include?("-") ? hyphenated : nil)
25
+ end
26
+
27
+ private
28
+
29
+ def validate_length!(raw)
30
+ return if raw.match?(INVALID_LENGTH)
31
+
32
+ raise ArgumentError,
33
+ "ISBN must be 10 or 13 digits (got #{raw.length})"
34
+ end
35
+
36
+ def validate_check_digit!(raw)
37
+ return if CheckDigit.valid?(raw)
38
+
39
+ raise ArgumentError,
40
+ "ISBN check digit invalid for #{raw}"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Isbn
5
+ # Pure-functional check digit math for ISBN-10 and ISBN-13 per ISO 2108.
6
+ #
7
+ # ISBN-10: weighted sum with weights 10..1, mod 11. Check digit 10 is
8
+ # rendered as "X".
9
+ # ISBN-13: weighted sum with alternating weights 1/3, mod 10. Check digit
10
+ # is 0-9.
11
+ class CheckDigit
12
+ # Compute the correct ISBN-10 check digit for a 9-digit payload.
13
+ # @return [String] "0".."9" or "X"
14
+ def self.compute_isbn10(payload)
15
+ raise ArgumentError, "ISBN-10 payload must be 9 digits" unless payload.to_s.match?(/\A\d{9}\z/)
16
+
17
+ sum = payload.to_s.each_char.with_index.sum { |c, i| c.to_i * (10 - i) }
18
+ digit = (11 - sum % 11) % 11
19
+ digit == 10 ? "X" : digit.to_s
20
+ end
21
+
22
+ # Compute the correct ISBN-13 check digit for a 12-digit payload.
23
+ # @return [String] "0".."9"
24
+ def self.compute_isbn13(payload)
25
+ raise ArgumentError, "ISBN-13 payload must be 12 digits" unless payload.to_s.match?(/\A\d{12}\z/)
26
+
27
+ sum = payload.to_s.each_char.with_index.sum do |c, i|
28
+ c.to_i * (i.even? ? 1 : 3)
29
+ end
30
+ ((10 - sum % 10) % 10).to_s
31
+ end
32
+
33
+ # Verify the check digit on a full 10- or 13-digit ISBN string.
34
+ # @param full [String] 10 or 13 chars; ISBN-10 may end with X.
35
+ # @return [Boolean]
36
+ def self.valid?(full)
37
+ digits = full.to_s.upcase.delete("^0-9X")
38
+ case digits.length
39
+ when 10
40
+ payload = digits[0, 9]
41
+ actual = digits[9]
42
+ compute_isbn10(payload) == actual
43
+ when 13
44
+ payload = digits[0, 12]
45
+ actual = digits[12]
46
+ compute_isbn13(payload) == actual
47
+ else
48
+ false
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Isbn
5
+ class Identifier < ::Pubid::Identifier
6
+ # The digits-only ISBN (no hyphens), including check digit. 10 or 13 chars.
7
+ attribute :raw, :string
8
+
9
+ # Original hyphenated form (may be nil when the input had no hyphens).
10
+ # Preserved for round-trip rendering; not queryable semantics.
11
+ attribute :hyphenated, :string
12
+
13
+ ISBN_TYPE_MAP = {
14
+ "pubid:isbn:book" => "Pubid::Isbn::Identifiers::Book",
15
+ }.freeze
16
+
17
+ key_value do
18
+ map "_type", to: :_type, polymorphic_map: ISBN_TYPE_MAP
19
+ map "raw", to: :raw
20
+ map "hyphenated", to: :hyphenated
21
+ end
22
+
23
+ PUBLISHER = "ISBN"
24
+
25
+ # Returns :isbn10 or :isbn13.
26
+ def form
27
+ case raw.to_s.length
28
+ when 10 then :isbn10
29
+ when 13 then :isbn13
30
+ else raise "Invalid ISBN length: #{raw.inspect}"
31
+ end
32
+ end
33
+
34
+ def check_digit
35
+ raw.to_s[-1]
36
+ end
37
+
38
+ def valid?
39
+ CheckDigit.valid?(raw)
40
+ end
41
+
42
+ def to_s(**opts)
43
+ render(format: :human, **opts)
44
+ end
45
+
46
+ def self.parse(identifier)
47
+ if identifier.length > Pubid::MAX_INPUT_LENGTH
48
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
49
+ end
50
+
51
+ parsed = Parser.parse(identifier)
52
+ Builder.build(parsed)
53
+ rescue Parslet::ParseFailed => e
54
+ raise "Failed to parse ISBN '#{identifier}': #{e.message}"
55
+ rescue ArgumentError => e
56
+ # Builder validates length/check-digit; surface as a parse error so
57
+ # the error contract matches other flavors (always raises a string
58
+ # beginning with "Failed to parse").
59
+ raise "Failed to parse ISBN '#{identifier}': #{e.message}"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Isbn
5
+ module Identifiers
6
+ # ISBN book identifier — supports both ISBN-10 and ISBN-13.
7
+ #
8
+ # Examples:
9
+ # ISBN 978-3-16-148410-0
10
+ # ISBN 0-306-40615-2
11
+ # 9783161484100
12
+ class Book < Identifier
13
+ TYPED_STAGES = [
14
+ Pubid::Components::TypedStage.new(
15
+ code: :pubisbn,
16
+ stage_code: :published,
17
+ type_code: :isbn,
18
+ abbr: ["ISBN"],
19
+ name: "ISBN",
20
+ harmonized_stages: [],
21
+ ),
22
+ ].freeze
23
+
24
+ def self.type
25
+ { key: :isbn, web: :book, title: "ISBN", short: "ISBN" }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Isbn
5
+ module Identifiers
6
+ autoload :Book, "#{__dir__}/identifiers/book"
7
+ end
8
+ end
9
+ end