pubid 2.0.0.pre.alpha.9 → 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 (432) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +33 -11
  3. data/conformance/pending.yaml +4 -0
  4. data/lib/pubid/adobe/identifier.rb +1 -3
  5. data/lib/pubid/adobe/parser.rb +10 -2
  6. data/lib/pubid/adobe.rb +1 -0
  7. data/lib/pubid/amca/builder.rb +2 -2
  8. data/lib/pubid/amca/identifiers/base.rb +49 -27
  9. data/lib/pubid/amca/identifiers/interpretation.rb +17 -9
  10. data/lib/pubid/amca/identifiers/publication.rb +13 -9
  11. data/lib/pubid/amca/identifiers/standard.rb +2 -0
  12. data/lib/pubid/amca/parser.rb +1 -1
  13. data/lib/pubid/amca/renderer.rb +4 -4
  14. data/lib/pubid/amca/urn_generator.rb +2 -2
  15. data/lib/pubid/amca.rb +2 -1
  16. data/lib/pubid/ansi/builder.rb +2 -2
  17. data/lib/pubid/ansi/identifier.rb +18 -0
  18. data/lib/pubid/ansi/parser.rb +1 -1
  19. data/lib/pubid/ansi/renderer.rb +2 -2
  20. data/lib/pubid/ansi.rb +5 -5
  21. data/lib/pubid/api/builder.rb +16 -2
  22. data/lib/pubid/api/identifier.rb +25 -4
  23. data/lib/pubid/api/identifiers/mpms.rb +10 -8
  24. data/lib/pubid/api/parser.rb +1 -1
  25. data/lib/pubid/api/renderer.rb +16 -7
  26. data/lib/pubid/api/single_identifier.rb +5 -12
  27. data/lib/pubid/api.rb +1 -0
  28. data/lib/pubid/ashrae/builder.rb +31 -10
  29. data/lib/pubid/ashrae/identifiers/addenda_package.rb +6 -0
  30. data/lib/pubid/ashrae/identifiers/addendum.rb +8 -0
  31. data/lib/pubid/ashrae/identifiers/base.rb +81 -5
  32. data/lib/pubid/ashrae/identifiers/combined_addenda.rb +7 -0
  33. data/lib/pubid/ashrae/identifiers/errata.rb +9 -0
  34. data/lib/pubid/ashrae/identifiers/guideline.rb +3 -0
  35. data/lib/pubid/ashrae/identifiers/interpretation.rb +16 -0
  36. data/lib/pubid/ashrae/identifiers/standard.rb +3 -0
  37. data/lib/pubid/ashrae/parser.rb +23 -8
  38. data/lib/pubid/ashrae/renderer.rb +6 -6
  39. data/lib/pubid/ashrae/supplement_identifier.rb +17 -2
  40. data/lib/pubid/ashrae/urn_generator.rb +8 -2
  41. data/lib/pubid/ashrae.rb +7 -1
  42. data/lib/pubid/asme/builder.rb +11 -2
  43. data/lib/pubid/asme/identifier.rb +9 -0
  44. data/lib/pubid/asme/identifiers/standard.rb +86 -2
  45. data/lib/pubid/asme/parser.rb +1 -1
  46. data/lib/pubid/asme/renderer.rb +3 -3
  47. data/lib/pubid/asme/single_identifier.rb +8 -1
  48. data/lib/pubid/asme/urn_generator.rb +2 -2
  49. data/lib/pubid/asme.rb +1 -0
  50. data/lib/pubid/astm/builder.rb +10 -3
  51. data/lib/pubid/astm/identifier.rb +9 -0
  52. data/lib/pubid/astm/identifiers/adjunct.rb +16 -1
  53. data/lib/pubid/astm/identifiers/code_number.rb +81 -0
  54. data/lib/pubid/astm/identifiers/data_series.rb +2 -0
  55. data/lib/pubid/astm/identifiers/iso_dual_published.rb +16 -0
  56. data/lib/pubid/astm/identifiers/manual.rb +10 -0
  57. data/lib/pubid/astm/identifiers/monograph.rb +2 -0
  58. data/lib/pubid/astm/identifiers/research_report.rb +10 -0
  59. data/lib/pubid/astm/identifiers/standard.rb +10 -0
  60. data/lib/pubid/astm/identifiers/technical_report.rb +2 -0
  61. data/lib/pubid/astm/identifiers/work_in_progress.rb +2 -0
  62. data/lib/pubid/astm/identifiers.rb +1 -0
  63. data/lib/pubid/astm/parser.rb +1 -1
  64. data/lib/pubid/astm/renderer.rb +1 -1
  65. data/lib/pubid/astm/single_identifier.rb +31 -1
  66. data/lib/pubid/astm/urn_generator.rb +7 -5
  67. data/lib/pubid/astm.rb +1 -0
  68. data/lib/pubid/bipm/builder.rb +66 -10
  69. data/lib/pubid/bipm/identifier.rb +134 -9
  70. data/lib/pubid/bipm/identifiers/committee_document.rb +12 -0
  71. data/lib/pubid/bipm/identifiers/guide.rb +11 -0
  72. data/lib/pubid/bipm/identifiers/meeting.rb +12 -0
  73. data/lib/pubid/bipm/identifiers/mep.rb +12 -0
  74. data/lib/pubid/bipm/identifiers/metrologia_article.rb +24 -0
  75. data/lib/pubid/bipm/identifiers/si_brochure.rb +13 -0
  76. data/lib/pubid/bipm/parser.rb +65 -12
  77. data/lib/pubid/bipm/renderer.rb +8 -0
  78. data/lib/pubid/bipm/urn_parser.rb +11 -3
  79. data/lib/pubid/bipm.rb +7 -1
  80. data/lib/pubid/bsi/builder.rb +48 -38
  81. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +36 -7
  82. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +7 -6
  83. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +0 -1
  84. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +10 -0
  85. data/lib/pubid/bsi/identifiers/committee_document.rb +10 -1
  86. data/lib/pubid/bsi/identifiers/handbook.rb +0 -2
  87. data/lib/pubid/bsi/identifiers/practice_guide.rb +0 -1
  88. data/lib/pubid/bsi/identifiers/set.rb +11 -0
  89. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +10 -1
  90. data/lib/pubid/bsi/parser.rb +1 -1
  91. data/lib/pubid/bsi/renderer.rb +63 -51
  92. data/lib/pubid/bsi/single_identifier.rb +16 -7
  93. data/lib/pubid/bsi/urn_generator.rb +11 -2
  94. data/lib/pubid/bsi.rb +7 -1
  95. data/lib/pubid/builder/base.rb +18 -8
  96. data/lib/pubid/bundled_identifier.rb +16 -6
  97. data/lib/pubid/calconnect/identifier.rb +9 -5
  98. data/lib/pubid/calconnect/parser.rb +1 -1
  99. data/lib/pubid/calconnect.rb +7 -1
  100. data/lib/pubid/ccsds/identifier.rb +9 -2
  101. data/lib/pubid/ccsds/identifiers/base.rb +4 -2
  102. data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
  103. data/lib/pubid/ccsds/parser.rb +1 -1
  104. data/lib/pubid/ccsds/single_identifier.rb +2 -2
  105. data/lib/pubid/ccsds.rb +1 -0
  106. data/lib/pubid/cen_cenelec/builder.rb +101 -76
  107. data/lib/pubid/cen_cenelec/identifier.rb +115 -3
  108. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +27 -16
  109. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +46 -6
  110. data/lib/pubid/cen_cenelec/identifiers/base.rb +8 -9
  111. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +1 -1
  112. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +1 -1
  113. data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +1 -1
  114. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +29 -20
  115. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +47 -8
  116. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +27 -2
  117. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +1 -1
  118. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +15 -5
  119. data/lib/pubid/cen_cenelec/identifiers/guide.rb +1 -1
  120. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +1 -1
  121. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +1 -1
  122. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +1 -1
  123. data/lib/pubid/cen_cenelec/parser.rb +1 -1
  124. data/lib/pubid/cen_cenelec/renderer.rb +55 -60
  125. data/lib/pubid/cen_cenelec/single_identifier.rb +20 -2
  126. data/lib/pubid/cen_cenelec/urn_generator.rb +66 -44
  127. data/lib/pubid/cen_cenelec.rb +28 -10
  128. data/lib/pubid/cie/builder.rb +10 -0
  129. data/lib/pubid/cie/identifier.rb +6 -1
  130. data/lib/pubid/cie/identifiers/bundle.rb +4 -2
  131. data/lib/pubid/cie/identifiers/conference.rb +2 -2
  132. data/lib/pubid/cie/identifiers/corrigendum.rb +2 -2
  133. data/lib/pubid/cie/identifiers/dual_published.rb +2 -2
  134. data/lib/pubid/cie/identifiers/identical.rb +2 -2
  135. data/lib/pubid/cie/identifiers/joint_published.rb +2 -2
  136. data/lib/pubid/cie/identifiers/proceedings.rb +8 -6
  137. data/lib/pubid/cie/identifiers/standard.rb +22 -13
  138. data/lib/pubid/cie/identifiers/supplement.rb +2 -2
  139. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +2 -2
  140. data/lib/pubid/cie/parser.rb +1 -1
  141. data/lib/pubid/cie.rb +7 -1
  142. data/lib/pubid/conformance/checks.rb +72 -0
  143. data/lib/pubid/conformance/corpus/case.rb +55 -0
  144. data/lib/pubid/conformance/corpus.rb +36 -0
  145. data/lib/pubid/conformance/generator.rb +212 -0
  146. data/lib/pubid/conformance/pending.rb +63 -0
  147. data/lib/pubid/conformance/runner.rb +153 -0
  148. data/lib/pubid/conformance.rb +55 -0
  149. data/lib/pubid/core.rb +2 -0
  150. data/lib/pubid/csa/builder.rb +47 -47
  151. data/lib/pubid/csa/composite_identifier.rb +14 -19
  152. data/lib/pubid/csa/identifier.rb +143 -81
  153. data/lib/pubid/csa/identifiers/bundled.rb +23 -13
  154. data/lib/pubid/csa/identifiers/canadian_adopted.rb +13 -13
  155. data/lib/pubid/csa/identifiers/cec.rb +44 -4
  156. data/lib/pubid/csa/identifiers/combined.rb +95 -73
  157. data/lib/pubid/csa/identifiers/csa_adopted.rb +4 -4
  158. data/lib/pubid/csa/identifiers/package.rb +2 -2
  159. data/lib/pubid/csa/parser.rb +6 -2
  160. data/lib/pubid/csa/renderer.rb +13 -5
  161. data/lib/pubid/csa/single_identifier.rb +93 -4
  162. data/lib/pubid/csa/urn_generator.rb +9 -2
  163. data/lib/pubid/csa/wrapper_identifier.rb +39 -23
  164. data/lib/pubid/csa.rb +7 -1
  165. data/lib/pubid/doi/identifier.rb +6 -3
  166. data/lib/pubid/doi/parser.rb +1 -1
  167. data/lib/pubid/doi.rb +1 -0
  168. data/lib/pubid/easc/identifier.rb +0 -2
  169. data/lib/pubid/easc/parser.rb +10 -2
  170. data/lib/pubid/easc.rb +1 -0
  171. data/lib/pubid/ecma/builder.rb +23 -9
  172. data/lib/pubid/ecma/identifier.rb +81 -10
  173. data/lib/pubid/ecma/parser.rb +39 -4
  174. data/lib/pubid/ecma/renderer.rb +29 -8
  175. data/lib/pubid/ecma/urn_generator.rb +34 -13
  176. data/lib/pubid/ecma/urn_parser.rb +30 -14
  177. data/lib/pubid/ecma.rb +1 -0
  178. data/lib/pubid/errors.rb +80 -0
  179. data/lib/pubid/etsi/builder.rb +6 -1
  180. data/lib/pubid/etsi/identifiers/base.rb +34 -20
  181. data/lib/pubid/etsi/identifiers/etsi_standard.rb +120 -41
  182. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +10 -0
  183. data/lib/pubid/etsi/parser.rb +1 -1
  184. data/lib/pubid/etsi.rb +1 -0
  185. data/lib/pubid/evs/builder.rb +26 -0
  186. data/lib/pubid/evs/identifier.rb +37 -0
  187. data/lib/pubid/evs/identifiers/national_adoption.rb +17 -0
  188. data/lib/pubid/evs/identifiers.rb +9 -0
  189. data/lib/pubid/evs/parser.rb +27 -0
  190. data/lib/pubid/evs/renderer.rb +30 -0
  191. data/lib/pubid/evs/urn_generator.rb +30 -0
  192. data/lib/pubid/evs/urn_parser.rb +80 -0
  193. data/lib/pubid/evs.rb +90 -0
  194. data/lib/pubid/export.rb +1 -0
  195. data/lib/pubid/format_detector.rb +1 -0
  196. data/lib/pubid/gb/identifier.rb +6 -3
  197. data/lib/pubid/gb/parser.rb +1 -1
  198. data/lib/pubid/gb.rb +1 -0
  199. data/lib/pubid/gost/builder.rb +46 -9
  200. data/lib/pubid/gost/identifier.rb +0 -2
  201. data/lib/pubid/gost/identifiers/foreign_reference.rb +1 -1
  202. data/lib/pubid/gost/parser.rb +10 -2
  203. data/lib/pubid/gost.rb +1 -0
  204. data/lib/pubid/iala/identifier.rb +9 -6
  205. data/lib/pubid/iala/parser.rb +10 -2
  206. data/lib/pubid/iala/urn_parser.rb +6 -2
  207. data/lib/pubid/iala.rb +1 -0
  208. data/lib/pubid/iana/builder.rb +3 -1
  209. data/lib/pubid/iana/identifier.rb +74 -6
  210. data/lib/pubid/iana/identifiers/registry.rb +36 -0
  211. data/lib/pubid/iana/parser.rb +1 -1
  212. data/lib/pubid/iana/renderer.rb +3 -0
  213. data/lib/pubid/iana/urn_generator.rb +5 -1
  214. data/lib/pubid/iana.rb +1 -0
  215. data/lib/pubid/identifier.rb +594 -10
  216. data/lib/pubid/identifier_metadata.rb +1 -0
  217. data/lib/pubid/idf/builder.rb +3 -3
  218. data/lib/pubid/idf/identifier.rb +18 -9
  219. data/lib/pubid/idf/parser.rb +1 -1
  220. data/lib/pubid/idf/renderer.rb +4 -4
  221. data/lib/pubid/idf/urn_generator.rb +1 -1
  222. data/lib/pubid/idf.rb +7 -1
  223. data/lib/pubid/iec/builder.rb +14 -7
  224. data/lib/pubid/iec/components.rb +0 -1
  225. data/lib/pubid/iec/identifier.rb +73 -83
  226. data/lib/pubid/iec/identifiers/amendment.rb +6 -2
  227. data/lib/pubid/iec/identifiers/component_specification.rb +0 -10
  228. data/lib/pubid/iec/identifiers/conformity_assessment.rb +0 -10
  229. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -2
  230. data/lib/pubid/iec/identifiers/fragment_identifier.rb +2 -4
  231. data/lib/pubid/iec/identifiers/guide.rb +0 -16
  232. data/lib/pubid/iec/identifiers/international_standard.rb +15 -2
  233. data/lib/pubid/iec/identifiers/operational_document.rb +0 -10
  234. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +0 -12
  235. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +0 -10
  236. data/lib/pubid/iec/identifiers/systems_reference_document.rb +0 -10
  237. data/lib/pubid/iec/identifiers/technical_report.rb +0 -17
  238. data/lib/pubid/iec/identifiers/technical_specification.rb +0 -17
  239. data/lib/pubid/iec/identifiers/technology_report.rb +0 -10
  240. data/lib/pubid/iec/identifiers/test_report_form.rb +0 -11
  241. data/lib/pubid/iec/identifiers/white_paper.rb +0 -10
  242. data/lib/pubid/iec/identifiers/working_document.rb +24 -10
  243. data/lib/pubid/iec/parser.rb +2 -18
  244. data/lib/pubid/iec/renderer.rb +13 -10
  245. data/lib/pubid/iec/single_identifier.rb +33 -10
  246. data/lib/pubid/iec/urn_generator.rb +227 -61
  247. data/lib/pubid/iec/urn_parser.rb +42 -4
  248. data/lib/pubid/iec.rb +1 -0
  249. data/lib/pubid/ieee/aiee/identifier.rb +2 -2
  250. data/lib/pubid/ieee/aiee/parser.rb +1 -1
  251. data/lib/pubid/ieee/builder.rb +45 -1
  252. data/lib/pubid/ieee/identifiers/adopted_standard.rb +32 -0
  253. data/lib/pubid/ieee/identifiers/base.rb +42 -5
  254. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +21 -0
  255. data/lib/pubid/ieee/identifiers/dual_published.rb +55 -0
  256. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +23 -0
  257. data/lib/pubid/ieee/identifiers/joint_development.rb +11 -7
  258. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +57 -5
  259. data/lib/pubid/ieee/identifiers/nesc/base.rb +2 -2
  260. data/lib/pubid/ieee/identifiers/nesc/draft.rb +2 -2
  261. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +2 -2
  262. data/lib/pubid/ieee/identifiers/nesc/redline.rb +2 -2
  263. data/lib/pubid/ieee/identifiers/nesc/standard.rb +2 -2
  264. data/lib/pubid/ieee/ire/identifier.rb +2 -2
  265. data/lib/pubid/ieee/ire/parser.rb +1 -1
  266. data/lib/pubid/ieee/nesc/parser.rb +1 -1
  267. data/lib/pubid/ieee/parser.rb +1 -1
  268. data/lib/pubid/ieee/renderer.rb +5 -1
  269. data/lib/pubid/ieee/urn_generator.rb +32 -3
  270. data/lib/pubid/ieee.rb +7 -1
  271. data/lib/pubid/ieee_debug.rb +1 -0
  272. data/lib/pubid/ietf/builder.rb +24 -8
  273. data/lib/pubid/ietf/identifiers/base.rb +25 -28
  274. data/lib/pubid/ietf/identifiers/bcp.rb +11 -0
  275. data/lib/pubid/ietf/identifiers/fyi.rb +11 -0
  276. data/lib/pubid/ietf/identifiers/internet_draft.rb +18 -2
  277. data/lib/pubid/ietf/identifiers/rfc.rb +2 -0
  278. data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
  279. data/lib/pubid/ietf/identifiers/std.rb +11 -0
  280. data/lib/pubid/ietf/identifiers.rb +1 -0
  281. data/lib/pubid/ietf/parser.rb +27 -9
  282. data/lib/pubid/ietf/renderer.rb +44 -6
  283. data/lib/pubid/ietf/urn_generator.rb +20 -6
  284. data/lib/pubid/ietf/urn_parser.rb +10 -2
  285. data/lib/pubid/ietf.rb +12 -2
  286. data/lib/pubid/iho/identifiers/base.rb +10 -3
  287. data/lib/pubid/iho/parser.rb +1 -1
  288. data/lib/pubid/iho.rb +1 -0
  289. data/lib/pubid/isbn/identifier.rb +25 -7
  290. data/lib/pubid/isbn/parser.rb +1 -1
  291. data/lib/pubid/isbn.rb +1 -0
  292. data/lib/pubid/iso/bundled_identifier.rb +5 -3
  293. data/lib/pubid/iso/combined_identifier.rb +5 -3
  294. data/lib/pubid/iso/identifier.rb +12 -7
  295. data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -4
  296. data/lib/pubid/iso/parser.rb +1 -1
  297. data/lib/pubid/iso.rb +7 -1
  298. data/lib/pubid/itu/identifiers/addendum.rb +2 -2
  299. data/lib/pubid/itu/identifiers/amendment.rb +2 -2
  300. data/lib/pubid/itu/identifiers/base.rb +19 -5
  301. data/lib/pubid/itu/identifiers/corrigendum.rb +2 -2
  302. data/lib/pubid/itu/identifiers/errata.rb +2 -2
  303. data/lib/pubid/itu/identifiers/supplement.rb +2 -2
  304. data/lib/pubid/itu/parser.rb +1 -1
  305. data/lib/pubid/itu.rb +1 -0
  306. data/lib/pubid/jcgm/builder.rb +1 -1
  307. data/lib/pubid/jcgm/identifier.rb +10 -0
  308. data/lib/pubid/jcgm/identifiers/meeting.rb +1 -1
  309. data/lib/pubid/jcgm/parser.rb +10 -3
  310. data/lib/pubid/jcgm/renderer.rb +10 -3
  311. data/lib/pubid/jcgm/single_identifier.rb +24 -15
  312. data/lib/pubid/jcgm/urn_generator.rb +1 -1
  313. data/lib/pubid/jcgm/urn_parser.rb +156 -14
  314. data/lib/pubid/jcgm.rb +10 -0
  315. data/lib/pubid/jis/identifier.rb +10 -3
  316. data/lib/pubid/jis/parser.rb +1 -1
  317. data/lib/pubid/jis.rb +1 -0
  318. data/lib/pubid/nist/components/stage.rb +2 -2
  319. data/lib/pubid/nist/configuration.rb +6 -8
  320. data/lib/pubid/nist/identifiers/base.rb +12 -2
  321. data/lib/pubid/nist/identifiers/circular.rb +9 -2
  322. data/lib/pubid/nist/identifiers/circular_supplement.rb +14 -5
  323. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +7 -1
  324. data/lib/pubid/nist/identifiers/crpl_report.rb +7 -1
  325. data/lib/pubid/nist/identifiers/handbook.rb +9 -2
  326. data/lib/pubid/nist/identifiers/internal_report.rb +12 -5
  327. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +14 -6
  328. data/lib/pubid/nist/identifiers/monograph.rb +14 -7
  329. data/lib/pubid/nist/identifiers/report.rb +14 -6
  330. data/lib/pubid/nist/parser.rb +1 -1
  331. data/lib/pubid/nist/supplement_identifier.rb +16 -1
  332. data/lib/pubid/nist.rb +7 -1
  333. data/lib/pubid/oasis/builder.rb +12 -10
  334. data/lib/pubid/oasis/identifier.rb +89 -11
  335. data/lib/pubid/oasis/parser.rb +1 -1
  336. data/lib/pubid/oasis.rb +7 -1
  337. data/lib/pubid/ogc/identifier.rb +9 -5
  338. data/lib/pubid/ogc/parser.rb +1 -1
  339. data/lib/pubid/ogc.rb +1 -0
  340. data/lib/pubid/oiml/builder.rb +5 -1
  341. data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
  342. data/lib/pubid/oiml/identifiers/bulletin.rb +36 -0
  343. data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
  344. data/lib/pubid/oiml/identifiers/document.rb +2 -0
  345. data/lib/pubid/oiml/identifiers/expert_report.rb +2 -0
  346. data/lib/pubid/oiml/identifiers/guide.rb +2 -0
  347. data/lib/pubid/oiml/identifiers/recommendation.rb +2 -0
  348. data/lib/pubid/oiml/identifiers/seminar_report.rb +2 -0
  349. data/lib/pubid/oiml/identifiers/vocabulary.rb +2 -0
  350. data/lib/pubid/oiml/identifiers.rb +1 -0
  351. data/lib/pubid/oiml/parser.rb +1 -1
  352. data/lib/pubid/oiml/single_identifier.rb +26 -42
  353. data/lib/pubid/oiml/supplement_identifier.rb +27 -0
  354. data/lib/pubid/oiml.rb +7 -1
  355. data/lib/pubid/omg/builder.rb +1 -0
  356. data/lib/pubid/omg/identifier.rb +20 -3
  357. data/lib/pubid/omg/parser.rb +64 -11
  358. data/lib/pubid/omg/renderer.rb +13 -1
  359. data/lib/pubid/omg.rb +2 -1
  360. data/lib/pubid/parser/grammar.rb +74 -0
  361. data/lib/pubid/parser.rb +2 -0
  362. data/lib/pubid/parsers/mr_string.rb +19 -0
  363. data/lib/pubid/plateau/parser.rb +1 -1
  364. data/lib/pubid/plateau.rb +10 -0
  365. data/lib/pubid/prefixes_support.rb +1 -0
  366. data/lib/pubid/renderers/annotator.rb +233 -0
  367. data/lib/pubid/renderers/base.rb +13 -0
  368. data/lib/pubid/renderers/directives_renderer.rb +3 -3
  369. data/lib/pubid/renderers/human_readable.rb +3 -3
  370. data/lib/pubid/renderers/mr_string.rb +15 -9
  371. data/lib/pubid/renderers.rb +1 -0
  372. data/lib/pubid/rendering/numbering.rb +25 -7
  373. data/lib/pubid/rendering.rb +1 -0
  374. data/lib/pubid/sae/identifiers/base.rb +9 -2
  375. data/lib/pubid/sae/parser.rb +1 -1
  376. data/lib/pubid/sae.rb +1 -0
  377. data/lib/pubid/schema/declaration.rb +33 -0
  378. data/lib/pubid/schema/error.rb +14 -0
  379. data/lib/pubid/schema/identifier_type.rb +23 -0
  380. data/lib/pubid/schema/loader.rb +117 -0
  381. data/lib/pubid/schema/typed_stage.rb +24 -0
  382. data/lib/pubid/schema.rb +25 -0
  383. data/lib/pubid/tgpp/builder.rb +1 -1
  384. data/lib/pubid/tgpp/identifier.rb +21 -5
  385. data/lib/pubid/tgpp/identifiers/technical_report.rb +2 -2
  386. data/lib/pubid/tgpp/identifiers/technical_specification.rb +2 -2
  387. data/lib/pubid/tgpp/parser.rb +22 -6
  388. data/lib/pubid/tgpp/renderer.rb +21 -5
  389. data/lib/pubid/tgpp/urn_generator.rb +27 -8
  390. data/lib/pubid/tgpp/urn_parser.rb +8 -6
  391. data/lib/pubid/tgpp.rb +7 -1
  392. data/lib/pubid/type_resolver.rb +16 -1
  393. data/lib/pubid/un/identifier.rb +6 -3
  394. data/lib/pubid/un/parser.rb +1 -1
  395. data/lib/pubid/un.rb +1 -0
  396. data/lib/pubid/urn_parser/errors.rb +8 -1
  397. data/lib/pubid/urn_parser.rb +1 -0
  398. data/lib/pubid/utils.rb +1 -0
  399. data/lib/pubid/version.rb +1 -1
  400. data/lib/pubid/w3c/builder.rb +5 -5
  401. data/lib/pubid/w3c/identifier.rb +38 -9
  402. data/lib/pubid/w3c/parser.rb +1 -1
  403. data/lib/pubid/w3c/renderer.rb +1 -1
  404. data/lib/pubid/w3c/urn_generator.rb +2 -2
  405. data/lib/pubid/w3c.rb +1 -0
  406. data/lib/pubid/xsf/identifier.rb +9 -5
  407. data/lib/pubid/xsf/parser.rb +17 -4
  408. data/lib/pubid/xsf.rb +7 -1
  409. data/lib/pubid.rb +399 -21
  410. data/lib/tasks/conformance.rake +34 -0
  411. data/lib/tasks/docs.rake +3 -3
  412. data/lib/tasks/schema.rake +88 -0
  413. data/schema/core/joint_prefixes.yaml +24 -0
  414. data/schema/iec.yaml +1017 -0
  415. data/schema/iso.yaml +1586 -0
  416. data/schema/schema.schema.yaml +96 -0
  417. metadata +38 -17
  418. data/archived-gems/pubid-ccsds/update_codes.yaml +0 -1
  419. data/archived-gems/pubid-iec/stages.yaml +0 -129
  420. data/archived-gems/pubid-iec/update_codes.yaml +0 -67
  421. data/archived-gems/pubid-ieee/update_codes.yaml +0 -104
  422. data/archived-gems/pubid-iso/stages.yaml +0 -106
  423. data/archived-gems/pubid-iso/update_codes.yaml +0 -4
  424. data/archived-gems/pubid-itu/i18n.yaml +0 -13
  425. data/archived-gems/pubid-itu/series.yaml +0 -42
  426. data/archived-gems/pubid-nist/publishers.yaml +0 -6
  427. data/archived-gems/pubid-nist/series.yaml +0 -121
  428. data/archived-gems/pubid-nist/update_codes.yaml +0 -93
  429. data/archived-gems/pubid-plateau/update_codes.yaml +0 -6
  430. data/lib/pubid/cen_cenelec/supplement_identifier.rb +0 -48
  431. data/lib/pubid/iec/components/code.rb +0 -36
  432. /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
