Class: Pubid::Core::Identifier::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/pubid/core/identifier/base.rb

Constant Summary collapse

TYPED_STAGES =
{}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(publisher:, number:, copublisher: nil, part: nil, year: nil, edition: nil, language: nil, amendments: nil, corrigendums: nil, stage: nil) ⇒ Base

Creates new identifier from options provided:

Parameters:

  • publisher (String)

    document’s publisher, eg. “ISO”

  • copublisher (String, Array<String>) (defaults to: nil)

    document’s copublisher, eg. “IEC”

  • number (Integer)

    document’s number, eg. “1234”

  • part (String) (defaults to: nil)

    document’s part and subparts, eg. “1”, “1-1A”, “2-3D”

  • type (String)

    document’s type, eg. “TR”, “TS”

  • year (Integer) (defaults to: nil)

    document’s year, eg. “2020”

  • edition (Integer) (defaults to: nil)

    document’s edition, eg. “1”

  • language (String) (defaults to: nil)

    document’s translation language (available languages: “ru”, “fr”, “en”, “ar”)

  • amendments (Array<Amendment>, Array<Hash>) (defaults to: nil)

    document’s amendments

  • corrigendums (Array<Corrigendum>, Array<Hash>) (defaults to: nil)

    document’s corrigendums

See Also:



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/pubid/core/identifier/base.rb', line 23

def initialize(publisher:, number:, copublisher: nil, part: nil,
               year: nil, edition: nil, language: nil, amendments: nil,
               corrigendums: nil, stage: nil)

  if amendments
    @amendments = amendments.map do |amendment|
      if amendment.is_a?(Hash)
        self.class.get_transformer_class.new.apply(:amendments => [amendment])[:amendments].first
      else
        amendment
      end
    end
  end

  if corrigendums
    @corrigendums = corrigendums.map do |corrigendum|
      if corrigendum.is_a?(Hash)
        self.class.get_transformer_class.new.apply(:corrigendums => [corrigendum])[:corrigendums].first
      else
        corrigendum
      end
    end
  end

  @publisher = publisher.to_s
  @number = number&.to_s
  @copublisher = copublisher if copublisher
  @part = part.to_s if part
  @year = year.to_i if year
  @edition = edition.to_i if edition
  @language = language.to_s if language

  @stage = resolve_stage(stage) if stage
end

Instance Attribute Details

#amendmentsObject

Returns the value of attribute amendments.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def amendments
  @amendments
end

#copublisherObject

Returns the value of attribute copublisher.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def copublisher
  @copublisher
end

#corrigendumsObject

Returns the value of attribute corrigendums.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def corrigendums
  @corrigendums
end

#editionObject

Returns the value of attribute edition.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def edition
  @edition
end

#languageObject

Returns the value of attribute language.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def language
  @language
end

#numberObject

Returns the value of attribute number.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def number
  @number
end

#partObject

Returns the value of attribute part.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def part
  @part
end

#publisherObject

Returns the value of attribute publisher.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def publisher
  @publisher
end

#stageObject

Returns the value of attribute stage.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def stage
  @stage
end

#yearObject

Returns the value of attribute year.



4
5
6
# File 'lib/pubid/core/identifier/base.rb', line 4

def year
  @year
end

Class Method Details

.array_to_hash(params) ⇒ Object

Converts array of hashes into single hash array like [{ publisher: “ISO” }, { number: 1 }] to hash { publisher: “ISO”, number: 1 }

Parameters:

  • params (Array<Hash>)

    input array of hashes, eg. [{ a: 1 }, { b: 2 }]



186
187
188
189
190
191
192
193
194
# File 'lib/pubid/core/identifier/base.rb', line 186

def array_to_hash(params)
  params.inject({}) do |r, i|
    result = r
    i.each do |k, v|
      result = result.merge(k => r.key?(k) ? [r[k], v].flatten : v)
    end
    result
  end
end

.find_typed_stage(typed_stage) ⇒ [Symbol, Stage]

Returns typed stage and stage with assigned harmonized codes.

Parameters:

  • typed_stage (String, Symbol)

    eg. “DTR” or :dtr

Returns:

  • ([Symbol, Stage])

    typed stage and stage with assigned harmonized codes



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/pubid/core/identifier/base.rb', line 278

def find_typed_stage(typed_stage)
  if typed_stage.is_a?(Symbol)
    return get_identifier
        .build_typed_stage(
          harmonized_code:
            get_identifier.build_harmonized_stage_code(self::TYPED_STAGES[typed_stage][:harmonized_stages]),
          abbr: typed_stage,
        )
  end

  typed_stage = self::TYPED_STAGES.find do |_, v|
    if v[:abbr].is_a?(Hash)
      v[:abbr].value?(typed_stage)
    elsif v.key?(:legacy_abbr)
      v[:legacy_abbr].include?(typed_stage) || v[:abbr] == typed_stage
    else
      v[:abbr] == typed_stage
    end
  end

  get_identifier.build_typed_stage(harmonized_code:
                               get_identifier.build_harmonized_stage_code(typed_stage[1][:harmonized_stages]),
                             abbr: typed_stage.first)
