glossarist 2.6.1 → 2.6.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b4e48f1d237829b78cd052e39afdd7c952c468be894e25856f79f93471ea2dc6
4
- data.tar.gz: f6502f7012e30138193c4c28eee2ab551020edf27ff0c6e08cc39939e5d0c0c3
3
+ metadata.gz: a4a05468d25c9ac0d13c748454dc98d7dc031718fe98d298c3db89d6874963a7
4
+ data.tar.gz: 203b26205a85b9593942d7d6095dab85faa93ed1e99b9f474f20c67a77e61c5d
5
5
  SHA512:
6
- metadata.gz: bcfb39fe52138d23d489cfbff45f62b0f00161d3183ef66dbb5718fcbc30694ef5e426bc9f7797329480dddb01a7c96b8f6e1dfc43e392032441bb62487c723a
7
- data.tar.gz: 289911c5a5851389cb5e37fbc07bd45825b00cdd51fa8cac5679168af3ec9e2b7313f6afbd7093fb93b35384bfc7318dcb97a22d72869f78a321883f4ab299a4
6
+ metadata.gz: dc177b1d927f7b309cb47fac5158c151001202ba0332b35f0eaf87a8e1e2d9eda400dd077145b10d4acc5ee968676f39dd95172a32ad16e6078ff3357c299317
7
+ data.tar.gz: eb60cfa90dd26008e2287cbafb35aaeb4e48bb60c120cc254fba024d945f4a6cdb41e9b51a2b8c68a30ac6e31e7e40f38243ec44437a5995126eba47f47110dd
data/.rubocop_todo.yml CHANGED
@@ -1,18 +1,11 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-05-06 18:35:41 UTC using RuboCop version 1.86.1.
3
+ # on 2026-05-07 13:57:54 UTC using RuboCop version 1.86.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 5
10
- # This cop supports safe autocorrection (--autocorrect).
11
- # Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation.
12
- Bundler/OrderedGems:
13
- Exclude:
14
- - 'Gemfile'
15
-
16
9
  # Offense count: 1
17
10
  Gemspec/RequiredRubyVersion:
18
11
  Exclude:
@@ -20,25 +13,48 @@ Gemspec/RequiredRubyVersion:
20
13
 
21
14
  # Offense count: 1
22
15
  # This cop supports safe autocorrection (--autocorrect).
23
- Layout/ClosingParenthesisIndentation:
16
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
17
+ # SupportedStyles: with_first_argument, with_fixed_indentation
18
+ Layout/ArgumentAlignment:
24
19
  Exclude:
25
- - 'spec/unit/concept_set_spec.rb'
20
+ - 'spec/unit/gcr_package_spec.rb'
26
21
 
27
- # Offense count: 1
22
+ # Offense count: 2
28
23
  # This cop supports safe autocorrection (--autocorrect).
29
- # Configuration parameters: EnforcedStyle, IndentationWidth.
30
- # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
31
- Layout/FirstArgumentIndentation:
24
+ # Configuration parameters: EnforcedStyleAlignWith.
25
+ # SupportedStylesAlignWith: either, start_of_block, start_of_line
26
+ Layout/BlockAlignment:
27
+ Exclude:
28
+ - 'lib/glossarist/gcr_validator.rb'
29
+
30
+ # Offense count: 2
31
+ # This cop supports safe autocorrection (--autocorrect).
32
+ Layout/BlockEndNewline:
33
+ Exclude:
34
+ - 'lib/glossarist/gcr_validator.rb'
35
+
36
+ # Offense count: 4
37
+ # This cop supports safe autocorrection (--autocorrect).
38
+ # Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
39
+ # SupportedStylesAlignWith: start_of_line, relative_to_receiver
40
+ Layout/IndentationWidth:
32
41
  Exclude:
33
- - 'spec/unit/concept_set_spec.rb'
42
+ - 'lib/glossarist/gcr_validator.rb'
34
43
 
35
- # Offense count: 202
44
+ # Offense count: 214
36
45
  # This cop supports safe autocorrection (--autocorrect).
37
46
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
38
47
  # URISchemes: http, https
39
48
  Layout/LineLength:
40
49
  Enabled: false
41
50
 
