suma 0.1.13 → 0.1.15

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: 8fcc000e30cb69dd5ab1d326cbcf06ca4fe2c2855a7368f2a0387a369c15721c
4
- data.tar.gz: 3873c8355f19b4ccb2f8b8d3530eeac2ad81e65e880e44b97765413377ff71a1
3
+ metadata.gz: 52836adb9e003f9d760a6c015207379be88b8821855d64388a5f30d09474de7e
4
+ data.tar.gz: d7427de3e6dc21291671122bd07bc23c739e4f59f031e3b02988f89254767d00
5
5
  SHA512:
6
- metadata.gz: 0a18e25ee8e47d39028d0bd9bd5dd9c2f602bf540f77b3729f402bf22c86cedc5f7b037c5901886c109d869aa64d1eb82ca70c4960ba73cc2e655bd73867f80a
7
- data.tar.gz: 0b29d4b9a641de7a7056785057379e9c26a4709cec7597aa2ee2135f22cc14b52dfd66c78b5ad3204848d775b7e3b3e0537ca34c21defb29155e8dd2a20d8342
6
+ metadata.gz: c0de4abdc501a6dba9b716e7ad9a15f66985bec98b2978c9f1b25ed0f069d02d8a172f8b78c442e8f90e32098ad1622a3ba16a890c2ed57d896c4c2b427c5c3e
7
+ data.tar.gz: ed0f32387285db507797e7b34962a20e4dc6174e7389ffa2488afb8724668c11d1e0089e9e2b62a958875e0e2bb9d7f4976d5d0ef887cd83604acb4939d25b7a
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2025-04-03 06:48:36 UTC using RuboCop version 1.75.1.
3
+ # on 2025-07-05 22:42:28 UTC using RuboCop version 1.77.0.
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
@@ -13,43 +13,32 @@ Gemspec/DuplicatedAssignment:
13
13
  Exclude:
14
14
  - 'suma.gemspec'
15
15
 
16
- # Offense count: 2
17
- # This cop supports safe autocorrection (--autocorrect).
18
- # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
19
- # SupportedHashRocketStyles: key, separator, table
20
- # SupportedColonStyles: key, separator, table
21
- # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
22
- Layout/HashAlignment:
23
- Exclude:
24
- - 'lib/suma/cli/validate.rb'
25
-
26
- # Offense count: 55
16
+ # Offense count: 57
27
17
  # This cop supports safe autocorrection (--autocorrect).
28
- # Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
18
+ # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
29
19
  # URISchemes: http, https
30
20
  Layout/LineLength:
31
21
  Exclude:
32
22
  - 'lib/suma/cli.rb'
33
23
  - 'lib/suma/cli/build.rb'
24
+ - 'lib/suma/cli/extract_terms.rb'
34
25
  - 'lib/suma/cli/validate.rb'
35
26
  - 'lib/suma/cli/validate_ascii.rb'
36
27
  - 'lib/suma/cli/validate_links.rb'
37
- - 'lib/suma/collection_manifest.rb'
38
28
  - 'lib/suma/processor.rb'
39
29
  - 'lib/suma/schema_attachment.rb'
40
30
  - 'lib/suma/schema_collection.rb'
41
31
  - 'lib/suma/schema_document.rb'
42
32
  - 'lib/suma/thor_ext.rb'
33
+ - 'spec/suma/cli/extract_terms_spec.rb'
43
34
  - 'spec/suma/cli/validate_ascii_spec.rb'
44
35
  - 'suma.gemspec'
45
36
 
46
- # Offense count: 3
47
- # This cop supports safe autocorrection (--autocorrect).
48
- # Configuration parameters: AllowInHeredoc.
49
- Layout/TrailingWhitespace:
37
+ # Offense count: 1
38
+ # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
39
+ Lint/DuplicateBranch:
50
40
  Exclude:
51
- - 'lib/suma/cli.rb'
52
- - 'lib/suma/cli/validate.rb'
41
+ - 'lib/suma/cli/extract_terms.rb'
53
42
 
54
43
  # Offense count: 2
55
44
  Lint/DuplicateMethods:
@@ -57,10 +46,11 @@ Lint/DuplicateMethods:
57
46
  - 'lib/suma/cli/validate_ascii.rb'
58
47
  - 'lib/suma/express_schema.rb'
59
48
 
60
- # Offense count: 15
49
+ # Offense count: 20
61
50
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
62
51
  Metrics/AbcSize:
63
52
  Exclude:
53
+ - 'lib/suma/cli/extract_terms.rb'
64
54
  - 'lib/suma/cli/validate_ascii.rb'
65
55
  - 'lib/suma/cli/validate_links.rb'
66
56
  - 'lib/suma/schema_attachment.rb'
@@ -73,15 +63,16 @@ Metrics/AbcSize:
73
63
  Metrics/BlockLength:
74
64
  Max: 64
75
65
 
76
- # Offense count: 4
66
+ # Offense count: 8
77
67
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
78
68
  Metrics/CyclomaticComplexity:
79
69
  Exclude:
70
+ - 'lib/suma/cli/extract_terms.rb'
80
71
  - 'lib/suma/cli/validate_ascii.rb'
81
72
  - 'lib/suma/cli/validate_links.rb'
82
73
  - 'lib/suma/thor_ext.rb'
83
74
 
84
- # Offense count: 21
75
+ # Offense count: 30
85
76
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
86
77
  Metrics/MethodLength:
87
78
  Max: 107
@@ -91,10 +82,11 @@ Metrics/MethodLength:
91
82
  Metrics/ParameterLists:
92
83
  Max: 6
93
84
 
94
- # Offense count: 2
85
+ # Offense count: 5
95
86
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
96
87
  Metrics/PerceivedComplexity:
97
88
  Exclude:
89
+ - 'lib/suma/cli/extract_terms.rb'
98
90
  - 'lib/suma/cli/validate_ascii.rb'
99
91
  - 'lib/suma/cli/validate_links.rb'
100
92
 
@@ -113,12 +105,12 @@ Performance/CollectionLiteralInLoop:
113
105
  Exclude:
