pubid 2.0.10 → 2.0.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pubid/adobe/pubid_urn_schema.rb +10 -3
  3. data/lib/pubid/amca/pubid_urn_schema.rb +25 -0
  4. data/lib/pubid/amca.rb +1 -0
  5. data/lib/pubid/bipm/CLAUDE.md +9 -0
  6. data/lib/pubid/bipm/pubid_urn_schema.rb +42 -0
  7. data/lib/pubid/bipm.rb +1 -0
  8. data/lib/pubid/bsi/CLAUDE.md +13 -0
  9. data/lib/pubid/bsi/pubid_urn_schema.rb +114 -0
  10. data/lib/pubid/bsi.rb +1 -0
  11. data/lib/pubid/cen_cenelec/CLAUDE.md +11 -0
  12. data/lib/pubid/cen_cenelec/pubid_urn_schema.rb +26 -8
  13. data/lib/pubid/cie/CLAUDE.md +9 -0
  14. data/lib/pubid/cie/pubid_urn_schema.rb +51 -0
  15. data/lib/pubid/cie.rb +1 -0
  16. data/lib/pubid/csa/CLAUDE.md +12 -0
  17. data/lib/pubid/csa/pubid_urn_schema.rb +58 -0
  18. data/lib/pubid/csa.rb +1 -0
  19. data/lib/pubid/doi/pubid_urn_schema.rb +19 -0
  20. data/lib/pubid/doi.rb +1 -0
  21. data/lib/pubid/evs/CLAUDE.md +10 -0
  22. data/lib/pubid/format_registry.rb +5 -1
  23. data/lib/pubid/gb/pubid_urn_schema.rb +23 -0
  24. data/lib/pubid/gb.rb +1 -0
  25. data/lib/pubid/idf/pubid_urn_schema.rb +44 -0
  26. data/lib/pubid/idf.rb +1 -0
  27. data/lib/pubid/iec/CLAUDE.md +13 -0
  28. data/lib/pubid/iec/pubid_urn_schema.rb +46 -8
  29. data/lib/pubid/ietf/pubid_urn_schema.rb +24 -0
  30. data/lib/pubid/ietf.rb +1 -0
  31. data/lib/pubid/iho/CLAUDE.md +11 -0
  32. data/lib/pubid/iho/pubid_urn_schema.rb +49 -0
  33. data/lib/pubid/iho.rb +1 -0
  34. data/lib/pubid/isbn/pubid_urn_schema.rb +20 -0
  35. data/lib/pubid/isbn.rb +1 -0
  36. data/lib/pubid/jis/pubid_urn_schema.rb +29 -0
  37. data/lib/pubid/jis.rb +1 -0
  38. data/lib/pubid/omg/pubid_urn_schema.rb +21 -0
  39. data/lib/pubid/omg.rb +1 -0
  40. data/lib/pubid/sae/pubid_urn_schema.rb +33 -0
  41. data/lib/pubid/sae.rb +1 -0
  42. data/lib/pubid/tgpp/pubid_urn_schema.rb +23 -0
  43. data/lib/pubid/tgpp.rb +1 -0
  44. data/lib/pubid/un/pubid_urn_schema.rb +19 -0
  45. data/lib/pubid/un.rb +1 -0
  46. data/lib/pubid/version.rb +1 -1
  47. data/lib/pubid.rb +28 -2
  48. metadata +18 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c304081718b1785ddaa948a20b017e37676ff3dc54ed2548eae57efdf6c21fdf
4
- data.tar.gz: 0fb5b401e28fc704a0f99c4f034ccc9eb33857df4e28fb1956e2f923ab1048cb
3
+ metadata.gz: 58015cc01e426fd158cdfb240253372da45722a1cd2b9dc7a725993bf0a75e86
4
+ data.tar.gz: 7f501c8c4d994d31cddca28c6d6a4b98ed0b3dce039941375b9f2ecd5a4600f5
5
5
  SHA512:
6
- metadata.gz: 7bbfeb56e3bae793cf01371ed43638e843fd8a22d297b2694dc7058f613ea4747d52789b44f1c442678016687d56a7d7a7500ddf51830dc7a037f63948f05c26
7
- data.tar.gz: e0343e84825edff0e9cc921f67d87430a3a9071f44fbd456dee79c39bc8a2631d4c899f2823619fe3d2e7622f27435828f73f1836f6903e1c5b6ab57c38fe5ff
6
+ metadata.gz: 6d4a780dce2975889f1be570cfa59573efcb5b0ad54bfc038fdb1f80c4f80e8798186be172f406bce72fc35a91d01aa5095da5c676a5c9a23e9e3375b7a1eaad
7
+ data.tar.gz: 75599585a088af0b03aaa29d6dda8cf4e84a45debaa8a3c81687854697ce132a422c5432f586e7f95fd8248f28cd8102951949cb22efaa8f5a323e32326cd081
@@ -2,11 +2,18 @@
2
2
 
3
3
  module Pubid
4
4
  module Adobe
5
- # The pubid-scheme URN of adobe (issue #656; docs/URN-SCHEMES.adoc).
5
+ # The pubid-scheme URN of Adobe (issue #670; docs/URN-SCHEMES.adoc).
6
6
  #
7
- # Declared from the doc's section: the atom, facet and type tables
8
- # below are the doc's design, conforming token-for-token.
7
+ # Adobe Technical Note #5014 -> urn:pubid:adobe:technote:5014
8
+ #
9
+ # A named publication has no positional core: its slug names it, and the
10
+ # version (`adobe-japan1` + `7`) is an atom. The current urn:adobe:…
11
+ # form of #to_urn is pubid-invented and stays there.
9
12
  PubidUrnSchema = Pubid::PubidUrn.define("adobe") do