51
+ # Offense count: 1
52
+ # This cop supports safe autocorrection (--autocorrect).
53
+ # Configuration parameters: AllowInHeredoc.
54
+ Layout/TrailingWhitespace:
55
+ Exclude:
56
+ - 'spec/unit/gcr_package_spec.rb'
57
+
42
58
  # Offense count: 1
43
59
  # Configuration parameters: AllowedMethods.
44
60
  # AllowedMethods: enums
@@ -54,7 +70,7 @@ Lint/UnusedMethodArgument:
54
70
  Exclude:
55
71
  - 'lib/glossarist/dataset_validator.rb'
56
72
 
57
- # Offense count: 23
73
+ # Offense count: 24
58
74
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
59
75
  Metrics/AbcSize:
60
76
  Exclude:
@@ -73,12 +89,6 @@ Metrics/AbcSize:
73
89
  - 'lib/glossarist/utilities/uuid.rb'
74
90
  - 'spec/unit/concept_collector_spec.rb'
75
91
 
76
- # Offense count: 1
77
- # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
78
- # AllowedMethods: refine
79
- Metrics/BlockLength:
80
- Max: 28
81
-
82
92
  # Offense count: 19
83
93
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
84
94
  Metrics/CyclomaticComplexity:
@@ -101,7 +111,7 @@ Metrics/CyclomaticComplexity:
101
111
  Metrics/MethodLength:
102
112
  Max: 42
103
113
 
104
- # Offense count: 4
114
+ # Offense count: 3
105
115
  # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
106
116
  Metrics/ParameterLists:
107
117
  Max: 6
@@ -135,6 +145,17 @@ Naming/VariableNumber:
135
145
  Exclude:
136
146
  - 'spec/unit/rdf/skos_vocabulary_spec.rb'
137
147
 
148
+ # Offense count: 3
149
+ # This cop supports safe autocorrection (--autocorrect).
150
+ # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
151
+ # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
152
+ # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
153
+ # FunctionalMethods: let, let!, subject, watch
154
+ # AllowedMethods: lambda, proc, it
155
+ Style/BlockDelimiters:
156
+ Exclude:
157
+ - 'lib/glossarist/gcr_validator.rb'
158
+
138
159
  # Offense count: 6
139
160
  # This cop supports safe autocorrection (--autocorrect).
140
161
  # Configuration parameters: MaxUnannotatedPlaceholdersAllowed, Mode, AllowedMethods, AllowedPatterns.
@@ -41,13 +41,35 @@ module Glossarist
41
41
  def v1_concepts?(dir)
42
42
  concepts_dir = File.join(dir, "concepts")
43
43
  File.directory?(concepts_dir) &&
44
+ !v2_flat_concepts?(dir) &&
45
+ !managed_concepts?(dir) &&
44
46
  Dir.glob(File.join(concepts_dir, "*.yaml")).any? do |f|
45
47
  V1::Concept.from_file(f)&.termid?
46
48
  end
47
49
  end
48
50
 
49
51
  def v2_concepts?(dir)
50
- File.directory?(File.join(dir, "geolexica-v2"))
52
+ File.directory?(File.join(dir, "geolexica-v2")) ||
53
+ v2_flat_concepts?(dir)
54
+ end
55
+
56
+ def v2_flat_concepts?(dir)
57
+ return false if managed_concepts?(dir)
58
+
59
+ concepts_dir = File.join(dir, "concepts")
60
+ return false unless File.directory?(concepts_dir)
61
+
62
+ Dir.glob(File.join(concepts_dir, "*.yaml")).first(5).any? do |f|
63
+ v2_flat_concept_file?(f)
64
+ end
65
+ end
66
+
67
+ def v2_flat_concept_file?(path)
68
+ raw = File.read(path, encoding: "utf-8")
69
+ doc = ConceptDocument.from_yamls(raw)
70
+ !!doc.concept&.data&.id
71
+ rescue StandardError
72
+ false
51
73
  end
52
74
 
53
75
  def managed_concepts?(dir)
@@ -74,24 +96,32 @@ module Glossarist
74
96
  end
75
97
 
76
98
  def collect_v2_concepts(dir)
77
- v2_dir = File.join(dir, "geolexica-v2")
78
- if File.directory?(File.join(v2_dir, "concepts"))
79
- collect_managed_concepts(v2_dir)
99
+ if v2_flat_concepts?(dir)
100
+ collect_grouped_v2_concepts(File.join(dir, "concepts"))
80
101
  else
