Class: Metanorma::Release::Publication

Inherits:
Object
  • Object
show all
Defined in:
lib/metanorma/release/publication.rb

Constant Summary collapse

METADATA_VERSION =
1

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(identifier:, slug:, title:, edition:, stage:, doctype:, revdate:, files:, channels:, source: nil, metadata_formats: nil) ⇒ Publication

Returns a new instance of Publication.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/metanorma/release/publication.rb', line 73

def initialize(identifier:, slug:, title:, edition:, stage:, doctype:,
               revdate:, files:, channels:, source: nil, metadata_formats: nil)
  @identifier = identifier
  @slug = slug
  @title = title
  @edition = edition
  @stage = stage
  @doctype = doctype
  @revdate = revdate
  @files = files.freeze
  @channels = channels.freeze
  @source = source
  @metadata_formats = 
  freeze
end

Instance Attribute Details

#channelsObject (readonly)

Returns the value of attribute channels.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def channels
  @channels
end

#doctypeObject (readonly)

Returns the value of attribute doctype.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def doctype
  @doctype
end

#editionObject (readonly)

Returns the value of attribute edition.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def edition
  @edition
end

#filesObject (readonly)

Returns the value of attribute files.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def files
  @files
end

#identifierObject (readonly)

Returns the value of attribute identifier.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def identifier
  @identifier
end

#revdateObject (readonly)

Returns the value of attribute revdate.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def revdate
  @revdate
end

#slugObject (readonly)

Returns the value of attribute slug.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def slug
  @slug
end

#sourceObject (readonly)

Returns the value of attribute source.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def source
  @source
end

#stageObject (readonly)

Returns the value of attribute stage.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def stage
  @stage
end

#titleObject (readonly)

Returns the value of attribute title.



70
71
72
# File 'lib/metanorma/release/publication.rb', line 70

def title
  @title
end

Class Method Details

.discover(output_dir) ⇒ Object

– RXL extraction –



238
239
240
241
242
243
244
245
# File 'lib/metanorma/release/publication.rb', line 238

def self.discover(output_dir)
  Dir.glob(File.join(output_dir, "**", "*.rxl")).filter_map do |path|
    from_rxl(path)
  rescue StandardError => e
    warn "Warning: Skipping #{path}: #{e.message}"
    nil
  end
end

.from_json(json_string) ⇒ Object

Raises:

  • (ArgumentError)


164
165
166
167
168
169
170
171
172
173
# File 'lib/metanorma/release/publication.rb', line 164

def self.from_json(json_string)
  data = JSON.parse(json_string)
  raise ArgumentError, "Missing required field: id" unless data["id"]
  unless data["title"]
    raise ArgumentError,
          "Missing required field: title"
  end

  (data)
end

.from_metadata_hash(data) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/metanorma/release/publication.rb', line 186

def self.(data)
  ident = data["identifier"] || data["id"]
  new(
    identifier: ident,
    slug: slug_from_identifier(ident),
    title: data["title"],
    edition: data["edition"],
    stage: data["stage"],
    doctype: data["doctype"],
    revdate: data["revdate"],
    files: [],
    channels: data["channels"] || [],
    source: nil,
    metadata_formats: data["formats"],
  )
end

.from_release_body(body) ⇒ Object



175
176
177
178
179
180
181
182
183
184
# File 'lib/metanorma/release/publication.rb', line 175

def self.from_release_body(body)
  return nil if body.nil? || body.empty?

  match = body.match(/<!--\s*mn-release-metadata\s*\n(.*?)\n-->/m)
  return nil unless match

  from_json(match[1])
rescue JSON::ParserError
  nil
end

.from_rxl(rxl_path) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/metanorma/release/publication.rb', line 247

def self.from_rxl(rxl_path)
  unless File.exist?(rxl_path)
    raise ArgumentError,
          "RXL file not found: #{rxl_path}"
  end

  content = File.read(rxl_path)
  bib = Relaton::Bib::Item.from_xml(content)
  build_from_bib(bib, rxl_path)
