expressir 2.1.30 → 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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/docs.yml +98 -0
  3. data/.github/workflows/links.yml +100 -0
  4. data/.github/workflows/rake.yml +4 -0
  5. data/.github/workflows/release.yml +5 -0
  6. data/.github/workflows/validate_schemas.yml +1 -1
  7. data/.gitignore +3 -0
  8. data/.rubocop.yml +1 -1
  9. data/.rubocop_todo.yml +244 -39
  10. data/Gemfile +2 -1
  11. data/README.adoc +621 -54
  12. data/docs/Gemfile +12 -0
  13. data/docs/_config.yml +141 -0
  14. data/docs/_guides/changes/changes-format.adoc +778 -0
  15. data/docs/_guides/changes/importing-eengine.adoc +898 -0
  16. data/docs/_guides/changes/index.adoc +396 -0
  17. data/docs/_guides/changes/programmatic-usage.adoc +1038 -0
  18. data/docs/_guides/changes/validating-changes.adoc +681 -0
  19. data/docs/_guides/cli/benchmark-performance.adoc +834 -0
  20. data/docs/_guides/cli/coverage-analysis.adoc +921 -0
  21. data/docs/_guides/cli/format-schemas.adoc +547 -0
  22. data/docs/_guides/cli/index.adoc +8 -0
  23. data/docs/_guides/cli/managing-changes.adoc +927 -0
  24. data/docs/_guides/cli/validate-ascii.adoc +645 -0
  25. data/docs/_guides/cli/validate-schemas.adoc +534 -0
  26. data/docs/_guides/index.adoc +165 -0
  27. data/docs/_guides/ler/creating-packages.adoc +664 -0
  28. data/docs/_guides/ler/index.adoc +305 -0
  29. data/docs/_guides/ler/loading-packages.adoc +707 -0
  30. data/docs/_guides/ler/package-formats.adoc +748 -0
  31. data/docs/_guides/ler/querying-packages.adoc +826 -0
  32. data/docs/_guides/ler/validating-packages.adoc +750 -0
  33. data/docs/_guides/liquid/basic-templates.adoc +813 -0
  34. data/docs/_guides/liquid/documentation-generation.adoc +1042 -0
  35. data/docs/_guides/liquid/drops-reference.adoc +829 -0
  36. data/docs/_guides/liquid/filters-and-tags.adoc +912 -0
  37. data/docs/_guides/liquid/index.adoc +468 -0
  38. data/docs/_guides/manifests/creating-manifests.adoc +483 -0
  39. data/docs/_guides/manifests/index.adoc +307 -0
  40. data/docs/_guides/manifests/resolving-manifests.adoc +557 -0
  41. data/docs/_guides/manifests/validating-manifests.adoc +713 -0
  42. data/docs/_guides/ruby-api/formatting-schemas.adoc +605 -0
  43. data/docs/_guides/ruby-api/index.adoc +257 -0
  44. data/docs/_guides/ruby-api/parsing-files.adoc +421 -0
  45. data/docs/_guides/ruby-api/search-engine.adoc +609 -0
  46. data/docs/_guides/ruby-api/working-with-repository.adoc +577 -0
  47. data/docs/_pages/data-model.adoc +665 -0
  48. data/docs/_pages/express-language.adoc +506 -0
  49. data/docs/_pages/getting-started.adoc +414 -0
  50. data/docs/_pages/index.adoc +116 -0
  51. data/docs/_pages/introduction.adoc +256 -0
  52. data/docs/_pages/ler-packages.adoc +837 -0
  53. data/docs/_pages/parsers.adoc +683 -0
  54. data/docs/_pages/schema-manifests.adoc +431 -0
  55. data/docs/_references/index.adoc +228 -0
  56. data/docs/_tutorials/creating-ler-package.adoc +735 -0
  57. data/docs/_tutorials/documentation-coverage.adoc +795 -0
  58. data/docs/_tutorials/index.adoc +221 -0
  59. data/docs/_tutorials/liquid-templates.adoc +806 -0
  60. data/docs/_tutorials/parsing-your-first-schema.adoc +522 -0
  61. data/docs/_tutorials/querying-schemas.adoc +751 -0
  62. data/docs/_tutorials/working-with-multiple-schemas.adoc +676 -0
  63. data/docs/index.adoc +242 -0
  64. data/docs/lychee.toml +84 -0
  65. data/examples/demo_ler_usage.sh +86 -0
  66. data/examples/ler/README.md +111 -0
  67. data/examples/ler/simple_example.ler +0 -0
  68. data/examples/ler/simple_schema.exp +33 -0
  69. data/examples/ler_build.rb +75 -0
  70. data/examples/ler_cli.rb +79 -0
  71. data/examples/ler_demo_complete.rb +276 -0
  72. data/examples/ler_query.rb +91 -0
  73. data/examples/ler_query_examples.rb +305 -0
  74. data/examples/ler_stats.rb +81 -0
  75. data/examples/phase3_demo.rb +159 -0
  76. data/examples/query_demo_simple.rb +131 -0
  77. data/expressir.gemspec +2 -0
  78. data/lib/expressir/cli.rb +12 -4
  79. data/lib/expressir/commands/manifest.rb +427 -0
  80. data/lib/expressir/commands/package.rb +1274 -0
  81. data/lib/expressir/commands/validate.rb +70 -37
  82. data/lib/expressir/commands/validate_ascii.rb +607 -0
  83. data/lib/expressir/commands/validate_load.rb +88 -0
  84. data/lib/expressir/express/formatter.rb +5 -1
  85. data/lib/expressir/express/formatters/remark_item_formatter.rb +25 -0
  86. data/lib/expressir/express/parser.rb +33 -0
  87. data/lib/expressir/manifest/resolver.rb +213 -0
  88. data/lib/expressir/manifest/validator.rb +195 -0
  89. data/lib/expressir/model/declarations/entity.rb +6 -0
  90. data/lib/expressir/model/dependency_resolver.rb +270 -0
  91. data/lib/expressir/model/indexes/entity_index.rb +103 -0
  92. data/lib/expressir/model/indexes/reference_index.rb +148 -0
  93. data/lib/expressir/model/indexes/type_index.rb +149 -0
  94. data/lib/expressir/model/interface_validator.rb +384 -0
  95. data/lib/expressir/model/repository.rb +400 -5
  96. data/lib/expressir/model/repository_validator.rb +295 -0
  97. data/lib/expressir/model/search_engine.rb +525 -0
  98. data/lib/expressir/model.rb +4 -94
  99. data/lib/expressir/package/builder.rb +200 -0
  100. data/lib/expressir/package/metadata.rb +81 -0
  101. data/lib/expressir/package/reader.rb +165 -0
  102. data/lib/expressir/schema_manifest.rb +11 -1
  103. data/lib/expressir/version.rb +1 -1
  104. data/lib/expressir.rb +15 -2
  105. metadata +114 -4
  106. data/docs/benchmarking.adoc +0 -107
  107. data/docs/liquid_drops.adoc +0 -1547