81
- collect_grouped_v2_concepts(v2_dir)
102
+ v2_dir = File.join(dir, "geolexica-v2")
103
+ if File.directory?(File.join(v2_dir, "concepts"))
104
+ collect_managed_concepts(v2_dir)
105
+ else
106
+ collect_grouped_v2_concepts(v2_dir)
107
+ end
82
108
  end
83
109
  end
84
110
 
85
111
  def each_v2_concept(dir, &block)
86
- v2_dir = File.join(dir, "geolexica-v2")
87
- if File.directory?(File.join(v2_dir, "concepts"))
88
- each_managed_concept(v2_dir, &block)
112
+ if v2_flat_concepts?(dir)
113
+ each_grouped_v2_concepts(File.join(dir, "concepts"), &block)
89
114
  else
90
- each_grouped_v2_concept(v2_dir, &block)
115
+ v2_dir = File.join(dir, "geolexica-v2")
116
+ if File.directory?(File.join(v2_dir, "concepts"))
117
+ each_managed_concept(v2_dir, &block)
118
+ else
119
+ each_grouped_v2_concepts(v2_dir, &block)
120
+ end
91
121
  end
92
122
  end
93
123
 
94
- def each_grouped_v2_concept(v2_dir, &block)
124
+ def each_grouped_v2_concepts(v2_dir, &block)
95
125
  collection = ManagedConceptCollection.new
96
126
  manager = ConceptManager.new(path: v2_dir)
97
127
  manager.load_from_files(collection: collection)
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "zip"
4
4
  require "fileutils"
5
+ require "pathname"
5
6
 
6
7
  module Glossarist
7
8
  class GcrPackage
@@ -14,12 +15,18 @@ module Glossarist
14
15
 
15
16
  KNOWN_COMPILED_FORMATS = COMPILED_EXTENSIONS.keys.freeze
16
17
 
17
- attr_reader :zip_path, :metadata, :concepts
18
+ DATASET_ASSETS = [
19
+ { path: "bibliography.yaml", type: :file, attr: :bibliography },
20
+ { path: "images", type: :directory },
21
+ ].freeze
22
+
23
+ attr_reader :zip_path, :metadata, :concepts, :bibliography
18
24
 
19
25
  def initialize(zip_path)
20
26
  @zip_path = zip_path
21
27
  @metadata = nil
22
28
  @concepts = []
29
+ @bibliography = nil
23
30
  end
24
31
 