@@ -5,34 +5,43 @@ module Pubid
5
5
  module Identifiers
6
6
  # Consolidated Identifier - contains base document plus supplements
7
7
  # Example: "EN 196-3:2005+A1:2008" = [EN 196-3:2005, Amendment(base + params)]
8
- class ConsolidatedIdentifier < Base
9
- attribute :identifiers, Base, polymorphic: true, collection: true
8
+ #
9
+ # It descends from the shared Pubid::CenCenelec::Identifier, not from
10
+ # the legacy Identifiers::Base. It used to inherit Base's publisher,
11
+ # number, year, parts and type attributes and to override each of them
12
+ # with a reader that delegated to the first member. `#exclude` and the
13
+ # serializer read every attribute through its reader, so they reached
14
+ # `EuropeanNorm#parts`, which does not exist, and raised. Read the base
15
+ # document through #base_document instead.
16
+ class ConsolidatedIdentifier < Pubid::CenCenelec::Identifier
17
+ attribute :identifiers, Pubid::CenCenelec::Identifier,
18
+ polymorphic: true, collection: true
10
19
 
11
- # Delegate to first identifier (base document)
12
- def publisher
13
- identifiers&.first&.publisher
20
+ # The origin document. Members live in `identifiers` (not `base`), so
21
+ # walk the first member to its root.
22
+ def root
23
+ identifiers&.first&.root || self
14
24
  end