114
106
  - 'spec/suma/cli_spec.rb'
115
107
 
116
- # Offense count: 3
108
+ # Offense count: 9
117
109
  # Configuration parameters: CountAsOne.
118
110
  RSpec/ExampleLength:
119
- Max: 16
111
+ Max: 44
120
112
 
121
- # Offense count: 5
113
+ # Offense count: 6
122
114
  RSpec/MultipleExpectations:
123
115
  Max: 12
124
116
 
@@ -136,3 +128,9 @@ Style/EmptyElse:
136
128
  # SupportedStyles: annotated, template, unannotated
137
129
  Style/FormatStringToken:
138
130
  EnforcedStyle: unannotated
131
+
132
+ # Offense count: 1
133
+ # Configuration parameters: Max.
134
+ Style/SafeNavigationChainLength:
135
+ Exclude:
136
+ - 'lib/suma/cli/extract_terms.rb'
data/README.adoc CHANGED
@@ -37,10 +37,12 @@ $ gem install suma
37
37
  # Defaults to `suma help`
38
38
  $ suma
39
39
  Commands:
40
- suma build METANORMA_SITE_MANIFEST # Build collection specified in site manifest (`metanorma*.yml`)
41
- suma reformat EXPRESS_FILE_PATH # Reformat EXPRESS files
42
- suma validate SUBCOMMAND ...ARGS # Validate express documents
43
- suma help [COMMAND] # Describe available commands or one specific command
40
+ suma build METANORMA_SITE_MANIFEST # Build collection specified in site manifest (`metanorma*.yml`)
41
+ suma reformat EXPRESS_FILE_PATH # Reformat EXPRESS files
42
+ suma validate SUBCOMMAND ...ARGS # Validate express documents
43
+ suma generate_schemas METANORMA_MANIFEST_FILE SCHEMA_MANIFEST_FILE # Generate schemas manifest file from Metanorma manifest YAML file
44
+ suma extract_terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH # Extract terms from schema manifest file
45
+ suma help [COMMAND] # Describe available commands or one specific command
44
46
  ----
45
47
 
46
48
  === Build command
@@ -287,11 +289,134 @@ Replacement: AsciiMath: xx
287
289
  ----
288
290
 
289
291
 
292
+ === Generate schemas command
293
+
294
+ The `suma generate_schemas` command generates a schema manifest file containing
295
+ all schemas defined in the Metanorma manifest file.
296
+
297
+ [source,sh]
298
+ ----
299
+ $ suma generate_schemas METANORMA_MANIFEST_FILE SCHEMA_MANIFEST_FILE [options]
300
+ ----
301
+
302
+ Parameters:
303
+
304
+ `METANORMA_MANIFEST_FILE`:: Path to the Metanorma manifest file
305
+ (e.g.: "metanorma-smrl-all.yml")
306
+
307
+ Options:
308
+
309
+ `--exclude_path`, `-e`:: Exclude schemas by pattern (e.g. `*_lf.exp`)
310
+
311
+ [example]
312
+ ====
313
+ .To generate schemas manifest file from Metanorma manifest file
314
+ [source,sh]
315
+ ----
316
+ $ bundle exec suma generate_schemas metanorma-smrl-all.yml schemas-smrl-all.yml
317
+ # => generates schemas-smrl-all.yml
318
+ ----
319
+
320
+ .To generate schemas manifest file from Metanorma manifest file and exclude schemas with names like `*_lf.exp`
321
+ [source,sh]
322
+ ----
323
+ $ bundle exec suma generate_schemas metanorma-smrl-all.yml schemas-smrl-all.yml -e *_lf.exp
324
+ # => generates schemas-smrl-all.yml without schemas with names like *_lf.exp
325
+ ----
326
+ ====
327
+
328
+ All documents need to have a `schemas.yaml` in their document root that lists
329
+ out which schemas the document includes.
330
+
331
+
332
+ === Extract terms command
333
+
334
+ The `suma extract_terms` command extracts terms from EXPRESS schemas and
335
+ generates a Glossarist v2 dataset in the output directory. This command processes
336
+ various types of STEP schemas and creates standardized terminology datasets
337
+ suitable for glossary and dictionary applications.
338
+
339
+ [source,sh]
340
+ ----
341
+ $ suma extract_terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH [options]
342
+ ----
343
+
344
+ Parameters:
345
+
346
+ `SCHEMA_MANIFEST_FILE`:: Path to the schema manifest file that lists all schemas
347
+ to process (e.g., "schemas-smrl-all.yml")
348
+
349
+ `GLOSSARIST_OUTPUT_PATH`:: Path to the output directory where the Glossarist v2
350
+ dataset will be generated
351
+
352
+ Options:
353
+
354
+ `--language_code`, `-l`:: Language code for the Glossarist dataset (default: "eng")
355
+
356
+ ==== Supported schema types
357
+
358
+ The command supports extraction from the following EXPRESS schema types:
359
+
360
+ * **ARM (Application Reference Model)** - Application module schemas ending with `_arm`
361
+ * **MIM (Module Implementation Model)** - Application module schemas ending with `_mim`
362
+ * **Resource schemas** - General resource schemas
363
+ * **BOM (Business Object Model)** - Business object model schemas ending with `_bom`
364
+
365
+ ==== Extracted terms
366
+
367
+ The command extracts the following types of terms from EXPRESS schemas:
368
+
369
+ * **Entities** - EXPRESS entity definitions with their attributes and relationships
370
+ * **Types** - EXPRESS type definitions including enumerations and select types
371
+ * **Functions** - EXPRESS function definitions
372
+ * **Procedures** - EXPRESS procedure definitions
373
+ * **Constants** - EXPRESS constant definitions
374
+
375
+ Each extracted term includes:
376
+
377
+ * Unique identifier based on schema and term name
378
+ * Term definition and description
379
+ * Source schema information
380
+ * Appropriate domain classification (application module, resource, or business object model)
381
+
382
+ ==== Output format
383
+
384
+ The command generates a Glossarist v2 compliant dataset with:
385
+
386
+ * `concept/` directory containing concept definition files
387
+ * `localized_concept/` directory containing localized concept files
388
+ * YAML format following Glossarist v2 schema specifications
389
+ * Proper cross-references and citations to source schemas
390
+
391
+ .To extract terms from a schema manifest file
392
+ [example]
393
+ ====
394
+ [source,sh]
395
+ ----
396
+ $ bundle exec suma extract_terms schemas-smrl-all.yml glossarist_output
397
+ # => generates glossarist_output/concept/*.yaml and glossarist_output/localized_concept/*.yaml
398
+ ----
399
+ ====
400
+
401
+ .To extract terms from a specific schema subset
402
+ [example]
403
+ ====
404
+ [source,sh]
405
+ ----
406
+ $ bundle exec suma extract_terms schemas-activity-modules.yml terms_output
407
+ # => processes only schemas listed in the manifest file
408
+ ----
409
+ ====
410
+
411
+ The generated dataset is meant to be used for ISO 10303-2.
412
+
413
+
290
414
  == Usage: Ruby