13
+ atom "slug", "slug"
14
+ atom "version", "v"
15
+
16
+ type "pubid:adobe:identifier", "id", core: []
10
17
  type "pubid:adobe:publication", "pub", core: []
11
18
  type "pubid:adobe:tech-note", "technote"
12
19
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Amca
5
+ # The pubid-scheme URN of AMCA (issue #670; docs/URN-SCHEMES.adoc).
6
+ #
7
+ # ANSI/AMCA 210-16 /ASHRAE 51-16 ->
8
+ # urn:pubid:amca:std:210:co-ASHRAE:year-16
9
+ #
10
+ # The current urn:amca:… form of #to_urn is pubid-invented and stays
11
+ # there.
12
+ PubidUrnSchema = Pubid::PubidUrn.define("amca") do
13
+ atom "copublisher", "co"
14
+ atom "year", "year"
15
+ atom "revision", "rev"
16
+ atom "reaffirmed", "reaffirmed"
17
+ atom "interpretation_code", "interpcode"
18
+
19
+ type "pubid:amca:identifier", "id"
20
+ type "pubid:amca:interpretation", "interp"
21
+ type "pubid:amca:publication", "pub"
22
+ type "pubid:amca:standard", "std"
23
+ end
24
+ end
25
+ end
data/lib/pubid/amca.rb CHANGED
@@ -17,6 +17,7 @@ module Pubid
17
17
  autoload :SingleIdentifier, "#{__dir__}/amca/single_identifier"
18
18
  autoload :UrnGenerator, "#{__dir__}/amca/urn_generator"
19
19
  autoload :UrnParser, "#{__dir__}/amca/urn_parser"
20
+ autoload :PubidUrnSchema, "#{__dir__}/amca/pubid_urn_schema"
20
21
 
21
22
  # Parse an ACMA identifier string into an identifier object
22
23
  # @param identifier [String] The ACMA identifier string to parse
@@ -13,3 +13,12 @@ These notes were part of the root `CLAUDE.md`. Read them before you change `lib/
13
13
  - **Routing reaches BIPM (`Pubid.parse`, pubid#644)**: the note above says "`Pubid.parse` auto-routing does not resolve **any** BIPM form today … so `PREFIXES` was left alone" — that is no longer true, in two halves. **(1) `PREFIXES` gained the two SI-family series tokens** `SI Brochure` and `SI MEP`: both lead real printed references on their own (`SI Brochure 9e v3.01 (2019/2024, E)` — the spelling relaton's `Bibliography#search` strips the `BIPM ` off, per the note above — and `SI MEP 10`), and before this both parsed **directly** but the router could not route them (no prefix owner ⇒ no non-exact fallback). "Rapport" stays excluded per the ambiguous-token policy (generic French word). **(2) The quoted-title form** `BIPM "The International System of Units"` — the brochure IS titled that — is mapped onto the parseable `BIPM SI Brochure` section form by **`data/bipm/update_codes.yaml`** (the CIPM-MRA precedent), so it parses as a **partial reference** that wildcards every edition, exactly like `SI Brochure Part 1`; the bare `"The International System of Units"` maps to `SI Brochure`. Both are normalizing parses and live with the loose-forms expectations, never in the byte-exact fixtures. The **French title is deliberately not mapped**: it names the F-language record specifically, and mapping it would silently drop typed language information (the loose-forms rule above). Also note the router's prefix-owner mechanism is what makes the normalizing parses routable: `Pubid::Bipm.parse("BIPM SI Brochure")` happens to round-trip exactly, but `SI Brochure 9e …` renders with the leading `BIPM ` the input lacked — without prefix-owner status the router would reject it. (hand-off: router-printed-forms-644.)
14
14
 
