pubid 2.0.0.pre.alpha.8 → 2.0.0.pre.alpha.11

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 (672) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +33 -11
  3. data/conformance/pending.yaml +4 -0
  4. data/data/bipm/update_codes.yaml +9 -0
  5. data/data/iec/update_codes.yaml +3 -0
  6. data/data/ieee/update_codes.yaml +107 -1
  7. data/{archived-gems/pubid-nist → data/nist}/series.yaml +34 -0
  8. data/data/nist/update_codes.yaml +8 -0
  9. data/lib/pubid/adobe/builder.rb +52 -0
  10. data/lib/pubid/adobe/identifier.rb +47 -0
  11. data/lib/pubid/adobe/identifiers/publication.rb +31 -0
  12. data/lib/pubid/adobe/identifiers/tech_note.rb +32 -0
  13. data/lib/pubid/adobe/identifiers.rb +10 -0
  14. data/lib/pubid/adobe/parser.rb +136 -0
  15. data/lib/pubid/adobe/renderer.rb +39 -0
  16. data/lib/pubid/adobe/urn_generator.rb +42 -0
  17. data/lib/pubid/adobe/urn_parser.rb +69 -0
  18. data/lib/pubid/adobe.rb +61 -0
  19. data/lib/pubid/amca/builder.rb +4 -4
  20. data/lib/pubid/amca/identifier.rb +1 -3
  21. data/lib/pubid/amca/identifiers/base.rb +50 -33
  22. data/lib/pubid/amca/identifiers/interpretation.rb +18 -10
  23. data/lib/pubid/amca/identifiers/publication.rb +14 -10
  24. data/lib/pubid/amca/identifiers/standard.rb +3 -1
  25. data/lib/pubid/amca/identifiers.rb +0 -1
  26. data/lib/pubid/amca/parser.rb +1 -1
  27. data/lib/pubid/amca/renderer.rb +4 -4
  28. data/lib/pubid/amca/single_identifier.rb +1 -1
  29. data/lib/pubid/amca/urn_generator.rb +2 -2
  30. data/lib/pubid/amca.rb +5 -4
  31. data/lib/pubid/ansi/builder.rb +2 -2
  32. data/lib/pubid/ansi/identifier.rb +18 -0
  33. data/lib/pubid/ansi/parser.rb +1 -1
  34. data/lib/pubid/ansi/renderer.rb +2 -2
  35. data/lib/pubid/ansi.rb +5 -5
  36. data/lib/pubid/api/builder.rb +16 -2
  37. data/lib/pubid/api/identifier.rb +25 -4
  38. data/lib/pubid/api/identifiers/mpms.rb +10 -8
  39. data/lib/pubid/api/parser.rb +1 -1
  40. data/lib/pubid/api/renderer.rb +16 -7
  41. data/lib/pubid/api/single_identifier.rb +5 -12
  42. data/lib/pubid/api.rb +1 -0
  43. data/lib/pubid/ashrae/builder.rb +53 -32
  44. data/lib/pubid/ashrae/identifier.rb +3 -4
  45. data/lib/pubid/ashrae/identifiers/addenda_package.rb +7 -1
  46. data/lib/pubid/ashrae/identifiers/addendum.rb +9 -1
  47. data/lib/pubid/ashrae/identifiers/base.rb +94 -12
  48. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +8 -1
  49. data/lib/pubid/ashrae/identifiers/errata.rb +9 -0
  50. data/lib/pubid/ashrae/identifiers/guideline.rb +3 -0
  51. data/lib/pubid/ashrae/identifiers/interpretation.rb +16 -0
  52. data/lib/pubid/ashrae/identifiers/standard.rb +3 -0
  53. data/lib/pubid/ashrae/identifiers.rb +0 -1
  54. data/lib/pubid/ashrae/parser.rb +37 -17
  55. data/lib/pubid/ashrae/renderer.rb +20 -20
  56. data/lib/pubid/ashrae/single_identifier.rb +1 -1
  57. data/lib/pubid/ashrae/supplement_identifier.rb +21 -6
  58. data/lib/pubid/ashrae/urn_generator.rb +8 -2
  59. data/lib/pubid/ashrae.rb +10 -4
  60. data/lib/pubid/asme/builder.rb +11 -2
  61. data/lib/pubid/asme/identifier.rb +9 -0
  62. data/lib/pubid/asme/identifiers/standard.rb +86 -2
  63. data/lib/pubid/asme/parser.rb +1 -1
  64. data/lib/pubid/asme/renderer.rb +3 -3
  65. data/lib/pubid/asme/single_identifier.rb +8 -1
  66. data/lib/pubid/asme/urn_generator.rb +2 -2
  67. data/lib/pubid/asme.rb +1 -0
  68. data/lib/pubid/astm/builder.rb +10 -3
  69. data/lib/pubid/astm/identifier.rb +9 -0
  70. data/lib/pubid/astm/identifiers/adjunct.rb +16 -1
  71. data/lib/pubid/astm/identifiers/code_number.rb +81 -0
  72. data/lib/pubid/astm/identifiers/data_series.rb +2 -0
  73. data/lib/pubid/astm/identifiers/iso_dual_published.rb +16 -0
  74. data/lib/pubid/astm/identifiers/manual.rb +10 -0
  75. data/lib/pubid/astm/identifiers/monograph.rb +2 -0
  76. data/lib/pubid/astm/identifiers/research_report.rb +10 -0
  77. data/lib/pubid/astm/identifiers/standard.rb +10 -0
  78. data/lib/pubid/astm/identifiers/technical_report.rb +2 -0
  79. data/lib/pubid/astm/identifiers/work_in_progress.rb +2 -0
  80. data/lib/pubid/astm/identifiers.rb +1 -0
  81. data/lib/pubid/astm/parser.rb +1 -1
  82. data/lib/pubid/astm/renderer.rb +1 -1
  83. data/lib/pubid/astm/single_identifier.rb +31 -1
  84. data/lib/pubid/astm/urn_generator.rb +7 -5
  85. data/lib/pubid/astm.rb +1 -0
  86. data/lib/pubid/bipm/builder.rb +163 -0
  87. data/lib/pubid/bipm/identifier.rb +285 -0
  88. data/lib/pubid/bipm/identifiers/committee_document.rb +36 -0
  89. data/lib/pubid/bipm/identifiers/guide.rb +35 -0
  90. data/lib/pubid/bipm/identifiers/meeting.rb +53 -0
  91. data/lib/pubid/bipm/identifiers/mep.rb +33 -0
  92. data/lib/pubid/bipm/identifiers/metrologia_article.rb +48 -0
  93. data/lib/pubid/bipm/identifiers/si_brochure.rb +33 -0
  94. data/lib/pubid/bipm/identifiers.rb +15 -0
  95. data/lib/pubid/bipm/parser.rb +237 -0
  96. data/lib/pubid/bipm/renderer.rb +118 -0
  97. data/lib/pubid/bipm/urn_generator.rb +58 -0
  98. data/lib/pubid/bipm/urn_parser.rb +60 -0
  99. data/lib/pubid/bipm.rb +92 -0
  100. data/lib/pubid/bsi/builder.rb +62 -52
  101. data/lib/pubid/bsi/identifier.rb +0 -1
  102. data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -2
  103. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +36 -7
  104. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +7 -6
  105. data/lib/pubid/bsi/identifiers/amendment.rb +4 -4
  106. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +0 -1
  107. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +10 -0
  108. data/lib/pubid/bsi/identifiers/committee_document.rb +10 -1
  109. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +6 -0
  110. data/lib/pubid/bsi/identifiers/corrigendum.rb +4 -4
  111. data/lib/pubid/bsi/identifiers/expert_commentary.rb +5 -5
  112. data/lib/pubid/bsi/identifiers/handbook.rb +0 -2
  113. data/lib/pubid/bsi/identifiers/practice_guide.rb +0 -1
  114. data/lib/pubid/bsi/identifiers/set.rb +11 -0
  115. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +10 -1
  116. data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -2
  117. data/lib/pubid/bsi/identifiers/value_added_publication.rb +6 -6
  118. data/lib/pubid/bsi/parser.rb +1 -1
  119. data/lib/pubid/bsi/renderer.rb +71 -59
  120. data/lib/pubid/bsi/single_identifier.rb +64 -7
  121. data/lib/pubid/bsi/urn_generator.rb +11 -2
  122. data/lib/pubid/bsi.rb +7 -1
  123. data/lib/pubid/builder/base.rb +23 -11
  124. data/lib/pubid/bundled_identifier.rb +19 -9
  125. data/lib/pubid/calconnect/builder.rb +38 -0
  126. data/lib/pubid/calconnect/identifier.rb +121 -0
  127. data/lib/pubid/calconnect/identifiers/standard.rb +29 -0
  128. data/lib/pubid/calconnect/identifiers.rb +9 -0
  129. data/lib/pubid/calconnect/parser.rb +54 -0
  130. data/lib/pubid/calconnect/renderer.rb +36 -0
  131. data/lib/pubid/calconnect/urn_generator.rb +33 -0
  132. data/lib/pubid/calconnect/urn_parser.rb +34 -0
  133. data/lib/pubid/calconnect.rb +83 -0
  134. data/lib/pubid/ccsds/builder.rb +1 -1
  135. data/lib/pubid/ccsds/identifier.rb +10 -3
  136. data/lib/pubid/ccsds/identifiers/base.rb +4 -2
  137. data/lib/pubid/ccsds/identifiers/corrigendum.rb +4 -4
  138. data/lib/pubid/ccsds/parser.rb +1 -1
  139. data/lib/pubid/ccsds/single_identifier.rb +2 -2
  140. data/lib/pubid/ccsds/supplement_identifier.rb +6 -6
  141. data/lib/pubid/ccsds/urn_generator.rb +3 -3
  142. data/lib/pubid/ccsds.rb +1 -0
  143. data/lib/pubid/cen_cenelec/builder.rb +131 -72
  144. data/lib/pubid/cen_cenelec/identifier.rb +115 -3
  145. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +27 -16
  146. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +46 -6
  147. data/lib/pubid/cen_cenelec/identifiers/base.rb +8 -9
  148. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +1 -1
  149. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +1 -1
  150. data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +1 -1
  151. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +29 -14
  152. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +47 -8
  153. data/lib/pubid/cen_cenelec/identifiers/european_norm.rb +60 -3
  154. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +27 -2
  155. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +1 -1
  156. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +15 -5
  157. data/lib/pubid/cen_cenelec/identifiers/guide.rb +1 -1
  158. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +1 -1
  159. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +1 -1
  160. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +1 -1
  161. data/lib/pubid/cen_cenelec/parser.rb +1 -1
  162. data/lib/pubid/cen_cenelec/renderer.rb +55 -60
  163. data/lib/pubid/cen_cenelec/single_identifier.rb +20 -2
  164. data/lib/pubid/cen_cenelec/urn_generator.rb +66 -44
  165. data/lib/pubid/cen_cenelec.rb +104 -82
  166. data/lib/pubid/cie/builder.rb +149 -24
  167. data/lib/pubid/cie/identifier.rb +13 -4
  168. data/lib/pubid/cie/identifiers/bundle.rb +35 -5
  169. data/lib/pubid/cie/identifiers/code_attributes.rb +52 -0
  170. data/lib/pubid/cie/identifiers/conference.rb +11 -6
  171. data/lib/pubid/cie/identifiers/corrigendum.rb +17 -23
  172. data/lib/pubid/cie/identifiers/dual_published.rb +6 -6
  173. data/lib/pubid/cie/identifiers/identical.rb +9 -9
  174. data/lib/pubid/cie/identifiers/joint_published.rb +10 -10
  175. data/lib/pubid/cie/identifiers/proceedings.rb +41 -0
  176. data/lib/pubid/cie/identifiers/standard.rb +43 -8
  177. data/lib/pubid/cie/identifiers/supplement.rb +27 -25
  178. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +7 -3
  179. data/lib/pubid/cie/identifiers.rb +2 -0
  180. data/lib/pubid/cie/parser.rb +55 -6
  181. data/lib/pubid/cie/single_identifier.rb +40 -1
  182. data/lib/pubid/cie/supplement_identifier.rb +29 -16
  183. data/lib/pubid/cie/urn_generator.rb +11 -8
  184. data/lib/pubid/cie.rb +7 -2
  185. data/lib/pubid/components/date.rb +21 -5
  186. data/lib/pubid/conformance/checks.rb +72 -0
  187. data/lib/pubid/conformance/corpus/case.rb +55 -0
  188. data/lib/pubid/conformance/corpus.rb +36 -0
  189. data/lib/pubid/conformance/generator.rb +212 -0
  190. data/lib/pubid/conformance/pending.rb +63 -0
  191. data/lib/pubid/conformance/runner.rb +153 -0
  192. data/lib/pubid/conformance.rb +55 -0
  193. data/lib/pubid/core.rb +2 -0
  194. data/lib/pubid/csa/builder.rb +48 -48
  195. data/lib/pubid/csa/composite_identifier.rb +18 -7
  196. data/lib/pubid/csa/identifier.rb +187 -80
  197. data/lib/pubid/csa/identifiers/bundled.rb +25 -9
  198. data/lib/pubid/csa/identifiers/canadian_adopted.rb +13 -13
  199. data/lib/pubid/csa/identifiers/cec.rb +44 -4
  200. data/lib/pubid/csa/identifiers/combined.rb +97 -69
  201. data/lib/pubid/csa/identifiers/csa_adopted.rb +4 -4
  202. data/lib/pubid/csa/identifiers/package.rb +4 -4
  203. data/lib/pubid/csa/parser.rb +12 -8
  204. data/lib/pubid/csa/renderer.rb +13 -5
  205. data/lib/pubid/csa/single_identifier.rb +93 -4
  206. data/lib/pubid/csa/urn_generator.rb +9 -2
  207. data/lib/pubid/csa/wrapper_identifier.rb +43 -10
  208. data/lib/pubid/csa.rb +7 -1
  209. data/lib/pubid/doi/builder.rb +18 -0
  210. data/lib/pubid/doi/identifier.rb +49 -0
  211. data/lib/pubid/doi/identifiers/resource.rb +30 -0
  212. data/lib/pubid/doi/identifiers.rb +9 -0
  213. data/lib/pubid/doi/parser.rb +52 -0
  214. data/lib/pubid/doi/renderer.rb +13 -0
  215. data/lib/pubid/doi.rb +56 -0
  216. data/lib/pubid/easc/builder.rb +55 -0
  217. data/lib/pubid/easc/identifier.rb +59 -0
  218. data/lib/pubid/easc/identifiers/pmg.rb +20 -0
  219. data/lib/pubid/easc/identifiers/rmg.rb +19 -0
  220. data/lib/pubid/easc/identifiers.rb +10 -0
  221. data/lib/pubid/easc/parser.rb +88 -0
  222. data/lib/pubid/easc/renderer.rb +48 -0
  223. data/lib/pubid/easc/urn_generator.rb +46 -0
  224. data/lib/pubid/easc/urn_parser.rb +57 -0
  225. data/lib/pubid/easc.rb +53 -0
  226. data/lib/pubid/ecma/builder.rb +45 -0
  227. data/lib/pubid/ecma/identifier.rb +147 -0
  228. data/lib/pubid/ecma/identifiers/memento.rb +30 -0
  229. data/lib/pubid/ecma/identifiers/standard.rb +31 -0
  230. data/lib/pubid/ecma/identifiers/technical_report.rb +31 -0
  231. data/lib/pubid/ecma/identifiers.rb +11 -0
  232. data/lib/pubid/ecma/parser.rb +76 -0
  233. data/lib/pubid/ecma/renderer.rb +67 -0
  234. data/lib/pubid/ecma/urn_generator.rb +46 -0
  235. data/lib/pubid/ecma/urn_parser.rb +51 -0
  236. data/lib/pubid/ecma.rb +68 -0
  237. data/lib/pubid/errors.rb +80 -0
  238. data/lib/pubid/etsi/builder.rb +13 -4
  239. data/lib/pubid/etsi/identifier.rb +1 -3
  240. data/lib/pubid/etsi/identifiers/base.rb +43 -11
  241. data/lib/pubid/etsi/identifiers/etsi_standard.rb +207 -4
  242. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +45 -3
  243. data/lib/pubid/etsi/identifiers.rb +0 -1
  244. data/lib/pubid/etsi/parser.rb +9 -3
  245. data/lib/pubid/etsi/renderer.rb +8 -2
  246. data/lib/pubid/etsi.rb +6 -5
  247. data/lib/pubid/evs/builder.rb +26 -0
  248. data/lib/pubid/evs/identifier.rb +37 -0
  249. data/lib/pubid/evs/identifiers/national_adoption.rb +17 -0
  250. data/lib/pubid/evs/identifiers.rb +9 -0
  251. data/lib/pubid/evs/parser.rb +27 -0
  252. data/lib/pubid/evs/renderer.rb +30 -0
  253. data/lib/pubid/evs/urn_generator.rb +30 -0
  254. data/lib/pubid/evs/urn_parser.rb +80 -0
  255. data/lib/pubid/evs.rb +90 -0
  256. data/lib/pubid/export/exporter.rb +2 -1
  257. data/lib/pubid/export/flavor_exporter.rb +18 -3
  258. data/lib/pubid/export.rb +1 -0
  259. data/lib/pubid/format_detector.rb +1 -0
  260. data/lib/pubid/gb/builder.rb +45 -0
  261. data/lib/pubid/gb/identifier.rb +67 -0
  262. data/lib/pubid/gb/identifiers/standard.rb +34 -0
  263. data/lib/pubid/gb/identifiers.rb +9 -0
  264. data/lib/pubid/gb/parser.rb +63 -0
  265. data/lib/pubid/gb/renderer.rb +35 -0
  266. data/lib/pubid/gb.rb +88 -0
  267. data/lib/pubid/gost/builder.rb +185 -0
  268. data/lib/pubid/gost/identifier.rb +47 -0
  269. data/lib/pubid/gost/identifiers/foreign_reference.rb +25 -0
  270. data/lib/pubid/gost/identifiers/harmonized.rb +39 -0
  271. data/lib/pubid/gost/identifiers/identical_adoption.rb +39 -0
  272. data/lib/pubid/gost/identifiers/interstate_standard.rb +20 -0
  273. data/lib/pubid/gost/identifiers/national_standard.rb +19 -0
  274. data/lib/pubid/gost/identifiers.rb +13 -0
  275. data/lib/pubid/gost/parser.rb +105 -0
  276. data/lib/pubid/gost/renderer.rb +48 -0
  277. data/lib/pubid/gost/urn_generator.rb +46 -0
  278. data/lib/pubid/gost/urn_parser.rb +52 -0
  279. data/lib/pubid/gost.rb +50 -0
  280. data/lib/pubid/iala/builder.rb +22 -27
  281. data/lib/pubid/iala/identifier.rb +36 -8
  282. data/lib/pubid/iala/identifiers/advice.rb +1 -1
  283. data/lib/pubid/iala/identifiers/annex.rb +10 -10
  284. data/lib/pubid/iala/identifiers/general_assembly.rb +5 -2
  285. data/lib/pubid/iala/identifiers/guideline.rb +3 -1
  286. data/lib/pubid/iala/identifiers/letter.rb +1 -1
  287. data/lib/pubid/iala/identifiers/manual.rb +3 -1
  288. data/lib/pubid/iala/identifiers/model_course.rb +3 -1
  289. data/lib/pubid/iala/identifiers/recommendation.rb +3 -1
  290. data/lib/pubid/iala/identifiers/report.rb +1 -1
  291. data/lib/pubid/iala/identifiers/resolution.rb +1 -1
  292. data/lib/pubid/iala/identifiers/standard.rb +3 -1
  293. data/lib/pubid/iala/identifiers.rb +0 -1
  294. data/lib/pubid/iala/parser.rb +10 -2
  295. data/lib/pubid/iala/renderer.rb +1 -1
  296. data/lib/pubid/iala/urn_generator.rb +1 -1
  297. data/lib/pubid/iala/urn_parser.rb +24 -3
  298. data/lib/pubid/iala.rb +5 -4
  299. data/lib/pubid/iana/builder.rb +22 -0
  300. data/lib/pubid/iana/identifier.rb +140 -0
  301. data/lib/pubid/iana/identifiers/registry.rb +69 -0
  302. data/lib/pubid/iana/identifiers.rb +9 -0
  303. data/lib/pubid/iana/parser.rb +38 -0
  304. data/lib/pubid/iana/renderer.rb +32 -0
  305. data/lib/pubid/iana/urn_generator.rb +19 -0
  306. data/lib/pubid/iana/urn_parser.rb +24 -0
  307. data/lib/pubid/iana.rb +70 -0
  308. data/lib/pubid/identifier.rb +797 -26
  309. data/lib/pubid/identifier_metadata.rb +1 -0
  310. data/lib/pubid/idf/builder.rb +4 -4
  311. data/lib/pubid/idf/identifier.rb +18 -9
  312. data/lib/pubid/idf/parser.rb +3 -3
  313. data/lib/pubid/idf/renderer.rb +5 -5
  314. data/lib/pubid/idf/supplement_identifier.rb +3 -3
  315. data/lib/pubid/idf/urn_generator.rb +1 -1
  316. data/lib/pubid/idf.rb +7 -1
  317. data/lib/pubid/iec/builder.rb +49 -32
  318. data/lib/pubid/iec/components.rb +0 -1
  319. data/lib/pubid/iec/identifier.rb +112 -77
  320. data/lib/pubid/iec/identifiers/amendment.rb +6 -2
  321. data/lib/pubid/iec/identifiers/base.rb +2 -2
  322. data/lib/pubid/iec/identifiers/component_specification.rb +0 -10
  323. data/lib/pubid/iec/identifiers/conformity_assessment.rb +0 -10
  324. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +6 -0
  325. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -2
  326. data/lib/pubid/iec/identifiers/fragment_identifier.rb +13 -15
  327. data/lib/pubid/iec/identifiers/guide.rb +0 -16
  328. data/lib/pubid/iec/identifiers/international_standard.rb +22 -6
  329. data/lib/pubid/iec/identifiers/operational_document.rb +0 -10
  330. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +0 -12
  331. data/lib/pubid/iec/identifiers/sheet_identifier.rb +12 -12
  332. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +0 -10
  333. data/lib/pubid/iec/identifiers/systems_reference_document.rb +0 -10
  334. data/lib/pubid/iec/identifiers/technical_group.rb +30 -0
  335. data/lib/pubid/iec/identifiers/technical_report.rb +1 -18
  336. data/lib/pubid/iec/identifiers/technical_specification.rb +1 -18
  337. data/lib/pubid/iec/identifiers/technology_report.rb +0 -10
  338. data/lib/pubid/iec/identifiers/test_report_form.rb +0 -11
  339. data/lib/pubid/iec/identifiers/vap_identifier.rb +12 -12
  340. data/lib/pubid/iec/identifiers/white_paper.rb +0 -10
  341. data/lib/pubid/iec/identifiers/working_document.rb +24 -10
  342. data/lib/pubid/iec/identifiers.rb +1 -0
  343. data/lib/pubid/iec/parser.rb +53 -28
  344. data/lib/pubid/iec/renderer.rb +31 -18
  345. data/lib/pubid/iec/single_identifier.rb +34 -11
  346. data/lib/pubid/iec/supplement_identifier.rb +32 -19
  347. data/lib/pubid/iec/urn_generator.rb +227 -61
  348. data/lib/pubid/iec/urn_parser.rb +42 -4
  349. data/lib/pubid/iec.rb +2 -6
  350. data/lib/pubid/ieee/aiee/builder.rb +17 -3
  351. data/lib/pubid/ieee/aiee/identifier.rb +46 -62
  352. data/lib/pubid/ieee/aiee/parser.rb +1 -1
  353. data/lib/pubid/ieee/builder.rb +386 -69
  354. data/lib/pubid/ieee/compaction.rb +121 -0
  355. data/lib/pubid/ieee/components/draft.rb +47 -7
  356. data/lib/pubid/ieee/identifier.rb +1 -3
  357. data/lib/pubid/ieee/identifiers/adopted_standard.rb +62 -5
  358. data/lib/pubid/ieee/identifiers/amendment.rb +40 -0
  359. data/lib/pubid/ieee/identifiers/base.rb +148 -18
  360. data/lib/pubid/ieee/identifiers/code_number.rb +82 -0
  361. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +6 -2
  362. data/lib/pubid/ieee/identifiers/corrigendum.rb +17 -2
  363. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +24 -3
  364. data/lib/pubid/ieee/identifiers/dual_identifier.rb +3 -3
  365. data/lib/pubid/ieee/identifiers/dual_published.rb +58 -3
  366. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +102 -5
  367. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +25 -1
  368. data/lib/pubid/ieee/identifiers/joint_development.rb +64 -15
  369. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +58 -6
  370. data/lib/pubid/ieee/identifiers/nesc/base.rb +90 -19
  371. data/lib/pubid/ieee/identifiers/nesc/draft.rb +20 -5
  372. data/lib/pubid/ieee/identifiers/nesc/edition.rb +32 -0
  373. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +16 -5
  374. data/lib/pubid/ieee/identifiers/nesc/redline.rb +11 -2
  375. data/lib/pubid/ieee/identifiers/nesc/standard.rb +18 -3
  376. data/lib/pubid/ieee/identifiers/nesc.rb +1 -0
  377. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +3 -3
  378. data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +14 -6
  379. data/lib/pubid/ieee/identifiers/redlined_standard.rb +4 -4
  380. data/lib/pubid/ieee/identifiers/si_standard.rb +4 -1
  381. data/lib/pubid/ieee/identifiers/standard.rb +4 -1
  382. data/lib/pubid/ieee/identifiers/supplement_identifier.rb +26 -7
  383. data/lib/pubid/ieee/identifiers.rb +2 -1
  384. data/lib/pubid/ieee/ire/builder.rb +7 -6
  385. data/lib/pubid/ieee/ire/identifier.rb +48 -33
  386. data/lib/pubid/ieee/ire/parser.rb +1 -1
  387. data/lib/pubid/ieee/nesc/builder.rb +33 -20
  388. data/lib/pubid/ieee/nesc/parser.rb +16 -15
  389. data/lib/pubid/ieee/parser.rb +462 -44
  390. data/lib/pubid/ieee/pre_parser.rb +1 -1
  391. data/lib/pubid/ieee/renderer.rb +158 -57
  392. data/lib/pubid/ieee/typed_stages.rb +12 -1
  393. data/lib/pubid/ieee/urn_generator.rb +35 -8
  394. data/lib/pubid/ieee.rb +63 -4
  395. data/lib/pubid/ieee_debug.rb +1 -0
  396. data/lib/pubid/ietf/builder.rb +78 -0
  397. data/lib/pubid/ietf/identifier.rb +5 -0
  398. data/lib/pubid/ietf/identifiers/base.rb +72 -0
  399. data/lib/pubid/ietf/identifiers/bcp.rb +36 -0
  400. data/lib/pubid/ietf/identifiers/fyi.rb +36 -0
  401. data/lib/pubid/ietf/identifiers/internet_draft.rb +45 -0
  402. data/lib/pubid/ietf/identifiers/rfc.rb +27 -0
  403. data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
  404. data/lib/pubid/ietf/identifiers/std.rb +36 -0
  405. data/lib/pubid/ietf/identifiers.rb +14 -0
  406. data/lib/pubid/ietf/parser.rb +61 -0
  407. data/lib/pubid/ietf/renderer.rb +64 -0
  408. data/lib/pubid/ietf/urn_generator.rb +37 -0
  409. data/lib/pubid/ietf/urn_parser.rb +43 -0
  410. data/lib/pubid/ietf.rb +86 -0
  411. data/lib/pubid/iho/identifier.rb +1 -3
  412. data/lib/pubid/iho/identifiers/base.rb +11 -10
  413. data/lib/pubid/iho/identifiers/bibliographic.rb +1 -1
  414. data/lib/pubid/iho/identifiers/circular_letter.rb +1 -1
  415. data/lib/pubid/iho/identifiers/miscellaneous.rb +1 -1
  416. data/lib/pubid/iho/identifiers/publication.rb +1 -1
  417. data/lib/pubid/iho/identifiers/standard.rb +1 -1
  418. data/lib/pubid/iho/identifiers.rb +0 -1
  419. data/lib/pubid/iho/parser.rb +1 -1
  420. data/lib/pubid/iho.rb +8 -7
  421. data/lib/pubid/isbn/builder.rb +44 -0
  422. data/lib/pubid/isbn/check_digit.rb +53 -0
  423. data/lib/pubid/isbn/identifier.rb +81 -0
  424. data/lib/pubid/isbn/identifiers/book.rb +30 -0
  425. data/lib/pubid/isbn/identifiers.rb +9 -0
  426. data/lib/pubid/isbn/parser.rb +45 -0
  427. data/lib/pubid/isbn/renderer.rb +16 -0
  428. data/lib/pubid/isbn.rb +53 -0
  429. data/lib/pubid/iso/builder.rb +9 -4
  430. data/lib/pubid/iso/bundled_identifier.rb +5 -3
  431. data/lib/pubid/iso/combined_identifier.rb +6 -4
  432. data/lib/pubid/iso/identifier.rb +29 -8
  433. data/lib/pubid/iso/identifiers/directives_supplement.rb +12 -12
  434. data/lib/pubid/iso/normalizer.rb +2 -2
  435. data/lib/pubid/iso/parser.rb +17 -13
  436. data/lib/pubid/iso/supplement_identifier.rb +19 -6
  437. data/lib/pubid/iso/urn_generator.rb +4 -1
  438. data/lib/pubid/iso/urn_parser.rb +1 -1
  439. data/lib/pubid/iso.rb +7 -1
  440. data/lib/pubid/itu/builder.rb +230 -29
  441. data/lib/pubid/itu/components/code.rb +48 -5
  442. data/lib/pubid/itu/components/designation.rb +35 -0
  443. data/lib/pubid/itu/components.rb +1 -0
  444. data/lib/pubid/itu/identifier.rb +1 -3
  445. data/lib/pubid/itu/identifiers/addendum.rb +15 -0
  446. data/lib/pubid/itu/identifiers/amendment.rb +7 -29
  447. data/lib/pubid/itu/identifiers/annex.rb +13 -2
  448. data/lib/pubid/itu/identifiers/annex_of_recommendation.rb +87 -0
  449. data/lib/pubid/itu/identifiers/appendix_of_recommendation.rb +92 -0
  450. data/lib/pubid/itu/identifiers/base.rb +357 -25
  451. data/lib/pubid/itu/identifiers/combined_identifier.rb +99 -23
  452. data/lib/pubid/itu/identifiers/corrigendum.rb +16 -23
  453. data/lib/pubid/itu/identifiers/errata.rb +15 -0
  454. data/lib/pubid/itu/identifiers/handbook.rb +38 -0
  455. data/lib/pubid/itu/identifiers/question.rb +63 -0
  456. data/lib/pubid/itu/identifiers/recommendation.rb +3 -2
  457. data/lib/pubid/itu/identifiers/report.rb +39 -0
  458. data/lib/pubid/itu/identifiers/special_publication.rb +3 -1
  459. data/lib/pubid/itu/identifiers/standard_serialization.rb +58 -0
  460. data/lib/pubid/itu/identifiers/supplement.rb +119 -14
  461. data/lib/pubid/itu/identifiers.rb +10 -1
  462. data/lib/pubid/itu/model.rb +1 -1
  463. data/lib/pubid/itu/parser.rb +481 -27
  464. data/lib/pubid/itu/urn_generator.rb +36 -6
  465. data/lib/pubid/itu/urn_parser.rb +8 -0
  466. data/lib/pubid/itu.rb +12 -3
  467. data/lib/pubid/jcgm/builder.rb +24 -14
  468. data/lib/pubid/jcgm/identifier.rb +10 -0
  469. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -2
  470. data/lib/pubid/jcgm/identifiers/corrigendum.rb +34 -0
  471. data/lib/pubid/jcgm/identifiers/gum_guide.rb +3 -3
  472. data/lib/pubid/jcgm/identifiers/meeting.rb +47 -0
  473. data/lib/pubid/jcgm/identifiers.rb +2 -0
  474. data/lib/pubid/jcgm/parser.rb +74 -7
  475. data/lib/pubid/jcgm/renderer.rb +33 -12
  476. data/lib/pubid/jcgm/single_identifier.rb +84 -6
  477. data/lib/pubid/jcgm/supplement_identifier.rb +39 -4
  478. data/lib/pubid/jcgm/urn_generator.rb +21 -13
  479. data/lib/pubid/jcgm/urn_parser.rb +164 -10
  480. data/lib/pubid/jcgm.rb +10 -0
  481. data/lib/pubid/jis/identifier.rb +62 -3
  482. data/lib/pubid/jis/parser.rb +1 -1
  483. data/lib/pubid/jis.rb +1 -0
  484. data/lib/pubid/nist/builder.rb +29 -9
  485. data/lib/pubid/nist/caster.rb +7 -45
  486. data/lib/pubid/nist/circular_supplement_builder.rb +7 -5
  487. data/lib/pubid/nist/components/stage.rb +2 -2
  488. data/lib/pubid/nist/components/supplement.rb +5 -2
  489. data/lib/pubid/nist/configuration.rb +6 -2
  490. data/lib/pubid/nist/identifier.rb +1 -3
  491. data/lib/pubid/nist/identifiers/base.rb +133 -39
  492. data/lib/pubid/nist/identifiers/circular.rb +10 -3
  493. data/lib/pubid/nist/identifiers/circular_supplement.rb +14 -5
  494. data/lib/pubid/nist/identifiers/commercial_standard.rb +1 -1
  495. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
  496. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +8 -2
  497. data/lib/pubid/nist/identifiers/crpl_report.rb +8 -2
  498. data/lib/pubid/nist/identifiers/dated_document.rb +1 -1
  499. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +1 -1
  500. data/lib/pubid/nist/identifiers/grant_contractor_report.rb +1 -1
  501. data/lib/pubid/nist/identifiers/handbook.rb +10 -3
  502. data/lib/pubid/nist/identifiers/internal_report.rb +13 -6
  503. data/lib/pubid/nist/identifiers/letter_circular.rb +1 -1
  504. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +15 -7
  505. data/lib/pubid/nist/identifiers/monograph.rb +15 -8
  506. data/lib/pubid/nist/identifiers/ncstar.rb +2 -2
  507. data/lib/pubid/nist/identifiers/nsrds.rb +1 -1
  508. data/lib/pubid/nist/identifiers/owmwp.rb +1 -1
  509. data/lib/pubid/nist/identifiers/report.rb +15 -7
  510. data/lib/pubid/nist/identifiers/special_publication.rb +10 -1
  511. data/lib/pubid/nist/identifiers/technical_note.rb +1 -1
  512. data/lib/pubid/nist/identifiers.rb +0 -1
  513. data/lib/pubid/nist/parser.rb +27 -4
  514. data/lib/pubid/nist/preprocessor.rb +15 -0
  515. data/lib/pubid/nist/router.rb +2 -2
  516. data/lib/pubid/nist/series/ir.rb +0 -3
  517. data/lib/pubid/nist/supplement_identifier.rb +24 -9
  518. data/lib/pubid/nist.rb +19 -13
  519. data/lib/pubid/oasis/builder.rb +79 -0
  520. data/lib/pubid/oasis/identifier.rb +160 -0
  521. data/lib/pubid/oasis/identifiers/standard.rb +29 -0
  522. data/lib/pubid/oasis/identifiers.rb +9 -0
  523. data/lib/pubid/oasis/parser.rb +34 -0
  524. data/lib/pubid/oasis/renderer.rb +29 -0
  525. data/lib/pubid/oasis/urn_generator.rb +25 -0
  526. data/lib/pubid/oasis/urn_parser.rb +22 -0
  527. data/lib/pubid/oasis.rb +80 -0
  528. data/lib/pubid/ogc/builder.rb +33 -0
  529. data/lib/pubid/ogc/identifier.rb +81 -0
  530. data/lib/pubid/ogc/identifiers/document.rb +26 -0
  531. data/lib/pubid/ogc/identifiers.rb +10 -0
  532. data/lib/pubid/ogc/parser.rb +40 -0
  533. data/lib/pubid/ogc/renderer.rb +33 -0
  534. data/lib/pubid/ogc/urn_generator.rb +14 -0
  535. data/lib/pubid/ogc/urn_parser.rb +22 -0
  536. data/lib/pubid/ogc.rb +72 -0
  537. data/lib/pubid/oiml/builder.rb +36 -8
  538. data/lib/pubid/oiml/identifier.rb +9 -1
  539. data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
  540. data/lib/pubid/oiml/identifiers/bulletin.rb +36 -0
  541. data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
  542. data/lib/pubid/oiml/identifiers/document.rb +2 -0
  543. data/lib/pubid/oiml/identifiers/expert_report.rb +2 -0
  544. data/lib/pubid/oiml/identifiers/guide.rb +2 -0
  545. data/lib/pubid/oiml/identifiers/recommendation.rb +2 -0
  546. data/lib/pubid/oiml/identifiers/seminar_report.rb +2 -0
  547. data/lib/pubid/oiml/identifiers/vocabulary.rb +2 -0
  548. data/lib/pubid/oiml/identifiers.rb +1 -0
  549. data/lib/pubid/oiml/parser.rb +12 -13
  550. data/lib/pubid/oiml/renderer.rb +13 -13
  551. data/lib/pubid/oiml/single_identifier.rb +41 -37
  552. data/lib/pubid/oiml/supplement_identifier.rb +36 -9
  553. data/lib/pubid/oiml/urn_parser.rb +23 -6
  554. data/lib/pubid/oiml.rb +10 -0
  555. data/lib/pubid/omg/builder.rb +20 -0
  556. data/lib/pubid/omg/identifier.rb +61 -0
  557. data/lib/pubid/omg/identifiers/specification.rb +32 -0
  558. data/lib/pubid/omg/identifiers.rb +9 -0
  559. data/lib/pubid/omg/parser.rb +93 -0
  560. data/lib/pubid/omg/renderer.rb +31 -0
  561. data/lib/pubid/omg.rb +52 -0
  562. data/lib/pubid/parser/grammar.rb +74 -0
  563. data/lib/pubid/parser.rb +2 -0
  564. data/lib/pubid/parsers/mr_string.rb +120 -7
  565. data/lib/pubid/plateau/builder.rb +8 -4
  566. data/lib/pubid/plateau/identifier.rb +1 -3
  567. data/lib/pubid/plateau/identifiers/base.rb +1 -6
  568. data/lib/pubid/plateau/identifiers/handbook.rb +1 -1
  569. data/lib/pubid/plateau/identifiers/technical_report.rb +1 -1
  570. data/lib/pubid/plateau/identifiers.rb +0 -1
  571. data/lib/pubid/plateau/parser.rb +16 -6
  572. data/lib/pubid/plateau/renderer.rb +1 -1
  573. data/lib/pubid/plateau/supplement_identifier.rb +11 -11
  574. data/lib/pubid/plateau.rb +14 -4
  575. data/lib/pubid/prefixes_support.rb +1 -0
  576. data/lib/pubid/renderers/annotator.rb +233 -0
  577. data/lib/pubid/renderers/base.rb +13 -0
  578. data/lib/pubid/renderers/directives_renderer.rb +3 -3
  579. data/lib/pubid/renderers/human_readable.rb +6 -4
  580. data/lib/pubid/renderers/mr_string.rb +54 -6
  581. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  582. data/lib/pubid/renderers.rb +1 -0
  583. data/lib/pubid/rendering/numbering.rb +25 -7
  584. data/lib/pubid/rendering/supplement.rb +4 -4
  585. data/lib/pubid/rendering.rb +1 -0
  586. data/lib/pubid/sae/builder.rb +1 -1
  587. data/lib/pubid/sae/identifier.rb +1 -3
  588. data/lib/pubid/sae/identifiers/base.rb +19 -9
  589. data/lib/pubid/sae/identifiers.rb +0 -1
  590. data/lib/pubid/sae/parser.rb +1 -1
  591. data/lib/pubid/sae.rb +4 -3
  592. data/lib/pubid/schema/declaration.rb +33 -0
  593. data/lib/pubid/schema/error.rb +14 -0
  594. data/lib/pubid/schema/identifier_type.rb +23 -0
  595. data/lib/pubid/schema/loader.rb +117 -0
  596. data/lib/pubid/schema/typed_stage.rb +24 -0
  597. data/lib/pubid/schema.rb +25 -0
  598. data/lib/pubid/tgpp/builder.rb +41 -0
  599. data/lib/pubid/tgpp/identifier.rb +107 -0
  600. data/lib/pubid/tgpp/identifiers/technical_report.rb +32 -0
  601. data/lib/pubid/tgpp/identifiers/technical_specification.rb +33 -0
  602. data/lib/pubid/tgpp/identifiers.rb +11 -0
  603. data/lib/pubid/tgpp/parser.rb +78 -0
  604. data/lib/pubid/tgpp/renderer.rb +52 -0
  605. data/lib/pubid/tgpp/urn_generator.rb +39 -0
  606. data/lib/pubid/tgpp/urn_parser.rb +30 -0
  607. data/lib/pubid/tgpp.rb +84 -0
  608. data/lib/pubid/type_resolver.rb +74 -0
  609. data/lib/pubid/un/builder.rb +42 -0
  610. data/lib/pubid/un/identifier.rb +40 -0
  611. data/lib/pubid/un/identifiers/document.rb +24 -0
  612. data/lib/pubid/un/identifiers.rb +9 -0
  613. data/lib/pubid/un/parser.rb +25 -0
  614. data/lib/pubid/un/renderer.rb +11 -0
  615. data/lib/pubid/un.rb +47 -0
  616. data/lib/pubid/urn_parser/errors.rb +8 -1
  617. data/lib/pubid/urn_parser.rb +1 -0
  618. data/lib/pubid/utils.rb +1 -0
  619. data/lib/pubid/version.rb +1 -1
  620. data/lib/pubid/w3c/builder.rb +55 -0
  621. data/lib/pubid/w3c/identifier.rb +130 -0
  622. data/lib/pubid/w3c/identifiers/candidate_recommendation.rb +31 -0
  623. data/lib/pubid/w3c/identifiers/candidate_recommendation_draft.rb +31 -0
  624. data/lib/pubid/w3c/identifiers/draft_note.rb +31 -0
  625. data/lib/pubid/w3c/identifiers/note.rb +30 -0
  626. data/lib/pubid/w3c/identifiers/obsolete_recommendation.rb +31 -0
  627. data/lib/pubid/w3c/identifiers/proposed_edited_recommendation.rb +31 -0
  628. data/lib/pubid/w3c/identifiers/proposed_recommendation.rb +31 -0
  629. data/lib/pubid/w3c/identifiers/recommendation.rb +31 -0
  630. data/lib/pubid/w3c/identifiers/standard.rb +12 -0
  631. data/lib/pubid/w3c/identifiers/superseded_recommendation.rb +31 -0
  632. data/lib/pubid/w3c/identifiers/working_draft.rb +30 -0
  633. data/lib/pubid/w3c/identifiers.rb +25 -0
  634. data/lib/pubid/w3c/parser.rb +43 -0
  635. data/lib/pubid/w3c/renderer.rb +35 -0
  636. data/lib/pubid/w3c/urn_generator.rb +18 -0
  637. data/lib/pubid/w3c/urn_parser.rb +36 -0
  638. data/lib/pubid/w3c.rb +68 -0
  639. data/lib/pubid/xsf/builder.rb +17 -0
  640. data/lib/pubid/xsf/identifier.rb +66 -0
  641. data/lib/pubid/xsf/identifiers/xep.rb +31 -0
  642. data/lib/pubid/xsf/identifiers.rb +9 -0
  643. data/lib/pubid/xsf/parser.rb +38 -0
  644. data/lib/pubid/xsf/renderer.rb +23 -0
  645. data/lib/pubid/xsf/urn_generator.rb +13 -0
  646. data/lib/pubid/xsf/urn_parser.rb +18 -0
  647. data/lib/pubid/xsf.rb +82 -0
  648. data/lib/pubid.rb +424 -22
  649. data/lib/tasks/conformance.rake +34 -0
  650. data/lib/tasks/docs.rake +3 -3
  651. data/lib/tasks/schema.rake +88 -0
  652. data/schema/core/joint_prefixes.yaml +24 -0
  653. data/schema/iec.yaml +1017 -0
  654. data/schema/iso.yaml +1586 -0
  655. data/schema/schema.schema.yaml +96 -0
  656. metadata +241 -19
  657. data/archived-gems/pubid-ccsds/update_codes.yaml +0 -1
  658. data/archived-gems/pubid-iec/stages.yaml +0 -129
  659. data/archived-gems/pubid-iec/update_codes.yaml +0 -67
  660. data/archived-gems/pubid-ieee/update_codes.yaml +0 -104
  661. data/archived-gems/pubid-iso/stages.yaml +0 -106
  662. data/archived-gems/pubid-iso/update_codes.yaml +0 -4
  663. data/archived-gems/pubid-itu/i18n.yaml +0 -13
  664. data/archived-gems/pubid-itu/series.yaml +0 -42
  665. data/archived-gems/pubid-nist/publishers.yaml +0 -6
  666. data/archived-gems/pubid-nist/update_codes.yaml +0 -93
  667. data/archived-gems/pubid-plateau/update_codes.yaml +0 -6
  668. data/lib/pubid/cen_cenelec/supplement_identifier.rb +0 -48
  669. data/lib/pubid/cie/components/code.rb +0 -80
  670. data/lib/pubid/iala/identifiers/base.rb +0 -14
  671. data/lib/pubid/iec/components/code.rb +0 -36
  672. /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
