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
@@ -24,7 +24,46 @@ module Pubid
24
24
  attribute :publisher, :string, default: -> { "CIE" }
25
25
 
26
26
  attribute :year, :string
27
- attribute :date_separator, :string # "dash" or "colon"
27
+ # The number<->year separator character, derived from +style+ (the sole
28
+ # separator field; there is no date_separator attribute):
29
+ # current -> ":" legacy -> "-" slash -> "/"
30
+ def date_sep_char
31
+ { "legacy" => "-", "slash" => "/" }.fetch(style, ":")
32
+ end
33
+
34
+ # Partial-reference matching: CIE keeps the publication year in its own
35
+ # `year` string attribute (the separator lives in `style`), not a `Date`
36
+ # component, so the base's `:year`->`:date` remap would nil the unused
37
+ # inherited `date` and leave `year` intact. Call super (preserving the
38
+ # nested-identifier recursion), then nil `year` directly so a year-less
39
+ # CIE ref is a year wildcard under `matches?(ignore: [:year])`.
40
+ #
41
+ # Known limit: `style` (which also encodes the era: current<->colon,
42
+ # legacy<->dash) is intentionally NOT wildcarded, so bare `CIE 015`
43
+ # (always current) matches a colon-dated full but not a legacy dash-dated
44
+ # (pre-2001) one. Partial-ref scope targets modern colon forms.
45
+ def exclude(*args)
46
+ result = super
47
+ result.year = nil if args.include?(:year) || args.include?(:date)
48
+ result
49
+ end
50
+
51
+ # CIE stores its publication year in its own `year` string attribute
52
+ # (not a Components::Date), and uses a single-Language component with
53
+ # multiple formats. Override the lossless MR template so `CIE S 017/E:2011`
54
+ # round-trips as `CIE.S.017.E.2011` rather than losing the type letter,
55
+ # language, and year (issue #142). Subclasses add the `s_prefix` and
56
+ # `language` attributes that this template reads.
57
+ def mr_year
58
+ year&.to_s
59
+ end
60
+
61
+ def mr_languages
62
+ return nil unless respond_to?(:language) && language
63
+
64
+ # Lowercase + filename-safe: drop the leading `/` (path-unsafe).
65
+ language.code.to_s.downcase
66
+ end
28
67
  end
29
68
  end
30
69
  end
@@ -2,25 +2,38 @@
2
2
 
3
3
  module Pubid
4
4
  module Cie
5
- # Base class for CIE supplement identifiers
6
- # Single Responsibility: Provide common attributes for supplement documents
5
+ # Base class for CIE supplement identifiers (Supplement, Corrigendum).
7
6
  #
8
- # Supplement identifiers modify or extend base identifiers.
9
- # Unlike ISO/IEC, CIE supplements store base information as flat
10
- # string attributes rather than recursive Identifier objects.
7
+ # Like ISO/IEC/BSI/JCGM, a CIE supplement wraps its base document as a
8
+ # nested full identifier (+base+, a Pubid::Cie::Identifier),
9
+ # rather than flat base_number/base_year strings. This lets CIE supplements
10
+ # participate in the shared base_document / drop_supplements / matches?
11
+ # vocabulary relaton uses to match a citation to its base standard.
11
12
  #
12
- # Classes inheriting from SupplementIdentifier:
13
- # - Corrigendum (corrigenda with /CorN notation)
14
- # - Supplement (supplements with -SPN notation)
15
- #
16
- # Architecture Note:
17
- # CIE uses a different architectural approach than ISO/IEC:
18
- # - ISO/IEC: Recursive base_identifier objects
19
- # - CIE: Flat string attributes (base_number, base_year, etc.)
13
+ # Concrete subtypes: Supplement (-SPN), Corrigendum (/CorN).
20
14
  class SupplementIdentifier < Identifier
21
- # Common attribute for all CIE identifiers
22
- # Values: "current" (colon date separator) or "legacy" (dash date separator)
23
- attribute :style, :string
15
+ attribute :base, Identifier, polymorphic: true
16
+ # The supplement's/corrigendum's own ordinal ("1" in -SP1 / Cor1).
17
+ # :string overrides the base ::Pubid::Identifier Components::Code type.
18
+ # (Not the index key — relaton keys on #root.number, the base standard's.)
19
+ attribute :number, :string
20
+
21
+ # Uniform, class-agnostic supplement interface (shared by Supplement and
22
+ # Corrigendum) so callers never special-case corrigenda. +supplement_type+
23
+ # and +supplement_year+ are defined per subclass.
24
+ def supplement_number
25
+ number
26
+ end
27
+
28
+ # The underlying standard, with supplement layer(s) peeled recursively.
29
+ def base_document
30
+ base&.base_document || self
31
+ end
32
+
33
+ # Dropping one supplement layer yields the wrapped base identifier.
34
+ def drop_supplements
35
+ base || self
36
+ end
24
37
  end
