pubid 2.0.25 → 2.0.27

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +115 -167
  3. data/data/parg/cen_pfs.json +1 -1
  4. data/data/parg/etsi_pfs.json +1 -1
  5. data/lib/pubid/cen_pfs/adopted_base.rb +114 -0
  6. data/lib/pubid/cen_pfs/builder.rb +157 -21
  7. data/lib/pubid/cen_pfs/identifier.rb +106 -48
  8. data/lib/pubid/cen_pfs/identifiers/adopted_european_norm.rb +55 -0
  9. data/lib/pubid/cen_pfs/identifiers/amendment.rb +27 -0
  10. data/lib/pubid/cen_pfs/identifiers/cen_report.rb +36 -0
  11. data/lib/pubid/cen_pfs/identifiers/cen_workshop_agreement.rb +36 -0
  12. data/lib/pubid/cen_pfs/identifiers/consolidated_identifier.rb +41 -0
  13. data/lib/pubid/cen_pfs/identifiers/corrigendum.rb +27 -0
  14. data/lib/pubid/cen_pfs/identifiers/european_norm.rb +43 -23
  15. data/lib/pubid/cen_pfs/identifiers/european_prestandard.rb +55 -0
  16. data/lib/pubid/cen_pfs/identifiers/european_specification.rb +36 -0
  17. data/lib/pubid/cen_pfs/identifiers/fragment.rb +28 -0
  18. data/lib/pubid/cen_pfs/identifiers/guide.rb +36 -0
  19. data/lib/pubid/cen_pfs/identifiers/harmonization_document.rb +36 -0
  20. data/lib/pubid/cen_pfs/identifiers/supplement.rb +39 -0
  21. data/lib/pubid/cen_pfs/identifiers/technical_report.rb +36 -0
  22. data/lib/pubid/cen_pfs/identifiers/technical_specification.rb +36 -0
  23. data/lib/pubid/cen_pfs/identifiers.rb +15 -1
  24. data/lib/pubid/cen_pfs/pubid_urn_schema.rb +20 -1
  25. data/lib/pubid/cen_pfs/renderer.rb +50 -1
  26. data/lib/pubid/cen_pfs/urn_generator.rb +75 -3
  27. data/lib/pubid/cen_pfs.rb +7 -16
  28. data/lib/pubid/doi_pfs/builder.rb +2 -2
  29. data/lib/pubid/etsi_pfs/CLAUDE.md +48 -40
  30. data/lib/pubid/etsi_pfs/builder.rb +45 -12
  31. data/lib/pubid/etsi_pfs/identifier.rb +23 -41
  32. data/lib/pubid/etsi_pfs/identifiers/amendment.rb +20 -0
  33. data/lib/pubid/etsi_pfs/identifiers/corrigendum.rb +20 -0
  34. data/lib/pubid/etsi_pfs/identifiers/standard.rb +64 -15
  35. data/lib/pubid/etsi_pfs/identifiers/supplement.rb +72 -0
  36. data/lib/pubid/etsi_pfs/identifiers.rb +4 -1
  37. data/lib/pubid/etsi_pfs/pubid_urn_schema.rb +4 -2
  38. data/lib/pubid/etsi_pfs/renderer.rb +29 -1
  39. data/lib/pubid/etsi_pfs/urn_generator.rb +40 -3
  40. data/lib/pubid/etsi_pfs.rb +2 -1
  41. data/lib/pubid/version.rb +1 -1
  42. metadata +20 -2
