Class: Pubid::Iso::Identifier

Inherits:
Pubid::Identifier show all
Defined in:
lib/pubid/iso/identifier.rb

Constant Summary collapse

ISO_TYPE_MAP =

Polymorphic type map for lutaml::Model key_value serialization Maps polymorphic_name → class name for deserialization Validated by spec to stay in sync with Scheme.identifiers

{
  "pubid:iso:international-standard" => "Pubid::Iso::Identifiers::InternationalStandard",
  "pubid:iso:international-standardized-profile" => "Pubid::Iso::Identifiers::InternationalStandardizedProfile",
  "pubid:iso:international-workshop-agreement" => "Pubid::Iso::Identifiers::InternationalWorkshopAgreement",
  "pubid:iso:technical-report" => "Pubid::Iso::Identifiers::TechnicalReport",
  "pubid:iso:technical-specification" => "Pubid::Iso::Identifiers::TechnicalSpecification",
  "pubid:iso:pas" => "Pubid::Iso::Identifiers::Pas",
  "pubid:iso:guide" => "Pubid::Iso::Identifiers::Guide",
  "pubid:iso:recommendation" => "Pubid::Iso::Identifiers::Recommendation",
  "pubid:iso:amendment" => "Pubid::Iso::Identifiers::Amendment",
  "pubid:iso:corrigendum" => "Pubid::Iso::Identifiers::Corrigendum",
  "pubid:iso:supplement" => "Pubid::Iso::Identifiers::Supplement",
  "pubid:iso:addendum" => "Pubid::Iso::Identifiers::Addendum",
  "pubid:iso:extract" => "Pubid::Iso::Identifiers::Extract",
  "pubid:iso:directives" => "Pubid::Iso::Identifiers::Directives",
  "pubid:iso:directives-supplement" => "Pubid::Iso::Identifiers::DirectivesSupplement",
  "pubid:iso:data" => "Pubid::Iso::Identifiers::Data",
  "pubid:iso:tc-document" => "Pubid::Iso::Identifiers::TcDocument",
  "pubid:iso:technology-trends-assessments" => "Pubid::Iso::Identifiers::TechnologyTrendsAssessments",
}.freeze

Class Method Summary collapse

Methods inherited from Pubid::Identifier

#base_identifier, #eql?, #exclude, #hash, #initialize, #mr_number, #mr_number_with_part, #mr_part, #mr_publisher, #mr_type, #mr_year, #new_edition_of?, polymorphic_name, #render, #resolve_urn_generator, #root, #to_mr_string, #to_s, #to_supplement_s, #to_urn, #urn_supplement_type, #urn_type_code, #year

Constructor Details

This class inherits a constructor from Pubid::Identifier

Class Method Details

.build_base_identifier(base) ⇒ Object

Build the base_identifier for a supplement from either an already constructed identifier or a 1.x-style attribute hash (the nested ‘:base` entry in a structured index). Recurses so supplement-of- supplement chains (e.g. a Corrigendum to an Amendment) build cleanly.



174
175
176
177
178
# File 'lib/pubid/iso/identifier.rb', line 174

def self.build_base_identifier(base)
  return base if base.is_a?(::Pubid::Identifier)

  create(**base.transform_keys(&:to_sym))
end

.build_type_mapObject

Build type map from Scheme.identifiers for validation



39
40
41
42
43
# File 'lib/pubid/iso/identifier.rb', line 39

def self.build_type_map
  Scheme.identifiers.to_h do |klass|
    [klass.polymorphic_name, klass.name]
  end
end

.create(type: nil, stage: nil, base: nil, **opts) ⇒ Pubid::Iso::Identifier

Factory mirroring pubid 1.x’s ‘Pubid::Iso::Identifier.create` API.

Accepts 1.x-style primitive kwargs and dispatches to the correct 2.x ‘Identifiers::*` subclass via Scheme. Coerces primitives into ISO-specific Component objects.

Dispatch rules:

* `type:` (e.g. `:tr`, `:amd`)        → lookup via Scheme
* else `stage:` (e.g. `"DIS"`, `"AMD"`) → lookup via Scheme
* else                                → InternationalStandard

Parameters:

  • type (Symbol, String, nil) (defaults to: nil)

    type key (‘:is`, `:tr`, `:amd`, …)

  • stage (String, Symbol, nil) (defaults to: nil)

    typed-stage abbreviation

  • opts (Hash)

    remaining attribute primitives: :publisher (String), :number, :part, :subpart, :year, :edition, :language

Returns:



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/pubid/iso/identifier.rb', line 85

