suma 0.1.14 → 0.1.16
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/.gitignore +4 -0
- data/.rubocop_todo.yml +25 -27
- data/README.adoc +57 -13
- data/lib/suma/cli/extract_terms.rb +397 -147
- data/lib/suma/cli/reformat.rb +1 -1
- data/lib/suma/cli/validate_links.rb +2 -2
- 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 +16 -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: 955161f5bfcd18f46e1fcafafdc05bea5a7310eaa8899b03552e7d22f6f41795
|
4
|
+
data.tar.gz: ff06abeaf766ce76d814079ef718c6deb45e1dd0cae5d89e9d03d203e3a5635d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2568587bc47fe2eb892fc7e9f8f4981aceaa06eef4b27ad54cb427e9082cc23571a2c26f8ae9380dfcd52fbb40f38a77ad0d2282e7ada54d8744e3e21edcd301
|
7
|
+
data.tar.gz: 4b8505d33b3eef150aeb76f23548f5983740d1940488a0ee1c7d6e515cd249e5fa74fbdadb72543a91104ca9ce609eb0f374dd01c033db8eee2bb7585525b09f
|
data/.gitignore
CHANGED
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
@@ -331,8 +331,10 @@ out which schemas the document includes.
|
|
331
331
|
|
332
332
|
=== Extract terms command
|
333
333
|
|
334
|
-
The `suma extract_terms` command extracts terms from
|
335
|
-
generates Glossarist v2 dataset in the output directory.
|
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.
|
336
338
|
|
337
339
|
[source,sh]
|
338
340
|
----
|
@@ -341,38 +343,80 @@ $ suma extract_terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH [options]
|
|
341
343
|
|
342
344
|
Parameters:
|
343
345
|
|
344
|
-
`SCHEMA_MANIFEST_FILE`:: Path to
|
346
|
+
`SCHEMA_MANIFEST_FILE`:: Path to the schema manifest file that lists all schemas
|
347
|
+
to process (e.g., "schemas-smrl-all.yml")
|
345
348
|
|
346
|
-
`GLOSSARIST_OUTPUT_PATH`:: Path to the output directory
|
347
|
-
dataset
|
349
|
+
`GLOSSARIST_OUTPUT_PATH`:: Path to the output directory where the Glossarist v2
|
350
|
+
dataset will be generated
|
348
351
|
|
349
352
|
Options:
|
350
353
|
|
351
|
-
|
354
|
+
`--language_code`, `-l`:: Language code for the Glossarist dataset (default: "eng")
|
352
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
|
353
392
|
[example]
|
354
393
|
====
|
355
|
-
.To extract terms from SCHEMA_MANIFEST_FILE
|
356
394
|
[source,sh]
|
357
395
|
----
|
358
|
-
$ bundle exec suma extract_terms
|
359
|
-
# => generates glossarist_output/concept
|
396
|
+
$ bundle exec suma extract_terms schemas-smrl-all.yml glossarist_output
|
397
|
+
# => generates glossarist_output/concept/*.yaml and glossarist_output/localized_concept/*.yaml
|
360
398
|
----
|
399
|
+
====
|
361
400
|
|
362
|
-
.To extract terms from
|
401
|
+
.To extract terms from a specific schema subset
|
402
|
+
[example]
|
403
|
+
====
|
363
404
|
[source,sh]
|
364
405
|
----
|
365
|
-
$ bundle exec suma extract_terms
|
366
|
-
# =>
|
406
|
+
$ bundle exec suma extract_terms schemas-activity-modules.yml terms_output
|
407
|
+
# => processes only schemas listed in the manifest file
|
367
408
|
----
|
368
409
|
====
|
369
410
|
|
411
|
+
The generated dataset is meant to be used for ISO 10303-2.
|
412
|
+
|
370
413
|
|
371
414
|
== Usage: Ruby
|
372
415
|
|
373
416
|
=== General
|
374
417
|
|
375
|
-
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.
|
376
420
|
|
377
421
|
=== Building collections
|
378
422
|
|
@@ -4,7 +4,6 @@ require "thor"
|
|
4
4
|
require_relative "../thor_ext"
|
5
5
|
require "fileutils"
|
6
6
|
require "expressir"
|
7
|
-
require "yaml"
|
8
7
|
require "securerandom"
|
9
8
|
require "glossarist"
|
10
9
|
|
@@ -13,29 +12,30 @@ module Suma
|
|
13
12
|
# ExtractTerms command using Expressir to extract terms into the
|
14
13
|
# Glossarist v2 format
|
15
14
|
class ExtractTerms < Thor
|
15
|
+
# Matches patterns like "A thing is a type of {{entity}}." or
|
16
|
+
# "An object is a type of a {{entity}}"
|
17
|
+
REDUNDANT_NOTE_REGEX =
|
18
|
+
%r{
|
19
|
+
^An? # Starts with "A" or "An"
|
20
|
+
\s.*?\sis\sa\stype\sof # Text followed by "is a type of"
|
21
|
+
(\sa|\san)? # Optional " a" or " an"
|
22
|
+
\s\{\{[^\}]*\}\} # Text in double curly braces
|
23
|
+
\s*?\.?$ # Optional whitespace and period at the end
|
24
|
+
}x
|
25
|
+
|
16
26
|
desc "extract_terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH",
|
17
27
|
"Extract terms from SCHEMA_MANIFEST_FILE into " \
|
18
28
|
"Glossarist v2 format"
|
19
29
|
option :language_code, type: :string, default: "eng", aliases: "-l",
|
20
30
|
desc: "Language code for the Glossarist"
|
21
31
|
|
22
|
-
|
23
|
-
|
24
|
-
def extract_terms(schema_manifest_file, output_path) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
32
|
+
def extract_terms(schema_manifest_file, output_path)
|
25
33
|
language_code = options[:language_code]
|
26
34
|
schema_manifest_file = File.expand_path(schema_manifest_file)
|
27
35
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
"`#{schema_manifest_file}` not found."
|
32
|
-
end
|
33
|
-
|
34
|
-
if !YAML_FILE_EXTENSIONS.include?(File.extname(schema_manifest_file))
|
35
|
-
raise ArgumentError, "Specified SCHEMA_MANIFEST_FILE " \
|
36
|
-
"`#{schema_manifest_file}` " \
|
37
|
-
"is not a YAML file."
|
38
|
-
end
|
36
|
+
unless File.exist?(schema_manifest_file)
|
37
|
+
raise Errno::ENOENT, "Specified SCHEMA_MANIFEST_FILE " \
|
38
|
+
"`#{schema_manifest_file}` not found."
|
39
39
|
end
|
40
40
|
|
41
41
|
run(schema_manifest_file, output_path, language_code)
|
@@ -44,152 +44,185 @@ module Suma
|
|
44
44
|
private
|
45
45
|
|
46
46
|
def run(schema_manifest_file, output_path, language_code = "eng")
|
47
|
-
|
48
|
-
|
49
|
-
exp_files.map do |exp_file|
|
47
|
+
get_exp_files(schema_manifest_file).map do |exp_file|
|
50
48
|
extract(exp_file, output_path, language_code)
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
52
|
def get_exp_files(schema_manifest_file)
|
55
|
-
|
56
|
-
|
57
|
-
permitted_classes: [Date, Time, Symbol],
|
58
|
-
permitted_symbols: [],
|
59
|
-
aliases: true,
|
60
|
-
)
|
61
|
-
|
62
|
-
paths = data["schemas"].values.filter_map { |v| v["path"] }
|
53
|
+
config = Expressir::SchemaManifest.from_file(schema_manifest_file)
|
54
|
+
paths = config.schemas.map(&:path)
|
63
55
|
|
64
56
|
if paths.empty?
|
65
57
|
raise Errno::ENOENT, "No EXPRESS files found in " \
|
66
58
|
"`#{schema_manifest_file}`."
|
67
59
|
end
|
68
60
|
|
69
|
-
|
70
|
-
paths.map do |path|
|
71
|
-
File.expand_path(path, File.dirname(schema_manifest_file))
|
72
|
-
end
|
61
|
+
paths
|
73
62
|
end
|
74
63
|
|
75
|
-
def extract(exp_file, output_path, language_code)
|
76
|
-
|
64
|
+
def extract(exp_file, output_path, language_code)
|
65
|
+
exp_path_rel = Pathname.new(exp_file).relative_path_from(Pathname.getwd)
|
66
|
+
puts "Building terms: #{exp_path_rel}"
|
67
|
+
|
77
68
|
repo = Expressir::Express::Parser.from_file(exp_file)
|
78
69
|
schema = get_default_schema(repo)
|
79
70
|
|
71
|
+
unless schema.file
|
72
|
+
raise Error.new("Schema must have an associated file")
|
73
|
+
end
|
74
|
+
|
80
75
|
collection = build_managed_concept_collection(
|
81
76
|
schema, language_code
|
82
77
|
)
|
83
78
|
|
84
|
-
output_data(collection, output_path
|
79
|
+
output_data(collection, output_path)
|
85
80
|
end
|
86
81
|
|
87
|
-
def output_data(collection, output_path
|
82
|
+
def output_data(collection, output_path)
|
88
83
|
unless File.exist?(output_path)
|
89
84
|
FileUtils.mkdir_p(File.expand_path(output_path))
|
90
85
|
end
|
91
86
|
|
92
|
-
puts "Saving collection to files in: #{
|
87
|
+
puts "Saving collection to files in: #{output_path}"
|
93
88
|
collection.save_to_files(File.expand_path(output_path))
|
94
89
|
|
95
|
-
puts "Processing EXPRESS file: #{exp_file}...Done."
|
96
90
|
collection
|
97
91
|
end
|
98
92
|
|
99
|
-
def build_managed_concept_collection(schema, language_code)
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
schema
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
93
|
+
def build_managed_concept_collection(schema, language_code)
|
94
|
+
Glossarist::ManagedConceptCollection.new.tap do |collection|
|
95
|
+
# Extract schema-level citation data once to reuse across all entities
|
96
|
+
source_ref = get_source_ref(schema)
|
97
|
+
|
98
|
+
# Create one concept per entity
|
99
|
+
schema.entities.each do |entity|
|
100
|
+
localized_concept = build_localized_concept(
|
101
|
+
schema: schema,
|
102
|
+
entity: entity,
|
103
|
+
language_code: language_code,
|
104
|
+
source_ref: source_ref,
|
105
|
+
)
|
106
|
+
|
107
|
+
managed_data = Glossarist::ManagedConceptData.new.tap do |data|
|
108
|
+
data.id = get_entity_identifier(schema, entity)
|
109
|
+
|
110
|
+
# TODO: Why do we need both localizations and localized_concepts??
|
111
|
+
data.localizations[language_code] = localized_concept
|
112
|
+
# uuid is automatically set from the serialization of the object
|
113
|
+
data.localized_concepts = {
|
114
|
+
language_code => get_localized_concept_identifier(
|
115
|
+
schema, entity, language_code
|
116
|
+
),
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
managed_concept = Glossarist::ManagedConcept.new.tap do |concept|
|
121
|
+
# uuid is automatically set from the serialization of the object
|
122
|
+
concept.id = get_entity_identifier(schema, entity)
|
123
|
+
concept.uuid = concept.id
|
124
|
+
concept.data = managed_data
|
125
|
+
end
|
126
|
+
|
127
|
+
collection.store(managed_concept)
|
128
|
+
end
|
129
|
+
end
|
122
130
|
end
|
123
131
|
|
124
|
-
def build_localized_concept(schema
|
132
|
+
def build_localized_concept(schema:, entity:, language_code:, source_ref:)
|
125
133
|
schema_domain = get_domain(schema)
|
126
134
|
|
127
|
-
localized_concept_data = Glossarist::ConceptData.new
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
localized_concept_data.language_code = language_code
|
134
|
-
localized_concept_data.domain = schema_domain
|
135
|
-
localized_concept_data.sources = get_source_ref(schema) || []
|
135
|
+
localized_concept_data = Glossarist::ConceptData.new.tap do |data|
|
136
|
+
data.terms = get_entity_terms(entity)
|
137
|
+
data.definition = get_entity_definitions(entity, schema)
|
138
|
+
data.language_code = language_code
|
139
|
+
data.domain = schema_domain
|
140
|
+
data.sources = [source_ref] if source_ref
|
136
141
|
|
137
|
-
|
138
|
-
|
142
|
+
# Only assign optional fields if they have content
|
143
|
+
notes = get_entity_notes(entity, schema_domain, data.definition)
|
144
|
+
data.notes = notes if notes && !notes.empty?
|
145
|
+
|
146
|
+
# examples = get_entity_examples(entity, schema_domain)
|
147
|
+
# data.examples = examples if examples && !examples.empty?
|
148
|
+
data.examples = []
|
149
|
+
end
|
139
150
|
|
140
|
-
|
141
|
-
|
151
|
+
Glossarist::LocalizedConcept.new.tap do |concept|
|
152
|
+
concept.data = localized_concept_data
|
153
|
+
end
|
142
154
|
end
|
143
155
|
|
156
|
+
# We only deal with 1 schema
|
144
157
|
def get_default_schema(repo)
|
145
158
|
repo.schemas.first
|
146
159
|
end
|
147
160
|
|
148
|
-
def
|
149
|
-
|
150
|
-
s.id == "__identifier"
|
151
|
-
end
|
152
|
-
remark_item.remarks.first || SecureRandom.uuid
|
161
|
+
def find_remark_value(schema, remark_id)
|
162
|
+
schema.remark_items.find { |s| s.id == remark_id }&.remarks&.first
|
153
163
|
end
|
154
164
|
|
155
|
-
def
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
165
|
+
def get_entity_identifier(schema, entity)
|
166
|
+
"#{schema.id}.#{entity.id}"
|
167
|
+
end
|
168
|
+
|
169
|
+
def get_localized_concept_identifier(schema, entity, lang)
|
170
|
+
"#{schema.id}.#{entity.id}-#{lang}"
|
160
171
|
end
|
161
172
|
|
162
173
|
def get_source_ref(schema)
|
163
|
-
|
164
|
-
|
174
|
+
origin = Glossarist::Citation.new.tap do |citation|
|
175
|
+
citation.ref = "ISO 10303"
|
176
|
+
custom_locality = build_custom_locality(schema)
|
177
|
+
|
178
|
+
unless custom_locality.empty?
|
179
|
+
citation.custom_locality = custom_locality
|
180
|
+
end
|
165
181
|
end
|
166
|
-
ref = remark_item&.remarks&.first
|
167
182
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
183
|
+
Glossarist::ConceptSource.new(type: "authoritative", origin: origin)
|
184
|
+
end
|
185
|
+
|
186
|
+
# SCHEMA action_schema
|
187
|
+
# '{iso standard 10303 part(41) version(9) object(1) action-schema(1)}';
|
188
|
+
def build_custom_locality(schema)
|
189
|
+
[].tap do |localities|
|
190
|
+
# Add schema name
|
191
|
+
localities << Glossarist::CustomLocality.new(
|
192
|
+
name: "schema",
|
193
|
+
value: schema.id,
|
172
194
|
)
|
195
|
+
|
196
|
+
# Add version if available
|
197
|
+
version_item = schema.version.items.detect { |i| i.name == "version" }
|
198
|
+
if version_item
|
199
|
+
localities << Glossarist::CustomLocality.new(
|
200
|
+
name: "version",
|
201
|
+
value: version_item.value,
|
202
|
+
)
|
203
|
+
end
|
173
204
|
end
|
174
205
|
end
|
175
206
|
|
207
|
+
# TODO: What if this was a "bom"?
|
176
208
|
def get_domain(schema)
|
177
|
-
prefix =
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
remark_item = schema.remark_items.find do |s|
|
183
|
-
s.id == "__schema_file"
|
184
|
-
end
|
209
|
+
prefix = if mim?(schema.id) || arm?(schema.id)
|
210
|
+
"application module"
|
211
|
+
else
|
212
|
+
"resource"
|
213
|
+
end
|
185
214
|
|
186
|
-
|
215
|
+
"#{prefix}: #{schema.id}"
|
187
216
|
end
|
188
217
|
|
189
218
|
def arm?(schema_id)
|
190
219
|
schema_id.end_with?("_arm")
|
191
220
|
end
|
192
221
|
|
222
|
+
def mim?(schema_id)
|
223
|
+
schema_id.end_with?("_mim")
|
224
|
+
end
|
225
|
+
|
193
226
|
def get_terms(schema)
|
194
227
|
schema_title = get_title(schema)
|
195
228
|
if schema_title
|
@@ -203,69 +236,291 @@ module Suma
|
|
203
236
|
end
|
204
237
|
end
|
205
238
|
|
206
|
-
def
|
207
|
-
|
239
|
+
def get_entity_terms(entity)
|
240
|
+
# For now, use the entity ID as the term
|
241
|
+
# This could be enhanced to look for entity-specific title remark items
|
242
|
+
[
|
243
|
+
Glossarist::Designation::Base.new(
|
244
|
+
designation: entity.id,
|
245
|
+
type: "expression",
|
246
|
+
normative_status: "preferred",
|
247
|
+
),
|
248
|
+
]
|
249
|
+
end
|
208
250
|
|
209
|
-
|
251
|
+
def get_entity_definitions(entity, schema)
|
252
|
+
schema_type = extract_file_type(schema.file)
|
253
|
+
schema_domain = get_domain(schema)
|
210
254
|
|
211
|
-
|
255
|
+
definition = generate_entity_definition(entity, schema_domain,
|
256
|
+
schema_type)
|
257
|
+
[Glossarist::DetailedDefinition.new(content: definition)]
|
212
258
|
end
|
213
259
|
|
214
|
-
def
|
215
|
-
|
216
|
-
|
260
|
+
def get_entity_notes(entity, schema_domain, definitions)
|
261
|
+
puts "Extracting notes for entity: #{entity.id}"
|
262
|
+
notes = []
|
263
|
+
|
264
|
+
notes = add_entity_notes(entity, schema_domain, notes)
|
265
|
+
# notes = add_other_notes(entity, schema_domain, notes)
|
266
|
+
notes = only_keep_first_sentence(notes)
|
267
|
+
notes = remove_see_content(notes)
|
268
|
+
notes = remove_redundant_note(notes)
|
269
|
+
notes = remove_invalid_references(notes)
|
270
|
+
compare_with_definitions(notes, definitions)
|
271
|
+
end
|
217
272
|
|
218
|
-
|
219
|
-
|
220
|
-
|
273
|
+
def add_entity_notes(entity, schema_domain, notes)
|
274
|
+
# Add trimmed definition from entity description as first note
|
275
|
+
if entity.remarks && !entity.remarks.empty?
|
276
|
+
trimmed_def = trim_definition(entity.remarks)
|
277
|
+
if trimmed_def && !trimmed_def.empty?
|
278
|
+
notes << Glossarist::DetailedDefinition.new(
|
279
|
+
content: convert_express_xref(trimmed_def, schema_domain),
|
280
|
+
)
|
281
|
+
end
|
221
282
|
end
|
222
283
|
|
223
|
-
|
224
|
-
when "arm"
|
225
|
-
"{{application object}} #{represent_str}"
|
226
|
-
else
|
227
|
-
"{{entity data type}} #{represent_str}"
|
228
|
-
end
|
229
|
-
[Glossarist::DetailedDefinition.new(content: definition)]
|
230
|
-
end
|
231
|
-
|
232
|
-
def get_subtype_of(schema)
|
233
|
-
schema.entities.first&.subtype_of&.first&.id # rubocop:disable Style/SafeNavigationChainLength
|
284
|
+
notes.compact
|
234
285
|
end
|
235
286
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
end&.map(&:remarks),
|
244
|
-
]
|
245
|
-
end&.flatten&.compact
|
287
|
+
def add_other_notes(entity, schema_domain, notes)
|
288
|
+
# Add other notes from entity remarks
|
289
|
+
other_notes = [
|
290
|
+
entity.remark_items&.select do |ri|
|
291
|
+
ri.id == "__note"
|
292
|
+
end&.map(&:remarks),
|
293
|
+
].flatten.compact
|
246
294
|
|
247
|
-
|
248
|
-
Glossarist::DetailedDefinition.new(
|
295
|
+
other_notes.each do |note|
|
296
|
+
notes << Glossarist::DetailedDefinition.new(
|
249
297
|
content: convert_express_xref(note, schema_domain),
|
250
298
|
)
|
251
299
|
end
|
300
|
+
|
301
|
+
notes
|
252
302
|
end
|
253
303
|
|
254
|
-
#
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
304
|
+
# https://github.com/metanorma/iso-10303/issues/621
|
305
|
+
# 1. First sentence in first paragraph of the entity description
|
306
|
+
# (in EXPRESS remark) becomes NOTE 1 in ISO 10303-2 of the entity.
|
307
|
+
def only_keep_first_sentence(notes)
|
308
|
+
notes.each do |note|
|
309
|
+
# Split by period and take the first sentence
|
310
|
+
# Avoid splitting by pattern like "abc.def"
|
311
|
+
if note&.content
|
312
|
+
new_content = note.content
|
313
|
+
.split(".\n").first.strip
|
314
|
+
.split(". ").first.strip
|
315
|
+
note.content = if new_content.end_with?(".")
|
316
|
+
new_content
|
317
|
+
else
|
318
|
+
"#{new_content}."
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# https://github.com/metanorma/iso-10303/issues/621
|
325
|
+
# 2. If this first sentence matches the 7-word magic sentence
|
326
|
+
# (2-3 forms of that), it is discarded so there will not be a NOTE 1.
|
327
|
+
def compare_with_definitions(notes, definitions)
|
328
|
+
if notes&.first&.content == definitions&.first&.content
|
329
|
+
# Discarding first note as it matches the definition
|
330
|
+
return []
|
331
|
+
end
|
332
|
+
|
333
|
+
notes
|
334
|
+
end
|
335
|
+
|
336
|
+
# https://github.com/metanorma/iso-10303/issues/621
|
337
|
+
# 3. No reference to any types or attribute or figures allowed in first
|
338
|
+
# sentence. Entity references “{{…}}” are allowed.
|
339
|
+
def remove_invalid_references(notes)
|
340
|
+
notes.reject do |note|
|
341
|
+
note.content.include?("image::") ||
|
342
|
+
note.content.match?(/<<(.*?){1,999}>>/)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
# https://github.com/metanorma/iso-10303/issues/621
|
347
|
+
# 4. Entity notes and examples in EXPRESS remarks are NOT represented in
|
348
|
+
# part 2.
|
349
|
+
def remove_redundant_note(notes)
|
350
|
+
notes.reject do |note|
|
351
|
+
note.content.match?(REDUNDANT_NOTE_REGEX) &&
|
352
|
+
!note.content.include?("\n")
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# https://github.com/metanorma/iso-10303/issues/621
|
357
|
+
# 5. If the sentence contains “\s+(see …)”, the contents including the
|
358
|
+
# parentheses are removed.
|
359
|
+
def remove_see_content(notes)
|
360
|
+
notes.each do |note|
|
361
|
+
note.content = note.content.gsub(/\s+\(see(.*?){1,999}\)/, "")
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def get_entity_examples(entity, schema_domain)
|
366
|
+
examples = entity.remark_items&.select do |ri|
|
367
|
+
ri.id == "__example"
|
368
|
+
end&.map(&:remarks)&.flatten&.compact || []
|
261
369
|
|
262
|
-
examples
|
370
|
+
examples.map do |example|
|
263
371
|
Glossarist::DetailedDefinition.new(
|
264
372
|
content: convert_express_xref(example, schema_domain),
|
265
373
|
)
|
266
374
|
end
|
267
375
|
end
|
268
376
|
|
377
|
+
def extract_file_type(filename)
|
378
|
+
match = filename.match(/(arm|mim|bom)_annotated\.exp$/)
|
379
|
+
return "resource" unless match
|
380
|
+
|
381
|
+
{
|
382
|
+
"arm" => "module_arm",
|
383
|
+
"mim" => "module_mim",
|
384
|
+
"bom" => "business_object_model",
|
385
|
+
}[match.captures[0]] || "resource"
|
386
|
+
end
|
387
|
+
|
388
|
+
def get_schema_type(schema)
|
389
|
+
return "mim" if mim?(schema.id)
|
390
|
+
return "arm" if arm?(schema.id)
|
391
|
+
return "bom" if bom?(schema.id)
|
392
|
+
|
393
|
+
"resource"
|
394
|
+
end
|
395
|
+
|
396
|
+
def bom?(schema_id)
|
397
|
+
schema_id.end_with?("_bom")
|
398
|
+
end
|
399
|
+
|
400
|
+
# rubocop:disable Metrics/MethodLength
|
401
|
+
def combine_paragraphs(full_paragraph, next_paragraph)
|
402
|
+
# If full_paragraph already contains a period, extract that.
|
403
|
+
if m = full_paragraph.match(/\A(?<inner_first>[^\n]*?\.)\s/)
|
404
|
+
# puts "CONDITION 1"
|
405
|
+
if m[:inner_first]
|
406
|
+
return m[:inner_first]
|
407
|
+
else
|
408
|
+
return full_paragraph
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
# If full_paragraph ends with a period, this is the last.
|
413
|
+
if /\.\s*\Z/.match?(full_paragraph)
|
414
|
+
# puts "CONDITION 2"
|
415
|
+
return full_paragraph
|
416
|
+
end
|
417
|
+
|
418
|
+
# If next_paragraph is a list
|
419
|
+
if next_paragraph.start_with?("*")
|
420
|
+
# puts "CONDITION 3"
|
421
|
+
return "#{full_paragraph}\n\n#{next_paragraph}"
|
422
|
+
end
|
423
|
+
|
424
|
+
# If next_paragraph is a continuation of a list
|
425
|
+
if next_paragraph.start_with?("which", "that")
|
426
|
+
# puts "CONDITION 4"
|
427
|
+
return "#{full_paragraph}\n\n#{next_paragraph}"
|
428
|
+
end
|
429
|
+
|
430
|
+
# puts "CONDITION 5"
|
431
|
+
full_paragraph
|
432
|
+
end
|
433
|
+
|
434
|
+
def trim_definition(definition)
|
435
|
+
return nil if definition.nil? || definition.empty?
|
436
|
+
|
437
|
+
# Handle case where definition is an array
|
438
|
+
definition_str = if definition.is_a?(Array)
|
439
|
+
definition.join("\n\n")
|
440
|
+
else
|
441
|
+
definition.to_s
|
442
|
+
end
|
443
|
+
|
444
|
+
return nil if definition_str.empty?
|
445
|
+
|
446
|
+
# Unless the first paragraph ends with "between" and is followed by a
|
447
|
+
# list, don't split
|
448
|
+
paragraphs = definition_str.split("\n\n")
|
449
|
+
|
450
|
+
# puts paragraphs.inspect
|
451
|
+
|
452
|
+
first_paragraph = paragraphs.first
|
453
|
+
|
454
|
+
combined = if paragraphs.length > 1
|
455
|
+
paragraphs[1..].inject(first_paragraph) do |acc, p|
|
456
|
+
combine_paragraphs(acc, p)
|
457
|
+
end
|
458
|
+
else
|
459
|
+
combine_paragraphs(first_paragraph, "")
|
460
|
+
end
|
461
|
+
|
462
|
+
# puts "combined--------- #{combined}"
|
463
|
+
|
464
|
+
# Remove comments until end of line
|
465
|
+
combined = "#{combined}\n"
|
466
|
+
combined.gsub!(/\n\/\/.*?\n/, "\n")
|
467
|
+
combined.strip!
|
468
|
+
|
469
|
+
express_reference_to_mention(combined)
|
470
|
+
end
|
471
|
+
# rubocop:enable Metrics/MethodLength
|
472
|
+
|
473
|
+
# Replace `<<express:{schema}.{entity}>>` with {{entity}}
|
474
|
+
# and `<<express:{schema}.{entity},{render}>>` with {{entity,render}}
|
475
|
+
def express_reference_to_mention(description)
|
476
|
+
# TODO: Use Expressir to check whether the "entity" is really an
|
477
|
+
# EXPRESS ENTITY. If not, skip the mention.
|
478
|
+
description
|
479
|
+
.gsub(/<<express:([^,]+)>>/) do |_match|
|
480
|
+
"{{#{Regexp.last_match[1].split('.').last}}}"
|
481
|
+
end.gsub(/<<express:([^,]+),([^>]+)>>/) do |_match|
|
482
|
+
"{{#{Regexp.last_match[1].split('.').last}," \
|
483
|
+
"#{Regexp.last_match[2]}}}"
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
def entity_name_to_text(entity_id)
|
488
|
+
entity_id.downcase.gsub("_", " ")
|
489
|
+
end
|
490
|
+
|
491
|
+
# rubocop:disable Layout/LineLength
|
492
|
+
def generate_entity_definition(entity, _domain, schema_type)
|
493
|
+
return "" if entity.nil?
|
494
|
+
|
495
|
+
# See: metanorma/iso-10303-2#90
|
496
|
+
entity_type = case schema_type
|
497
|
+
when "module_arm"
|
498
|
+
"{{application object}}"
|
499
|
+
when "module_mim"
|
500
|
+
"{{entity data type}}"
|
501
|
+
when "resource", "business_object_model"
|
502
|
+
"{{entity data type}}"
|
503
|
+
else
|
504
|
+
raise Error.new("[suma] encountered unsupported schema_type")
|
505
|
+
end
|
506
|
+
|
507
|
+
if entity.subtype_of.empty?
|
508
|
+
"#{entity_type} " \
|
509
|
+
"that represents the " \
|
510
|
+
"#{entity_name_to_text(entity.id)} {{entity}}"
|
511
|
+
else
|
512
|
+
entity_subtypes = entity.subtype_of.map do |e|
|
513
|
+
"{{#{e.id}}}"
|
514
|
+
end
|
515
|
+
|
516
|
+
"#{entity_type} that is a type of " \
|
517
|
+
"#{entity_subtypes.join(' and ')} " \
|
518
|
+
"that represents the " \
|
519
|
+
"#{entity_name_to_text(entity.id)} {{entity}}"
|
520
|
+
end
|
521
|
+
end
|
522
|
+
# rubocop:enable Layout/LineLength
|
523
|
+
|
269
524
|
def convert_express_xref(content, schema_domain)
|
270
525
|
content.gsub(/<<express:(.*),(.*)>>/) do
|
271
526
|
"{{<#{schema_domain}>" \
|
@@ -273,13 +528,8 @@ module Suma
|
|
273
528
|
end
|
274
529
|
end
|
275
530
|
|
276
|
-
def
|
277
|
-
|
278
|
-
"#{sanitize_string(identifier)}.yaml"
|
279
|
-
end
|
280
|
-
|
281
|
-
def sanitize_string(str)
|
282
|
-
str.gsub(" ", "_").gsub("/", "_").gsub(":", "_")
|
531
|
+
def id_from_designation(designation)
|
532
|
+
designation.gsub(" ", "_").gsub("/", "_").gsub(":", "_")
|
283
533
|
end
|
284
534
|
end
|
285
535
|
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
|
@@ -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.16
|
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-11 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
|
@@ -146,9 +160,6 @@ files:
|
|
146
160
|
- lib/suma/processor.rb
|
147
161
|
- lib/suma/schema_attachment.rb
|
148
162
|
- lib/suma/schema_collection.rb
|
149
|
-
- lib/suma/schema_config.rb
|
150
|
-
- lib/suma/schema_config/config.rb
|
151
|
-
- lib/suma/schema_config/schema.rb
|
152
163
|
- lib/suma/schema_document.rb
|
153
164
|
- lib/suma/site_config.rb
|
154
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