25
32
  def self.create(concepts:, metadata:, output_path:, register_data: nil,
@@ -66,12 +73,43 @@ module Glossarist
66
73
  end
67
74
  end
68
75
 
76
+ def self.each_dataset_asset(source_dir)
77
+ base = Pathname.new(source_dir)
78
+ DATASET_ASSETS.each do |asset|
79
+ path = File.join(source_dir, asset[:path])
80
+ case asset[:type]
81
+ when :file
82
+ yield_file_asset(path, asset[:path]) { |*a| yield(*a) }
83
+ when :directory
84
+ yield_directory_assets(path, base) { |*a| yield(*a) }
85
+ end
86
+ end
87
+ end
88
+
89
+ def self.yield_file_asset(path, entry_name)
90
+ return unless File.exist?(path)
91
+
92
+ yield entry_name, File.binread(path)
93
+ end
94
+
95
+ def self.yield_directory_assets(dir_path, base_path)
96
+ return unless File.directory?(dir_path)
97
+
98
+ Dir.glob(File.join(dir_path, "**", "*")).each do |file|
99
+ next unless File.file?(file)
100
+
101
+ relative = Pathname.new(file).relative_path_from(base_path).to_s
102
+ yield relative, File.binread(file)
103
+ end
104
+ end
105
+
69
106
  def validate
70
107
  GcrValidator.new.validate(@zip_path)
71
108
  end
72
109
 
73
- def write(concepts, metadata, register_data, compiled_formats: [],
74
- shortname: nil, **opts)
110
+ def write(concepts, metadata, register_data, # rubocop:disable Metrics/ParameterLists
111
+ compiled_formats: [],
112
+ shortname: nil, source_dir: nil, **opts)
75
113
  Zip::File.open(@zip_path, create: true) do |zf|
76
114
  zf.get_output_stream("metadata.yaml") do |f|
77
115
  f.write(metadata.to_yaml)
@@ -87,6 +125,12 @@ module Glossarist
87
125
  write_concept(zf, mc)
88
126
  end
89
127
 
128
+ if source_dir
129
+ self.class.each_dataset_asset(source_dir) do |name, content|
130
+ zf.get_output_stream(name) { |f| f.write(content) }
131
+ end
132
+ end
133
+
90
134
  if compiled_formats.any?
91
135
  write_compiled(zf, concepts, compiled_formats, shortname: shortname,
92
136
  **opts)
@@ -94,29 +138,51 @@ module Glossarist
94
138
  end
95
139
  end
96
140
 
97
- def write_concept(zip_file, concept)
98
- termid = concept.data.id.to_s
99
- doc = ConceptDocument.from_managed_concept(concept)
100
- zip_file.get_output_stream("concepts/#{termid}.yaml") do |f|
101
- f.write(doc.to_yamls)
102
- end
103
- end
104
-
105
141
  def read
106
142
  @concepts = []
107
143
 
108
144
  Zip::File.open(@zip_path) do |zf|
109
- if (entry = zf.find_entry("metadata.yaml"))
110
- @metadata = GcrMetadata.from_yaml(entry.get_input_stream.read)
111
- end
145
+ read_metadata(zf)
146
+ read_file_assets(zf)
147
+ read_concepts(zf)
148
+ end
149
+ end
112
150
 
113
- zf.entries.each do |entry|
114
- next unless entry.name.start_with?("concepts/") && entry.name.end_with?(".yaml")
151
+ def read_metadata(zip_file)
152
+ entry = zip_file.find_entry("metadata.yaml")
153
+ return unless entry
115
154
 
116
- raw = entry.get_input_stream.read
117
- doc = ConceptDocument.from_yamls(raw)
118
- @concepts << doc.to_managed_concept
119
- end
155
+ @metadata = GcrMetadata.from_yaml(entry.get_input_stream.read)
156
+ end
157
+
158
+ def read_file_assets(zip_file)
159
+ DATASET_ASSETS.each do |asset|
160
+ next unless asset[:type] == :file && asset[:attr]
161
+
162
+ entry = zip_file.find_entry(asset[:path])
163
+ next unless entry
164
+
165
+ instance_variable_set("@#{asset[:attr]}", entry.get_input_stream.read)
166
+ end
167
+ end
168
+
169
+ def read_concepts(zip_file)
170
+ zip_file.entries.each do |entry|
171
+ next unless entry.name.start_with?("concepts/") && entry.name.end_with?(".yaml")
172
+
173
+ raw = entry.get_input_stream.read
174
+ doc = ConceptDocument.from_yamls(raw)
175
+ @concepts << doc.to_managed_concept
176
+ end
177
+ end
178
+
179
+ private
180
+
181
+ def write_concept(zip_file, concept)
182
+ termid = concept.data.id.to_s
183
+ doc = ConceptDocument.from_managed_concept(concept)
184
+ zip_file.get_output_stream("concepts/#{termid}.yaml") do |f|
185
+ f.write(doc.to_yamls)
120
186
  end
121
187
  end
122
188
 
@@ -206,6 +272,7 @@ compiled_formats: [], **opts)
206
272
  output_path: File.expand_path(output),
207
273
  compiled_formats: compiled_formats,
208
274
  shortname: shortname,
275
+ source_dir: dir,
209
276
  **opts,
210
277
  )
211
278
  end
@@ -219,7 +286,7 @@ compiled_formats: [], **opts)
219
286
  concept_count = 0
220
287
  languages = Set.new
221
288
 
222
- Zip::OutputStream.open(output_path) do |zos|
289
+ Zip::OutputStream.open(output_path) do |zos| # rubocop:disable Metrics/BlockLength
223
290
  if register_data
224
291
  zos.put_next_entry("register.yaml")
225
292
  zos.write(register_data.to_yaml)
@@ -253,6 +320,11 @@ compiled_formats: [], **opts)
253
320
  register_data: register_data, **opts)
254
321
  zos.put_next_entry("metadata.yaml")
255
322
  zos.write(metadata.to_yaml)
