expressir 2.1.29 → 2.1.31
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/.github/workflows/docs.yml +98 -0
- data/.github/workflows/links.yml +100 -0
- data/.github/workflows/rake.yml +4 -0
- data/.github/workflows/release.yml +5 -0
- data/.github/workflows/validate_schemas.yml +1 -1
- data/.gitignore +3 -0
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +209 -55
- data/Gemfile +2 -1
- data/README.adoc +650 -83
- data/docs/Gemfile +12 -0
- data/docs/_config.yml +141 -0
- data/docs/_guides/changes/changes-format.adoc +778 -0
- data/docs/_guides/changes/importing-eengine.adoc +898 -0
- data/docs/_guides/changes/index.adoc +396 -0
- data/docs/_guides/changes/programmatic-usage.adoc +1038 -0
- data/docs/_guides/changes/validating-changes.adoc +681 -0
- data/docs/_guides/cli/benchmark-performance.adoc +834 -0
- data/docs/_guides/cli/coverage-analysis.adoc +921 -0
- data/docs/_guides/cli/format-schemas.adoc +547 -0
- data/docs/_guides/cli/index.adoc +8 -0
- data/docs/_guides/cli/managing-changes.adoc +927 -0
- data/docs/_guides/cli/validate-ascii.adoc +645 -0
- data/docs/_guides/cli/validate-schemas.adoc +534 -0
- data/docs/_guides/index.adoc +165 -0
- data/docs/_guides/ler/creating-packages.adoc +664 -0
- data/docs/_guides/ler/index.adoc +305 -0
- data/docs/_guides/ler/loading-packages.adoc +707 -0
- data/docs/_guides/ler/package-formats.adoc +748 -0
- data/docs/_guides/ler/querying-packages.adoc +826 -0
- data/docs/_guides/ler/validating-packages.adoc +750 -0
- data/docs/_guides/liquid/basic-templates.adoc +813 -0
- data/docs/_guides/liquid/documentation-generation.adoc +1042 -0
- data/docs/_guides/liquid/drops-reference.adoc +829 -0
- data/docs/_guides/liquid/filters-and-tags.adoc +912 -0
- data/docs/_guides/liquid/index.adoc +468 -0
- data/docs/_guides/manifests/creating-manifests.adoc +483 -0
- data/docs/_guides/manifests/index.adoc +307 -0
- data/docs/_guides/manifests/resolving-manifests.adoc +557 -0
- data/docs/_guides/manifests/validating-manifests.adoc +713 -0
- data/docs/_guides/ruby-api/formatting-schemas.adoc +605 -0
- data/docs/_guides/ruby-api/index.adoc +257 -0
- data/docs/_guides/ruby-api/parsing-files.adoc +421 -0
- data/docs/_guides/ruby-api/search-engine.adoc +609 -0
- data/docs/_guides/ruby-api/working-with-repository.adoc +577 -0
- data/docs/_pages/data-model.adoc +665 -0
- data/docs/_pages/express-language.adoc +506 -0
- data/docs/_pages/getting-started.adoc +414 -0
- data/docs/_pages/index.adoc +116 -0
- data/docs/_pages/introduction.adoc +256 -0
- data/docs/_pages/ler-packages.adoc +837 -0
- data/docs/_pages/parsers.adoc +683 -0
- data/docs/_pages/schema-manifests.adoc +431 -0
- data/docs/_references/index.adoc +228 -0
- data/docs/_tutorials/creating-ler-package.adoc +735 -0
- data/docs/_tutorials/documentation-coverage.adoc +795 -0
- data/docs/_tutorials/index.adoc +221 -0
- data/docs/_tutorials/liquid-templates.adoc +806 -0
- data/docs/_tutorials/parsing-your-first-schema.adoc +522 -0
- data/docs/_tutorials/querying-schemas.adoc +751 -0
- data/docs/_tutorials/working-with-multiple-schemas.adoc +676 -0
- data/docs/index.adoc +242 -0
- data/docs/lychee.toml +84 -0
- data/examples/demo_ler_usage.sh +86 -0
- data/examples/ler/README.md +111 -0
- data/examples/ler/simple_example.ler +0 -0
- data/examples/ler/simple_schema.exp +33 -0
- data/examples/ler_build.rb +75 -0
- data/examples/ler_cli.rb +79 -0
- data/examples/ler_demo_complete.rb +276 -0
- data/examples/ler_query.rb +91 -0
- data/examples/ler_query_examples.rb +305 -0
- data/examples/ler_stats.rb +81 -0
- data/examples/phase3_demo.rb +159 -0
- data/examples/query_demo_simple.rb +131 -0
- data/expressir.gemspec +2 -0
- data/lib/expressir/changes/schema_change.rb +32 -22
- data/lib/expressir/changes/{edition_change.rb → version_change.rb} +3 -3
- data/lib/expressir/cli.rb +12 -4
- data/lib/expressir/commands/changes_import_eengine.rb +2 -2
- data/lib/expressir/commands/changes_validate.rb +1 -1
- data/lib/expressir/commands/manifest.rb +427 -0
- data/lib/expressir/commands/package.rb +1274 -0
- data/lib/expressir/commands/validate.rb +70 -37
- data/lib/expressir/commands/validate_ascii.rb +607 -0
- data/lib/expressir/commands/validate_load.rb +88 -0
- data/lib/expressir/express/formatter.rb +5 -1
- data/lib/expressir/express/formatters/remark_item_formatter.rb +25 -0
- data/lib/expressir/express/parser.rb +33 -0
- data/lib/expressir/manifest/resolver.rb +213 -0
- data/lib/expressir/manifest/validator.rb +195 -0
- data/lib/expressir/model/declarations/entity.rb +6 -0
- data/lib/expressir/model/dependency_resolver.rb +270 -0
- data/lib/expressir/model/indexes/entity_index.rb +103 -0
- data/lib/expressir/model/indexes/reference_index.rb +148 -0
- data/lib/expressir/model/indexes/type_index.rb +149 -0
- data/lib/expressir/model/interface_validator.rb +384 -0
- data/lib/expressir/model/repository.rb +400 -5
- data/lib/expressir/model/repository_validator.rb +295 -0
- data/lib/expressir/model/search_engine.rb +525 -0
- data/lib/expressir/model.rb +4 -94
- data/lib/expressir/package/builder.rb +200 -0
- data/lib/expressir/package/metadata.rb +81 -0
- data/lib/expressir/package/reader.rb +165 -0
- data/lib/expressir/schema_manifest.rb +11 -1
- data/lib/expressir/version.rb +1 -1
- data/lib/expressir.rb +16 -3
- metadata +115 -5
- data/docs/benchmarking.adoc +0 -107
- data/docs/liquid_drops.adoc +0 -1547
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Loading Packages
|
|
3
|
+
parent: LER Packages
|
|
4
|
+
grand_parent: Guides
|
|
5
|
+
nav_order: 2
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
= Loading Packages
|
|
9
|
+
|
|
10
|
+
== Purpose
|
|
11
|
+
|
|
12
|
+
This guide explains how to load LER packages into your applications using both
|
|
13
|
+
the Ruby API and CLI commands. Loading pre-built packages is significantly
|
|
14
|
+
faster than parsing raw EXPRESS files.
|
|
15
|
+
|
|
16
|
+
== References
|
|
17
|
+
|
|
18
|
+
* link:index.html[LER Packages Overview]
|
|
19
|
+
* link:creating-packages.html[Creating Packages]
|
|
20
|
+
* link:querying-packages.html[Querying Packages]
|
|
21
|
+
* link:../ruby-api/working-with-repository.html[Working with Repository]
|
|
22
|
+
|
|
23
|
+
== Concepts
|
|
24
|
+
|
|
25
|
+
Package loading:: The process of reading a LER package file and deserializing
|
|
26
|
+
its contents into a [`Repository`](../../lib/expressir/model/repository.rb)
|
|
27
|
+
instance.
|
|
28
|
+
|
|
29
|
+
Package reader:: The [`Expressir::Package::Reader`](../../lib/expressir/package/reader.rb)
|
|
30
|
+
class responsible for loading LER packages.
|
|
31
|
+
|
|
32
|
+
Deserialization:: Converting serialized data (Marshal, YAML, or JSON) back
|
|
33
|
+
into Ruby objects.
|
|
34
|
+
|
|
35
|
+
Pre-built indexes:: Entity, type, and reference indexes stored in the package
|
|
36
|
+
that are loaded directly without rebuilding.
|
|
37
|
+
|
|
38
|
+
== Loading packages via Ruby API
|
|
39
|
+
|
|
40
|
+
=== Basic package loading
|
|
41
|
+
|
|
42
|
+
Use [`Repository.from_package`](../../lib/expressir/model/repository.rb:256)
|
|
43
|
+
to load a LER package:
|
|
44
|
+
|
|
45
|
+
[source,ruby]
|
|
46
|
+
----
|
|
47
|
+
require "expressir"
|
|
48
|
+
|
|
49
|
+
# Load package
|
|
50
|
+
repo = Expressir::Model::Repository.from_package("schemas.ler")
|
|
51
|
+
|
|
52
|
+
# Package is ready to use
|
|
53
|
+
puts "Loaded #{repo.schemas.size} schemas"
|
|
54
|
+
----
|
|
55
|
+
|
|
56
|
+
The repository is fully initialized with:
|
|
57
|
+
|
|
58
|
+
* All schemas loaded and resolved
|
|
59
|
+
* Pre-built indexes ready for queries
|
|
60
|
+
* All references resolved
|
|
61
|
+
|
|
62
|
+
=== Using Package::Reader directly
|
|
63
|
+
|
|
64
|
+
For more control, use the [`Package::Reader`](../../lib/expressir/package/reader.rb:10)
|
|
65
|
+
class:
|
|
66
|
+
|
|
67
|
+
[source,ruby]
|
|
68
|
+
----
|
|
69
|
+
require "expressir/package/reader"
|
|
70
|
+
|
|
71
|
+
# Load using reader
|
|
72
|
+
reader = Expressir::Package::Reader.new
|
|
73
|
+
repo = reader.load("schemas.ler")
|
|
74
|
+
|
|
75
|
+
# Or use class method
|
|
76
|
+
repo = Expressir::Package::Reader.load("schemas.ler")
|
|
77
|
+
----
|
|
78
|
+
|
|
79
|
+
=== Accessing loaded data
|
|
80
|
+
|
|
81
|
+
Once loaded, use the repository normally:
|
|
82
|
+
|
|
83
|
+
[source,ruby]
|
|
84
|
+
----
|
|
85
|
+
# Load package
|
|
86
|
+
repo = Expressir::Model::Repository.from_package("schemas.ler")
|
|
87
|
+
|
|
88
|
+
# Access schemas
|
|
89
|
+
repo.schemas.each do |schema|
|
|
90
|
+
puts "Schema: #{schema.id}"
|
|
91
|
+
puts " Entities: #{schema.entities&.size || 0}"
|
|
92
|
+
puts " Types: #{schema.types&.size || 0}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Use pre-built indexes
|
|
96
|
+
entity = repo.find_entity(qualified_name: "action_schema.action")
|
|
97
|
+
puts "Found entity: #{entity.id}" if entity
|
|
98
|
+
|
|
99
|
+
# List entities
|
|
100
|
+
entities = repo.list_entities
|
|
101
|
+
puts "Total entities: #{entities.size}"
|
|
102
|
+
----
|
|
103
|
+
|
|
104
|
+
=== Loading with error handling
|
|
105
|
+
|
|
106
|
+
Handle loading errors gracefully:
|
|
107
|
+
|
|
108
|
+
[source,ruby]
|
|
109
|
+
----
|
|
110
|
+
begin
|
|
111
|
+
repo = Expressir::Model::Repository.from_package("schemas.ler")
|
|
112
|
+
puts "✓ Package loaded successfully"
|
|
113
|
+
rescue ArgumentError => e
|
|
114
|
+
puts "Error: #{e.message}"
|
|
115
|
+
# Package file not found
|
|
116
|
+
rescue StandardError => e
|
|
117
|
+
puts "Loading error: #{e.message}"
|
|
118
|
+
# Corrupted package or incompatible format
|
|
119
|
+
end
|
|
120
|
+
----
|
|
121
|
+
|
|
122
|
+
=== Measuring load time
|
|
123
|
+
|
|
124
|
+
Track loading performance:
|
|
125
|
+
|
|
126
|
+
[source,ruby]
|
|
127
|
+
----
|
|
128
|
+
require "benchmark"
|
|
129
|
+
|
|
130
|
+
load_time = Benchmark.realtime do
|
|
131
|
+
@repo = Expressir::Model::Repository.from_package("large_schemas.ler")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
puts "Load time: #{(load_time * 1000).round(2)} ms"
|
|
135
|
+
puts "Schemas: #{@repo.schemas.size}"
|
|
136
|
+
puts "Entities: #{@repo.list_entities.size}"
|
|
137
|
+
----
|
|
138
|
+
|
|
139
|
+
== Loading packages via CLI
|
|
140
|
+
|
|
141
|
+
=== Package information
|
|
142
|
+
|
|
143
|
+
View package contents without full loading:
|
|
144
|
+
|
|
145
|
+
[source,bash]
|
|
146
|
+
----
|
|
147
|
+
# Show package metadata and statistics
|
|
148
|
+
expressir package info schemas.ler
|
|
149
|
+
|
|
150
|
+
# Output in JSON format
|
|
151
|
+
expressir package info schemas.ler --format json
|
|
152
|
+
|
|
153
|
+
# Output in YAML format
|
|
154
|
+
expressir package info schemas.ler --format yaml
|
|
155
|
+
----
|
|
156
|
+
|
|
157
|
+
.Example output
|
|
158
|
+
[example]
|
|
159
|
+
====
|
|
160
|
+
[source]
|
|
161
|
+
----
|
|
162
|
+
Package Information
|
|
163
|
+
==================================================
|
|
164
|
+
Name: Production Schemas
|
|
165
|
+
Version: 2.1.0
|
|
166
|
+
Description: Schema set for production deployment
|
|
167
|
+
Created: 2024-01-15T10:30:00Z
|
|
168
|
+
|
|
169
|
+
Configuration
|
|
170
|
+
--------------------------------------------------
|
|
171
|
+
Express mode: include_all
|
|
172
|
+
Resolution mode: resolved
|
|
173
|
+
Serialization format: marshal
|
|
174
|
+
|
|
175
|
+
Statistics
|
|
176
|
+
--------------------------------------------------
|
|
177
|
+
Total schemas: 45
|
|
178
|
+
Total entities: 892
|
|
179
|
+
Total types: 456
|
|
180
|
+
Total functions: 123
|
|
181
|
+
Total rules: 67
|
|
182
|
+
Total procedures: 34
|
|
183
|
+
----
|
|
184
|
+
====
|
|
185
|
+
|
|
186
|
+
=== Listing package contents
|
|
187
|
+
|
|
188
|
+
List elements in the package:
|
|
189
|
+
|
|
190
|
+
[source,bash]
|
|
191
|
+
----
|
|
192
|
+
# List all entities
|
|
193
|
+
expressir package list schemas.ler --type entity
|
|
194
|
+
|
|
195
|
+
# List types
|
|
196
|
+
expressir package list schemas.ler --type type
|
|
197
|
+
|
|
198
|
+
# List entities from specific schema
|
|
199
|
+
expressir package list schemas.ler --type entity --schema action_schema
|
|
200
|
+
|
|
201
|
+
# List SELECT types only
|
|
202
|
+
expressir package list schemas.ler --type type --category select
|
|
203
|
+
|
|
204
|
+
# Show counts only
|
|
205
|
+
expressir package list schemas.ler --type entity --count-only
|
|
206
|
+
----
|
|
207
|
+
|
|
208
|
+
=== Extracting package contents
|
|
209
|
+
|
|
210
|
+
Extract package contents to directory:
|
|
211
|
+
|
|
212
|
+
[source,bash]
|
|
213
|
+
----
|
|
214
|
+
# Extract to directory
|
|
215
|
+
expressir package extract schemas.ler --output extracted/
|
|
216
|
+
|
|
217
|
+
# View extracted structure
|
|
218
|
+
ls -R extracted/
|
|
219
|
+
----
|
|
220
|
+
|
|
221
|
+
Extracted contents include:
|
|
222
|
+
|
|
223
|
+
* `metadata.yaml` - Package metadata
|
|
224
|
+
* `manifest.yaml` - Schema manifest
|
|
225
|
+
* `repository.marshal` (or `.yaml`, `.json`) - Serialized repository
|
|
226
|
+
* `entity_index.marshal` - Entity index
|
|
227
|
+
* `type_index.marshal` - Type index
|
|
228
|
+
* `reference_index.marshal` - Reference index
|
|
229
|
+
* `express_files/` - Original EXPRESS files (if included)
|
|
230
|
+
|
|
231
|
+
== Performance comparison
|
|
232
|
+
|
|
233
|
+
=== Load time comparison
|
|
234
|
+
|
|
235
|
+
LER packages load significantly faster than parsing EXPRESS files:
|
|
236
|
+
|
|
237
|
+
.Performance comparison example
|
|
238
|
+
[example]
|
|
239
|
+
====
|
|
240
|
+
[source,ruby]
|
|
241
|
+
----
|
|
242
|
+
require "benchmark"
|
|
243
|
+
|
|
244
|
+
# Scenario: 100 EXPRESS schema files
|
|
245
|
+
# Total size: 15 MB of EXPRESS source
|
|
246
|
+
|
|
247
|
+
# Method 1: Parse from EXPRESS files
|
|
248
|
+
parse_time = Benchmark.realtime do
|
|
249
|
+
files = Dir.glob("schemas/**/*.exp")
|
|
250
|
+
@repo1 = Expressir::Express::Parser.from_files(files)
|
|
251
|
+
end
|
|
252
|
+
puts "Parse time: #{parse_time.round(2)}s" # ~45 seconds
|
|
253
|
+
|
|
254
|
+
# Method 2: Load from LER package
|
|
255
|
+
load_time = Benchmark.realtime do
|
|
256
|
+
@repo2 = Expressir::Model::Repository.from_package("schemas.ler")
|
|
257
|
+
end
|
|
258
|
+
puts "Load time: #{load_time.round(2)}s" # ~2 seconds
|
|
259
|
+
|
|
260
|
+
# Speed improvement
|
|
261
|
+
speedup = parse_time / load_time
|
|
262
|
+
puts "Speed improvement: #{speedup.round(1)}x faster" # ~22x faster
|
|
263
|
+
----
|
|
264
|
+
====
|
|
265
|
+
|
|
266
|
+
=== Real-world performance data
|
|
267
|
+
|
|
268
|
+
Typical performance improvements:
|
|
269
|
+
|
|
270
|
+
[options="header"]
|
|
271
|
+
|===
|
|
272
|
+
| Schema Set Size | Parse Time | Load Time | Improvement
|
|
273
|
+
|
|
274
|
+
| Small (10 files)
|
|
275
|
+
| 5s
|
|
276
|
+
| 0.3s
|
|
277
|
+
| 16x faster
|
|
278
|
+
|
|
279
|
+
| Medium (50 files)
|
|
280
|
+
| 22s
|
|
281
|
+
| 1.2s
|
|
282
|
+
| 18x faster
|
|
283
|
+
|
|
284
|
+
| Large (100 files)
|
|
285
|
+
| 45s
|
|
286
|
+
| 2.0s
|
|
287
|
+
| 22x faster
|
|
288
|
+
|
|
289
|
+
| Very Large (200 files)
|
|
290
|
+
| 95s
|
|
291
|
+
| 4.5s
|
|
292
|
+
| 21x faster
|
|
293
|
+
|===
|
|
294
|
+
|
|
295
|
+
=== Performance factors
|
|
296
|
+
|
|
297
|
+
Factors affecting load performance:
|
|
298
|
+
|
|
299
|
+
Serialization format:: Marshal is fastest, YAML is slowest
|
|
300
|
+
+
|
|
301
|
+
[source]
|
|
302
|
+
----
|
|
303
|
+
Marshal: 1.0x (baseline)
|
|
304
|
+
JSON: 3.2x slower
|
|
305
|
+
YAML: 4.1x slower
|
|
306
|
+
----
|
|
307
|
+
|
|
308
|
+
Package size:: Linear relationship with schema count
|
|
309
|
+
|
|
310
|
+
Disk I/O speed:: SSD vs HDD can differ by 2-3x
|
|
311
|
+
|
|
312
|
+
Pre-built indexes:: No rebuild time needed (saves 0.5-2s)
|
|
313
|
+
|
|
314
|
+
== Memory considerations
|
|
315
|
+
|
|
316
|
+
=== Memory usage patterns
|
|
317
|
+
|
|
318
|
+
LER packages load entire repository into memory:
|
|
319
|
+
|
|
320
|
+
[options="header"]
|
|
321
|
+
|===
|
|
322
|
+
| Schema Count | Repository Size | Memory Usage | Load Time
|
|
323
|
+
|
|
324
|
+
| 10-50
|
|
325
|
+
| Small
|
|
326
|
+
| 10-50 MB
|
|
327
|
+
| <1 second
|
|
328
|
+
|
|
329
|
+
| 50-100
|
|
330
|
+
| Medium
|
|
331
|
+
| 50-200 MB
|
|
332
|
+
| 1-2 seconds
|
|
333
|
+
|
|
334
|
+
| 100-500
|
|
335
|
+
| Large
|
|
336
|
+
| 200-500 MB
|
|
337
|
+
| 2-5 seconds
|
|
338
|
+
|
|
339
|
+
| 500+
|
|
340
|
+
| Very Large
|
|
341
|
+
| 500+ MB
|
|
342
|
+
| 5+ seconds
|
|
343
|
+
|===
|
|
344
|
+
|
|
345
|
+
=== Managing memory usage
|
|
346
|
+
|
|
347
|
+
For large packages, consider:
|
|
348
|
+
|
|
349
|
+
.Memory optimization strategies
|
|
350
|
+
[example]
|
|
351
|
+
====
|
|
352
|
+
1. Use selective loading (load only needed schemas)
|
|
353
|
+
2. Clear repository when done: `repo = nil; GC.start`
|
|
354
|
+
3. Use streaming for one-time queries
|
|
355
|
+
4. Split into multiple smaller packages
|
|
356
|
+
====
|
|
357
|
+
|
|
358
|
+
=== Monitoring memory usage
|
|
359
|
+
|
|
360
|
+
Track memory consumption:
|
|
361
|
+
|
|
362
|
+
[source,ruby]
|
|
363
|
+
----
|
|
364
|
+
require "get_process_mem"
|
|
365
|
+
|
|
366
|
+
# Measure memory before
|
|
367
|
+
mem_before = GetProcessMem.new.mb
|
|
368
|
+
|
|
369
|
+
# Load package
|
|
370
|
+
repo = Expressir::Model::Repository.from_package("large.ler")
|
|
371
|
+
|
|
372
|
+
# Measure memory after
|
|
373
|
+
mem_after = GetProcessMem.new.mb
|
|
374
|
+
mem_used = mem_after - mem_before
|
|
375
|
+
|
|
376
|
+
puts "Memory used: #{mem_used.round(2)} MB"
|
|
377
|
+
puts "Schemas: #{repo.schemas.size}"
|
|
378
|
+
puts "Per schema: #{(mem_used / repo.schemas.size).round(2)} MB"
|
|
379
|
+
----
|
|
380
|
+
|
|
381
|
+
== Cache strategies
|
|
382
|
+
|
|
383
|
+
=== When to use caching
|
|
384
|
+
|
|
385
|
+
Use LER packages as a cache layer:
|
|
386
|
+
|
|
387
|
+
Development:: Keep EXPRESS files, build packages for testing
|
|
388
|
+
|
|
389
|
+
Production:: Deploy pre-built packages, no parsing needed
|
|
390
|
+
|
|
391
|
+
CI/CD:: Build once, deploy everywhere
|
|
392
|
+
|
|
393
|
+
=== Cache invalidation
|
|
394
|
+
|
|
395
|
+
Rebuild packages when:
|
|
396
|
+
|
|
397
|
+
* EXPRESS schemas change
|
|
398
|
+
* Schema versions are updated
|
|
399
|
+
* Dependencies are modified
|
|
400
|
+
* Validation rules change
|
|
401
|
+
|
|
402
|
+
=== Hybrid approach
|
|
403
|
+
|
|
404
|
+
Combine EXPRESS files and LER packages:
|
|
405
|
+
|
|
406
|
+
[source,ruby]
|
|
407
|
+
----
|
|
408
|
+
class SchemaLoader
|
|
409
|
+
def initialize(package_path, schemas_dir)
|
|
410
|
+
@package_path = package_path
|
|
411
|
+
@schemas_dir = schemas_dir
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def load
|
|
415
|
+
# Check if package exists and is recent
|
|
416
|
+
if package_fresh?
|
|
417
|
+
load_from_package
|
|
418
|
+
else
|
|
419
|
+
load_from_express_and_rebuild
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
private
|
|
424
|
+
|
|
425
|
+
def package_fresh?
|
|
426
|
+
return false unless File.exist?(@package_path)
|
|
427
|
+
|
|
428
|
+
package_mtime = File.mtime(@package_path)
|
|
429
|
+
schemas_mtime = Dir.glob("#{@schemas_dir}/**/*.exp")
|
|
430
|
+
.map { |f| File.mtime(f) }
|
|
431
|
+
.max
|
|
432
|
+
|
|
433
|
+
package_mtime > schemas_mtime
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def load_from_package
|
|
437
|
+
puts "Loading from package (cached)..."
|
|
438
|
+
Expressir::Model::Repository.from_package(@package_path)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def load_from_express_and_rebuild
|
|
442
|
+
puts "Loading from EXPRESS (cache stale)..."
|
|
443
|
+
files = Dir.glob("#{@schemas_dir}/**/*.exp")
|
|
444
|
+
repo = Expressir::Express::Parser.from_files(files)
|
|
445
|
+
|
|
446
|
+
puts "Rebuilding package cache..."
|
|
447
|
+
repo.export_to_package(@package_path)
|
|
448
|
+
|
|
449
|
+
repo
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Usage
|
|
454
|
+
loader = SchemaLoader.new("cache/schemas.ler", "schemas/")
|
|
455
|
+
repo = loader.load
|
|
456
|
+
----
|
|
457
|
+
|
|
458
|
+
== Error handling
|
|
459
|
+
|
|
460
|
+
=== Common loading errors
|
|
461
|
+
|
|
462
|
+
==== Package file not found
|
|
463
|
+
|
|
464
|
+
.Error
|
|
465
|
+
[example]
|
|
466
|
+
====
|
|
467
|
+
[source]
|
|
468
|
+
----
|
|
469
|
+
ArgumentError: Package file not found: schemas.ler
|
|
470
|
+
----
|
|
471
|
+
====
|
|
472
|
+
|
|
473
|
+
.Solution
|
|
474
|
+
[example]
|
|
475
|
+
====
|
|
476
|
+
[source,ruby]
|
|
477
|
+
----
|
|
478
|
+
unless File.exist?("schemas.ler")
|
|
479
|
+
abort "Package file not found. Build with: expressir package build ..."
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
repo = Expressir::Model::Repository.from_package("schemas.ler")
|
|
483
|
+
----
|
|
484
|
+
====
|
|
485
|
+
|
|
486
|
+
==== Corrupted package
|
|
487
|
+
|
|
488
|
+
.Error
|
|
489
|
+
[example]
|
|
490
|
+
====
|
|
491
|
+
[source]
|
|
492
|
+
----
|
|
493
|
+
Error: Metadata not found in package
|
|
494
|
+
----
|
|
495
|
+
====
|
|
496
|
+
|
|
497
|
+
.Solution
|
|
498
|
+
[example]
|
|
499
|
+
====
|
|
500
|
+
1. Verify package is a valid ZIP file: `unzip -t schemas.ler`
|
|
501
|
+
2. Rebuild package from source
|
|
502
|
+
3. Check disk space and file permissions
|
|
503
|
+
====
|
|
504
|
+
|
|
505
|
+
==== Incompatible format
|
|
506
|
+
|
|
507
|
+
.Error
|
|
508
|
+
[example]
|
|
509
|
+
====
|
|
510
|
+
[source]
|
|
511
|
+
----
|
|
512
|
+
Error: Unknown serialization format: custom
|
|
513
|
+
----
|
|
514
|
+
====
|
|
515
|
+
|
|
516
|
+
.Solution
|
|
517
|
+
[example]
|
|
518
|
+
====
|
|
519
|
+
Package was built with unsupported format. Rebuild with:
|
|
520
|
+
* `marshal` (recommended)
|
|
521
|
+
* `yaml`
|
|
522
|
+
* `json`
|
|
523
|
+
====
|
|
524
|
+
|
|
525
|
+
==== Version mismatch
|
|
526
|
+
|
|
527
|
+
.Error
|
|
528
|
+
[example]
|
|
529
|
+
====
|
|
530
|
+
[source]
|
|
531
|
+
----
|
|
532
|
+
Error: Package built with expressir 0.6.0, current version is 0.7.0
|
|
533
|
+
----
|
|
534
|
+
====
|
|
535
|
+
|
|
536
|
+
.Solution
|
|
537
|
+
[example]
|
|
538
|
+
====
|
|
539
|
+
Rebuild package with current Expressir version:
|
|
540
|
+
[source,bash]
|
|
541
|
+
----
|
|
542
|
+
expressir package build schemas/ new_package.ler
|
|
543
|
+
----
|
|
544
|
+
====
|
|
545
|
+
|
|
546
|
+
=== Robust error handling
|
|
547
|
+
|
|
548
|
+
Implement comprehensive error handling:
|
|
549
|
+
|
|
550
|
+
[source,ruby]
|
|
551
|
+
----
|
|
552
|
+
def load_package_safely(path, fallback_dir = nil)
|
|
553
|
+
begin
|
|
554
|
+
# Try loading package
|
|
555
|
+
repo = Expressir::Model::Repository.from_package(path)
|
|
556
|
+
puts "✓ Loaded package: #{path}"
|
|
557
|
+
return repo
|
|
558
|
+
|
|
559
|
+
rescue ArgumentError => e
|
|
560
|
+
puts "Package not found: #{path}"
|
|
561
|
+
|
|
562
|
+
if fallback_dir && Dir.exist?(fallback_dir)
|
|
563
|
+
puts "Falling back to EXPRESS files..."
|
|
564
|
+
return load_from_express(fallback_dir)
|
|
565
|
+
else
|
|
566
|
+
raise "No package or fallback available"
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
rescue StandardError => e
|
|
570
|
+
puts "Error loading package: #{e.message}"
|
|
571
|
+
|
|
572
|
+
if fallback_dir && Dir.exist?(fallback_dir)
|
|
573
|
+
puts "Attempting recovery from EXPRESS files..."
|
|
574
|
+
return load_from_express(fallback_dir)
|
|
575
|
+
else
|
|
576
|
+
raise
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
def load_from_express(dir)
|
|
582
|
+
files = Dir.glob("#{dir}/**/*.exp")
|
|
583
|
+
Expressir::Express::Parser.from_files(files)
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
# Usage with fallback
|
|
587
|
+
repo = load_package_safely(
|
|
588
|
+
"cache/schemas.ler",
|
|
589
|
+
"schemas/" # fallback directory
|
|
590
|
+
)
|
|
591
|
+
----
|
|
592
|
+
|
|
593
|
+
== Verification after loading
|
|
594
|
+
|
|
595
|
+
=== Verify package integrity
|
|
596
|
+
|
|
597
|
+
Check loaded repository:
|
|
598
|
+
|
|
599
|
+
[source,ruby]
|
|
600
|
+
----
|
|
601
|
+
repo = Expressir::Model::Repository.from_package("schemas.ler")
|
|
602
|
+
|
|
603
|
+
# Verify schemas loaded
|
|
604
|
+
if repo.schemas.empty?
|
|
605
|
+
abort "Error: No schemas loaded from package"
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
puts "Loaded schemas:"
|
|
609
|
+
repo.schemas.each { |s| puts " - #{s.id}" }
|
|
610
|
+
|
|
611
|
+
# Verify indexes built
|
|
612
|
+
if repo.entity_index.nil?
|
|
613
|
+
puts "Warning: Entity index not loaded"
|
|
614
|
+
repo.build_indexes
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
# Test entity lookup
|
|
618
|
+
test_entity = repo.find_entity(qualified_name: "action_schema.action")
|
|
619
|
+
if test_entity
|
|
620
|
+
puts "✓ Entity lookup working"
|
|
621
|
+
else
|
|
622
|
+
puts "⚠ Entity lookup failed"
|
|
623
|
+
end
|
|
624
|
+
----
|
|
625
|
+
|
|
626
|
+
=== Validate repository
|
|
627
|
+
|
|
628
|
+
Run validation after loading:
|
|
629
|
+
|
|
630
|
+
[source,ruby]
|
|
631
|
+
----
|
|
632
|
+
repo = Expressir::Model::Repository.from_package("schemas.ler")
|
|
633
|
+
|
|
634
|
+
# Validate repository
|
|
635
|
+
validation = repo.validate
|
|
636
|
+
|
|
637
|
+
if validation[:valid?]
|
|
638
|
+
puts "✓ Repository is valid"
|
|
639
|
+
else
|
|
640
|
+
puts "⚠ Validation errors found:"
|
|
641
|
+
validation[:errors].each do |error|
|
|
642
|
+
puts " - #{error[:message]}"
|
|
643
|
+
end
|
|
644
|
+
end
|
|
645
|
+
----
|
|
646
|
+
|
|
647
|
+
=== Statistics check
|
|
648
|
+
|
|
649
|
+
Verify expected schema contents:
|
|
650
|
+
|
|
651
|
+
[source,ruby]
|
|
652
|
+
----
|
|
653
|
+
repo = Expressir::Model::Repository.from_package("schemas.ler")
|
|
654
|
+
stats = repo.statistics
|
|
655
|
+
|
|
656
|
+
puts "Package Statistics:"
|
|
657
|
+
puts " Schemas: #{stats[:total_schemas]}"
|
|
658
|
+
puts " Entities: #{stats[:total_entities]}"
|
|
659
|
+
puts " Types: #{stats[:total_types]}"
|
|
660
|
+
puts " Functions: #{stats[:total_functions]}"
|
|
661
|
+
|
|
662
|
+
# Compare with expected values
|
|
663
|
+
expected = { schemas: 45, entities: 892 }
|
|
664
|
+
|
|
665
|
+
if stats[:total_schemas] != expected[:schemas]
|
|
666
|
+
puts "⚠ Schema count mismatch"
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
if stats[:total_entities] != expected[:entities]
|
|
670
|
+
puts "⚠ Entity count mismatch"
|
|
671
|
+
end
|
|
672
|
+
----
|
|
673
|
+
|
|
674
|
+
== Next steps
|
|
675
|
+
|
|
676
|
+
* link:querying-packages.html[Querying Packages] - Search and filter package
|
|
677
|
+
contents
|
|
678
|
+
* link:validating-packages.html[Validating Packages] - Comprehensive package
|
|
679
|
+
validation
|
|
680
|
+
* link:package-formats.html[Package Formats] - Understanding serialization
|
|
681
|
+
formats
|
|
682
|
+
* link:creating-packages.html[Creating Packages] - Build your own packages
|
|
683
|
+
|
|
684
|
+
== Summary
|
|
685
|
+
|
|
686
|
+
Key takeaways for loading LER packages:
|
|
687
|
+
|
|
688
|
+
* Use `Repository.from_package()` for simplest loading
|
|
689
|
+
* Loading is 20-30x faster than parsing EXPRESS files
|
|
690
|
+
* Packages are fully ready after loading (indexes included)
|
|
691
|
+
* Memory usage scales linearly with package size
|
|
692
|
+
* Use packages as cache layer for best performance
|
|
693
|
+
* Implement error handling with fallback to EXPRESS files
|
|
694
|
+
* Validate repository after loading critical packages
|
|
695
|
+
* Marshal format provides fastest loading
|
|
696
|
+
* Extract packages to debug contents
|
|
697
|
+
|
|
698
|
+
Best practices:
|
|
699
|
+
|
|
700
|
+
* Always check package exists before loading
|
|
701
|
+
* Use try-catch for robust applications
|
|
702
|
+
* Verify loaded content with statistics
|
|
703
|
+
* Consider memory constraints for large packages
|
|
704
|
+
* Implement cache invalidation strategy
|
|
705
|
+
* Keep original EXPRESS files as source of truth
|
|
706
|
+
* Monitor load times in production
|
|
707
|
+
* Use fallback to EXPRESS files when needed
|