@@ -0,0 +1,27 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # The synthesized Amendment wrapper (PFS supplements
5
+ # declaration, issue #121 feature 3): the kind face
6
+ # "A" is the run's dispatch token and the
7
+ # printed notation's face.
8
+ class Amendment < Supplement
9
+ FACE = "A".freeze
10
+
11
+ def self.face
12
+ FACE
13
+ end
14
+
15
+ def self.polymorphic_name
16
+ "pubid:cencenelec:amendment"
17
+ end
18
+
19
+ # The MR slug's supplement suffix: the shared MrString
20
+ # recurses into base and appends this.
21
+ def mr_supplement_suffix
22
+ mr_join_segments("amd", number, year)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete CEN Report identifier type (PFS type `cen_report`).
5
+ class CenReport < Identifier
6
+ TYPED_STAGES = [
7
+ ].freeze
8
+
9
+ def self.type
10
+ { key: :cr, web: :cen_report, title: "CEN Report", short: "CR" }
11
+ end
12
+
13
+ # The publisher default (feature 5): the type's own token
14
+ # when the type is its designation, else the scheme default.
15
+ def self.default_publisher
16
+ ::Pubid::Components::Publisher.new(body: "CR")
17
+ end
18
+
19
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
20
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
21
+
22
+ def self.default_type
23
+ ::Pubid::Components::Type.new(abbr: type[:short])
24
+ end
25
+
26
+ # The scheme-canonical wire tag declared in the definition:
27
+ # to_hash stays byte-identical with the scheme's coded
28
+ # flavor, and this flavor's own from_hash routes the tag
29
+ # to this class.
30
+ def self.polymorphic_name
31
+ "pubid:cencenelec:cen-report"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete CEN Workshop Agreement identifier type (PFS type `cen_workshop_agreement`).
5
+ class CenWorkshopAgreement < Identifier
6
+ TYPED_STAGES = [
7
+ ].freeze
8
+
9
+ def self.type
10
+ { key: :cwa, web: :cen_workshop_agreement, title: "CEN Workshop Agreement", short: "CWA" }
11
+ end
12
+
13
+ # The publisher default (feature 5): the type's own token
14
+ # when the type is its designation, else the scheme default.
15
+ def self.default_publisher
16
+ ::Pubid::Components::Publisher.new(body: "CWA")
17
+ end
18
+
19
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
20
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
21
+
22
+ def self.default_type
23
+ ::Pubid::Components::Type.new(abbr: type[:short])
24
+ end
25
+
26
+ # The scheme-canonical wire tag declared in the definition:
27
+ # to_hash stays byte-identical with the scheme's coded
28
+ # flavor, and this flavor's own from_hash routes the tag
29
+ # to this class.
30
+ def self.polymorphic_name
31
+ "pubid:cencenelec:cen-workshop-agreement"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,41 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # The consolidated (plus-run) bundle: the base document is
5
+ # the first member; the supplements carry no base.
6
+ class ConsolidatedIdentifier < ::Pubid::CenPfs::Identifier
7
+ attribute :identifiers, ::Pubid::CenPfs::Identifier,
8
+ polymorphic: true, collection: true
9
+
10
+ # The origin document. Members live in `identifiers`, so
11
+ # walk the first member to its root.
12
+ def root
13
+ identifiers&.first&.root || self
14
+ end
15
+
16
+ def base_document
17
+ identifiers&.first&.base_document || self
18
+ end
19
+
20
+ def drop_supplements
21
+ identifiers&.first || self
22
+ end
23
+
24
+ # The base document, then each member's own supplement
25
+ # suffix behind the plus marker — the coded shape.
26
+ def to_mr_string
27
+ base, *supplements = identifiers
28
+ return "" unless base
29
+
30
+ ([base.to_mr_string] +
31
+ supplements.map { |s| "plus-#{s.mr_supplement_suffix}" })
32
+ .join(::Pubid::Renderers::MrString::SEPARATOR_SUPPLEMENT)
33
+ end
34
+
35
+ def self.polymorphic_name
36
+ "pubid:cencenelec:consolidated-identifier"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # The synthesized Corrigendum wrapper (PFS supplements
5
+ # declaration, issue #121 feature 3): the kind face
6
+ # "AC" is the run's dispatch token and the
7
+ # printed notation's face.
8
+ class Corrigendum < Supplement
9
+ FACE = "AC".freeze
10
+
11
+ def self.face
12
+ FACE
13
+ end
14
+
15
+ def self.polymorphic_name
16
+ "pubid:cencenelec:corrigendum"
17
+ end
18
+
19
+ # The MR slug's supplement suffix: the shared MrString
20
+ # recurses into base and appends this.
21
+ def mr_supplement_suffix
22
+ mr_join_segments("cor", number, supplement_date)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,31 +1,51 @@
1
- module Pubid
2
- module CenPfs
3
- module Identifiers
4
- # Concrete European Norm identifier type (PFS type `european_norm`).
5
- class EuropeanNorm < Identifier
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete European Norm identifier type (PFS type `european_norm`).
5
+ class EuropeanNorm < Identifier
6
6
  TYPED_STAGES = [
7
- Pubid::Components::TypedStage.new(
8
- code: :puben,
9
- stage_code: :published,
10
- type_code: :en,
11
- abbr: ["EN"],
12
- name: "European Norm",
13
- harmonized_stages: [],
14
- ),
7
+ ::Pubid::Components::TypedStage.new(
8
+ code: :puben, stage_code: :published,
9
+ type_code: :en, abbr: ["EN"],
10
+ name: "European Norm", harmonized_stages: [],
11
+ ),
12
+ ::Pubid::Components::TypedStage.new(
13
+ code: :pren, stage_code: :proposal,
14
+ type_code: :en, abbr: ["prEN"],
15
+ name: "pren", harmonized_stages: [],
16
+ ),
17
+ ::Pubid::Components::TypedStage.new(
18
+ code: :fpren, stage_code: :final_proposal,
19
+ type_code: :en, abbr: ["FprEN"],
20
+ name: "fpren", harmonized_stages: [],
21
+ ),
15
22
  ].freeze