15
25
 
16
- def number
17
- identifiers&.first&.number
26
+ def base_document
27
+ identifiers&.first&.base_document || self
18
28
  end
19
29
 
20
- def year
21
- identifiers&.first&.year
30
+ # Dropping the supplement layer yields the base standard alone.
31
+ def drop_supplements
32
+ identifiers&.first || self
22
33
  end
23
34
 
24
- def parts
25
- identifiers&.first&.parts
26
- end
35
+ # "en.285.2015_plus-amd.1.2021": the base document, then each member's
36
+ # own supplement suffix behind a "plus" marker, so the consolidated
37
+ # form does not share a slug with the standalone "EN 285:2015/A1:2021".
38
+ def to_mr_string
39
+ base, *supplements = identifiers
40
+ return "" unless base
27
41
 
28
- def type
29
- identifiers&.first&.type
30
- end
31
-
32
- # The origin document. Members live in `identifiers` (not `base`), so
33
- # walk the first member to its root.
34
- def root
35
- identifiers&.first&.root || self
42
+ ([base.to_mr_string] +
43
+ supplements.map { |s| "plus-#{s.mr_supplement_suffix}" })
44
+ .join(Renderers::MrString::SEPARATOR_SUPPLEMENT)
36
45
  end
37
46
  end
38
47
  end
