expressir 2.3.6 → 2.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +1 -1
  3. data/.gitignore +2 -0
  4. data/.rubocop_todo.yml +17 -12
  5. data/CHANGELOG.md +159 -0
  6. data/docs/_guides/ler/step-packages.adoc +385 -0
  7. data/lib/expressir/coverage.rb +4 -4
  8. data/lib/expressir/express/builder_registry.rb +3 -1
  9. data/lib/expressir/express/builders/expression_builder.rb +2 -2
  10. data/lib/expressir/express/builders/helpers.rb +2 -8
  11. data/lib/expressir/express/builders/qualifier_builder.rb +2 -1
  12. data/lib/expressir/express/formatter.rb +32 -164
  13. data/lib/expressir/express/formatters/data_types_formatter.rb +39 -6
  14. data/lib/expressir/express/formatters/declarations_formatter.rb +47 -8
  15. data/lib/expressir/express/formatters/expressions_formatter.rb +20 -5
  16. data/lib/expressir/express/formatters/literals_formatter.rb +11 -1
  17. data/lib/expressir/express/formatters/references_formatter.rb +10 -1
  18. data/lib/expressir/express/formatters/remark_formatter.rb +1 -89
  19. data/lib/expressir/express/formatters/remark_item_formatter.rb +5 -4
  20. data/lib/expressir/express/formatters/statements_formatter.rb +32 -9
  21. data/lib/expressir/express/formatters/supertype_expressions_formatter.rb +7 -3
  22. data/lib/expressir/express/hyperlink_formatter.rb +1 -3
  23. data/lib/expressir/express/model_visitor.rb +1 -1
  24. data/lib/expressir/express/pretty_formatter.rb +31 -108
  25. data/lib/expressir/express/remark_attacher.rb +118 -88
  26. data/lib/expressir/express/schema_head_formatter.rb +1 -3
  27. data/lib/expressir/model/concerns.rb +6 -0
  28. data/lib/expressir/model/declarations/interface_item.rb +2 -0
  29. data/lib/expressir/model/declarations/interfaced_item.rb +3 -0
  30. data/lib/expressir/model/declarations/remark_item.rb +3 -0
  31. data/lib/expressir/model/declarations/schema.rb +7 -5
  32. data/lib/expressir/model/exp_file.rb +1 -0
  33. data/lib/expressir/model/identifier.rb +3 -1
  34. data/lib/expressir/model/model_element.rb +3 -3
  35. data/lib/expressir/model/repository.rb +8 -0
  36. data/lib/expressir/model/search_engine.rb +1 -1
  37. data/lib/expressir/package/reader.rb +9 -24
  38. data/lib/expressir/version.rb +1 -1
  39. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6af1982d1df8fc35cf696c67614f670e45386121feb42b962290a8b40acbc7f6
4
- data.tar.gz: c03425e140c7b68391efef97105a3c86124d4269a8bb564515b0e83596a62932
3
+ metadata.gz: ecbd13317e56cc0139eb317331134c80ba9f5ae95eaf221f2f5e2046ebe95387
4
+ data.tar.gz: 86dbdfe6818f5c751d11c6fc4cd81e53a60b38145d3f7d80f5bd1b5ff6869815
5
5
  SHA512:
6
- metadata.gz: a330cbcd461ed7099e473a4a3d8c689f238096afce4c581b35a198bc487ddf5bd7a8bb777af698b1553efc1950eb878aa03874cc0b6904cb451b95a128962998
7
- data.tar.gz: 1c995702e07eb2756811f35cbde5dfad4f1d32452c77a45404d551a1bfce1e374789219c72be5383eb5f804cf4489aee05cb2e29def2245ddd2d40cf591fa4c3
6
+ metadata.gz: b3b26b8456c55b2a5b342d508a2af8f1e3c46ed23f78b96b5900a036292533c33b68f140248f6c8b552f5ed571adc245fe71acf1159b21feca3aa6c0b7bb354f
7
+ data.tar.gz: 3d33e2d5c850898a8b451a91cd76a9a85736b7e4c6d846c29e1652dc5e8fbb080bec35b2c55a908c7da68bdb32c5b7940162ea88cd811a519643a5f97db65fcf
@@ -3,7 +3,7 @@
3
3
  name: rake
