pubid 2.0.0.pre.alpha.9 → 2.0.0.pre.alpha.12

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 (461) 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/components/date.rb +10 -4
  82. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +36 -7
  83. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +7 -6
  84. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +1 -2
  85. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +10 -0
  86. data/lib/pubid/bsi/identifiers/committee_document.rb +10 -1
  87. data/lib/pubid/bsi/identifiers/handbook.rb +1 -3
  88. data/lib/pubid/bsi/identifiers/practice_guide.rb +1 -2
  89. data/lib/pubid/bsi/identifiers/set.rb +11 -0
  90. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +10 -1
  91. data/lib/pubid/bsi/parser.rb +1 -1
  92. data/lib/pubid/bsi/renderer.rb +63 -51
  93. data/lib/pubid/bsi/single_identifier.rb +27 -9
  94. data/lib/pubid/bsi/urn_generator.rb +11 -2
  95. data/lib/pubid/bsi.rb +7 -1
  96. data/lib/pubid/builder/base.rb +18 -8
  97. data/lib/pubid/bundled_identifier.rb +16 -6
  98. data/lib/pubid/calconnect/identifier.rb +9 -5
  99. data/lib/pubid/calconnect/parser.rb +1 -1
  100. data/lib/pubid/calconnect.rb +7 -1
  101. data/lib/pubid/ccsds/identifier.rb +13 -2
  102. data/lib/pubid/ccsds/identifiers/base.rb +4 -2
  103. data/lib/pubid/ccsds/identifiers/corrigendum.rb +2 -2
  104. data/lib/pubid/ccsds/parser.rb +1 -1
  105. data/lib/pubid/ccsds/single_identifier.rb +16 -12
  106. data/lib/pubid/ccsds.rb +1 -0
  107. data/lib/pubid/cen_cenelec/builder.rb +101 -76
  108. data/lib/pubid/cen_cenelec/identifier.rb +115 -3
  109. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +27 -16
  110. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +46 -6
  111. data/lib/pubid/cen_cenelec/identifiers/base.rb +8 -9
  112. data/lib/pubid/cen_cenelec/identifiers/cen_report.rb +1 -1
  113. data/lib/pubid/cen_cenelec/identifiers/cen_workshop_agreement.rb +1 -1
  114. data/lib/pubid/cen_cenelec/identifiers/cenelec_harmonization_document.rb +1 -1
  115. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +29 -20
  116. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +47 -8
  117. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +27 -2
  118. data/lib/pubid/cen_cenelec/identifiers/european_specification.rb +1 -1
  119. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +15 -5
  120. data/lib/pubid/cen_cenelec/identifiers/guide.rb +1 -1
  121. data/lib/pubid/cen_cenelec/identifiers/harmonization_document.rb +1 -1
  122. data/lib/pubid/cen_cenelec/identifiers/technical_report.rb +1 -1
  123. data/lib/pubid/cen_cenelec/identifiers/technical_specification.rb +1 -1
  124. data/lib/pubid/cen_cenelec/parser.rb +1 -1
  125. data/lib/pubid/cen_cenelec/renderer.rb +55 -60
  126. data/lib/pubid/cen_cenelec/single_identifier.rb +20 -2
  127. data/lib/pubid/cen_cenelec/urn_generator.rb +66 -44
  128. data/lib/pubid/cen_cenelec.rb +28 -10
  129. data/lib/pubid/cie/builder.rb +10 -0
  130. data/lib/pubid/cie/identifier.rb +6 -1
  131. data/lib/pubid/cie/identifiers/bundle.rb +4 -2
  132. data/lib/pubid/cie/identifiers/conference.rb +2 -2
  133. data/lib/pubid/cie/identifiers/corrigendum.rb +2 -2
  134. data/lib/pubid/cie/identifiers/dual_published.rb +2 -2
  135. data/lib/pubid/cie/identifiers/identical.rb +2 -2
  136. data/lib/pubid/cie/identifiers/joint_published.rb +2 -2
  137. data/lib/pubid/cie/identifiers/proceedings.rb +8 -6
  138. data/lib/pubid/cie/identifiers/standard.rb +22 -13
  139. data/lib/pubid/cie/identifiers/supplement.rb +2 -2
  140. data/lib/pubid/cie/identifiers/tutorial_bundle.rb +2 -2
  141. data/lib/pubid/cie/parser.rb +1 -1
  142. data/lib/pubid/cie.rb +7 -1
  143. data/lib/pubid/conformance/checks.rb +72 -0
  144. data/lib/pubid/conformance/corpus/case.rb +55 -0
  145. data/lib/pubid/conformance/corpus.rb +36 -0
  146. data/lib/pubid/conformance/generator.rb +212 -0
  147. data/lib/pubid/conformance/pending.rb +63 -0
  148. data/lib/pubid/conformance/runner.rb +153 -0
  149. data/lib/pubid/conformance.rb +55 -0
  150. data/lib/pubid/core.rb +2 -0
  151. data/lib/pubid/csa/builder.rb +47 -47
  152. data/lib/pubid/csa/composite_identifier.rb +14 -19
  153. data/lib/pubid/csa/identifier.rb +143 -81
  154. data/lib/pubid/csa/identifiers/bundled.rb +23 -13
  155. data/lib/pubid/csa/identifiers/canadian_adopted.rb +13 -13
  156. data/lib/pubid/csa/identifiers/cec.rb +44 -4
  157. data/lib/pubid/csa/identifiers/combined.rb +95 -73
  158. data/lib/pubid/csa/identifiers/csa_adopted.rb +4 -4
  159. data/lib/pubid/csa/identifiers/package.rb +2 -2
  160. data/lib/pubid/csa/parser.rb +6 -2
  161. data/lib/pubid/csa/renderer.rb +13 -5
  162. data/lib/pubid/csa/single_identifier.rb +93 -4
  163. data/lib/pubid/csa/urn_generator.rb +9 -2
  164. data/lib/pubid/csa/wrapper_identifier.rb +39 -23
  165. data/lib/pubid/csa.rb +7 -1
  166. data/lib/pubid/doi/identifier.rb +6 -3
  167. data/lib/pubid/doi/parser.rb +1 -1
  168. data/lib/pubid/doi.rb +1 -0
  169. data/lib/pubid/easc/identifier.rb +0 -2
  170. data/lib/pubid/easc/parser.rb +10 -2
  171. data/lib/pubid/easc.rb +1 -0
  172. data/lib/pubid/ecma/builder.rb +23 -9
  173. data/lib/pubid/ecma/identifier.rb +81 -10
  174. data/lib/pubid/ecma/parser.rb +39 -4
  175. data/lib/pubid/ecma/renderer.rb +29 -8
  176. data/lib/pubid/ecma/urn_generator.rb +34 -13
  177. data/lib/pubid/ecma/urn_parser.rb +30 -14
  178. data/lib/pubid/ecma.rb +1 -0
  179. data/lib/pubid/errors.rb +80 -0
  180. data/lib/pubid/etsi/builder.rb +6 -1
  181. data/lib/pubid/etsi/identifiers/base.rb +34 -20
  182. data/lib/pubid/etsi/identifiers/etsi_standard.rb +120 -41
  183. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +10 -0
  184. data/lib/pubid/etsi/parser.rb +1 -1
  185. data/lib/pubid/etsi.rb +1 -0
  186. data/lib/pubid/evs/builder.rb +26 -0
  187. data/lib/pubid/evs/identifier.rb +37 -0
  188. data/lib/pubid/evs/identifiers/national_adoption.rb +22 -0
  189. data/lib/pubid/evs/identifiers.rb +9 -0
  190. data/lib/pubid/evs/parser.rb +27 -0
  191. data/lib/pubid/evs/renderer.rb +30 -0
  192. data/lib/pubid/evs/urn_generator.rb +30 -0
  193. data/lib/pubid/evs/urn_parser.rb +80 -0
  194. data/lib/pubid/evs.rb +90 -0
  195. data/lib/pubid/export.rb +1 -0
  196. data/lib/pubid/format_detector.rb +1 -0
  197. data/lib/pubid/gb/builder.rb +14 -9
  198. data/lib/pubid/gb/identifier.rb +29 -7
  199. data/lib/pubid/gb/parser.rb +5 -1
  200. data/lib/pubid/gb/renderer.rb +4 -3
  201. data/lib/pubid/gb.rb +2 -0
  202. data/lib/pubid/gost/builder.rb +46 -9
  203. data/lib/pubid/gost/identifier.rb +0 -2
  204. data/lib/pubid/gost/identifiers/foreign_reference.rb +1 -1
  205. data/lib/pubid/gost/parser.rb +10 -2
  206. data/lib/pubid/gost.rb +1 -0
  207. data/lib/pubid/iala/identifier.rb +9 -6
  208. data/lib/pubid/iala/parser.rb +10 -2
  209. data/lib/pubid/iala/urn_parser.rb +6 -2
  210. data/lib/pubid/iala.rb +1 -0
  211. data/lib/pubid/iana/builder.rb +3 -1
  212. data/lib/pubid/iana/identifier.rb +74 -6
  213. data/lib/pubid/iana/identifiers/registry.rb +36 -0
  214. data/lib/pubid/iana/parser.rb +1 -1
  215. data/lib/pubid/iana/renderer.rb +3 -0
  216. data/lib/pubid/iana/urn_generator.rb +5 -1
  217. data/lib/pubid/iana.rb +1 -0
  218. data/lib/pubid/identifier.rb +605 -13
  219. data/lib/pubid/identifier_metadata.rb +1 -0
  220. data/lib/pubid/idf/builder.rb +3 -3
  221. data/lib/pubid/idf/identifier.rb +25 -9
  222. data/lib/pubid/idf/identifiers/amendment.rb +1 -1
  223. data/lib/pubid/idf/identifiers/corrigendum.rb +1 -1
  224. data/lib/pubid/idf/identifiers/international_standard.rb +1 -1
  225. data/lib/pubid/idf/identifiers/reviewed_method.rb +1 -1
  226. data/lib/pubid/idf/parser.rb +1 -1
  227. data/lib/pubid/idf/renderer.rb +4 -4
  228. data/lib/pubid/idf/single_identifier.rb +1 -1
  229. data/lib/pubid/idf/urn_generator.rb +1 -1
  230. data/lib/pubid/idf.rb +7 -1
  231. data/lib/pubid/iec/builder.rb +14 -7
  232. data/lib/pubid/iec/components.rb +0 -1
  233. data/lib/pubid/iec/identifier.rb +73 -83
  234. data/lib/pubid/iec/identifiers/amendment.rb +6 -2
  235. data/lib/pubid/iec/identifiers/component_specification.rb +0 -10
  236. data/lib/pubid/iec/identifiers/conformity_assessment.rb +0 -10
  237. data/lib/pubid/iec/identifiers/corrigendum.rb +2 -2
  238. data/lib/pubid/iec/identifiers/fragment_identifier.rb +2 -4
  239. data/lib/pubid/iec/identifiers/guide.rb +0 -16
  240. data/lib/pubid/iec/identifiers/international_standard.rb +15 -2
  241. data/lib/pubid/iec/identifiers/operational_document.rb +0 -10
  242. data/lib/pubid/iec/identifiers/publicly_available_specification.rb +0 -12
  243. data/lib/pubid/iec/identifiers/societal_technology_trend_report.rb +0 -10
  244. data/lib/pubid/iec/identifiers/systems_reference_document.rb +0 -10
  245. data/lib/pubid/iec/identifiers/technical_report.rb +0 -17
  246. data/lib/pubid/iec/identifiers/technical_specification.rb +0 -17
  247. data/lib/pubid/iec/identifiers/technology_report.rb +0 -10
  248. data/lib/pubid/iec/identifiers/test_report_form.rb +0 -11
  249. data/lib/pubid/iec/identifiers/white_paper.rb +0 -10
  250. data/lib/pubid/iec/identifiers/working_document.rb +24 -10
  251. data/lib/pubid/iec/parser.rb +2 -18
  252. data/lib/pubid/iec/renderer.rb +13 -10
  253. data/lib/pubid/iec/single_identifier.rb +33 -10
  254. data/lib/pubid/iec/urn_generator.rb +227 -61
  255. data/lib/pubid/iec/urn_parser.rb +42 -4
  256. data/lib/pubid/iec.rb +1 -0
  257. data/lib/pubid/ieee/aiee/identifier.rb +2 -2
  258. data/lib/pubid/ieee/aiee/parser.rb +1 -1
  259. data/lib/pubid/ieee/builder.rb +87 -3
  260. data/lib/pubid/ieee/identifiers/adopted_standard.rb +32 -0
  261. data/lib/pubid/ieee/identifiers/base.rb +42 -5
  262. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +21 -0
  263. data/lib/pubid/ieee/identifiers/dual_published.rb +55 -0
  264. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +23 -0
  265. data/lib/pubid/ieee/identifiers/joint_development.rb +11 -7
  266. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +57 -5
  267. data/lib/pubid/ieee/identifiers/nesc/base.rb +2 -2
  268. data/lib/pubid/ieee/identifiers/nesc/draft.rb +2 -2
  269. data/lib/pubid/ieee/identifiers/nesc/handbook.rb +2 -2
  270. data/lib/pubid/ieee/identifiers/nesc/redline.rb +2 -2
  271. data/lib/pubid/ieee/identifiers/nesc/standard.rb +2 -2
  272. data/lib/pubid/ieee/identifiers/si_standard.rb +5 -2
  273. data/lib/pubid/ieee/ire/identifier.rb +2 -2
  274. data/lib/pubid/ieee/ire/parser.rb +20 -2
  275. data/lib/pubid/ieee/nesc/parser.rb +1 -1
  276. data/lib/pubid/ieee/parser.rb +208 -33
  277. data/lib/pubid/ieee/project_renderer.rb +46 -0
  278. data/lib/pubid/ieee/renderer.rb +11 -8
  279. data/lib/pubid/ieee/urn_generator.rb +32 -3
  280. data/lib/pubid/ieee.rb +9 -1
  281. data/lib/pubid/ieee_debug.rb +1 -0
  282. data/lib/pubid/ietf/builder.rb +24 -8
  283. data/lib/pubid/ietf/identifiers/base.rb +25 -28
  284. data/lib/pubid/ietf/identifiers/bcp.rb +11 -0
  285. data/lib/pubid/ietf/identifiers/fyi.rb +11 -0
  286. data/lib/pubid/ietf/identifiers/internet_draft.rb +18 -2
  287. data/lib/pubid/ietf/identifiers/rfc.rb +2 -0
  288. data/lib/pubid/ietf/identifiers/serialization.rb +51 -0
  289. data/lib/pubid/ietf/identifiers/std.rb +11 -0
  290. data/lib/pubid/ietf/identifiers.rb +1 -0
  291. data/lib/pubid/ietf/parser.rb +27 -9
  292. data/lib/pubid/ietf/renderer.rb +44 -6
  293. data/lib/pubid/ietf/urn_generator.rb +20 -6
  294. data/lib/pubid/ietf/urn_parser.rb +10 -2
  295. data/lib/pubid/ietf.rb +12 -2
  296. data/lib/pubid/iho/identifiers/base.rb +10 -3
  297. data/lib/pubid/iho/parser.rb +1 -1
  298. data/lib/pubid/iho.rb +1 -0
  299. data/lib/pubid/isbn/identifier.rb +25 -7
  300. data/lib/pubid/isbn/parser.rb +1 -1
  301. data/lib/pubid/isbn.rb +1 -0
  302. data/lib/pubid/iso/builder.rb +10 -11
  303. data/lib/pubid/iso/bundled_identifier.rb +5 -3
  304. data/lib/pubid/iso/combined_identifier.rb +5 -3
  305. data/lib/pubid/iso/components.rb +0 -1
  306. data/lib/pubid/iso/identifier.rb +23 -11
  307. data/lib/pubid/iso/identifiers/directives.rb +7 -4
  308. data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -4
  309. data/lib/pubid/iso/identifiers/tc_document.rb +31 -46
  310. data/lib/pubid/iso/normalizer.rb +1 -1
  311. data/lib/pubid/iso/parser.rb +1 -1
  312. data/lib/pubid/iso/urn_generator.rb +10 -10
  313. data/lib/pubid/iso.rb +12 -5
  314. data/lib/pubid/itu/builder.rb +10 -0
  315. data/lib/pubid/itu/identifiers/addendum.rb +2 -2
  316. data/lib/pubid/itu/identifiers/amendment.rb +2 -2
  317. data/lib/pubid/itu/identifiers/base.rb +29 -5
  318. data/lib/pubid/itu/identifiers/contribution.rb +31 -0
  319. data/lib/pubid/itu/identifiers/corrigendum.rb +2 -2
  320. data/lib/pubid/itu/identifiers/errata.rb +2 -2
  321. data/lib/pubid/itu/identifiers/supplement.rb +2 -2
  322. data/lib/pubid/itu/identifiers.rb +1 -0
  323. data/lib/pubid/itu/parser.rb +20 -3
  324. data/lib/pubid/itu.rb +1 -0
  325. data/lib/pubid/jcgm/builder.rb +1 -1
  326. data/lib/pubid/jcgm/identifier.rb +10 -0
  327. data/lib/pubid/jcgm/identifiers/meeting.rb +1 -1
  328. data/lib/pubid/jcgm/parser.rb +10 -3
  329. data/lib/pubid/jcgm/renderer.rb +10 -3
  330. data/lib/pubid/jcgm/single_identifier.rb +24 -15
  331. data/lib/pubid/jcgm/urn_generator.rb +1 -1
  332. data/lib/pubid/jcgm/urn_parser.rb +156 -14
  333. data/lib/pubid/jcgm.rb +10 -0
  334. data/lib/pubid/jis/identifier.rb +10 -3
  335. data/lib/pubid/jis/parser.rb +1 -1
  336. data/lib/pubid/jis.rb +1 -0
  337. data/lib/pubid/nist/builder.rb +12 -12
  338. data/lib/pubid/nist/components/stage.rb +2 -2
  339. data/lib/pubid/nist/configuration.rb +6 -8
  340. data/lib/pubid/nist/identifiers/base.rb +22 -5
  341. data/lib/pubid/nist/identifiers/circular.rb +9 -2
  342. data/lib/pubid/nist/identifiers/circular_supplement.rb +14 -5
  343. data/lib/pubid/nist/identifiers/commercial_standard_emergency.rb +1 -1
  344. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +7 -1
  345. data/lib/pubid/nist/identifiers/crpl_report.rb +12 -7
  346. data/lib/pubid/nist/identifiers/federal_information_processing_standards.rb +2 -2
  347. data/lib/pubid/nist/identifiers/handbook.rb +9 -2
  348. data/lib/pubid/nist/identifiers/internal_report.rb +12 -5
  349. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +16 -8
  350. data/lib/pubid/nist/identifiers/monograph.rb +14 -7
  351. data/lib/pubid/nist/identifiers/report.rb +14 -6
  352. data/lib/pubid/nist/parser.rb +1 -1
  353. data/lib/pubid/nist/series/ir.rb +3 -7
  354. data/lib/pubid/nist/supplement_identifier.rb +16 -1
  355. data/lib/pubid/nist.rb +7 -1
  356. data/lib/pubid/oasis/builder.rb +12 -10
  357. data/lib/pubid/oasis/identifier.rb +89 -11
  358. data/lib/pubid/oasis/parser.rb +1 -1
  359. data/lib/pubid/oasis.rb +7 -1
  360. data/lib/pubid/ogc/identifier.rb +9 -5
  361. data/lib/pubid/ogc/parser.rb +1 -1
  362. data/lib/pubid/ogc.rb +1 -0
  363. data/lib/pubid/oiml/builder.rb +7 -3
  364. data/lib/pubid/oiml/identifiers/basic_publication.rb +2 -0
  365. data/lib/pubid/oiml/identifiers/bulletin.rb +40 -10
  366. data/lib/pubid/oiml/identifiers/code_number.rb +90 -0
  367. data/lib/pubid/oiml/identifiers/document.rb +2 -0
  368. data/lib/pubid/oiml/identifiers/expert_report.rb +2 -0
  369. data/lib/pubid/oiml/identifiers/guide.rb +2 -0
  370. data/lib/pubid/oiml/identifiers/recommendation.rb +2 -0
  371. data/lib/pubid/oiml/identifiers/seminar_report.rb +2 -0
  372. data/lib/pubid/oiml/identifiers/vocabulary.rb +2 -0
  373. data/lib/pubid/oiml/identifiers.rb +1 -0
  374. data/lib/pubid/oiml/parser.rb +8 -3
  375. data/lib/pubid/oiml/renderer.rb +3 -3
  376. data/lib/pubid/oiml/single_identifier.rb +26 -42
  377. data/lib/pubid/oiml/supplement_identifier.rb +27 -0
  378. data/lib/pubid/oiml/urn_generator.rb +4 -4
  379. data/lib/pubid/oiml.rb +7 -1
  380. data/lib/pubid/omg/builder.rb +1 -0
  381. data/lib/pubid/omg/identifier.rb +20 -3
  382. data/lib/pubid/omg/parser.rb +64 -11
  383. data/lib/pubid/omg/renderer.rb +13 -1
  384. data/lib/pubid/omg.rb +2 -1
  385. data/lib/pubid/parser/grammar.rb +74 -0
  386. data/lib/pubid/parser.rb +2 -0
  387. data/lib/pubid/parsers/mr_string.rb +19 -0
  388. data/lib/pubid/plateau/parser.rb +1 -1
  389. data/lib/pubid/plateau.rb +10 -0
  390. data/lib/pubid/prefixes_support.rb +1 -0
  391. data/lib/pubid/renderers/annotator.rb +233 -0
  392. data/lib/pubid/renderers/base.rb +13 -0
  393. data/lib/pubid/renderers/directives_renderer.rb +6 -4
  394. data/lib/pubid/renderers/human_readable.rb +3 -3
  395. data/lib/pubid/renderers/mr_string.rb +15 -9
  396. data/lib/pubid/renderers.rb +1 -0
  397. data/lib/pubid/rendering/numbering.rb +25 -7
  398. data/lib/pubid/rendering.rb +1 -0
  399. data/lib/pubid/sae/builder.rb +1 -1
  400. data/lib/pubid/sae/identifiers/base.rb +13 -3
  401. data/lib/pubid/sae/parser.rb +1 -1
  402. data/lib/pubid/sae/urn_generator.rb +1 -1
  403. data/lib/pubid/sae.rb +1 -0
  404. data/lib/pubid/schema/declaration.rb +33 -0
  405. data/lib/pubid/schema/error.rb +14 -0
  406. data/lib/pubid/schema/identifier_type.rb +23 -0
  407. data/lib/pubid/schema/loader.rb +117 -0
  408. data/lib/pubid/schema/typed_stage.rb +24 -0
  409. data/lib/pubid/schema.rb +25 -0
  410. data/lib/pubid/tgpp/builder.rb +1 -1
  411. data/lib/pubid/tgpp/identifier.rb +21 -5
  412. data/lib/pubid/tgpp/identifiers/technical_report.rb +2 -2
  413. data/lib/pubid/tgpp/identifiers/technical_specification.rb +2 -2
  414. data/lib/pubid/tgpp/parser.rb +22 -6
  415. data/lib/pubid/tgpp/renderer.rb +21 -5
  416. data/lib/pubid/tgpp/urn_generator.rb +27 -8
  417. data/lib/pubid/tgpp/urn_parser.rb +8 -6
  418. data/lib/pubid/tgpp.rb +7 -1
  419. data/lib/pubid/type_resolver.rb +16 -1
  420. data/lib/pubid/un/identifier.rb +6 -3
  421. data/lib/pubid/un/parser.rb +1 -1
  422. data/lib/pubid/un.rb +1 -0
  423. data/lib/pubid/urn_parser/errors.rb +8 -1
  424. data/lib/pubid/urn_parser.rb +1 -0
  425. data/lib/pubid/utils.rb +1 -0
  426. data/lib/pubid/version.rb +1 -1
  427. data/lib/pubid/w3c/builder.rb +5 -5
  428. data/lib/pubid/w3c/identifier.rb +38 -9
  429. data/lib/pubid/w3c/parser.rb +1 -1
  430. data/lib/pubid/w3c/renderer.rb +1 -1
  431. data/lib/pubid/w3c/urn_generator.rb +2 -2
  432. data/lib/pubid/w3c.rb +1 -0
  433. data/lib/pubid/xsf/identifier.rb +9 -5
  434. data/lib/pubid/xsf/parser.rb +17 -4
  435. data/lib/pubid/xsf.rb +7 -1
  436. data/lib/pubid.rb +399 -21
  437. data/lib/tasks/conformance.rake +34 -0
  438. data/lib/tasks/docs.rake +16 -14
  439. data/lib/tasks/schema.rake +88 -0
  440. data/schema/core/joint_prefixes.yaml +24 -0
  441. data/schema/iec.yaml +1017 -0
  442. data/schema/iso.yaml +1586 -0
  443. data/schema/schema.schema.yaml +96 -0
  444. metadata +40 -19
  445. data/archived-gems/pubid-ccsds/update_codes.yaml +0 -1
  446. data/archived-gems/pubid-iec/stages.yaml +0 -129
  447. data/archived-gems/pubid-iec/update_codes.yaml +0 -67
  448. data/archived-gems/pubid-ieee/update_codes.yaml +0 -104
  449. data/archived-gems/pubid-iso/stages.yaml +0 -106
  450. data/archived-gems/pubid-iso/update_codes.yaml +0 -4
  451. data/archived-gems/pubid-itu/i18n.yaml +0 -13
  452. data/archived-gems/pubid-itu/series.yaml +0 -42
  453. data/archived-gems/pubid-nist/publishers.yaml +0 -6
  454. data/archived-gems/pubid-nist/series.yaml +0 -121
  455. data/archived-gems/pubid-nist/update_codes.yaml +0 -93
  456. data/archived-gems/pubid-plateau/update_codes.yaml +0 -6
  457. data/lib/pubid/ccsds/identifiers/base_BASE_88929.rb +0 -70
  458. data/lib/pubid/cen_cenelec/supplement_identifier.rb +0 -48
  459. data/lib/pubid/iec/components/code.rb +0 -36
  460. data/lib/pubid/iso/components/code.rb +0 -24
  461. /data/{archived-gems/pubid-nist → data/nist}/stages.yaml +0 -0