@@ -5,14 +5,53 @@ module Pubid
5
5
  module Identifiers
6
6
  # Corrigendum Identifier
7
7
  # Contains a base identifier plus corrigendum parameters
8
- class Corrigendum < Base
9
- attribute :base, Base, polymorphic: true
10
- attribute :corrigendum_number, :string
11
- attribute :corrigendum_year, :integer
12
- attribute :corrigendum_month, :string
13
-
14
- def publisher
15
- base&.publisher
8
+ #
9
+ # Like Amendment, it descends from the shared
10
+ # Pubid::CenCenelec::Identifier and not from the legacy Identifiers::Base,
11
+ # and it keeps its date in `year` and `month` strings:
12
+ # {"base" => {…}, "year" => "2016", "month" => "11"}. An unnumbered
13
+ # "/AC" has no `number`.
14
+ class Corrigendum < Pubid::CenCenelec::Identifier
15
+ attribute :base, Pubid::CenCenelec::Identifier, polymorphic: true
16
+ attribute :year, :string
17
+ attribute :month, :string
18
+
19
+ def self.supplement_date_attributes
20
+ %i[year month]
21
+ end
22
+
23
+ def base_document
24
+ base&.base_document || self
25
+ end
26
+
27
+ # Dropping the supplement layer yields the base standard.
28
+ def drop_supplements
29
+ base || self
30
+ end
31
+
32
+ # Uniform supplement interface (shared with Amendment and with BSI)
33
+ # so callers need not special-case the class.
34
+ def supplement_type
35
+ :corrigendum
36
+ end
37
+
38
+ def supplement_number
39
+ number
40
+ end
41
+
42
+ def supplement_year
43
+ year
44
+ end
45
+
46
+ # The date part of the supplement: "2016-11", "2003", or nil.
47
+ def supplement_date
48
+ return nil unless year
49
+
50
+ [year, month].compact.reject(&:empty?).join("-")
51
+ end
52
+
53
+ def mr_supplement_suffix
54
+ mr_join_segments("cor", number, supplement_date)
16
55
  end
