glossarist 2.8.1 → 2.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.rubocop_todo.yml +413 -63
  4. data/CLAUDE.md +1 -1
  5. data/Gemfile +1 -1
  6. data/README.adoc +4 -1
  7. data/glossarist.gemspec +2 -1
  8. data/lib/glossarist/bibliography_data.rb +41 -0
  9. data/lib/glossarist/bibliography_entry.rb +13 -0
  10. data/lib/glossarist/citation.rb +8 -2
  11. data/lib/glossarist/cli/export_command.rb +10 -5
  12. data/lib/glossarist/cli/validate_command.rb +21 -5
  13. data/lib/glossarist/collection.rb +2 -2
  14. data/lib/glossarist/collections/bibliography_collection.rb +2 -1
  15. data/lib/glossarist/collections/collection.rb +2 -2
  16. data/lib/glossarist/collections/localization_collection.rb +4 -4
  17. data/lib/glossarist/concept_collector.rb +6 -6
  18. data/lib/glossarist/concept_document.rb +2 -3
  19. data/lib/glossarist/concept_manager.rb +6 -8
  20. data/lib/glossarist/concept_set.rb +4 -4
  21. data/lib/glossarist/concept_store.rb +84 -0
  22. data/lib/glossarist/dataset_validator.rb +2 -1
  23. data/lib/glossarist/gcr_package_definition.rb +37 -0
  24. data/lib/glossarist/gcr_statistics.rb +2 -2
  25. data/lib/glossarist/glossary_definition.rb +1 -1
  26. data/lib/glossarist/glossary_store.rb +201 -0
  27. data/lib/glossarist/managed_concept_collection.rb +2 -2
  28. data/lib/glossarist/managed_concept_data.rb +2 -0
  29. data/lib/glossarist/rdf/gloss_citation.rb +8 -4
  30. data/lib/glossarist/rdf/gloss_concept.rb +13 -4
  31. data/lib/glossarist/rdf/gloss_concept_date.rb +4 -2
  32. data/lib/glossarist/rdf/gloss_concept_reference.rb +6 -3
  33. data/lib/glossarist/rdf/gloss_concept_source.rb +6 -3
  34. data/lib/glossarist/rdf/gloss_designation.rb +63 -26
  35. data/lib/glossarist/rdf/gloss_grammar_info.rb +19 -9
  36. data/lib/glossarist/rdf/gloss_locality.rb +6 -3
  37. data/lib/glossarist/rdf/gloss_localized_concept.rb +14 -7
  38. data/lib/glossarist/rdf/gloss_non_verbal_rep.rb +9 -4
  39. data/lib/glossarist/rdf/gloss_pronunciation.rb +13 -6
  40. data/lib/glossarist/rdf/gloss_reference.rb +8 -4
  41. data/lib/glossarist/rdf/namespaces.rb +3 -2
  42. data/lib/glossarist/rdf/relationship_predicates.rb +79 -0
  43. data/lib/glossarist/rdf/v3/configuration.rb +0 -2
  44. data/lib/glossarist/rdf/v3.rb +4 -43
  45. data/lib/glossarist/rdf.rb +26 -23
  46. data/lib/glossarist/register_data.rb +68 -18
  47. data/lib/glossarist/schema_migration.rb +8 -5
  48. data/lib/glossarist/sts/importer.rb +0 -1
  49. data/lib/glossarist/transforms/concept_to_gloss_transform.rb +57 -72
  50. data/lib/glossarist/v2/concept_data.rb +2 -1
  51. data/lib/glossarist/v2/concept_document.rb +1 -1
  52. data/lib/glossarist/v2/configuration.rb +0 -2
  53. data/lib/glossarist/v2/managed_concept_data.rb +1 -0
  54. data/lib/glossarist/v2.rb +12 -12
  55. data/lib/glossarist/v3/concept_data.rb +2 -1
  56. data/lib/glossarist/v3/concept_document.rb +1 -1
  57. data/lib/glossarist/v3/configuration.rb +0 -2
  58. data/lib/glossarist/v3/managed_concept_data.rb +1 -0
  59. data/lib/glossarist/v3.rb +16 -16
  60. data/lib/glossarist/validation/asset_index.rb +2 -2
  61. data/lib/glossarist/validation/bibliography_index.rb +11 -8
  62. data/lib/glossarist/validation/rules/asciidoc_xref_rule.rb +2 -1
  63. data/lib/glossarist/validation/rules/authoritative_source_rule.rb +1 -1
  64. data/lib/glossarist/validation/rules/bibliography_yaml_rule.rb +1 -1
  65. data/lib/glossarist/validation/rules/citation_completeness_rule.rb +1 -1
  66. data/lib/glossarist/validation/rules/concept_count_rule.rb +2 -3
  67. data/lib/glossarist/validation/rules/concept_id_rule.rb +0 -1
  68. data/lib/glossarist/validation/rules/concept_id_uniqueness_rule.rb +0 -1
  69. data/lib/glossarist/validation/rules/concept_mention_rule.rb +1 -2
  70. data/lib/glossarist/validation/rules/concept_status_rule.rb +1 -2
  71. data/lib/glossarist/validation/rules/concept_uri_rule.rb +1 -1
  72. data/lib/glossarist/validation/rules/date_type_rule.rb +5 -3
  73. data/lib/glossarist/validation/rules/date_validity_rule.rb +1 -1
  74. data/lib/glossarist/validation/rules/definition_content_rule.rb +1 -2
  75. data/lib/glossarist/validation/rules/domain_target_rule.rb +1 -1
  76. data/lib/glossarist/validation/rules/duplicate_term_rule.rb +1 -2
  77. data/lib/glossarist/validation/rules/entry_status_rule.rb +1 -2
  78. data/lib/glossarist/validation/rules/filename_id_rule.rb +2 -3
  79. data/lib/glossarist/validation/rules/image_reference_rule.rb +3 -2
  80. data/lib/glossarist/validation/rules/l10n_uuid_integrity_rule.rb +1 -2
  81. data/lib/glossarist/validation/rules/language_coverage_rule.rb +1 -2
  82. data/lib/glossarist/validation/rules/language_list_rule.rb +2 -3
  83. data/lib/glossarist/validation/rules/locality_completeness_rule.rb +3 -1
  84. data/lib/glossarist/validation/rules/localization_consistency_rule.rb +1 -1
  85. data/lib/glossarist/validation/rules/localization_presence_rule.rb +0 -1
  86. data/lib/glossarist/validation/rules/model_validity_rule.rb +1 -1
  87. data/lib/glossarist/validation/rules/orphaned_bibliography_rule.rb +2 -1
  88. data/lib/glossarist/validation/rules/orphaned_images_rule.rb +6 -4
  89. data/lib/glossarist/validation/rules/orphaned_l10n_files_rule.rb +1 -2
  90. data/lib/glossarist/validation/rules/preferred_term_rule.rb +1 -2
  91. data/lib/glossarist/validation/rules/related_concept_cycle_rule.rb +2 -2
  92. data/lib/glossarist/validation/rules/related_concept_rule.rb +1 -2
  93. data/lib/glossarist/validation/rules/related_concept_symmetry_rule.rb +1 -1
  94. data/lib/glossarist/validation/rules/related_concept_target_rule.rb +1 -1
  95. data/lib/glossarist/validation/rules/source_type_rule.rb +2 -2
  96. data/lib/glossarist/validation/rules/source_urn_format_rule.rb +2 -2
  97. data/lib/glossarist/validation/rules/terms_presence_rule.rb +1 -1
  98. data/lib/glossarist/validation/rules/uuid_format_rule.rb +1 -1
  99. data/lib/glossarist/validation/rules.rb +18 -49
  100. data/lib/glossarist/version.rb +1 -1
  101. data/lib/glossarist.rb +13 -11
  102. data/scripts/migrate_dataset.rb +14 -8
  103. data/scripts/migrate_isotc204_to_v3.rb +3 -1
  104. data/scripts/migrate_isotc211_to_v3.rb +5 -3
  105. data/scripts/migrate_osgeo_to_v3.rb +4 -2
  106. data/scripts/upgrade_dataset_to_v3.rb +0 -0
  107. metadata +24 -11
  108. data/lib/glossarist/rdf/ext/jsonld_transform_ext.rb +0 -208
  109. data/lib/glossarist/rdf/ext/mapping_ext.rb +0 -37
  110. data/lib/glossarist/rdf/ext/mapping_rule_ext.rb +0 -27
  111. data/lib/glossarist/rdf/ext/member_rule_ext.rb +0 -34
  112. data/lib/glossarist/rdf/ext/turtle_transform_ext.rb +0 -222
  113. data/lib/glossarist/rdf/ext.rb +0 -39
  114. data/lib/glossarist/rdf/relationships.rb +0 -19