4
4
 
5
5
  permissions:
6
- contents: read
6
+ contents: write
7
7
  pull-requests: write
8
8
 
9
9
  on:
data/.gitignore CHANGED
@@ -32,6 +32,7 @@ Gemfile.lock
32
32
  *.ler
33
33
  *.pax
34
34
  TODO.*.md
35
+ TODO.refactor/
35
36
  debug_*.rb
36
37
  measure_mem.rb
37
38
  tmp_*.rb
@@ -40,3 +41,4 @@ Gemfile.local
40
41
  Gemfile.local.lock
41
42
  Gemfile.original
42
43
  benchmark/
44
+ CLAUDE.md
data/.rubocop_todo.yml CHANGED
@@ -1,12 +1,12 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-05-12 14:41:49 UTC using RuboCop version 1.86.0.
3
+ # on 2026-06-05 10:03:10 UTC using RuboCop version 1.86.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
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 1084
9
+ # Offense count: 1072
10
10
  # This cop supports safe autocorrection (--autocorrect).
11
11
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
12
12
  # URISchemes: http, https
@@ -24,11 +24,10 @@ Lint/DuplicateBranch:
24
24
  - 'lib/expressir/express/remark_attacher.rb'
25
25
  - 'lib/expressir/model/search_engine.rb'
26
26
 
27
- # Offense count: 2
27
+ # Offense count: 1
28
28
  Lint/DuplicateCaseCondition:
29
29
  Exclude:
30
30
  - 'lib/expressir/commands/package.rb'
31
- - 'lib/expressir/express/formatter.rb'
32
31
 
33
32
  # Offense count: 1
34
33
  Lint/DuplicateMethods:
@@ -51,7 +50,12 @@ Lint/UnusedMethodArgument:
51
50
  - 'lib/expressir/express/cache.rb'
52
51
  - 'lib/expressir/express/parser.rb'
53
52
 
54
- # Offense count: 239
53
+ # Offense count: 2
54
+ Lint/UselessConstantScoping:
55
+ Exclude:
56
+ - 'lib/expressir/express/remark_attacher.rb'
57
+
58
+ # Offense count: 240
55
59
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
56
60
  Metrics/AbcSize:
57
61
  Enabled: false
@@ -67,12 +71,12 @@ Metrics/BlockLength:
67
71
  Metrics/BlockNesting:
68
72
  Max: 6
69
73
 
70
- # Offense count: 194
74
+ # Offense count: 190
71
75
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
72
76
  Metrics/CyclomaticComplexity:
73
77
  Enabled: false
74
78
 
75
- # Offense count: 289
79
+ # Offense count: 290
76
80
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
77
81
  Metrics/MethodLength:
78
82
  Max: 167
@@ -82,7 +86,7 @@ Metrics/MethodLength:
82
86
  Metrics/ParameterLists:
83
87
  Max: 8
84
88
 
85
- # Offense count: 167
89
+ # Offense count: 162
86
90
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
87
91
  Metrics/PerceivedComplexity:
88
92
  Enabled: false
@@ -151,7 +155,7 @@ RSpec/ContextWording:
151
155
  - 'spec/expressir/commands/validate_ascii_spec.rb'
152
156
  - 'spec/expressir/model/repository_spec.rb'
153
157
 
154
- # Offense count: 1
158
+ # Offense count: 2
155
159
  # Configuration parameters: IgnoredMetadata.
156
160
  RSpec/DescribeClass:
157
161
  Exclude:
@@ -160,6 +164,7 @@ RSpec/DescribeClass:
160
164
  - '**/spec/routing/**/*'
161
165
  - '**/spec/system/**/*'
162
166
  - '**/spec/views/**/*'
167
+ - 'spec/expressir/express/formatter_architecture_spec.rb'
163
168
  - 'spec/expressir/integration/package_roundtrip_spec.rb'
164
169
 
165
170
  # Offense count: 6
@@ -172,7 +177,7 @@ RSpec/DescribeMethod:
172
177
  - 'spec/expressir/model/repository_statistics_spec.rb'
173
178
  - 'spec/expressir/model/search_engine_advanced_spec.rb'
174
179
 