17
56
  end
18
57
  end
@@ -6,8 +6,8 @@ module Pubid
6
6
  module CenCenelec
7
7
  module Identifiers
8
8
  class EuropeanPrestandard < SingleIdentifier
9
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
10
- attribute :adopted_identifier, Pubid::Identifier, polymorphic: true
9
+ attribute :type, Components::Type, default: -> { self.class.default_type }
10
+ attribute :adopted, Pubid::Identifier, polymorphic: true
11
11
 
12
12
  TYPED_STAGES = [
13
13
  Components::TypedStage.new(
@@ -25,6 +25,31 @@ module Pubid
25
25
  web: :european_prestandard, title: "European Prestandard", short: "ENV" }
26
26
  end
27
27
 
28
+ # An "ENV ISO 11079:1999" is a WRAPPER: the whole document identity
29
+ # lives on the nested `adopted`, and this class carries no
30
+ # number of its own, so `root.number` — the key relaton-index sorts and
31
+ # bsearches on — was "". Walk to the adopted document instead.
32
+ #
33
+ # The chain reached further than this flavor: Bsi's
34
+ # `AdoptedEuropeanNorm#number` delegates INTO this class, so a
35
+ # "DD ENV ISO 11079:1999" keyed "" for the same reason.
36
+ #
37
+ # This is deliberately `#root` and not a `#number` method. `number` is a
38
+ # lutaml attribute in this hierarchy, and a method of that name collides
39
+ # with the generated accessor and corrupts attribute resolution
40
+ # hierarchy-wide (the IEEE landmine in CLAUDE.md). `#root` is a plain
41
+ # method on ::Pubid::Identifier, and walking a wrapper's member is its
42
+ # documented shape — ConsolidatedIdentifier already walks
43
+ # `identifiers.first.root`.
44
+ def root
45
+ adopted ? adopted.root : self
46
+ end
47
+
48
+ # MR "env.iso.11079.1999": an adoption puts the adopted document's MR
49
+ # string where the number goes, as AdoptedEuropeanNorm does.
50
+ def mr_number_with_part
51
+ adopted ? adopted.to_mr_string : super
52
+ end
28
53
  end
29
54
  end
30
55
  end
@@ -6,7 +6,7 @@ module Pubid
6
6
  module CenCenelec
7
7
  module Identifiers
8
8
  class EuropeanSpecification < SingleIdentifier
9
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
9
+ attribute :type, Components::Type, default: -> { self.class.default_type }
10
10
 
11
11
  TYPED_STAGES = [
12
12
  Components::TypedStage.new(
@@ -5,12 +5,22 @@ module Pubid
5
5
  module Identifiers
6
6
  # Fragment Identifier - wraps an Amendment with a fragment number
7
7
  # Example: "EN 60038 AMD1 FRAG2" = Fragment 2 of Amendment 1 to EN 60038
8
- class Fragment < Base
9
- attribute :base, Amendment
10
- attribute :fragment_number, :string
8
+ #
9
+ # The fragment number is the inherited `number`, as for a supplement.
10
+ class Fragment < Pubid::CenCenelec::Identifier
11
+ attribute :base, Pubid::CenCenelec::Identifier, polymorphic: true
11
12
 
12
- def publisher
13
- base&.base&.publisher
13
+ def base_document
14
+ base&.base_document || self
15
+ end
16
+
17
+ # Dropping the fragment layer yields the amendment it is part of.
18
+ def drop_supplements
19
+ base || self
20
+ end
21
+
22
+ def mr_supplement_suffix
23
+ mr_join_segments("frag", number)
14
24
  end
15
25
  end
16
26
  end
@@ -5,7 +5,7 @@ module Pubid
5
5
  module CenCenelec
6
6
  module Identifiers
7
7
  class Guide < SingleIdentifier
8
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
8
+ attribute :type, Components::Type, default: -> { self.class.default_type }
9
9
 
10
10
  TYPED_STAGES = [
11
11
  Components::TypedStage.new(
@@ -5,7 +5,7 @@ module Pubid
5
5
  module CenCenelec
6
6
  module Identifiers
7
7
  class HarmonizationDocument < SingleIdentifier
8
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
8
+ attribute :type, Components::Type, default: -> { self.class.default_type }
9
9
 
10
10
  TYPED_STAGES = [
11
11
  Components::TypedStage.new(
@@ -5,7 +5,7 @@ module Pubid
5
5
  module CenCenelec
6
6
  module Identifiers
7
7
  class TechnicalReport < SingleIdentifier
8
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
8
+ attribute :type, Components::Type, default: -> { self.class.default_type }
9
9
 
10
10
  TYPED_STAGES = [
11
11
  Components::TypedStage.new(
@@ -5,7 +5,7 @@ module Pubid
5
5
  module CenCenelec
6
6
  module Identifiers
7
7
  class TechnicalSpecification < SingleIdentifier
8
- attribute :type, Components::Type, default: -> { self.class.type[:key] }
8
+ attribute :type, Components::Type, default: -> { self.class.default_type }
9
9
 
10
10
  TYPED_STAGES = [
11
11
  Components::TypedStage.new(
@@ -4,7 +4,7 @@ require "parslet"
4
4
 
5
5
  module Pubid
6
6
  module CenCenelec
7
- class Parser < Parslet::Parser
7
+ class Parser < ::Pubid::Parser::Grammar
8
8
  rule(:digit) { match["0-9"] }
9
9
  rule(:digits) { digit.repeat(1) }
10
10
  rule(:space) { str(" ") }
@@ -51,8 +51,7 @@ module Pubid
51
51
  parts = []
52
52
 
53
53
  # Check if we have a draft stage (prEN, FprEN) - these include both stage and type
54
- is_draft_stage = id.typed_stage&.abbr && %w[prEN
55
- FprEN].include?(id.typed_stage.abbr.first)
54
+ is_draft_stage = !draft_stage_abbr(id).nil?
56
55
 
57
56
  # Get type short name - for draft stages, extract base type
58
57
  type_short = if is_draft_stage
@@ -68,8 +67,8 @@ module Pubid
68
67
  # Track if we should use slash before type
69
68
  use_slash_before_type = false
70
69
 
71
- # For CWA/HD, they act as publisher (not EN)
72
- if %w[CWA HD CR].include?(type_short)
70
+ # CWA, HD, ES, CR and ENV act as the publisher (not EN)
71
+ if CenCenelec::PUBLISHER_TYPES.include?(type_short)
73
72
  # Stage prefix OR type as publisher
74
73
  parts << if id.typed_stage&.abbr && id.typed_stage.abbr.first != type_short
75
74
  id.typed_stage.abbr.first
@@ -96,8 +95,10 @@ module Pubid
96
95
  end
97
96
  end
98
97
 
99
- # Type for non-EN documents (TS, TR) - but not CWA/HD or Guide
100
- if type_short != "EN" && !%w[CWA HD CR Guide].include?(type_short)
98
+ # Type for non-EN documents (TS, TR) - but not the publisher-types
99
+ # or Guide
100
+ if type_short != "EN" && type_short != "Guide" &&
101
+ !CenCenelec::PUBLISHER_TYPES.include?(type_short)
101
102
  if use_slash_before_type && parts.any?
102
103
  # Use slash separator for publisher/type combination (TS, TR only)
103
104
  parts << "/#{type_short}"
@@ -111,9 +112,9 @@ module Pubid
111
112
 
112
113
  # Number with part (which may be multi-level like "5-1-1")
113
114
  if id.number
114
- number_str = id.number.render(context: @context)
115
+ number_str = id.number
115
116
  if id.part
116
- number_str += "-#{id.part.render(context: @context)}"
117
+ number_str += "-#{id.part}"
117
118
  end
118
119
  parts << number_str
119
120
  end
@@ -136,6 +137,13 @@ module Pubid
136
137
  result
137
138
  end
138
139
 
140
+ # "prEN" or "FprEN" when +id+ has that draft stage, else nil. A draft
141
+ # stage prints in place of the publisher.
142
+ def draft_stage_abbr(id)
143
+ abbr = id.typed_stage&.abbr&.first
144
+ abbr if %w[prEN FprEN].include?(abbr)
145
+ end
146
+
139
147
  # CEN Identifiers::Base: simple key-value model
140
148
  # Format: {PUBLISHER} NUMBER[-PART]:YEAR
141
149
  def render_cen_base(id)
@@ -148,10 +156,10 @@ module Pubid
148
156
  result += id.publisher.join("/")
149
157
  end
150
158
 
151
- # If we have adopted_identifier, render it (contains all info)
152
- if id.adopted_identifier
153
- result += " #{id.adopted_identifier}"
154
- # Don't add our own number/parts/year - they're in adopted_identifier
159
+ # If we have adopted, render it (contains all info)
160
+ if id.adopted
161
+ result += " #{id.adopted}"
162
+ # Don't add our own number/parts/year - they're in adopted
155
163
  else
156
164
  # Only render our own fields if no adoption
157
165
  # Type - use space for Guide, slash for TR/TS
@@ -181,77 +189,64 @@ module Pubid
181
189
  result
182
190
  end
183
191
 
184
- # AdoptedEuropeanNorm: "EN ISO 8601:2019"
192
+ # AdoptedEuropeanNorm: "EN ISO 8601:2019", "CEN/CLC ISO/IEC 17000",
193
+ # "prEN ISO 1234:2020" (a draft stage prints in place of "EN")
185
194
  def render_adopted_european_norm(id)
186
- result = id.publisher.is_a?(Array) ? id.publisher.join("/") : id.publisher.join("/")
187
- result += " #{id.adopted_identifier}" if id.adopted_identifier
195
+ publishers = ([id.publisher] + Array(id.copublishers)).compact
196
+ .map { |p| p.render(context: @context) }
197
+ draft = draft_stage_abbr(id)
198
+ publishers[0] = draft if draft
199
+ result = publishers.join("/")
200
+ result += " #{id.adopted}" if id.adopted
188
201
  result
189
202
  end
190
203
 
191
204
  # Amendment: "EN 196-3:2005/A1:2008"
192
205
  def render_amendment(id)
193
- result = if id.base
194
- "#{id.base}/A#{id.amendment_number}"
195
- else
196
- "/A#{id.amendment_number}"
197
- end
198
- result += ":#{id.amendment_year}" if id.amendment_year
199
- result
206
+ "#{id.base}/#{supplement_token(id)}"
200
207
  end
201
208
 
202
- # Corrigendum: "EN 60038/AC1:2012"
209
+ # Corrigendum: "EN 60038/AC1:2012", "EN 61375-2-3:2015/AC:2016-11"
203
210
  def render_corrigendum(id)
204
- if id.base
205
- result = id.base.to_s
206
- result += "/AC"
207
- result += id.corrigendum_number if id.corrigendum_number && !id.corrigendum_number.empty?
208
- else
209
- result = "/AC#{id.corrigendum_number}"
210
- end
211
- if id.corrigendum_year
212
- result += ":#{id.corrigendum_year}"
213
- result += "-#{id.corrigendum_month}" if id.corrigendum_month && !id.corrigendum_month.empty?
214
- end
215
- result
211
+ "#{id.base}/#{supplement_token(id)}"
216
212
  end
217
213
 
218
- # ConsolidatedIdentifier: "EN 196-3:2005+A1:2008"
214
+ # ConsolidatedIdentifier: "EN 196-3:2005+A1:2008". The first member is
215
+ # the base document; the others are supplements with no base.
219
216
  def render_consolidated(id)
220
- id.identifiers.map.with_index do |sub_id, idx|
221
- if idx.zero?
222
- # First identifier renders normally
223
- sub_id.to_s
224
- elsif sub_id.is_a?(Identifiers::Amendment)
225
- # Supplements render with "+" prefix (bundled/consolidated format)
226
- result = "+A#{sub_id.amendment_number}"
227
- result += ":#{sub_id.amendment_year}" if sub_id.amendment_year
228
- result
229
- # Only render the amendment portion, not the full id.to_s
230
- elsif sub_id.is_a?(Identifiers::Corrigendum)
231
- # Only render the corrigendum portion
232
- result = "+AC"
233
- result += sub_id.corrigendum_number if sub_id.corrigendum_number && !sub_id.corrigendum_number.empty?
234
- if sub_id.corrigendum_year
235
- result += ":#{sub_id.corrigendum_year}"
236
- result += "-#{sub_id.corrigendum_month}" if sub_id.corrigendum_month && !sub_id.corrigendum_month.empty?
237
- end
238
- result
217
+ base, *supplements = id.identifiers
218
+ base.to_s + supplements.map do |sub_id|
219
+ if sub_id.is_a?(Identifiers::Amendment) ||
220
+ sub_id.is_a?(Identifiers::Corrigendum)
221
+ "+#{supplement_token(sub_id)}"
239
222
  else
240
- # Other identifiers (should not happen in typical bundles) render with +
223
+ # Other identifiers (should not happen in typical bundles)
241
224
  "+#{sub_id}"
242
225
  end
243
- end.compact.join
226
+ end.join
227
+ end
228
+
229
+ # The supplement without its base: "A1:2008", "AC1:2012",
230
+ # "AC:2016-11" (an unnumbered corrigendum).
231
+ def supplement_token(id)
232
+ prefix = id.is_a?(Identifiers::Corrigendum) ? "AC" : "A"
233
+ result = "#{prefix}#{id.number}"
234
+ return result unless id.year
235
+
236
+ result += ":#{id.year}"
237
+ result += "-#{id.month}" if id.respond_to?(:month) && id.month
238
+ result
244
239
  end
245
240
 
246
241
  # Fragment: "EN 60038 AMD1 FRAG2"
247
242
  def render_fragment(id)
248
- "#{id.base} FRAG#{id.fragment_number}"
243
+ "#{id.base} FRAG#{id.number}"
249
244
  end
250
245
 
251
246
  # EuropeanPrestandard: "ENV ISO 8601" or falls through to SingleIdentifier
252
247
  def render_european_prestandard(id, **opts)
253
- if id.adopted_identifier
254
- "ENV #{id.adopted_identifier}"
248
+ if id.adopted
249
+ "ENV #{id.adopted}"
255
250
  else
256
251
  render_single(id)
257
252
  end
@@ -7,7 +7,7 @@ module Pubid
7
7
  # concrete type is `is_a?` it.
8
8
  class SingleIdentifier < Pubid::CenCenelec::Identifier
9
9
  attribute :publisher, Components::Publisher, default: -> {
10
- Components::Publisher.new(body: "EN")
10
+ self.class.default_publisher
11
11
  }
12
12
 
13
13
  # Generate URN for this identifier
@@ -18,6 +18,24 @@ module Pubid
18
18
  nil
19
19
  end
20
20
 
21
+ # The `publisher` default: the type token for a publisher-type
22
+ # ("CWA 14050", "HD 1215", "CR 954", "ES 59008", "ENV 1613"), else EN.
23
+ # `to_hash` leaves out a value equal to its default, so the publisher
24
+ # of those five is not written: `_type` already names it.
25
+ def self.default_publisher
26
+ short = type.is_a?(Hash) ? type[:short] : nil
27
+ body = CenCenelec::PUBLISHER_TYPES.include?(short) ? short : "EN"
28
+ Components::Publisher.new(body: body)
29
+ end
30
+
31
+ # The `type` default of a typed leaf. It is a Components::Type, like
32
+ # the value the parser sets for "CEN/TR", so a document with no type
33
+ # token deserializes the same way it parses. The default used to be the
34
+ # bare Symbol `type[:key]`, and from_hash raised on it.
35
+ def self.default_type
36
+ Components::Type.new(abbr: type[:short])
37
+ end
38
+
21
39
  def to_s(lang: :en, lang_single: false, **opts)
22
40
  render(format: :human, lang: lang, lang_single: lang_single, **opts)
23
41
  end
@@ -30,7 +48,7 @@ module Pubid
30
48
  return num_cmp unless num_cmp.zero?
31
49
 
32
50
  # Then by part
33
- part_cmp = (part || Components::Code.new(value: "0")).to_s <=> (other.part || Components::Code.new(value: "0")).to_s
51
+ part_cmp = (part || "0").to_s <=> (other.part || "0").to_s
34
52
  return part_cmp unless part_cmp.zero?
35
53
 
36
54
  # Then by date
@@ -4,14 +4,76 @@ module Pubid
4
4
  module CenCenelec
5
5
  class UrnGenerator < Pubid::UrnGenerator::Base
6
6
  def generate
7
- if identifier.is_a?(CenCenelec::SupplementIdentifier)
8
- generate_supplement_urn
7
+ urn_for(identifier)
8
+ end
9
+
10
+ protected
11
+
12
+ # The URN of +id+, walking the wrapper structure:
13
+ # EN 13250:2000/A1:2005 urn:cen:en:13250:2000:amd:1:2005
14
+ # EN 285:2015+A1:2021 urn:cen:en:285:2015:plus:amd:1:2021
15
+ # EN 60038 AMD1 FRAG2 urn:cen:en:60038:amd:1:frag:2
16
+ # CEN ISO/TS 21003-7:2019 urn:cen:cen:iso:ts:21003-7:2019
17
+ # ENV ISO 11079:1999 urn:cen:env:iso:11079:1999
18
+ # prEN ISO 1234:2020 urn:cen:en:iso:1234:2020:stage.proposal
19
+ # The "plus" marker keeps a consolidated identifier apart from the
20
+ # standalone amendment with the same number and year.
21
+ def urn_for(id)
22
+ case id
23
+ when nil
24
+ "urn:cen"
25
+ when Identifiers::Amendment, Identifiers::Corrigendum,
26
+ Identifiers::Fragment
27
+ [urn_for(id.base), *supplement_segments(id)].join(":")
28
+ when Identifiers::ConsolidatedIdentifier
29
+ base, *supplements = id.identifiers
30
+ [urn_for(base), *supplements.flat_map do |s|
31
+ ["plus", *supplement_segments(s)]
32
+ end].join(":")
9
33
  else
10
- generate_base_urn
34
+ if adoption?(id)
35
+ # The publisher, then the adopted document's MR string with its
36
+ # dot and underscore separators as colons, then a draft stage as
37
+ # the base URN writes it.
38
+ body = [id.mr_publisher, id.adopted&.to_mr_string]
39
+ .compact.reject(&:empty?).join(".").tr("._", "::")
40
+ ["urn:cen:#{body}", *stage_segment(id)].join(":")
41
+ else
42
+ self.class.new(id).generate_base_urn
43
+ end
11
44
  end
12
45
  end
13
46
 
14
- protected
47
+ # "EN ISO 8601:2019" or "ENV ISO 11079:1999": the document identity is
48
+ # on the adopted ISO/IEC identifier, not on this one.
49
+ def adoption?(id)
50
+ id.is_a?(Identifiers::AdoptedEuropeanNorm) ||
51
+ (id.is_a?(Identifiers::EuropeanPrestandard) && id.adopted)
52
+ end
53
+
54
+ # ["stage.proposal"] for a draft stage, [] for a published document.
55
+ def stage_segment(id)
56
+ code = id.typed_stage&.stage_code
57
+ return [] if code.nil? || code.to_s == "published"
58
+
59
+ ["stage.#{code}"]
60
+ end
61
+
62
+ # The segments that a supplement adds to its base: type, number (none
63
+ # for an unnumbered "/AC"), then the date.
64
+ def supplement_segments(id)
65
+ segments = case id
66
+ when Identifiers::Amendment
67
+ ["amd", id.number, id.year]
68
+ when Identifiers::Corrigendum
69
+ ["cor", id.number, id.supplement_date]
70
+ when Identifiers::Fragment
71
+ ["frag", id.number]
72
+ else
73
+ []
74
+ end
75
+ segments.map(&:to_s).reject(&:empty?)
76
+ end
15
77
 
16
78
  def generate_base_urn
17
79
  parts = ["urn", "cen"]
@@ -75,46 +137,6 @@ module Pubid
75
137
  parts.join(":")
76
138
  end
77
139
 
78
- def generate_supplement_urn
79
- parts = ["urn", "cen"]
80
-
81
- base_id = maybe(:base)
82
- if base_id
83
- base_gen = self.class.new(base_id)
84
- base_urn = base_gen.generate_base_urn
85
-
86
- base_part = base_urn.sub(/^urn:cen:/, "")
87
- base_parts = base_part.split(":")
88
-
89
- parts.concat(base_parts)
90
-
91
- typed_stage = maybe(:typed_stage)
92
- if typed_stage
93
- supp_type = typed_stage.type_code.to_s
94
- parts << supp_type if supp_type
95
- end
96
-
97
- amendment_number = maybe(:amendment_number)
98
- if amendment_number
99
- parts << amendment_number.to_s
100
- elsif identifier.number
101
- number = identifier.number.to_s
102
- parts << number
103
- end
104
-
105
- amendment_year = maybe(:amendment_year)
106
- if amendment_year
107
- parts << amendment_year.to_s
108
- elsif identifier.date&.is_a?(::Pubid::Components::Date) && identifier.date.present?
109
- parts << identifier.date.render(context: URN_CONTEXT)
110
- end
111
- else
112
- parts << "unknown"
113
- end
114
-
115
- parts.join(":")
116
- end
117
-
118
140
  def type_component
119
141
  typed_stage = maybe(:typed_stage)
120
142
  return nil unless typed_stage