end

.get_amendment_classObject



219
220
221
# File 'lib/pubid/core/identifier/base.rb', line 219

def get_amendment_class
  Amendment
end

.get_corrigendum_classObject



223
224
225
# File 'lib/pubid/core/identifier/base.rb', line 223

def get_corrigendum_class
  Corrigendum
end

.get_identifierObject



240
241
242
# File 'lib/pubid/core/identifier/base.rb', line 240

def get_identifier
  Identifier
end

.get_renderer_classObject



227
228
229
# File 'lib/pubid/core/identifier/base.rb', line 227

def get_renderer_class
  Renderer::Base
end

.get_transformer_classObject



231
232
233
# File 'lib/pubid/core/identifier/base.rb', line 231

def get_transformer_class
  Transformer
end

.get_update_codesHash?

Returns replacement patterns.

Returns:

  • (Hash, nil)

    replacement patterns



236
237
238
# File 'lib/pubid/core/identifier/base.rb', line 236

def get_update_codes
  nil
end

.has_type?(type) ⇒ Boolean

Returns true if provided type matches with identifier’s class type.

Parameters:

  • type (Symbol, String)

    eg. :tr, :ts, “TS”

Returns:

  • (Boolean)

    true if provided type matches with identifier’s class type



213
214
215
216
217
# File 'lib/pubid/core/identifier/base.rb', line 213

def has_type?(type)
  return type == self.type[:key] if type.is_a?(Symbol)

  self.type.key?(:values) ? self.type[:values].include?(type) : type.to_s.downcase.to_sym == self.type[:key]
end

.has_typed_stage?(typed_stage) ⇒ Boolean

Returns true when identifier has associated typed stage.

Parameters:

  • typed_stage (String, Symbol)

    typed stage, eg. “DTR” or :dtr

Returns:

  • (Boolean)

    true when identifier has associated typed stage



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/pubid/core/identifier/base.rb', line 255

def has_typed_stage?(typed_stage)
  return self::TYPED_STAGES.key?(typed_stage) if typed_stage.is_a?(Symbol)

  self::TYPED_STAGES.any? do |_, v|
    if v[:abbr].is_a?(Hash)
      v[:abbr].value?(typed_stage)
    else
      if v.key?(:legacy_abbr)
        v[:legacy_abbr].include?(typed_stage) || v[:abbr] == typed_stage
      else
        v[:abbr] == typed_stage
      end
    end
  end
end

.parse(code_or_params) ⇒ Pubid::Core::Identifier

Parses given identifier

Parameters:

  • code_or_params (String, Hash)

    code or hash from parser eg. “ISO 1234”, { }

Returns:



175
176
177
178
179
180
181
# File 'lib/pubid/core/identifier/base.rb', line 175

def parse(code_or_params)
  params = code_or_params.is_a?(String) ?
             get_parser_class.new.parse(update_old_code(code_or_params)) : code_or_params
  transform(params.is_a?(Array) ? array_to_hash(params) : params)
rescue Parslet::ParseFailed => failure
  raise Errors::ParseError, "#{failure.message}\ncause: #{failure.parse_failure_cause.ascii_tree}"
end

.resolve_typed_stage(harmonized_code) ⇒ Symbol?

Resolve typed stage using stage harmonized stage code

Parameters:

Returns:

  • (Symbol, nil)

    typed stage or nil



306
307
308
309
310
311
312
313
# File 'lib/pubid/core/identifier/base.rb', line 306

def resolve_typed_stage(harmonized_code)
  self::TYPED_STAGES.each do |k, v|
    if (v[:harmonized_stages] & harmonized_code.stages) == harmonized_code.stages
      return get_identifier.build_typed_stage(abbr: k, harmonized_code: harmonized_code)
    end
  end
  nil
end

.transform(params) ⇒ Object

Transform parameters hash or array or hashes to identifier



197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/pubid/core/identifier/base.rb', line 197

def transform(params)
  # run transform through each element,
  # like running transformer.apply(number: 1) and transformer.apply(year: 1999)
  # instead of running transformer on whole hash, like running transformer.apply({ number: 1, year: 1999 })
  # where rule for number or year only will be not applied
  # transformation only applied to rules matching the whole hash

  identifier_params = params.map do |k, v|
                        get_transformer_class.new.apply(k => v).to_a.first
                      end.to_h

  new(**identifier_params)
end

.type_match?(parameters) ⇒ Boolean

Returns true when identifier’s type match with provided parameters

Returns:

  • (Boolean)


272
273
274
# File 'lib/pubid/core/identifier/base.rb', line 272

def type_match?(parameters)
  parameters[:type] ? has_type?(parameters[:type]) : has_typed_stage?(parameters[:stage])
end

.update_old_code(code) ⇒ Object