@@ -3,8 +3,9 @@
3
3
  module Glossarist
4
4
  module Rdf
5
5
  module Namespaces
6
- autoload :DctermsNamespace, "#{__dir__}/namespaces/dcterms_namespace"
7
- autoload :GlossaristNamespace, "#{__dir__}/namespaces/glossarist_namespace"
6
+ autoload :DctermsNamespace, "#{__dir__}/namespaces/dcterms_namespace"
7
+ autoload :GlossaristNamespace,
8
+ "#{__dir__}/namespaces/glossarist_namespace"
8
9
  autoload :IsoThesNamespace, "#{__dir__}/namespaces/iso_thes_namespace"
9
10
  autoload :OwlNamespace, "#{__dir__}/namespaces/owl_namespace"
10
11
  autoload :RdfNamespace, "#{__dir__}/namespaces/rdf_namespace"
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ module Rdf
5
+ # Canonical data-driven maps for relationship predicates.
6
+ #
7
+ # Each entry maps a relationship type symbol to [namespace_module, predicate_name].
8
+ # These maps drive:
9
+ # 1. Attribute declarations in RDF view classes (one typed collection per predicate)
10
+ # 2. RDF predicate mappings with uri_reference: true
11
+ # 3. Transform grouping logic in ConceptToGlossTransform
12
+ module RelationshipPredicates
13
+ CONCEPT_REL_PREDICATES = {
14
+ broader: [Namespaces::SkosNamespace, :broader],
15
+ narrower: [Namespaces::SkosNamespace, :narrower],
16
+ broader_generic: [Namespaces::IsoThesNamespace, :broaderGeneric],
17
+ narrower_generic: [Namespaces::IsoThesNamespace, :narrowerGeneric],
18
+ broader_partitive: [Namespaces::IsoThesNamespace, :broaderPartitive],
19
+ narrower_partitive: [Namespaces::IsoThesNamespace, :narrowerPartitive],
20
+ broader_instantial: [Namespaces::IsoThesNamespace, :broaderInstantial],
21
+ narrower_instantial: [Namespaces::IsoThesNamespace,
22
+ :narrowerInstantial],
23
+ equivalent: [Namespaces::SkosNamespace, :exactMatch],
24
+ close_match: [Namespaces::SkosNamespace, :closeMatch],
25
+ broad_match: [Namespaces::SkosNamespace, :broadMatch],
26
+ narrow_match: [Namespaces::SkosNamespace, :narrowMatch],
27
+ related_match: [Namespaces::SkosNamespace, :relatedMatch],
28
+ see: [Namespaces::SkosNamespace, :related],
29
+ deprecates: [Namespaces::GlossaristNamespace, :deprecates],
30
+ supersedes: [Namespaces::GlossaristNamespace, :supersedes],
31
+ superseded_by: [Namespaces::GlossaristNamespace, :supersededBy],
32
+ compare: [Namespaces::GlossaristNamespace, :compares],
33
+ contrast: [Namespaces::GlossaristNamespace, :contrasts],
34
+ sequentially_related_concept: [Namespaces::GlossaristNamespace,
35
+ :sequentiallyRelated],
36
+ spatially_related_concept: [Namespaces::GlossaristNamespace,
37
+ :spatiallyRelated],
38
+ temporally_related_concept: [Namespaces::GlossaristNamespace,
39
+ :temporallyRelated],
40
+ related_concept_broader: [Namespaces::GlossaristNamespace,
41
+ :relatedConceptBroader],
42
+ related_concept_narrower: [Namespaces::GlossaristNamespace,
43
+ :relatedConceptNarrower],
44
+ }.freeze
45
+
46
+ DESIGNATION_REL_PREDICATES = {
47
+ homograph: [Namespaces::GlossaristNamespace, :hasHomograph],
48
+ false_friend: [Namespaces::GlossaristNamespace, :hasFalseFriend],
49
+ abbreviated_form_for: [Namespaces::GlossaristNamespace,
50
+ :abbreviatedFormFor],
51
+ short_form_for: [Namespaces::GlossaristNamespace, :shortFormFor],
52
+ }.freeze
53
+
54
+ ALL_REL_PREDICATES = CONCEPT_REL_PREDICATES.merge(DESIGNATION_REL_PREDICATES).freeze
55
+
56
+ def self.related_targets_by_type(related_concepts, predicate_map)
57
+ targets = group_targets(related_concepts, predicate_map)
58
+ predicate_map.each_key.to_h do |type|
59
+ [:"#{type}_targets", targets[:"#{type}_targets"] || []]
60
+ end
61
+ end
62
+
63
+ def self.group_targets(related_concepts, predicate_map)
64
+ valid = valid_related(related_concepts, predicate_map)
65
+ valid
66
+ .group_by { |rc| rc.type.to_sym }
67
+ .transform_values { |rcs| rcs.map { |rc| "concept/#{rc.ref.id}" } }
68
+ .transform_keys { |type| :"#{type}_targets" }
69
+ end
70
+
71
+ def self.valid_related(related_concepts, predicate_map)
72
+ Array(related_concepts).select do |rc|
73
+ rc.ref&.id && predicate_map.key?(rc.type.to_sym)
74
+ end
75
+ end
76
+ private_class_method :group_targets, :valid_related
77
+ end
78
+ end
79
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../context_configuration"
4
-
5
3
  module Glossarist