291
415
 
292
416
  === General
293
417
 
294
- Suma can be used programmatically in your Ruby applications. The following examples demonstrate common usage patterns.
418
+ Suma can be used programmatically in your Ruby applications. The following
419
+ examples demonstrate common usage patterns.
295
420
 
296
421
  === Building collections
297
422
 
@@ -0,0 +1,443 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require_relative "../thor_ext"
5
+ require "fileutils"
6
+ require "expressir"
7
+ require "securerandom"
8
+ require "glossarist"
9
+
10
+ module Suma
11
+ module Cli
12
+ # ExtractTerms command using Expressir to extract terms into the
13
+ # Glossarist v2 format
14
+ class ExtractTerms < Thor
15
+ desc "extract_terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH",
16
+ "Extract terms from SCHEMA_MANIFEST_FILE into " \
17
+ "Glossarist v2 format"
18
+ option :language_code, type: :string, default: "eng", aliases: "-l",
19
+ desc: "Language code for the Glossarist"
20
+
21
+ def extract_terms(schema_manifest_file, output_path)
22
+ language_code = options[:language_code]
23
+ schema_manifest_file = File.expand_path(schema_manifest_file)
24
+
25
+ unless File.exist?(schema_manifest_file)
26
+ raise Errno::ENOENT, "Specified SCHEMA_MANIFEST_FILE " \
27
+ "`#{schema_manifest_file}` not found."
28
+ end
29
+
30
+ run(schema_manifest_file, output_path, language_code)
31
+ end
32
+
33
+ private
34
+
35
+ def run(schema_manifest_file, output_path, language_code = "eng")
36
+ get_exp_files(schema_manifest_file).map do |exp_file|
37
+ extract(exp_file, output_path, language_code)
38
+ end
39
+ end
40
+
41
+ def get_exp_files(schema_manifest_file)
42
+ config = Expressir::SchemaManifest.from_file(schema_manifest_file)
43
+ paths = config.schemas.map(&:path)
44
+
45
+ if paths.empty?
46
+ raise Errno::ENOENT, "No EXPRESS files found in " \
47
+ "`#{schema_manifest_file}`."
48
+ end
49
+
50
+ paths
51
+ end
52
+
53
+ def extract(exp_file, output_path, language_code)
54
+ exp_path_rel = Pathname.new(exp_file).relative_path_from(Pathname.getwd)
55
+ puts "Building terms: #{exp_path_rel}"
56
+
57
+ repo = Expressir::Express::Parser.from_file(exp_file)
58
+ schema = get_default_schema(repo)
59
+
60
+ unless schema.file
61
+ raise Error.new("Schema must have an associated file")
62
+ end
63
+
64
+ collection = build_managed_concept_collection(
65
+ schema, language_code
66
+ )
67
+
68
+ output_data(collection, output_path)
69
+ end
70
+
71
+ def output_data(collection, output_path)
72
+ unless File.exist?(output_path)
73
+ FileUtils.mkdir_p(File.expand_path(output_path))
74
+ end
75
+
76
+ puts "Saving collection to files in: #{output_path}"
77
+ collection.save_to_files(File.expand_path(output_path))
78
+
79
+ collection
80
+ end
81
+
82
+ def build_managed_concept_collection(schema, language_code)
83
+ Glossarist::ManagedConceptCollection.new.tap do |collection|
84
+ # Extract schema-level citation data once to reuse across all entities
85
+ source_ref = get_source_ref(schema)
86
+
87
+ # Create one concept per entity
88
+ schema.entities.each do |entity|
89
+ localized_concept = build_localized_concept(
90
+ schema: schema,
91
+ entity: entity,
92
+ language_code: language_code,
93
+ source_ref: source_ref,
94
+ )
95
+
96
+ managed_data = Glossarist::ManagedConceptData.new.tap do |data|
97
+ data.id = get_entity_identifier(schema, entity)
98
+
99
+ # TODO: Why do we need both localizations and localized_concepts??
100
+ data.localizations[language_code] = localized_concept
101
+ # uuid is automatically set from the serialization of the object
102
+ data.localized_concepts = {
103
+ language_code => get_localized_concept_identifier(
104
+ schema, entity, language_code
105
+ ),
106
+ }
107
+ end
108
+
109
+ managed_concept = Glossarist::ManagedConcept.new.tap do |concept|
110
+ # uuid is automatically set from the serialization of the object
111
+ concept.id = get_entity_identifier(schema, entity)
112
+ concept.uuid = concept.id
113
+ concept.data = managed_data
114
+ end
115
+
116
+ collection.store(managed_concept)
117
+ end
118
+ end
119
+ end
120
+
121
+ def build_localized_concept(schema:, entity:, language_code:, source_ref:)
122
+ schema_domain = get_domain(schema)
123
+
124
+ localized_concept_data = Glossarist::ConceptData.new.tap do |data|
125
+ data.terms = get_entity_terms(entity)
126
+ data.definition = get_entity_definitions(entity, schema)
127
+ data.language_code = language_code
128
+ data.domain = schema_domain
129
+ data.sources = [source_ref] if source_ref
130
+
131
+ # Only assign optional fields if they have content
132
+ notes = get_entity_notes(entity, schema_domain)
133
+ data.notes = notes if notes && !notes.empty?
134
+
135
+ examples = get_entity_examples(entity, schema_domain)
136
+ data.examples = examples if examples && !examples.empty?
137
+ end
138
+
139
+ Glossarist::LocalizedConcept.new.tap do |concept|
140
+ concept.data = localized_concept_data
141
+ end
142
+ end
143
+
144
+ # We only deal with 1 schema
145
+ def get_default_schema(repo)
146
+ repo.schemas.first
147
+ end
148
+
149
+ def find_remark_value(schema, remark_id)
150
+ schema.remark_items.find { |s| s.id == remark_id }&.remarks&.first
151
+ end
152
+
153
+ def get_entity_identifier(schema, entity)
154
+ "#{schema.id}.#{entity.id}"
155
+ end
156
+
157
+ def get_localized_concept_identifier(schema, entity, lang)
158
+ "#{schema.id}.#{entity.id}-#{lang}"
159
+ end
160
+
161
+ def get_source_ref(schema)
162
+ origin = Glossarist::Citation.new.tap do |citation|
163
+ citation.ref = "ISO 10303"
164
+ custom_locality = build_custom_locality(schema)
165
+
166
+ unless custom_locality.empty?
167
+ citation.custom_locality = custom_locality
168
+ end
169
+ end
170
+
171
+ Glossarist::ConceptSource.new(type: "authoritative", origin: origin)
172
+ end
173
+
174
+ # SCHEMA action_schema
175
+ # '{iso standard 10303 part(41) version(9) object(1) action-schema(1)}';
176
+ def build_custom_locality(schema)
177
+ [].tap do |localities|
178
+ # Add schema name
179
+ localities << Glossarist::CustomLocality.new(
180
+ name: "schema",
181
+ value: schema.id,
182
+ )
183
+
184
+ # Add version if available
185
+ version_item = schema.version.items.detect { |i| i.name == "version" }
186
+ if version_item
187
+ localities << Glossarist::CustomLocality.new(
188
+ name: "version",
189
+ value: version_item.value,
190
+ )
191
+ end
192
+ end
193
+ end
194
+
195
+ # TODO: What if this was a "bom"?
196
+ def get_domain(schema)
197
+ prefix = if mim?(schema.id) || arm?(schema.id)
198
+ "application module"
199
+ else
200
+ "resource"
201
+ end
202
+
203
+ "#{prefix}: #{schema.id}"
204
+ end
205
+
206
+ def arm?(schema_id)
207
+ schema_id.end_with?("_arm")
208
+ end
209
+
210
+ def mim?(schema_id)
211
+ schema_id.end_with?("_mim")
212
+ end
213
+
214
+ def get_terms(schema)
215
+ schema_title = get_title(schema)
216
+ if schema_title
217
+ [
218
+ Glossarist::Designation::Base.new(
219
+ designation: schema_title,
220
+ type: "expression",
221
+ normative_status: "preferred",
222
+ ),
223
+ ]
224
+ end
225
+ end
226
+
227
+ def get_entity_terms(entity)
228
+ # For now, use the entity ID as the term
229
+ # This could be enhanced to look for entity-specific title remark items
230
+ [
231
+ Glossarist::Designation::Base.new(
232
+ designation: entity.id,
233
+ type: "expression",
234
+ normative_status: "preferred",
235
+ ),
236
+ ]
237
+ end
238
+
239
+ def get_entity_definitions(entity, schema)
240
+ schema_type = extract_file_type(schema.file)
241
+ schema_domain = get_domain(schema)
242
+
243
+ definition = generate_entity_definition(entity, schema_domain,
244
+ schema_type)
245
+ [Glossarist::DetailedDefinition.new(content: definition)]
246
+ end
247
+
248
+ def get_entity_notes(entity, schema_domain)
249
+ notes = []
250
+
251
+ # Add trimmed definition from entity description as first note
252
+ if entity.remarks && !entity.remarks.empty?
253
+ trimmed_def = trim_definition(entity.remarks)
254
+ if trimmed_def && !trimmed_def.empty?
255
+ notes << Glossarist::DetailedDefinition.new(
256
+ content: convert_express_xref(trimmed_def, schema_domain),
257
+ )
258
+ end
259
+ end
260
+
261
+ # Add other notes
262
+ other_notes = [
263
+ entity.remark_items&.select do |ri|
264
+ ri.id == "__note"
265
+ end&.map(&:remarks),
266
+ ].flatten.compact
267
+
268
+ other_notes.each do |note|
269
+ notes << Glossarist::DetailedDefinition.new(
270
+ content: convert_express_xref(note, schema_domain),
271
+ )
272
+ end
273
+
274
+ notes
275
+ end
276
+
277
+ def get_entity_examples(entity, schema_domain)
278
+ examples = entity.remark_items&.select do |ri|
279
+ ri.id == "__example"
280
+ end&.map(&:remarks)&.flatten&.compact || []
281
+
282
+ examples.map do |example|
283
+ Glossarist::DetailedDefinition.new(
284
+ content: convert_express_xref(example, schema_domain),
285
+ )
286
+ end
287
+ end
288
+
289
+ def extract_file_type(filename)
290
+ match = filename.match(/(arm|mim|bom)_annotated\.exp$/)
291
+ return "resource" unless match
292
+
293
+ {
294
+ "arm" => "module_arm",
295
+ "mim" => "module_mim",
296
+ "bom" => "business_object_model",
297
+ }[match.captures[0]] || "resource"
298
+ end
299
+
300
+ def get_schema_type(schema)
301
+ return "mim" if mim?(schema.id)
302
+ return "arm" if arm?(schema.id)
303
+ return "bom" if bom?(schema.id)
304
+
305
+ "resource"
306
+ end
307
+
308
+ def bom?(schema_id)
309
+ schema_id.end_with?("_bom")
310
+ end
311
+
312
+ # rubocop:disable Metrics/MethodLength
313
+ def combine_paragraphs(full_paragraph, next_paragraph)
314
+ # If full_paragraph already contains a period, extract that.
315
+ if m = full_paragraph.match(/\A(?<inner_first>[^\n]*?\.)\s/)
316
+ # puts "CONDITION 1"
317
+ if m[:inner_first]
318
+ return m[:inner_first]
319
+ else
320
+ return full_paragraph
321
+ end
322
+ end
323
+
324
+ # If full_paragraph ends with a period, this is the last.
325
+ if /\.\s*\Z/.match?(full_paragraph)
326
+ # puts "CONDITION 2"
327
+ return full_paragraph
328
+ end
329
+
330
+ # If next_paragraph is a list
331
+ if next_paragraph.start_with?("*")
332
+ # puts "CONDITION 3"
333
+ return "#{full_paragraph}\n\n#{next_paragraph}"
334
+ end
335
+
336
+ # If next_paragraph is a continuation of a list
337
+ if next_paragraph.start_with?("which", "that")
338
+ # puts "CONDITION 4"
339
+ return "#{full_paragraph}\n\n#{next_paragraph}"
340
+ end
341
+
342
+ # puts "CONDITION 5"
343
+ full_paragraph
344
+ end
345
+
346
+ def trim_definition(definition)
347
+ return nil if definition.nil? || definition.empty?
348
+
349
+ # Handle case where definition is an array
350
+ definition_str = if definition.is_a?(Array)
351
+ definition.join("\n\n")
352
+ else
353
+ definition.to_s
354
+ end
355
+
356
+ return nil if definition_str.empty?
357
+
358
+ # Unless the first paragraph ends with "between" and is followed by a
359
+ # list, don't split
360
+ paragraphs = definition_str.split("\n\n")
361
+
362
+ # puts paragraphs.inspect
363
+
364
+ first_paragraph = paragraphs.first
365
+
366
+ combined = if paragraphs.length > 1
367
+ paragraphs[1..].inject(first_paragraph) do |acc, p|
368
+ combine_paragraphs(acc, p)
369
+ end
370
+ else
371
+ combine_paragraphs(first_paragraph, "")
372
+ end
373
+
374
+ # puts "combined--------- #{combined}"
375
+
376
+ # Remove comments until end of line
377
+ combined = "#{combined}\n"
378
+ combined.gsub!(/\n\/\/.*?\n/, "\n")
379
+ combined.strip!
380
+
381
+ express_reference_to_mention(combined)
382
+ end
383
+ # rubocop:enable Metrics/MethodLength
384
+
385
+ # Replace `<<express:{schema}.{entity},{render}>>` with {{entity,render}}
386
+ def express_reference_to_mention(description)
387
+ # TODO: Use Expressir to check whether the "entity" is really an
388
+ # EXPRESS ENTITY. If not, skip the mention.
389
+ description.gsub(/<<express:([^,]+),([^>]+)>>/) do |_match|
390
+ "{{#{Regexp.last_match[1].split('.').last},#{Regexp.last_match[2]}}}"
391
+ end
392
+ end
393
+
394
+ def entity_name_to_text(entity_id)
395
+ entity_id.downcase.gsub("_", " ")
396
+ end
397
+
398
+ # rubocop:disable Layout/LineLength
399
+ def generate_entity_definition(entity, _domain, schema_type)
400
+ return "" if entity.nil?
401
+
402
+ # See: metanorma/iso-10303-2#90
403
+ entity_type = case schema_type
404
+ when "module_arm"
405
+ "{{application object}}"
406
+ when "module_mim"
407
+ "{{entity data type}}"
408
+ when "resource", "business_object_model"
409
+ "{{entity data type}}"
410
+ else
411
+ raise Error.new("[suma] encountered unsupported schema_type")
412
+ end
413
+
414
+ if entity.subtype_of.empty?
415
+ "#{entity_type} " \
416
+ "that represents the " \
417
+ "#{entity_name_to_text(entity.id)} {{entity}}"
418
+ else
419
+ entity_subtypes = entity.subtype_of.map do |e|
420
+ "{{#{e.id}}}"
421
+ end
422
+
423
+ "#{entity_type} that is a type of " \
424
+ "#{entity_subtypes.join(' and ')} " \
425
+ "that represents the " \
426
+ "#{entity_name_to_text(entity.id)} {{entity}}"
427
+ end
428
+ end
429
+ # rubocop:enable Layout/LineLength
430
+
431
+ def convert_express_xref(content, schema_domain)
432
+ content.gsub(/<<express:(.*),(.*)>>/) do
433
+ "{{<#{schema_domain}>" \
434
+ "#{Regexp.last_match(1).split('.').last},#{Regexp.last_match(2)}}}"
435
+ end
436
+ end
437
+
438
+ def id_from_designation(designation)
439
+ designation.gsub(" ", "_").gsub("/", "_").gsub(":", "_")
440
+ end
441
+ end
442
+ end
443
+ end
@@ -0,0 +1,141 @@
1
+ require "thor"
2
+ require_relative "../thor_ext"
3
+ require "fileutils"
4
+ require "yaml"
5
+ require "pathname"
6
+
7
+ module Suma
8
+ module Cli
9
+ # GenerateSchemas command to generate Schemas YAML by Metanorma YAML
10
+ class GenerateSchemas < Thor
11
+ desc "generate_schemas METANORMA_MANIFEST_FILE SCHEMA_MANIFEST_FILE",
12
+ "Generate EXPRESS schema manifest file from Metanorma site manifest"
13
+ option :exclude_paths, type: :string, default: nil, aliases: "-e",
14
+ desc: "Exclude schemas paths by pattern " \
15
+ "(e.g. `*_lf.exp`)"
16
+
17
+ YAML_FILE_EXTENSIONS = [".yaml", ".yml"].freeze
18
+
19
+ def generate_schemas(metanorma_manifest_file, schema_manifest_file) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
20
+ metanorma_manifest_file = File.expand_path(metanorma_manifest_file)
21
+
22
+ unless File.exist?(metanorma_manifest_file)
23
+ raise Errno::ENOENT, "Specified file `#{metanorma_manifest_file}` " \
24
+ "not found."
25
+ end
26
+
27
+ unless File.file?(metanorma_manifest_file)
28
+ raise ArgumentError, "Specified path `#{metanorma_manifest_file}` " \
29
+ "is not a file."
30
+ end
31
+
32
+ [metanorma_manifest_file, schema_manifest_file].each do |file|
33
+ if !YAML_FILE_EXTENSIONS.include?(File.extname(file))
34
+ raise ArgumentError, "Specified file `#{file}` is not a YAML file."
35
+ end
36
+ end
37
+
38
+ run(
39
+ metanorma_manifest_file, schema_manifest_file,
40
+ exclude_paths: options[:exclude_paths]
41
+ )
42
+ end
43
+
44
+ private
45
+
46
+ def run(metanorma_manifest_file, schema_manifest_file, exclude_paths: nil)
47
+ metanorma_data = load_yaml(metanorma_manifest_file)
48
+ collection_files = metanorma_data["metanorma"]["source"]["files"]
49
+ manifest_files = load_manifest_files(collection_files)
50
+ all_schemas = load_project_schemas(manifest_files, exclude_paths,
51
+ schema_manifest_file)
52
+ all_schemas["schemas"] = all_schemas["schemas"].sort.to_h
53
+ output_data(all_schemas, schema_manifest_file)
54
+ end
55
+
56
+ def output_data(all_schemas, path)
57
+ puts "Writing the Schemas YAML file to #{File.expand_path(path)}..."
58
+ # debug use only
59
+ # puts all_schemas.to_yaml
60
+ File.write(File.expand_path(path), all_schemas.to_yaml)
61
+ puts "Writing the Schemas YAML file to #{File.expand_path(path)}...Done"
62
+ end
63
+
64
+ def load_yaml(file_path)
65
+ YAML.safe_load(
66
+ File.read(file_path, encoding: "UTF-8"),
67
+ permitted_classes: [Date, Time, Symbol],
68
+ permitted_symbols: [],
69
+ aliases: true,
70
+ )
71
+ end
72
+
73
+ def load_manifest_files(collection_files)
74
+ manifest_files = collection_files.map do |c|
75
+ collection_data = load_yaml(c)
76
+ collection_data["manifest"]["docref"].map { |docref| docref["file"] }
77
+ end
78
+ manifest_files.flatten
79
+ end
80
+
81
+ def load_project_schemas( # rubocop:disable Metrics/AbcSize
82
+ manifest_files, exclude_paths, schema_manifest_file
83
+ )
84
+ all_schemas = { "schemas" => {} }
85
+
86
+ manifest_files.each do |file|
87
+ # load schemas.yaml from the location of the collection.yml file
88
+ schemas_file_path = File.expand_path(
89
+ file.gsub("collection.yml", "schemas.yaml"),
90
+ )
91
+ unless File.exist?(schemas_file_path)
92
+ puts "Schemas file not found: #{schemas_file_path}"
93
+ next
94
+ end
95
+
96
+ schemas_data = load_yaml(schemas_file_path)
97
+
98
+ if schemas_data["schemas"]
99
+ schemas_data["schemas"] = fix_path(
100
+ schemas_data,
101
+ schemas_file_path,
102
+ schema_manifest_file,
103
+ )
104
+ all_schemas["schemas"].merge!(schemas_data["schemas"])
105
+ end
106
+
107
+ if exclude_paths
108
+ all_schemas["schemas"].delete_if do |_key, value|
109
+ value["path"].match?(
110
+ Regexp.new(exclude_paths.gsub("*", "(.*){1,999}")),
111
+ )
112
+ end
113
+ end
114
+ end
115
+
116
+ all_schemas
117
+ end
118
+
119
+ def fix_path(schemas_data, schemas_file_path, schema_manifest_file) # rubocop:disable Metrics/AbcSize
120
+ schema_manifest_path = File.expand_path(schema_manifest_file, Dir.pwd)
121
+
122
+ schemas_data["schemas"].each do |key, value|
123
+ # resolve the path in the schema file by the path in the schemas.yaml
124
+ path_in_schema = File.expand_path(
125
+ value["path"],
126
+ File.dirname(schemas_file_path),
127
+ )
128
+
129
+ # calculate the relative path from the schema manifest file
130
+ fixed_path = Pathname.new(path_in_schema).relative_path_from(
131
+ Pathname.new(File.dirname(schema_manifest_path)),
132
+ )
133
+
134
+ { key => value.merge!("path" => fixed_path.to_s) }
135
+ end
136
+
137
+ schemas_data["schemas"]
138
+ end
139
+ end
140
+ end
141
+ end
@@ -57,7 +57,7 @@ module Suma
57
57
  # containing '(*text*)' inside