25
38
  end
26
39
  end
@@ -15,8 +15,8 @@ module Pubid
15
15
 
16
16
  parts << publisher_component
17
17
 
18
- if identifier.code
19
- parts << identifier.code.to_s
18
+ if identifier.respond_to?(:code_string) && identifier.code_string
19
+ parts << identifier.code_string
20
20
  end
21
21
 
22
22
  year = extract_year
@@ -37,8 +37,8 @@ module Pubid
37
37
  stage = maybe(:stage)
38
38
  parts << stage.to_s.downcase if stage
39
39
 
40
- date_separator = maybe(:date_separator)
41
- parts << "sep.#{date_separator}" if date_separator
40
+ # style is the sole separator field; record it for dated identifiers
41
+ parts << "sep.#{maybe(:style)}" if year
42
42
 
43
43
  iec_identifier = maybe(:iec_identifier)
44
44
  parts << "iec.#{iec_identifier}" if iec_identifier
@@ -49,11 +49,14 @@ module Pubid
49
49
  doc_type = maybe(:doc_type)
50
50
  parts << "doctype.#{doc_type}" if doc_type
51
51
 
52
- identifiers_string = maybe(:identifiers_string)
53
- parts << "bundle.#{identifiers_string}" if identifiers_string
52
+ if identifier.respond_to?(:ids) && identifier.ids&.any?
53
+ parts << "bundle.#{identifier}"
54
+ end
54
55
 
55
- bundle_number = maybe(:bundle_number)
56
- parts << "tut-bundle.#{bundle_number}" if bundle_number
56
+ if identifier.is_a?(Cie::Identifiers::TutorialBundle) &&
57
+ identifier.number
58
+ parts << "tut-bundle.#{identifier.number}"
59
+ end
57
60
 
58
61
  languages = maybe(:languages)
59
62
  if languages&.any?
data/lib/pubid/cie.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pubid"
3
4
  module Pubid
4
5
  module Cie
5
6
  extend Pubid::PrefixesSupport
@@ -8,7 +9,6 @@ module Pubid
8
9
  PREFIXES = ["CIE"].freeze
9
10
 
10
11
  module Components
11
- autoload :Code, "#{__dir__}/cie/components/code"
12
12
  autoload :Language, "#{__dir__}/cie/components/language"
13
13
  end
14
14
 
@@ -24,8 +24,13 @@ module Pubid
24
24
  # Main entry point for CIE identifiers
25
25
  # Delegates to Identifier.parse
26
26
  def self.parse(input)
27
+ unless input.is_a?(String)
28
+ raise Pubid::Errors::InvalidInputError,
29
+ Pubid::INPUT_NOT_A_STRING_MESSAGE
30
+ end
31
+
27
32
  if input.length > Pubid::MAX_INPUT_LENGTH
28
- raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
33
+ raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
29
34
  end
30
35
 
31
36
  Identifier.parse(input)
@@ -6,19 +6,33 @@ module Pubid
6
6
  module Components
7
7
  # Publication date component
8
8
  #
9
- # Human render: "YYYY" or "YYYY-MM" or "YYYY-MM-DD".
10
- # URN render: year only (RFC 5141-bis URN spec).
9
+ # Human render: "YYYY" or "YYYY-MM" or "YYYY-MM-DD"; or "--" when the
10
+ # date slot is present but explicitly undated (ISO/IEC undated-reference
11
+ # convention, e.g. "ISO 16634:--"). URN render: year only (RFC 5141-bis
12
+ # URN spec); flavors that drop the slot when undated gate that decision
13
+ # at the URN-generator level, not here.
11
14
  class Date < Lutaml::Model::Serializable
12
15
  attribute :year, :string
13
16
  attribute :month, :string
14
17
  attribute :day, :string
18
+ attribute :undated, :boolean, default: false
15
19
 
16
- # True when the year is set to a non-empty value.
20
+ # True when the year is set to a non-empty value, OR the date is
21
+ # explicitly marked undated. An undated date is a meaningful
22
+ # publication-date slot (it is what renders as `:--` in ISO/IEC), so
23
+ # callers that gate rendering on "is there a date at all?" should
24
+ # treat undated as present.
17
25
  def present?