6
4
  module Rdf
7
5
  module V3
@@ -1,51 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Load shared infrastructure first
4
- require_relative "ext"
5
- require_relative "namespaces"
6
- require_relative "relationships"
7
- require_relative "localized_literal"
8
-
9
- # V3 Configuration must be loaded before view classes are registered
10
- require_relative "v3/configuration"
11
-
12
- # Load all view class files (must precede V3 constant assignments)
13
- require_relative "gloss_locality"
14
- require_relative "gloss_reference"
15
- require_relative "gloss_concept_source"
16
- require_relative "gloss_detailed_definition"
17
- require_relative "gloss_pronunciation"
18
- require_relative "gloss_grammar_info"
19
- require_relative "gloss_non_verbal_rep"
20
- require_relative "gloss_concept_date"
21
- require_relative "gloss_designation"
22
- require_relative "gloss_localized_concept"
23
- require_relative "gloss_concept"
24
-
25
3
  module Glossarist
26
4
  module Rdf
27
- # V3 is the current (and only) RDF schema version.
28
- #
29
- # All RDF view classes produce v3 gloss ontology output:
30
- # namespace URI: https://www.glossarist.org/ontologies/v3/
31
- #
32
- # Each version has its own Configuration module with a unique CONTEXT_ID
33
- # so that V3 and (future) V4 classes are isolated in separate
34
- # Lutaml::Model::GlobalContext registries.
35
- #
36
- # When v4 is added:
37
- # - Create Rdf::V4::Configuration with CONTEXT_ID = :glossarist_rdf_v4
38
- # - Create V4 view classes (standalone or inheriting from V3)
39
- # - Register V4 classes in Rdf::V4::Configuration
40
- # - Update ConceptToGlossTransform to support v4
41
- # - V3 and V4 coexist — consumers choose which to use
42
5
  module V3