58
58
  comments = file_content.scan(/\(\*"(.*?)\n\*\)/m).map(&:first)
59
59
 
60
- if comments.count.positive?
60
+ if comments.any?
61
61
  content_without_comments = file_content.gsub(/\(\*".*?\n\*\)/m, "")
62
62
 
63
63
  # remove extra newlines
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "thor"
4
4
  require_relative "../utils"
5
+ require "expressir"
5
6
 
6
7
  module Suma
7
8
  module Cli
@@ -43,7 +44,6 @@ module Suma
43
44
  # Lazy-load dependencies only when this command is actually used
44
45
  require "expressir"
45
46
  require "ruby-progressbar"
46
- require_relative "../schema_config"
47
47
  require "pathname"
48
48
  end
49
49
 
@@ -74,7 +74,7 @@ module Suma
74
74
 
75
75
  # Load and initialize the schemas configuration
76
76
  def load_schemas_config(schemas_file_path)
77
- schemas_config = Suma::SchemaConfig::Config.from_yaml(File.read(schemas_file_path))
77
+ schemas_config = Expressir::SchemaManifest.from_yaml(File.read(schemas_file_path))
78
78
  # Ensure the config is initialized with the correct path to resolve relative paths
79
79
  schemas_config.set_initial_path(schemas_file_path.to_s)
80
80
  schemas_config
data/lib/suma/cli.rb CHANGED
@@ -23,6 +23,16 @@ module Suma
23
23
  Cli::Build.start
24
24
  end
25
25
 
26
+ desc "generate_schemas METANORMA_MANIFEST_FILE SCHEMA_MANIFEST_FILE",
27
+ "Generate EXPRESS schema manifest file from Metanorma site manifest"
28
+ option :exclude_paths, type: :string, default: nil, aliases: "-e",
29
+ desc: "Exclude schemas paths by pattern " \
30
+ "(e.g. `*_lf.exp`)"
31
+ def generate_schemas(_metanorma_manifest_file, _schema_manifest_file)
32
+ require_relative "cli/generate_schemas"
33
+ Cli::GenerateSchemas.start
34
+ end
35
+
26
36
  desc "reformat EXPRESS_FILE_PATH",
27
37
  "Reformat EXPRESS files"
28
38
  option :recursive, type: :boolean, default: false, aliases: "-r",
@@ -33,6 +43,16 @@ module Suma
33
43
  Cli::Reformat.start
34
44
  end
35
45
 
46
+ desc "extract_terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH",
47
+ "Extract terms from SCHEMA_MANIFEST_FILE into " \
48
+ "Glossarist v2 format"
49
+ option :language_code, type: :string, default: "eng", aliases: "-l",
50
+ desc: "Language code for the Glossarist"
51
+ def extract_terms(_schema_manifest_file, _glossarist_output_path)
52
+ require_relative "cli/extract_terms"
53
+ Cli::ExtractTerms.start
54
+ end
55
+
36
56
  desc "validate SUBCOMMAND ...ARGS", "Validate express documents"
37
57
  subcommand "validate", Cli::Validate
38
58
 
@@ -3,6 +3,7 @@
3
3
  require "metanorma/cli"
4
4
  require "metanorma/cli/collection"
5
5
  require "metanorma/collection/collection"
6
+ require "expressir"
6
7
 
7
8
  module Suma
8
9
  class CollectionManifest < Metanorma::Collection::Config::Manifest
@@ -36,7 +37,7 @@ module Suma
36
37
  end
37
38
 
38
39
  def export_schema_config(path)
39
- export_config = @schema_config || Suma::SchemaConfig::Config.new
40
+ export_config = @schema_config || Expressir::SchemaManifest.new
40
41
  return export_config unless entry
41
42
 
42
43
  entry.each do |x|
@@ -127,7 +128,7 @@ module Suma
127
128
  if File.basename(file) == "collection.yml"
128
129
  schemas_yaml_path = File.join(File.dirname(file), "schemas.yaml")
129
130
  if schemas_yaml_path && File.exist?(schemas_yaml_path)
130
- @schema_config = Suma::SchemaConfig::Config.from_file(schemas_yaml_path)
131
+ @schema_config = Expressir::SchemaManifest.from_file(schemas_yaml_path)
131
132
  end
132
133
  end
133
134
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "schema_config"
4
3
  require_relative "schema_collection"
5
4
  require_relative "utils"
6
5
  require_relative "collection_config"
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fileutils"
4
+ require "expressir"
4
5
  # require "metanorma/cli"
5
- require_relative "schema_config"
6
6
 
7
7
  module Suma
8
8
  class SchemaAttachment
@@ -68,8 +68,8 @@ module Suma
68
68
 
69
69
  def to_config(path: nil)
70
70
  # return @config unless @config
71
- @config = SchemaConfig::Config.new
72
- @config.schemas << SchemaConfig::Schema.new(
71
+ @config = Expressir::SchemaManifest.new
72
+ @config.schemas << Expressir::SchemaManifestEntry.new(
73
73
  id: @schema.id,
74
74
  path: @schema.path,
75
75
  )
@@ -3,7 +3,7 @@
3
3
  require_relative "express_schema"
4
4
  require_relative "schema_attachment"
5
5
  require_relative "schema_document"
6
- require_relative "schema_config"
6
+ require "expressir"
7
7
  require_relative "utils"
8
8
 
9
9
  module Suma
@@ -19,7 +19,7 @@ module Suma
19
19
  @output_path_docs = Pathname.new(output_path_docs || Dir.pwd).expand_path
20
20
  @output_path_schemas = Pathname.new(output_path_schemas || Dir.pwd).expand_path
21
21
  @config = config
22
- @config ||= config_yaml && SchemaConfig::Config.from_file(config_yaml)
22
+ @config ||= config_yaml && Expressir::SchemaManifest.from_file(config_yaml)
23
23
  @manifest = manifest
24
24
  end
25
25
 
data/lib/suma/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Suma
4
- VERSION = "0.1.13"
4
+ VERSION = "0.1.15"
5
5
  end
data/lib/suma.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "expressir"
3
4
  require_relative "suma/version"
4
5
  require_relative "suma/processor"
5
6
 
data/suma.gemspec CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
34
34
  spec.require_paths = ["lib"]
35
35
 
36
36
  spec.add_dependency "expressir", "~> 2.1"
37
+ spec.add_dependency "glossarist", "~> 2.3.7"
37
38
  spec.add_dependency "lutaml-model", "~> 0.7"
38
39
  spec.add_dependency "metanorma-cli"
39
40
  spec.add_dependency "plurimath"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: suma
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-05-24 00:00:00.000000000 Z
11
+ date: 2025-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: expressir
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: glossarist
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.3.7
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.3.7
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: lutaml-model
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -134,6 +148,8 @@ files:
134
148
  - lib/suma.rb
135
149
  - lib/suma/cli.rb
136
150
  - lib/suma/cli/build.rb
151
+ - lib/suma/cli/extract_terms.rb
152
+ - lib/suma/cli/generate_schemas.rb
137
153
  - lib/suma/cli/reformat.rb
138
154
  - lib/suma/cli/validate.rb
139
155
  - lib/suma/cli/validate_ascii.rb
@@ -144,9 +160,6 @@ files:
144
160
  - lib/suma/processor.rb
145
161
  - lib/suma/schema_attachment.rb
146
162
  - lib/suma/schema_collection.rb
147
- - lib/suma/schema_config.rb
148
- - lib/suma/schema_config/config.rb
149
- - lib/suma/schema_config/schema.rb
150
163
  - lib/suma/schema_document.rb
151
164
  - lib/suma/site_config.rb
152
165
  - lib/suma/thor_ext.rb
@@ -1,147 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "lutaml/model"
4
- require_relative "schema"
5
- require_relative "../utils"
6
-
7
- module Suma
8
- module SchemaConfig
9
- class Config < Lutaml::Model::Serializable
10
- attribute :schemas, Schema, collection: true, initialize_empty: true
11
- attribute :path, Lutaml::Model::Type::String
12
- attr_accessor :output_path
13
-
14
- def initialize(**args)
15
- @path = path_relative_to_absolute(path) if path
16
- super
17
- end
18
-
19
- def base_path
20
- File.dirname(@path)
21
- end
22
-
23
- yaml do
24
- map "schemas", with: { from: :schemas_from_yaml, to: :schemas_to_yaml }
25
- end
26
-
27
- def self.from_file(path)
28
- from_yaml(File.read(path)).tap do |x|
29
- x.set_initial_path(path)
30
- end
31
- end
32
-
33
- def to_file(to_path = path)
34
- File.write(to_path, to_yaml)
35
- end
36
-
37
- def set_initial_path(new_path)
38
- @path = path_relative_to_absolute(new_path)
39
- schemas.each do |schema|
40
- schema.path = path_relative_to_absolute(schema.path)
41
- schema.container_path = File.expand_path(@path)
42
- end
43
- end
44
-
45
- def schemas_from_yaml(model, value)
46
- model.schemas = value.map do |k, v|
47
- Schema.new(id: k, path: path_relative_to_absolute(v["path"]))
48
- end
49
- end
50
-
51
- def schemas_to_yaml(model, doc)
52
- doc["schemas"] = model.schemas.sort_by(&:id).to_h do |schema|
53
- # We are outputting the schemas collection file to the directory where
54
- # the collection config is at (assumed to be Dir.pwd), not to the
55
- # directory we sourced the manifest from, e.g.
56
- # documents/iso-10303-41/schemas.yaml.
57
-
58
- # So the schema.container_path = @config.path is not
59
- # in fact needed, as the files are already absolute. This notion of
60
- # using @path to create relative paths was misconceived
61
- [
62
- schema.id,
63
- {
64
- "path" => path_absolute_to_relative(
65
- schema.path,
66
- model.output_path || Dir.pwd,
67
- ),
68
- },
69
- ]
70
- end
71
- end
72
-
73
- def path_relative_to_absolute(relative_path)
74
- eval_path = Pathname.new(relative_path)
75
- return relative_path if eval_path.absolute?
76
-
77
- # Or based on current working directory?
78
- return relative_path unless @path
79
-
80
- # ... but if this calculates path, we end up expanding it anyway
81
-
82
- Pathname.new(File.dirname(@path)).join(eval_path).expand_path.to_s
83
- end
84
-
85
- def path_absolute_to_relative(absolute_path, container_path)
86
- container_path ||= @path
87
- return absolute_path unless container_path
88
-
89
- p = Pathname.new(container_path)
90
- container = p.directory? ? p.to_s : p.dirname
91
- Pathname.new(absolute_path).relative_path_from(container).to_s
92
- end
93
-
94
- def update_path(new_path)
95
- if @path.nil?
96
- @path = new_path
97
- return @path
98
- end
99
-
100
- old_base_path = File.dirname(@path)
101
- new_base_path = File.dirname(new_path)
102
- update_schema_path(old_base_path, new_base_path)
103
-
104
- @path = new_path
105
- end
106
-
107
- def concat(another_config)
108
- unless another_config.is_a?(self.class)
109
- raise StandardError, "Can only concat a SchemaConfig::Config object."
110
- end
111
-
112
- # We need to update the relative paths when paths exist
113
- if path && another_config.path && path != another_config.path
114
- new_config = another_config.dup
115
- new_config.update_path(path)
116
- end
117
-
118
- schemas.concat(another_config.schemas)
119
- end
120
-
121
- def save_to_path(filename)
122
- new_config = dup.tap do |c|
123
- c.path = filename
124
- c.update_path(File.dirname(filename))
125
- c.output_path = filename
126
- end
127
-
128
- File.open(filename, "w") do |f|
129
- Utils.log "Writing #{filename}..."
130
- f.write(new_config.to_yaml)
131
- Utils.log "Done."
132
- end
133
- end
134
-
135
- def update_schema_path(old_base_path, new_base_path)
136
- schemas.each do |schema|
137
- schema_path = Pathname.new(schema.path)
138
- next if schema_path.absolute?
139
-
140
- schema_path = (Pathname.new(old_base_path) + schema_path).cleanpath
141
- # This is the new relative schema_path
142
- schema.path = schema_path.relative_path_from(new_base_path)
143
- end
144
- end
145
- end
146
- end
147
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "lutaml/model"
4
-
5
- module Suma
6
- module SchemaConfig
7
- class Schema < Lutaml::Model::Serializable
8
- attribute :id, Lutaml::Model::Type::String
9
- attribute :path, Lutaml::Model::Type::String
10
- # attribute :schemas_only, Lutaml::Model::Type::Boolean
11
-
12
- # container_path is a copy of Suma::SchemaConfig::Config.path,
13
- # used to resolve the path of each schema within
14
- # Suma::SchemaConfig::Config.schemas,
15
- # when Suma::SchemaConfig::Config.schemas is recursively flattened
16
- attr_accessor :container_path
17
- end
18
- end
19
- end
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "schema_config/schema"
4
- require_relative "schema_config/config"