323
+
324
+ each_dataset_asset(dir) do |name, content|
325
+ zos.put_next_entry(name)
326
+ zos.write(content)
327
+ end
256
328
  end
257
329
 
258
330
  new(output_path)
@@ -13,27 +13,8 @@ module Glossarist
13
13
  end
14
14
 
15
15
  begin
16
- Zip::File.open(zip_path) do |zf|
17
- unless zf.find_entry("metadata.yaml")
18
- result.add_error("Missing metadata.yaml")
19
- return result
20
- end
21
-
22
- metadata = GcrMetadata.from_yaml(
23
- zf.find_entry("metadata.yaml").get_input_stream.read,
24
- )
25
- validate_metadata(metadata, result)
26
-
27
- concept_entries = zf.entries.select do |e|
28
- e.name.start_with?("concepts/") && e.name.end_with?(".yaml")
29
- end
30
- if concept_entries.empty?
31
- result.add_error("No concept files found in concepts/")
32
- end
33
-
34
- concept_entries.each do |entry|
35
- validate_concept_entry(entry, metadata, result)
36
- end
16
+ Zip::File.open(zip_path) do |zip_file|
17
+ validate_zip_contents(zip_file, result)
37
18
  end
38
19
  rescue StandardError => e
39
20
  result.add_error("Failed to read ZIP: #{e.message}")
@@ -44,6 +25,31 @@ module Glossarist
44
25
 
45
26
  private
46
27
 
28
+ def validate_zip_contents(zip_file, result) # rubocop:disable Metrics/AbcSize
29
+ unless zip_file.find_entry("metadata.yaml")
30
+ result.add_error("Missing metadata.yaml")
31
+ return
32
+ end
33
+
34
+ metadata = GcrMetadata.from_yaml(
35
+ zip_file.find_entry("metadata.yaml").get_input_stream.read,
36
+ )
37
+ validate_metadata(metadata, result)
38
+
39
+ concept_entries = zip_file.entries.select do |e|
40
+ e.name.start_with?("concepts/") && e.name.end_with?(".yaml")
41
+ end
42
+ if concept_entries.empty?
43
+ result.add_error("No concept files found in concepts/")
44
+ end
45
+
46
+ concept_entries.each do |entry|
47
+ validate_concept_entry(entry, metadata, result)
48
+ end
49
+
50
+ validate_assets(zip_file, result)
51
+ end
52
+
47
53
  def validate_metadata(metadata, result)
48
54
  unless metadata&.concept_count
49
55
  result.add_error("metadata.yaml missing required fields (concept_count)")
@@ -94,5 +100,36 @@ module Glossarist
94
100
  result.add_warning("#{entry.name}: no concept URI (data.uri) and no concept_uri_template or uri_prefix in metadata")
95
101
  end
96
102
  end
103
+
104
+ def validate_assets(zip_file, result)
105
+ GcrPackage::DATASET_ASSETS.each do |asset|
106
+ case asset[:type]
107
+ when :file
108
+ validate_file_asset_entry(zip_file, asset[:path], result)
109
+ when :directory
110
+ validate_directory_asset(zip_file, asset[:path], result)
111
+ end
112
+ end
113
+ end
114
+
115
+ def validate_file_asset_entry(zip_file, path, result)
116
+ entry = zip_file.find_entry(path)
117
+ return unless entry
118
+
119
+ YAML.safe_load(entry.get_input_stream.read)
120
+ rescue Psych::SyntaxError => e
121
+ result.add_error("#{path}: invalid YAML at line #{e.line}: #{e.message}")
122
+ end
123
+
124
+ def validate_directory_asset(zip_file, dir_path, result)
125
+ dir_entries = zip_file.entries.select do |e|
126
+ e.name.start_with?("#{dir_path}/")
127
+ end
128
+ return unless dir_entries.any? && dir_entries.all? do |e|
129
+ e.name.end_with?("/")
130
+ end
131
+
132
+ result.add_warning("#{dir_path}/ directory is empty")
133
+ end
97
134
  end
98
135
  end
@@ -4,5 +4,5 @@
4
4
  #
5
5
 
6
6
  module Glossarist
7
- VERSION = "2.6.1"
7
+ VERSION = "2.6.2"
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glossarist
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.1
4
+ version: 2.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-06 00:00:00.000000000 Z
11
+ date: 2026-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model