@@ -12,20 +12,19 @@ module Pubid
12
12
 
13
13
  attribute :publisher, :string, collection: true # EN, CEN, CLC, etc.
14
14
  attribute :type, :string # TR, TS, Guide
15
- attribute :number, :string
15
+ # `number` is inherited as a :string from Pubid::CenCenelec::Identifier;
16
+ # a same-type redeclaration here is the determinism landmine in
17
+ # miniature, and it moves the generated accessor onto this class.
16
18
  attribute :parts, :string, collection: true
17
19
  attribute :year, :integer
18
20
  attribute :stage, :string # prEN, FprEN
19
21
  attribute :supplements, :string, collection: true # Amendments and corrigenda
20
- attribute :adopted_identifier, Base, polymorphic: true # Nested identifier object (ISO, IEC, etc.)
22
+ # Nested identifier object (ISO, IEC, etc.)
23
+ attribute :adopted, Base, polymorphic: true
21
24
  attribute :edition, :string # Edition number
22
-
23
- def ==(other)
24
- return false unless other.is_a?(Base)
25
-
26
- publisher == other.publisher && number == other.number &&
27
- parts == other.parts && year == other.year
28
- end
25
+ # No custom `==`: the one that was here compared only publisher,
26
+ # number, parts and year, so every amendment equalled every other.
27
+ # lutaml's attribute-wise `==` compares the whole identifier.
29
28
  end
30
29
  end
31
30
  end
@@ -6,7 +6,7 @@ module Pubid
6
6
  module CenCenelec
7
7
  module Identifiers
8
8
  class CenReport < 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,7 +5,7 @@ module Pubid
5
5
  module CenCenelec
6
6
  module Identifiers
7
7
  class CenWorkshopAgreement < 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(
@@ -6,7 +6,7 @@ module Pubid
6
6
  module CenCenelec
7
7
  module Identifiers
8
8
  class CenelecHarmonizationDocument < 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,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