43
- # Namespace
44
- GlossaristNamespace = Namespaces::GlossaristNamespace
6
+ autoload :Configuration, "glossarist/rdf/v3/configuration"
45
7
 
46
- # Single source of truth: add new view classes here once.
47
- # Each entry is registered in the V3 type registry and
48
- # re-exported as a V3:: constant.
49
8
  VIEW_CLASS_NAMES = %i[
50
9
  GlossLocality
51
10
  GlossPronunciation
@@ -70,7 +29,9 @@ module Glossarist
70
29
 
71
30
  VIEW_CLASS_NAMES.each do |name|
72
31
  klass = ::Glossarist::Rdf.const_get(name)
73
- registry_id = name.to_s.gsub(/([A-Z])/) { |c| "_#{c.downcase}" }.sub(/^_/, "").to_sym
32
+ registry_id = name.to_s
33
+ .gsub(/([A-Z])/) { |c| "_#{c.downcase}" }
34
+ .sub(/^_/, "").to_sym
74
35
  Configuration.register_model(klass, id: registry_id)
75
36
  const_set(name, klass)
76
37
  end
@@ -1,30 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Load lutaml-model RDF extensions before any RDF view classes
4
- require_relative "rdf/ext"
3
+ require "lutaml/rdf"
4
+ require "lutaml/turtle"
5
+ require "lutaml/jsonld"
5
6
 
6
7
  module Glossarist
7
8
  module Rdf
8
- autoload :Namespaces, "#{__dir__}/rdf/namespaces"
9
- autoload :LocalizedLiteral, "#{__dir__}/rdf/localized_literal"
10
- autoload :Relationships, "#{__dir__}/rdf/relationships"
11
- autoload :GlossLocality, "#{__dir__}/rdf/gloss_locality"
12
- autoload :GlossCitation, "#{__dir__}/rdf/gloss_citation"
13
- autoload :GlossConceptSource, "#{__dir__}/rdf/gloss_concept_source"
14
- autoload :GlossDetailedDefinition, "#{__dir__}/rdf/gloss_detailed_definition"
15
- autoload :GlossPronunciation, "#{__dir__}/rdf/gloss_pronunciation"
16
- autoload :GlossGrammarInfo, "#{__dir__}/rdf/gloss_grammar_info"
17
- autoload :GlossNonVerbalRep, "#{__dir__}/rdf/gloss_non_verbal_rep"
18
- autoload :GlossConceptReference, "#{__dir__}/rdf/gloss_concept_reference"
19
- autoload :GlossConceptDate, "#{__dir__}/rdf/gloss_concept_date"
20
- autoload :GlossDesignation, "#{__dir__}/rdf/gloss_designation"
21
- autoload :GlossExpression, "#{__dir__}/rdf/gloss_designation"
22
- autoload :GlossAbbreviation, "#{__dir__}/rdf/gloss_designation"
23
- autoload :GlossSymbol, "#{__dir__}/rdf/gloss_designation"
24
- autoload :GlossLetterSymbol, "#{__dir__}/rdf/gloss_designation"
25
- autoload :GlossGraphicalSymbol, "#{__dir__}/rdf/gloss_designation"
26
- autoload :GlossLocalizedConcept, "#{__dir__}/rdf/gloss_localized_concept"
27
- autoload :GlossConcept, "#{__dir__}/rdf/gloss_concept"
28
- autoload :GlossDocument, "#{__dir__}/rdf/gloss_concept"
9
+ autoload :Namespaces, "#{__dir__}/rdf/namespaces"
10
+ autoload :LocalizedLiteral, "#{__dir__}/rdf/localized_literal"
11
+ autoload :RelationshipPredicates, "#{__dir__}/rdf/relationship_predicates"
12
+ autoload :GlossLocality, "#{__dir__}/rdf/gloss_locality"
13
+ autoload :GlossCitation, "#{__dir__}/rdf/gloss_citation"
14
+ autoload :GlossConceptSource, "#{__dir__}/rdf/gloss_concept_source"
15
+ autoload :GlossDetailedDefinition,
16
+ "#{__dir__}/rdf/gloss_detailed_definition"
17
+ autoload :GlossPronunciation, "#{__dir__}/rdf/gloss_pronunciation"
18
+ autoload :GlossGrammarInfo, "#{__dir__}/rdf/gloss_grammar_info"
19
+ autoload :GlossNonVerbalRep, "#{__dir__}/rdf/gloss_non_verbal_rep"
20
+ autoload :GlossConceptReference, "#{__dir__}/rdf/gloss_concept_reference"
21
+ autoload :GlossConceptDate, "#{__dir__}/rdf/gloss_concept_date"
22
+ autoload :GlossDesignation, "#{__dir__}/rdf/gloss_designation"
23
+ autoload :GlossExpression, "#{__dir__}/rdf/gloss_designation"
24
+ autoload :GlossAbbreviation, "#{__dir__}/rdf/gloss_designation"
25
+ autoload :GlossSymbol, "#{__dir__}/rdf/gloss_designation"
26
+ autoload :GlossLetterSymbol, "#{__dir__}/rdf/gloss_designation"
27
+ autoload :GlossGraphicalSymbol, "#{__dir__}/rdf/gloss_designation"
28
+ autoload :GlossLocalizedConcept, "#{__dir__}/rdf/gloss_localized_concept"
29
+ autoload :GlossConcept, "#{__dir__}/rdf/gloss_concept"
30
+ autoload :GlossDocument, "#{__dir__}/rdf/gloss_concept"
31
+ autoload :V3, "#{__dir__}/rdf/v3"
29
32
  end
30
33
  end
@@ -2,38 +2,88 @@
2
2
 
3
3
  module Glossarist
4
4
  class RegisterData < Lutaml::Model::Serializable
5
- attribute :data, :hash, default: -> { {} }
5
+ attribute :key, :string, default: -> { "register" }
6
+ attribute :shortname, :string
7
+ attribute :name, :string
8
+ attribute :description, :string
9
+ attribute :schema_version, :string
10
+ attribute :version, :string
11
+ attribute :owner, :string
12
+ attribute :languages, :string, collection: true
13
+ attribute :subregisters, :hash, default: -> { {} }
14
+ attribute :uri_prefix, :string
15
+ attribute :concept_uri_template, :string
16
+ attribute :homepage, :string
17
+ attribute :repository, :string
18
+ attribute :license, :string
19
+ attribute :tags, :string, collection: true
6
20
 
7
21
  key_value do
8
- map nil, to: :data, with: { from: :data_from, to: :data_to }
9
- end
10
-
11
- def self.from_file(path)
12
- from_yaml(File.read(path))
13
- rescue Errno::ENOENT
14
- nil
22
+ map %i[id shortname], to: :shortname
23
+ map "name", to: :name
24
+ map "description", to: :description
25
+ map "schema_version", to: :schema_version
26
+ map "version", to: :version
27
+ map "owner", to: :owner
28
+ map "languages", to: :languages
29
+ map "subregisters", to: :subregisters
30
+ map "uri_prefix", to: :uri_prefix
31
+ map "concept_uri_template", to: :concept_uri_template
32
+ map "homepage", to: :homepage
33
+ map "repository", to: :repository
34
+ map "license", to: :license
35
+ map "tags", to: :tags
15
36
  end
16
37
 
17
38
  def [](key)
18
- data[key]
39
+ case key
40
+ when "shortname", "id" then shortname
41
+ when "name" then name
42
+ when "description" then description
43
+ when "schema_version" then schema_version
44
+ when "version" then version
45
+ when "owner" then owner
46
+ when "languages" then languages
47
+ when "subregisters" then subregisters
48
+ when "uri_prefix" then uri_prefix
49
+ when "concept_uri_template" then concept_uri_template
50
+ when "homepage" then homepage
51
+ when "repository" then repository
52
+ when "license" then license
53
+ when "tags" then tags
54
+ end
19
55
  end
20
56
 
21
57
  def dig(*keys)
22
- data.dig(*keys)
58
+ return nil if keys.empty?
59
+
60
+ first = self[keys.first]
61
+ keys.length == 1 ? first : nil
23
62
  end
24
63
 
25
64
  def to_h
26
- data
65
+ h = {}
66
+ h["shortname"] = shortname if shortname
67
+ h["name"] = name if name
68
+ h["description"] = description if description
69
+ h["schema_version"] = schema_version if schema_version
70
+ h["version"] = version if version
71
+ h["owner"] = owner if owner
72
+ h["languages"] = languages if languages && !languages.empty?
73
+ h["subregisters"] = subregisters if subregisters && !subregisters.empty?
74
+ h["uri_prefix"] = uri_prefix if uri_prefix
75
+ h["concept_uri_template"] = concept_uri_template if concept_uri_template
76
+ h["homepage"] = homepage if homepage
77
+ h["repository"] = repository if repository
78
+ h["license"] = license if license
79
+ h["tags"] = tags if tags && !tags.empty?
80
+ h
27
81
  end
28
82
 
29
- def data_from(model, value)
30
- model.data = value
31
- end
83
+ def self.from_file(path)
84
+ return nil unless File.exist?(path)
32
85
 
33
- def data_to(model, doc)
34
- model.data.each do |key, value|
35
- doc[key] = value
36
- end
86
+ from_yaml(File.read(path, encoding: "utf-8"))
37
87
  end
38
88
  end
39
89
  end
@@ -23,7 +23,10 @@ module Glossarist
23
23
  end
24
24
  end
25
25
 
26
- raise Error, "Migration chain too long or unresolvable" unless current == target
26
+ unless current == target
27
+ raise Error,
28
+ "Migration chain too long or unresolvable"
29
+ end
27
30
 
28
31
  concept.schema_version = target
29
32
  concept
@@ -53,8 +56,8 @@ module Glossarist
53
56
 
54
57
  LANG_CODES = Glossarist::LANG_CODES
55
58
 
56
- IEV_PATTERN = /\{\{([^,}]+),\s*IEV:([^}]+)\}\}/.freeze
57
- URN_PATTERN = /\{urn:iso:std:iso:(\d+):([^,}]+),([^}]+)\}/.freeze
59
+ IEV_PATTERN = /\{\{([^,}]+),\s*IEV:([^}]+)\}\}/
60
+ URN_PATTERN = /\{urn:iso:std:iso:(\d+):([^,}]+),([^}]+)\}/
58
61
 