16
23
 
17
- def self.type
18
- { key: :en, web: :"european-norm", title: "European Norm", short: "EN" }
19
- end
24
+ def self.type
25
+ { key: :en, web: :"european-norm", title: "European Norm", short: "EN" }
26
+ end
27
+
28
+ # The publisher default (feature 5): the type's own token
29
+ # when the type is its designation, else the scheme default.
30
+ def self.default_publisher
31
+ ::Pubid::Components::Publisher.new(body: "EN")
32
+ end
33
+
34
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
35
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
36
+
37
+ def self.default_type
38
+ ::Pubid::Components::Type.new(abbr: type[:short])
39
+ end
20
40
 
21
- # The scheme-canonical wire tag declared in the definition:
22
- # to_hash stays byte-identical with the scheme's coded
23
- # flavor, and this flavor's own from_hash routes the tag
24
- # to this class.
25
- def self.polymorphic_name
26
- "pubid:cencenelec:european-norm"
27
- end
41
+ # The scheme-canonical wire tag declared in the definition:
42
+ # to_hash stays byte-identical with the scheme's coded
43
+ # flavor, and this flavor's own from_hash routes the tag
44
+ # to this class.
45
+ def self.polymorphic_name
46
+ "pubid:cencenelec:european-norm"
28
47
  end
29
48
  end
30
49
  end
31
50
  end
