Class: Pubid::Identifier
- Inherits:
-
Lutaml::Model::Serializable
- Object
- Lutaml::Model::Serializable
- Pubid::Identifier
show all
- Defined in:
- lib/pubid/identifier.rb
Direct Known Subclasses
Amca::Identifier, Ansi::Identifier, Api::Identifier, Ashrae::Identifier, Asme::Identifier, Astm::Identifier, Bsi::Identifier, BundledIdentifier, Ccsds::Identifier, Ccsds::SingleIdentifier, CenCenelec::Identifier, Cie::Identifier, Csa::Identifier, Etsi::Identifier, Pubid::Idf::Identifier, Pubid::Iec::Identifier, Pubid::Ieee::Identifier, Pubid::Iho::Identifier, Pubid::Iso::Identifier, Pubid::Itu::Identifier, Jcgm::Identifier, Jis::Identifier, Nist::Identifier, Oiml::Identifier, Plateau::Identifier, Plateau::SupplementIdentifier, Sae::Identifier
Class Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(attrs = {}, options = {}) ⇒ Identifier
Returns a new instance of Identifier.
206
207
208
209
210
|
# File 'lib/pubid/identifier.rb', line 206
def initialize(attrs = {}, options = {})
attrs = attrs.dup
attrs[:_type] ||= self.class.polymorphic_name
super
end
|
Class Attribute Details
6
7
8
|
# File 'lib/pubid/identifier.rb', line 6
def format_registry
@format_registry || superclass&.format_registry
end
|
Class Method Details
.from_hash(data, options = {}) ⇒ Object
Polymorphic deserialization shared by every flavor base. lutaml's
key_value polymorphic_map reads _type only to VALIDATE; it does not
re-instantiate the concrete subclass. So a base-class from_hash would
return a bare base object and drop subtype-specific attributes (e.g. a
supplement's base_identifier). Route by _type to the concrete class
named in polymorphic_type_map, then let its inherited from_hash (this
method again, where klass == self) fall through to lutaml's real work.
This generalizes the per-flavor *_TYPE_MAP dispatch that ISO, JIS,
IEC, CCSDS and IHO each hand-rolled — one implementation, inherited by
every flavor base.
23
24
25
26
27
28
29
|
# File 'lib/pubid/identifier.rb', line 23
def from_hash(data, options = {})
type = data && (data["_type"] || data[:_type])
klass = polymorphic_type_map[type]
return klass.from_hash(data, options) if klass && klass != self
super
end
|
.polymorphic_name ⇒ Object
212
213
214
215
216
217
218
219
220
221
222
|
# File 'lib/pubid/identifier.rb', line 212
def self.polymorphic_name
return nil unless name
parts = name.split("::")
flavor = parts[1]&.downcase
type_kebab = parts.last
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1-\2')
.gsub(/([a-z\d])([A-Z])/, '\1-\2')
.downcase
"pubid:#{flavor}:#{type_kebab}"
end
|
.polymorphic_type_map ⇒ Object
Map of polymorphic_name ("pubid:iso:corrigendum") => concrete class for
the flavor this base belongs to. Built once by scanning the flavor's
Identifiers namespace for Pubid::Identifier descendants and unioning
the flavor's identifier_types registry (which may register classes
living outside that namespace, e.g. ISO's BundledIdentifier). Memoized
per class.
37
38
39
40
41
42
43
|
# File 'lib/pubid/identifier.rb', line 37
def polymorphic_type_map
@polymorphic_type_map ||=
identifier_registry_classes.each_with_object({}) do |klass, map|
poly = klass.polymorphic_name
map[poly] ||= klass if poly
end
end
|
Instance Method Details
#base_identifier ⇒ Object
base_identifier is declared by supplement subclasses with proper type
119
120
121
|
# File 'lib/pubid/identifier.rb', line 119
def base_identifier
nil
end
|
#eql?(other) ⇒ Boolean
357
358
359
360
361
|
# File 'lib/pubid/identifier.rb', line 357
def eql?(other)
return false unless other.is_a?(self.class)
hash == other.hash && self == other
end
|
#exclude(*args) ⇒ Object
314
315
316
317
318
319
320
321
322
323
|
# File 'lib/pubid/identifier.rb', line 314
def exclude(*args)
excluded_args = args.dup
excluded_args << :date if excluded_args.delete(:year)
attrs = self.class.attributes.each_with_object({}) do |(name, _), h|
h[name] = excluded_args.include?(name) ? nil : public_send(name)
end
self.class.new(attrs)
end
|
#hash ⇒ Object
353
354
355
|
# File 'lib/pubid/identifier.rb', line 353
def hash
@hash ||= compute_hash
end
|
#mr_number ⇒ Object
276
277
278
|
# File 'lib/pubid/identifier.rb', line 276
def mr_number
number&.to_s
end
|
#mr_number_with_part ⇒ Object
268
269
270
271
272
273
274
|
# File 'lib/pubid/identifier.rb', line 268
def mr_number_with_part
num = mr_number
return nil unless num
prt = mr_part
prt ? "#{num}-#{prt}" : num
end
|
#mr_part ⇒ Object
280
281
282
|
# File 'lib/pubid/identifier.rb', line 280
def mr_part
part&.to_s
end
|
#mr_publisher ⇒ Object
MR string template methods — flavors override as needed
255
256
257
|
# File 'lib/pubid/identifier.rb', line 255
def mr_publisher
publisher&.to_s
end
|
#mr_type ⇒ Object
259
260
261
262
263
264
265
266
|
# File 'lib/pubid/identifier.rb', line 259
def mr_type
return nil unless typed_stage
code = typed_stage.type_code
return nil if code.nil? || code.empty? || code == "is"
code
end
|
#mr_year ⇒ Object
284
285
286
|
# File 'lib/pubid/identifier.rb', line 284
def mr_year
date&.year&.to_s
end
|
#new_edition_of?(other) ⇒ Boolean
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
# File 'lib/pubid/identifier.rb', line 325
def new_edition_of?(other)
unless publisher == other.publisher
raise ArgumentError,
"Cannot compare edition: different publisher"
end
unless number == other.number
raise ArgumentError,
"Cannot compare edition: different number"
end
unless part == other.part
raise ArgumentError,
"Cannot compare edition: different part"
end
unless date && other.date
raise ArgumentError,
"Cannot compare identifier without date/year"
end
return date.year > other.date.year if date.year != other.date.year
if edition && other.edition
return edition.number > other.edition.number
end
false
end
|
#render(format: :human, **opts) ⇒ Object
Unified render — delegates to format registry
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
# File 'lib/pubid/identifier.rb', line 231
def render(format: :human, **opts)
registry = self.class.format_registry
unless registry
raise ArgumentError, "No format registry configured on #{self.class}"
end
renderer = registry.renderer_for(format)
unless renderer
raise ArgumentError, "No renderer registered for format: #{format}"
end
context = build_rendering_context(renderer, format:, **opts)
renderer.new(self).render(context:, **opts.slice(:with_edition))
end
|
#resolve_urn_generator ⇒ Object
307
308
309
310
311
312
|
# File 'lib/pubid/identifier.rb', line 307
def resolve_urn_generator
flavor = self.class.name.split("::")[1]
Object.const_get("Pubid::#{flavor}::UrnGenerator")
rescue NameError
Pubid::UrnGenerator::Base
end
|
#root ⇒ Object
224
225
226
227
228
|
# File 'lib/pubid/identifier.rb', line 224
def root
return base_identifier.root if base_identifier
self
end
|
#to_hash(*args) ⇒ Object
Canonicalize the serialized hash so it never carries a defaulted attribute
still at its default (or empty) value. This makes to_hash a pure function
of the identifier's values, independent of how the object was built.
Motivation: lutaml materializes each attribute's default as an explicit
assignment during deserialization (flipping using_default? to false), so a
naive from_hash(x).to_hash re-emits defaults that parse(x).to_hash omits —
breaking the exact-equality round-trip relaton-index relies on
(from_hash(raw).to_hash == raw). pubid never consults lutaml's unset
tracking and defines no render_default: true, so a defaulted attribute at
its default/empty value carries no meaning and does not belong in the
canonical hash. Dropping it here (rather than repairing from_hash) fixes
the round-trip through every construction path — parse, from_hash, manual.
141
142
143
144
145
|
# File 'lib/pubid/identifier.rb', line 141
def to_hash(*args)
hash = super
canonicalize_hash(self, hash) if hash.is_a?(::Hash)
hash
end
|
#to_mr_string ⇒ Object
250
251
252
|
# File 'lib/pubid/identifier.rb', line 250
def to_mr_string
render(format: :mr_string)
end
|
#to_s(**opts) ⇒ Object
246
247
248
|
# File 'lib/pubid/identifier.rb', line 246
def to_s(**opts)
render(format: :human, **opts)
end
|
#to_supplement_s(**opts) ⇒ Object
Supplement rendering hook — flavors override for supplement-specific rendering
298
299
300
|
# File 'lib/pubid/identifier.rb', line 298
def to_supplement_s(**opts)
to_s(**opts)
end
|
#to_urn ⇒ Object
Default URN generation — resolves flavor's UrnGenerator class
303
304
305
|
# File 'lib/pubid/identifier.rb', line 303
def to_urn
resolve_urn_generator.new(self).generate
end
|
#urn_supplement_type ⇒ Object
293
294
295
|
# File 'lib/pubid/identifier.rb', line 293
def urn_supplement_type
nil
end
|
#urn_type_code ⇒ Object
URN template methods — flavors override as needed
289
290
291
|
# File 'lib/pubid/identifier.rb', line 289
def urn_type_code
nil
end
|
#year ⇒ String?
Returns publication year from the date component.
124
125
126
|
# File 'lib/pubid/identifier.rb', line 124
def year
date&.year&.to_s
end
|