data/lib/pubid.rb CHANGED
@@ -15,6 +15,8 @@ require "pubid/lutaml/no_store_registration"
15
15
  require "pubid/prefixes_support"
16
16
 
17
17
  module Pubid
18
+ autoload :Schema, "pubid/schema"
19
+ autoload :Conformance, "pubid/conformance"
18
20
  # Upper bound on the length of an identifier string accepted by any +parse+
19
21
  # entry point. Real-world standards identifiers are well under 200 characters;
20
22
  # this limit exists purely to keep pathological, attacker-controlled inputs
@@ -30,12 +32,28 @@ module Pubid
30
32
  INPUT_TOO_LONG_MESSAGE =
31
33
  "identifier string exceeds maximum length of #{MAX_INPUT_LENGTH} characters"
32
34
 
35
+ # Raised (as an ArgumentError) when +parse+ gets something that is not a
36
+ # String. Without this check the input reaches +.length+ and the caller gets a
37
+ # NoMethodError ("undefined method 'length' for nil"), a Ruby internal error
38
+ # that says nothing about the identifier contract. Every public +parse+ entry
39
+ # point rejects a non-String before it measures the length.
40
+ INPUT_NOT_A_STRING_MESSAGE = "identifier must be a String"
41
+
33
42
  # Registry for tracking all loaded flavors