@@ -0,0 +1,829 @@
1
+ ---
2
+ title: Drops Reference
3
+ parent: Liquid
4
+ grand_parent: Guides
5
+ nav_order: 2
6
+ ---
7
+
8
+ = Expressir Liquid drops reference
9
+
10
+ == Purpose
11
+
12
+ This guide documents all Expressir Liquid drop classes and their
13
+ available attributes. Drops are template-friendly wrappers around
14
+ Expressir model objects that expose data for use in Liquid templates.
15
+
16
+ == References
17
+
18
+ * link:index.html[Liquid Overview] - Integration introduction
19
+ * link:basic-templates.html[Basic Templates] - Template syntax
20
+ * link:../../_pages/data-model.html[Data Model] - Understanding EXPRESS
21
+ structures
22
+ * link:../../_tutorials/liquid-templates.html[Liquid Templates Tutorial]
23
+ - Hands-on examples
24
+
25
+ == Concepts
26
+
27
+ Drop:: A Ruby class that wraps an Expressir model object and exposes
28
+ its attributes for Liquid template access.
29
+
30
+ Attribute:: A data field accessible via dot notation in templates (e.g.,
31
+ `entity.id`, `schema.entities`).
32
+
33
+ Collection:: An array of objects that can be iterated with `for` loops.
34
+
35
+ Reference:: A pointer to another model object, accessible through
36
+ navigation.
37
+
38
+ == What are drops?
39
+
40
+ Drops are adapter objects that make Expressir's Ruby model accessible
41
+ in Liquid templates. They provide:
42
+
43
+ **Simplified access**::
44
+ Use dot notation instead of method calls: `entity.id` instead of
45
+ `entity.id()`.
46
+
47
+ **Safe exposure**::
48
+ Only expose relevant attributes, hiding internal implementation details.
49
+
50
+ **Template-friendly types**::
51
+ Convert Ruby objects to Liquid-compatible types automatically.
52
+
53
+ **Consistent interface**::
54
+ All drops follow the same access pattern.
55
+
56
+ [source]
57
+ ----
58
+ Expressir Model Object → to_liquid() → Drop Object → Template Access
59
+ ----
60
+
61
+ == Understanding drop inheritance
62
+
63
+ All drop classes inherit common attributes:
64
+
65
+ [source]
66
+ ----
67
+ ModelElement (base)
68
+ ├── id (from Identifier mixin)
69
+ ├── remarks (from Identifier mixin)
70
+ ├── remark_items (from Identifier mixin)
71
+ ├── _class (object type identifier)
72
+ ├── source (formatted EXPRESS source)
73
+ └── parent (parent object reference)
74
+ ----
75
+
76
+ Every drop includes these base attributes plus its specific attributes.
77
+
78
+ == Repository drop
79
+
80
+ The top-level container for all schemas.
81
+
82
+ === Attributes
83
+
84
+ `schemas`:: Array of `SchemaDrop` objects representing all loaded
85
+ schemas.
86
+
87
+ `_class`:: String `"Expressir::Model::Repository"`.
88
+
89
+ === Usage
90
+
91
+ [source,liquid]
92
+ ----
93
+ Total schemas: {{ repository.schemas.size }}
94
+
95
+ {% for schema in repository.schemas %}
96
+ - {{ schema.id }}
97
+ {% endfor %}
98
+ ----
99
+
100
+ === Example
101
+
102
+ [source,ruby]
103
+ ----
104
+ repo = Expressir::Express::Parser.from_file("schema.exp")
105
+ repo_drop = repo.to_liquid
106
+
107
+ template = Liquid::Template.parse("{{ repository.schemas.size }} schemas")
108
+ output = template.render("repository" => repo_drop)
109
+ # Output: "1 schemas"
110
+ ----
111
+
112
+ == Schema drop
113
+
114
+ Represents an EXPRESS schema definition.
115
+
116
+ === Attributes
117
+
118
+ `id`:: Schema name (String).
119
+
120
+ `file`:: Source file path (String).
121
+
122
+ `version`:: `SchemaVersionDrop` object with version information.
123
+
124
+ `remarks`:: Array of documentation strings.
125
+
126
+ `remark_items`:: Array of `RemarkItemDrop` for detailed documentation.
127
+
128
+ `interfaces`:: Array of `InterfaceDrop` for USE_FROM and REFERENCE_FROM.
129
+
130
+ `constants`:: Array of `ConstantDrop` objects.
131
+
132
+ `types`:: Array of `TypeDrop` objects.
133
+
134
+ `entities`:: Array of `EntityDrop` objects.
135
+
136
+ `subtype_constraints`:: Array of `SubtypeConstraintDrop` objects.
137
+
138
+ `functions`:: Array of `FunctionDrop` objects.
139
+
140
+ `rules`:: Array of `RuleDrop` objects.
141
+
142
+ `procedures`:: Array of `ProcedureDrop` objects.
143
+
144
+ `source`:: Formatted EXPRESS source code (String).
145
+
146
+ `_class`:: String `"Expressir::Model::Declarations::Schema"`.
147
+
148
+ `parent`:: Reference to `RepositoryDrop`.
149
+
150
+ === Usage
151
+
152
+ [source,liquid]
153
+ ----
154
+ # {{ schema.id }}
155
+
156
+ {% if schema.version %}
157
+ Version: {{ schema.version.value }}
158
+ {% endif %}
159
+
160
+ File: {{ schema.file }}
161
+
162
+ ## Statistics
163
+
164
+ - Entities: {{ schema.entities.size }}
165
+ - Types: {{ schema.types.size }}
166
+ - Functions: {{ schema.functions.size }}
167
+ - Rules: {{ schema.rules.size }}
168
+
169
+ ## Contents
170
+
171
+ {% for entity in schema.entities %}
172
+ - {{ entity.id }}
173
+ {% endfor %}
174
+ ----
175
+
176
+ === Example
177
+
178
+ [source,ruby]
179
+ ----
180
+ repo = Expressir::Express::Parser.from_file("action_schema.exp")
181
+ schema_drop = repo.schemas.first.to_liquid
182
+
183
+ puts schema_drop.id # "action_schema"
184
+ puts schema_drop.file # "action_schema.exp"
185
+ puts schema_drop.entities.size # 5
186
+ ----
187
+
188
+ == Entity drop
189
+
190
+ Represents an EXPRESS entity definition.
191
+
192
+ === Attributes
193
+
194
+ `id`:: Entity name (String).
195
+
196
+ `abstract`:: Boolean indicating if entity is abstract.
197
+
198
+ `supertype_expression`:: Supertype expression object.
199
+
200
+ `subtype_of`:: Array of supertype references.
201
+
202
+ `attributes`:: Array of `AttributeDrop` for explicit attributes.
203
+
204
+ `derived_attributes`:: Array of `DerivedAttributeDrop`.
205
+
206
+ `inverse_attributes`:: Array of `InverseAttributeDrop`.
207
+
208
+ `unique_rules`:: Array of `UniqueRuleDrop`.
209
+
210
+ `where_rules`:: Array of `WhereRuleDrop`.
211
+
212
+ `informal_propositions`:: Array of `InformalPropositionRuleDrop`.
213
+
214
+ `remarks`:: Array of documentation strings.
215
+
216
+ `remark_items`:: Array of `RemarkItemDrop`.
217
+
218
+ `source`:: Formatted EXPRESS source code (String).
219
+
220
+ `_class`:: String `"Expressir::Model::Declarations::Entity"`.
221
+
222
+ `parent`:: Reference to `SchemaDrop`.
223
+
224
+ === Usage
225
+
226
+ [source,liquid]
227
+ ----
228
+ ## {{ entity.id }}
229
+
230
+ {% if entity.abstract %}
231
+ **Abstract Entity**
232
+ {% endif %}
233
+
234
+ {% if entity.subtype_of.size > 0 %}
235
+ Supertypes:
236
+ {% for super in entity.subtype_of %}
237
+ - {{ super }}
238
+ {% endfor %}
239
+ {% endif %}
240
+
241
+ ### Attributes
242
+
243
+ {% for attr in entity.attributes %}
244
+ - **{{ attr.id }}**: {{ attr.type }}
245
+ {% if attr.optional %}(optional){% endif %}
246
+ {% endfor %}
247
+
248
+ {% if entity.where_rules.size > 0 %}
249
+ ### Constraints
250
+
251
+ {% for rule in entity.where_rules %}
252
+ **{{ rule.id }}**: {{ rule.expression }}
253
+ {% endfor %}
254
+ {% endif %}
255
+ ----
256
+
257
+ === Example
258
+
259
+ [source,ruby]
260
+ ----
261
+ entity_drop = schema_drop.entities.first
262
+
263
+ puts entity_drop.id # "person"
264
+ puts entity_drop.abstract # false
265
+ puts entity_drop.attributes.size # 2
266
+ puts entity_drop.attributes.first.id # "name"
267
+ ----
268
+
269
+ == Type drop
270
+
271
+ Represents an EXPRESS type definition.
272
+
273
+ === Attributes
274
+
275
+ `id`:: Type name (String).
276
+
277
+ `underlying_type`:: The base type object (aggregate, select, etc.).
278
+
279
+ `where_rules`:: Array of `WhereRuleDrop`.
280
+
281
+ `informal_propositions`:: Array of `InformalPropositionRuleDrop`.
282
+
283
+ `remarks`:: Array of documentation strings.
284
+
285
+ `remark_items`:: Array of `RemarkItemDrop`.
286
+
287
+ `source`:: Formatted EXPRESS source code (String).
288
+
289
+ `_class`:: String `"Expressir::Model::Declarations::Type"`.
290
+
291
+ `parent`:: Reference to `SchemaDrop`.
292
+
293
+ === Usage
294
+
295
+ [source,liquid]
296
+ ----
297
+ ### {{ type.id }}
298
+
299
+ Type: {{ type.underlying_type._class }}
300
+
301
+ {% if type.remarks.size > 0 %}
302
+ {{ type.remarks | join: " " }}
303
+ {% endif %}
304
+
305
+ {% if type.where_rules.size > 0 %}
306
+ Constraints:
307
+ {% for rule in type.where_rules %}
308
+ - {{ rule.id }}
309
+ {% endfor %}
310
+ {% endif %}
311
+ ----
312
+
313
+ === Checking type categories
314
+
315
+ [source,liquid]
316
+ ----
317
+ {% if type.underlying_type._class contains "Select" %}
318
+ This is a SELECT type.
319
+ {% elsif type.underlying_type._class contains "Enumeration" %}
320
+ This is an ENUMERATION type.
321
+ {% elsif type.underlying_type._class contains "Aggregate" %}
322
+ This is an AGGREGATE type.
323
+ {% endif %}
324
+ ----
325
+
326
+ === Example
327
+
328
+ [source,ruby]
329
+ ----
330
+ type_drop = schema_drop.types.first
331
+
332
+ puts type_drop.id # "label"
333
+ puts type_drop.underlying_type._class #
334
+ # "Expressir::Model::DataTypes::String"
335
+ ----
336
+
337
+ == Attribute drop
338
+
339
+ Represents an entity attribute.
340
+
341
+ === Attributes
342
+
343
+ `id`:: Attribute name (String).
344
+
345
+ `kind`:: Attribute kind: `"EXPLICIT"`, `"DERIVED"`, or `"INVERSE"`.
346
+
347
+ `optional`:: Boolean indicating if attribute is optional.
348
+
349
+ `type`:: The attribute type object.
350
+
351
+ `expression`:: Expression object (for derived attributes).
352
+
353
+ `supertype_attribute`:: Reference to supertype attribute if redeclared.
354
+
355
+ `remarks`:: Array of documentation strings.
356
+
357
+ `remark_items`:: Array of `RemarkItemDrop`.
358
+
359
+ `source`:: Formatted EXPRESS source code (String).
360
+
361
+ `_class`:: String `"Expressir::Model::Declarations::Attribute"`.
362
+
363
+ `parent`:: Reference to `EntityDrop`.
364
+
365
+ === Usage
366
+
367
+ [source,liquid]
368
+ ----
369
+ {% for attr in entity.attributes %}
370
+ - **{{ attr.id }}**
371
+ - Type: {{ attr.type }}
372
+ - Optional: {{ attr.optional }}
373
+ - Kind: {{ attr.kind }}
374
+ {% if attr.remarks.size > 0 %}
375
+ - Description: {{ attr.remarks | join: " " }}
376
+ {% endif %}
377
+ {% endfor %}
378
+ ----
379
+
380
+ === Example
381
+
382
+ [source,ruby]
383
+ ----
384
+ attr_drop = entity_drop.attributes.first
385
+
386
+ puts attr_drop.id # "name"
387
+ puts attr_drop.kind # "EXPLICIT"
388
+ puts attr_drop.optional # false
389
+ puts attr_drop.type # String representation
390
+ ----
391
+
392
+ == Function drop
393
+
394
+ Represents an EXPRESS function.
395
+
396
+ === Attributes
397
+
398
+ `id`:: Function name (String).
399
+
400
+ `parameters`:: Array of `ParameterDrop`.
401
+
402
+ `return_type`:: Return type object.
403
+
404
+ `types`:: Array of local `TypeDrop`.
405
+
406
+ `entities`:: Array of local `EntityDrop`.
407
+
408
+ `subtype_constraints`:: Array of local `SubtypeConstraintDrop`.
409
+
410
+ `functions`:: Array of nested `FunctionDrop`.
411
+
412
+ `procedures`:: Array of nested `ProcedureDrop`.
413
+
414
+ `constants`:: Array of local `ConstantDrop`.
415
+
416
+ `variables`:: Array of local `VariableDrop`.
417
+
418
+ `statements`:: Array of statement objects.
419
+
420
+ `remarks`:: Array of documentation strings.
421
+
422
+ `remark_items`:: Array of `RemarkItemDrop`.
423
+
424
+ `source`:: Formatted EXPRESS source code (String).
425
+
426
+ `_class`:: String `"Expressir::Model::Declarations::Function"`.
427
+
428
+ `parent`:: Reference to `SchemaDrop`.
429
+
430
+ === Usage
431
+
432
+ [source,liquid]
433
+ ----
434
+ ### {{ function.id }}
435
+
436
+ **Returns**: {{ function.return_type }}
437
+
438
+ {% if function.parameters.size > 0 %}
439
+ **Parameters**:
440
+ {% for param in function.parameters %}
441
+ - {{ param.id }}: {{ param.type }}
442
+ {% endfor %}
443
+ {% endif %}
444
+
445
+ {% if function.remarks.size > 0 %}
446
+ {{ function.remarks | join: " " }}
447
+ {% endif %}
448
+ ----
449
+
450
+ === Example
451
+
452
+ [source,ruby]
453
+ ----
454
+ func_drop = schema_drop.functions.first
455
+
456
+ puts func_drop.id # "bag_to_set"
457
+ puts func_drop.parameters.size # 1
458
+ puts func_drop.return_type # Return type representation
459
+ ----
460
+
461
+ == Procedure drop
462
+
463
+ Similar to Function drop but without return type.
464
+
465
+ === Attributes
466
+
467
+ `id`:: Procedure name (String).
468
+
469
+ `parameters`:: Array of `ParameterDrop`.
470
+
471
+ `types`:: Array of local `TypeDrop`.
472
+
473
+ `entities`:: Array of local `EntityDrop`.
474
+
475
+ `constants`:: Array of local `ConstantDrop`.
476
+
477
+ `variables`:: Array of local `VariableDrop`.
478
+
479
+ `statements`:: Array of statement objects.
480
+
481
+ `remarks`:: Array of documentation strings.
482
+
483
+ `remark_items`:: Array of `RemarkItemDrop`.
484
+
485
+ `source`:: Formatted EXPRESS source code (String).
486
+
487
+ `_class`:: String `"Expressir::Model::Declarations::Procedure"`.
488
+
489
+ `parent`:: Reference to `SchemaDrop`.
490
+
491
+ == Rule drop
492
+
493
+ Represents an EXPRESS global rule.
494
+
495
+ === Attributes
496
+
497
+ `id`:: Rule name (String).
498
+
499
+ `applies_to`:: Array of entities the rule applies to.
500
+
501
+ `types`:: Array of local `TypeDrop`.
502
+
503
+ `entities`:: Array of local `EntityDrop`.
504
+
505
+ `functions`:: Array of local `FunctionDrop`.
506
+
507
+ `procedures`:: Array of local `ProcedureDrop`.
508
+
509
+ `constants`:: Array of local `ConstantDrop`.
510
+
511
+ `variables`:: Array of local `VariableDrop`.
512
+
513
+ `statements`:: Array of statement objects.
514
+
515
+ `where_rules`:: Array of `WhereRuleDrop`.
516
+
517
+ `remarks`:: Array of documentation strings.
518
+
519
+ `remark_items`:: Array of `RemarkItemDrop`.
520
+
521
+ `source`:: Formatted EXPRESS source code (String).
522
+
523
+ `_class`:: String `"Expressir::Model::Declarations::Rule"`.
524
+
525
+ `parent`:: Reference to `SchemaDrop`.
526
+
527
+ == Where rule drop
528
+
529
+ Represents a WHERE constraint.
530
+
531
+ === Attributes
532
+
533
+ `id`:: Rule identifier (String).
534
+
535
+ `expression`:: Constraint expression object.
536
+
537
+ `remarks`:: Array of documentation strings.
538
+
539
+ `remark_items`:: Array of `RemarkItemDrop`.
540
+
541
+ `_class`:: String `"Expressir::Model::Declarations::WhereRule"`.
542
+
543
+ `parent`:: Reference to parent entity or type.
544
+
545
+ === Usage
546
+
547
+ [source,liquid]
548
+ ----
549
+ {% if entity.where_rules.size > 0 %}
550
+ ## Constraints
551
+
552
+ {% for rule in entity.where_rules %}
553
+ ### {{ rule.id }}
554
+
555
+ {{ rule.expression }}
556
+
557
+ {% if rule.remarks.size > 0 %}
558
+ {{ rule.remarks | join: " " }}
559
+ {% endif %}
560
+ {% endfor %}
561
+ {% endif %}
562
+ ----
563
+
564
+ == Interface drop
565
+
566
+ Represents USE_FROM or REFERENCE_FROM declarations.
567
+
568
+ === Attributes
569
+
570
+ `kind`:: Interface kind: `"USE"` or `"REFERENCE"`.
571
+
572
+ `schema`:: Reference to referenced schema.
573
+
574
+ `items`:: Array of `InterfaceItemDrop` for specific items imported.
575
+
576
+ `_class`:: String `"Expressir::Model::Declarations::Interface"`.
577
+
578
+ `parent`:: Reference to `SchemaDrop`.
579
+
580
+ === Usage
581
+
582
+ [source,liquid]
583
+ ----
584
+ {% if schema.interfaces.size > 0 %}
585
+ ## Dependencies
586
+
587
+ {% for interface in schema.interfaces %}
588
+ {% if interface.kind == "USE" %}
589
+ **USE FROM** {{ interface.schema.id }}
590
+ {% else %}
591
+ **REFERENCE FROM** {{ interface.schema.id }}
592
+ {% endif %}
593
+
594
+ {% if interface.items.size > 0 %}
595
+ Items:
596
+ {% for item in interface.items %}
597
+ - {{ item.id }}
598
+ {% endfor %}
599
+ {% endif %}
600
+ {% endfor %}
601
+ {% endif %}
602
+ ----
603
+
604
+ == Schema version drop
605
+
606
+ Represents schema version information.
607
+
608
+ === Attributes
609
+
610
+ `value`:: Version string (e.g., `"ISO 10303-41:2019"`).
611
+
612
+ `items`:: Array of `SchemaVersionItemDrop` for detailed version info.
613
+
614
+ `_class`:: String `"Expressir::Model::Declarations::SchemaVersion"`.
615
+
616
+ `parent`:: Reference to `SchemaDrop`.
617
+
618
+ === Usage
619
+
620
+ [source,liquid]
621
+ ----
622
+ {% if schema.version %}
623
+ **Version**: {{ schema.version.value }}
624
+ {% endif %}
625
+ ----
626
+
627
+ == Parameter drop
628
+
629
+ Represents function/procedure parameters.
630
+
631
+ === Attributes
632
+
633
+ `id`:: Parameter name (String).
634
+
635
+ `type`:: Parameter type object.
636
+
637
+ `var`:: Boolean indicating VAR parameter.
638
+
639
+ `remarks`:: Array of documentation strings.
640
+
641
+ `_class`:: String `"Expressir::Model::Declarations::Parameter"`.
642
+
643
+ `parent`:: Reference to function or procedure.
644
+
645
+ === Usage
646
+
647
+ [source,liquid]
648
+ ----
649
+ {% for param in function.parameters %}
650
+ - {{ param.id }}: {{ param.type }}
651
+ {% if param.var %}(VAR){% endif %}
652
+ {% endfor %}
653
+ ----
654
+
655
+ == Variable drop
656
+
657
+ Represents local variables in functions/rules/procedures.
658
+
659
+ === Attributes
660
+
661
+ `id`:: Variable name (String).
662
+
663
+ `type`:: Variable type object.
664
+
665
+ `remarks`:: Array of documentation strings.
666
+
667
+ `_class`:: String `"Expressir::Model::Declarations::Variable"`.
668
+
669
+ `parent`:: Reference to containing function, rule, or procedure.
670
+
671
+ == Constant drop
672
+
673
+ Represents EXPRESS constant definitions.
674
+
675
+ === Attributes
676
+
677
+ `id`:: Constant name (String).
678
+
679
+ `type`:: Constant type object.
680
+
681
+ `expression`:: Constant value expression.
682
+
683
+ `remarks`:: Array of documentation strings.
684
+
685
+ `_class`:: String `"Expressir::Model::Declarations::Constant"`.
686
+
687
+ `parent`:: Reference to `SchemaDrop` or function/rule/procedure.
688
+
689
+ == Navigating between drops
690
+
691
+ Drops maintain parent-child relationships for navigation:
692
+
693
+ [source,liquid]
694
+ ----
695
+ {% comment %}Navigate up{% endcomment %}
696
+ {{ entity.parent.id }} {# Schema name #}
697
+ {{ attribute.parent.id }} {# Entity name #}
698
+
699
+ {% comment %}Navigate down{% endcomment %}
700
+ {% for entity in schema.entities %}
701
+ {% for attr in entity.attributes %}
702
+ {{ schema.id }}.{{ entity.id }}.{{ attr.id }}
703
+ {% endfor %}
704
+ {% endfor %}
705
+
706
+ {% comment %}Navigate across{% endcomment %}
707
+ {% for entity in schema.entities %}
708
+ Same schema entities: {{ schema.entities.size }}
709
+ {% endfor %}
710
+ ----
711
+
712
+ == Common patterns
713
+
714
+ === Checking for empty collections
715
+
716
+ [source,liquid]
717
+ ----
718
+ {% if entity.attributes.size > 0 %}
719
+ Entity has attributes
720
+ {% else %}
721
+ Entity has no attributes
722
+ {% endif %}
723
+
724
+ {% if schema.entities and schema.entities.size > 0 %}
725
+ Schema has entities
726
+ {% endif %}
727
+ ----
728
+
729
+ === Accessing nested data
730
+
731
+ [source,liquid]
732
+ ----
733
+ {% for schema in repository.schemas %}
734
+ {% for entity in schema.entities %}
735
+ {% for attr in entity.attributes %}
736
+ {{ schema.id }}.{{ entity.id }}.{{ attr.id }}
737
+ {% endfor %}
738
+ {% endfor %}
739
+ {% endfor %}
740
+ ----
741
+
742
+ === Type checking with _class
743
+
744
+ [source,liquid]
745
+ ----
746
+ {% if object._class contains "Entity" %}
747
+ This is an entity
748
+ {% elsif object._class contains "Type" %}
749
+ This is a type
750
+ {% elsif object._class contains "Function" %}
751
+ This is a function
752
+ {% endif %}
753
+ ----
754
+
755
+ === Checking object types
756
+
757
+ [source,liquid]
758
+ ----
759
+ {% if type.underlying_type._class contains "Select" %}
760
+ SELECT type
761
+ {% elsif type.underlying_type._class contains "Enumeration" %}
762
+ ENUMERATION type
763
+ {% elsif type.underlying_type._class contains "Aggregate" %}
764
+ AGGREGATE type
765
+ {% endif %}
766
+ ----
767
+
768
+ == Best practices
769
+
770
+ **Always check size before looping**::
771
+ [source,liquid]
772
+ ----
773
+ {% if entity.attributes.size > 0 %}
774
+ {% for attr in entity.attributes %}
775
+ ...
776
+ {% endfor %}
777
+ {% endif %}
778
+ ----
779
+
780
+ **Use meaningful variable names**::
781
+ [source,liquid]
782
+ ----
783
+ {% comment %}❌ Unclear{% endcomment %}
784
+ {% for e in schema.entities %}
785
+
786
+ {% comment %}✅ Clear{% endcomment %}
787
+ {% for entity in schema.entities %}
788
+ ----
789
+
790
+ **Access parent carefully**::
791
+ [source,liquid]
792
+ ----
793
+ {% if entity.parent %}
794
+ Schema: {{ entity.parent.id }}
795
+ {% endif %}
796
+ ----
797
+
798
+ **Cache frequently accessed values**::
799
+ [source,liquid]
800
+ ----
801
+ {% assign entity_count = schema.entities.size %}
802
+ {% assign type_count = schema.types.size %}
803
+ {% assign total = entity_count | plus: type_count %}
804
+ ----
805
+
806
+ == Next steps
807
+
808
+ Apply this knowledge:
809
+
810
+ * link:basic-templates.html[Basic Templates] - Learn template syntax
811
+ * link:filters-and-tags.html[Filters and Tags] - Transform drop data
812
+ * link:documentation-generation.html[Documentation Generation] - Build
813
+ complete systems
814
+ * link:../../_tutorials/liquid-templates.html[Liquid Templates Tutorial]
815
+ - Practice exercises
816
+
817
+ == Summary
818
+
819
+ Expressir Liquid drops provide:
820
+
821
+ * ✅ Template-friendly access to all model attributes
822
+ * ✅ Parent-child navigation through relationships
823
+ * ✅ Consistent interface across all drop types
824
+ * ✅ Safe exposure of data without implementation details
825
+ * ✅ Full coverage of EXPRESS constructs
826
+ * ✅ Type information via `_class` attribute
827
+
828
+ Understanding drops enables effective template creation for EXPRESS
829
+ schema documentation.