51
+ end
@@ -0,0 +1,55 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete European Prestandard identifier type (PFS type `european_prestandard`).
5
+ class EuropeanPrestandard < Identifier
6
+ TYPED_STAGES = [
7
+ ].freeze
8
+
9
+ def self.type
10
+ { key: :env, web: :european_prestandard, title: "European Prestandard", short: "ENV" }
11
+ end
12
+
13
+ # The publisher default (feature 5): the type's own token
14
+ # when the type is its designation, else the scheme default.
15
+ def self.default_publisher
16
+ ::Pubid::Components::Publisher.new(body: "ENV")
17
+ end
18
+
19
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
20
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
21
+
22
+ def self.default_type
23
+ ::Pubid::Components::Type.new(abbr: type[:short])
24
+ end
25
+
26
+ # The adopted document (feature 4): the whole identity lives
27
+ # on the nested ISO/IEC identifier.
28
+ attribute :adopted, ::Pubid::Identifier, polymorphic: true
29
+
30
+ def root
31
+ adopted ? adopted.root : self
32
+ end
33
+
34
+ # MR "cen.iso.ts.21003-7": the publisher group fused, then the
35
+ # adopted document's own MR string in place of a number.
36
+ def mr_publisher
37
+ mr_join(*([publisher] + Array(copublishers)).compact
38
+ .map { |p| p.to_s.downcase })
39
+ end
40
+
41
+ def mr_number_with_part
42
+ adopted ? adopted.to_mr_string : super
43
+ end
44
+
45
+ # The scheme-canonical wire tag declared in the definition:
46
+ # to_hash stays byte-identical with the scheme's coded
47
+ # flavor, and this flavor's own from_hash routes the tag
48
+ # to this class.
49
+ def self.polymorphic_name
50
+ "pubid:cencenelec:european-prestandard"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,36 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete European Specification identifier type (PFS type `european_specification`).
5
+ class EuropeanSpecification < Identifier
6
+ TYPED_STAGES = [
7
+ ].freeze
8
+
9
+ def self.type
10
+ { key: :es, web: :european_specification, title: "European Specification", short: "ES" }
11
+ end
12
+
13
+ # The publisher default (feature 5): the type's own token
14
+ # when the type is its designation, else the scheme default.
15
+ def self.default_publisher
16
+ ::Pubid::Components::Publisher.new(body: "ES")
17
+ end
18
+
19
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
20
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
21
+
22
+ def self.default_type
23
+ ::Pubid::Components::Type.new(abbr: type[:short])
24
+ end
25
+
26
+ # The scheme-canonical wire tag declared in the definition:
27
+ # to_hash stays byte-identical with the scheme's coded
28
+ # flavor, and this flavor's own from_hash routes the tag
29
+ # to this class.
30
+ def self.polymorphic_name
31
+ "pubid:cencenelec:european-specification"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # The fragment wrapper: a fragment of the amendment it
5
+ # wraps; the fragment ordinal is its own `number`.
6
+ class Fragment < ::Pubid::CenPfs::Identifier
7
+ attribute :base, ::Pubid::CenPfs::Identifier
8
+ attribute :number, :string
9
+
10
+ def base_document
11
+ base&.base_document || self
12
+ end
13
+
14
+ def drop_supplements
15
+ base || self
16
+ end
17
+
18
+ def mr_supplement_suffix
19
+ mr_join_segments("frag", number)
20
+ end
21
+
22
+ def self.polymorphic_name
23
+ "pubid:cencenelec:fragment"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete Guide identifier type (PFS type `guide`).
5
+ class Guide < Identifier
6
+ TYPED_STAGES = [
7
+ ].freeze
8
+
9
+ def self.type
10
+ { key: :guide, web: :guide, title: "Guide", short: "Guide" }
11
+ end
12
+
13
+ # The publisher default (feature 5): the type's own token
14
+ # when the type is its designation, else the scheme default.
15
+ def self.default_publisher
16
+ ::Pubid::Components::Publisher.new(body: "EN")
17
+ end
18
+
19
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
20
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
21
+
22
+ def self.default_type
23
+ ::Pubid::Components::Type.new(abbr: type[:short])
24
+ end
25
+
26
+ # The scheme-canonical wire tag declared in the definition:
27
+ # to_hash stays byte-identical with the scheme's coded
28
+ # flavor, and this flavor's own from_hash routes the tag
29
+ # to this class.
30
+ def self.polymorphic_name
31
+ "pubid:cencenelec:guide"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete Harmonization Document identifier type (PFS type `harmonization_document`).
5
+ class HarmonizationDocument < Identifier
6
+ TYPED_STAGES = [
7
+ ].freeze
8
+
9
+ def self.type
10
+ { key: :hd, web: :harmonization_document, title: "Harmonization Document", short: "HD" }
11
+ end
12
+
13
+ # The publisher default (feature 5): the type's own token
14
+ # when the type is its designation, else the scheme default.
15
+ def self.default_publisher
16
+ ::Pubid::Components::Publisher.new(body: "HD")
17
+ end
18
+
19
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
20
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
21
+
22
+ def self.default_type
23
+ ::Pubid::Components::Type.new(abbr: type[:short])
24
+ end
25
+
26
+ # The scheme-canonical wire tag declared in the definition:
27
+ # to_hash stays byte-identical with the scheme's coded
28
+ # flavor, and this flavor's own from_hash routes the tag
29
+ # to this class.
30
+ def self.polymorphic_name
31
+ "pubid:cencenelec:harmonization-document"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,39 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # The supplement wrapper base: the wrapper owns its ordinal
5
+ # and the base identifier; every delegated attribute reads
6
+ # through (the coded SupplementIdentifier shape).
7
+ class Supplement < ::Pubid::CenPfs::Identifier
8
+ attribute :base, ::Pubid::CenPfs::Identifier
9
+ attribute :number, :string
10
+ attribute :year, :string
11
+ attribute :month, :string
12
+
13
+ def base_document
14
+ base&.base_document || self
15
+ end
16
+
17
+ def drop_supplements
18
+ base || self
19
+ end
20
+
21
+ # The wrapper's date: "2016-11", "2003", or nil.
22
+ def supplement_date
23
+ return nil unless year
24
+
25
+ [year, month].compact.reject(&:empty?).join("-")
26
+ end
27
+
28
+ # The printed notation: the kind face, the ordinal (absent
29
+ # for an unnumbered corrigendum) and the declared date tail.
30
+ # The bare notation; the renderer's walkers add the
31
+ # standalone slash and the consolidated plus themselves.
32
+ def supplement_notation
33
+ "#{self.class.face}#{number}#{year ? ":#{year}" : ''}#{month ? "-#{month}" : ''}"
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete Technical Report identifier type (PFS type `technical_report`).
5
+ class TechnicalReport < Identifier
6
+ TYPED_STAGES = [
7
+ ].freeze
8
+
9
+ def self.type
10
+ { key: :tr, web: :technical_report, title: "Technical Report", short: "TR" }
11
+ end
12
+
13
+ # The publisher default (feature 5): the type's own token
14
+ # when the type is its designation, else the scheme default.
15
+ def self.default_publisher
16
+ ::Pubid::Components::Publisher.new(body: "EN")
17
+ end
18
+
19
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
20
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
21
+
22
+ def self.default_type
23
+ ::Pubid::Components::Type.new(abbr: type[:short])
24
+ end
25
+
26
+ # The scheme-canonical wire tag declared in the definition:
27
+ # to_hash stays byte-identical with the scheme's coded
28
+ # flavor, and this flavor's own from_hash routes the tag
29
+ # to this class.
30
+ def self.polymorphic_name
31
+ "pubid:cencenelec:technical-report"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ module Pubid
2
+ module CenPfs
3
+ module Identifiers
4
+ # Concrete Technical Specification identifier type (PFS type `technical_specification`).
5
+ class TechnicalSpecification < Identifier
6
+ TYPED_STAGES = [
7
+ ].freeze
8
+
9
+ def self.type
10
+ { key: :ts, web: :technical_specification, title: "Technical Specification", short: "TS" }
11
+ end
12
+
13
+ # The publisher default (feature 5): the type's own token
14
+ # when the type is its designation, else the scheme default.
15
+ def self.default_publisher
16
+ ::Pubid::Components::Publisher.new(body: "EN")
17
+ end
18
+
19
+ attribute :publisher, ::Pubid::Components::Publisher, default: -> { self.class.default_publisher }
20
+ attribute :type, ::Pubid::Components::Type, default: -> { self.class.default_type }
21
+
22
+ def self.default_type
23
+ ::Pubid::Components::Type.new(abbr: type[:short])
24
+ end
25
+
26
+ # The scheme-canonical wire tag declared in the definition:
27
+ # to_hash stays byte-identical with the scheme's coded
28
+ # flavor, and this flavor's own from_hash routes the tag
29
+ # to this class.
30
+ def self.polymorphic_name
31
+ "pubid:cencenelec:technical-specification"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,7 +1,21 @@
1
1
  module Pubid