34
43
  class Registry
35
44
  @flavors = {}
36
45
 
37
46
  class << self
38
- attr_reader :flavors
47
+ # The registered flavors, always key-sorted and frozen. Sorted so
48
+ # no behavior can observe registration (= module load) order -
49
+ # hosts autoload flavor modules in any order, and order-dependent
50
+ # iteration once routed the same identifier to different flavors
51
+ # per process. Frozen so the raw table is not public mutable
52
+ # state; #register is the only mutator.
53
+ # @return [Hash{String => Module}]
54
+ def flavors
55
+ @flavors.sort.to_h.freeze
56
+ end
39
57
 
40
58
  # Register a flavor with the registry
41
59
  # @param name [String, Symbol] Flavor name (e.g., :iso, :iec)
@@ -44,6 +62,15 @@ module Pubid
44
62
  @flavors[name.to_s.downcase] = flavor_module
45
63
  end
46
64
 
65
+ # Remove a flavor registration. Tests that register probe flavors
66
+ # MUST unregister them: registry-driven specs enumerate every
67
+ # registered flavor, so a leaked probe fails them for everyone
68
+ # else in the process.
69
+ # @param name [String, Symbol] Flavor name
70
+ def unregister(name)
71
+ @flavors.delete(name.to_s.downcase)
72
+ end
73
+
47
74
  # Get all registered flavor names