def self.create(type: nil, stage: nil, base: nil, **opts)
  # A bundled directive (e.g. "ISO/IEC DIR 1 + IEC SUP") is stored by the
  # 1.x index as the base document's fields plus a nested joint_document
  # (or a supplements array). The 2.x model is a separate
  # BundledIdentifier; build that so .create round-trips parse.
  if opts[:joint_document] || opts[:supplements]
    return build_bundled(type: type, stage: stage, base: base, **opts)
  end

  klass = resolve_create_class(type: type, stage: stage, base: base)
  attrs = coerce_create_attrs(opts)
  ts = resolve_create_typed_stage(klass, stage)
  if ts
    # dup the (shared) TYPED_STAGES element before tweaking, and set
    # original_abbr to the canonical abbr so rendering matches a
    # parsed identifier (parse records the spelled abbr, e.g. "Amd"
    # not the upcased short_abbr "AMD").
    ts = ts.dup
    ts.original_abbr ||= Array(ts.abbr).first&.to_s
    attrs[:typed_stage] = ts
    # Parse fills `type` and `stage` Components derived from
    # typed_stage; mirror that here so .create round-trips through
    # Pubid::Identifier#== with a parsed identifier.
    attrs[:type] ||= ::Pubid::Components::Type.new(
      name:      ts.name,
      abbr:      Array(ts.abbr).first.to_s,
      type_code: ts.type_code&.to_s,
    )
    attrs[:stage] ||= ::Pubid::Components::Stage.new(
      name:              ts.name,
      stage_code:        ts.stage_code&.to_s,
      abbr:              Array(ts.abbr).first.to_s,
      harmonized_stages: Array(ts.harmonized_stages),
    )
  end
  # Build the base_identifier whenever a `base:` is supplied, regardless
  # of whether the resolved class is registered as a supplement (e.g.
  # DirectivesSupplement holds a base but is not in
  # Scheme#supplement_identifiers). Only classes that *require* a base
  # and were given none raise.
  if base
    attrs[:base_identifier] = build_base_identifier(base)
  elsif supplement_klass?(klass)
    raise ArgumentError, "#{klass} requires a base: identifier"
  end
  # For a DirectivesSupplement the top-level `publisher:` names the
  # supplement's own publisher ("… ISO SUP"), not the document's — the
  # document publisher lives on the base. Mirror parse, which records it
  # as `supplement_publisher`.
  if klass <= Identifiers::DirectivesSupplement && attrs.key?(:publisher)
    attrs[:supplement_publisher] = attrs.delete(:publisher)
    attrs.delete(:copublishers)
  end
  klass.new(**attrs)
end

.locate_create_typed_stage(stage) ⇒ Object

Resolve a TypedStage from a create() :stage value. The index may supply it as an abbreviation (“DIS”), a generic stage_code (:dis), or a unique per-typed-stage code (:dtr, :fdisp). Try each in turn.



219
220
221
222
223
# File 'lib/pubid/iso/identifier.rb', line 219

def self.locate_create_typed_stage(stage)
  Scheme.locate_typed_stage_by_abbr(stage.to_s) ||
    Scheme.locate_typed_stage_by_stage_code(stage) ||
    Scheme.locate_typed_stage_by_code(stage)
end

.locate_klass_by_type_or_short(type) ⇒ Object

Try direct key lookup, then a case-insensitive key lookup (indexes store e.g. “DATA” but the registry key is :data), then fall back to matching the class’s :short letter (e.g. type “R” → Recommendation, whose key is :rec and short is “R”). Indexes and legacy data carry either the key, an upper-cased key, or the short form.



248
249
250
251
252
# File 'lib/pubid/iso/identifier.rb', line 248

def self.locate_klass_by_type_or_short(type)
  Scheme.locate_identifier_klass_by_type_code(type) ||
    Scheme.locate_identifier_klass_by_type_code(type.to_s.downcase) ||
    Scheme.identifiers.detect { |k| k.type&.dig(:short)&.to_s == type.to_s }
end

.parse(string, format: :auto) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/pubid/iso/identifier.rb', line 49

def self.parse(string, format: :auto)
  format = Pubid::FormatDetector.detect(string) if format == :auto

  case format
  when :urn
    Pubid::Iso::UrnParser.parse(string)
  when :mr_string
    Pubid::Parsers::MrString.parse(string)
  else
    parsed = Pubid::Iso::Parser.new.parse(string)
    if parsed.nil? || parsed.empty?
      raise Pubid::Iso::Parser::ParseError,
            "Invalid identifier format"
    end

    Pubid::Iso::Builder.new(Pubid::Iso::Scheme).build(parsed)
  end
end

.retype_stage_for_class(klass, ts) ⇒ Object

Indexes store a supplement’s stage as the bare review-stage abbr (“CD”, “WD”, “AWI”) plus a separate type (“AMD”), so the global lookup resolves the stage to the IS-typed variant (cdis) rather than the amendment-typed one (committee_draft_amd). When the resolved stage’s type differs from the class chosen via ‘type:`, re-pick the equivalent stage from the class’s own TYPED_STAGES. harmonized_stages is the stable cross-type key (stage_code/abbr diverge between IS and amd: IS “WD” is :working_draft, the amendment is :wd_amd).



203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/pubid/iso/identifier.rb', line 203

def self.retype_stage_for_class(klass, ts)
  return ts unless klass.const_defined?(:TYPED_STAGES)
  return ts unless klass.respond_to?(:type) && klass.type
  return ts if ts.type_code.to_s == klass.type[:key].to_s

  harmonized = Array(ts.harmonized_stages)
  return ts if harmonized.empty?

  klass.const_get(:TYPED_STAGES).find do |s|
    (Array(s.harmonized_stages) & harmonized).any?
  end || ts
end