26
+ return true if undated
18
27
  !year.nil? && !year.to_s.empty?
19
28
  end
20
29
 
30
+ def undated?
31
+ !!undated
32
+ end
33
+
21
34
  def render(context: nil)
35
+ return "--" if undated? && (year.nil? || year.to_s.empty?)
22
36
  return nil unless present?
23
37
  return year.to_s if context&.urn?
24
38
  return year.to_s unless month
@@ -29,6 +43,7 @@ module Pubid
29
43
  end
30
44
 
31
45
  def to_s(_context: nil, _include_month: false)
46
+ return "--" if undated? && (year.nil? || year.to_s.empty?)
32
47
  return year.to_s unless month
33
48
 
34
49
  result = "#{year}-#{pad2(month)}"
@@ -43,13 +58,14 @@ module Pubid
43
58
  end
44
59
 
45
60
  def hash
46
- @hash ||= [year, month, day].compact.map(&:hash).hash
61
+ @hash ||= [year, month, day, undated].compact.map(&:hash).hash
47
62
  end
48
63
 
49
64
  def eql?(other)
50
65
  return false unless other.is_a?(self.class)
51
66
 
52
- year == other.year && month == other.month && day == other.day
67
+ year == other.year && month == other.month && day == other.day &&
68
+ undated == other.undated
53
69
  end
54
70
  end