48
75
  # @return [Array<String>] Array of flavor names
49
76
  def flavor_names
@@ -57,30 +84,62 @@ module Pubid
57
84
  @flavors[name.to_s.downcase]
58
85
  end
59
86
 
87
+ # The canonical registered name of a module that may be registered
88
+ # under aliases (CenCenelec registers both cen_cenelec and cen).
89
+ # Canonical = the name the module's own prefix table is keyed by,
90
+ # so the answer cannot depend on registration or iteration order.
91
+ # @param flavor_module [Module]
92
+ # @return [String, nil]
93
+ def canonical_name(flavor_module)
94
+ if flavor_module.singleton_class.method_defined?(:prefix_flavor_key)
95
+ key = flavor_module.prefix_flavor_key.to_s
96
+ return key if @flavors[key] == flavor_module
97
+ end
98
+ @flavors.key(flavor_module)
99
+ end
100
+
60
101
  # Check if a flavor is registered
61
102
  # @param name [String, Symbol] Flavor name
62
103
  # @return [Boolean]
63
104
  def registered?(name)
64
105
  @flavors.key?(name.to_s.downcase)
65
106
  end
107
+
108
+ # Parse an identifier without naming its flavor.
109
+ #
110
+ # The pubid 1.x entry point, kept because consumers still call it —
111
+ # isodoc's +std_docid_semantic_parse+ among them. It delegates to
112
+ # {Pubid.parse}; it is not a second implementation.
113
+ #
114
+ # @param string [String] the identifier string
115
+ # @return [Pubid::Identifier]
116
+ # @raise [Parslet::ParseFailed] when no flavor can parse it
117
+ def parse(string, **opts)
118
+ Pubid.parse(string, **opts)
119
+ end
120
+
121
+ # Build an identifier from its hash without naming its flavor.
122
+ # It delegates to {Pubid.from_hash}, as {parse} delegates to
123
+ # {Pubid.parse}.
124
+ #
125
+ # @param data [Hash] an identifier hash
126
+ # @return [Pubid::Identifier]
127
+ # @raise [Pubid::Errors::InvalidInputError] see {Pubid.from_hash}
128
+ def from_hash(data)
129
+ Pubid.from_hash(data)
130
+ end
66
131
  end
