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 +4 -4
- data/.rubocop_todo.yml +25 -27
- data/README.adoc +130 -5
- data/lib/suma/cli/extract_terms.rb +443 -0
- data/lib/suma/cli/generate_schemas.rb +141 -0
- data/lib/suma/cli/reformat.rb +1 -1
- data/lib/suma/cli/validate_links.rb +2 -2
- data/lib/suma/cli.rb +20 -0
- data/lib/suma/collection_manifest.rb +3 -2
- data/lib/suma/processor.rb +0 -1
- data/lib/suma/schema_attachment.rb +3 -3
- data/lib/suma/schema_collection.rb +2 -2
- data/lib/suma/version.rb +1 -1
- data/lib/suma.rb +1 -0
- data/suma.gemspec +1 -0
- metadata +18 -5
- data/lib/suma/schema_config/config.rb +0 -147
- data/lib/suma/schema_config/schema.rb +0 -19
- data/lib/suma/schema_config.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52836adb9e003f9d760a6c015207379be88b8821855d64388a5f30d09474de7e
|
4
|
+
data.tar.gz: d7427de3e6dc21291671122bd07bc23c739e4f59f031e3b02988f89254767d00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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-
|
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:
|
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:
|
47
|
-
#
|
48
|
-
|
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:
|
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:
|
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:
|
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:
|
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:
|
108
|
+
# Offense count: 9
|
117
109
|
# Configuration parameters: CountAsOne.
|
118
110
|
RSpec/ExampleLength:
|
119
|
-
Max:
|
111
|
+
Max: 44
|
120
112
|
|
121
|
-
# Offense count:
|
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
|
41
|
-
suma reformat EXPRESS_FILE_PATH
|
42
|
-
suma validate SUBCOMMAND ...ARGS
|
43
|
-
suma
|
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
|
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
|
data/lib/suma/cli/reformat.rb
CHANGED
@@ -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.
|
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 =
|
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 ||
|
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 =
|
131
|
+
@schema_config = Expressir::SchemaManifest.from_file(schemas_yaml_path)
|
131
132
|
end
|
132
133
|
end
|
133
134
|
end
|
data/lib/suma/processor.rb
CHANGED
@@ -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 =
|
72
|
-
@config.schemas <<
|
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
|
-
|
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 &&
|
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
data/lib/suma.rb
CHANGED
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.
|
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-
|
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
|
data/lib/suma/schema_config.rb
DELETED