pubid 2.0.0.pre.alpha.12 → 2.0.0.pre.alpha.13
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.
- checksums.yaml +4 -4
- data/README.adoc +43 -1
- data/data/ieee/update_codes.yaml +17 -4
- data/data/nist/update_codes.yaml +7 -3
- data/lib/pubid/adobe/builder.rb +2 -0
- data/lib/pubid/all_parts.rb +201 -0
- data/lib/pubid/all_parts_identifier.rb +19 -0
- data/lib/pubid/amca/CLAUDE.md +47 -0
- data/lib/pubid/amca/builder.rb +3 -5
- data/lib/pubid/amca/identifiers/base.rb +10 -0
- data/lib/pubid/amca/identifiers/publication.rb +13 -0
- data/lib/pubid/amca/parser.rb +2 -1
- data/lib/pubid/amca/renderer.rb +22 -33
- data/lib/pubid/amca/urn_generator.rb +21 -2
- data/lib/pubid/amca/urn_parser.rb +36 -10
- data/lib/pubid/ansi/builder.rb +6 -0
- data/lib/pubid/api/CLAUDE.md +23 -0
- data/lib/pubid/api/builder.rb +2 -0
- data/lib/pubid/ashrae/CLAUDE.md +13 -0
- data/lib/pubid/ashrae/builder.rb +58 -14
- data/lib/pubid/ashrae/identifiers/errata.rb +14 -2
- data/lib/pubid/ashrae/identifiers/interpretation.rb +2 -10
- data/lib/pubid/ashrae/parser.rb +62 -28
- data/lib/pubid/ashrae/renderer.rb +32 -1
- data/lib/pubid/ashrae/urn_generator.rb +32 -9
- data/lib/pubid/asme/CLAUDE.md +25 -0
- data/lib/pubid/asme/builder.rb +16 -9
- data/lib/pubid/asme/components/code.rb +2 -0
- data/lib/pubid/asme/identifiers/standard.rb +6 -1
- data/lib/pubid/asme/parser.rb +41 -14
- data/lib/pubid/astm/CLAUDE.md +9 -0
- data/lib/pubid/astm/builder.rb +2 -0
- data/lib/pubid/astm/components/code.rb +2 -0
- data/lib/pubid/astm/parser.rb +4 -1
- data/lib/pubid/bipm/CLAUDE.md +11 -0
- data/lib/pubid/bipm/builder.rb +2 -0
- data/lib/pubid/bsi/CLAUDE.md +93 -0
- data/lib/pubid/bsi/builder.rb +13 -11
- data/lib/pubid/bsi/identifiers/addendum_document.rb +2 -0
- data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +6 -54
- data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +5 -22
- data/lib/pubid/bsi/identifiers/amendment.rb +36 -12
- data/lib/pubid/bsi/identifiers/bundled_identifier.rb +2 -0
- data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +23 -26
- data/lib/pubid/bsi/identifiers/corrigendum.rb +29 -12
- data/lib/pubid/bsi/identifiers/expert_commentary.rb +6 -7
- data/lib/pubid/bsi/identifiers/national_annex.rb +18 -20
- data/lib/pubid/bsi/identifiers/root_identity.rb +31 -0
- data/lib/pubid/bsi/identifiers/set.rb +2 -0
- data/lib/pubid/bsi/identifiers/supplement_document.rb +2 -0
- data/lib/pubid/bsi/identifiers.rb +1 -0
- data/lib/pubid/bsi/parser.rb +8 -8
- data/lib/pubid/bsi/renderer.rb +20 -20
- data/lib/pubid/bsi/urn_generator.rb +28 -18
- data/lib/pubid/builder/base.rb +27 -0
- data/lib/pubid/calconnect/builder.rb +2 -0
- data/lib/pubid/calconnect/identifier.rb +4 -0
- data/lib/pubid/ccsds/builder.rb +2 -0
- data/lib/pubid/ccsds/identifier.rb +8 -0
- data/lib/pubid/cen_cenelec/CLAUDE.md +59 -0
- data/lib/pubid/cen_cenelec/builder.rb +6 -1
- data/lib/pubid/cen_cenelec/identifier.rb +10 -27
- data/lib/pubid/cen_cenelec/identifiers/amendment.rb +3 -10
- data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +3 -10
- data/lib/pubid/cen_cenelec/parser.rb +11 -3
- data/lib/pubid/cie/CLAUDE.md +58 -0
- data/lib/pubid/cie/builder.rb +2 -0
- data/lib/pubid/cie/components/language.rb +2 -0
- data/lib/pubid/components/adoption.rb +2 -0
- data/lib/pubid/components/code.rb +2 -0
- data/lib/pubid/components/date.rb +8 -6
- data/lib/pubid/components/edition.rb +2 -0
- data/lib/pubid/components/iteration.rb +2 -0
- data/lib/pubid/components/language.rb +2 -0
- data/lib/pubid/components/locality.rb +2 -0
- data/lib/pubid/components/publisher.rb +2 -0
- data/lib/pubid/components/relationship.rb +2 -0
- data/lib/pubid/components/stage.rb +2 -0
- data/lib/pubid/components/supplement.rb +2 -0
- data/lib/pubid/components/type.rb +2 -0
- data/lib/pubid/components/typed_stage.rb +8 -0
- data/lib/pubid/csa/CLAUDE.md +41 -0
- data/lib/pubid/csa/builder.rb +2 -0
- data/lib/pubid/csa/identifier.rb +13 -1
- data/lib/pubid/csa/renderer.rb +12 -12
- data/lib/pubid/csa/single_identifier.rb +17 -0
- data/lib/pubid/doi/builder.rb +2 -0
- data/lib/pubid/easc/builder.rb +2 -0
- data/lib/pubid/ecma/CLAUDE.md +28 -0
- data/lib/pubid/ecma/builder.rb +2 -0
- data/lib/pubid/ecma/identifier.rb +7 -0
- data/lib/pubid/etsi/CLAUDE.md +34 -0
- data/lib/pubid/etsi/builder.rb +2 -0
- data/lib/pubid/etsi/components/code.rb +6 -0
- data/lib/pubid/etsi/components/version.rb +2 -0
- data/lib/pubid/etsi/identifiers/etsi_standard.rb +7 -0
- data/lib/pubid/evs/CLAUDE.md +58 -0
- data/lib/pubid/evs/builder.rb +2 -0
- data/lib/pubid/gb/CLAUDE.md +140 -0
- data/lib/pubid/gb/builder.rb +7 -2
- data/lib/pubid/gb/identifier.rb +5 -3
- data/lib/pubid/gb/identifiers/all_parts.rb +17 -0
- data/lib/pubid/gb/identifiers.rb +1 -0
- data/lib/pubid/gb/renderer.rb +0 -1
- data/lib/pubid/gost/CLAUDE.md +64 -0
- data/lib/pubid/gost/builder.rb +3 -1
- data/lib/pubid/gost/identifier.rb +5 -0
- data/lib/pubid/iala/CLAUDE.md +82 -0
- data/lib/pubid/iala/builder.rb +2 -0
- data/lib/pubid/iana/CLAUDE.md +7 -0
- data/lib/pubid/iana/builder.rb +2 -0
- data/lib/pubid/identifier.rb +161 -17
- data/lib/pubid/idf/builder.rb +6 -1
- data/lib/pubid/idf/identifier.rb +5 -0
- data/lib/pubid/idf/identifiers/all_parts.rb +17 -0
- data/lib/pubid/idf/identifiers.rb +1 -0
- data/lib/pubid/iec/CLAUDE.md +31 -0
- data/lib/pubid/iec/builder.rb +7 -1
- data/lib/pubid/iec/components/consolidated_amendment.rb +4 -0
- data/lib/pubid/iec/components/sheet.rb +2 -0
- data/lib/pubid/iec/components/trf_info.rb +2 -0
- data/lib/pubid/iec/components/vap_suffix.rb +2 -0
- data/lib/pubid/iec/identifier.rb +7 -2
- data/lib/pubid/iec/identifiers/all_parts.rb +19 -0
- data/lib/pubid/iec/identifiers.rb +1 -0
- data/lib/pubid/iec/renderer.rb +0 -1
- data/lib/pubid/iec/urn_generator.rb +9 -1
- data/lib/pubid/iec/urn_parser.rb +3 -2
- data/lib/pubid/ieee/CLAUDE.md +97 -0
- data/lib/pubid/ieee/builder.rb +134 -5
- data/lib/pubid/ieee/components/code.rb +2 -0
- data/lib/pubid/ieee/components/draft.rb +35 -2
- data/lib/pubid/ieee/components/typed_stage.rb +2 -0
- data/lib/pubid/ieee/identifiers/base.rb +20 -0
- data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +9 -0
- data/lib/pubid/ieee/identifiers/joint_development.rb +17 -10
- data/lib/pubid/ieee/identifiers/project_draft_identifier.rb +8 -1
- data/lib/pubid/ieee/parser.rb +134 -21
- data/lib/pubid/ieee/renderer.rb +40 -7
- data/lib/pubid/ieee/urn_generator.rb +31 -0
- data/lib/pubid/ietf/CLAUDE.md +7 -0
- data/lib/pubid/ietf/builder.rb +2 -0
- data/lib/pubid/iho/builder.rb +2 -0
- data/lib/pubid/isbn/builder.rb +2 -0
- data/lib/pubid/iso/CLAUDE.md +47 -0
- data/lib/pubid/iso/builder.rb +19 -5
- data/lib/pubid/iso/components/publisher.rb +2 -0
- data/lib/pubid/iso/identifier.rb +6 -14
- data/lib/pubid/iso/identifiers/all_parts.rb +19 -0
- data/lib/pubid/iso/identifiers/directives_supplement.rb +4 -2
- data/lib/pubid/iso/identifiers.rb +1 -0
- data/lib/pubid/iso/rendering_style.rb +0 -1
- data/lib/pubid/itu/CLAUDE.md +69 -0
- data/lib/pubid/itu/builder.rb +2 -0
- data/lib/pubid/itu/components/code.rb +2 -0
- data/lib/pubid/itu/components/designation.rb +2 -0
- data/lib/pubid/itu/components/sector.rb +2 -0
- data/lib/pubid/itu/components/series.rb +2 -0
- data/lib/pubid/itu/identifiers/supplement.rb +15 -0
- data/lib/pubid/jcgm/CLAUDE.md +7 -0
- data/lib/pubid/jcgm/builder.rb +2 -0
- data/lib/pubid/jcgm/components/publisher.rb +2 -0
- data/lib/pubid/jis/builder.rb +5 -1
- data/lib/pubid/jis/identifier.rb +5 -17
- data/lib/pubid/jis/identifiers/all_parts.rb +19 -0
- data/lib/pubid/jis/identifiers.rb +1 -0
- data/lib/pubid/jis/renderer.rb +0 -2
- data/lib/pubid/jis/urn_generator.rb +0 -1
- data/lib/pubid/nist/CLAUDE.md +56 -0
- data/lib/pubid/nist/builder.rb +2 -0
- data/lib/pubid/nist/components/edition.rb +2 -0
- data/lib/pubid/nist/components/issue_number.rb +2 -0
- data/lib/pubid/nist/components/part.rb +2 -0
- data/lib/pubid/nist/components/stage.rb +2 -0
- data/lib/pubid/nist/components/supplement.rb +2 -0
- data/lib/pubid/nist/components/translation.rb +2 -0
- data/lib/pubid/nist/components/update.rb +2 -0
- data/lib/pubid/nist/components/version.rb +2 -0
- data/lib/pubid/nist/components/volume.rb +2 -0
- data/lib/pubid/nist/identifiers/base.rb +24 -3
- data/lib/pubid/nist/parser.rb +15 -2
- data/lib/pubid/nist/preprocessor.rb +53 -2
- data/lib/pubid/oasis/CLAUDE.md +19 -0
- data/lib/pubid/oasis/builder.rb +2 -0
- data/lib/pubid/oasis/identifier.rb +19 -0
- data/lib/pubid/ogc/CLAUDE.md +34 -0
- data/lib/pubid/ogc/builder.rb +2 -0
- data/lib/pubid/ogc/identifier.rb +11 -0
- data/lib/pubid/oiml/CLAUDE.md +189 -0
- data/lib/pubid/oiml/builder.rb +20 -0
- data/lib/pubid/oiml/components/code.rb +6 -0
- data/lib/pubid/oiml/identifier.rb +13 -0
- data/lib/pubid/oiml/identifiers/annex.rb +4 -0
- data/lib/pubid/oiml/identifiers/certification_system.rb +34 -0
- data/lib/pubid/oiml/identifiers/code_number.rb +8 -0
- data/lib/pubid/oiml/identifiers/dual_published.rb +174 -0
- data/lib/pubid/oiml/identifiers.rb +2 -0
- data/lib/pubid/oiml/parser.rb +35 -4
- data/lib/pubid/oiml/renderer.rb +23 -1
- data/lib/pubid/oiml/single_identifier.rb +4 -0
- data/lib/pubid/oiml/supplement_identifier.rb +7 -0
- data/lib/pubid/oiml/urn_generator.rb +28 -0
- data/lib/pubid/oiml.rb +5 -0
- data/lib/pubid/omg/CLAUDE.md +15 -0
- data/lib/pubid/omg/builder.rb +2 -0
- data/lib/pubid/parser/grammar.rb +23 -0
- data/lib/pubid/plateau/builder.rb +2 -0
- data/lib/pubid/plateau/identifiers/base.rb +4 -0
- data/lib/pubid/plateau/supplement_identifier.rb +14 -2
- data/lib/pubid/plateau/urn_generator.rb +7 -1
- data/lib/pubid/renderers/human_readable.rb +0 -1
- data/lib/pubid/sae/builder.rb +2 -0
- data/lib/pubid/sae/components/date.rb +2 -0
- data/lib/pubid/sae/components/type.rb +2 -0
- data/lib/pubid/subset_match.rb +197 -0
- data/lib/pubid/tgpp/CLAUDE.md +43 -0
- data/lib/pubid/tgpp/builder.rb +2 -0
- data/lib/pubid/tgpp/identifier.rb +14 -0
- data/lib/pubid/type_resolver.rb +14 -2
- data/lib/pubid/un/builder.rb +2 -0
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/CLAUDE.md +7 -0
- data/lib/pubid/w3c/builder.rb +2 -0
- data/lib/pubid/xsf/CLAUDE.md +11 -0
- data/lib/pubid/xsf/builder.rb +2 -0
- data/lib/pubid.rb +16 -3
- metadata +44 -2
|
@@ -7,8 +7,22 @@ module Pubid
|
|
|
7
7
|
# Contains a base identifier plus amendment parameters
|
|
8
8
|
class Amendment < SingleIdentifier
|
|
9
9
|
attribute :base, ::Pubid::Identifier, polymorphic: true
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
# The amendment's ordinal lives in the `number` inherited from
|
|
11
|
+
# SingleIdentifier — already a `:string` there, which is what the
|
|
12
|
+
# ordinal is ("1", "11", "AA") — so the row reads `number:` rather than
|
|
13
|
+
# `amendment_number:`.
|
|
14
|
+
#
|
|
15
|
+
# This does NOT make the ordinal a document number: the amended
|
|
16
|
+
# standard is reached through `base`, and `#root` walks it, which is
|
|
17
|
+
# what relaton-index keys on.
|
|
18
|
+
#
|
|
19
|
+
# The year lives in the inherited `date` component, the natural home:
|
|
20
|
+
# an amendment's year belongs to the supplement, not to the standard,
|
|
21
|
+
# and `#exclude` protects it via `supplement_date_attributes` below,
|
|
22
|
+
# so `exclude(:date)` on a consolidated identifier drops only the
|
|
23
|
+
# standard's date. The flat scalar serialization rule renders a
|
|
24
|
+
# degenerate `date` as a bare `year:` key, matching CEN and every
|
|
25
|
+
# other BSI row.
|
|
12
26
|
attribute :separator, :string, default: -> { "+" }
|
|
13
27
|
# true for the trailing " AMD5" / " AMD AA" suffix form, false for the
|
|
14
28
|
# compact "+A5" / "/A5" join form. Distinguishes the two when no year is
|
|
@@ -19,6 +33,23 @@ module Pubid
|
|
|
19
33
|
base&.publisher
|
|
20
34
|
end
|
|
21
35
|
|
|
36
|
+
# `publisher` reads through to the base, so it is never this
|
|
37
|
+
# amendment's own state. Lutaml only serializes the borrowed component
|
|
38
|
+
# when the member came from from_hash (the parse path shares the base
|
|
39
|
+
# instance, and lutaml omits the reference), which made
|
|
40
|
+
# from_hash(to_hash(id)).to_hash regrow a `publisher` key the parse
|
|
41
|
+
# path never emits. Drop it unconditionally to keep the wire symmetric.
|
|
42
|
+
def self.compact_hash(_model, hash)
|
|
43
|
+
hash.delete("publisher")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# See the comment on `date` above: protects the amendment's own date
|
|
47
|
+
# from a bare `exclude(:date)`/`exclude(:year)`, which otherwise
|
|
48
|
+
# recurses into `base` and drops the standard's date too.
|
|
49
|
+
def self.supplement_date_attributes
|
|
50
|
+
%i[date]
|
|
51
|
+
end
|
|
52
|
+
|
|
22
53
|
# Base document = the standard this amendment applies to, fully peeled.
|
|
23
54
|
def base_document
|
|
24
55
|
base&.base_document || self
|
|
@@ -29,19 +60,12 @@ module Pubid
|
|
|
29
60
|
base || self
|
|
30
61
|
end
|
|
31
62
|
|
|
32
|
-
#
|
|
33
|
-
#
|
|
63
|
+
# Names the supplement class, so callers need not special-case it. The
|
|
64
|
+
# ordinal and the year need no such method: Amendment and Corrigendum —
|
|
65
|
+
# in BSI and in CEN — all declare them as `number` and `year`.
|
|
34
66
|
def supplement_type
|
|
35
67
|
:amendment
|
|
36
68
|
end
|
|
37
|
-
|
|
38
|
-
def supplement_number
|
|
39
|
-
amendment_number
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def supplement_year
|
|
43
|
-
amendment_year
|
|
44
|
-
end
|
|
45
69
|
end
|
|
46
70
|
end
|
|
47
71
|
end
|
|
@@ -12,6 +12,8 @@ module Pubid
|
|
|
12
12
|
# BS SP 13; 14; 15 and 16:1949
|
|
13
13
|
# BS 4048:Parts 1 and 2:1966
|
|
14
14
|
class BundledIdentifier < SingleIdentifier
|
|
15
|
+
include RootIdentity
|
|
16
|
+
|
|
15
17
|
attribute :identifiers, ::Pubid::Identifier, collection: true,
|
|
16
18
|
polymorphic: true
|
|
17
19
|
attribute :separators, :string, collection: true # Separators between identifiers
|
|
@@ -6,6 +6,8 @@ module Pubid
|
|
|
6
6
|
# Consolidated Identifier - contains base document plus supplements
|
|
7
7
|
# Example: "BS 4592-0:2006+A1:2012" = [BS 4592-0:2006, Amendment 1:2012]
|
|
8
8
|
class ConsolidatedIdentifier < SingleIdentifier
|
|
9
|
+
include RootIdentity
|
|
10
|
+
|
|
9
11
|
attribute :identifiers, ::Pubid::Identifier, polymorphic: true,
|
|
10
12
|
collection: true
|
|
11
13
|
|
|
@@ -19,11 +21,11 @@ module Pubid
|
|
|
19
21
|
# Append supplement info to URN
|
|
20
22
|
identifiers[1..].each do |id|
|
|
21
23
|
if id.is_a?(Amendment)
|
|
22
|
-
urn += ":amd:#{id.
|
|
23
|
-
urn += ":#{id.
|
|
24
|
+
urn += ":amd:#{id.number}"
|
|
25
|
+
urn += ":#{id.year}" if id.year
|
|
24
26
|
elsif id.is_a?(Corrigendum)
|
|
25
|
-
urn += ":cor:#{id.
|
|
26
|
-
urn += ":#{id.
|
|
27
|
+
urn += ":cor:#{id.number}"
|
|
28
|
+
urn += ":#{id.year}" if id.year
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
urn
|
|
@@ -34,30 +36,25 @@ module Pubid
|
|
|
34
36
|
identifiers&.first&.publisher
|
|
35
37
|
end
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
base = identifiers&.first
|
|
43
|
-
base.year if base&.class&.attributes&.key?(:year)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def date
|
|
47
|
-
base = identifiers&.first
|
|
48
|
-
base.date if base&.class&.attributes&.key?(:date)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def parts
|
|
52
|
-
base = identifiers&.first
|
|
53
|
-
base.parts if base&.class&.attributes&.key?(:parts)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def part
|
|
57
|
-
base = identifiers&.first
|
|
58
|
-
base.part if base&.class&.attributes&.key?(:part)
|
|
39
|
+
# See Identifiers::Amendment.compact_hash: the publisher is derived
|
|
40
|
+
# from the first member and must stay off the wrapper's own wire entry,
|
|
41
|
+
# or from_hash round-trips regrow it.
|
|
42
|
+
def self.compact_hash(_model, hash)
|
|
43
|
+
hash.delete("publisher")
|
|
59
44
|
end
|
|
60
45
|
|
|
46
|
+
# `number`, `part`, `parts`, `date` and `year` are deliberately NOT
|
|
47
|
+
# delegated. They used to read `identifiers.first`, one level only, so
|
|
48
|
+
# they answered with the member's value when that member was a plain
|
|
49
|
+
# standard and with nil when it was itself a wrapper (an adoption) —
|
|
50
|
+
# the same accessor reporting two different things. They also shadowed
|
|
51
|
+
# real lutaml attributes, and the `date` one handed lutaml a foreign
|
|
52
|
+
# `Pubid::Components::Date` where BSI declares its own subclass, which
|
|
53
|
+
# is what made `to_hash` raise.
|
|
54
|
+
#
|
|
55
|
+
# A BSI wrapper owns no identity: `#root` carries it, recursively and
|
|
56
|
+
# for every layer. See `Identifiers::RootIdentity` and
|
|
57
|
+
# lib/pubid/bsi/CLAUDE.md.
|
|
61
58
|
def type
|
|
62
59
|
base = identifiers&.first
|
|
63
60
|
base.type if base&.class&.attributes&.key?(:type)
|
|
@@ -7,14 +7,38 @@ module Pubid
|
|
|
7
7
|
# Contains a base identifier plus corrigendum parameters
|
|
8
8
|
class Corrigendum < SingleIdentifier
|
|
9
9
|
attribute :base, ::Pubid::Identifier, polymorphic: true
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
# The ordinal lives in `number` (inherited, already a `:string`), and
|
|
11
|
+
# the year in the inherited `date` component, exactly as on Amendment
|
|
12
|
+
# — see that class for why `date` is now safe to use: `#exclude`
|
|
13
|
+
# protects it via `supplement_date_attributes` below, so
|
|
14
|
+
# `exclude(:date)` drops only the standard's date. The flat scalar
|
|
15
|
+
# serialization rule renders a degenerate `date` as a bare `year:`
|
|
16
|
+
# key, so relaton still compares a plain String across supplement
|
|
17
|
+
# classes and flavors.
|
|
18
|
+
#
|
|
19
|
+
# The year is nil for a year-less corrigendum (`BS 1234:2015+C1`),
|
|
20
|
+
# which parses; `number` is in practice always set, because the grammar
|
|
21
|
+
# requires a digit after the `C` — the unnumbered `+C:2016` form that
|
|
22
|
+
# CEN spells `AC` does not parse in BSI at all.
|
|
12
23
|
attribute :separator, :string, default: -> { "+" }
|
|
13
24
|
|
|
14
25
|
def publisher
|
|
15
26
|
base&.publisher
|
|
16
27
|
end
|
|
17
28
|
|
|
29
|
+
# See Amendment.compact_hash: the publisher is borrowed from the base
|
|
30
|
+
# and must never appear on the supplement's own wire entry.
|
|
31
|
+
def self.compact_hash(_model, hash)
|
|
32
|
+
hash.delete("publisher")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# See the comment on `date` above: protects the corrigendum's own
|
|
36
|
+
# date from a bare `exclude(:date)`/`exclude(:year)`, which otherwise
|
|
37
|
+
# recurses into `base` and drops the standard's date too.
|
|
38
|
+
def self.supplement_date_attributes
|
|
39
|
+
%i[date]
|
|
40
|
+
end
|
|
41
|
+
|
|
18
42
|
# Base document = the standard this corrigendum applies to, fully peeled.
|
|
19
43
|
def base_document
|
|
20
44
|
base&.base_document || self
|
|
@@ -25,19 +49,12 @@ module Pubid
|
|
|
25
49
|
base || self
|
|
26
50
|
end
|
|
27
51
|
|
|
28
|
-
#
|
|
29
|
-
#
|
|
52
|
+
# Names the supplement class, so callers need not special-case it. The
|
|
53
|
+
# ordinal and the year need no such method: Amendment and Corrigendum —
|
|
54
|
+
# in BSI and in CEN — all declare them as `number` and `year`.
|
|
30
55
|
def supplement_type
|
|
31
56
|
:corrigendum
|
|
32
57
|
end
|
|
33
|
-
|
|
34
|
-
def supplement_number
|
|
35
|
-
corrigendum_number
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def supplement_year
|
|
39
|
-
corrigendum_year
|
|
40
|
-
end
|
|
41
58
|
end
|
|
42
59
|
end
|
|
43
60
|
end
|
|
@@ -10,6 +10,8 @@ module Pubid
|
|
|
10
10
|
# 2. "ExComm" (abbreviated form)
|
|
11
11
|
# 3. "ExComm (Fire)" (with optional topic suffix)
|
|
12
12
|
class ExpertCommentary < SingleIdentifier
|
|
13
|
+
include RootIdentity
|
|
14
|
+
|
|
13
15
|
attribute :base, ::Pubid::Identifier, polymorphic: true
|
|
14
16
|
attribute :format, :string # "full", "abbr", "abbr_with_topic"
|
|
15
17
|
attribute :topic, :string # e.g., "Fire"
|
|
@@ -18,13 +20,10 @@ module Pubid
|
|
|
18
20
|
base&.publisher
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def year
|
|
26
|
-
base&.year
|
|
27
|
-
end
|
|
23
|
+
# `number` and `year` are deliberately NOT delegated — a BSI wrapper
|
|
24
|
+
# owns no identity, and a one-level delegation answered with nil
|
|
25
|
+
# whenever `base` was itself a wrapper. `#root` carries identity for
|
|
26
|
+
# every layer. See `Identifiers::RootIdentity` and lib/pubid/bsi/CLAUDE.md.
|
|
28
27
|
|
|
29
28
|
# Base document = the commented standard, fully peeled.
|
|
30
29
|
def base_document
|
|
@@ -6,8 +6,24 @@ module Pubid
|
|
|
6
6
|
# National Annex (NA) identifier
|
|
7
7
|
# Can have own supplements: "NA+A1:2012 to BASE"
|
|
8
8
|
class NationalAnnex < SingleIdentifier
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
include RootIdentity
|
|
10
|
+
|
|
11
|
+
# Supplements on the NA itself. `initialize_empty: true` because the
|
|
12
|
+
# builder always passes an array (empty when the grammar matched no
|
|
13
|
+
# supplement) while `from_hash` never sets the attribute at all — the
|
|
14
|
+
# serialized hash omits an empty collection — so a parsed NA held `[]`
|
|
15
|
+
# and a deserialized one `nil`, and the two were not `==`. `#matches?`
|
|
16
|
+
# is `exclude(*ignore) == other.exclude(*ignore)`, so every index lookup
|
|
17
|
+
# of a supplement-less NA silently returned nothing. The `collection:
|
|
18
|
+
# true` lesson in CLAUDE.md, and the same one-line remedy.
|
|
19
|
+
attribute :na_supplements, ::Pubid::Identifier, polymorphic: true,
|
|
20
|
+
collection: true,
|
|
21
|
+
initialize_empty: true
|
|
22
|
+
# The identifier after "to", under the uniform parent accessor. `#root`
|
|
23
|
+
# and `#base_document` are inherited and walk it, so the delegating
|
|
24
|
+
# readers this class used to carry are gone — they shadowed real lutaml
|
|
25
|
+
# accessors and reached only one level down.
|
|
26
|
+
attribute :base, ::Pubid::Identifier, polymorphic: true
|
|
11
27
|
|
|
12
28
|
TYPED_STAGES = [
|
|
13
29
|
Pubid::Components::TypedStage.new(
|
|
@@ -24,24 +40,6 @@ module Pubid
|
|
|
24
40
|
{ key: :na,
|
|
25
41
|
web: :national_annex, title: "National Annex", short: "NA" }
|
|
26
42
|
end
|
|
27
|
-
|
|
28
|
-
# Delegation methods to access wrapped base_doc attributes
|
|
29
|
-
def number
|
|
30
|
-
base_doc&.number || super
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def date
|
|
34
|
-
base_doc&.date || super
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def part
|
|
38
|
-
base_doc&.part || super
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def subpart
|
|
42
|
-
base_doc&.subpart || super
|
|
43
|
-
end
|
|
44
|
-
|
|
45
43
|
end
|
|
46
44
|
end
|
|
47
45
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pubid
|
|
4
|
+
module Bsi
|
|
5
|
+
module Identifiers
|
|
6
|
+
# MR-slug hooks for a BSI wrapper that carries no identity of its own.
|
|
7
|
+
#
|
|
8
|
+
# The base `mr_number_with_part` and `mr_year` read the receiver's own
|
|
9
|
+
# `number`, `part`, `subpart` and `date`. A wrapper — an adoption, a
|
|
10
|
+
# national annex, a consolidated edition, an Expert-commentary volume —
|
|
11
|
+
# leaves all four nil and keeps the identity on the document it wraps, so
|
|
12
|
+
# those hooks produced a slug with no number at all: 158 BSI identifiers
|
|
13
|
+
# collapsed onto the bare `bs`, and `to_slug` is an output FILENAME.
|
|
14
|
+
#
|
|
15
|
+
# `#root` and not `base`: a "DD ENV ISO 11079:1999" adopts a CEN
|
|
16
|
+
# EuropeanPrestandard, which is itself a wrapper around the ISO standard,
|
|
17
|
+
# so one level down is not far enough. `#root` recurses, and for a
|
|
18
|
+
# non-wrapper it is `self` — hence the `equal?` guard, which sends an
|
|
19
|
+
# ordinary identifier to the base hooks unchanged.
|
|
20
|
+
module RootIdentity
|
|
21
|
+
def mr_number_with_part
|
|
22
|
+
root.equal?(self) ? super : root.mr_number_with_part
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def mr_year
|
|
26
|
+
root.equal?(self) ? super : root.mr_year
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -13,6 +13,8 @@ module Pubid
|
|
|
13
13
|
# BS ISO 20400 + BS ISO 44001+BS ISO 44002
|
|
14
14
|
# BS ISO 9001+BS ISO 14001
|
|
15
15
|
class Set < SingleIdentifier
|
|
16
|
+
include RootIdentity
|
|
17
|
+
|
|
16
18
|
attribute :identifiers, ::Pubid::Identifier, collection: true,
|
|
17
19
|
polymorphic: true
|
|
18
20
|
attribute :separators, :string, collection: true # Should all be " + "
|
|
@@ -9,6 +9,8 @@ module Pubid
|
|
|
9
9
|
# Forward: "BS 1000:Supplement No. 1:1972", "BS 1722-1 Supplement No. 1:1974"
|
|
10
10
|
# Reverse: "Supplement No. 1 (1970) to BS 1831:1969"
|
|
11
11
|
class SupplementDocument < SingleIdentifier
|
|
12
|
+
include RootIdentity
|
|
13
|
+
|
|
12
14
|
attribute :base, ::Pubid::Identifier, polymorphic: true
|
|
13
15
|
attribute :supplement_number, :string
|
|
14
16
|
attribute :supplement_year, :integer
|
|
@@ -35,6 +35,7 @@ module Pubid
|
|
|
35
35
|
autoload :PublishedDocument, "#{__dir__}/identifiers/published_document"
|
|
36
36
|
autoload :PubliclyAvailableSpecification,
|
|
37
37
|
"#{__dir__}/identifiers/publicly_available_specification"
|
|
38
|
+
autoload :RootIdentity, "#{__dir__}/identifiers/root_identity"
|
|
38
39
|
autoload :Section, "#{__dir__}/identifiers/section"
|
|
39
40
|
autoload :Set, "#{__dir__}/identifiers/set"
|
|
40
41
|
autoload :StandaloneAmendment,
|
data/lib/pubid/bsi/parser.rb
CHANGED
|
@@ -412,49 +412,49 @@ module Pubid
|
|
|
412
412
|
rule(:addendum_document) do
|
|
413
413
|
# With multi-letter flex type prefix (CECC, E9111, etc.)
|
|
414
414
|
(bs.as(:publisher) >> space >> multi_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
|
|
415
|
-
(colon | space).as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
|
|
415
|
+
(colon | space).as(:add_sep) >> str("Addendum") >> space.repeat(1) >> str("No.").as(:add_no_prefix) >> space.repeat(1) >>
|
|
416
416
|
digits.as(:addendum_number) >> colon >> digit.repeat(4,
|
|
417
417
|
4).as(:addendum_year)
|
|
418
418
|
).as(:addendum_document) |
|
|
419
419
|
(bs.as(:publisher) >> space >> multi_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
|
|
420
|
-
(colon | space).as(:add_sep) >> str("Addendum") >> space >>
|
|
420
|
+
(colon | space).as(:add_sep) >> str("Addendum") >> space.repeat(1) >>
|
|
421
421
|
digits.as(:addendum_number) >> colon >> digit.repeat(4,
|
|
422
422
|
4).as(:addendum_year)
|
|
423
423
|
).as(:addendum_document) |
|
|
424
424
|
# With single-letter flex type prefix (M, etc.)
|
|
425
425
|
(bs.as(:publisher) >> space >> single_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
|
|
426
|
-
(colon | space).as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
|
|
426
|
+
(colon | space).as(:add_sep) >> str("Addendum") >> space.repeat(1) >> str("No.").as(:add_no_prefix) >> space.repeat(1) >>
|
|
427
427
|
digits.as(:addendum_number) >> colon >> digit.repeat(4,
|
|
428
428
|
4).as(:addendum_year)
|
|
429
429
|
).as(:addendum_document) |
|
|
430
430
|
(bs.as(:publisher) >> space >> single_letter_prefix.as(:flex_prefix) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
|
|
431
|
-
(colon | space).as(:add_sep) >> str("Addendum") >> space >>
|
|
431
|
+
(colon | space).as(:add_sep) >> str("Addendum") >> space.repeat(1) >>
|
|
432
432
|
digits.as(:addendum_number) >> colon >> digit.repeat(4,
|
|
433
433
|
4).as(:addendum_year)
|
|
434
434
|
).as(:addendum_document) |
|
|
435
435
|
# With year before Addendum and SPACE separator: "BS NUMBER:YEAR Addendum No. N:YEAR"
|
|
436
436
|
(bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
|
|
437
437
|
colon >> digit.repeat(4,
|
|
438
|
-
4).as(:base_year) >> space.as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
|
|
438
|
+
4).as(:base_year) >> space.as(:add_sep) >> str("Addendum") >> space.repeat(1) >> str("No.").as(:add_no_prefix) >> space.repeat(1) >>
|
|
439
439
|
digits.as(:addendum_number) >> colon >> digit.repeat(4,
|
|
440
440
|
4).as(:addendum_year)
|
|
441
441
|
).as(:addendum_document) |
|
|
442
442
|
# With year before Addendum and COLON separator: "BS NUMBER:YEAR:Addendum No. N:YEAR"
|
|
443
443
|
(bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
|
|
444
444
|
colon >> digit.repeat(4,
|
|
445
|
-
4).as(:base_year) >> colon.as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
|
|
445
|
+
4).as(:base_year) >> colon.as(:add_sep) >> str("Addendum") >> space.repeat(1) >> str("No.").as(:add_no_prefix) >> space.repeat(1) >>
|
|
446
446
|
digits.as(:addendum_number) >> colon >> digit.repeat(4,
|
|
447
447
|
4).as(:addendum_year)
|
|
448
448
|
).as(:addendum_document) |
|
|
449
449
|
# Without flex type prefix - with "No." prefix
|
|
450
450
|
(bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
|
|
451
|
-
(colon | space).as(:add_sep) >> str("Addendum") >> space >> str("No.").as(:add_no_prefix) >> space >>
|
|
451
|
+
(colon | space).as(:add_sep) >> str("Addendum") >> space.repeat(1) >> str("No.").as(:add_no_prefix) >> space.repeat(1) >>
|
|
452
452
|
digits.as(:addendum_number) >> colon >> digit.repeat(4,
|
|
453
453
|
4).as(:addendum_year)
|
|
454
454
|
).as(:addendum_document) |
|
|
455
455
|
# Without "No." prefix
|
|
456
456
|
(bs.as(:publisher) >> space >> number.as(:number) >> iteration.as(:iteration) >> parts.as(:parts) >>
|
|
457
|
-
(colon | space).as(:add_sep) >> str("Addendum") >> space >>
|
|
457
|
+
(colon | space).as(:add_sep) >> str("Addendum") >> space.repeat(1) >>
|
|
458
458
|
digits.as(:addendum_number) >> colon >> digit.repeat(4,
|
|
459
459
|
4).as(:addendum_year)
|
|
460
460
|
).as(:addendum_document)
|
data/lib/pubid/bsi/renderer.rb
CHANGED
|
@@ -212,7 +212,7 @@ module Pubid
|
|
|
212
212
|
end
|
|
213
213
|
|
|
214
214
|
result = prefix
|
|
215
|
-
result += " #{id.
|
|
215
|
+
result += " #{id.base}" if id.base
|
|
216
216
|
result += " ED#{id.edition}" if id.edition
|
|
217
217
|
|
|
218
218
|
result += " (R#{id.reaffirmation_year})" if id.reaffirmation_year
|
|
@@ -237,7 +237,7 @@ module Pubid
|
|
|
237
237
|
end
|
|
238
238
|
|
|
239
239
|
result = prefix
|
|
240
|
-
result += " #{id.
|
|
240
|
+
result += " #{id.base}" if id.base
|
|
241
241
|
result += " ED#{id.edition}" if id.edition
|
|
242
242
|
|
|
243
243
|
result += " (R#{id.reaffirmation_year})" if id.reaffirmation_year
|
|
@@ -303,16 +303,16 @@ module Pubid
|
|
|
303
303
|
|
|
304
304
|
if id.amd_suffix_form
|
|
305
305
|
# Trailing " AMD5" / " AMD AA" suffix form
|
|
306
|
-
suffix = if id.
|
|
307
|
-
" AMD #{id.
|
|
306
|
+
suffix = if id.number&.match?(/^[A-Z]+$/)
|
|
307
|
+
" AMD #{id.number}"
|
|
308
308
|
else
|
|
309
|
-
" AMD#{id.
|
|
309
|
+
" AMD#{id.number}"
|
|
310
310
|
end
|
|
311
311
|
base.empty? ? suffix.lstrip : "#{base}#{suffix}"
|
|
312
312
|
else
|
|
313
313
|
# Compact "+A5" / "/A5" join form, with an optional ":year"
|
|
314
|
-
compact = "#{id.separator}A#{id.
|
|
315
|
-
compact += ":#{id.
|
|
314
|
+
compact = "#{id.separator}A#{id.number}"
|
|
315
|
+
compact += ":#{id.year}" if id.year
|
|
316
316
|
"#{base}#{compact}"
|
|
317
317
|
end
|
|
318
318
|
end
|
|
@@ -422,21 +422,21 @@ module Pubid
|
|
|
422
422
|
id.identifiers[1..].each do |idd|
|
|
423
423
|
if idd.is_a?(Identifiers::Amendment)
|
|
424
424
|
if idd.amd_suffix_form
|
|
425
|
-
result += if idd.
|
|
426
|
-
" AMD #{idd.
|
|
425
|
+
result += if idd.number&.match?(/^[A-Z]+$/)
|
|
426
|
+
" AMD #{idd.number}"
|
|
427
427
|
else
|
|
428
|
-
" AMD#{idd.
|
|
428
|
+
" AMD#{idd.number}"
|
|
429
429
|
end
|
|
430
430
|
else
|
|
431
431
|
sep = idd.separator || "+"
|
|
432
|
-
result += "#{sep}A#{idd.
|
|
433
|
-
result += ":#{idd.
|
|
432
|
+
result += "#{sep}A#{idd.number}"
|
|
433
|
+
result += ":#{idd.year}" if idd.year
|
|
434
434
|
end
|
|
435
435
|
elsif idd.is_a?(Identifiers::Corrigendum)
|
|
436
436
|
sep = idd.separator || "+"
|
|
437
437
|
result += "#{sep}C"
|
|
438
|
-
result += idd.
|
|
439
|
-
result += ":#{idd.
|
|
438
|
+
result += idd.number.to_s if idd.number
|
|
439
|
+
result += ":#{idd.year}" if idd.year
|
|
440
440
|
else
|
|
441
441
|
result += idd.to_s
|
|
442
442
|
end
|
|
@@ -485,8 +485,8 @@ module Pubid
|
|
|
485
485
|
def render_corrigendum(id)
|
|
486
486
|
result = id.base ? id.base.to_s : ""
|
|
487
487
|
result += "#{id.separator}C"
|
|
488
|
-
result += id.
|
|
489
|
-
result += ":#{id.
|
|
488
|
+
result += id.number.to_s if id.number
|
|
489
|
+
result += ":#{id.year}" if id.year
|
|
490
490
|
result
|
|
491
491
|
end
|
|
492
492
|
|
|
@@ -753,17 +753,17 @@ module Pubid
|
|
|
753
753
|
if id.na_supplements&.any?
|
|
754
754
|
id.na_supplements.each do |supp|
|
|
755
755
|
if supp.is_a?(Identifiers::Amendment)
|
|
756
|
-
result += "+A#{supp.
|
|
756
|
+
result += "+A#{supp.number}:#{supp.year}"
|
|
757
757
|
elsif supp.is_a?(Identifiers::Corrigendum)
|
|
758
|
-
result += "+C#{supp.
|
|
758
|
+
result += "+C#{supp.number}:#{supp.year}"
|
|
759
759
|
end
|
|
760
760
|
end
|
|
761
761
|
end
|
|
762
762
|
|
|
763
763
|
result += " to "
|
|
764
764
|
|
|
765
|
-
result += if id.
|
|
766
|
-
id.
|
|
765
|
+
result += if id.base
|
|
766
|
+
id.base.to_s
|
|
767
767
|
else
|
|
768
768
|
render_single_identifier(id)
|
|
769
769
|
end
|
|
@@ -21,15 +21,15 @@ module Pubid
|
|
|
21
21
|
parts << identifier.flex_prefix.to_s.downcase
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
#
|
|
25
|
-
# European norm, a bundle, a set —
|
|
26
|
-
#
|
|
27
|
-
# "DD ENV ISO 11079:1999" (which adopts a CEN prestandard that is
|
|
28
|
-
#
|
|
24
|
+
# Read identity from the wrapped document when the wrapper has none of
|
|
25
|
+
# its own. A wrapper — an adopted European norm, a bundle, a set —
|
|
26
|
+
# carries no number, part, subpart or date, so a
|
|
27
|
+
# "DD ENV ISO 11079:1999" (which adopts a CEN prestandard that is itself
|
|
28
|
+
# a wrapper around the ISO standard) emitted the identity-free
|
|
29
29
|
# `urn:bsi:dd` — the same URN as every other DD adoption. `#root`
|
|
30
30
|
# recurses to the origin document, and for a non-wrapper it is `self`,
|
|
31
31
|
# so this changes nothing for an ordinary identifier.
|
|
32
|
-
urn_number =
|
|
32
|
+
urn_number = identity(:number)
|
|
33
33
|
if urn_number
|
|
34
34
|
number = urn_number.to_s
|
|
35
35
|
if identifier.iteration && !identifier.iteration.empty?
|
|
@@ -38,25 +38,22 @@ module Pubid
|
|
|
38
38
|
parts << number
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
parts << "-#{part}"
|
|
44
|
-
end
|
|
41
|
+
urn_part = identity(:part)
|
|
42
|
+
parts << "-#{urn_part}" if urn_part
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
parts << "-#{subpart}"
|
|
49
|
-
end
|
|
44
|
+
urn_subpart = identity(:subpart)
|
|
45
|
+
parts << "-#{urn_subpart}" if urn_subpart
|
|
50
46
|
|
|
51
47
|
if identifier.second_number
|
|
52
48
|
second = identifier.second_number.to_s
|
|
53
49
|
parts << "/#{second}"
|
|
54
50
|
end
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
urn_date = identity(:date)
|
|
53
|
+
if urn_date.is_a?(::Pubid::Components::Date) && urn_date.present?
|
|
54
|
+
parts << urn_date.render(context: URN_CONTEXT)
|
|
55
|
+
elsif (urn_year = identity(:year))
|
|
56
|
+
parts << urn_year.to_s
|
|
60
57
|
end
|
|
61
58
|
|
|
62
59
|
if identifier.month
|
|
@@ -87,6 +84,19 @@ module Pubid
|
|
|
87
84
|
|
|
88
85
|
parts.join(":")
|
|
89
86
|
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
# An identity attribute of the identifier, or of the document it wraps.
|
|
91
|
+
# `#root` is `self` for a non-wrapper, so an ordinary identifier reads its
|
|
92
|
+
# own value twice and nothing changes.
|
|
93
|
+
def identity(attr)
|
|
94
|
+
own = identifier.public_send(attr)
|
|
95
|
+
return own if own
|
|
96
|
+
|
|
97
|
+
root = identifier.root
|
|
98
|
+
root.equal?(identifier) ? nil : root.public_send(attr)
|
|
99
|
+
end
|
|
90
100
|
end
|
|
91
101
|
end
|
|
92
102
|
end
|
data/lib/pubid/builder/base.rb
CHANGED
|
@@ -195,3 +195,30 @@ module Pubid
|
|
|
195
195
|
end
|
|
196
196
|
end
|
|
197
197
|
end
|
|
198
|
+
|
|
199
|
+
module Pubid
|
|
200
|
+
module Builder
|
|
201
|
+
# A trailing "(all parts)" is stripped by the shared Grammar and marked
|
|
202
|
+
# on the parse tree (:all_parts). Prepended to Builder::Base so every
|
|
203
|
+
# subclass — including the ones that override #build — wraps the built
|
|
204
|
+
# identifier in its flavor's all-parts class (Pubid::AllParts).
|
|
205
|
+
module AllPartsWrap
|
|
206
|
+
# Parslet tops are a Hash or an Array of Hashes (UN's multi-token tree
|
|
207
|
+
# is an Array); the marker rides every element.
|
|
208
|
+
def all_parts_marked?(data)
|
|
209
|
+
case data
|
|
210
|
+
when Hash then data[:all_parts]
|
|
211
|
+
when Array then data.any? { |e| all_parts_marked?(e) }
|
|
212
|
+
else false
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def build(data, *args, **kwargs)
|
|
217
|
+
marked = all_parts_marked?(data)
|
|
218
|
+
built = super
|
|
219
|
+
marked ? built.to_all_parts : built
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
end
|
|
224
|
+
end
|
|
@@ -18,6 +18,10 @@ module Pubid
|
|
|
18
18
|
attribute :number, :string
|
|
19
19
|
attribute :date, ::Pubid::Components::Date
|
|
20
20
|
|
|
21
|
+
# A nil `series` means the document has none: `CC 36010` is not
|
|
22
|
+
# `CC/WD 36010`, which is a working draft of it.
|
|
23
|
+
subset_strict :series
|
|
24
|
+
|
|
21
25
|
# Polymorphic type map for lutaml::Model key_value (de)serialization,
|
|
22
26
|
# mapping the concrete class's polymorphic_name to its class name so a
|
|
23
27
|
# stored hash rebuilds the correct identifier type via from_hash.
|