67
132
  end
68
133
 
69
- # Canonical joint / co-publication leading tokens, injected symmetrically into
70
- # every participating flavor's +prefixes+ (see {PrefixesSupport}). Single
71
- # source of truth: editing an entry here updates both sides at once
72
- # (e.g. +"ISO/IEC"+ appears in +Pubid::Iso.prefixes+ and +Pubid::Iec.prefixes+),
73
- # so co-publication symmetry can never drift. Keyed by
134
+ # Canonical joint / co-publication leading tokens, sourced at boot from
135
+ # schema/core/joint_prefixes.yaml - the single source of truth. Injected
136
+ # symmetrically into every participating flavor's +prefixes+ (see
137
+ # {PrefixesSupport}) so co-publication symmetry can never drift. Keyed by
74
138
  # {PrefixesSupport#prefix_flavor_key}.
75
- JOINT_PREFIXES = {
76
- iso: ["ISO/IEC", "IEC/ISO", "ISO/IEC/IEEE"],
77
- iec: ["ISO/IEC", "IEC/ISO", "ISO/IEC/IEEE"],
78
- ieee: ["ISO/IEC/IEEE"],
79
- ansi: ["ANSI/ASHRAE", "ANSI/AMCA"],
80
- ashrae: ["ANSI/ASHRAE"],
81
- amca: ["ANSI/AMCA"],
82
- }.freeze
139
+ JOINT_PREFIXES = Schema::Loader.joint_prefixes_map
140
+ .transform_keys(&:to_sym).freeze
83
141
 