2
2
  module CenPfs
3
3
  module Identifiers
4
- autoload :EuropeanNorm, "#{__dir__}/identifiers/european_norm"
4
+ autoload :EuropeanNorm, "#{__dir__}/identifiers/european_norm"
5
+ autoload :AdoptedEuropeanNorm, "#{__dir__}/identifiers/adopted_european_norm"
6
+ autoload :TechnicalReport, "#{__dir__}/identifiers/technical_report"
7
+ autoload :TechnicalSpecification, "#{__dir__}/identifiers/technical_specification"
8
+ autoload :Guide, "#{__dir__}/identifiers/guide"
9
+ autoload :CenReport, "#{__dir__}/identifiers/cen_report"
10
+ autoload :CenWorkshopAgreement, "#{__dir__}/identifiers/cen_workshop_agreement"
11
+ autoload :EuropeanSpecification, "#{__dir__}/identifiers/european_specification"
12
+ autoload :EuropeanPrestandard, "#{__dir__}/identifiers/european_prestandard"
13
+ autoload :HarmonizationDocument, "#{__dir__}/identifiers/harmonization_document"
14
+ autoload :Supplement, "#{__dir__}/identifiers/supplement"
15
+ autoload :Amendment, "#{__dir__}/identifiers/amendment"
16
+ autoload :Corrigendum, "#{__dir__}/identifiers/corrigendum"
17
+ autoload :ConsolidatedIdentifier, "#{__dir__}/identifiers/consolidated_identifier"
18
+ autoload :Fragment, "#{__dir__}/identifiers/fragment"
5
19
  end