244
245
246
247
248
249
250
251
# File 'lib/pubid/core/identifier/base.rb', line 244

def update_old_code(code)
  return code unless get_update_codes

  get_update_codes.each do |from, to|
    code = code.gsub(from.match?(/^\/.*\/$/) ? Regexp.new(from[1..-2]) : /^#{Regexp.escape(from)}$/, to)
  end
  code
end

Instance Method Details

#==(other) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/pubid/core/identifier/base.rb', line 91

def ==(other)
  case other
  when String
    to_s == other
  when Identifier::Base
    to_h == other.to_h
  when Hash
    to_h == other
  else
    raise Errors::WrongTypeError, "cannot compare with #{other.class} type"
  end
end

#exclude(*args) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/pubid/core/identifier/base.rb', line 109

def exclude(*args)
  nested_exclusions, top_level_exclusions = args.partition { |arg| arg.is_a?(Hash) }

  nested_exclusions = nested_exclusions.reduce({}, :merge)

  excluded_hash = to_h(add_type: false)
    .reject { |k, v| top_level_exclusions.include?(k) }
    .each_with_object({}) do |(k, v), memo|
      memo[k] = if v.is_a?(Hash) && nested_exclusions.key?(k)
                  v.reject { |key, _| nested_exclusions[k].include?(key) }
                else
                  v
                end
    end

  self.class.new(**excluded_hash)
end

#resolve_stage(stage) ⇒ [nil, Stage], [Symbol, Stage]

Returns typed stage and stage values.

Parameters:

  • stage (Stage, Symbol, String)

    stage or typed stage, e.g. “PWI”, “NP”, “50.00”, Stage.new(abbr: :WD), “DTR”

Returns:

  • ([nil, Stage], [Symbol, Stage])

    typed stage and stage values



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/pubid/core/identifier/base.rb', line 146

def resolve_stage(stage)
  if stage.is_a?(Stage)
    return self.class.resolve_typed_stage(stage.harmonized_code) || stage unless stage.abbr

    return stage
  end

  if self.class.has_typed_stage?(stage)
    return self.class.find_typed_stage(stage)
  end

  parsed_stage = self.class.get_identifier.parse_stage(stage)
  # resolve typed stage when harmonized code provided as stage
  # or stage abbreviation was not resolved
  if /\A[\d.]+\z/.match?(stage) || parsed_stage.empty_abbr?(with_prf: true)
    return self.class.resolve_typed_stage(parsed_stage.harmonized_code) || parsed_stage
  end

  parsed_stage

  # from IEC
  # @typed_stage = self.class::TYPED_STAGES[@typed_stage][:abbr] if @typed_stage
end

#to_h(deep: true, add_type: true) ⇒ Hash

Returns Identifier’s parameters.

Returns:

  • (Hash)

    Identifier’s parameters



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/pubid/core/identifier/base.rb', line 64

def to_h(deep: true, add_type: true)
  result = instance_variables.map do |var|
    value = instance_variable_get(var)

    [var.to_s.gsub("@", "").to_sym,
     if value.is_a?(Array)
       value.map { |v| (v.respond_to?(:to_h) && deep) ? v.to_h : v }
     elsif value.nil?
       nil
     else
       (value.respond_to?(:to_h) && deep) ? value.to_h : value
     end
    ]
  end.to_h

  if add_type && respond_to?(:type) && type[:short]
    result[:type] = type[:short]
  end

  result.reject { |k, v| k != :number && v.nil? }
end

#to_sObject

Render identifier using default renderer



105
106
107
# File 'lib/pubid/core/identifier/base.rb', line 105

def to_s
  self.class.get_renderer_class.new(to_h(deep: false)).render
end

#to_yamlObject



86
87
88
89
# File 'lib/pubid/core/identifier/base.rb', line 86

def to_yaml
  # use #to_h for serialization to avoid !ruby/object in output
  to_h.to_yaml
end

#typed_stage_abbrevObject



127
128
129
130
131
132
133
# File 'lib/pubid/core/identifier/base.rb', line 127

def typed_stage_abbrev
  if stage.is_a?(TypedStage)
    return stage.to_s
  end

  stage ? "#{stage.abbr} #{self.class.type[:key].to_s.upcase}" : self.class.type[:key].to_s.upcase
end

#typed_stage_nameObject

Return typed stage name, eg. “Final Draft Technical Report” for “FDTR”



136
137
138
139
140
141
142
# File 'lib/pubid/core/identifier/base.rb', line 136

def typed_stage_name
  if stage.is_a?(TypedStage) && self.class::TYPED_STAGES.key?(stage.abbr)
    return self.class::TYPED_STAGES[stage.abbr][:name]
  end

  stage ? "#{stage.name} #{self.class.type[:title]}" : self.class.type[:title]
end

#urnString

Returns Rendered URN identifier.

Returns:

  • (String)

    Rendered URN identifier



59
60
61
# File 'lib/pubid/core/identifier/base.rb', line 59

def urn
  Renderer::Urn.new(to_h).render
end