142
+ autoload :Errors, "pubid/errors"
84
143
  autoload :Parser, "pubid/parser"
85
144
  autoload :Components, "pubid/components"
86
145
  autoload :BundledIdentifier, "pubid/bundled_identifier"
@@ -97,35 +156,55 @@ module Pubid
97
156
  autoload :Utils, "pubid/utils"
98
157
  autoload :Version, "pubid/version"
99
158
  autoload :Core, "pubid/core"
159
+ autoload :TypeResolver, "pubid/type_resolver"
100
160
 
101
161
 
102
162
  # Require all flavor modules
163
+ autoload :Adobe, "pubid/adobe"
103
164
  autoload :Amca, "pubid/amca"
104
165
  autoload :Ansi, "pubid/ansi"
105
166
  autoload :Api, "pubid/api"
106
167
  autoload :Ashrae, "pubid/ashrae"
107
168
  autoload :Asme, "pubid/asme"
169
+ autoload :Doi, "pubid/doi"
170
+ autoload :Easc, "pubid/easc"
108
171
  autoload :Astm, "pubid/astm"
172
+ autoload :Bipm, "pubid/bipm"
109
173
  autoload :Bsi, "pubid/bsi"
174
+ autoload :Calconnect, "pubid/calconnect"
110
175
  autoload :Ccsds, "pubid/ccsds"
111
176
  autoload :CenCenelec, "pubid/cen_cenelec"
112
177
  autoload :Cie, "pubid/cie"
113
178
  autoload :Csa, "pubid/csa"
179
+ autoload :Ecma, "pubid/ecma"
114
180
  autoload :Etsi, "pubid/etsi"
181
+ autoload :Evs, "pubid/evs"
182
+ autoload :Gost, "pubid/gost"
183
+ autoload :Gb, "pubid/gb"
115
184
  autoload :Idf, "pubid/idf"
116
185
  autoload :Iec, "pubid/iec"
117
186
  autoload :Ieee, "pubid/ieee"
187
+ autoload :Ietf, "pubid/ietf"
188
+ autoload :Isbn, "pubid/isbn"
118
189
  autoload :Iala, "pubid/iala"
190
+ autoload :Iana, "pubid/iana"
119
191
  autoload :Iho, "pubid/iho"
120
192
  autoload :Iso, "pubid/iso"
121
193
  autoload :Itu, "pubid/itu"
122
194
  autoload :Jcgm, "pubid/jcgm"
123
195
  autoload :Jis, "pubid/jis"
124
196
  autoload :Nist, "pubid/nist"
197
+ autoload :Oasis, "pubid/oasis"
198
+ autoload :Ogc, "pubid/ogc"
125
199
  autoload :Oiml, "pubid/oiml"
200
+ autoload :Omg, "pubid/omg"
126
201
  autoload :Plateau, "pubid/plateau"
127
202
  autoload :Export, "pubid/export"
128
203
  autoload :Sae, "pubid/sae"
204
+ autoload :Tgpp, "pubid/tgpp"
205
+ autoload :Un, "pubid/un"
206
+ autoload :Xsf, "pubid/xsf"
207
+ autoload :W3c, "pubid/w3c"
129
208
 
130
209
  # Format infrastructure (loaded eagerly so Pubid::Renderers / Pubid::Parsers are always available)
131
210
  require "pubid/renderers/base"
@@ -142,17 +221,47 @@ module Pubid
142
221
 
143
222
  # Unified parse entry point with auto-detection
144
223
  #
224
+ # A human-readable string is routed to its owning flavor by leading prefix
225
+ # token, using the {prefix_flavors} table. This restores the pubid 1.x
226
+ # +Pubid::Registry.parse+ capability, which isodoc still calls; before it,
227
+ # this method raised +No flavor specified+ for every human-readable string,
228
+ # so a reference whose flavor the caller did not already know could not be
229
+ # parsed at all.
230
+ #
145
231
  # @param string [String] The identifier string to parse
146
232
  # @param format [Symbol] :auto, :human, :mr_string, or :urn
147
233
  # @return [Identifier] The parsed identifier
234
+ # @raise [ArgumentError] for a non-String, or one over {MAX_INPUT_LENGTH}
235
+ # @raise [Parslet::ParseFailed] when no flavor can parse the string — the
236
+ # class every flavor's own +parse+ raises (see the parse-failure contract)
148
237
  def self.parse(string, format: :auto)
