glossarist 2.6.6 → 2.6.7

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +90 -29
  3. data/glossarist.gemspec +2 -0
  4. data/lib/glossarist/citation.rb +26 -123
  5. data/lib/glossarist/cli/compare_command.rb +106 -0
  6. data/lib/glossarist/cli/export_command.rb +11 -14
  7. data/lib/glossarist/cli/validate_command.rb +111 -20
  8. data/lib/glossarist/cli.rb +18 -0
  9. data/lib/glossarist/collections/bibliography_collection.rb +4 -2
  10. data/lib/glossarist/collections/localization_collection.rb +2 -0
  11. data/lib/glossarist/comparison_result.rb +35 -0
  12. data/lib/glossarist/concept_collector.rb +44 -0
  13. data/lib/glossarist/concept_comparator.rb +72 -0
  14. data/lib/glossarist/concept_data.rb +16 -0
  15. data/lib/glossarist/concept_diff.rb +15 -0
  16. data/lib/glossarist/concept_document.rb +11 -0
  17. data/lib/glossarist/concept_manager.rb +19 -5
  18. data/lib/glossarist/concept_ref.rb +13 -0
  19. data/lib/glossarist/concept_validator.rb +6 -1
  20. data/lib/glossarist/context_configuration.rb +90 -0
  21. data/lib/glossarist/dataset_validator.rb +8 -4
  22. data/lib/glossarist/designation/prefix.rb +17 -0
  23. data/lib/glossarist/designation/suffix.rb +17 -0
  24. data/lib/glossarist/gcr_metadata.rb +7 -14
  25. data/lib/glossarist/gcr_package.rb +35 -23
  26. data/lib/glossarist/gcr_validator.rb +38 -17
  27. data/lib/glossarist/localized_concept.rb +8 -0
  28. data/lib/glossarist/managed_concept.rb +39 -6
  29. data/lib/glossarist/managed_concept_data.rb +2 -1
  30. data/lib/glossarist/rdf/ext/jsonld_transform_ext.rb +208 -0
  31. data/lib/glossarist/rdf/ext/mapping_ext.rb +37 -0
  32. data/lib/glossarist/rdf/ext/mapping_rule_ext.rb +27 -0
  33. data/lib/glossarist/rdf/ext/member_rule_ext.rb +34 -0
  34. data/lib/glossarist/rdf/ext/turtle_transform_ext.rb +222 -0
  35. data/lib/glossarist/rdf/ext.rb +39 -0
  36. data/lib/glossarist/rdf/gloss_citation.rb +36 -0
  37. data/lib/glossarist/rdf/gloss_concept.rb +58 -0
  38. data/lib/glossarist/rdf/gloss_concept_date.rb +24 -0
  39. data/lib/glossarist/rdf/gloss_concept_reference.rb +29 -0
  40. data/lib/glossarist/rdf/gloss_concept_source.rb +37 -0
  41. data/lib/glossarist/rdf/gloss_designation.rb +146 -0
  42. data/lib/glossarist/rdf/gloss_detailed_definition.rb +24 -0
  43. data/lib/glossarist/rdf/gloss_grammar_info.rb +57 -0
  44. data/lib/glossarist/rdf/gloss_locality.rb +25 -0
  45. data/lib/glossarist/rdf/gloss_localized_concept.rb +67 -0
  46. data/lib/glossarist/rdf/gloss_non_verbal_rep.rb +31 -0
  47. data/lib/glossarist/rdf/gloss_pronunciation.rb +32 -0
  48. data/lib/glossarist/rdf/gloss_reference.rb +55 -0
  49. data/lib/glossarist/rdf/namespaces/glossarist_namespace.rb +12 -0
  50. data/lib/glossarist/rdf/namespaces/iso_thes_namespace.rb +12 -0
  51. data/lib/glossarist/rdf/namespaces/owl_namespace.rb +12 -0
  52. data/lib/glossarist/rdf/namespaces/prov_namespace.rb +12 -0
  53. data/lib/glossarist/rdf/namespaces/rdf_namespace.rb +12 -0
  54. data/lib/glossarist/rdf/namespaces/skosxl_namespace.rb +12 -0
  55. data/lib/glossarist/rdf/namespaces.rb +8 -2
  56. data/lib/glossarist/rdf/relationships.rb +19 -0
  57. data/lib/glossarist/rdf/v3/configuration.rb +15 -0
  58. data/lib/glossarist/rdf/v3.rb +79 -0
  59. data/lib/glossarist/rdf.rb +22 -2
  60. data/lib/glossarist/reference_extractor.rb +12 -19
  61. data/lib/glossarist/reference_resolver.rb +3 -3
  62. data/lib/glossarist/related_concept.rb +2 -10
  63. data/lib/glossarist/schema_migration.rb +39 -0
  64. data/lib/glossarist/sts/term_mapper.rb +2 -2
  65. data/lib/glossarist/transforms/concept_to_gloss_transform.rb +355 -0
  66. data/lib/glossarist/transforms.rb +2 -2
  67. data/lib/glossarist/v1/concept.rb +17 -17
  68. data/lib/glossarist/v2/citation.rb +36 -0
  69. data/lib/glossarist/v2/concept_data.rb +46 -0
  70. data/lib/glossarist/v2/concept_document.rb +18 -0
  71. data/lib/glossarist/v2/concept_ref.rb +8 -0
  72. data/lib/glossarist/v2/concept_source.rb +16 -0
  73. data/lib/glossarist/v2/configuration.rb +13 -0
  74. data/lib/glossarist/v2/detailed_definition.rb +14 -0
  75. data/lib/glossarist/v2/localized_concept.rb +9 -0
  76. data/lib/glossarist/v2/managed_concept.rb +25 -0
  77. data/lib/glossarist/v2/managed_concept_data.rb +49 -0
  78. data/lib/glossarist/v2/related_concept.rb +15 -0
  79. data/lib/glossarist/v2.rb +28 -0
  80. data/lib/glossarist/v3/bibliography_entry.rb +19 -0
  81. data/lib/glossarist/v3/bibliography_file.rb +27 -0
  82. data/lib/glossarist/v3/citation.rb +30 -0
  83. data/lib/glossarist/v3/concept_data.rb +46 -0
  84. data/lib/glossarist/v3/concept_document.rb +18 -0
  85. data/lib/glossarist/v3/concept_ref.rb +8 -0
  86. data/lib/glossarist/v3/concept_source.rb +16 -0
  87. data/lib/glossarist/v3/configuration.rb +13 -0
  88. data/lib/glossarist/v3/detailed_definition.rb +14 -0
  89. data/lib/glossarist/v3/image_entry.rb +21 -0
  90. data/lib/glossarist/v3/image_file.rb +31 -0
  91. data/lib/glossarist/v3/localized_concept.rb +9 -0
  92. data/lib/glossarist/v3/managed_concept.rb +26 -0
  93. data/lib/glossarist/v3/managed_concept_data.rb +34 -0
  94. data/lib/glossarist/v3/related_concept.rb +15 -0
  95. data/lib/glossarist/v3.rb +36 -0
  96. data/lib/glossarist/validation/bibliography_index.rb +61 -30
  97. data/lib/glossarist/validation/rules/asciidoc_xref_rule.rb +2 -15
  98. data/lib/glossarist/validation/rules/authoritative_source_rule.rb +2 -15
  99. data/lib/glossarist/validation/rules/base.rb +5 -0
  100. data/lib/glossarist/validation/rules/bibliography_yaml_rule.rb +2 -3
  101. data/lib/glossarist/validation/rules/citation_completeness_rule.rb +5 -27
  102. data/lib/glossarist/validation/rules/dataset_context.rb +8 -3
  103. data/lib/glossarist/validation/rules/date_validity_rule.rb +1 -1
  104. data/lib/glossarist/validation/rules/designation_status_rule.rb +0 -1
  105. data/lib/glossarist/validation/rules/designation_type_rule.rb +1 -5
  106. data/lib/glossarist/validation/rules/domain_ref_rule.rb +37 -0
  107. data/lib/glossarist/validation/rules/domain_target_rule.rb +56 -0
  108. data/lib/glossarist/validation/rules/gcr_context.rb +12 -13
  109. data/lib/glossarist/validation/rules/image_reference_rule.rb +2 -17
  110. data/lib/glossarist/validation/rules/locality_completeness_rule.rb +58 -0
  111. data/lib/glossarist/validation/rules/localization_consistency_rule.rb +72 -0
  112. data/lib/glossarist/validation/rules/localization_presence_rule.rb +1 -1
  113. data/lib/glossarist/validation/rules/model_validity_rule.rb +71 -0
  114. data/lib/glossarist/validation/rules/orphaned_bibliography_rule.rb +1 -13
  115. data/lib/glossarist/validation/rules/orphaned_images_rule.rb +16 -11
  116. data/lib/glossarist/validation/rules/ref_shape_rule.rb +68 -0
  117. data/lib/glossarist/validation/rules/related_concept_cycle_rule.rb +1 -3
  118. data/lib/glossarist/validation/rules/related_concept_symmetry_rule.rb +1 -3
  119. data/lib/glossarist/validation/rules/related_concept_target_rule.rb +64 -0
  120. data/lib/glossarist/validation/rules/schema_version_rule.rb +41 -0
  121. data/lib/glossarist/validation/rules/source_type_rule.rb +1 -15
  122. data/lib/glossarist/validation/rules/source_urn_format_rule.rb +65 -0
  123. data/lib/glossarist/validation/rules/uuid_format_rule.rb +33 -0
  124. data/lib/glossarist/validation/rules.rb +10 -43
  125. data/lib/glossarist/validation/validation_issue.rb +14 -11
  126. data/lib/glossarist/validation_result.rb +12 -22
  127. data/lib/glossarist/version.rb +1 -1
  128. data/lib/glossarist.rb +9 -0
  129. data/memory/project-status.md +43 -0
  130. data/scripts/migrate_dataset.rb +180 -0
  131. data/scripts/migrate_isotc204_to_v3.rb +134 -0
  132. data/scripts/migrate_isotc211_to_v3.rb +153 -0
  133. data/scripts/migrate_osgeo_to_v3.rb +155 -0
  134. data/scripts/upgrade_dataset_to_v3.rb +47 -0
  135. metadata +111 -6
  136. data/TODO.integration/01-gcr-package-cli.md +0 -180
  137. data/lib/glossarist/rdf/skos_concept.rb +0 -43
  138. data/lib/glossarist/rdf/skos_vocabulary.rb +0 -25
  139. data/lib/glossarist/transforms/concept_to_skos_transform.rb +0 -131
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extends Lutaml::Rdf::Mapping with support for multiple rdf:type values.
4
+ #
5
+ # Usage in rdf do blocks:
6
+ # type "gloss:Concept" # single type (original API)
7
+ # types "gloss:Concept", "skos:Concept" # multiple types (new API)
8
+ module Lutaml
9
+ module Rdf
10
+ class Mapping
11
+ attr_writer :namespace_set, :rdf_subject, :rdf_type, :rdf_predicates,
12
+ :rdf_members
13
+
14
+ def types(*values)
15
+ @rdf_types = values.flatten.map(&:to_s)
16
+ end
17
+
18
+ def rdf_types
19
+ if defined?(@rdf_types) && @rdf_types
20
+ @rdf_types
21
+ elsif @rdf_type
22
+ [@rdf_type.to_s]
23
+ else
24
+ []
25
+ end
26
+ end
27
+
28
+ def rdf_types=(values)
29
+ @rdf_types = values
30
+ end
31
+
32
+ def has_types_or_predicates?
33
+ rdf_types.any? || rdf_predicates.any?
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extends Lutaml::Rdf::MappingRule with `as:` option for URI-valued predicates.
4
+ #
5
+ # Usage:
6
+ # predicate :hasStatus, namespace: Ns, to: :status, as: :uri
7
+ # predicate :name, namespace: Ns, to: :name # default: :literal
8
+ module Lutaml
9
+ module Rdf
10
+ class MappingRule
11
+ attr_reader :as
12
+
13
+ def initialize(predicate_name, namespace:, to:, lang_tagged: false, as: :literal)
14
+ validate!(predicate_name, namespace, to)
15
+ @predicate_name = predicate_name.to_s.freeze
16
+ @namespace = namespace
17
+ @to = to
18
+ @lang_tagged = lang_tagged
19
+ @as = as
20
+ end
21
+
22
+ def uri_value?
23
+ @as == :uri
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Extends Lutaml::Rdf::MemberRule with `inline:` and `link:` options.
4
+ #
5
+ # Usage:
6
+ # members :localizations, link: "gloss:hasLocalization"
7
+ # members :designations, link: ->(d) { skosxl_predicate_for(d) }
8
+ # members :definitions, link: "gloss:hasDefinition"
9
+ # members :sources # no linking predicate
10
+ module Lutaml
11
+ module Rdf
12
+ class MemberRule
13
+ attr_reader :attr_name, :inline, :link
14
+
15
+ def initialize(attr_name, inline: true, link: nil)
16
+ @attr_name = attr_name.to_sym
17
+ @inline = inline
18
+ @link = link
19
+ end
20
+
21
+ def link_predicate_for(member, mapping)
22
+ return nil unless @link
23
+
24
+ case @link
25
+ when String
26
+ mapping.namespace_set.resolve_compact_iri(@link)
27
+ when Proc
28
+ uri = @link.call(member)
29
+ uri.include?(":") ? mapping.namespace_set.resolve_compact_iri(uri) : uri
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rdf/turtle"
4
+
5
+ # Extends Lutaml::Turtle::Transform to handle:
6
+ # - Multiple rdf:type values (types method)
7
+ # - URI-valued predicates (as: :uri)
8
+ # - Reference-only members (inline: false)
9
+ # - Linking predicates for members (link option)
10
+ # - Recursive prefix collection
11
+ # - Polymorphic member collections
12
+ module Lutaml
13
+ module Turtle
14
+ class Transform < Lutaml::Rdf::Transform
15
+ def model_to_data(instance, _format, options = {})
16
+ mapping = extract_turtle_mapping(options)
17
+ return "" unless mapping
18
+
19
+ if !mapping.rdf_subject && mapping.has_types_or_predicates? && mapping.rdf_members.empty?
20
+ raise MissingSubjectError,
21
+ "Turtle mapping requires a subject block"
22
+ end
23
+
24
+ graph = build_graph(mapping, instance)
25
+ return "" if graph.empty?
26
+
27
+ prefixes = collect_all_prefixes(mapping, instance)
28
+ RDF::Turtle::Writer.buffer(prefixes: prefixes) do |writer|
29
+ graph.each_statement { |stmt| writer << stmt }
30
+ end.strip
31
+ end
32
+
33
+ def data_to_model(data, _format, options = {})
34
+ mapping = extract_turtle_mapping(options)
35
+ unless mapping&.rdf_subject
36
+ raise MissingSubjectError,
37
+ "Turtle mapping requires a subject block"
38
+ end
39
+
40
+ graph = data.is_a?(RDF::Graph) ? data : Lutaml::Turtle::Adapter.parse(data)
41
+ attrs = extract_attributes(graph, mapping)
42
+ build_instance(attrs, options)
43
+ end
44
+
45
+ private
46
+
47
+ def extract_turtle_mapping(options)
48
+ options[:mappings] || mappings_for(:turtle, lutaml_register)
49
+ end
50
+
51
+ def build_graph(mapping, instance)
52
+ graph = RDF::Graph.new
53
+
54
+ if mapping.has_types_or_predicates?
55
+ subject_uri = if mapping.rdf_subject
56
+ RDF::URI(resolve_subject_uri(mapping, instance))
57
+ else
58
+ RDF::Node.new
59
+ end
60
+
61
+ emit_type_statements(graph, subject_uri, mapping)
62
+ emit_predicate_statements(graph, subject_uri, instance, mapping)
63
+ emit_member_link_statements(graph, subject_uri, instance, mapping)
64
+ emit_relationship_statements(graph, subject_uri, instance)
65
+ end
66
+
67
+ emit_child_resources(graph, instance, mapping)
68
+
69
+ graph
70
+ end
71
+
72
+ def emit_type_statements(graph, subject_uri, mapping)
73
+ mapping.rdf_types.each do |type_str|
74
+ type_uri = RDF::URI(mapping.namespace_set.resolve_compact_iri(type_str))
75
+ graph << RDF::Statement.new(subject_uri, RDF.type, type_uri)
76
+ end
77
+ end
78
+
79
+ def emit_predicate_statements(graph, subject_uri, instance, mapping)
80
+ mapping.rdf_predicates.each do |rule|
81
+ value = instance.public_send(rule.to)
82
+ next if value.nil?
83
+
84
+ Array(value).each do |v|
85
+ next if v.is_a?(String) && v.empty?
86
+
87
+ object = build_rdf_object(v, rule, mapping)
88
+ graph << RDF::Statement.new(subject_uri, RDF::URI(rule.uri), object)
89
+ end
90
+ end
91
+ end
92
+
93
+ def emit_member_link_statements(graph, subject_uri, instance, mapping)
94
+ mapping.rdf_members.each do |member_rule|
95
+ next unless member_rule.link
96
+
97
+ collection = Array(instance.public_send(member_rule.attr_name))
98
+ collection.each do |member|
99
+ child_mapping = member.class.mappings[:turtle]
100
+ next unless child_mapping&.rdf_subject
101
+
102
+ child_uri = RDF::URI(resolve_subject_uri(child_mapping, member))
103
+ link_uri = RDF::URI(member_rule.link_predicate_for(member, mapping))
104
+ next unless link_uri
105
+
106
+ graph << RDF::Statement.new(subject_uri, link_uri, child_uri)
107
+ end
108
+ end
109
+ end
110
+
111
+ def emit_relationship_statements(graph, subject_uri, instance)
112
+ return unless instance.is_a?(Glossarist::Rdf::Relationships)
113
+
114
+ Array(instance.relationship_triples).each do |pred_uri, obj_uri|
115
+ graph << RDF::Statement.new(subject_uri, RDF::URI(pred_uri), RDF::URI(obj_uri))
116
+ end
117
+ end
118
+
119
+ def emit_child_resources(graph, instance, mapping)
120
+ mapping.rdf_members.each do |member_rule|
121
+ collection = Array(instance.public_send(member_rule.attr_name))
122
+ collection.each do |member|
123
+ member_mapping = member.class.mappings[:turtle]
124
+ next unless member_mapping
125
+
126
+ graph << build_graph(member_mapping, member)
127
+ end
128
+ end
129
+ end
130
+
131
+ def build_rdf_object(value, rule, mapping = nil)
132
+ if rule.uri_value?
133
+ resolved = if mapping && value.include?(":")
134
+ mapping.namespace_set.resolve_compact_iri(value)
135
+ else
136
+ value
137
+ end
138
+ RDF::URI(resolved)
139
+ elsif rule.lang_tagged
140
+ lang = extract_language(value)
141
+ RDF::Literal.new(value.to_s, language: lang)
142
+ else
143
+ case value
144
+ when Integer then RDF::Literal.new(value, datatype: RDF::XSD.integer)
145
+ when Float then RDF::Literal.new(value, datatype: RDF::XSD.double)
146
+ when TrueClass, FalseClass then RDF::Literal.new(value, datatype: RDF::XSD.boolean)
147
+ else RDF::Literal.new(value.to_s)
148
+ end
149
+ end
150
+ end
151
+
152
+ def collect_all_prefixes(mapping, instance)
153
+ ns_set = collect_namespaces_recursive(mapping, instance)
154
+ ns_set.each.with_object({}) do |ns, h|
155
+ h[ns.prefix.to_sym] = ns.uri if ns.prefix && ns.uri
156
+ end
157
+ end
158
+
159
+ def collect_namespaces_recursive(mapping, instance)
160
+ ns_set = mapping.namespace_set
161
+
162
+ mapping.rdf_members.each do |member_rule|
163
+ collection = Array(instance.public_send(member_rule.attr_name))
164
+ next if collection.empty?
165
+
166
+ collection.map(&:class).uniq.each do |klass|
167
+ member_mapping = klass.mappings[:turtle]
168
+ next unless member_mapping
169
+
170
+ ns_set = ns_set.merge(member_mapping.namespace_set)
171
+ # Recurse into child members
172
+ child_ns = collect_namespaces_recursive(member_mapping, collection.first)
173
+ ns_set = ns_set.merge(child_ns)
174
+ end
175
+ end
176
+
177
+ ns_set
178
+ end
179
+
180
+ def extract_attributes(graph, mapping)
181
+ attrs = {}
182
+ first_type_uri = mapping.rdf_types.first
183
+ return attrs unless first_type_uri
184
+
185
+ type_uri = RDF::URI(mapping.namespace_set.resolve_compact_iri(first_type_uri))
186
+ matching_subjects = find_subjects_by_type(graph, type_uri)
187
+
188
+ matching_subjects.each do |subject|
189
+ mapping.rdf_predicates.each do |rule|
190
+ stmts = graph.query([subject, RDF::URI(rule.uri), nil])
191
+ next if stmts.empty?
192
+
193
+ values = stmts.map do |s|
194
+ rule.uri_value? ? s.object.to_s : literal_to_ruby(s.object)
195
+ end
196
+ attrs[rule.to] = values.length == 1 ? values.first : values
197
+ end
198
+ end
199
+
200
+ attrs
201
+ end
202
+
203
+ def find_subjects_by_type(graph, type_uri)
204
+ graph.query([nil, RDF.type, RDF::URI(type_uri)]).map(&:subject).uniq
205
+ end
206
+
207
+ def literal_to_ruby(rdf_object)
208
+ case rdf_object
209
+ when RDF::Literal
210
+ case rdf_object.datatype
211
+ when RDF::XSD.integer then rdf_object.value.to_i
212
+ when RDF::XSD.double, RDF::XSD.decimal, RDF::XSD.float then rdf_object.value.to_f
213
+ when RDF::XSD.boolean then rdf_object.value == "true"
214
+ else rdf_object.value
215
+ end
216
+ else
217
+ rdf_object.to_s
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/turtle"
4
+ require "lutaml/jsonld"
5
+
6
+ require_relative "ext/mapping_ext"
7
+ require_relative "ext/mapping_rule_ext"
8
+ require_relative "ext/member_rule_ext"
9
+ require_relative "ext/turtle_transform_ext"
10
+ require_relative "ext/jsonld_transform_ext"
11
+
12
+ # Update Lutaml::Rdf::Mapping#predicate to pass through `as` option.
13
+ # Update Lutaml::Rdf::Mapping#members to pass through `inline` and `link` options.
14
+ Lutaml::Rdf::Mapping.class_eval do
15
+ def predicate(name, namespace:, to:, lang_tagged: false, as: :literal)
16
+ @rdf_predicates << Lutaml::Rdf::MappingRule.new(
17
+ name,
18
+ namespace: namespace,
19
+ to: to,
20
+ lang_tagged: lang_tagged,
21
+ as: as,
22
+ )
23
+ end
24
+
25
+ def members(attr_name, inline: true, link: nil)
26
+ @rdf_members << Lutaml::Rdf::MemberRule.new(attr_name, inline: inline, link: link)
27
+ end
28
+
29
+ def deep_dup
30
+ self.class.new.tap do |new_mapping|
31
+ new_mapping.namespace_set = @namespace_set
32
+ new_mapping.rdf_subject = @rdf_subject
33
+ new_mapping.rdf_type = @rdf_type
34
+ new_mapping.rdf_types = @rdf_types&.dup
35
+ new_mapping.rdf_predicates = @rdf_predicates.dup
36
+ new_mapping.rdf_members = @rdf_members.dup
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Glossarist
6
+ module Rdf
7
+ class GlossCitation < Lutaml::Model::Serializable
8
+ attribute :source, :string
9
+ attribute :id, :string
10
+ attribute :version, :string
11
+ attribute :link, :string
12
+ attribute :locality, GlossLocality
13
+
14
+ rdf do
15
+ namespace Namespaces::GlossaristNamespace
16
+
17
+ subject { |c| "citation/#{GlossCitation.slug(c)}" }
18
+
19
+ types "gloss:Citation"
20
+
21
+ predicate :citationSource, namespace: Namespaces::GlossaristNamespace, to: :source
22
+ predicate :citationId, namespace: Namespaces::GlossaristNamespace, to: :id
23
+ predicate :citationVersion, namespace: Namespaces::GlossaristNamespace, to: :version
24
+ predicate :citationLink, namespace: Namespaces::GlossaristNamespace, to: :link
25
+
26
+ members :locality, link: "gloss:hasLocality"
27
+ end
28
+
29
+ def self.slug(citation)
30
+ slug = [citation.source, citation.id].compact.join("/")
31
+ slug = Digest::MD5.hexdigest(citation.source || "")[0..11] if slug.empty?
32
+ slug
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Glossarist
6
+ module Rdf
7
+ class GlossConcept < Lutaml::Model::Serializable
8
+ include Relationships
9
+
10
+ attribute :identifier, :string
11
+ attribute :status, :string
12
+ attribute :localizations, GlossLocalizedConcept, collection: true
13
+ attribute :sources, GlossConceptSource, collection: true
14
+ attribute :domains, GlossConceptReference, collection: true
15
+ attribute :dates, GlossConceptDate, collection: true
16
+
17
+ rdf do
18
+ namespace Namespaces::GlossaristNamespace,
19
+ Namespaces::SkosNamespace,
20
+ Namespaces::DctermsNamespace,
21
+ Namespaces::SkosxlNamespace,
22
+ Namespaces::IsoThesNamespace,
23
+ Namespaces::RdfNamespace
24
+
25
+ subject { |c| "concept/#{c.identifier}" }
26
+
27
+ types "gloss:Concept", "skos:Concept"
28
+
29
+ predicate :identifier, namespace: Namespaces::GlossaristNamespace, to: :identifier
30
+ predicate :hasStatus, namespace: Namespaces::GlossaristNamespace, to: :status, as: :uri
31
+
32
+ members :localizations,
33
+ link: "gloss:hasLocalization"
34
+ members :sources,
35
+ link: "gloss:hasSource"
36
+ members :domains,
37
+ link: "gloss:hasDomain"
38
+ members :dates,
39
+ link: "gloss:hasDate"
40
+ end
41
+ end
42
+
43
+ class GlossDocument < Lutaml::Model::Serializable
44
+ attribute :concepts, GlossConcept, collection: true
45
+
46
+ rdf do
47
+ namespace Namespaces::GlossaristNamespace,
48
+ Namespaces::SkosNamespace,
49
+ Namespaces::DctermsNamespace,
50
+ Namespaces::SkosxlNamespace,
51
+ Namespaces::IsoThesNamespace,
52
+ Namespaces::RdfNamespace
53
+
54
+ members :concepts
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Glossarist
6
+ module Rdf
7
+ class GlossConceptDate < Lutaml::Model::Serializable
8
+ attribute :date_value, :string
9
+ attribute :date_type, :string
10
+ attribute :concept_id, :string
11
+
12
+ rdf do
13
+ namespace Namespaces::GlossaristNamespace
14
+
15
+ subject { |d| "concept/#{d.concept_id}/date/#{d.date_type}" }
16
+
17
+ types "gloss:ConceptDate"
18
+
19
+ predicate :dateValue, namespace: Namespaces::GlossaristNamespace, to: :date_value
20
+ predicate :dateType, namespace: Namespaces::GlossaristNamespace, to: :date_type, as: :uri
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Glossarist
6
+ module Rdf
7
+ class GlossConceptReference < Lutaml::Model::Serializable
8
+ attribute :term, :string
9
+ attribute :concept_id, :string
10
+ attribute :source, :string
11
+ attribute :ref_type, :string
12
+ attribute :urn, :string
13
+ attribute :parent_id, :string
14
+
15
+ rdf do
16
+ namespace Namespaces::GlossaristNamespace
17
+
18
+ subject { |r| "concept/#{r.parent_id}/ref/#{r.concept_id || r.urn}" }
19
+
20
+ types "gloss:ConceptReference"
21
+
22
+ predicate :refType, namespace: Namespaces::GlossaristNamespace, to: :ref_type
23
+ predicate :conceptId, namespace: Namespaces::GlossaristNamespace, to: :concept_id
24
+ predicate :sourceUri, namespace: Namespaces::GlossaristNamespace, to: :source
25
+ predicate :urn, namespace: Namespaces::GlossaristNamespace, to: :urn
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Glossarist
6
+ module Rdf
7
+ class GlossConceptSource < Lutaml::Model::Serializable
8
+ attribute :status, :string
9
+ attribute :type, :string
10
+ attribute :modification, :string
11
+ attribute :origin, GlossCitation
12
+
13
+ rdf do
14
+ namespace Namespaces::GlossaristNamespace
15
+
16
+ subject { |s| "source/#{GlossConceptSource.deterministic_id(s)}" }
17
+
18
+ types "gloss:ConceptSource"
19
+
20
+ predicate :sourceStatus, namespace: Namespaces::GlossaristNamespace, to: :status, as: :uri
21
+ predicate :sourceType, namespace: Namespaces::GlossaristNamespace, to: :type, as: :uri
22
+ predicate :modification, namespace: Namespaces::GlossaristNamespace, to: :modification
23
+
24
+ members :origin, link: "gloss:sourceOrigin"
25
+ end
26
+
27
+ def self.deterministic_id(source)
28
+ parts = [source.status, source.type, source.modification]
29
+ origin = source.origin
30
+ if origin
31
+ parts << origin.source << origin.id << origin.version << origin.link
32
+ end
33
+ Digest::MD5.hexdigest(parts.compact.join("|"))[0..11]
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/model"
4
+
5
+ module Glossarist
6
+ module Rdf
7
+ COMMON_DESIGNATION_PREDICATES = lambda { |dsl|
8
+ dsl.predicate :literalForm, namespace: Namespaces::SkosxlNamespace, to: :designation
9
+ dsl.predicate :normativeStatus, namespace: Namespaces::GlossaristNamespace, to: :normative_status, as: :uri
10
+ dsl.predicate :hasTermType, namespace: Namespaces::GlossaristNamespace, to: :term_type, as: :uri
11
+ dsl.predicate :isInternational, namespace: Namespaces::GlossaristNamespace, to: :international
12
+ dsl.predicate :isAbsent, namespace: Namespaces::GlossaristNamespace, to: :absent
13
+ dsl.predicate :geographicalArea, namespace: Namespaces::GlossaristNamespace, to: :language
14
+ dsl.predicate :language, namespace: Namespaces::DctermsNamespace, to: :lang_code
15
+ dsl.predicate :script, namespace: Namespaces::GlossaristNamespace, to: :script
16
+ dsl.predicate :conversionSystem, namespace: Namespaces::GlossaristNamespace, to: :system
17
+ dsl.members :pronunciations, link: "gloss:hasPronunciation"
18
+ dsl.members :sources
19
+ }.freeze
20
+
21
+ DESIGNATION_NAMESPACES = [
22
+ Namespaces::GlossaristNamespace,
23
+ Namespaces::SkosxlNamespace,
24
+ Namespaces::SkosNamespace,
25
+ Namespaces::DctermsNamespace,
26
+ Namespaces::IsoThesNamespace,
27
+ ].freeze
28
+
29
+ class GlossDesignation < Lutaml::Model::Serializable
30
+ include Relationships
31
+
32
+ attribute :designation, :string
33
+ attribute :normative_status, :string
34
+ attribute :type, :string
35
+ attribute :language, :string
36
+ attribute :script, :string
37
+ attribute :system, :string
38
+ attribute :international, :boolean
39
+ attribute :absent, :boolean
40
+ attribute :term_type, :string
41
+ attribute :concept_id, :string
42
+ attribute :lang_code, :string
43
+ attribute :index, :string
44
+ attribute :pronunciations, GlossPronunciation, collection: true
45
+ attribute :sources, GlossConceptSource, collection: true
46
+
47
+ rdf do
48
+ namespace(*DESIGNATION_NAMESPACES)
49
+
50
+ subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
51
+
52
+ types "gloss:Designation", "skosxl:Label"
53
+
54
+ COMMON_DESIGNATION_PREDICATES.call(self)
55
+ end
56
+ end
57
+
58
+ class GlossExpression < GlossDesignation
59
+ attribute :prefix, :string
60
+ attribute :usage_info, :string
61
+ attribute :field_of_application, :string
62
+ attribute :grammar_info, GlossGrammarInfo, collection: true
63
+
64
+ rdf do
65
+ namespace(*DESIGNATION_NAMESPACES)
66
+
67
+ subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
68
+
69
+ types "gloss:Expression", "skosxl:Label"
70
+
71
+ COMMON_DESIGNATION_PREDICATES.call(self)
72
+ predicate :prefix, namespace: Namespaces::GlossaristNamespace, to: :prefix
73
+ predicate :usageInfo, namespace: Namespaces::GlossaristNamespace, to: :usage_info
74
+ predicate :fieldOfApplication, namespace: Namespaces::GlossaristNamespace, to: :field_of_application
75
+ members :grammar_info, link: "gloss:hasGrammarInfo"
76
+ end
77
+ end
78
+
79
+ class GlossAbbreviation < GlossExpression
80
+ attribute :acronym, :boolean
81
+ attribute :initialism, :boolean
82
+ attribute :truncation, :boolean
83
+
84
+ rdf do
85
+ namespace(*DESIGNATION_NAMESPACES)
86
+
87
+ subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
88
+
89
+ types "gloss:Abbreviation", "skosxl:Label"
90
+
91
+ COMMON_DESIGNATION_PREDICATES.call(self)
92
+ predicate :prefix, namespace: Namespaces::GlossaristNamespace, to: :prefix
93
+ predicate :usageInfo, namespace: Namespaces::GlossaristNamespace, to: :usage_info
94
+ predicate :fieldOfApplication, namespace: Namespaces::GlossaristNamespace, to: :field_of_application
95
+ members :grammar_info, link: "gloss:hasGrammarInfo"
96
+ predicate :isAcronym, namespace: Namespaces::GlossaristNamespace, to: :acronym
97
+ predicate :isInitialism, namespace: Namespaces::GlossaristNamespace, to: :initialism
98
+ predicate :isTruncation, namespace: Namespaces::GlossaristNamespace, to: :truncation
99
+ end
100
+ end
101
+
102
+ class GlossSymbol < GlossDesignation
103
+ rdf do
104
+ namespace(*DESIGNATION_NAMESPACES)
105
+
106
+ subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
107
+
108
+ types "gloss:Symbol", "skosxl:Label"
109
+
110
+ COMMON_DESIGNATION_PREDICATES.call(self)
111
+ end
112
+ end
113
+
114
+ class GlossLetterSymbol < GlossSymbol
115
+ attribute :text, :string
116
+
117
+ rdf do
118
+ namespace(*DESIGNATION_NAMESPACES)
119
+
120
+ subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
121
+
122
+ types "gloss:LetterSymbol", "skosxl:Label"
123
+
124
+ COMMON_DESIGNATION_PREDICATES.call(self)
125
+ predicate :text, namespace: Namespaces::GlossaristNamespace, to: :text
126
+ end
127
+ end
128
+
129
+ class GlossGraphicalSymbol < GlossSymbol
130
+ attribute :text, :string
131
+ attribute :image, :string
132
+
133
+ rdf do
134
+ namespace(*DESIGNATION_NAMESPACES)
135
+
136
+ subject { |d| "concept/#{d.concept_id}/#{d.lang_code}/designation/#{d.index}" }
137
+
138
+ types "gloss:GraphicalSymbol", "skosxl:Label"
139
+
140
+ COMMON_DESIGNATION_PREDICATES.call(self)
141
+ predicate :text, namespace: Namespaces::GlossaristNamespace, to: :text
142
+ predicate :image, namespace: Namespaces::GlossaristNamespace, to: :image
143
+ end
144
+ end
145
+ end
146
+ end