Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add lutaml model #118

Merged
merged 8 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ There are two ways to initialize and populate a concept date
[,ruby]
----
concept_date = Glossarist::ConceptDate.new({
date: "2010-11-01T00:00:00.000Z",
date: "2010-11-01T00:00:00+00:00",
type: :accepted,
})
----
Expand All @@ -221,7 +221,7 @@ concept_date = Glossarist::ConceptDate.new({
----
concept_date = Glossarist::ConceptDate.new
concept_date.type = :accepted
concept_date.date = "2010-11-01T00:00:00.000Z"
concept_date.date = "2010-11-01T00:00:00+00:00"
----

[[id,detailed-definition]]
Expand Down
1 change: 1 addition & 0 deletions glossarist.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_dependency "lutaml-model"
spec.add_dependency "relaton", "~> 1.19"
spec.add_dependency "thor"
end
2 changes: 2 additions & 0 deletions lib/glossarist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

require "psych"
require "thor"
require "lutaml/model"

require_relative "glossarist/utilities"
require_relative "glossarist/version"
Expand All @@ -30,6 +31,7 @@

require_relative "glossarist/collections"

require_relative "glossarist/lutaml_models"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HassanAkbar why do we have to use a special namespace for these? Why not just replace the classes in the original namespace?

require_relative "glossarist/config"
require_relative "glossarist/error"

Expand Down
4 changes: 3 additions & 1 deletion lib/glossarist/concept.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class Concept < Model

attr_accessor :release

attr_accessor :localizations

def initialize(*args)
@localizations = {}
@sources = Glossarist::Collections::Collection.new(klass: ConceptSource)
Expand Down Expand Up @@ -78,7 +80,7 @@ def id=(id)
# so adding a temporary check until every glossary is updated using glossarist.
if !id.nil? && (id.is_a?(String) || id.is_a?(Integer))
@id = id
else
elsif !id.nil?
raise(Glossarist::Error, "Expect id to be a String or Integer, Got #{id.class} (#{id})")
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/glossarist/concept_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def load_concept_from_file(filename)
concept_hash["uuid"] = concept_hash["id"] || File.basename(filename, ".*")

concept = Config.class_for(:managed_concept).new(concept_hash)

concept.localized_concepts.each do |_lang, id|
localized_concept = load_localized_concept(id)
concept.add_l10n(localized_concept)
Expand All @@ -55,7 +56,7 @@ def load_localized_concept(id)
)
concept_hash["uuid"] = id

Config.class_for(:localized_concept).new(concept_hash)
Config.class_for(:localized_concept).of_yaml(concept_hash)
rescue Psych::SyntaxError => e
raise Glossarist::ParseError.new(filename: filename, line: e.line)
end
Expand Down
4 changes: 2 additions & 2 deletions lib/glossarist/concept_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ def to_latex_from_file(entries_file)
end

def read_concepts(concepts)
return concepts if concepts.is_a?(Glossarist::ManagedConceptCollection)
return concepts if concepts.is_a?(Glossarist::LutamlModel::ManagedConceptCollection)

collection = Glossarist::ManagedConceptCollection.new
collection = Glossarist::LutamlModel::ManagedConceptCollection.new
collection.load_from_files(concepts)
collection
end
Expand Down
4 changes: 2 additions & 2 deletions lib/glossarist/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ class Config
include Singleton

DEFAULT_CLASSES = {
localized_concept: Glossarist::LocalizedConcept,
managed_concept: Glossarist::ManagedConcept,
localized_concept: Glossarist::LutamlModel::LocalizedConcept,
managed_concept: Glossarist::LutamlModel::ManagedConcept,
}.freeze

attr_reader :registered_classes
Expand Down
15 changes: 15 additions & 0 deletions lib/glossarist/lutaml_model/asset.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Glossarist
module LutamlModel
class Asset < Lutaml::Model::Serializable
attribute :path, :string

yaml do
map :path, to: :path
end

def eql?(asset)
path == asset.path
end
end
end
end
121 changes: 121 additions & 0 deletions lib/glossarist/lutaml_model/citation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
module Glossarist
module LutamlModel
class Citation < Lutaml::Model::Serializable
# Unstructured (plain text) reference.
# @return [String]
attribute :text, :string

# Source in structured reference.
# @return [String]
attribute :source, :string

# Document ID in structured reference.
# @return [String]
attribute :id, :string

# Document version in structured reference.
# @return [String]
attribute :version, :string

# @return [String]
# Referred clause of the document.
attribute :clause, :string

# Link to document.
# @return [String]
attribute :link, :string

# Original ref text before parsing.
# @return [String]
# @note This attribute is likely to be removed or reworked in future.
# It is arguably not relevant to Glossarist itself.
attribute :original, :string

attribute :ref, :string

yaml do
map :id, to: :id, with: { from: :id_from_hash, to: :id_to_hash }
map :text, to: :text, with: { from: :text_from_hash, to: :text_to_hash }
map :source, to: :source, with: { from: :source_from_hash, to: :source_to_hash }
map :version, to: :version, with: { from: :version_from_hash, to: :version_to_hash }
map :ref, to: :ref, with: { from: :ref_from_hash, to: :ref_to_hash }

map :clause, to: :clause
map :link, to: :link
map :original, to: :original
end

def ref_from_hash(model, value)
model.ref = value
end

def ref_to_hash(model, doc)
doc["ref"] = if model.structured?
ref_hash(model)
else
model.text
end
end

def id_from_hash(model, value)
model.id = value
end

def id_to_hash(_model, _doc)
# skip, will be handled in ref
end

def text_from_hash(model, value)
model.text = value
end

def text_to_hash(_model, _doc)
# skip, will be handled in ref
end

def source_from_hash(model, value)
model.source = value
end

def source_to_hash(_model, _doc)
# skip, will be handled in ref
end

def version_from_hash(model, value)
model.version = value
end

def version_to_hash(_model, _doc)
# skip, will be handled in ref
end

def ref_hash(model = self)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need a special method to convert into hash? We should just use the default lutaml-model methods.

{
"source" => model.source,
"id" => model.id,
"version" => model.version
}.compact
end

def ref=(ref)
if ref.is_a?(Hash)
@source = ref["source"]
@id = ref["id"]
@version = ref["version"]
else
@text = ref
end
end

def plain?
(source && id && version).nil?
end

# Whether it is a structured ref.
# @return [Boolean]
def structured?
!plain?
end
end
end
end
57 changes: 57 additions & 0 deletions lib/glossarist/lutaml_model/collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module Glossarist
module LutamlModel
class Collection < Lutaml::Model::Serializable
include Enumerable

attribute :path, :string
attribute :index, :hash, default: -> { {} }

yaml do
map :path, to: :path
map :index, to: :index, render_default: true
end

def each(&block)
@index.each_value(&block)
end

def fetch(id)
@index[id]
end
alias :[] :fetch

def fetch_or_initialize(id)
fetch(id) or store(Concept.of_yaml({ id: id }))
end

def store(concept)
@index[concept.id] = concept
end
alias :<< :store

def load_concepts
Dir.glob(concepts_glob) do |filename|
store(load_concept_from_file(filename))
end
end

# Writes all concepts to files.
def save_concepts
@index.each_value &method(:save_concept_to_file)
end

def load_concept_from_file(filename)
Concept.from_yaml(File.read(filename))
end

def save_concept_to_file(concept)
filename = File.join(path, "concept-#{concept.id}.yaml")
File.write(filename, Psych.dump(concept.to_h))
end

def concepts_glob
File.join(path, "concept-*.{yaml,yml}")
end
end
end
end
Loading
Loading