149
- raise ArgumentError, INPUT_TOO_LONG_MESSAGE if string.length > MAX_INPUT_LENGTH
238
+ unless string.is_a?(String)
239
+ raise Pubid::Errors::InvalidInputError,
240
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
241
+ end
242
+ if string.length > MAX_INPUT_LENGTH
243
+ raise Pubid::Errors::InvalidInputError,
244
+ Pubid::INPUT_TOO_LONG_MESSAGE
245
+ end
150
246
 
151
247
  format = FormatDetector.detect(string) if format == :auto
152
248
 
153
249
  case format
154
250
  when :mr_string
155
- Parsers::MrString.parse(string)
251
+ # The MR detector is a shape heuristic (`/\A[A-Z]{2,}[.-]/`), and some
252
+ # human-readable identifiers have that shape — "ITU-T G.711" is the
253
+ # standing example. Fall through to prefix routing when the MR parse
254
+ # fails, rather than reporting an MR error for a string that was never
255
+ # an MR string. A genuine MR failure still surfaces, from the second
256
+ # attempt, as Parslet::ParseFailed.
257
+ #
258
+ # Narrow, for the reason spelled out on {parse_by_prefix}: only a parse
259
+ # failure means "wrong shape". Anything else is a defect and propagates.
260
+ begin
261
+ Parsers::MrString.parse(string)
262
+ rescue Parslet::ParseFailed
263
+ parse_by_prefix(string)
264
+ end
156
265
  when :urn
157
266
  eager_load_flavors!
158
267
  flavor = detect_flavor_from_urn(string)
@@ -163,29 +272,255 @@ module Pubid
163
272
  end
164
273
 
165
274
  urn_parser = flavor_module.const_get(:UrnParser)
166
- urn_parser.parse(string) else
167
- # Default to MR string parser for MR format, human-readable otherwise
168
- # The MR string parser converts to human-readable and delegates to flavor.parse
169
- raise ArgumentError,
170
- "No flavor specified. Use Pubid::Iso.parse() or another flavor-specific parse method."
275
+ urn_parser.parse(string)
276
+ else
277
+ parse_by_prefix(string)
278
+ end
279
+ end
280
+
281
+ # Build an identifier from its serialized hash, without naming its flavor —
282
+ # the hash counterpart of {parse}.
283
+ #
284
+ # The hash is what {Identifier#to_hash} emits, and what a relaton-data
285
+ # +index-v2.yaml+ row stores under +:id+. Its +_type+ key
286
+ # ("pubid:<flavor>:<type>") names the concrete class, so no prefix guessing
287
+ # is necessary. The class is resolved by {TypeResolver}, and the class's own
288
+ # +from_hash+ does the rest, nested identifiers of other flavors included.
289
+ #
290
+ # @example
291
+ # Pubid.from_hash("_type" => "pubid:iso:international-standard",
292
+ # "number" => "9001", "year" => "2015").to_s
293
+ # # => "ISO 9001:2015"
294
+ #
295
+ # @param data [Hash] an identifier hash. String and Symbol keys are both
296
+ # accepted.
297
+ # @return [Identifier] an instance of the class that +_type+ names
298
+ # @raise [Pubid::Errors::InvalidInputError] when +data+ is not a Hash, has no
299
+ # +_type+, or has a +_type+ that no registered flavor defines. These are
300
+ # the only failures it translates: once +_type+ names a class, an error
301
+ # from that class's own +from_hash+ (a malformed field, or a bad +_type+
302
+ # in a NESTED hash) propagates unchanged, so a flavor defect is not
303
+ # disguised as bad input.
304
+ def self.from_hash(data)
305
+ unless data.is_a?(Hash)
306
+ raise Pubid::Errors::InvalidInputError,
307
+ "identifier data must be a Hash, got #{data.class}"
308
+ end
309
+
310
+ identifier_class_for(data).from_hash(data)
311
+ end
312
+
313
+ # The concrete class that the +_type+ of +data+ names.
314
+ #
315
+ # @param data [Hash] an identifier hash
316
+ # @return [Class<Identifier>]
317
+ # @raise [Pubid::Errors::InvalidInputError] no +_type+, or an unknown one
318
+ # @api private
319
+ def self.identifier_class_for(data)
320
+ type = data["_type"] || data[:_type]
321
+ unless type
322
+ raise Pubid::Errors::InvalidInputError,
323
+ "identifier hash has no _type key: #{data.inspect[0, 200]}"
324
+ end
325
+
326
+ TypeResolver.resolve(type) ||
327
+ raise(Pubid::Errors::InvalidInputError,
328
+ "unknown identifier _type: #{type.inspect}")
329
+ end
330
+ private_class_method :identifier_class_for
331
+
332
+ # Route a human-readable identifier to its flavor by leading prefix token.
333
+ #
334
+ # Three passes, widening each time — the pubid 1.x +Registry.parse+ shape:
335
+ #
336
+ # 1. flavors owning the longest matching prefix ("ISO/IEC" before "ISO")
337
+ # 2. every other flavor, in registry order
338
+ #
339
+ # A longest-match-first order matters because prefixes nest: "ISO/IEC 2131"
340
+ # must not be handed to the flavor that merely owns "ISO".
341
+ #
342
+ # @param string [String] a human-readable identifier
343
+ # @return [Identifier]
344
+ # @raise [Parslet::ParseFailed] when no flavor accepts the string
345
+ # @api private
346
+ def self.parse_by_prefix(string)
347
+ eager_load_flavors!
348
+
349
+ first_error = nil
350
+ fallback = nil
351
+
352
+ prefix_owners = candidates_by_prefix(string)
353
+ (prefix_owners + other_candidates(prefix_owners)).each do |mod|
354
+ begin
355
+ parsed = mod.parse(string)
356
+ rescue Parslet::ParseFailed => e
357
+ # ONLY a parse failure means "not this flavor's identifier". Every
358
+ # other exception is a defect in that flavor and must propagate.
359
+ #
360
+ # A blanket `rescue StandardError` here would swallow exactly the
361
+ # `ArgumentError: unknown attribute…` that the constructor contract on
362
+ # `Identifier` now raises — the error that turned three silent
363
+ # data-loss bugs (CIE `s_prefix`, IEEE `adopted_identifier`,
364
+ # IEEE `csa_identifier`) into visible ones. Catching it one layer up
365
+ # would hand it straight back its disguise: a real builder bug in any
366
+ # flavor would read as "this string is not an identifier".
367
+ first_error ||= e
368
+ next
369
+ end
370
+
371
+ # An exact round trip is the strongest evidence the string belongs to
372
+ # this flavor. It matters because some grammars accept anything by
373
+ # design — adobe and iana take any slug — so without it the first such
374
+ # flavor in registry order claims every unclaimed string and invents
375
+ # structure that was not in the input. Same test isodoc applies before
376
+ # it will annotate a parsed id.
377
+ return parsed if parsed.to_s == string
378
+
379
+ # A non-exact parse is still usable — several flavors legitimately
380
+ # normalise on render, so the round trip is a preference, not a
381
+ # requirement (OGC prints `06-121r9` for `OGC 06-121r9`, and 32 ASHRAE /
382
+ # ASME / CSA / IEEE identifiers route only this way). What it must NOT
383
+ # come from is a flavor that accepts anything: that is how `iec.60050`
384
+ # came back as `IANA iec.60050`. Reporting that no flavor could be
385
+ # determined beats inventing one.
386
+ fallback ||= parsed unless accepts_anything?(mod)
387
+ end
388
+
389
+ return fallback if fallback
390
+ raise first_error if first_error
391
+
392
+ raise Parslet::ParseFailed,
393
+ "no registered flavor could parse #{string.inspect}"
394
+ end
395
+ private_class_method :parse_by_prefix
396
+
397
+ # Flavor modules that own a prefix +string+ starts with, longest prefix
398
+ # first. Deduplicated by module identity, so an alias registration is not
399
+ # tried twice.
400
+ #
401
+ # These are the flavors with an actual claim on the string; a parse from one
402
+ # of them is trusted even when the flavor normalises on render.
403
+ #
404
+ # @param string [String] a human-readable identifier
405
+ # @return [Array<Module>]
406
+ # @api private
407
+ def self.candidates_by_prefix(string)
408
+ ordered = []
409
+ routing_table.each do |prefix, modules|
410
+ ordered.concat(modules) if prefix_match?(string, prefix)
171
411
  end
412
+ ordered.compact.uniq
172
413
  end