6
20
  end
7
21
  end
@@ -6,10 +6,29 @@
6
6
  # namespace; identifiers carry the scheme's wire tag, so their
7
7
  # pubid URNs encode through the scheme's own schema.
8
8
  PubidUrnSchema = Pubid::PubidUrn.define("cen_pfs") do
9
+ atom "publisher", "pub"
10
+ atom "copublishers", "co", kind: :list
9
11
  atom "part", "part"
10
12
  atom "year", "year"
13
+ atom "version", "v"
14
+ atom "stage", "stage"
15
+ atom "adopted", "adopted", kind: :id
16
+ atom "identifiers", "ids", kind: :ids
17
+ type "pubid:cencenelec:adopted-european-norm", "aen", core: []
18
+ type "pubid:cencenelec:amendment", "amd", core: []
19
+ type "pubid:cencenelec:cen-report", "cr", core: []
20
+ type "pubid:cencenelec:cen-workshop-agreement", "cwa", core: []
21
+ type "pubid:cencenelec:consolidated-identifier", "consol", core: []
22
+ type "pubid:cencenelec:corrigendum", "cor", core: []
23
+ type "pubid:cencenelec:european-norm", "en", core: []
24
+ type "pubid:cencenelec:european-prestandard", "ep", core: []
25
+ type "pubid:cencenelec:european-specification", "es", core: []
26
+ type "pubid:cencenelec:fragment", "fragment", core: []
27
+ type "pubid:cencenelec:guide", "guide", core: []
28
+ type "pubid:cencenelec:harmonization-document", "hd", core: []
11
29
  type "pubid:cencenelec:identifier", "id", core: []
12
- type "pubid:cencenelec:european-norm", "en", core: ["number"]
30
+ type "pubid:cencenelec:technical-report", "tr", core: []
31
+ type "pubid:cencenelec:technical-specification", "ts", core: []
13
32
  end