15
15
  - **Corpus-cited forms + guide printings (pubid#657)**: the metanorma-bipm fetch queue cites two spellings the grammar rejected, and the 2026-11 guide update adds printings of its own. All are **parse-in forms over the existing canonical identities** — the canonical render follows the guide, nothing that already parsed changed. **(1) The em-dash meeting variant** `CGPM -- Meeting 1 (1889)`: `meeting_en` gained `<group> -- Meeting <n>` and `<group> -- <n><ord> Meeting` branches (the corpus cites only the first; the second is the same reordering over the other word order). They build through the existing `Meeting` path, so the canonical render is `CGPM 1st Meeting (1889)`. **(2) The publisher-prefixed decision** `BIPM DECN CIPM/101-1 (2012, EN)` (and `, FR`): new `committee_prefixed` rule — a **literal `BIPM`** lead (the constant publisher, deliberately NOT the `group` table, which contains BIPM and would collide with the second `group` capture), `type_abbrev`, then the body-qualified id `{group}/{number}`. Builds through `build_committee` short-form, so it equals `CIPM DECN 101-1 (2012, E)` — verified against real `index-v2` rows in `loose_consumer_forms_spec` (the corpus's citeas comes out as the BIPM-long style, which is the consumer's rendering choice, not pubid's). **(3) The guide's French body-prefixed long form** `Décision CIPM/111-10 (2022)` / `Recommandation JCRB/43-1 (2021)`: an alternative inside `committee_long_fr` (same capture name, so the same builder path — long form, language F). **The canonical French long form stays the connective spelling** (`Décision 101-1 du CIPM (2012)`) even though the guide's language-independent example prefers the body-prefixed one — the corpus freezes the connective render for what already parsed, and flipping the canonical would move frozen cases; that flip is an owner decision if the guide is adopted wholesale. **(4) SI Brochure guide forms**: the language code and the version are now OPTIONAL (`SI Brochure 9e v3.01 (2019/2024)` language-independent, `SI Brochure 9e (2019, E)` version-less — both byte round-trips with the canonical `BIPM SI Brochure ` lead), and the guide's French lead `Brochure sur le SI 9e …` parses as an alias of the `BIPM SI Brochure sur le SI …` canonical (note the lead alternation is `"BIPM SI Brochure" / "SI Brochure" / "Brochure sur le SI"` with the `["sur le SI" space]` phrase still optional after the first two — it just fails cleanly after the third). **(5) The corpus-cited ordinal-edition spelling** `SI Brochure 9th edition (2019)`: its own `si_brochure_ordinal_edition` rule (a separate branch, because the `edition` capture would otherwise bind `"9th"`); the builder strips the ordinal and appends `e`, so it normalizes onto `BIPM SI Brochure 9e (2019)`. **(6) Part numbers** (the guide's resource-specific-id numbering, `partnumbers` proposal, bipm-si-brochure#301): parts/subparts are dash forms inside `number` (`CIPM DECN 111-10-2`) and always parsed; the appendix/annex complement `CIPM DECN 112 A3[.5]` is the new optional ` A<n>[.<m>]` tail on `committee_short`, stored in the shared `appendix`/`annex` attributes (the MEP/guide tail's home), printed back byte-exactly by `appendix_segment`, folded into the URN identifier segment as `-a<n>[.<m>]` (`urn:bipm:cipm:decn:112-a3.5:2022` — unambiguous, because a bare number never carries letters; `UrnParser#split_appendix` splits it back), and joined into the MR number segment (`mr_slug` collapses the annex dot). It requires a number before it (`CIPM DECN A3` still fails). **URN deviations from the guide, deliberate**: the guide's own committee-example URNs (`urn:bipm:v1:cipm:resolution:95-2006:1`) carry a `v1` version segment and venue-qualified shapes the flavor's URNs never adopted (`urn:bipm:cipm:res:101-1:2012`, no `v1`, no venue segments — green for years, kept byte-identical); the new forms emit URNs under the EXISTING shape for the same reason, and the same applies to the brochure (`urn:bipm:si-brochure:<lang>:<edition>:<version>:<years>` vs the guide's `urn:bipm:v1:bipm:si-brochure:9:3.01:2024` — the guide strips the `e`/`v` and drops the language segment; adopting that is an index-affecting owner decision, not taken here). **One Ruby trap the URN fold exposed**: `id.number.to_s` on a String **attribute** returns the attribute itself, so building the folded segment by `<<` mutated `number` in place — every later `to_s`/`to_hash` of the same object then carried `-a3`; the fold is now interpolation, and `urn_spec` pins that a URN emission leaves `number` untouched. **The unmerged `si-brochure-id` proposal** (`SI Brochure 9`, `SI Brochure 9 (E)`, `SI Brochure 9 (2024) (F)` — bare-number edition) is NOT implemented: it conflicts with the merged guide's `9e` spelling. (hand-off: bipm-657-corpus-forms.)
16
+
17
+ ## pubid-scheme URN (issue #670)
18
+
19
+ `lib/pubid/bipm/pubid_urn_schema.rb`; rulings in `docs/URN-SCHEMES.adoc`
20
+ (`[[urn-bipm]]`). The schema reads `#to_hash` only — the owner-pinned
21
+ deviations of the official `urn:bipm:…` shape (this file's URN section)
22
+ are untouched, and the codec needed no deviation knob. Years are Integer
23
+ atoms; a committee document with no number emits no core segment and the
24
+ atoms carry it (`urn:pubid:bipm:cd:year-1889:group-CGPM:typecode-DECL`).
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Bipm
5
+ # The pubid-scheme URN of BIPM (issue #670; docs/URN-SCHEMES.adoc).
6
+ #
7
+ # CCTF REC 2 (2012, E) ->
8
+ # urn:pubid:bipm:cd:2:group-CCTF:typecode-REC:year-2012:lang-E
9
+ #
10
+ # The current urn:bipm:… form of #to_urn is pubid-invented (the
11
+ # deviations from the JCGM 200:2012 URN pattern are owner-pinned in
12
+ # lib/pubid/bipm/CLAUDE.md) and stays there; this schema reads #to_hash
13
+ # only, so no codec deviation knob was needed. Years are Integers.
14
+ PubidUrnSchema = Pubid::PubidUrn.define("bipm") do
15
+ atom "part", "part"
16
+ atom "issue", "issue"
17
+ atom "year", "year", kind: :int
18
+ atom "edition", "ed"
19
+ atom "version", "v"
20
+ atom "appendix", "appendix"
21
+ atom "annex", "annex"
22
+ atom "language", "lang"
23
+ atom "article", "article"
24
+ atom "form", "form"
25
+ atom "group", "group"
26
+ atom "guide_kind", "guidekind"
27
+ atom "mep_code", "mepcode"
28
+ atom "report_code", "reportcode"
29
+ atom "type_code", "typecode"
30
+ atom "variant", "variant"
31
+ atom "years", "years"
32
+
33
+ type "pubid:bipm:committee-document", "cd"
34
+ type "pubid:bipm:guide", "guide"
35
+ type "pubid:bipm:identifier", "id"
36
+ type "pubid:bipm:meeting", "meeting"
37
+ type "pubid:bipm:mep", "mep"
38
+ type "pubid:bipm:metrologia-article", "ma"
39
+ type "pubid:bipm:si-brochure", "sb"
40
+ end
41
+ end
42
+ end
data/lib/pubid/bipm.rb CHANGED
@@ -29,6 +29,7 @@ module Pubid
29
29
  autoload :Renderer, "#{__dir__}/bipm/renderer"
30
30
  autoload :UrnGenerator, "#{__dir__}/bipm/urn_generator"
31
31
  autoload :UrnParser, "#{__dir__}/bipm/urn_parser"
32
+ autoload :PubidUrnSchema, "#{__dir__}/bipm/pubid_urn_schema"
32
33
 
33
34
  # Parse a BIPM identifier string into an identifier object.
34
35
  # @param identifier [String] the printed identifier
@@ -95,3 +95,16 @@ Verified: `spec/pubid/supplement_date_attributes_spec.rb` exercises the mechanis
95
95
  ## The `BSI `-prefixed spelling of the BS series parses (pubid#644)
96
96
 
97
97
  `BSI BS 5950` used to be a hard parse failure: the strip in `Pubid::Bsi::Identifier.parse` (`strip_bsi_prefix`) only dropped the `BSI ` prefix before PAS/PD/DD/BIP (`BSI_PREFIXED_SERIES`), and `BS` was deliberately absent because **BSI never prints `BSI` in front of its own BS series**. That remains true of the **render** — `to_s(with_publisher: true)` still answers `BS 5950` for a British Standard, and the `BSI` prefix is re-added only for `BSI_PREFIXED_SERIES` — but **external references do cite the series as `BSI BS 5950`**, so the prefixed spelling is now accepted on **parse**: `STRIPPABLE_SERIES = BSI_PREFIXED_SERIES + ["BS"]` drives the strip, and the input normalizes to the canonical `BS 5950` (a normalizing parse — never a byte-exact fixture). Two lists, one line apart, because the parse and render halves of the same question legitimately differ: `BSI_PREFIXED_SERIES` answers "which series does BSI *print* its publisher in front of", `STRIPPABLE_SERIES` answers "which series does an *external* citation print it in front of". Locked by `spec/pubid/router_printed_forms_spec.rb` (routing + canonical render + stable reparse).
98
+
99
+ ## pubid-scheme URN (issue #670)
100
+
101
+ `lib/pubid/bsi/pubid_urn_schema.rb`; rulings in `docs/URN-SCHEMES.adoc`
102
+ (`[[urn-bsi]]`). An adopted norm carries the European document along
103
+ `base`, so the wrapper shares the slug prefix of the document it wraps
104
+ (`BS EN 1073-2:2002` is
105
+ `urn:pubid:bsi:cencenelec.en:1073:part-2:year-2002:aen` — qualified
106
+ `cencenelec.` token, the document keeps its own schema). `type`, `stage`
107
+ and `typed_stage` serialize every registry field, so each field is its own
108
+ atom (`typeabbr-`, `stagehs-`, `tsabbr-` …; `typed_stage.abbr` is a list)
109
+ — the NIST ruling; reducing them would change `to_hash` and need a
110
+ re-crawl.
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Bsi
5
+ # The pubid-scheme URN of BSI (issue #670; docs/URN-SCHEMES.adoc).
6
+ #
7
+ # BS EN 1073-2:2002 ->
8
+ # urn:pubid:bsi:aen:cencenelec:en:1073:part-2:year-2002
9
+ #
10
+ # An adopted norm carries the European document along +base+, so the
11
+ # wrapper and the document share the slug prefix and the document keeps
12
+ # its own flavor's schema (`cencenelec`, `iec`, `iso`). The rest of the
13
+ # family follows the wrapper precedents: a consolidated identifier and
14
+ # a bundle are `ids` bracketed lists; a national annex carries its
15
+ # supplements as `nasup`; `type`, `stage` and `typed_stage` serialize
16
+ # every registry field of their components, so each field is its own
17
+ # atom (the NIST ruling) — reducing them to one identifying value would
18
+ # change to_hash and need a re-crawl, a separate decision.
19
+ #
20
+ # The current urn:bsi:… form of #to_urn is pubid-invented and stays
21
+ # there.
22
+ PubidUrnSchema = Pubid::PubidUrn.define("bsi") do
23
+ atom "publisher.body", "pubbody"
24
+ atom "copublishers", "co", kind: :list
25
+ atom "prefix", "prefix"
26
+ atom "flex_prefix", "flexprefix"
27
+ atom "part", "part"
28
+ atom "subpart", "subpart"
29
+ atom "year", "year"
30
+ atom "month", "month", kind: :int
31
+ atom "edition", "ed"
32
+ atom "type.abbr", "typeabbr"
33
+ atom "type.name", "typename"
34
+ atom "type.type_code", "typetypecode"
35
+ atom "stage.abbr", "stageabbr"
36
+ atom "stage.name", "stagename"
37
+ atom "stage.stage_code", "stagecode"
38
+ atom "stage.harmonized_stages", "stagehs", kind: :list
39
+ atom "typed_stage.abbr", "tsabbr", kind: :list
40
+ atom "typed_stage.name", "tsname"
41
+ atom "typed_stage.code", "tscode"
42
+ atom "typed_stage.stage_code", "tsstagecode"
43
+ atom "typed_stage.type_code", "tstypecode"
44
+ atom "typed_stage.harmonized_stages", "tshs", kind: :list
45
+ atom "format", "format"
46
+ atom "topic", "topic"
47
+ atom "separators", "seps", kind: :list
48
+ atom "separator", "sep"
49
+ atom "reverse_format", "revfmt", kind: :bool
50
+ atom "common_year.year", "cyear"
51
+ atom "supplement_number", "sup"
52
+ atom "supplement_year", "supyear", kind: :int
53
+ atom "addendum_number", "addn"
54
+ atom "addendum_year", "addy", kind: :int
55
+ atom "method_code", "mcode"
56
+ atom "method_to", "mto"
57
+ atom "method_and", "mand"
58
+ atom "is_plural", "isplural", kind: :bool
59
+ atom "section_id", "secid"
60
+ atom "section_format", "secfmt"
61
+ atom "second_number.value", "snd"
62
+ atom "spec_code.value", "spc"
63
+ atom "index_format", "idxfmt"
64
+ atom "issue_number", "issue"
65
+ atom "translation_lang", "translang"
66
+ atom "test_id", "testid"
67
+ atom "test_series", "testseries"
68
+ atom "iteration", "iter"
69
+ atom "fragment_number", "frag"
70
+ atom "explicit_prefix", "expprefix", kind: :bool
71
+ atom "explicit_publisher", "exppub", kind: :bool
72
+ atom "space_separated_part", "sspart", kind: :bool
73
+ atom "amd_suffix_form", "amdsuffix", kind: :bool
74
+ atom "bundle_type", "btype"
75
+ atom "identifiers", "ids", kind: :ids
76
+ atom "na_supplements", "nasup", kind: :ids
77
+
78
+ type "pubid:bsi:addendum-document", "ad"
79
+ type "pubid:bsi:adopted-european-norm", "aen", core: []
80
+ type "pubid:bsi:adopted-international-standard", "ais", core: []
81
+ type "pubid:bsi:aerospace-standard", "as"
82
+ type "pubid:bsi:amendment", "amd"
83
+ type "pubid:bsi:british-industrial-practice", "bip"
84
+ type "pubid:bsi:british-standard", "bs"
85
+ type "pubid:bsi:bundled-identifier", "bundle", core: []
86
+ type "pubid:bsi:committee-document", "cd"
87
+ type "pubid:bsi:consolidated-identifier", "consol", core: []
88
+ type "pubid:bsi:corrigendum", "cor"
89
+ type "pubid:bsi:detailed-specification", "ds"
90
+ type "pubid:bsi:disc", "disc"
91
+ type "pubid:bsi:draft-document", "dd"
92
+ type "pubid:bsi:electronic-book", "eb"
93
+ type "pubid:bsi:expert-commentary", "ec", core: []
94
+ type "pubid:bsi:explanatory-supplement", "es"
95
+ type "pubid:bsi:flex", "flex"
96
+ type "pubid:bsi:handbook", "hb"
97
+ type "pubid:bsi:identifier", "id"
98
+ type "pubid:bsi:index", "index"
99
+ type "pubid:bsi:method", "method"
100
+ type "pubid:bsi:national-annex", "na"
101
+ type "pubid:bsi:practice-guide", "pg"
102
+ type "pubid:bsi:publicly-available-specification", "pas"
103
+ type "pubid:bsi:published-document", "pd"
104
+ type "pubid:bsi:section", "section"
105
+ type "pubid:bsi:set", "set", core: []
106
+ type "pubid:bsi:standalone-amendment", "sa"
107
+ type "pubid:bsi:supplement-document", "sd"
108
+ type "pubid:bsi:supplementary-index", "si"
109
+ type "pubid:bsi:technical-specification", "ts"
110
+ type "pubid:bsi:test-method", "tm"
111
+ type "pubid:bsi:value-added-publication", "vap"
112
+ end
113
+ end
114
+ end
data/lib/pubid/bsi.rb CHANGED
@@ -37,6 +37,7 @@ module Pubid
37
37
  autoload :SingleIdentifier, "#{__dir__}/bsi/single_identifier"
38
38
  autoload :UrnGenerator, "#{__dir__}/bsi/urn_generator"
39
39
  autoload :UrnParser, "#{__dir__}/bsi/urn_parser"
40
+ autoload :PubidUrnSchema, "#{__dir__}/bsi/pubid_urn_schema"
40
41
 
41
42
  # TYPED_STAGES_REGISTRY for native BSI types. Used by Pubid::Bsi.locate_stage
42
43
  # to map abbreviations (e.g. "BS", "PD", "Handbook") to typed stages.
@@ -74,3 +74,14 @@ gives it); `spec/pubid/cen_cenelec/type_key_spec.rb` loads the class and
74
74
  rebuilds the list, so it does not depend on order. **Every type key in a
75
75
  flavor must be unique**; ANSI has the same shape (`Standard` and
76
76
  `AmericanNationalStandard` both declare `ans`) and is not checked here.
77
+
78
+ ## pubid-scheme URN (issue #670)
79
+
80
+ `lib/pubid/cen_cenelec/pubid_urn_schema.rb` completes the partial schema
81
+ the GOST wave landed; rulings in `docs/URN-SCHEMES.adoc`
82
+ (`[[urn-cen_cenelec]]`). Every atom added after that wave sits after the
83
+ ones it placed (`subpart-` between `part-` and `year-` never fires on
84
+ them; `dateyear-`/`datemonth-` after `month-`), so a GOST-nested URN
85
+ encodes identically. The nested `type`/`typed_stage` of an EN whose stage
86
+ is not in the registry stays unplaced — no parse makes that shape today,
87
+ and it keeps raising "does not place" instead of a silent drop.
@@ -2,22 +2,30 @@
2
2
 
3
3
  module Pubid
4
4
  module CenCenelec
5
- # The pubid-scheme URN of CEN/CENELEC — PARTIAL (issue #656;
5
+ # The pubid-scheme URN of CEN/CENELEC (issue #670 completes the flavor;
6
6
  # docs/URN-SCHEMES.adoc).
7
7
  #
8
- # Only the types a GOST adoption can name are declared: an EN, an
9
- # adopted EN ("EN ISO 12100:2010", no number of its own), its amendment
10
- # and corrigendum, a CEN TS or TR, and the consolidated
11
- # "EN 14988:2017+A1:2020". The atoms keep the doc's canonical order; an
12
- # absent atom writes nothing, so the CEN wave can add types and atoms
13
- # without changing these URNs. Until then cen_cenelec stays pending in
14
- # the contract spec.
8
+ # EN 302 326-2 V2.2.1:2026 ->
9
+ # urn:pubid:cencenelec:en:302~20326:part-2:year-2026:v-~20V2.2.1
10
+ #
11
+ # The partial schema landed with GOST named the types a GOST adoption
12
+ # can reach; this wave adds the rest of the flavor (CR, CWA, the two
13
+ # harmonization documents, the prestandard, the specification, the
14
+ # fragment and the guides) and the `subpart` and nested-date atoms. An
15
+ # absent atom writes nothing, and every new atom sits after the ones
16
+ # the GOST wave placed, so the URNs it publishes are unchanged. The
17
+ # adopted document goes along +base+ and keeps its own flavor's schema;
18
+ # a consolidated identifier has only its `identifiers`
19
+ # (`urn:pubid:cencenelec:consol:ids-(cencenelec:en:14988:year-2017),…`).
15
20
  PubidUrnSchema = Pubid::PubidUrn.define("cencenelec") do
16
21
  atom "publisher", "pub"
17
22
  atom "copublishers", "co", kind: :list
18
23
  atom "part", "part"
24
+ atom "subpart", "subpart"
19
25
  atom "year", "year"
20
26
  atom "month", "month"
27
+ atom "date.year", "dateyear"
28
+ atom "date.month", "datemonth"
21
29
  atom "version", "v"
22
30
  atom "stage", "stage"
23
31
  atom "adopted", "adopted", kind: :id
@@ -25,9 +33,19 @@ module Pubid
25
33
 
26
34
  type "pubid:cencenelec:adopted-european-norm", "aen", core: []
27
35
  type "pubid:cencenelec:amendment", "amd"
36
+ type "pubid:cencenelec:base", "base"
37
+ type "pubid:cencenelec:cen-report", "cr"
38
+ type "pubid:cencenelec:cen-workshop-agreement", "cwa"
39
+ type "pubid:cencenelec:cenelec-harmonization-document", "chd"
28
40
  type "pubid:cencenelec:consolidated-identifier", "consol", core: []
29
41
  type "pubid:cencenelec:corrigendum", "cor"
30
42
  type "pubid:cencenelec:european-norm", "en"
43
+ type "pubid:cencenelec:european-prestandard", "ep"
44
+ type "pubid:cencenelec:european-specification", "es"
45
+ type "pubid:cencenelec:fragment", "fragment"
46
+ type "pubid:cencenelec:guide", "guide"
47
+ type "pubid:cencenelec:harmonization-document", "hd"
48
+ type "pubid:cencenelec:identifier", "id"
31
49
  type "pubid:cencenelec:technical-report", "tr"
32
50
  type "pubid:cencenelec:technical-specification", "ts"
33
51
  end
@@ -56,3 +56,12 @@ Read this before you change `lib/pubid/cie/` or `spec/pubid/cie/`. The root
56
56
  year `2009` — lives on `base`. Wrapping its `to_s` changed nothing,
57
57
  because the annotator only read the wrapper's own attributes. It is fixed
58
58
  by `Annotator#emit_tokens` walking `base`, not by anything in CIE.
59
+
60
+ ## pubid-scheme URN (issue #670)
61
+
62
+ `lib/pubid/cie/pubid_urn_schema.rb`; rulings in `docs/URN-SCHEMES.adoc`
63
+ (`[[urn-cie]]`). `s_prefix`/`d_prefix` and `part_separator` are bool/value
64
+ facets (spelling only); `style` names how the designation reads and is an
65
+ atom; the language format rides `langformat-` and a paren-year
66
+ translation's year `transyear-`. A bundle's members are `ids-`; a
67
+ supplement's document goes along `base`.
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Cie
5
+ # The pubid-scheme URN of CIE (issue #670; docs/URN-SCHEMES.adoc).
6
+ #
7
+ # CIE S 004/E-2001 ->
8
+ # urn:pubid:cie:std:004:style-legacy:year-2001:f:0.sp-true:…
9
+ #
10
+ # The current urn:cie:… form of #to_urn is pubid-invented and stays
11
+ # there. `s_prefix`/`d_prefix` (the leading `S`/`D` token) and the part
12
+ # separator are spelling-only, so they are facets; `style` names how the
13
+ # designation reads and is an atom. A bundle's members are the `ids`
14
+ # list; its base document shares the slug prefix.
15
+ PubidUrnSchema = Pubid::PubidUrn.define("cie") do
16
+ atom "copublisher", "co"
17
+ atom "part", "part"
18
+ atom "year", "year"
19
+ atom "stage", "stage"
20
+ atom "language.code", "lang"
21
+ atom "language.format", "langformat"
22
+ atom "language.translation_year", "transyear"
23
+ atom "amendment_number", "amendmentnumber"
24
+ atom "conference", "conference"
25
+ atom "doc_type", "doctype"
26
+ atom "iec_identifier", "iecidentifier"
27
+ atom "iso_reference", "isoreference"
28
+ atom "iteration", "iter"
29
+ atom "page", "page"
30
+ atom "style", "style"
31
+ atom "variant", "variant"
32
+ atom "ids", "ids", kind: :ids
33
+
34
+ facet "s_prefix", "sp", kind: :bool
35
+ facet "part_separator", "partsep"
36
+ facet "d_prefix", "dp", kind: :bool
37
+
38
+ type "pubid:cie:bundle", "bundle"
39
+ type "pubid:cie:conference", "c"
40
+ type "pubid:cie:corrigendum", "cor"
41
+ type "pubid:cie:dual-published", "dp"
42
+ type "pubid:cie:identical", "i"
43
+ type "pubid:cie:identifier", "id"
44
+ type "pubid:cie:joint-published", "jp"
45
+ type "pubid:cie:proceedings", "p"
46
+ type "pubid:cie:standard", "std"
47
+ type "pubid:cie:supplement", "sup"
48
+ type "pubid:cie:tutorial-bundle", "tb"
49
+ end
50
+ end
51
+ end
data/lib/pubid/cie.rb CHANGED
@@ -20,6 +20,7 @@ module Pubid
20
20
  autoload :SupplementIdentifier, "#{__dir__}/cie/supplement_identifier"
21
21
  autoload :UrnGenerator, "#{__dir__}/cie/urn_generator"
22
22
  autoload :UrnParser, "#{__dir__}/cie/urn_parser"
23
+ autoload :PubidUrnSchema, "#{__dir__}/cie/pubid_urn_schema"
23
24
 
24
25
  # Main entry point for CIE identifiers
25
26
  # Delegates to Identifier.parse
@@ -39,3 +39,15 @@ These notes were part of the root `CLAUDE.md`. Read them before you change `lib/
39
39
  Moved from the root `CLAUDE.md`'s `#exclude` bullet (`metanorma__pubid__exclude-recursion-depth`), where it had grown that bullet past the 100,000-byte session-load budget `spec/pubid/flavor_notes_spec.rb` enforces.
40
40
 
41
41
  **CSA follows the same scalar-year pattern** (`Csa::Identifier#exclude`): its `year` is a plain `:string`, but unlike BIPM the year carries *format metadata* stored in sibling attributes (`year_format`, `year_prefix`, `original_year_4digit`, and `french` — the last set **only** from a `:F` year prefix, the French-edition form `CSA B149.1:F20`). A year-less parse leaves all of these nil/false, so the override must reset **every** year-derived attribute (not just `year`) after `super`, or `==` — and thus `matches?` — would still diverge (e.g. a bare `CSA B149.1` would fail to match the French edition `CSA B149.1:F20`). The `respond_to?(:year=)` guard skips the adoption wrappers (`CanadianAdopted`/`CsaAdopted`), which delegate year to a nested inner id and lack a `year` accessor — those are handled by the base recursion.
42
+
43
+ ## pubid-scheme URN (issue #670)
44
+
45
+ `lib/pubid/csa/pubid_urn_schema.rb`; rulings in `docs/URN-SCHEMES.adoc`
46
+ (`[[urn-csa]]`). The spelling/format cluster of the year — `year_format`,
47
+ `year_prefix`, `publisher_prefix`, `has_publisher`,
48
+ `original_reaffirmation_4digit`, `original_year_4digit`, `separator`,
49
+ `series_prefix`, `french` — is facets, so the same document printed two
50
+ ways merges only spellings; everything else is an atom. An adoption's
51
+ document goes along `base` and keeps its own flavor's schema (`CSA
52
+ ISO/IEC 8824-1:22` is
53
+ `urn:pubid:csa:iso.is:8824:co-IEC:part-1:year-2022:ca2`).
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Csa
5
+ # The pubid-scheme URN of CSA (issue #670; docs/URN-SCHEMES.adoc).
6
+ #
7
+ # CAN/CSA-A123.2-03 (R2023) ->
8
+ # urn:pubid:csa:ca:A123.2:year-2003:f:0.yearformat-dash:…
9
+ #
10
+ # The current urn:csa:… form of #to_urn is pubid-invented and stays
11
+ # there. The spelling/format cluster of the CSA year (`year_format`,
12
+ # `year_prefix`, the publisher prefix it is printed with, the
13
+ # original-digit spellings of a reaffirmation, the French marker) is
14
+ # facets — the same document prints two ways; everything else is an
15
+ # atom. A combined identifier carries its members in `identifiers`, a
16
+ # bundled one in `bundled_with` (both bracketed lists); the adopted
17
+ # document goes along +base+ and keeps its own flavor's schema.
18
+ PubidUrnSchema = Pubid::PubidUrn.define("csa") do
19
+ atom "publisher", "pub"
20
+ atom "part", "part"
21
+ atom "subpart", "subpart"
22
+ atom "copublishers", "co", kind: :list
23
+ atom "series", "series", kind: :bool
24
+ atom "year", "year"
25
+ atom "reaffirmation", "reaff"
26
+ atom "cec_part", "cecpart"
27
+ atom "code_only", "codeonly", kind: :bool
28
+ atom "materials_after_keyword", "materialsafterkeyword", kind: :bool
29
+ atom "no_number", "nonumber"
30
+ atom "package_keyword", "packagekeyword"
31
+ atom "package_materials", "packagematerials"
32
+ atom "identifiers", "ids", kind: :ids
33
+ atom "bundled_with", "bundledwith", kind: :ids
34
+
35
+ facet "year_format", "yearformat"
36
+ facet "year_prefix", "yearprefix"
37
+ facet "publisher_prefix", "pubprefix"
38
+ facet "has_publisher", "haspublisher", kind: :bool
39
+ facet "original_reaffirmation_4digit", "origreaff4", kind: :bool
40
+ facet "original_year_4digit", "origyear4", kind: :bool
41
+ facet "separator", "separator"
42
+ facet "series_prefix", "seriesprefix"
43
+ facet "french", "french", kind: :bool
44
+
45
+ type "pubid:csa:amendment", "amd"
46
+ type "pubid:csa:base", "base"
47
+ type "pubid:csa:bundled", "bundled"
48
+ type "pubid:csa:canadian-adopted", "ca"
49
+ type "pubid:csa:cec", "cec"
50
+ type "pubid:csa:combined", "combined"
51
+ type "pubid:csa:csa-adopted", "ca2"
52
+ type "pubid:csa:identifier", "id"
53
+ type "pubid:csa:package", "package"
54
+ type "pubid:csa:series", "series"
55
+ type "pubid:csa:standard", "std"
56
+ end
57
+ end
58
+ end
data/lib/pubid/csa.rb CHANGED
@@ -19,6 +19,7 @@ module Pubid
19
19
  autoload :WrapperIdentifier, "#{__dir__}/csa/wrapper_identifier"
20
20
  autoload :CompositeIdentifier, "#{__dir__}/csa/composite_identifier"
21
21
  autoload :Components, "#{__dir__}/csa/components"
22
+ autoload :PubidUrnSchema, "#{__dir__}/csa/pubid_urn_schema"
22
23
 
23
24
  def self.parse(identifier_string)
24
25
  unless identifier_string.is_a?(String)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Doi
5
+ # The pubid-scheme URN of DOI (issue #670; docs/URN-SCHEMES.adoc).
6
+ #
7
+ # doi:10.1000/182 -> urn:pubid:doi:resource:prefix-10.1000:suffix-182
8
+ #
9
+ # The official urn:doi: namespace (the IANA formal template) stays on
10
+ # #to_urn.
11
+ PubidUrnSchema = Pubid::PubidUrn.define("doi") do
12
+ atom "prefix", "prefix"
13
+ atom "suffix", "suffix"
14
+
15
+ type "pubid:doi:identifier", "id", core: []
16
+ type "pubid:doi:resource", "resource", core: []
17
+ end
18
+ end
19
+ end
data/lib/pubid/doi.rb CHANGED
@@ -21,6 +21,7 @@ module Pubid
21
21
  autoload :Identifiers, "#{__dir__}/doi/identifiers"
22
22
  autoload :Parser, "#{__dir__}/doi/parser"
23
23
  autoload :Renderer, "#{__dir__}/doi/renderer"
24
+ autoload :PubidUrnSchema, "#{__dir__}/doi/pubid_urn_schema"
24
25
 
25
26
  def self.parse(identifier)
26
27
  Identifier.parse(identifier)
@@ -56,3 +56,13 @@
56
56
  flavor, so a raw default of any spelling or component type fails, whatever
57
57
  flavor introduces it. Its `PENDING_RAW_DEFAULTS` table is empty today; an
58
58
  entry that starts to pass turns red, which is the signal to delete it.
59
+
60
+ ## pubid-scheme URN (issue #670)
61
+
62
+ `lib/pubid/evs/pubid_urn_schema.rb`; rulings in `docs/URN-SCHEMES.adoc`
63
+ (`[[urn-evs]]`). The separators and the draft marker are facets; the
64
+ amendment/corrigendum columns are atoms. An adoption of a European
65
+ document carries it along `base` and it keeps the CEN/CENELEC schema
66
+ (`EVS-EN 18216:2026` is
67
+ `urn:pubid:evs:cencenelec.en:18216:year-2026:na`); `intlorg-` covers an
68
+ adoption of an organization pubid does not model as a nested identifier.
@@ -75,7 +75,11 @@ module Pubid
75
75
  mapping_class: ::Lutaml::Model::Mapping,
76
76
  adapter_class: adapter,
77
77
  transformer: transformer,
78
- error_types: [Pubid::Errors::ParseError],
78
+ # Both decode-failure classes wrap as InvalidFormatError here, so
79
+ # `Identifier.from_urn` keeps its one failure shape (issue #670:
80
+ # the umbrella raises UrnParseError where it leaked raw
81
+ # ArgumentError, and a grammar failure is ParseError).
82
+ error_types: [Pubid::Errors::ParseError, Pubid::Errors::UrnParseError],
79
83
  )
80
84
  end
81
85
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Gb
5
+ # The pubid-scheme URN of GB (issue #670; docs/URN-SCHEMES.adoc).
6
+ #
7
+ # JB/T 13368-2018 -> urn:pubid:gb:std:13368:pub-JB:mandate-T:year-2018
8
+ #
9
+ # The publisher and the mandate letter (`T` of GB/T) are atoms. The
10
+ # current urn:gb:… form of #to_urn is pubid-invented and stays there.
11
+ PubidUrnSchema = Pubid::PubidUrn.define("gb") do
12
+ atom "publisher", "pub"
13
+ atom "part", "part"
14
+ atom "year", "year"
15
+ atom "mandate", "mandate"
16
+ atom "identifiers", "ids", kind: :ids
17
+
18
+ type "pubid:gb:all-parts", "all", atoms: []
19
+ type "pubid:gb:identifier", "id"
20
+ type "pubid:gb:standard", "std"
21
+ end
22
+ end
23
+ end
data/lib/pubid/gb.rb CHANGED
@@ -41,6 +41,7 @@ module Pubid
41
41
  autoload :Identifiers, "#{__dir__}/gb/identifiers"
42
42
  autoload :Parser, "#{__dir__}/gb/parser"
43
43
  autoload :Renderer, "#{__dir__}/gb/renderer"
44
+ autoload :PubidUrnSchema, "#{__dir__}/gb/pubid_urn_schema"
44
45
 
45
46
  # Parse a Chinese Standard identifier string.
46
47
  # @param identifier [String] e.g. "GB/T 20223-2006"