414
+ private_class_method :candidates_by_prefix
415
+
416
+ # Every other registered flavor, for the exhaustive second pass.
417
+ #
418
+ # @param exclude [Array<Module>] modules already tried
419
+ # @return [Array<Module>]
420
+ # @api private
421
+ def self.other_candidates(exclude)
422
+ ordered = []
423
+ each_prefix_flavor_module { |mod| ordered << mod }
424
+ ordered.compact.uniq - exclude
425
+ end
426
+ private_class_method :other_candidates
427
+
428
+ # A meaningless string no real identifier scheme should claim. Used to find
429
+ # the flavors whose grammar accepts anything.
430
+ ROUTING_PROBE = "zzqx-nonsense-9714"
431
+ private_constant :ROUTING_PROBE
432
+
433
+ # True when +mod+'s grammar accepts an arbitrary slug.
434
+ #
435
+ # `adobe` and `iana` do, by design — their identifiers genuinely are free
436
+ # text. That makes them unsafe as a fallback: whichever came first in
437
+ # registry order would claim every string no other flavor matched, and
438
+ # answer with structure the input never had.
439
+ #
440
+ # Detected by probing rather than by a hardcoded list, so a flavor that
441
+ # acquires (or loses) an anything-goes grammar is classified correctly
442
+ # without anyone remembering to edit a constant. Computed once per module.
443
+ #
444
+ # @param mod [Module] a flavor module
445
+ # @return [Boolean]
446
+ # @api private
447
+ def self.accepts_anything?(mod)
448
+ @accepts_anything ||= {}
449
+ return @accepts_anything[mod] if @accepts_anything.key?(mod)
450
+
451
+ @accepts_anything[mod] =
452
+ begin
453
+ mod.parse(ROUTING_PROBE)
454
+ true
455
+ rescue StandardError, Parslet::ParseFailed
456
+ false
457
+ end
458
+ end
459
+ private_class_method :accepts_anything?
460
+
461
+ # Prefix => flavor modules, longest prefix first, built once.
462
+ #
463
+ # {prefix_flavors} rebuilds its index on every call, iterating every
464
+ # registered flavor; routing consulted it twice per parse. The registry is
465
+ # static once +eager_load_flavors!+ has run, so the table is memoised here
466
+ # rather than making the public method's cost implicit.
467
+ #
468
+ # The memo is never invalidated, which is safe for every flavor shipped in
469
+ # this gem — they are all +Pubid+-namespace constants that
470
+ # +eager_load_flavors!+ loads before the first parse. A flavor registered
471
+ # from OUTSIDE that namespace after the first {parse} call would miss its
472
+ # prefix priority (it is still tried in the exhaustive second pass, so it is
473
+ # reachable, just not preferred). Bust the memo in +Registry.register+ if
474
+ # out-of-namespace flavors ever become a supported extension point.
475
+ #
476
+ # @return [Hash{String => Array<Module>}]
477
+ # @api private
478
+ def self.routing_table
479
+ @routing_table ||= begin
480
+ index = prefix_flavors
481
+ index.keys
482
+ .sort_by { |prefix| -prefix.length }
483
+ .to_h { |prefix| [prefix, index[prefix].map { |key| Registry.get(key) }] }
484
+ end
485
+ end
486
+ private_class_method :routing_table
487
+
488
+ # True when +string+ starts with +prefix+ at a token boundary, so "ISO" does
489
+ # not claim "ISOFIX" and "BS" does not claim "BSI".
490
+ # @api private
491
+ def self.prefix_match?(string, prefix)
492
+ return false unless string.start_with?(prefix)
493
+
494
+ rest = string[prefix.length]
495
+ rest.nil? || !/[A-Za-z0-9]/.match?(rest)
496
+ end
497
+ private_class_method :prefix_match?
173
498
 
174
499
  def self.detect_flavor_from_urn(urn)
175
500
  # urn:iso:std:... → "iso"
176
501
  # urn:iec:std:... → "iec"
502
+ # urn:mrn:iala:pub:... → "iala": MRN URNs carry an assigning authority
503
+ # where ISO-style URNs carry their namespace, so routing follows the
504
+ # authority (works for any future MRN assignee, not only IALA).
177
505
  parts = urn.downcase.split(":")
506
+ return parts[2] if parts[1] == "mrn"
507
+
178
508
  parts[1] # The namespace part after "urn"
179
509
  end
180
510
 
181
511
  # Trigger autoloads for every declared flavor module so that
182
512
  # Registry is populated before URN dispatch needs it. Safe to call
183
513
  # repeatedly; no-op after the first invocation.
514
+ #
515
+ # The constant filter allows a digit inside the name (the +0-9+ in the regex)
516
+ # so digit-bearing flavor modules such as +W3c+ are loaded/registered too —
517
+ # without it +W3c+ is silently dropped from the registry enumeration and thus
518
+ # from every registry-driven cross-flavor spec.
184
519
  def self.eager_load_flavors!
185
520
  return if @flavors_loaded
186
521
 
187
522
  constants.each do |c|
188
- next unless c.to_s.match?(/\A[A-Z][a-zA-Z]+\z/)
523
+ next unless c.to_s.match?(/\A[A-Z][a-zA-Z0-9]+\z/)
189
524
 
190
525
  begin
191
526
  const_get(c)
@@ -243,4 +578,71 @@ module Pubid
243
578
  yield mod
244
579
  end
245
580
  end
581
+
582
+ # Typed-stage lookup by abbreviation, across flavors.
583
+ #
584
+ # Each flavor module memoises +all_typed_stages+ over its own +Identifiers+
585
+ # namespace, so an abbreviation only one flavor uses is invisible from any
586
+ # other: +Pubid::Iso.locate_stage("ADTS")+ is nil while
587
+ # +Pubid::Iec.locate_stage("ADTS")+ finds it. A consumer that holds an
588
+ # abbreviation but not the owning flavor had nowhere to ask.
589
+ #
590
+ # @param abbr [String, Symbol] the stage abbreviation (case-insensitive)
591
+ # @param flavor [Symbol, String, nil] search this flavor only; nil searches
592
+ # every registered flavor and returns the first match
593
+ # @return [Object, nil] the flavor's typed-stage object, or nil. The class is
594
+ # flavor-specific: most return {Pubid::Components::TypedStage}, but IEEE
595
+ # has its own +Ieee::Components::TypedStage+, which is not a subclass.
596
+ # @raise [ArgumentError] if +flavor+ names a flavor that is not registered
597
+ def self.locate_stage(abbr, flavor: nil)
598
+ return locate_stage_in(Registry.get(flavor), abbr, flavor) if flavor
599
+
600
+ each_stage_flavor_module do |mod|
601
+ stage = mod.locate_stage(abbr)
602
+ return stage if stage
603
+ end
604
+ nil
605
+ end
606
+
607
+ # Every flavor that knows +abbr+ — the diagnostic companion to
608
+ # {locate_stage}, for telling a consumer which module owns a stage.
609
+ #
610
+ # @param abbr [String, Symbol] the stage abbreviation (case-insensitive)
611
+ # @return [Array<Symbol>] registered flavor keys, sorted
612
+ def self.locate_stage_flavors(abbr)
613
+ found = []
614
+ each_stage_flavor_module do |mod, flavor_name|
615
+ found << flavor_name.to_sym if mod.locate_stage(abbr)
616
+ end
617
+ found.sort
618
+ end
619
+
620
+ # Yields each unique flavor module that implements +locate_stage+, exactly
621
+ # once. Three registered flavors (adobe, easc, gost) define no typed stages
622
+ # at all, so a cross-flavor sweep must skip them rather than raise on the
623
+ # first one it reaches; alias registrations are collapsed by module identity,
624
+ # as in {each_prefix_flavor_module}.
625
+ #
626
+ # @yieldparam mod [Module] a flavor module
627
+ # @yieldparam flavor_name [String] the registry key it was reached under
628
+ def self.each_stage_flavor_module
629
+ eager_load_flavors!
630
+ seen = {}
631
+ Registry.flavor_names.each do |flavor_name|
632
+ mod = Registry.get(flavor_name)
633
+ next if seen.key?(mod) || !mod.respond_to?(:locate_stage)
634
+
635
+ seen[mod] = true
636
+ yield mod, flavor_name
637
+ end
638
+ end
639
+
640
+ # @api private
641
+ def self.locate_stage_in(mod, abbr, flavor)
642
+ raise ArgumentError, "unknown flavor: #{flavor.inspect}" unless mod
643
+ return nil unless mod.respond_to?(:locate_stage)
644
+
645
+ mod.locate_stage(abbr)
646
+ end
647
+ private_class_method :locate_stage_in
246
648
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ namespace :conformance do
7
+ desc "Generate the neutral corpus from ground-truth fixtures"
8
+ task :generate, [:flavor] do |_t, args|
9
+ require "pubid"
10
+ require "pubid/conformance"
11
+ flavor = args[:flavor] || "iso"
12
+ tests_repo = ENV.fetch("PUBID_TESTSUITE_PATH",
13
+ File.expand_path("../../../pubid-testsuite",
14
+ __dir__))
15
+ output_dir = File.join(tests_repo, "tests", flavor)
16
+ FileUtils.mkdir_p(output_dir)
17
+ results = Pubid::Conformance::Generator.new(flavor)
18
+ .generate(output_dir: output_dir)
19
+ stats = results
20
+ puts "#{flavor}: #{stats[:files]} files, #{stats[:cases]} cases, " \
21
+ "#{stats[:aliases]} aliases, #{stats[:duplicates]} duplicates, " \
22
+ "#{stats[:reclassify]} reclassify, #{stats[:negative]} negative, " \
23
+ "#{stats[:debt]} debt, #{stats[:roundtrip_failures]} rt-failures"
24
+ end
25
+
26
+ desc "Run the neutral corpus against this implementation"
27
+ task :run do
28
+ require "pubid"
29
+ require "pubid/conformance"
30
+ failures = Pubid::Conformance::Runner.new.run.flatten
31
+ puts "TOTAL failures: #{failures.size}"
32
+ exit(failures.empty? ? 0 : 1)
33
+ end
34
+ end
data/lib/tasks/docs.rake CHANGED
@@ -1,10 +1,10 @@
1
- # frozen_string_literal
2
-
3
- require_relative "../../lib/pubid/core/pattern_doc_generator"
1
+ # frozen_string_literal: true
4
2
 
5
3
  namespace :docs do
6
4
  desc "Generate identifier pattern reference docs"
7
5
  task :patterns do
6
+ require "pubid"
7
+
8
8
  output_dir = File.join(__dir__, "..", "..", "docs", "identifier-patterns")
9
9
  FileUtils.mkdir_p(output_dir)
10
10