14
33
  end
15
34
  end
@@ -2,8 +2,57 @@ module Pubid
2
2
  module CenPfs
3
3
  # Human renderer, generated from the canonical template.
4
4
  class Renderer < ::Pubid::Renderers::Base
5
+ FACE_stage = {
6
+ "fpren" => "FprEN",
7
+ "pren" => "prEN",
8
+ }.freeze
5
9
  def render(**_opts)
6
- "EN #{@id.number}#{"-#{@id.part}" if @id.part}#{":#{@id.date.year}" if @id.date&.year}"
10
+ f = render_fields(@id)
11
+ "#{if f[:stage] && f[:number]; "#{f[:stage]} #{f[:number]}#{("-#{f[:part]}") if f[:part]}#{("#{f[:version]}") if f[:version]}#{(":#{f[:year]}") if f[:year]}" elsif f[:publisher] && f[:guide] && f[:number]; "#{f[:publisher]}#{("#{f[:copublishers]}") if f[:copublishers]} #{f[:guide]} #{f[:number]}#{("-#{f[:part]}") if f[:part]}#{(":#{f[:year]}") if f[:year]}" elsif f[:publisher] && f[:adopted]; "#{f[:publisher]}#{("#{f[:copublishers]}") if f[:copublishers]} #{f[:adopted]}" elsif f[:publisher] && f[:number]; "#{f[:publisher]}#{("#{f[:copublishers]}") if f[:copublishers]}#{("/#{f[:type]}") if f[:type]} #{f[:number]}#{("-#{f[:part]}") if f[:part]}#{("#{f[:version]}") if f[:version]}#{(":#{f[:year]}") if f[:year]}"; end}#{("#{f[:supplements]}#{(" FRAG#{f[:fragment_number]}") if f[:fragment_number]}") if f[:supplements]}"
12
+ end
13
+
14
+ private
15
+
16
+ # The field view: a wrapper reads through to the wrapped
17
+ # standard and composes the printed run once — the standalone
18
+ # chain behind its slash, the consolidated members behind the
19
+ # plus — and the fragment face follows its base.
20
+ def render_fields(id)
21
+ root = id
22
+ run = +""
23
+ members = nil
24
+ frag = nil
25
+ if root.is_a?(Identifiers::Fragment)
26
+ frag = root.number
27
+ root = root.base
28
+ end
29
+ if root.is_a?(Identifiers::ConsolidatedIdentifier)
30
+ base, *consolidated = root.identifiers
31
+ members = consolidated
32
+ root = base
33
+ end
34
+ while root.is_a?(Identifiers::Supplement)
35
+ run.prepend("/#{root.supplement_notation}")
36
+ root = root.base
37
+ end
38
+ members&.each do |member|
39
+ run << "+#{member.supplement_notation}"
40
+ end
41
+ view = {
42
+ publisher: root.publisher&.respond_to?(:body) ? root.publisher.body : root.publisher,
43
+ copublishers: root.copublishers.to_a.any? ? root.copublishers.map { |item| "/#{item.respond_to?(:body) ? item.body : item}" }.join : nil,
44
+ stage: FACE_stage.fetch(root.typed_stage&.code&.to_s, root.typed_stage&.code&.to_s),
45
+ type: (v = root.type&.abbr) && ["TR", "TS"].include?(v) ? v : nil,
46
+ guide: (v = root.type&.abbr) && ["Guide"].include?(v) ? v : nil,
47
+ number: root.number,
48
+ part: root.part,
49
+ version: root.version,
50
+ year: root.date&.year,
51
+ adopted: root.respond_to?(:adopted) ? root.adopted : nil,
52
+ }
53
+ view[:supplements] = run.empty? ? nil : run
54
+ view[:fragment_number] = frag
55
+ view
7
56
  end
8
57
  end
9
58
  end