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.
- 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 +244 -39
- data/Gemfile +2 -1
- data/README.adoc +621 -54
- 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/cli.rb +12 -4
- 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 +15 -2
- metadata +114 -4
- data/docs/benchmarking.adoc +0 -107
- data/docs/liquid_drops.adoc +0 -1547
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Formatting Schemas
|
|
3
|
+
parent: Ruby API
|
|
4
|
+
grand_parent: Guides
|
|
5
|
+
nav_order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
= Formatting Schemas
|
|
9
|
+
|
|
10
|
+
== Purpose
|
|
11
|
+
|
|
12
|
+
The Formatter API converts EXPRESS model objects back into formatted EXPRESS
|
|
13
|
+
language text. This is essential for generating human-readable schema files,
|
|
14
|
+
creating documentation, and implementing schema transformation tools.
|
|
15
|
+
|
|
16
|
+
== References
|
|
17
|
+
|
|
18
|
+
* link:parsing-files.html[Parsing Files] - Creating model objects
|
|
19
|
+
* link:working-with-repository.html[Working with Repository] - Managing schemas
|
|
20
|
+
* link:../cli/format-schemas.html[CLI: Format Schemas]
|
|
21
|
+
|
|
22
|
+
== Concepts
|
|
23
|
+
|
|
24
|
+
formatter:: Component that converts model objects to EXPRESS text
|
|
25
|
+
hyperlink_formatter:: Specialized formatter that generates HTML links
|
|
26
|
+
pretty_printing:: Formatting with consistent indentation and spacing
|
|
27
|
+
no_remarks:: Option to exclude documentation comments from output
|
|
28
|
+
source_preservation:: Maintaining original formatting and comments
|
|
29
|
+
|
|
30
|
+
== Basic usage
|
|
31
|
+
|
|
32
|
+
=== Format a complete schema
|
|
33
|
+
|
|
34
|
+
[source,ruby]
|
|
35
|
+
----
|
|
36
|
+
require "expressir"
|
|
37
|
+
|
|
38
|
+
# Parse schema
|
|
39
|
+
repository = Expressir::Express::Parser.from_file("schema.exp")
|
|
40
|
+
schema = repository.schemas.first
|
|
41
|
+
|
|
42
|
+
# Create formatter
|
|
43
|
+
formatter = Expressir::Express::Formatter.new
|
|
44
|
+
|
|
45
|
+
# Format to EXPRESS text
|
|
46
|
+
output = formatter.format(schema)
|
|
47
|
+
|
|
48
|
+
# Save to file
|
|
49
|
+
File.write("formatted_schema.exp", output)
|
|
50
|
+
----
|
|
51
|
+
|
|
52
|
+
=== Format individual elements
|
|
53
|
+
|
|
54
|
+
The formatter can format any model element:
|
|
55
|
+
|
|
56
|
+
[source,ruby]
|
|
57
|
+
----
|
|
58
|
+
formatter = Expressir::Express::Formatter.new
|
|
59
|
+
|
|
60
|
+
# Format an entity
|
|
61
|
+
entity = schema.entities.first
|
|
62
|
+
entity_text = formatter.format(entity)
|
|
63
|
+
|
|
64
|
+
# Format a type
|
|
65
|
+
type = schema.types.first
|
|
66
|
+
type_text = formatter.format(type)
|
|
67
|
+
|
|
68
|
+
# Format a function
|
|
69
|
+
function = schema.functions.first
|
|
70
|
+
function_text = formatter.format(function)
|
|
71
|
+
----
|
|
72
|
+
|
|
73
|
+
== Formatter options
|
|
74
|
+
|
|
75
|
+
=== Excluding remarks
|
|
76
|
+
|
|
77
|
+
Remove all documentation comments from output:
|
|
78
|
+
|
|
79
|
+
[source,ruby]
|
|
80
|
+
----
|
|
81
|
+
# Include remarks (default)
|
|
82
|
+
formatter = Expressir::Express::Formatter.new(no_remarks: false)
|
|
83
|
+
output_with_remarks = formatter.format(schema)
|
|
84
|
+
|
|
85
|
+
# Exclude remarks
|
|
86
|
+
formatter = Expressir::Express::Formatter.new(no_remarks: true)
|
|
87
|
+
output_without_remarks = formatter.format(schema)
|
|
88
|
+
----
|
|
89
|
+
|
|
90
|
+
This is useful for:
|
|
91
|
+
|
|
92
|
+
* Creating clean reference implementations
|
|
93
|
+
* Reducing file size
|
|
94
|
+
* Generating machine-readable output
|
|
95
|
+
* Removing potentially sensitive comments
|
|
96
|
+
|
|
97
|
+
=== Accessing formatter settings
|
|
98
|
+
|
|
99
|
+
[source,ruby]
|
|
100
|
+
----
|
|
101
|
+
formatter = Expressir::Express::Formatter.new(no_remarks: true)
|
|
102
|
+
|
|
103
|
+
# Check current settings
|
|
104
|
+
puts "Remarks excluded: #{formatter.no_remarks}"
|
|
105
|
+
|
|
106
|
+
# Change settings
|
|
107
|
+
formatter.no_remarks = false
|
|
108
|
+
----
|
|
109
|
+
|
|
110
|
+
== Static formatting
|
|
111
|
+
|
|
112
|
+
Use the static `format` method for one-off formatting:
|
|
113
|
+
|
|
114
|
+
[source,ruby]
|
|
115
|
+
----
|
|
116
|
+
# Format without creating instance
|
|
117
|
+
output = Expressir::Express::Formatter.format(schema)
|
|
118
|
+
|
|
119
|
+
# Equivalent to:
|
|
120
|
+
formatter = Expressir::Express::Formatter.new
|
|
121
|
+
output = formatter.format(schema)
|
|
122
|
+
----
|
|
123
|
+
|
|
124
|
+
This is convenient for simple formatting operations.
|
|
125
|
+
|
|
126
|
+
== Formatting complete repositories
|
|
127
|
+
|
|
128
|
+
=== Format all schemas
|
|
129
|
+
|
|
130
|
+
[source,ruby]
|
|
131
|
+
----
|
|
132
|
+
repository = Expressir::Express::Parser.from_file("multi_schema.exp")
|
|
133
|
+
formatter = Expressir::Express::Formatter.new
|
|
134
|
+
|
|
135
|
+
# Format entire repository
|
|
136
|
+
output = formatter.format(repository)
|
|
137
|
+
|
|
138
|
+
# Output contains all schemas separated by blank lines
|
|
139
|
+
File.write("all_schemas.exp", output)
|
|
140
|
+
----
|
|
141
|
+
|
|
142
|
+
=== Format schemas individually
|
|
143
|
+
|
|
144
|
+
[source,ruby]
|
|
145
|
+
----
|
|
146
|
+
repository.schemas.each do |schema|
|
|
147
|
+
output = formatter.format(schema)
|
|
148
|
+
filename = "#{schema.id}.exp"
|
|
149
|
+
File.write(filename, output)
|
|
150
|
+
puts "Wrote #{filename}"
|
|
151
|
+
end
|
|
152
|
+
----
|
|
153
|
+
|
|
154
|
+
== Formatting specific constructs
|
|
155
|
+
|
|
156
|
+
=== Schema heads
|
|
157
|
+
|
|
158
|
+
Format just the schema header:
|
|
159
|
+
|
|
160
|
+
[source,ruby]
|
|
161
|
+
----
|
|
162
|
+
# Schema head includes SCHEMA declaration and interfaces
|
|
163
|
+
schema = repository.schemas.first
|
|
164
|
+
|
|
165
|
+
# Note: schema_head_formatter is internal
|
|
166
|
+
# Use regular formatter on the full schema instead
|
|
167
|
+
formatter = Expressir::Express::Formatter.new
|
|
168
|
+
output = formatter.format(schema)
|
|
169
|
+
----
|
|
170
|
+
|
|
171
|
+
=== Entity definitions
|
|
172
|
+
|
|
173
|
+
[source,ruby]
|
|
174
|
+
----
|
|
175
|
+
entity = schema.entities.first
|
|
176
|
+
formatter = Expressir::Express::Formatter.new
|
|
177
|
+
|
|
178
|
+
output = formatter.format(entity)
|
|
179
|
+
# Produces:
|
|
180
|
+
# ENTITY entity_name;
|
|
181
|
+
# attribute1 : STRING;
|
|
182
|
+
# attribute2 : INTEGER;
|
|
183
|
+
# END_ENTITY;
|
|
184
|
+
----
|
|
185
|
+
|
|
186
|
+
=== Type definitions
|
|
187
|
+
|
|
188
|
+
[source,ruby]
|
|
189
|
+
----
|
|
190
|
+
type = schema.types.first
|
|
191
|
+
formatter = Expressir::Express::Formatter.new
|
|
192
|
+
|
|
193
|
+
output = formatter.format(type)
|
|
194
|
+
# Produces:
|
|
195
|
+
# TYPE type_name = SELECT
|
|
196
|
+
# (option1,
|
|
197
|
+
# option2,
|
|
198
|
+
# option3);
|
|
199
|
+
# END_TYPE;
|
|
200
|
+
----
|
|
201
|
+
|
|
202
|
+
=== Functions and procedures
|
|
203
|
+
|
|
204
|
+
[source,ruby]
|
|
205
|
+
----
|
|
206
|
+
function = schema.functions.first
|
|
207
|
+
formatter = Expressir::Express::Formatter.new
|
|
208
|
+
|
|
209
|
+
output = formatter.format(function)
|
|
210
|
+
# Produces complete function definition with:
|
|
211
|
+
# - Parameter declarations
|
|
212
|
+
# - Local variables
|
|
213
|
+
# - Statements
|
|
214
|
+
# - Return type
|
|
215
|
+
----
|
|
216
|
+
|
|
217
|
+
== HyperLinkFormatter
|
|
218
|
+
|
|
219
|
+
The HyperLinkFormatter generates HTML output with hyperlinks for cross-references:
|
|
220
|
+
|
|
221
|
+
[source,ruby]
|
|
222
|
+
----
|
|
223
|
+
require "expressir/express/hyperlink_formatter"
|
|
224
|
+
|
|
225
|
+
# Create hyperlink formatter
|
|
226
|
+
formatter = Expressir::Express::HyperLinkFormatter.new
|
|
227
|
+
|
|
228
|
+
# Format schema with hyperlinks
|
|
229
|
+
html_output = formatter.format(schema)
|
|
230
|
+
|
|
231
|
+
# Output contains <a> tags for references
|
|
232
|
+
File.write("schema.html", html_output)
|
|
233
|
+
----
|
|
234
|
+
|
|
235
|
+
This is useful for:
|
|
236
|
+
|
|
237
|
+
* Generating browsable schema documentation
|
|
238
|
+
* Creating online schema viewers
|
|
239
|
+
* Building schema navigation tools
|
|
240
|
+
|
|
241
|
+
=== Hyperlink format
|
|
242
|
+
|
|
243
|
+
The HyperLinkFormatter wraps references in HTML links:
|
|
244
|
+
|
|
245
|
+
[source,html]
|
|
246
|
+
----
|
|
247
|
+
<!-- Entity reference becomes a link -->
|
|
248
|
+
<a href="#entity_name">entity_name</a>
|
|
249
|
+
|
|
250
|
+
<!-- Type reference becomes a link -->
|
|
251
|
+
<a href="#type_name">type_name</a>
|
|
252
|
+
|
|
253
|
+
<!-- Schema reference becomes a link -->
|
|
254
|
+
<a href="schema_name.html">schema_name</a>
|
|
255
|
+
----
|
|
256
|
+
|
|
257
|
+
== Formatting options and output
|
|
258
|
+
|
|
259
|
+
=== Consistent indentation
|
|
260
|
+
|
|
261
|
+
The formatter applies consistent indentation:
|
|
262
|
+
|
|
263
|
+
[source,ruby]
|
|
264
|
+
----
|
|
265
|
+
formatter = Expressir::Express::Formatter.new
|
|
266
|
+
output = formatter.format(entity)
|
|
267
|
+
|
|
268
|
+
# Produces properly indented output:
|
|
269
|
+
# ENTITY example;
|
|
270
|
+
# attribute1 : STRING;
|
|
271
|
+
# DERIVE
|
|
272
|
+
# derived_attr : INTEGER := 42;
|
|
273
|
+
# WHERE
|
|
274
|
+
# WR1: attribute1 <> '';
|
|
275
|
+
# END_ENTITY;
|
|
276
|
+
----
|
|
277
|
+
|
|
278
|
+
Indentation rules:
|
|
279
|
+
|
|
280
|
+
* 2 spaces per level (configurable via INDENT_WIDTH constant)
|
|
281
|
+
* Attributes indented under ENTITY
|
|
282
|
+
* WHERE rules indented under WHERE keyword
|
|
283
|
+
* Nested constructs properly indented
|
|
284
|
+
|
|
285
|
+
=== Operator precedence
|
|
286
|
+
|
|
287
|
+
The formatter handles operator precedence correctly:
|
|
288
|
+
|
|
289
|
+
[source,ruby]
|
|
290
|
+
----
|
|
291
|
+
# Adds parentheses where needed
|
|
292
|
+
expression = parse_expression("a + b * c")
|
|
293
|
+
formatted = formatter.format(expression)
|
|
294
|
+
# Produces: a + (b * c)
|
|
295
|
+
|
|
296
|
+
# Removes unnecessary parentheses
|
|
297
|
+
expression = parse_expression("(a + b) + c")
|
|
298
|
+
formatted = formatter.format(expression)
|
|
299
|
+
# Produces: a + b + c
|
|
300
|
+
----
|
|
301
|
+
|
|
302
|
+
=== Line wrapping
|
|
303
|
+
|
|
304
|
+
Long lines are wrapped appropriately:
|
|
305
|
+
|
|
306
|
+
[source,ruby]
|
|
307
|
+
----
|
|
308
|
+
# Long parameter lists are wrapped
|
|
309
|
+
output = formatter.format(function)
|
|
310
|
+
# Produces:
|
|
311
|
+
# FUNCTION long_function(param1 : STRING;
|
|
312
|
+
# param2 : INTEGER;
|
|
313
|
+
# param3 : BOOLEAN) : REAL;
|
|
314
|
+
----
|
|
315
|
+
|
|
316
|
+
== Integrating with workflows
|
|
317
|
+
|
|
318
|
+
=== Schema validation and formatting
|
|
319
|
+
|
|
320
|
+
[source,ruby]
|
|
321
|
+
----
|
|
322
|
+
# Parse, validate, and format
|
|
323
|
+
repository = Expressir::Express::Parser.from_file("schema.exp")
|
|
324
|
+
|
|
325
|
+
# Validate
|
|
326
|
+
result = repository.validate
|
|
327
|
+
if result[:valid?]
|
|
328
|
+
puts "Schema is valid"
|
|
329
|
+
|
|
330
|
+
# Format and save
|
|
331
|
+
formatter = Expressir::Express::Formatter.new(no_remarks: true)
|
|
332
|
+
output = formatter.format(repository)
|
|
333
|
+
File.write("validated_schema.exp", output)
|
|
334
|
+
else
|
|
335
|
+
puts "Validation errors:"
|
|
336
|
+
result[:errors].each { |e| puts " #{e}" }
|
|
337
|
+
end
|
|
338
|
+
----
|
|
339
|
+
|
|
340
|
+
=== Schema transformation
|
|
341
|
+
|
|
342
|
+
[source,ruby]
|
|
343
|
+
----
|
|
344
|
+
# Parse original schema
|
|
345
|
+
repository = Expressir::Express::Parser.from_file("original.exp")
|
|
346
|
+
|
|
347
|
+
# Modify schema (example: add version)
|
|
348
|
+
schema = repository.schemas.first
|
|
349
|
+
schema.version = Expressir::Model::Declarations::SchemaVersion.new(
|
|
350
|
+
value: "2.0"
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
# Format and save modified schema
|
|
354
|
+
formatter = Expressir::Express::Formatter.new
|
|
355
|
+
output = formatter.format(repository)
|
|
356
|
+
File.write("modified.exp", output)
|
|
357
|
+
----
|
|
358
|
+
|
|
359
|
+
=== Documentation generation
|
|
360
|
+
|
|
361
|
+
[source,ruby]
|
|
362
|
+
----
|
|
363
|
+
repository = Expressir::Express::Parser.from_file("schema.exp")
|
|
364
|
+
|
|
365
|
+
# Generate clean reference
|
|
366
|
+
clean_formatter = Expressir::Express::Formatter.new(no_remarks: true)
|
|
367
|
+
reference = clean_formatter.format(repository)
|
|
368
|
+
File.write("reference.exp", reference)
|
|
369
|
+
|
|
370
|
+
# Generate documentation version with remarks
|
|
371
|
+
doc_formatter = Expressir::Express::Formatter.new(no_remarks: false)
|
|
372
|
+
documented = doc_formatter.format(repository)
|
|
373
|
+
File.write("documented.exp", documented)
|
|
374
|
+
----
|
|
375
|
+
|
|
376
|
+
=== Batch processing
|
|
377
|
+
|
|
378
|
+
[source,ruby]
|
|
379
|
+
----
|
|
380
|
+
files = Dir.glob("schemas/**/*.exp")
|
|
381
|
+
formatter = Expressir::Express::Formatter.new(no_remarks: true)
|
|
382
|
+
|
|
383
|
+
files.each do |file|
|
|
384
|
+
begin
|
|
385
|
+
repository = Expressir::Express::Parser.from_file(file)
|
|
386
|
+
output = formatter.format(repository)
|
|
387
|
+
|
|
388
|
+
# Save to output directory
|
|
389
|
+
output_file = file.sub("schemas/", "formatted/")
|
|
390
|
+
FileUtils.mkdir_p(File.dirname(output_file))
|
|
391
|
+
File.write(output_file, output)
|
|
392
|
+
|
|
393
|
+
puts "✓ Formatted #{file}"
|
|
394
|
+
rescue => e
|
|
395
|
+
puts "✗ Error formatting #{file}: #{e.message}"
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
----
|
|
399
|
+
|
|
400
|
+
== Performance considerations
|
|
401
|
+
|
|
402
|
+
=== Reuse formatter instances
|
|
403
|
+
|
|
404
|
+
[source,ruby]
|
|
405
|
+
----
|
|
406
|
+
# Create once
|
|
407
|
+
formatter = Expressir::Express::Formatter.new
|
|
408
|
+
|
|
409
|
+
# Reuse for multiple schemas
|
|
410
|
+
repository.schemas.each do |schema|
|
|
411
|
+
output = formatter.format(schema)
|
|
412
|
+
File.write("#{schema.id}.exp", output)
|
|
413
|
+
end
|
|
414
|
+
----
|
|
415
|
+
|
|
416
|
+
=== Format selectively
|
|
417
|
+
|
|
418
|
+
For large repositories, format only what you need:
|
|
419
|
+
|
|
420
|
+
[source,ruby]
|
|
421
|
+
----
|
|
422
|
+
# Format specific schemas
|
|
423
|
+
selected_schemas = repository.schemas.select do |s|
|
|
424
|
+
s.id.start_with?("action_")
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
formatter = Expressir::Express::Formatter.new
|
|
428
|
+
selected_schemas.each do |schema|
|
|
429
|
+
output = formatter.format(schema)
|
|
430
|
+
File.write("#{schema.id}.exp", output)
|
|
431
|
+
end
|
|
432
|
+
----
|
|
433
|
+
|
|
434
|
+
=== Memory management
|
|
435
|
+
|
|
436
|
+
For very large schemas, process in chunks:
|
|
437
|
+
|
|
438
|
+
[source,ruby]
|
|
439
|
+
----
|
|
440
|
+
formatter = Expressir::Express::Formatter.new
|
|
441
|
+
|
|
442
|
+
File.open("output.exp", "w") do |f|
|
|
443
|
+
repository.schemas.each do |schema|
|
|
444
|
+
output = formatter.format(schema)
|
|
445
|
+
f.write(output)
|
|
446
|
+
f.write("\n\n")
|
|
447
|
+
|
|
448
|
+
# Output is written and can be garbage collected
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
----
|
|
452
|
+
|
|
453
|
+
== Output handling
|
|
454
|
+
|
|
455
|
+
=== Direct file writing
|
|
456
|
+
|
|
457
|
+
[source,ruby]
|
|
458
|
+
----
|
|
459
|
+
formatter = Expressir::Express::Formatter.new
|
|
460
|
+
output = formatter.format(repository)
|
|
461
|
+
File.write("output.exp", output)
|
|
462
|
+
----
|
|
463
|
+
|
|
464
|
+
=== Streaming output
|
|
465
|
+
|
|
466
|
+
[source,ruby]
|
|
467
|
+
----
|
|
468
|
+
formatter = Expressir::Express::Formatter.new
|
|
469
|
+
|
|
470
|
+
File.open("output.exp", "w") do |file|
|
|
471
|
+
repository.schemas.each do |schema|
|
|
472
|
+
file.puts formatter.format(schema)
|
|
473
|
+
file.puts # Blank line between schemas
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
----
|
|
477
|
+
|
|
478
|
+
=== String handling
|
|
479
|
+
|
|
480
|
+
[source,ruby]
|
|
481
|
+
----
|
|
482
|
+
formatter = Expressir::Express::Formatter.new
|
|
483
|
+
output = formatter.format(schema)
|
|
484
|
+
|
|
485
|
+
# Process as string
|
|
486
|
+
lines = output.lines
|
|
487
|
+
line_count = lines.size
|
|
488
|
+
entity_count = lines.count { |l| l.include?("ENTITY") }
|
|
489
|
+
|
|
490
|
+
puts "Output: #{line_count} lines, #{entity_count} entities"
|
|
491
|
+
----
|
|
492
|
+
|
|
493
|
+
== Comparing with original
|
|
494
|
+
|
|
495
|
+
=== Round-trip verification
|
|
496
|
+
|
|
497
|
+
[source,ruby]
|
|
498
|
+
----
|
|
499
|
+
original_file = "schema.exp"
|
|
500
|
+
|
|
501
|
+
# Parse original
|
|
502
|
+
repository = Expressir::Express::Parser.from_file(original_file)
|
|
503
|
+
|
|
504
|
+
# Format back to EXPRESS
|
|
505
|
+
formatter = Expressir::Express::Formatter.new
|
|
506
|
+
formatted = formatter.format(repository)
|
|
507
|
+
|
|
508
|
+
# Parse formatted version
|
|
509
|
+
repo2 = Expressir::Express::Parser.from_exp(formatted)
|
|
510
|
+
|
|
511
|
+
# Compare
|
|
512
|
+
if repository.schemas.size == repo2.schemas.size
|
|
513
|
+
puts "Round-trip successful"
|
|
514
|
+
else
|
|
515
|
+
puts "Round-trip failed: schema count mismatch"
|
|
516
|
+
end
|
|
517
|
+
----
|
|
518
|
+
|
|
519
|
+
=== Structural comparison
|
|
520
|
+
|
|
521
|
+
[source,ruby]
|
|
522
|
+
----
|
|
523
|
+
# Parse both versions
|
|
524
|
+
orig_repo = Expressir::Express::Parser.from_file("original.exp")
|
|
525
|
+
fmt_repo = Expressir::Express::Parser.from_exp(formatted_output)
|
|
526
|
+
|
|
527
|
+
# Compare structure
|
|
528
|
+
orig_schema = orig_repo.schemas.first
|
|
529
|
+
fmt_schema = fmt_repo.schemas.first
|
|
530
|
+
|
|
531
|
+
puts "Entities: #{orig_schema.entities.size} vs #{fmt_schema.entities.size}"
|
|
532
|
+
puts "Types: #{orig_schema.types.size} vs #{fmt_schema.types.size}"
|
|
533
|
+
puts "Functions: #{orig_schema.functions.size} vs #{fmt_schema.functions.size}"
|
|
534
|
+
----
|
|
535
|
+
|
|
536
|
+
== Common patterns
|
|
537
|
+
|
|
538
|
+
=== Clean and format
|
|
539
|
+
|
|
540
|
+
[source,ruby]
|
|
541
|
+
----
|
|
542
|
+
# Remove remarks and reformat
|
|
543
|
+
repository = Expressir::Express::Parser.from_file("messy.exp")
|
|
544
|
+
formatter = Expressir::Express::Formatter.new(no_remarks: true)
|
|
545
|
+
clean_output = formatter.format(repository)
|
|
546
|
+
File.write("clean.exp", clean_output)
|
|
547
|
+
----
|
|
548
|
+
|
|
549
|
+
=== Extract specific elements
|
|
550
|
+
|
|
551
|
+
[source,ruby]
|
|
552
|
+
----
|
|
553
|
+
# Format only entities
|
|
554
|
+
repository = Expressir::Express::Parser.from_file("schema.exp")
|
|
555
|
+
formatter = Expressir::Express::Formatter.new
|
|
556
|
+
|
|
557
|
+
schema = repository.schemas.first
|
|
558
|
+
schema.entities.each do |entity|
|
|
559
|
+
puts formatter.format(entity)
|
|
560
|
+
puts # Blank line separator
|
|
561
|
+
end
|
|
562
|
+
----
|
|
563
|
+
|
|
564
|
+
=== Generate partial schema
|
|
565
|
+
|
|
566
|
+
[source,ruby]
|
|
567
|
+
----
|
|
568
|
+
# Create new schema with subset of elements
|
|
569
|
+
original = repository.schemas.first
|
|
570
|
+
subset = Expressir::Model::Declarations::Schema.new(
|
|
571
|
+
id: "#{original.id}_subset"
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
# Copy selected entities
|
|
575
|
+
subset.entities = original.entities.first(10)
|
|
576
|
+
|
|
577
|
+
# Format subset
|
|
578
|
+
formatter = Expressir::Express::Formatter.new
|
|
579
|
+
output = formatter.format(subset)
|
|
580
|
+
----
|
|
581
|
+
|
|
582
|
+
== Next steps
|
|
583
|
+
|
|
584
|
+
* link:../cli/format-schemas.html[CLI Format Command] - Command-line formatting
|
|
585
|
+
* link:parsing-files.html[Parsing Files] - Creating model objects to format
|
|
586
|
+
|
|
587
|
+
== Summary
|
|
588
|
+
|
|
589
|
+
The Formatter API provides comprehensive schema output capabilities:
|
|
590
|
+
|
|
591
|
+
* Format complete repositories or individual elements
|
|
592
|
+
* Control remarks inclusion with `no_remarks` option
|
|
593
|
+
* Consistent indentation and pretty-printing
|
|
594
|
+
* HyperLinkFormatter for HTML output with cross-references
|
|
595
|
+
* Integration with parsing, validation, and transformation workflows
|
|
596
|
+
* Performance optimizations for large schemas
|
|
597
|
+
|
|
598
|
+
Key takeaways:
|
|
599
|
+
|
|
600
|
+
* Create formatter instances with appropriate options
|
|
601
|
+
* Reuse formatter instances for multiple operations
|
|
602
|
+
* Use `no_remarks: true` for clean reference output
|
|
603
|
+
* HyperLinkFormatter generates HTML with hyperlinks
|
|
604
|
+
* Round-trip parsing verifies formatting correctness
|
|
605
|
+
* Formatter handles operator precedence and line wrapping automatically
|