rescue StandardError => e
  warn "Warning: Failed to parse RXL #{rxl_path}: #{e.message}"
  fallback_from_rxl(rxl_path)
end

.publisher_from_identifier(identifier) ⇒ Object



230
231
232
233
234
# File 'lib/metanorma/release/publication.rb', line 230

def self.publisher_from_identifier(identifier)
  return nil if identifier.nil? || identifier.strip.empty?

  identifier.strip.split(/[\s-]/).first&.downcase
end

.slug_from_identifier(identifier) ⇒ Object



221
222
223
224
225
226
227
228
# File 'lib/metanorma/release/publication.rb', line 221

def self.slug_from_identifier(identifier)
  identifier.to_s.strip
    .gsub(/\s+/, "-")
    .gsub(/:+/, "-")
    .downcase
    .gsub(/--+/, "-")
    .gsub(/[-.]+$/, "")
end

Instance Method Details

#base_dirObject



93
94
95
# File 'lib/metanorma/release/publication.rb', line 93

def base_dir
  files.any? ? File.dirname(files.first.path) : "."
end

#content_hashObject



97
98
99
# File 'lib/metanorma/release/publication.rb', line 97

def content_hash
  ContentHash.of_directory(base_dir, base: slug)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


105
106
107
108
# File 'lib/metanorma/release/publication.rb', line 105

def eql?(other)
  other.is_a?(self.class) && identifier == other.identifier &&
    edition == other.edition && stage == other.stage
end

#file?(format) ⇒ Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/metanorma/release/publication.rb', line 101

def file?(format)
  formats.include?(format)
end

#formatsObject



89
90
91
# File 'lib/metanorma/release/publication.rb', line 89

def formats
  @metadata_formats || files.map(&:format)
end

#hashObject



110
111
112
# File 'lib/metanorma/release/publication.rb', line 110

def hash
  [identifier, edition, stage].hash
end

#to_hObject



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/metanorma/release/publication.rb', line 114

def to_h
  h = {
    "id" => slug, "identifier" => identifier, "title" => title,
    "edition" => edition, "stage" => stage, "doctype" => doctype,
    "channels" => channels, "formats" => formats,
    "revdate" => revdate
  }
  h["source"] = source.to_h if source
  h["files"] = files.map(&:to_h) unless files.empty?
  h
end

#to_json(*_args) ⇒ Object



160
161
162
# File 'lib/metanorma/release/publication.rb', line 160

def to_json(*_args)
  JSON.generate()
end

#to_release_bodyObject



156
157
158
# File 'lib/metanorma/release/publication.rb', line 156

def to_release_body
  "<!-- mn-release-metadata\n#{JSON.generate()}\n-->"
end

#with_channels(new_channels) ⇒ Object



126
127
128
129
130
131
132
133
134
# File 'lib/metanorma/release/publication.rb', line 126

def with_channels(new_channels)
  self.class.new(
    identifier: identifier, slug: slug, title: title,
    edition: edition, stage: stage, doctype: doctype,
    revdate: revdate, files: files,
    channels: new_channels, source: source,
    metadata_formats: @metadata_formats
  )
end

#with_files_and_source(new_files, release, repo) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/metanorma/release/publication.rb', line 136

def with_files_and_source(new_files, release, repo)
  source = PublicationSource.new(
    owner: repo.owner, repo: repo.repo,
    tag: release.tag_name,
    url: release.html_url,
    date: release.published_at
  )
  pub_files = new_files.map do |f|
    name = File.basename(f)
    ext = File.extname(name).delete_prefix(".")
    PublicationFile.new(format: ext, name: name, path: f)
  end
  self.class.new(
    identifier: identifier, slug: slug, title: title,
    edition: edition, stage: stage, doctype: doctype,
    revdate: revdate, files: pub_files,
    channels: channels, source: source
  )
end