pubid 2.0.1 → 2.0.3
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/data/ieee/update_codes.yaml +2 -2
- data/data/parg/adobe.json +1 -1
- data/data/parg/aiee.json +1 -1
- data/data/parg/aiee.parg +99 -9
- data/data/parg/amca.json +1 -1
- data/data/parg/ansi.json +1 -1
- data/data/parg/api.json +1 -1
- data/data/parg/ashrae.json +1 -1
- data/data/parg/asme.json +1 -1
- data/data/parg/astm.json +1 -1
- data/data/parg/bipm.json +1 -1
- data/data/parg/bsi.json +1 -1
- data/data/parg/ccsds.json +1 -1
- data/data/parg/cen_cenelec.json +1 -1
- data/data/parg/cie.json +1 -1
- data/data/parg/csa.json +1 -1
- data/data/parg/ecma.json +1 -1
- data/data/parg/etsi.json +1 -1
- data/data/parg/evs.json +1 -1
- data/data/parg/gost.json +1 -1
- data/data/parg/iala.json +1 -1
- data/data/parg/iana.json +1 -1
- data/data/parg/idf.json +1 -1
- data/data/parg/iec.json +1 -1
- data/data/parg/ieee.json +1 -1
- data/data/parg/iho.json +1 -0
- data/data/parg/ire.json +1 -1
- data/data/parg/ire.parg +51 -12
- data/data/parg/isbn.json +1 -1
- data/data/parg/iso.json +1 -1
- data/data/parg/iso.parg +751 -0
- data/data/parg/itu.json +1 -1
- data/data/parg/jcgm.json +1 -1
- data/data/parg/jis.json +1 -1
- data/data/parg/nesc.json +1 -1
- data/data/parg/nesc.parg +97 -12
- data/data/parg/nist.json +1 -1
- data/data/parg/oiml.json +1 -1
- data/data/parg/omg.json +1 -1
- data/data/parg/parg.json +1 -1
- data/data/parg/plateau.json +1 -1
- data/data/parg/tgpp.json +1 -1
- data/data/parg/un.json +1 -1
- data/lib/pubid/adobe/identifier.rb +1 -1
- data/lib/pubid/adobe/parser.rb +2 -113
- data/lib/pubid/amca/identifiers/base.rb +1 -1
- data/lib/pubid/amca/parser.rb +1 -145
- data/lib/pubid/ansi/identifier.rb +1 -1
- data/lib/pubid/ansi/parser.rb +1 -82
- data/lib/pubid/api/builder.rb +32 -1
- data/lib/pubid/api/identifier.rb +1 -1
- data/lib/pubid/api/parser.rb +1 -131
- data/lib/pubid/ashrae/identifiers/base.rb +1 -1
- data/lib/pubid/ashrae/parser.rb +3 -710
- data/lib/pubid/asme/builder.rb +6 -4
- data/lib/pubid/asme/identifier.rb +1 -2
- data/lib/pubid/asme/parser.rb +1 -328
- data/lib/pubid/astm/builder.rb +12 -3
- data/lib/pubid/astm/identifier.rb +1 -2
- data/lib/pubid/astm/parser.rb +1 -227
- data/lib/pubid/bipm/identifier.rb +8 -1
- data/lib/pubid/bipm/parser.rb +2 -224
- data/lib/pubid/bsi/builder.rb +2 -4
- data/lib/pubid/bsi/parser.rb +1 -666
- data/lib/pubid/bsi/single_identifier.rb +38 -1
- data/lib/pubid/calconnect/parser.rb +2 -40
- data/lib/pubid/ccsds/identifier.rb +1 -1
- data/lib/pubid/ccsds/parser.rb +1 -66
- data/lib/pubid/cen_cenelec/identifier.rb +16 -1
- data/lib/pubid/cen_cenelec/parser.rb +3 -136
- data/lib/pubid/cie/identifier.rb +1 -1
- data/lib/pubid/cie/parser.rb +3 -378
- data/lib/pubid/conformance.rb +1 -1
- data/lib/pubid/csa/builder.rb +41 -18
- data/lib/pubid/csa/identifier.rb +12 -4
- data/lib/pubid/csa/identifiers/amendment.rb +28 -0
- data/lib/pubid/csa/identifiers.rb +1 -0
- data/lib/pubid/csa/parser.rb +16 -397
- data/lib/pubid/doi/parser.rb +2 -37
- data/lib/pubid/easc/builder.rb +1 -1
- data/lib/pubid/easc/parser.rb +2 -70
- data/lib/pubid/ecma/CLAUDE.md +8 -1
- data/lib/pubid/ecma/identifier.rb +13 -8
- data/lib/pubid/ecma/parser.rb +2 -54
- data/lib/pubid/ecma/renderer.rb +3 -7
- data/lib/pubid/errors.rb +18 -13
- data/lib/pubid/etsi/builder.rb +8 -5
- data/lib/pubid/etsi/identifiers/base.rb +1 -1
- data/lib/pubid/etsi/parser.rb +1 -132
- data/lib/pubid/evs/identifier.rb +7 -0
- data/lib/pubid/evs/parser.rb +1 -8
- data/lib/pubid/evs.rb +1 -1
- data/lib/pubid/gb/identifier.rb +6 -0
- data/lib/pubid/gb/parser.rb +2 -51
- data/lib/pubid/gost/identifier.rb +9 -1
- data/lib/pubid/gost/parser.rb +4 -81
- data/lib/pubid/iala/builder.rb +48 -39
- data/lib/pubid/iala/identifier.rb +1 -1
- data/lib/pubid/iala/parser.rb +2 -121
- data/lib/pubid/iana/identifier.rb +1 -1
- data/lib/pubid/iana/parser.rb +2 -24
- data/lib/pubid/identifier.rb +78 -1
- data/lib/pubid/idf/builder.rb +42 -0
- data/lib/pubid/idf/identifier.rb +1 -1
- data/lib/pubid/idf/parser.rb +1 -137
- data/lib/pubid/idf.rb +1 -2
- data/lib/pubid/iec/builder.rb +158 -50
- data/lib/pubid/iec/identifier.rb +1 -1
- data/lib/pubid/iec/parser.rb +3 -430
- data/lib/pubid/ieee/CLAUDE.md +2 -0
- data/lib/pubid/ieee/aiee/identifier.rb +2 -1
- data/lib/pubid/ieee/aiee.rb +0 -1
- data/lib/pubid/ieee/builder.rb +177 -30
- data/lib/pubid/ieee/components/code.rb +46 -7
- data/lib/pubid/ieee/identifiers/base.rb +5 -2
- data/lib/pubid/ieee/identifiers/joint_development.rb +7 -3
- data/lib/pubid/ieee/ire/identifier.rb +2 -1
- data/lib/pubid/ieee/ire.rb +0 -1
- data/lib/pubid/ieee/nesc/builder.rb +1 -1
- data/lib/pubid/ieee/nesc.rb +0 -1
- data/lib/pubid/ieee/parser.rb +1 -1257
- data/lib/pubid/ieee/project_renderer.rb +5 -1
- data/lib/pubid/ieee/renderer.rb +4 -2
- data/lib/pubid/ieee/urn_generator.rb +4 -1
- data/lib/pubid/ietf/identifiers/base.rb +17 -1
- data/lib/pubid/ietf/parser.rb +2 -47
- data/lib/pubid/ietf/renderer.rb +17 -2
- data/lib/pubid/iho/CLAUDE.md +98 -0
- data/lib/pubid/iho/builder.rb +4 -1
- data/lib/pubid/iho/identifiers/base.rb +28 -2
- data/lib/pubid/iho/renderer.rb +8 -0
- data/lib/pubid/iho/urn_generator.rb +14 -1
- data/lib/pubid/iho/urn_parser.rb +45 -32
- data/lib/pubid/iho.rb +0 -1
- data/lib/pubid/isbn/identifier.rb +1 -1
- data/lib/pubid/isbn/parser.rb +2 -31
- data/lib/pubid/iso/CLAUDE.md +66 -0
- data/lib/pubid/iso/builder.rb +229 -15
- data/lib/pubid/iso/identifier.rb +22 -12
- data/lib/pubid/iso/identifiers/directives.rb +6 -3
- data/lib/pubid/iso/identifiers/guide.rb +6 -3
- data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
- data/lib/pubid/iso/normalizer.rb +5 -4
- data/lib/pubid/iso/parser.rb +1 -539
- data/lib/pubid/iso/supplement_identifier.rb +6 -3
- data/lib/pubid/iso/urn_parser.rb +13 -8
- data/lib/pubid/iso/utilities.rb +4 -5
- data/lib/pubid/iso.rb +1 -19
- data/lib/pubid/itu/builder.rb +36 -20
- data/lib/pubid/itu/identifiers/base.rb +15 -2
- data/lib/pubid/itu/parser.rb +1 -775
- data/lib/pubid/jcgm/builder.rb +35 -0
- data/lib/pubid/jcgm/parser.rb +1 -151
- data/lib/pubid/jcgm.rb +1 -2
- data/lib/pubid/jis/CLAUDE.md +36 -0
- data/lib/pubid/jis/builder.rb +30 -41
- data/lib/pubid/jis/identifier.rb +12 -2
- data/lib/pubid/jis/identifiers/welding_engineering_standard.rb +35 -0
- data/lib/pubid/jis/identifiers.rb +2 -0
- data/lib/pubid/jis/parser.rb +1 -128
- data/lib/pubid/jis/renderer.rb +1 -1
- data/lib/pubid/jis/supplement_identifier.rb +5 -5
- data/lib/pubid/jis/urn_parser.rb +2 -1
- data/lib/pubid/jis.rb +3 -2
- data/lib/pubid/nist/builder.rb +5 -1
- data/lib/pubid/nist/caster.rb +13 -3
- data/lib/pubid/nist/identifiers/base.rb +37 -2
- data/lib/pubid/nist/identifiers/circular.rb +2 -2
- data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -2
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +2 -2
- data/lib/pubid/nist/identifiers/crpl_report.rb +2 -2
- data/lib/pubid/nist/identifiers/handbook.rb +2 -2
- data/lib/pubid/nist/identifiers/internal_report.rb +2 -2
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
- data/lib/pubid/nist/identifiers/monograph.rb +2 -2
- data/lib/pubid/nist/identifiers/report.rb +2 -2
- data/lib/pubid/nist/parser.rb +19 -775
- data/lib/pubid/nist/router.rb +4 -1
- data/lib/pubid/nist/supplement_identifier.rb +2 -2
- data/lib/pubid/oasis/parser.rb +2 -16
- data/lib/pubid/ogc/parser.rb +2 -26
- data/lib/pubid/oiml/identifiers/certification_system.rb +7 -0
- data/lib/pubid/oiml/identifiers/dual_published.rb +2 -2
- data/lib/pubid/oiml/parser.rb +1 -303
- data/lib/pubid/oiml.rb +1 -2
- data/lib/pubid/omg/identifier.rb +6 -1
- data/lib/pubid/omg/parser.rb +2 -76
- data/lib/pubid/parser.rb +5 -4
- data/lib/pubid/parsers/mr_string.rb +1 -1
- data/lib/pubid/plateau/parser.rb +1 -66
- data/lib/pubid/plateau.rb +1 -2
- data/lib/pubid/renderers/directives_renderer.rb +1 -1
- data/lib/pubid/renderers/iwa_renderer.rb +1 -1
- data/lib/pubid/renderers/publisher_stripper.rb +82 -0
- data/lib/pubid/renderers/supplement_renderer.rb +1 -1
- data/lib/pubid/renderers.rb +1 -0
- data/lib/pubid/sae/parser.rb +1 -48
- data/lib/pubid/tgpp/identifier.rb +1 -1
- data/lib/pubid/tgpp/parser.rb +2 -59
- data/lib/pubid/un/identifier.rb +1 -1
- data/lib/pubid/un/parser.rb +1 -18
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/parser.rb +2 -27
- data/lib/pubid/xsf/identifier.rb +10 -6
- data/lib/pubid/xsf/parser.rb +3 -31
- data/lib/pubid/xsf/renderer.rb +2 -4
- data/lib/pubid.rb +8 -9
- metadata +9 -23
- data/lib/pubid/ieee/aiee/parser.rb +0 -130
- data/lib/pubid/ieee/ire/parser.rb +0 -109
- data/lib/pubid/ieee/nesc/parser.rb +0 -155
- data/lib/pubid/iho/parser.rb +0 -68
- data/lib/pubid/parser/common_parse_methods.rb +0 -13
- data/lib/pubid/parser/common_parse_rules.rb +0 -56
- data/lib/pubid/parser/grammar.rb +0 -96
data/lib/pubid/iso/builder.rb
CHANGED
|
@@ -66,6 +66,84 @@ module Pubid
|
|
|
66
66
|
Pubid::Iso.locate_type(typed_stage.type_code)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# Bound-hash layer fields: the grammar captures every supplement
|
|
70
|
+
# layer into a disjoint prefix (supp_ on the first supplement,
|
|
71
|
+
# supp2_ / supp3_ on the chain's later layers, isor_supp_ on an
|
|
72
|
+
# ISO/R supplement, dsupp_ on a directive supplement), so each
|
|
73
|
+
# wrapper's fields peel off the flat bound hash by prefix and
|
|
74
|
+
# re-key onto the builder-input names.
|
|
75
|
+
SUPPLEMENT_LAYERS = [
|
|
76
|
+
{
|
|
77
|
+
prefix: "supp3_",
|
|
78
|
+
keys: %i[supp3_type_with_stage supp3_number_with_part supp3_stage_iteration
|
|
79
|
+
supp3_number supp3_date supp3_undated_marker supp3_edition
|
|
80
|
+
supp3_languages supp3_all_parts],
|
|
81
|
+
plain_third_part: false,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
prefix: "supp2_",
|
|
85
|
+
keys: %i[supp2_type_with_stage supp2_number_with_part supp2_stage_iteration
|
|
86
|
+
supp2_number supp2_date supp2_undated_marker supp2_edition
|
|
87
|
+
supp2_languages supp2_all_parts],
|
|
88
|
+
plain_third_part: false,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
prefix: "supp_",
|
|
92
|
+
keys: %i[supp_type_with_stage supp_number_with_part supp_stage_iteration
|
|
93
|
+
supp_number supp_date supp_undated_marker supp_edition
|
|
94
|
+
supp_languages supp_all_parts],
|
|
95
|
+
# The first supplement's third_part keeps the plain names: the
|
|
96
|
+
# base document's own edition captures as base_edition, so the
|
|
97
|
+
# plain edition/languages/all_parts belong to the supplement.
|
|
98
|
+
plain_third_part: true,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
prefix: "isor_supp_",
|
|
102
|
+
keys: %i[isor_supp_type_with_stage isor_supp_number_with_part
|
|
103
|
+
isor_supp_stage_iteration isor_supp_date isor_supp_undated_marker],
|
|
104
|
+
plain_third_part: true,
|
|
105
|
+
},
|
|
106
|
+
].freeze
|
|
107
|
+
PLAIN_THIRD_PART_KEYS = %i[edition languages all_parts].freeze
|
|
108
|
+
|
|
109
|
+
# Directive-supplement layer (ISO/IEC DIR 1 ISO SUP): dsupp_* fields
|
|
110
|
+
# re-key onto the supplement hash, the base directive's fields stay
|
|
111
|
+
# plain.
|
|
112
|
+
DSUPP_KEYS = %i[dsupp_publisher dsupp_type_with_stage dsupp_date
|
|
113
|
+
dsupp_undated_marker dsupp_edition dsupp_languages
|
|
114
|
+
dsupp_all_parts].freeze
|
|
115
|
+
|
|
116
|
+
# Bundled directive items capture into position-scoped prefixes
|
|
117
|
+
# (one per bundle item — the engine's array-group harvest pads
|
|
118
|
+
# non-firing reps with empty hashes, parsanol-ruby#399, so bundle
|
|
119
|
+
# items cannot collect through an array binding).
|
|
120
|
+
BUNDLE_PREFIXES = %w[bs1_ bs2_ bs3_].freeze
|
|
121
|
+
|
|
122
|
+
# Joint identifier (ISO x|IDF y): the IDF side captures under idf_*
|
|
123
|
+
# names; they re-key onto the tree-shape hash Pubid::Idf.build_from_parse
|
|
124
|
+
# consumes.
|
|
125
|
+
IDF_KEYS = %i[idf_publisher idf_type_with_stage idf_stage_iteration
|
|
126
|
+
idf_number_with_part idf_date idf_languages idf_all_parts
|
|
127
|
+
idf_supp_type_with_stage idf_supp_number_with_part2
|
|
128
|
+
idf_supp_stage_iteration2 idf_supp_date2
|
|
129
|
+
idf_supp_undated_marker].freeze
|
|
130
|
+
IDF_REKEY = {
|
|
131
|
+
idf_publisher: :publisher,
|
|
132
|
+
idf_type_with_stage: :type_with_stage,
|
|
133
|
+
idf_stage_iteration: :stage_iteration,
|
|
134
|
+
idf_number_with_part: :number_with_part,
|
|
135
|
+
idf_date: :date,
|
|
136
|
+
idf_languages: :languages,
|
|
137
|
+
idf_all_parts: :all_parts,
|
|
138
|
+
}.freeze
|
|
139
|
+
IDF_SUPP_REKEY = {
|
|
140
|
+
idf_supp_type_with_stage: :type_with_stage,
|
|
141
|
+
idf_supp_number_with_part2: :number_with_part,
|
|
142
|
+
idf_supp_stage_iteration2: :stage_iteration,
|
|
143
|
+
idf_supp_date2: :date,
|
|
144
|
+
idf_supp_undated_marker: :undated_marker,
|
|
145
|
+
}.freeze
|
|
146
|
+
|
|
69
147
|
def build(parsed_hash)
|
|
70
148
|
# "(all parts)" and the ":ser" URN name every part of the document,
|
|
71
149
|
# so they build an AllPartsIdentifier around the document (the URN
|
|
@@ -73,6 +151,51 @@ module Pubid
|
|
|
73
151
|
# reason). The document itself holds no all-parts mark.
|
|
74
152
|
all_parts = parsed_hash.delete(:all_parts)
|
|
75
153
|
|
|
154
|
+
# The copublisher tail captures as one scalar span ("/IEC/IEEE");
|
|
155
|
+
# split it into the {copublisher:} element hashes the merge and
|
|
156
|
+
# the :copublishers cast consume. A pre-built array (the URN
|
|
157
|
+
# parser) passes through.
|
|
158
|
+
if parsed_hash[:copublishers].is_a?(String)
|
|
159
|
+
parsed_hash[:copublishers] = parsed_hash.delete(:copublishers)
|
|
160
|
+
.split("/").map(&:strip).reject(&:empty?)
|
|
161
|
+
.map { |cp| { copublisher: cp } }
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Peel supplement layers outermost-first: each layer re-keys its
|
|
165
|
+
# prefixed fields onto the builder-input names, nests the rest as
|
|
166
|
+
# its :base, and re-enters build — the same shape the grammar's
|
|
167
|
+
# tree used to nest.
|
|
168
|
+
SUPPLEMENT_LAYERS.each do |layer|
|
|
169
|
+
next unless parsed_hash.keys.any? do |key|
|
|
170
|
+
key.to_s.start_with?(layer[:prefix])
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
return build_supplement_layer(parsed_hash, layer, all_parts)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Joint identifier (ISO x|IDF y): the base designation's fields
|
|
177
|
+
# stay plain, the IDF side re-keys into the tree-shape hash the
|
|
178
|
+
# IDF builder consumes, and the pair routes through the
|
|
179
|
+
# CombinedIdentifier via the :joint_identifier key.
|
|
180
|
+
if parsed_hash.key?(:idf_publisher)
|
|
181
|
+
return build_joint_identifier(parsed_hash, all_parts)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Directive supplement (ISO/IEC DIR 1 ISO SUP): the dsupp_* fields
|
|
185
|
+
# are the supplement's, the plain fields its base directive's.
|
|
186
|
+
if parsed_hash.key?(:dsupp_type_with_stage)
|
|
187
|
+
return build_directive_supplement(parsed_hash, all_parts)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Bundled directives ("DIR 1:2022 + IEC SUP:2022"): the plain
|
|
191
|
+
# fields are the base document's; each bundle item captures under
|
|
192
|
+
# its bs1_/bs2_/bs3_ prefix.
|
|
193
|
+
if BUNDLE_PREFIXES.any? do |prefix|
|
|
194
|
+
parsed_hash.keys.any? { |key| key.to_s.start_with?(prefix) }
|
|
195
|
+
end
|
|
196
|
+
return build_bundled(parsed_hash, all_parts)
|
|
197
|
+
end
|
|
198
|
+
|
|
76
199
|
# For ISO/R legacy format, split into publisher and type
|
|
77
200
|
if parsed_hash[:iso_r_prefix]
|
|
78
201
|
parsed_hash[:publisher] = "ISO"
|
|
@@ -80,6 +203,12 @@ module Pubid
|
|
|
80
203
|
parsed_hash.delete(:iso_r_prefix)
|
|
81
204
|
end
|
|
82
205
|
|
|
206
|
+
# The base document's own edition captures as base_edition (the
|
|
207
|
+
# supplement layers' third_part editions own the plain key), so
|
|
208
|
+
# it re-keys onto :edition only here — at the innermost base,
|
|
209
|
+
# after every wrapper layer has been peeled off.
|
|
210
|
+
parsed_hash[:edition] = parsed_hash.delete(:base_edition) if parsed_hash.key?(:base_edition)
|
|
211
|
+
|
|
83
212
|
# For NSB-prefixed identifiers (FprISO, WD/ISO), set stage
|
|
84
213
|
if parsed_hash[:nsb_stage]
|
|
85
214
|
nsb_stage = parsed_hash.delete(:nsb_stage)
|
|
@@ -94,12 +223,11 @@ module Pubid
|
|
|
94
223
|
|
|
95
224
|
# For French GUIDE entries: "Guide ISO/CEI 37:1995". The rename
|
|
96
225
|
# must happen BEFORE class selection — locate_identifier_klass
|
|
97
|
-
# reads :type_with_stage, and the
|
|
98
|
-
# carries
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
if type_with_stage_fr = parsed_hash.delete(:type_with_stage_fr)
|
|
226
|
+
# reads :type_with_stage, and the bound map of a guide-first
|
|
227
|
+
# spelling carries the type under :type_with_stage_fr, so
|
|
228
|
+
# deferring the rename selected the default International
|
|
229
|
+
# Standard class for every guide-first reference.
|
|
230
|
+
if (type_with_stage_fr = parsed_hash.delete(:type_with_stage_fr))
|
|
103
231
|
parsed_hash[:type_with_stage] = type_with_stage_fr
|
|
104
232
|
end
|
|
105
233
|
|
|
@@ -136,6 +264,89 @@ module Pubid
|
|
|
136
264
|
all_parts ? identifier.to_all_parts : identifier
|
|
137
265
|
end
|
|
138
266
|
|
|
267
|
+
# "ISO 5537|IDF 26": the ISO side builds as the combined
|
|
268
|
+
# identifier's base, the IDF side re-keys into the tree-shape hash
|
|
269
|
+
# Pubid::Idf.build_from_parse consumes and lands in
|
|
270
|
+
# :joint_identifier.
|
|
271
|
+
def build_joint_identifier(hash, all_parts)
|
|
272
|
+
base_fields = hash.except(*IDF_KEYS)
|
|
273
|
+
idf_fields = rekey(hash.slice(*IDF_REKEY.keys), IDF_REKEY)
|
|
274
|
+
|
|
275
|
+
if (supp_keys = IDF_SUPP_REKEY.keys & hash.keys).any?
|
|
276
|
+
idf_fields = {
|
|
277
|
+
base: idf_fields,
|
|
278
|
+
**rekey(hash.slice(*supp_keys), IDF_SUPP_REKEY),
|
|
279
|
+
}
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
inner = { base: base_fields, joint_identifier: idf_fields }
|
|
283
|
+
inner[:all_parts] = all_parts if all_parts
|
|
284
|
+
build(inner)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# One supplement layer: re-key the layer's prefixed fields, move
|
|
288
|
+
# the shared plain third-part fields onto the layer where the
|
|
289
|
+
# grammar captures them there, nest everything else as the layer's
|
|
290
|
+
# base, and re-enter build.
|
|
291
|
+
def build_supplement_layer(hash, layer, all_parts)
|
|
292
|
+
prefix = layer[:prefix]
|
|
293
|
+
layer_hash = hash.select { |key, _| key.to_s.start_with?(prefix) }
|
|
294
|
+
fields = rekey_prefix(layer_hash, prefix)
|
|
295
|
+
|
|
296
|
+
if layer[:plain_third_part]
|
|
297
|
+
third_part = hash.slice(*PLAIN_THIRD_PART_KEYS)
|
|
298
|
+
fields = { **third_part, **fields }
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
rest = hash.except(*layer_hash.keys)
|
|
302
|
+
rest = rest.except(*PLAIN_THIRD_PART_KEYS) if layer[:plain_third_part]
|
|
303
|
+
|
|
304
|
+
inner = { **fields, base: rest }
|
|
305
|
+
inner[:all_parts] = all_parts if all_parts
|
|
306
|
+
build(inner)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def build_directive_supplement(hash, all_parts)
|
|
310
|
+
fields = rekey_prefix(hash.slice(*DSUPP_KEYS), "dsupp_")
|
|
311
|
+
rest = hash.except(*DSUPP_KEYS)
|
|
312
|
+
|
|
313
|
+
inner = { **fields, base: rest }
|
|
314
|
+
inner[:all_parts] = all_parts if all_parts
|
|
315
|
+
build(inner)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Bundled directives: each bundle item's prefixed fields re-key to
|
|
319
|
+
# the supplement hash and build a DirectivesSupplement, the plain
|
|
320
|
+
# fields build the base document, and the pair lands on a
|
|
321
|
+
# BundledIdentifier.
|
|
322
|
+
def build_bundled(hash, all_parts)
|
|
323
|
+
bundle_keys = BUNDLE_PREFIXES.flat_map do |prefix|
|
|
324
|
+
hash.keys.select { |key| key.to_s.start_with?(prefix) }
|
|
325
|
+
end
|
|
326
|
+
supplements = BUNDLE_PREFIXES.filter_map do |prefix|
|
|
327
|
+
keys = hash.keys.select { |key| key.to_s.start_with?(prefix) }
|
|
328
|
+
next if keys.empty?
|
|
329
|
+
|
|
330
|
+
build(rekey_prefix(hash.slice(*keys), prefix))
|
|
331
|
+
end
|
|
332
|
+
identifier = BundledIdentifier.new
|
|
333
|
+
identifier.base_document = build(hash.except(*bundle_keys))
|
|
334
|
+
identifier.supplements = supplements
|
|
335
|
+
all_parts ? identifier.to_all_parts : identifier
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Strip a layer prefix from every key ("supp_" / "supp2_" /
|
|
339
|
+
# "supp3_" / "isor_supp_" / "dsupp_").
|
|
340
|
+
def rekey_prefix(hash, prefix)
|
|
341
|
+
hash.to_h do |key, value|
|
|
342
|
+
[key.to_s.delete_prefix(prefix).to_sym, value]
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def rekey(hash, map)
|
|
347
|
+
hash.to_h { |key, value| [map[key], value] }
|
|
348
|
+
end
|
|
349
|
+
|
|
139
350
|
def handle_key(identifier, key, value)
|
|
140
351
|
if key == :joint_identifier
|
|
141
352
|
identifier.additional_identifiers ||= []
|
|
@@ -150,8 +361,8 @@ module Pubid
|
|
|
150
361
|
# "4037/1979", "4037-1979", and "ISO/IEC DIR 1 IEC" all split cleanly.
|
|
151
362
|
def normalize_number_with_part(value)
|
|
152
363
|
value.to_s
|
|
153
|
-
|
|
154
|
-
|
|
364
|
+
.tr("#{Parser::DASH_CHARS.join}/", "-")
|
|
365
|
+
.gsub(" ", "-")
|
|
155
366
|
end
|
|
156
367
|
|
|
157
368
|
# LEGACY: "ISO 4037-1979" used a hyphen where the modern form is
|
|
@@ -190,7 +401,7 @@ module Pubid
|
|
|
190
401
|
# (e.g. a TC document, which skips the copublisher merge) matches
|
|
191
402
|
# the [] convention used by copublisher-merged parses and by
|
|
192
403
|
# Identifier.create. Otherwise equality fails on [] vs nil.
|
|
193
|
-
Pubid::Iso::Components::Publisher.new(publisher: value,
|
|
404
|
+
Pubid::Iso::Components::Publisher.new(publisher: value,
|
|
194
405
|
copublisher: [])
|
|
195
406
|
end
|
|
196
407
|
|
|
@@ -285,10 +496,17 @@ module Pubid
|
|
|
285
496
|
# Handle JTC 1 subgroup in directives (ISO/IEC JTC 1 DIR)
|
|
286
497
|
value.to_s
|
|
287
498
|
|
|
499
|
+
when :publisher_name
|
|
500
|
+
# The grammar's publisher_names preprocess binding (the ISO
|
|
501
|
+
# organization's full name, consumed by the ts artifact's
|
|
502
|
+
# schema materialization). The Ruby identifier carries only
|
|
503
|
+
# the Publisher component, so the field assigns nothing.
|
|
504
|
+
nil
|
|
505
|
+
|
|
288
506
|
when :supplements
|
|
289
507
|
# Handle bundled supplements (+ operator)
|
|
290
508
|
# Each supplement is a hash that needs to be built
|
|
291
|
-
value.map { |supplement_hash| build(supplement_hash
|
|
509
|
+
value.map { |supplement_hash| build(supplement_hash) }
|
|
292
510
|
|
|
293
511
|
when :base_document
|
|
294
512
|
# For bundled identifiers, build the base document
|
|
@@ -301,14 +519,10 @@ module Pubid
|
|
|
301
519
|
when :tc_number, :sc_number, :wg_number
|
|
302
520
|
value.to_s
|
|
303
521
|
|
|
304
|
-
when :year
|
|
305
|
-
# For TC documents with year, convert to Date
|
|
306
|
-
Pubid::Components::Date.new(year: value.to_s)
|
|
307
|
-
|
|
308
522
|
when :number
|
|
309
523
|
# For TC documents, number is the document number (N number)
|
|
310
524
|
# For regular identifiers, this is handled in :number_with_part
|
|
311
|
-
if value.is_a?(
|
|
525
|
+
if value.is_a?(String) ||
|
|
312
526
|
value.is_a?(Integer)
|
|
313
527
|
value.to_s
|
|
314
528
|
else
|
data/lib/pubid/iso/identifier.rb
CHANGED
|
@@ -135,8 +135,10 @@ module Pubid
|
|
|
135
135
|
map "languages", to: :languages
|
|
136
136
|
# publisher emitted only when the primary isn't the type default;
|
|
137
137
|
# copublishers (the other bodies) as an array, omitted when empty.
|
|
138
|
-
map "publisher",
|
|
139
|
-
|
|
138
|
+
map "publisher",
|
|
139
|
+
with: { to: :publisher_to_kv, from: :publisher_from_kv }
|
|
140
|
+
map "copublishers",
|
|
141
|
+
with: { to: :copublishers_to_kv, from: :copublishers_from_kv }
|
|
140
142
|
map "locality", to: :locality
|
|
141
143
|
# `type` and generic `stage` are fully derived from `typed_stage`
|
|
142
144
|
# (builder sets them via to_type/to_stage), so we serialize only the
|
|
@@ -169,8 +171,10 @@ module Pubid
|
|
|
169
171
|
# instead of falling back. The IEC twin (iec/identifier.rb) was
|
|
170
172
|
# migrated at the time; ISO was missed.
|
|
171
173
|
ts = (model.class.const_defined?(:TYPED_STAGES) &&
|
|
172
|
-
model.class::TYPED_STAGES.find
|
|
173
|
-
|
|
174
|
+
model.class::TYPED_STAGES.find do |t|
|
|
175
|
+
t.code.to_s == value.to_s
|
|
176
|
+
end) ||
|
|
177
|
+
Pubid::Iso.locate_stage_by_code(value)
|
|
174
178
|
return unless ts
|
|
175
179
|
|
|
176
180
|
# The renderer prefers `original_abbr` (the parsed surface form); without
|
|
@@ -196,7 +200,7 @@ module Pubid
|
|
|
196
200
|
return if v.nil? || v.to_s.empty?
|
|
197
201
|
|
|
198
202
|
doc.add_child(Lutaml::KeyValue::DataModel::Element.new("stage_iteration",
|
|
199
|
-
|
|
203
|
+
v.to_s))
|
|
200
204
|
end
|
|
201
205
|
|
|
202
206
|
def stage_iteration_from_kv(model, value)
|
|
@@ -219,7 +223,11 @@ module Pubid
|
|
|
219
223
|
# --- date serialized flat as year/month/day ---
|
|
220
224
|
def year_to_kv(model, doc) = emit_date_part(doc, "year", model.date&.year)
|
|
221
225
|
def year_from_kv(model, value) = date_for(model).year = value.to_s
|
|
222
|
-
|
|
226
|
+
|
|
227
|
+
def month_to_kv(model, doc)
|
|
228
|
+
emit_date_part(doc, "month", model.date&.month)
|
|
229
|
+
end
|
|
230
|
+
|
|
223
231
|
def month_from_kv(model, value) = date_for(model).month = value.to_s
|
|
224
232
|
def day_to_kv(model, doc) = emit_date_part(doc, "day", model.date&.day)
|
|
225
233
|
def day_from_kv(model, value) = date_for(model).day = value.to_s
|
|
@@ -252,7 +260,8 @@ module Pubid
|
|
|
252
260
|
pub = model.publisher&.publisher
|
|
253
261
|
return if pub.nil? || pub == model.class.default_publisher&.publisher
|
|
254
262
|
|
|
255
|
-
doc.add_child(Lutaml::KeyValue::DataModel::Element.new("publisher",
|
|
263
|
+
doc.add_child(Lutaml::KeyValue::DataModel::Element.new("publisher",
|
|
264
|
+
pub))
|
|
256
265
|
end
|
|
257
266
|
|
|
258
267
|
def publisher_from_kv(model, value)
|
|
@@ -264,7 +273,8 @@ module Pubid
|
|
|
264
273
|
return unless cp&.any?
|
|
265
274
|
|
|
266
275
|
doc.add_child(
|
|
267
|
-
Lutaml::KeyValue::DataModel::Element.new("copublishers",
|
|
276
|
+
Lutaml::KeyValue::DataModel::Element.new("copublishers",
|
|
277
|
+
cp.map(&:to_s)),
|
|
268
278
|
)
|
|
269
279
|
end
|
|
270
280
|
|
|
@@ -304,10 +314,10 @@ module Pubid
|
|
|
304
314
|
when :mr_string
|
|
305
315
|
Pubid::Parsers::MrString.parse(string)
|
|
306
316
|
else
|
|
307
|
-
#
|
|
308
|
-
#
|
|
309
|
-
#
|
|
310
|
-
parsed = Pubid::Parg::
|
|
317
|
+
# The baked PG artifact parses through the grammar's declared
|
|
318
|
+
# bindings: the Builder consumes the typed bound map (every
|
|
319
|
+
# capture bound by name, supplement layers position-scoped).
|
|
320
|
+
parsed = Pubid::Parg::Model.bound(:iso, string)
|
|
311
321
|
Pubid::Iso::Builder.new.build(parsed)
|
|
312
322
|
end
|
|
313
323
|
end
|
|
@@ -35,9 +35,12 @@ module Pubid
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def to_s(**opts)
|
|
38
|
-
context = build_rendering_context(
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
context = build_rendering_context(
|
|
39
|
+
nil, format: :human, **opts.except(:with_publisher)
|
|
40
|
+
)
|
|
41
|
+
rendered = Pubid::Renderers::DirectivesRenderer.new(self)
|
|
42
|
+
.render(context:, **opts.slice(:with_edition))
|
|
43
|
+
apply_with_publisher(rendered, :human, opts[:with_publisher])
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
# Directives use a different URN scheme: urn:iso:doc instead of urn:iso:std
|
|
@@ -91,9 +91,12 @@ module Pubid
|
|
|
91
91
|
def to_s(**opts)
|
|
92
92
|
return super if opts[:format] && opts[:format] != :human
|
|
93
93
|
|
|
94
|
-
context = build_rendering_context(
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
context = build_rendering_context(
|
|
95
|
+
nil, format: :human, **opts.except(:with_publisher)
|
|
96
|
+
)
|
|
97
|
+
rendered = Pubid::Renderers::GuideRenderer.new(self)
|
|
98
|
+
.render(context:, **opts.slice(:with_edition))
|
|
99
|
+
apply_with_publisher(rendered, :human, opts[:with_publisher])
|
|
97
100
|
end
|
|
98
101
|
end
|
|
99
102
|
end
|
|
@@ -85,9 +85,12 @@ module Pubid
|
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
def to_s(**opts)
|
|
88
|
-
context = build_rendering_context(
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
context = build_rendering_context(
|
|
89
|
+
nil, format: :human, **opts.except(:with_publisher)
|
|
90
|
+
)
|
|
91
|
+
rendered = Pubid::Renderers::IwaRenderer.new(self)
|
|
92
|
+
.render(context:, **opts.slice(:with_edition))
|
|
93
|
+
apply_with_publisher(rendered, :human, opts[:with_publisher])
|
|
91
94
|
end
|
|
92
95
|
end
|
|
93
96
|
end
|
data/lib/pubid/iso/normalizer.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Pubid
|
|
|
7
7
|
# update_codes regex rewrites, and the DAD/FDAM pattern that the PEG
|
|
8
8
|
# parser cannot recognize because it treats "/" as a copublisher separator.
|
|
9
9
|
class Normalizer
|
|
10
|
-
DAD_PATTERN = /^(.+?)\/(F?DAD)\s+(\d+)(?::(\d{4}))
|
|
10
|
+
DAD_PATTERN = /^(.+?)\/(F?DAD)\s+(\d+)(?::(\d{4}))?$/
|
|
11
11
|
|
|
12
12
|
class << self
|
|
13
13
|
# Apply all normalizations to an identifier string and return the
|
|
@@ -29,8 +29,9 @@ module Pubid
|
|
|
29
29
|
def parse_with_builder(string)
|
|
30
30
|
# R2 ingestion hook: normalized strings reach the model through
|
|
31
31
|
# the same parser of record as Identifier.parse (the baked PG
|
|
32
|
-
# artifact), so every Tier-3 normalization feeds one
|
|
33
|
-
|
|
32
|
+
# artifact's bindings), so every Tier-3 normalization feeds one
|
|
33
|
+
# grammar.
|
|
34
|
+
parsed = Pubid::Parg::Model.bound(:iso, string)
|
|
34
35
|
Pubid::Iso.builder.build(parsed)
|
|
35
36
|
end
|
|
36
37
|
|
|
@@ -71,7 +72,7 @@ module Pubid
|
|
|
71
72
|
supplement_number = match[3] # "1"
|
|
72
73
|
supplement_year = match[4] # "1987" or nil
|
|
73
74
|
|
|
74
|
-
base_parsed = Pubid::
|
|
75
|
+
base_parsed = Pubid::Parg::Model.bound(:iso, base_str)
|
|
75
76
|
base = Pubid::Iso.builder.build(base_parsed)
|
|
76
77
|
|
|
77
78
|
addendum = Identifiers::Addendum.new
|