59
62
  attr_reader :from_version, :to_version
60
63
 
@@ -149,7 +152,7 @@ module Glossarist
149
152
  src = lc.delete("authoritative_source")
150
153
  return if lc.key?("sources")
151
154
 
152
- sources = (src.is_a?(Array) ? src : [src]).map do |s|
155
+ sources = (src.is_a?(Array) ? src : [src]).filter_map do |s|
153
156
  next unless s.is_a?(Hash)
154
157
 
155
158
  origin = {}
@@ -166,7 +169,7 @@ module Glossarist
166
169
  end
167
170
  end
168
171
  entry
169
- end.compact
172
+ end
170
173
 
171
174
  lc["sources"] = sources if sources.any?
172
175
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "tmpdir"
4
- require_relative "import_result"
5
4
 
6
5
  module Glossarist
7
6
  module Sts
@@ -15,36 +15,10 @@ module Glossarist
15
15
  DCT = Rdf::Namespaces::DctermsNamespace.uri
16
16
  RDF_NS = Rdf::Namespaces::RdfNamespace.uri
17
17
 
18
- REL_PROPERTY_MAP = {
19
- "broader" => "#{SKOS}broader",
20
- "narrower" => "#{SKOS}narrower",
21
- "broader_generic" => "#{ISO}broaderGeneric",
22
- "narrower_generic" => "#{ISO}narrowerGeneric",
23
- "broader_partitive" => "#{ISO}broaderPartitive",
24
- "narrower_partitive" => "#{ISO}narrowerPartitive",
25
- "broader_instantial" => "#{ISO}broaderInstantial",
26
- "narrower_instantial" => "#{ISO}narrowerInstantial",
27
- "equivalent" => "#{SKOS}exactMatch",
28
- "close_match" => "#{SKOS}closeMatch",
29
- "broad_match" => "#{SKOS}broadMatch",
30
- "narrow_match" => "#{SKOS}narrowMatch",
31
- "related_match" => "#{SKOS}relatedMatch",
32
- "see" => "#{SKOS}related",
33
- "deprecates" => "#{GLOSS}deprecates",
34
- "supersedes" => "#{GLOSS}supersedes",
35
- "superseded_by" => "#{GLOSS}supersededBy",
36
- "compare" => "#{GLOSS}compares",
37
- "contrast" => "#{GLOSS}contrasts",
38
- "sequentially_related_concept" => "#{GLOSS}sequentiallyRelated",
39
- "spatially_related_concept" => "#{GLOSS}spatiallyRelated",
40
- "temporally_related_concept" => "#{GLOSS}temporallyRelated",
41
- "homograph" => "#{GLOSS}hasHomograph",
42
- "false_friend" => "#{GLOSS}hasFalseFriend",
43
- "related_concept_broader" => "#{GLOSS}relatedConceptBroader",
44
- "related_concept_narrower" => "#{GLOSS}relatedConceptNarrower",
45
- "abbreviated_form_for" => "#{GLOSS}abbreviatedFormFor",
46
- "short_form_for" => "#{GLOSS}shortFormFor",
47
- }.freeze
18
+ REL_PROPERTY_MAP = Rdf::RelationshipPredicates::ALL_REL_PREDICATES
19
+ .transform_values { |ns, name| ns[name] }
20
+ .transform_keys(&:to_s)
21
+ .freeze
48
22
 