55
71
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Conformance
5
+ # The single check core shared by the conformance runner and the rspec
6
+ # corpus gate. One corpus case in, its mismatch list out (empty ==
7
+ # passing). The list shape is load-bearing: RSpec's aggregate_failures
8
+ # does not raise on a failed expectation, so exception-based control
9
+ # flow would misread real failures as passes - and the runner needs to
10
+ # accumulate across cases rather than abort.
11
+ module Checks
12
+ class << self
13
+ # @param test_case [Pubid::Conformance::Corpus::Case]
14
+ # @param flavor_module [Module] the flavor owning the case
15
+ # @return [Array<String>] mismatch descriptions, empty when passing
16
+ def check_case(test_case, flavor_module)
17
+ identifier = flavor_module.parse(test_case.representations.human)
18
+ mismatchers(identifier, test_case, flavor_module)
19
+ .flat_map(&:call)
20
+ rescue StandardError => e
21
+ ["#{test_case.id} raised #{e.class}"]
22
+ end
23
+
24
+ # Each checker returns the case's mismatch list for its concern.
25
+ def mismatchers(identifier, test_case, flavor_module)
26
+ label = test_case.id.to_s
27
+ [
28
+ -> { canonical_mismatches(identifier, test_case, label) },
29
+ -> { representation_mismatches(identifier, test_case, label) },
30
+ -> { alias_mismatches(test_case, flavor_module, label) },
31
+ -> { deserialize_mismatches(identifier, flavor_module, label) },
32
+ ]
33
+ end
34
+
35
+ def canonical_mismatches(identifier, test_case, label)
36
+ actual = Conformance.plainify(identifier.to_hash)
37
+ actual == test_case.identifier ? [] : ["#{label} canonical hash"]
38
+ end
39
+
40
+ private
41
+
42
+ def representation_mismatches(identifier, test_case, label)
43
+ mismatches = []
44
+ reps = test_case.representations
45
+ mismatches << "#{label} human" if identifier.to_s != reps.human
46
+ if reps.urn && identifier.to_urn != reps.urn
47
+ mismatches << "#{label} urn"
48
+ end
49
+ mismatches
50
+ end
51
+
52
+ def alias_mismatches(test_case, flavor_module, label)
53
+ human = test_case.representations.human
54
+ test_case.non_normalized_aliases.filter_map do |entry|
55
+ aliased = flavor_module.parse(entry.spelling)
56
+ "#{label} alias #{entry.spelling}" if aliased.to_s != human
57
+ rescue StandardError
58
+ "#{label} alias #{entry.spelling} raised"
59
+ end
60
+ end
61
+
62
+ def deserialize_mismatches(identifier, flavor_module, label)
63
+ hash = identifier.to_hash
64
+ ok = flavor_module::Identifier.from_hash(hash).to_hash == hash
65
+ ok ? [] : ["#{label} deserialize"]
66
+ rescue StandardError
67
+ ["#{label} deserialize raised"]
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Conformance
5
+ module Corpus
6
+ # Every proper rendering of the case's identifier.
7
+ class Representations < Lutaml::Model::Serializable
8
+ attribute :human, :string
9
+ attribute :urn, :string
10
+ end
11
+
12
+ # One old spelling that must normalize to the human form.
13
+ class Spelling < Lutaml::Model::Serializable
14
+ attribute :spelling, :string
15
+ attribute :style, :string
16
+ end
17
+
18
+ # Neutral rejection expectation - never an implementation class.
19
+ class Error < Lutaml::Model::Serializable
20
+ attribute :code, :string
21
+ end
22
+
23
+ class Expectation < Lutaml::Model::Serializable
24
+ attribute :error, Error
25
+ end
26
+
27
+ # One corpus case (schema/test.schema.yaml is the wire contract).
28
+ # `identifier` stays an opaque hash on purpose: it is the flavor's
29
+ # own canonical to_hash carried as DATA to compare against, not a
30
+ # structure the reader interprets.
31
+ class Case < Lutaml::Model::Serializable
32
+ attribute :id, :string
33
+ attribute :style, :string
34
+ attribute :identifier, :hash
35
+ attribute :representations, Representations
36
+ attribute :non_normalized_aliases, Spelling, collection: true,
37
+ default: -> { [] }
38
+ attribute :roundtrip, :boolean
39
+ attribute :expect, Expectation
40
+ attribute :input, :string
41
+ attribute :notes, :string
42
+ attribute :review, :string
43
+
44
+ def error_case? = !expect.nil? && !expect.error.nil?
45
+
46
+ # Reference-bug debt: nothing to gate on.
47
+ def quarantined? = identifier.nil? && !error_case?
48
+
49
+ def review? = !review.to_s.empty?
50
+
51
+ def roundtrip_failure_expected? = roundtrip == false
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Conformance
5
+ # Typed reading layer for pubid-testsuite payloads. The YAML schema
6
+ # (schema/test.schema.yaml in pubid-testsuite) is the wire contract;
7
+ # these models are the shared typed reader for every implementation -
8
+ # the Ruby gem now, pubid-ts mirroring the same shape later. No
9
+ # consumer pokes payload hashes directly.
10
+ module Corpus
11
+ autoload :Case, "pubid/conformance/corpus/case"
12
+
13
+ class << self
14
+ # Cases from one payload file (underscore payloads excluded).
15
+ def load_file(path)
16
+ Array(YAML.safe_load_file(path)).map { |doc| Case.from_hash(doc) }
17
+ end
18
+
19
+ def case_files(flavor, corpus_dir)
20
+ Dir[File.join(corpus_dir, flavor, "*.yaml")]
21
+ .reject { |p| File.basename(p).start_with?("_") }.sort
22
+ end
23
+
24
+ def cases(flavor, corpus_dir)
25
+ case_files(flavor, corpus_dir).flat_map { |p| load_file(p) }
26
+ end
27
+
28
+ # The must-fail payload (fail fixtures decoded by the exporter).
29
+ def negative_file(flavor, corpus_dir)
30
+ path = File.join(corpus_dir, flavor, "_negative.yaml")
31
+ File.exist?(path) ? [path] : []
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Conformance
5
+ # Migrates the ground-truth fixture library (spec/fixtures/{flavor}/
6
+ # identifiers/{pass,fail}/*.txt) into the neutral corpus by running the
7
+ # reference implementation. Fixture lines that normalize to the same
8
+ # identifier collapse into one canonical case carrying the old
9
+ # spellings as non_normalized_aliases (old => normalized, and the
10
+ # normalized form round-trips). Unparseable pass lines are recorded as
11
+ # visible debt; fail lines (stored as "#ID# Error: ..." comments in the
12
+ # fixture files) become negative cases. Nothing is sampled, filtered,
13
+ # or dropped.
14
+ class Generator
15
+ attr_reader :flavor
16
+
17
+ def initialize(flavor)
18
+ require "pubid"
19
+
20
+ @flavor = flavor.to_s
21
+ Pubid.eager_load_flavors!
22
+ @flavor_module = Pubid::Registry.get(@flavor)
23
+ raise ArgumentError, "unknown flavor #{@flavor}" unless @flavor_module
24
+ end
25
+
26
+ def generate(output_dir:)
27
+ results = { files: 0, cases: 0, negative: 0, debt: 0, aliases: 0,
28
+ duplicates: 0, reclassify: 0, roundtrip_failures: 0 }
29
+ debt = []
30
+ pass_files.each do |path|
31
+ type = File.basename(path, ".txt")
32
+ cases, type_debt = build_pass_cases(path, type, results)
33
+ debt.concat(type_debt)
34
+ next if cases.empty?
35
+
36
+ write_yaml(File.join(output_dir, "#{type}.yaml"), cases)
37
+ results[:files] += 1
38
+ end
39
+ results[:debt] = debt.size
40
+ write_yaml(File.join(output_dir, "_debt.yaml"), debt) if debt.any?
41
+ negative = build_negative_cases(results)
42
+ if negative.any?
43
+ write_yaml(File.join(output_dir, "_negative.yaml"), negative)
44
+ end
45
+ results
46
+ end
47
+
48
+ private
49
+
50
+ def pass_files
51
+ Dir[File.join(fixtures_dir, "identifiers", "pass", "*.txt")] +
52
+ Dir[File.join(fixtures_dir, "identifiers", "full", "*.txt")]
53
+ end
54
+
55
+ def fail_files
56
+ Dir[File.join(fixtures_dir, "identifiers", "fail", "*.txt")]
57
+ end
58
+
59
+ def fixtures_dir
60
+ File.join(tests_repo, "reference-docs", @flavor)
61
+ end
62
+
63
+ def tests_repo
64
+ @tests_repo ||= ENV.fetch("PUBID_TESTSUITE_PATH",
65
+ File.expand_path("../../../../pubid-testsuite",
66
+ __dir__))
67
+ end
68
+
69
+ def fixture_lines(path)
70
+ File.readlines(path).map(&:strip).reject do |line|
71
+ line.empty? || line.start_with?("#")
72
+ end
73
+ end
74
+
75
+ # Fail fixtures store identifiers as comment lines shaped
76
+ # "#IDENTIFIER# Parslet::ParseFailed: ...". Strip the leading # and
77
+ # the trailing historical annotation to recover the input.
78
+ def fail_fixture_lines(path)
79
+ File.readlines(path).filter_map do |raw|
80
+ line = raw.strip
81
+ next if line.empty?
82
+ next line unless line.start_with?("#")
83
+
84
+ input = line.sub(/\A#/, "").split("#", 2).first.to_s.strip
85
+ input unless input.empty?
86
+ end
87
+ end
88
+
89
+ def build_pass_cases(path, type, results)
90
+ groups = {}
91
+ debt = []
92
+ fixture_lines(path).each do |input|
93
+ record = build_record(input)
94
+ if record.key?(:debt)
95
+ debt << record[:debt]
96
+ next
97
+ end
98
+ key = JSON.generate(record[:case]["identifier"]) +
99
+ record[:case]["representations"]["human"]
100
+ (groups[key] ||= { record: record[:case],
101
+ inputs: [] })[:inputs] << input
102
+ end
103
+ cases = assign_ids(groups, type, results)
104
+ [cases, debt]
105
+ end
106
+
107
+ def assign_ids(groups, type, results)
108
+ groups.values.sort_by { |g| canonical_input(g) }.each_with_index
109
+ .map do |group, index|
110
+ record = group[:record]
111
+ record["id"] = format("%s.%s.%04d", @flavor, type, index + 1)
112
+ canonical = canonical_input(group)
113
+ record["style"] = Conformance.style_for(canonical)
114
+ inputs = group[:inputs]
115
+ duplicates = [inputs.count(canonical) - 1, 0].max
116
+ results[:duplicates] += duplicates
117
+ aliases = inputs.reject { |i| i == canonical }.uniq.sort
118
+ results[:aliases] += aliases.size
119
+ unless aliases.empty?
120
+ record["non_normalized_aliases"] = aliases.map do |a|
121
+ { "input" => a, "style" => Conformance.style_for(a) }
122
+ end
123
+ end
124
+ results[:roundtrip_failures] += 1 if record["roundtrip"] == false
125
+ results[:cases] += 1
126
+ record
127
+ end
128
+ end
129
+
130
+ def canonical_input(group)
131
+ group.dig(:record, "representations", "human")
132
+ end
133
+
134
+ def build_record(input)
135
+ identifier = @flavor_module.parse(input)
136
+ hash = identifier.to_hash
137
+ representations = { "human" => identifier.to_s }
138
+ urn = safe_urn(identifier)
139
+ representations["urn"] = urn if urn
140
+ record = { "id" => nil,
141
+ "identifier" => Conformance.plainify(hash) }
142
+ record["representations"] = representations
143
+ record["roundtrip"] = false unless round_trips?(hash)
144
+ quarantine!(record) if bundled_month_bug?(hash)
145
+ { case: record }
146
+ rescue StandardError => e
147
+ { debt: { "id" => "#{@flavor}.debt.#{input.hash.abs}",
148
+ "input" => input,
149
+ "expect" => { "error" =>
150
+ { "code" => Conformance.error_code_for(e) } },
151
+ "notes" => "unparsed ground-truth fixture: " \
152
+ "#{e.class}: #{e.message.to_s[0, 200]}" } }
153
+ end
154
+
155
+ # Reference implementation parses bundled directive supplements with
156
+ # month-bearing dates nondeterministically across load orders (a
157
+ # spurious day component appears). Quarantine deterministically.
158
+ def bundled_month_bug?(hash)
159
+ hash.to_s.include?("bundled_identifier") && hash.to_s.include?("month")
160
+ end
161
+
162
+ def quarantine!(record)
163
+ record.delete("identifier")
164
+ record.delete("representations")
165
+ record.delete("roundtrip")
166
+ record.delete("non_normalized_aliases")
167
+ record["notes"] = "nondeterministic parse in reference " \
168
+ "implementation (month/day divergence) - " \
169
+ "reference bug, quarantined from gates"
170
+ end
171
+
172
+ def round_trips?(hash)
173
+ @flavor_module::Identifier.from_hash(hash).to_hash == hash
174
+ rescue StandardError
175
+ false
176
+ end
177
+
178
+ def safe_urn(identifier)
179
+ identifier.to_urn
180
+ rescue StandardError
181
+ nil
182
+ end
183
+
184
+ def build_negative_cases(results)
185
+ cases = []
186
+ fail_files.each do |path|
187
+ type = File.basename(path, ".txt")
188
+ fail_fixture_lines(path).each_with_index do |input, index|
189
+ cases << negative_case(format("%s.neg.%s.%04d",
190
+ @flavor, type, index + 1), input)
191
+ results[:negative] += 1
192
+ end
193
+ end
194
+ cases
195
+ end
196
+
197
+ def negative_case(id, input)
198
+ @flavor_module.parse(input)
199
+ { "id" => id, "input" => input, "style" => Conformance.style_for(input),
200
+ "notes" => "fail fixture unexpectedly parsed - reclassify" }
201
+ rescue StandardError => e
202
+ { "id" => id, "input" => input,
203
+ "expect" => { "error" =>
204
+ { "code" => Conformance.error_code_for(e) } } }
205
+ end
206
+
207
+ def write_yaml(path, entries)
208
+ File.write(path, YAML.dump(entries))
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Conformance
5
+ # Implementation-side PENDING markers: corpus cases this implementation
6
+ # explicitly cannot handle yet. The testsuite owns expectations; this
7
+ # file owns the admission that they are not met - so a pending case is
8
+ # visible debt, never a silent failure and never a hidden pass.
9
+ #
10
+ # Format (conformance/pending.yaml at the implementation repo root):
11
+ # "<case-id glob>":
12
+ # reason: <one line, the root cause>
13
+ # since: <YYYY-MM-DD>
14
+ # ref: <TODO.correct-test-suite PR queue entry or contract id>
15
+ #
16
+ # Rules enforced elsewhere: a pending case that passes raises the
17
+ # "pending satisfied - remove the marker" alarm; entries without a ref
18
+ # are rejected at load.
19
+ class Pending
20
+ PATH = File.expand_path("../../../conformance/pending.yaml", __dir__)
21
+
22
+ class << self
23
+ def for(case_id)
24
+ entry = registry[case_id]
25
+ return entry if entry
26
+
27
+ registry.each do |pattern, meta|
28
+ next if pattern == case_id
29
+
30
+ return meta if File.fnmatch(pattern, case_id)
31
+ end
32
+ nil
33
+ end
34
+
35
+ def empty?
36
+ registry.empty?
37
+ end
38
+
39
+ private
40
+
41
+ def registry
42
+ @registry ||= load_registry
43
+ end
44
+
45
+ def load_registry
46
+ return {} unless File.exist?(PATH)
47
+
48
+ (YAML.safe_load_file(PATH) || {})
49
+ .to_h { |pattern, meta| [pattern, validated(meta, pattern)] }
50
+ end
51
+
52
+ def validated(meta, pattern)
53
+ unless meta.is_a?(Hash) && meta["reason"] && meta["ref"]
54
+ raise ArgumentError,
55
+ "pending entry #{pattern.inspect} needs reason and ref"
56
+ end
57
+
58
+ meta
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end