175
- # Offense count: 453
180
+ # Offense count: 480
176
181
  # Configuration parameters: CountAsOne.
177
182
  RSpec/ExampleLength:
178
183
  Max: 122
@@ -213,7 +218,7 @@ RSpec/IteratedExpectation:
213
218
  RSpec/MessageSpies:
214
219
  EnforcedStyle: receive
215
220
 
216
- # Offense count: 583
221
+ # Offense count: 596
217
222
  RSpec/MultipleExpectations:
218
223
  Max: 114
219
224
 
@@ -253,7 +258,7 @@ RSpec/SpecFilePathFormat:
253
258
  - 'spec/expressir/model/repository_statistics_spec.rb'
254
259
  - 'spec/expressir/model/search_engine_advanced_spec.rb'
255
260
 
256
- # Offense count: 4
261
+ # Offense count: 2
257
262
  Security/MarshalLoad:
258
263
  Exclude:
259
264
  - 'lib/expressir/package/reader.rb'
data/CHANGELOG.md ADDED
@@ -0,0 +1,159 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Breaking Changes
11
+
12
+ #### Repository Structure Change
13
+
14
+ The `Repository` class now uses a `files` attribute containing `ExpFile` objects instead of a direct `schemas` attribute.
15
+
16
+ **Old structure:**
17
+ ```ruby
18
+ repository = Expressir::Model::Repository.new
19
+ repository.schemas << schema1
20
+ repository.schemas << schema2
21
+ ```
22
+
23
+ **New structure:**
24
+ ```ruby
25
+ repository = Expressir::Model::Repository.new
26
+ repository.add_schema(schema1)
27
+ repository.add_schema(schema2)
28
+
29
+ # Or with files:
30
+ exp_file = Expressir::Express::Parser.from_file("schema.exp")
31
+ repository.files << exp_file
32
+ ```
33
+
34
+ #### ExpFile Model Introduced
35
+
36
+ A new `ExpFile` class represents a single EXPRESS file with its own preamble remarks and schemas:
37
+
38
+ ```ruby
39
+ # ExpFile has:
40
+ # - path: the file path
41
+ # - schemas: array of schemas in the file
42
+ # - untagged_remarks: file-level preamble remarks
43
+
44
+ exp_file = Expressir::Model::ExpFile.new(path: "my_schema.exp")
45
+ exp_file.schemas = [schema]
46
+ exp_file.untagged_remarks = [remark_info]
47
+ ```
48
+
49
+ #### Parser Return Type Changed
50
+
51
+ `Expressir::Express::Parser.from_file` now returns an `ExpFile` instead of a `Repository`:
52
+
53
+ ```ruby
54
+ # Old: returned Repository
55
+ # New: returns ExpFile
56
+ exp_file = Expressir::Express::Parser.from_file("schema.exp")
57
+ exp_file.path # => "schema.exp"
58
+ exp_file.schemas # => [#<Expressir::Model::Declarations::Schema...>]
59
+ ```
60
+
61
+ #### Error Class Changes
62
+
63
+ - `InvalidSchemaManifestError` → Use `ManifestValidationError` instead
64
+ - `Expressir::Express::CacheVersionMismatchError` → Use `Expressir::Express::Error::CacheVersionMismatchError`
65
+
66
+ #### RemarkInfo Required
67
+
68
+ Remark formatters now require `RemarkInfo` objects instead of strings:
69
+
70
+ ```ruby
71
+ # Old:
72
+ formatter.format_preamble_remark("This is a remark")
73
+
74
+ # New:
75
+ remark = Expressir::Model::RemarkInfo.new(text: "This is a remark")
76
+ formatter.format_preamble_remark(remark)
77
+ ```
78
+
79
+ ### Added
80
+
81
+ - `Expressir::Model::ExpFile` class for representing EXPRESS files
82
+ - `Expressir::Model::Concerns` module with marker modules for O(1) type checking:
83
+ - `HasRemarkItems` - types that can have remark_items children
84
+ - `ScopeContainer` - types that can contain declarations
85
+ - `HasInformalPropositions` - types supporting informal propositions
86
+ - `HasWhereRules` - types supporting where rules
87
+ - `Repository#add_schema(schema)` method for adding schemas
88
+ - `Repository#files` attribute for storing ExpFile objects
89
+ - `Package::Builder#normalize_repository` ensures proper serialization format
90
+
91
+ ### Changed
92
+
93
+ - `Repository#schemas` now returns schemas from both `files` and internal storage
94
+ - `Parser.from_file` returns `ExpFile` instead of `Repository`
95
+ - `Parser.from_files` creates `Repository` with `ExpFile` objects
96
+ - `Parser.from_exp` returns `ExpFile` instead of `Repository`
97
+ - `format_repository` in formatters handles both file-based and direct schemas
98
+ - Preamble remarks now attach to `ExpFile` instead of first `Schema`
99
+
100
+ ### Removed
101
+
102
+ - All backward compatibility code for legacy serialized data
103
+ - `Repository#schemas=` writer (use `add_schema` instead)
104
+ - Legacy string handling in remark formatters
105
+ - `InvalidSchemaManifestError` alias (use `ManifestValidationError`)
106
+ - Legacy `@schemas` attribute migration in Repository
107
+ - Array-based type checking in `remark_attacher.rb` (replaced with module markers)
108
+
109
+ ### Migration Guide
110
+
111
+ #### Updating Code That Uses Repository
112
+
113
+ ```ruby
114
+ # Before:
115
+ repo = Expressir::Model::Repository.new
116
+ repo.schemas << schema
117
+
118
+ # After:
119
+ repo = Expressir::Model::Repository.new
120
+ repo.add_schema(schema)
121
+ ```
122
+
123
+ #### Updating Code That Parses Files
124
+
125
+ ```ruby
126
+ # Before:
127
+ repo = Expressir::Express::Parser.from_file("schema.exp")
128
+ schema = repo.schemas.first
129
+
130
+ # After:
131
+ exp_file = Expressir::Express::Parser.from_file("schema.exp")
132
+ schema = exp_file.schemas.first
133
+
134
+ # Or wrap in repository:
135
+ repo = Expressir::Model::Repository.new
136
+ repo.files << Expressir::Express::Parser.from_file("schema.exp")
137
+ ```
138
+
139
+ #### Updating Serialized Packages
140
+
141
+ Old `.ler` packages need to be regenerated with the new format:
142
+
143
+ ```ruby
144
+ # Load old package (will fail with new code)
145
+ # repo = Expressir::Model::Repository.from_package("old.ler")
146
+
147
+ # Regenerate by parsing original EXPRESS files
148
+ exp_file = Expressir::Express::Parser.from_file("schema.exp")
149
+ repo = Expressir::Model::Repository.new
150
+ repo.files << exp_file
151
+ repo.export_to_package("new.ler", name: "My Package", version: "1.0.0")
152
+ ```
153
+
154
+ ## [2.2.1] - 2024-03-14
155
+
156
+ ### Changed
157
+
158
+ - Refactored `require` to `autoload` pattern for better load performance
159
+ - Updated error handling to use error classes instead of `abort`
@@ -0,0 +1,385 @@
1
+ ---
2
+ title: STEP Standard Packages
3
+ parent: LER Packages
4
+ grand_parent: Guides
5
+ nav_order: 7
6
+ ---
7
+
8
+ = STEP Standard Packages (SRL, SML, SMRL)
9
+
10
+ == Purpose
11
+
12
+ This guide explains how to create and use LER packages from STEP standard
13
+ schema collections: the STEPmod Resource Library (SRL), STEPmod Module Library
14
+ (SML), and the combined STEP Resource and Module Library (SMRL).
15
+
16
+ == References
17
+
18
+ * link:creating-packages.html[Creating Packages]
19
+ * link:loading-packages.html[Loading Packages]
20
+ * link:querying-packages.html[Querying Packages]
21
+
22
+ == Concepts
23
+
24
+ SRL (STEPmod Resource Library):: The collection of 133 resource schemas that
25
+ define core EXPRESS types, entities, and functions used across STEP application
26
+ protocols. Located in `schemas/resources/` of the STEPmod distribution.
27
+
28
+ SML (STEP Module Library):: The collection of application modules (643 modules,
29
+ 1205 ARM and MIM schemas) that define modular data models. Located in
30
+ `schemas/modules/` of the STEPmod distribution.
31
+
32
+ SMRL (STEP Resource and Module Library):: The combined set of all SRL resource
33
+ schemas and SML module schemas (1341 total).
34
+
35
+ STEPmod:: The ISO 10303 standards maintenance and development toolkit that
36
+ contains the source EXPRESS schemas for STEP.
37
+
38
+ == Prerequisites
39
+
40
+ You need a local copy of the STEPmod distribution (ISO 10303 repository). The
41
+ schema directory structure looks like:
42
+
43
+ [source]
44
+ ----
45
+ iso-10303/
46
+ ├── schemas/
47
+ │ ├── resources/ # SRL: 133 resource schemas
48
+ │ │ ├── action_schema/
49
+ │ │ │ └── action_schema.exp
50
+ │ │ ├── geometry_schema/
51
+ │ │ │ └── geometry_schema.exp
52
+ │ │ └── ...
53
+ │ └── modules/ # SML: 643 modules, 1205 schemas
54
+ │ ├── colour/
55
+ │ │ ├── arm.exp
56
+ │ │ └── mim.exp
57
+ │ ├── geometry/
58
+ │ │ ├── arm.exp
59
+ │ │ └── mim.exp
60
+ │ └── ...
61
+ └── ...
62
+ ----
63
+
64
+ == Creating an SRL package
65
+
66
+ The SRL contains resource schemas that provide common definitions reused across
67
+ STEP application protocols.
68
+
69
+ === Using the Ruby API
70
+
71
+ [source,ruby]
72
+ ----
73
+ require "expressir"
74
+
75
+ base_dir = "/path/to/iso-10303"
76
+ resource_files = Dir.glob("#{base_dir}/schemas/resources/**/*.exp").sort
77
+
78
+ puts "Building SRL from #{resource_files.length} resource schemas..."
79
+
80
+ # Parse all resource schemas
81
+ repo = Expressir::Express::Parser.from_files(resource_files)
82
+
83
+ puts "Parsed #{repo.schemas.length} schemas"
84
+
85
+ # Export as LER package
86
+ repo.export_to_package(
87
+ "srl.ler",
88
+ name: "SRL",
89
+ description: "STEPmod Resource Library - ISO 10303 resource schemas",
90
+ serialization_format: "marshal"
91
+ )
92
+
93
+ puts "Created srl.ler"
94
+ ----
95
+
96
+ === Performance characteristics
97
+
98
+ [example]
99
+ ====
100
+ * 133 resource schemas
101
+ * Parse time: ~10 seconds
102
+ * Package size: ~5 MB
103
+ ====
104
+
105
+ == Creating an SML package
106
+
107
+ The SML contains application modules, each with ARM (Application Reference
108
+ Model) and MIM (Mapped Information Model) schemas.
109
+
110
+ === Using the Ruby API
111
+
112
+ [source,ruby]
113
+ ----
114
+ require "expressir"
115
+
116
+ base_dir = "/path/to/iso-10303"
117
+ module_files = Dir.glob("#{base_dir}/schemas/modules/**/{arm,mim}.exp").sort
118
+
119
+ puts "Building SML from #{module_files.length} module schemas..."
120
+
121
+ # Parse all module schemas
122
+ repo = Expressir::Express::Parser.from_files(module_files)
123
+
124
+ puts "Parsed #{repo.schemas.length} schemas"
125
+
126
+ # Export as LER package
127
+ repo.export_to_package(
128
+ "sml.ler",
129
+ name: "SML",
130
+ description: "STEP Module Library - ISO 10303 application modules",
131
+ serialization_format: "marshal"
132
+ )
133
+
134
+ puts "Created sml.ler"
135
+ ----
136
+
137
+ === Performance characteristics
138
+
139
+ [example]
140
+ ====
141
+ * 1205 module schemas (643 modules)
142
+ * Parse time: ~3 minutes
143
+ * Package size: ~14 MB
144
+ ====
145
+
146
+ == Creating an SMRL package
147
+
148
+ The SMRL combines all resource and module schemas into a single package.
149
+
150
+ === Using the Ruby API
151
+
152
+ [source,ruby]
153
+ ----
154
+ require "expressir"
155
+
156
+ base_dir = "/path/to/iso-10303"
157
+ resource_files = Dir.glob("#{base_dir}/schemas/resources/**/*.exp").sort
158
+ module_files = Dir.glob("#{base_dir}/schemas/modules/**/{arm,mim}.exp").sort
159
+ all_files = resource_files + module_files
160
+
161
+ puts "Building SMRL from #{all_files.length} schemas..."
162
+
163
+ # Parse all schemas
164
+ repo = Expressir::Express::Parser.from_files(all_files)
165
+
166
+ puts "Parsed #{repo.schemas.length} schemas"
167
+
168
+ # Export as LER package
169
+ repo.export_to_package(
170
+ "smrl.ler",
171
+ name: "SMRL",
172
+ description: "STEP Resource and Module Library - Complete ISO 10303 schemas",
173
+ serialization_format: "marshal"
174
+ )
175
+
176
+ puts "Created smrl.ler"
177
+ ----
178
+
179
+ === Performance characteristics
180
+
181
+ [example]
182
+ ====
183
+ * 1341 schemas (133 resources + 1205 modules)
184
+ * Parse time: ~8 minutes
185
+ * Package size: ~24 MB
186
+ ====
187
+
188
+ == Loading and searching packages
189
+
190
+ All three package types use the same loading and querying API.
191
+
192
+ === Loading a package
193
+
194
+ [source,ruby]
195
+ ----
196
+ require "expressir"
197
+
198
+ # Load any .ler package
199
+ repo = Expressir::Model::Repository.from_package("smrl.ler")
200
+ puts "Loaded #{repo.schemas.length} schemas"
201
+ ----
202
+
203
+ Load times are fast regardless of package size:
204
+
205
+ [example]
206
+ ====
207
+ * SRL (133 schemas): ~1 second
208
+ * SML (1205 schemas): ~3 seconds
209
+ * SMRL (1340 schemas): ~5 seconds
210
+ ====
211
+
212
+ === Finding entities by qualified name
213
+
214
+ Use `find_entity` for instant lookups when you know the schema and entity name:
215
+
216
+ [source,ruby]
217
+ ----
218
+ entity = repo.find_entity(qualified_name: "geometry_schema.axis2_placement_3d")
219
+ if entity
220
+ puts "Found: #{entity.id}"
221
+ puts "Schema: #{entity.parent.id}"
222
+ end
223
+ ----
224
+
225
+ === Listing all entities
226
+
227
+ [source,ruby]
228
+ ----
229
+ entities = repo.list_entities
230
+ puts "Total: #{entities.length} entities"
231
+
232
+ entities.first(5).each do |e|
233
+ puts " #{e.parent.id}.#{e.id}"
234
+ end
235
+ ----
236
+
237
+ === Listing entities from a specific schema
238
+
239
+ [source,ruby]
240
+ ----
241
+ entities = repo.list_entities(schema: "mathematical_functions_schema")
242
+ puts "Entities in mathematical_functions_schema: #{entities.length}"
243
+ ----
244
+
245
+ === Listing all types
246
+
247
+ [source,ruby]
248
+ ----
249
+ types = repo.list_types
250
+ puts "Total: #{types.length} types"
251
+ ----
252
+
253
+ === Finding a specific schema
254
+
255
+ [source,ruby]
256
+ ----
257
+ schema = repo.schemas.find { |s| s.id == "mathematical_functions_schema" }
258
+ if schema
259
+ puts "Entities: #{schema.entities&.length || 0}"
260
+ puts "Types: #{schema.types&.length || 0}"
261
+ puts "Functions: #{schema.functions&.length || 0}"
262
+ end
263
+ ----
264
+
265
+ === Using SearchEngine for pattern matching
266
+
267
+ [source,ruby]
268
+ ----
269
+ require "expressir"
270
+
271
+ repo = Expressir::Model::Repository.from_package("smrl.ler")
272
+ engine = Expressir::Model::SearchEngine.new(repo)
273
+
274
+ # Find all entities containing "product"
275
+ results = engine.search(pattern: "product", type: "entity")
276
+ results.each do |r|
277
+ puts "#{r[:schema]}.#{r[:id]}"
278
+ end
279
+
280
+ # Find all SELECT types
281
+ select_types = engine.list(type: "type", category: "select")
282
+ puts "SELECT types: #{select_types.length}"
283
+
284
+ # Wildcard search for geometry-related entities
285
+ results = engine.search(pattern: "geometry*")
286
+ ----
287
+
288
+ == Complete build script
289
+
290
+ Here is a complete script for building all three STEP packages:
291
+
292
+ [source,ruby]
293
+ ----
294
+ #!/usr/bin/env ruby
295
+ # build_step_packages.rb
296
+
297
+ require "expressir"
298
+ require "optparse"
299
+
300
+ options = {
301
+ stepmod_dir: nil,
302
+ output_dir: ".",
303
+ packages: ["srl", "sml", "smrl"]
304
+ }
305
+
306
+ OptionParser.new do |opts|
307
+ opts.banner = "Usage: build_step_packages.rb [options]"
308
+
309
+ opts.on("--stepmod DIR", "Path to iso-10303 directory") do |v|
310
+ options[:stepmod_dir] = v
311
+ end
312
+
313
+ opts.on("--output DIR", "Output directory (default: .)") do |v|
314
+ options[:output_dir] = v
315
+ end
316
+
317
+ opts.on("--packages LIST", "Comma-separated list: srl,sml,smrl") do |v|
318
+ options[:packages] = v.split(",")
319
+ end
320
+ end.parse!
321
+
322
+ abort("--stepmod is required") unless options[:stepmod_dir]
323
+
324
+ base_dir = options[:stepmod_dir]
325
+
326
+ if options[:packages].include?("srl")
327
+ puts "=== Building SRL ==="
328
+ files = Dir.glob("#{base_dir}/schemas/resources/**/*.exp").sort
329
+ repo = Expressir::Express::Parser.from_files(files)
330
+ output = File.join(options[:output_dir], "srl.ler")
331
+ repo.export_to_package(output,
332
+ name: "SRL",
333
+ description: "STEPmod Resource Library",
334
+ serialization_format: "marshal")
335
+ puts "Created #{output} (#{repo.schemas.length} schemas)"
336
+ end
337
+
338
+ if options[:packages].include?("sml")
339
+ puts "\n=== Building SML ==="
340
+ files = Dir.glob("#{base_dir}/schemas/modules/**/{arm,mim}.exp").sort
341
+ repo = Expressir::Express::Parser.from_files(files)
342
+ output = File.join(options[:output_dir], "sml.ler")
343
+ repo.export_to_package(output,
344
+ name: "SML",
345
+ description: "STEP Module Library",
346
+ serialization_format: "marshal")
347
+ puts "Created #{output} (#{repo.schemas.length} schemas)"
348
+ end
349
+
350
+ if options[:packages].include?("smrl")
351
+ puts "\n=== Building SMRL ==="
352
+ resource_files = Dir.glob("#{base_dir}/schemas/resources/**/*.exp").sort
353
+ module_files = Dir.glob("#{base_dir}/schemas/modules/**/{arm,mim}.exp").sort
354
+ repo = Expressir::Express::Parser.from_files(resource_files + module_files)
355
+ output = File.join(options[:output_dir], "smrl.ler")
356
+ repo.export_to_package(output,
357
+ name: "SMRL",
358
+ description: "STEP Resource and Module Library",
359
+ serialization_format: "marshal")
360
+ puts "Created #{output} (#{repo.schemas.length} schemas)"
361
+ end
362
+
363
+ puts "\nDone!"
364
+ ----
365
+
366
+ Usage:
367
+
368
+ [source,bash]
369
+ ----
370
+ ruby build_step_packages.rb \
371
+ --stepmod /path/to/iso-10303 \
372
+ --output ./packages \
373
+ --packages srl,sml,smrl
374
+ ----
375
+
376
+ == Summary
377
+
378
+ * Use `Dir.glob` to collect all EXPRESS files for SRL, SML, or SMRL
379
+ * `Expressir::Express::Parser.from_files` parses all files into a single
380
+ repository
381
+ * `repo.export_to_package` creates a `.ler` package with pre-built indexes
382
+ * `Repository.from_package` loads packages in seconds
383
+ * `find_entity(qualified_name:)` provides instant lookups
384
+ * `list_entities` and `list_types` enumerate all items
385
+ * `SearchEngine` supports pattern matching and filtering