49
23
  DATE_TYPE_MAP = {
50
24
  "accepted" => "#{GLOSS}status/accepted",
@@ -89,7 +63,9 @@ module Glossarist
89
63
 
90
64
  def to_jsonld(concepts_or_concept = nil)
91
65
  if concepts_or_concept.is_a?(Array)
92
- gloss_concepts = concepts_or_concept.map { |c| build_gloss_concept(c) }
66
+ gloss_concepts = concepts_or_concept.map do |c|
67
+ build_gloss_concept(c)
68
+ end
93
69
  doc = Rdf::GlossDocument.new(concepts: gloss_concepts)
94
70
  Rdf::GlossDocument.to_jsonld(doc)
95
71
  else
@@ -112,8 +88,6 @@ module Glossarist
112
88
 
113
89
  attr_reader :concept, :options
114
90
 
115
- # ── Build RDF view instances from domain model ─────────────────────
116
-
117
91
  def build_gloss_concept(managed_concept)
118
92
  identifier = managed_concept.data&.id || managed_concept.identifier
119
93
 
@@ -121,17 +95,21 @@ module Glossarist
121
95
  build_gloss_localized_concept(l10n, identifier)
122
96
  end
123
97
 
124
- gc = Rdf::GlossConcept.new(
98
+ rel_targets = Rdf::RelationshipPredicates.related_targets_by_type(
99
+ managed_concept.related,
100
+ Rdf::RelationshipPredicates::CONCEPT_REL_PREDICATES,
101
+ )
102
+
103
+ Rdf::GlossConcept.new(
125
104
  identifier: identifier.to_s,
126
105
  status: status_uri(managed_concept.status),
127
106
  localizations: localizations,
128
107
  sources: build_gloss_sources(managed_concept.data&.sources),
129
- domains: build_gloss_domains(managed_concept.data&.domains, identifier),
108
+ domains: build_gloss_domains(managed_concept.data&.domains,
109
+ identifier),
130
110
  dates: build_gloss_dates(managed_concept.dates, identifier),
111
+ **rel_targets,
131
112
  )
132
-
133
- gc.relationship_triples = build_relationship_triples(managed_concept.related)
134
- gc
135
113
  end
136
114
 
137
115
  def build_gloss_localized_concept(l10n, concept_id)
@@ -146,7 +124,8 @@ module Glossarist
146
124
  notes = build_gloss_definitions(data&.notes)
147
125
  examples = build_gloss_definitions(data&.examples)
148
126
  sources = build_gloss_sources(data&.sources)
149
- non_verb_reps = build_gloss_non_verbal_reps(l10n.non_verb_rep, concept_id, lang)
127
+ non_verb_reps = build_gloss_non_verbal_reps(l10n.non_verb_rep,
128
+ concept_id, lang)
150
129
 
151
130
  Rdf::GlossLocalizedConcept.new(
152
131
  concept_id: concept_id.to_s,
@@ -168,26 +147,37 @@ module Glossarist
168
147
 
169
148
  def build_gloss_designation(desig, concept_id, lang, index)
170
149
  common_attrs = designation_common_attrs(desig, concept_id, lang, index)
150
+ instance = designation_instance_for(desig, common_attrs, concept_id,
151
+ lang, index)
171
152
 
172
- instance = case desig
173
- when Designation::Abbreviation
174
- build_gloss_abbreviation(desig, common_attrs, concept_id, lang, index)
175
- when Designation::Expression
176
- build_gloss_expression(desig, common_attrs, concept_id, lang, index)
177
- when Designation::GraphicalSymbol
178
- Rdf::GlossGraphicalSymbol.new(common_attrs.merge(text: desig.text, image: desig.image))
179
- when Designation::LetterSymbol
180
- Rdf::GlossLetterSymbol.new(common_attrs.merge(text: desig.text))
181
- when Designation::Symbol
182
- Rdf::GlossSymbol.new(common_attrs)
183
- else
184
- Rdf::GlossExpression.new(common_attrs)
185
- end
186
-
187
- instance.relationship_triples = build_relationship_triples(desig.related)
153
+ rel_targets = Rdf::RelationshipPredicates.related_targets_by_type(
154
+ desig.related,
155
+ Rdf::RelationshipPredicates::DESIGNATION_REL_PREDICATES,
156
+ )
157
+ rel_targets.each do |attr_name, targets|
158
+ instance.send(:"#{attr_name}=", targets) unless targets.empty?
159
+ end
188
160
  instance
189
161
  end
190
162
 
163
+ def designation_instance_for(desig, common_attrs, concept_id, lang, index)
164
+ case desig
165
+ when Designation::Abbreviation
166
+ build_gloss_abbreviation(desig, common_attrs, concept_id, lang, index)
167
+ when Designation::Expression
168
+ build_gloss_expression(desig, common_attrs, concept_id, lang, index)
169
+ when Designation::GraphicalSymbol
170
+ Rdf::GlossGraphicalSymbol.new(common_attrs.merge(text: desig.text,
171
+ image: desig.image))
172
+ when Designation::LetterSymbol
173
+ Rdf::GlossLetterSymbol.new(common_attrs.merge(text: desig.text))
174
+ when Designation::Symbol
175
+ Rdf::GlossSymbol.new(common_attrs)
176
+ else
177
+ Rdf::GlossExpression.new(common_attrs)
178
+ end
179
+ end
180
+
191
181
  def designation_common_attrs(desig, concept_id, lang, index)
192
182
  norm_status = desig.normative_status
193
183
  {
@@ -203,7 +193,8 @@ module Glossarist
203
193
  concept_id: concept_id.to_s,
204
194
  lang_code: (desig.language || lang).to_s,
205
195
  index: index.to_s,
206
- pronunciations: build_gloss_pronunciations(desig.pronunciation, concept_id, lang, index),
196
+ pronunciations: build_gloss_pronunciations(desig.pronunciation,
197
+ concept_id, lang, index),
207
198
  sources: build_gloss_sources(desig.sources),
208
199
  }
209
200
  end
@@ -216,7 +207,9 @@ module Glossarist
216
207
  acronym: desig.acronym,
217
208
  initialism: desig.initialism,
218
209
  truncation: desig.truncation,
219
- grammar_info: build_gloss_grammar_infos(desig.grammar_info, concept_id, lang, index),
210
+ grammar_info: build_gloss_grammar_infos(
211
+ desig.grammar_info, concept_id, lang, index
212
+ ),
220
213
  ))
221
214
  end
222
215
 
@@ -225,7 +218,9 @@ module Glossarist
225
218
  prefix: desig.prefix,
226
219
  usage_info: desig.usage_info,
227
220
  field_of_application: desig.field_of_application,
228
- grammar_info: build_gloss_grammar_infos(desig.grammar_info, concept_id, lang, index),
221
+ grammar_info: build_gloss_grammar_infos(
222
+ desig.grammar_info, concept_id, lang, index
223
+ ),
229
224
  ))
230
225
  end
231
226
 
@@ -271,7 +266,8 @@ module Glossarist
271
266
  )
272
267
  end
273
268
 
274
- def build_gloss_pronunciations(pronunciations, concept_id, lang, _desig_index)
269
+ def build_gloss_pronunciations(pronunciations, concept_id, lang,
270
+ _desig_index)
275
271
  Array(pronunciations).each_with_index.map do |pron, idx|
276
272
  Rdf::GlossPronunciation.new(
277
273
  content: pron.content,
@@ -286,7 +282,8 @@ module Glossarist
286
282
  end
287
283
  end
288
284
 
289
- def build_gloss_grammar_infos(grammar_infos, concept_id, lang, desig_index)
285
+ def build_gloss_grammar_infos(grammar_infos, concept_id, lang,
286
+ desig_index)
290
287
  Array(grammar_infos).map do |gi|
291
288
  Rdf::GlossGrammarInfo.new(
292
289
  gender: Array(gi.gender).map { |g| "gloss:gender/#{g}" },
@@ -335,18 +332,6 @@ module Glossarist
335
332
  end
336
333
  end
337
334
 
338
- def build_relationship_triples(related_concepts)
339
- Array(related_concepts).filter_map do |rc|
340
- predicate_uri = REL_PROPERTY_MAP[rc.type]
341
- next unless predicate_uri
342
-
343
- target_id = rc.ref&.id
344
- next unless target_id
345
-
346
- [predicate_uri, "concept/#{target_id}"]
347
- end
348
- end
349
-
350
335
  def status_uri(status)
351
336
  status ? "gloss:status/#{status}" : nil
352
337
  end
@@ -37,7 +37,8 @@ module Glossarist
37
37
  map :system, to: :system
38
38
  map %i[entry_status entryStatus], to: :entry_status
39
39
  map %i[review_date reviewDate], to: :review_date
40
- map %i[review_decision_date reviewDecisionDate], to: :review_decision_date
40
+ map %i[review_decision_date reviewDecisionDate],
41
+ to: :review_decision_date
41
42
  map %i[review_decision_event reviewDecisionEvent],
42
43
  to: :review_decision_event
43
44
  end
@@ -10,7 +10,7 @@ module Glossarist
10
10
  sequence do
11
11
  map_document 0, to: :concept, type: V2::ManagedConcept
12
12
  map_document 1.., to: :localizations, type: V2::LocalizedConcept,
13
- collection: true
13
+ collection: true
14
14
  end
15
15
  end
16
16
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../context_configuration"
4
-
5
3
  module Glossarist
6
4
  module V2
7
5
  module Configuration
@@ -16,6 +16,7 @@ module Glossarist
16
16
  map %i[localized_concepts localizedConcepts], to: :localized_concepts
17
17
  map %i[domains groups], to: :domains,
18
18
  with: { from: :domains_from_yaml, to: :domains_to_yaml }
19
+ map :tags, to: :tags
19
20
  map :sources, to: :sources
20
21
  map :localizations, to: :localizations,
21
22
  with: { from: :localizations_from_yaml, to: :localizations_to_yaml }