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,1038 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Programmatic Usage
|
|
3
|
+
parent: Changes
|
|
4
|
+
grand_parent: Guides
|
|
5
|
+
nav_order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
= Programmatic Usage
|
|
9
|
+
|
|
10
|
+
== Purpose
|
|
11
|
+
|
|
12
|
+
The Expressir Changes API provides Ruby classes for programmatically creating,
|
|
13
|
+
reading, updating, and managing EXPRESS Changes files. This guide covers the
|
|
14
|
+
complete Ruby API for working with changes.
|
|
15
|
+
|
|
16
|
+
== References
|
|
17
|
+
|
|
18
|
+
* link:index.html[Changes Overview] - Introduction to Changes files
|
|
19
|
+
* link:changes-format.html[Changes Format] - YAML format specification
|
|
20
|
+
* link:validating-changes.html[Validating Changes] - Validation guide
|
|
21
|
+
* link:importing-eengine.html[Importing from Express Engine] - Import guide
|
|
22
|
+
|
|
23
|
+
== Concepts
|
|
24
|
+
|
|
25
|
+
SchemaChange:: Top-level class representing a complete Changes file for a
|
|
26
|
+
schema
|
|
27
|
+
|
|
28
|
+
VersionChange:: Class representing changes for a specific version
|
|
29
|
+
|
|
30
|
+
ItemChange:: Class representing a single change to an EXPRESS construct
|
|
31
|
+
|
|
32
|
+
MappingChange:: Class representing a mapping-related change
|
|
33
|
+
|
|
34
|
+
round-trip serialization:: Loading from YAML and saving back to YAML with
|
|
35
|
+
consistent formatting
|
|
36
|
+
|
|
37
|
+
== Core classes
|
|
38
|
+
|
|
39
|
+
The Changes API consists of four main model classes:
|
|
40
|
+
|
|
41
|
+
[`Expressir::Changes::SchemaChange`](../../references/data-model/changes.html#schema-change)::
|
|
42
|
+
Top-level container for all changes to a schema
|
|
43
|
+
|
|
44
|
+
[`Expressir::Changes::VersionChange`](../../references/data-model/changes.html#version-change)::
|
|
45
|
+
Changes for a specific version
|
|
46
|
+
|
|
47
|
+
[`Expressir::Changes::ItemChange`](../../references/data-model/changes.html#item-change)::
|
|
48
|
+
Individual change to an EXPRESS construct
|
|
49
|
+
|
|
50
|
+
[`Expressir::Changes::MappingChange`](../../references/data-model/changes.html#mapping-change)::
|
|
51
|
+
Mapping-related change for ARM/MIM schemas
|
|
52
|
+
|
|
53
|
+
== Reading Changes files
|
|
54
|
+
|
|
55
|
+
=== Loading from file
|
|
56
|
+
|
|
57
|
+
Load an existing Changes file:
|
|
58
|
+
|
|
59
|
+
[source,ruby]
|
|
60
|
+
----
|
|
61
|
+
require "expressir/changes"
|
|
62
|
+
|
|
63
|
+
# Load from file
|
|
64
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
65
|
+
"schema.changes.yaml"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Access top-level properties
|
|
69
|
+
puts "Schema: #{changes.schema}"
|
|
70
|
+
puts "Versions: #{changes.versions&.size || 0}"
|
|
71
|
+
----
|
|
72
|
+
|
|
73
|
+
=== Accessing versions
|
|
74
|
+
|
|
75
|
+
Iterate through versions:
|
|
76
|
+
|
|
77
|
+
[source,ruby]
|
|
78
|
+
----
|
|
79
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
80
|
+
"schema.changes.yaml"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Iterate through all versions
|
|
84
|
+
changes.versions&.each do |version|
|
|
85
|
+
puts "Version #{version.version}"
|
|
86
|
+
puts " Description: #{version.description}"
|
|
87
|
+
puts " Additions: #{version.additions&.size || 0}"
|
|
88
|
+
puts " Modifications: #{version.modifications&.size || 0}"
|
|
89
|
+
puts " Deletions: #{version.deletions&.size || 0}"
|
|
90
|
+
end
|
|
91
|
+
----
|
|
92
|
+
|
|
93
|
+
=== Finding specific versions
|
|
94
|
+
|
|
95
|
+
Find a version by number:
|
|
96
|
+
|
|
97
|
+
[source,ruby]
|
|
98
|
+
----
|
|
99
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
100
|
+
"schema.changes.yaml"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Find version 3
|
|
104
|
+
version_3 = changes.versions&.find { |v| v.version == 3 }
|
|
105
|
+
|
|
106
|
+
if version_3
|
|
107
|
+
puts "Found version 3"
|
|
108
|
+
puts "Additions: #{version_3.additions&.size || 0}"
|
|
109
|
+
else
|
|
110
|
+
puts "Version 3 not found"
|
|
111
|
+
end
|
|
112
|
+
----
|
|
113
|
+
|
|
114
|
+
=== Accessing change items
|
|
115
|
+
|
|
116
|
+
Access individual changes:
|
|
117
|
+
|
|
118
|
+
[source,ruby]
|
|
119
|
+
----
|
|
120
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
121
|
+
"schema.changes.yaml"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
version = changes.versions&.first
|
|
125
|
+
|
|
126
|
+
# Access additions
|
|
127
|
+
version.additions&.each do |item|
|
|
128
|
+
puts "Added #{item.type}: #{item.name}"
|
|
129
|
+
if item.description
|
|
130
|
+
puts " Description:"
|
|
131
|
+
item.description.each { |desc| puts " - #{desc}" }
|
|
132
|
+
end
|
|
133
|
+
if item.interfaced_items
|
|
134
|
+
puts " Interfaced items: #{item.interfaced_items}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Access modifications
|
|
139
|
+
version.modifications&.each do |item|
|
|
140
|
+
puts "Modified #{item.type}: #{item.name}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Access deletions
|
|
144
|
+
version.deletions&.each do |item|
|
|
145
|
+
puts "Deleted #{item.type}: #{item.name}"
|
|
146
|
+
end
|
|
147
|
+
----
|
|
148
|
+
|
|
149
|
+
=== Handling empty files
|
|
150
|
+
|
|
151
|
+
Handle empty or minimal Changes files:
|
|
152
|
+
|
|
153
|
+
[source,ruby]
|
|
154
|
+
----
|
|
155
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
156
|
+
"empty.changes.yaml"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Check for versions
|
|
160
|
+
if changes.versions.nil? || changes.versions.empty?
|
|
161
|
+
puts "No versions found"
|
|
162
|
+
else
|
|
163
|
+
puts "Found #{changes.versions.size} versions"
|
|
164
|
+
end
|
|
165
|
+
----
|
|
166
|
+
|
|
167
|
+
== Creating Changes files
|
|
168
|
+
|
|
169
|
+
=== Creating from scratch
|
|
170
|
+
|
|
171
|
+
Create a new SchemaChange:
|
|
172
|
+
|
|
173
|
+
[source,ruby]
|
|
174
|
+
----
|
|
175
|
+
require "expressir/changes"
|
|
176
|
+
|
|
177
|
+
# Create empty schema change
|
|
178
|
+
changes = Expressir::Changes::SchemaChange.new(
|
|
179
|
+
schema: "my_schema"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
puts "Created changes for: #{changes.schema}"
|
|
183
|
+
----
|
|
184
|
+
|
|
185
|
+
=== Adding versions
|
|
186
|
+
|
|
187
|
+
Add a version with changes:
|
|
188
|
+
|
|
189
|
+
[source,ruby]
|
|
190
|
+
----
|
|
191
|
+
changes = Expressir::Changes::SchemaChange.new(
|
|
192
|
+
schema: "my_schema"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Create change items
|
|
196
|
+
new_entity = Expressir::Changes::ItemChange.new(
|
|
197
|
+
type: "ENTITY",
|
|
198
|
+
name: "new_product",
|
|
199
|
+
description: ["Represents product information"]
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
modified_function = Expressir::Changes::ItemChange.new(
|
|
203
|
+
type: "FUNCTION",
|
|
204
|
+
name: "validate_data",
|
|
205
|
+
description: [
|
|
206
|
+
"Updated parameters",
|
|
207
|
+
"Improved validation logic"
|
|
208
|
+
]
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
# Add version with changes
|
|
212
|
+
changes.add_or_update_version(
|
|
213
|
+
"2", # Version number
|
|
214
|
+
"Added product entity", # Description
|
|
215
|
+
{
|
|
216
|
+
additions: [new_entity],
|
|
217
|
+
modifications: [modified_function],
|
|
218
|
+
deletions: []
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
puts "Added version 2"
|
|
223
|
+
----
|
|
224
|
+
|
|
225
|
+
=== Creating interface changes
|
|
226
|
+
|
|
227
|
+
Create USE_FROM and REFERENCE_FROM changes:
|
|
228
|
+
|
|
229
|
+
[source,ruby]
|
|
230
|
+
----
|
|
231
|
+
# Create interface imports
|
|
232
|
+
use_from = Expressir::Changes::ItemChange.new(
|
|
233
|
+
type: "USE_FROM",
|
|
234
|
+
name: "geometry_schema",
|
|
235
|
+
interfaced_items: "point"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
reference_from = Expressir::Changes::ItemChange.new(
|
|
239
|
+
type: "REFERENCE_FROM",
|
|
240
|
+
name: "measure_schema",
|
|
241
|
+
interfaced_items: "length_measure"
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Add to version
|
|
245
|
+
changes.add_or_update_version(
|
|
246
|
+
"2",
|
|
247
|
+
"Added external references",
|
|
248
|
+
{
|
|
249
|
+
additions: [use_from, reference_from]
|
|
250
|
+
}
|
|
251
|
+
)
|
|
252
|
+
----
|
|
253
|
+
|
|
254
|
+
=== Creating mapping changes
|
|
255
|
+
|
|
256
|
+
Create mapping changes for ARM/MIM:
|
|
257
|
+
|
|
258
|
+
[source,ruby]
|
|
259
|
+
----
|
|
260
|
+
# Create mapping changes
|
|
261
|
+
mapping1 = Expressir::Changes::MappingChange.new(
|
|
262
|
+
name: "Product_entity",
|
|
263
|
+
description: "ENTITY mapping updated for new MIM structure"
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
mapping2 = Expressir::Changes::MappingChange.new(
|
|
267
|
+
name: "Identifier_type",
|
|
268
|
+
description: "TYPE mapping simplified"
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
# Add version with mappings
|
|
272
|
+
changes.add_or_update_version(
|
|
273
|
+
"2",
|
|
274
|
+
"Updated ARM mappings",
|
|
275
|
+
{
|
|
276
|
+
mappings: [mapping1, mapping2]
|
|
277
|
+
}
|
|
278
|
+
)
|
|
279
|
+
----
|
|
280
|
+
|
|
281
|
+
=== Complete example
|
|
282
|
+
|
|
283
|
+
Create a complete Changes file from scratch:
|
|
284
|
+
|
|
285
|
+
[source,ruby]
|
|
286
|
+
----
|
|
287
|
+
require "expressir/changes"
|
|
288
|
+
|
|
289
|
+
# Create schema change
|
|
290
|
+
changes = Expressir::Changes::SchemaChange.new(
|
|
291
|
+
schema: "action_schema"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# Create version 2 changes
|
|
295
|
+
entity_addition = Expressir::Changes::ItemChange.new(
|
|
296
|
+
type: "ENTITY",
|
|
297
|
+
name: "action_status",
|
|
298
|
+
description: ["Tracks status of actions"]
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
function_mod = Expressir::Changes::ItemChange.new(
|
|
302
|
+
type: "FUNCTION",
|
|
303
|
+
name: "validate_action",
|
|
304
|
+
description: [
|
|
305
|
+
"Added status parameter",
|
|
306
|
+
"Improved validation"
|
|
307
|
+
]
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
constant_deletion = Expressir::Changes::ItemChange.new(
|
|
311
|
+
type: "CONSTANT",
|
|
312
|
+
name: "old_status",
|
|
313
|
+
description: ["Replaced by action_status entity"]
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
# Add version 2
|
|
317
|
+
changes.add_or_update_version(
|
|
318
|
+
"2",
|
|
319
|
+
"Status tracking improvements",
|
|
320
|
+
{
|
|
321
|
+
additions: [entity_addition],
|
|
322
|
+
modifications: [function_mod],
|
|
323
|
+
deletions: [constant_deletion]
|
|
324
|
+
}
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# Add version 3
|
|
328
|
+
interface_addition = Expressir::Changes::ItemChange.new(
|
|
329
|
+
type: "USE_FROM",
|
|
330
|
+
name: "support_resource_schema",
|
|
331
|
+
interfaced_items: "bag_to_set"
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
changes.add_or_update_version(
|
|
335
|
+
"3",
|
|
336
|
+
"Added external references",
|
|
337
|
+
{
|
|
338
|
+
additions: [interface_addition]
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
puts "Created changes with #{changes.versions.size} versions"
|
|
343
|
+
----
|
|
344
|
+
|
|
345
|
+
== Updating Changes files
|
|
346
|
+
|
|
347
|
+
=== Loading and modifying
|
|
348
|
+
|
|
349
|
+
Load an existing file and add changes:
|
|
350
|
+
|
|
351
|
+
[source,ruby]
|
|
352
|
+
----
|
|
353
|
+
# Load existing file
|
|
354
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
355
|
+
"schema.changes.yaml"
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
puts "Current versions: #{changes.versions.size}"
|
|
359
|
+
|
|
360
|
+
# Add new version
|
|
361
|
+
new_item = Expressir::Changes::ItemChange.new(
|
|
362
|
+
type: "TYPE",
|
|
363
|
+
name: "status_enum",
|
|
364
|
+
description: ["New status enumeration"]
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
changes.add_or_update_version(
|
|
368
|
+
"4",
|
|
369
|
+
"Added status enumeration",
|
|
370
|
+
{
|
|
371
|
+
additions: [new_item]
|
|
372
|
+
}
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
puts "After update: #{changes.versions.size} versions"
|
|
376
|
+
----
|
|
377
|
+
|
|
378
|
+
=== Replacing existing versions
|
|
379
|
+
|
|
380
|
+
Replace an existing version:
|
|
381
|
+
|
|
382
|
+
[source,ruby]
|
|
383
|
+
----
|
|
384
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
385
|
+
"schema.changes.yaml"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
# Create new changes for version 2
|
|
389
|
+
revised_item = Expressir::Changes::ItemChange.new(
|
|
390
|
+
type: "ENTITY",
|
|
391
|
+
name: "revised_entity",
|
|
392
|
+
description: ["Corrected entity definition"]
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
# This replaces existing version 2
|
|
396
|
+
changes.add_or_update_version(
|
|
397
|
+
"2",
|
|
398
|
+
"Revised version 2 changes",
|
|
399
|
+
{
|
|
400
|
+
additions: [revised_item]
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
puts "Version 2 replaced"
|
|
405
|
+
----
|
|
406
|
+
|
|
407
|
+
=== Modifying existing items
|
|
408
|
+
|
|
409
|
+
Modify the changes directly:
|
|
410
|
+
|
|
411
|
+
[source,ruby]
|
|
412
|
+
----
|
|
413
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
414
|
+
"schema.changes.yaml"
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
# Find and modify a version
|
|
418
|
+
version_2 = changes.versions&.find { |v| v.version == 2 }
|
|
419
|
+
|
|
420
|
+
if version_2
|
|
421
|
+
# Add to existing additions
|
|
422
|
+
version_2.additions ||= []
|
|
423
|
+
version_2.additions << Expressir::Changes::ItemChange.new(
|
|
424
|
+
type: "FUNCTION",
|
|
425
|
+
name: "new_function"
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
# Update description
|
|
429
|
+
version_2.description = "Enhanced version 2 with new function"
|
|
430
|
+
|
|
431
|
+
puts "Modified version 2"
|
|
432
|
+
end
|
|
433
|
+
----
|
|
434
|
+
|
|
435
|
+
=== Removing versions
|
|
436
|
+
|
|
437
|
+
Remove a version from the file:
|
|
438
|
+
|
|
439
|
+
[source,ruby]
|
|
440
|
+
----
|
|
441
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
442
|
+
"schema.changes.yaml"
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
# Remove version 3
|
|
446
|
+
changes.versions&.reject! { |v| v.version == 3 }
|
|
447
|
+
|
|
448
|
+
puts "Removed version 3"
|
|
449
|
+
----
|
|
450
|
+
|
|
451
|
+
== Saving Changes files
|
|
452
|
+
|
|
453
|
+
=== Saving to file
|
|
454
|
+
|
|
455
|
+
Save a SchemaChange to a file:
|
|
456
|
+
|
|
457
|
+
[source,ruby]
|
|
458
|
+
----
|
|
459
|
+
changes = Expressir::Changes::SchemaChange.new(
|
|
460
|
+
schema: "my_schema"
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
# ... add versions ...
|
|
464
|
+
|
|
465
|
+
# Save to file
|
|
466
|
+
changes.to_file("my_schema.changes.yaml")
|
|
467
|
+
|
|
468
|
+
puts "Saved to my_schema.changes.yaml"
|
|
469
|
+
----
|
|
470
|
+
|
|
471
|
+
The `to_file` method:
|
|
472
|
+
|
|
473
|
+
* Automatically adds YAML schema hint comment
|
|
474
|
+
* Formats with consistent indentation
|
|
475
|
+
* Creates parent directories if needed
|
|
476
|
+
* Overwrites existing file
|
|
477
|
+
|
|
478
|
+
=== Converting to YAML string
|
|
479
|
+
|
|
480
|
+
Get YAML as a string without saving:
|
|
481
|
+
|
|
482
|
+
[source,ruby]
|
|
483
|
+
----
|
|
484
|
+
changes = Expressir::Changes::SchemaChange.new(
|
|
485
|
+
schema: "my_schema"
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
# Convert to YAML string
|
|
489
|
+
yaml_content = changes.to_yaml
|
|
490
|
+
|
|
491
|
+
puts yaml_content
|
|
492
|
+
----
|
|
493
|
+
|
|
494
|
+
=== Saving to stdout
|
|
495
|
+
|
|
496
|
+
Output to stdout for piping or display:
|
|
497
|
+
|
|
498
|
+
[source,ruby]
|
|
499
|
+
----
|
|
500
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
501
|
+
"schema.changes.yaml"
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
# Output to stdout
|
|
505
|
+
puts changes.to_yaml
|
|
506
|
+
----
|
|
507
|
+
|
|
508
|
+
== Version management strategies
|
|
509
|
+
|
|
510
|
+
=== Sequential versioning
|
|
511
|
+
|
|
512
|
+
Maintain sequential version numbers:
|
|
513
|
+
|
|
514
|
+
[source,ruby]
|
|
515
|
+
----
|
|
516
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
517
|
+
"schema.changes.yaml"
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# Find highest version number
|
|
521
|
+
max_version = changes.versions&.map(&:version)&.max&.to_i || 1
|
|
522
|
+
|
|
523
|
+
# Add next version
|
|
524
|
+
next_version = max_version + 1
|
|
525
|
+
changes.add_or_update_version(
|
|
526
|
+
next_version,
|
|
527
|
+
"New features",
|
|
528
|
+
{
|
|
529
|
+
additions: [...]
|
|
530
|
+
}
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
puts "Added version #{next_version}"
|
|
534
|
+
----
|
|
535
|
+
|
|
536
|
+
=== Semantic versioning
|
|
537
|
+
|
|
538
|
+
Use semantic version strings:
|
|
539
|
+
|
|
540
|
+
[source,ruby]
|
|
541
|
+
----
|
|
542
|
+
changes = Expressir::Changes::SchemaChange.new(
|
|
543
|
+
schema: "my_schema"
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
# Add semantic versions
|
|
547
|
+
changes.add_or_update_version(
|
|
548
|
+
"1.0.0",
|
|
549
|
+
"Initial release",
|
|
550
|
+
{ additions: [...] }
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
changes.add_or_update_version(
|
|
554
|
+
"1.1.0",
|
|
555
|
+
"Minor update",
|
|
556
|
+
{ modifications: [...] }
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
changes.add_or_update_version(
|
|
560
|
+
"2.0.0",
|
|
561
|
+
"Major update",
|
|
562
|
+
{ additions: [...], deletions: [...] }
|
|
563
|
+
)
|
|
564
|
+
----
|
|
565
|
+
|
|
566
|
+
=== Version with metadata
|
|
567
|
+
|
|
568
|
+
Include detailed metadata in descriptions:
|
|
569
|
+
|
|
570
|
+
[source,ruby]
|
|
571
|
+
----
|
|
572
|
+
changes.add_or_update_version(
|
|
573
|
+
"2",
|
|
574
|
+
"Version 2.0 - Released 2024-01-15\n" \
|
|
575
|
+
"Added support for new features.\n" \
|
|
576
|
+
"Breaking changes: Removed deprecated constants.",
|
|
577
|
+
{
|
|
578
|
+
additions: [...],
|
|
579
|
+
deletions: [...]
|
|
580
|
+
}
|
|
581
|
+
)
|
|
582
|
+
----
|
|
583
|
+
|
|
584
|
+
=== Branch-based versioning
|
|
585
|
+
|
|
586
|
+
Track changes for different branches:
|
|
587
|
+
|
|
588
|
+
[source,ruby]
|
|
589
|
+
----
|
|
590
|
+
# Development version
|
|
591
|
+
changes.add_or_update_version(
|
|
592
|
+
"2-dev",
|
|
593
|
+
"Development changes",
|
|
594
|
+
{ additions: [...] }
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
# Release candidate
|
|
598
|
+
changes.add_or_update_version(
|
|
599
|
+
"2-rc1",
|
|
600
|
+
"Release candidate 1",
|
|
601
|
+
{ modifications: [...] }
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
# Final release
|
|
605
|
+
changes.add_or_update_version(
|
|
606
|
+
"2",
|
|
607
|
+
"Final release",
|
|
608
|
+
{ ... }
|
|
609
|
+
)
|
|
610
|
+
----
|
|
611
|
+
|
|
612
|
+
== Integration patterns
|
|
613
|
+
|
|
614
|
+
=== Automated change tracking
|
|
615
|
+
|
|
616
|
+
Track changes automatically when schemas are modified:
|
|
617
|
+
|
|
618
|
+
[source,ruby]
|
|
619
|
+
----
|
|
620
|
+
require "expressir"
|
|
621
|
+
require "expressir/changes"
|
|
622
|
+
|
|
623
|
+
class SchemaChangeTracker
|
|
624
|
+
def initialize(schema_name, changes_file)
|
|
625
|
+
@schema_name = schema_name
|
|
626
|
+
@changes_file = changes_file
|
|
627
|
+
@changes = load_or_create_changes
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def track_addition(type, name, description)
|
|
631
|
+
item = Expressir::Changes::ItemChange.new(
|
|
632
|
+
type: type,
|
|
633
|
+
name: name,
|
|
634
|
+
description: description ? [description] : nil
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
@pending_additions << item
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
def track_modification(type, name, description)
|
|
641
|
+
item = Expressir::Changes::ItemChange.new(
|
|
642
|
+
type: type,
|
|
643
|
+
name: name,
|
|
644
|
+
description: description ? [description] : nil
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
@pending_modifications << item
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
def save_version(version, description)
|
|
651
|
+
@changes.add_or_update_version(
|
|
652
|
+
version,
|
|
653
|
+
description,
|
|
654
|
+
{
|
|
655
|
+
additions: @pending_additions,
|
|
656
|
+
modifications: @pending_modifications,
|
|
657
|
+
deletions: @pending_deletions
|
|
658
|
+
}
|
|
659
|
+
)
|
|
660
|
+
|
|
661
|
+
@changes.to_file(@changes_file)
|
|
662
|
+
clear_pending_changes
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
private
|
|
666
|
+
|
|
667
|
+
def load_or_create_changes
|
|
668
|
+
if File.exist?(@changes_file)
|
|
669
|
+
Expressir::Changes::SchemaChange.from_file(@changes_file)
|
|
670
|
+
else
|
|
671
|
+
Expressir::Changes::SchemaChange.new(schema: @schema_name)
|
|
672
|
+
end
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
def clear_pending_changes
|
|
676
|
+
@pending_additions = []
|
|
677
|
+
@pending_modifications = []
|
|
678
|
+
@pending_deletions = []
|
|
679
|
+
end
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
# Usage
|
|
683
|
+
tracker = SchemaChangeTracker.new(
|
|
684
|
+
"action_schema",
|
|
685
|
+
"action_schema.changes.yaml"
|
|
686
|
+
)
|
|
687
|
+
|
|
688
|
+
tracker.track_addition("ENTITY", "new_entity", "New entity added")
|
|
689
|
+
tracker.track_modification("FUNCTION", "validate", "Updated logic")
|
|
690
|
+
tracker.save_version("2", "Version 2 changes")
|
|
691
|
+
----
|
|
692
|
+
|
|
693
|
+
=== Report generation
|
|
694
|
+
|
|
695
|
+
Generate human-readable reports from changes:
|
|
696
|
+
|
|
697
|
+
[source,ruby]
|
|
698
|
+
----
|
|
699
|
+
require "expressir/changes"
|
|
700
|
+
|
|
701
|
+
class ChangeReportGenerator
|
|
702
|
+
def initialize(changes_file)
|
|
703
|
+
@changes = Expressir::Changes::SchemaChange.from_file(changes_file)
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
def generate_report
|
|
707
|
+
report = []
|
|
708
|
+
report << "# Change Report for #{@changes.schema}"
|
|
709
|
+
report << ""
|
|
710
|
+
|
|
711
|
+
@changes.versions&.each do |version|
|
|
712
|
+
report << generate_version_section(version)
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
report.join("\n")
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
private
|
|
719
|
+
|
|
720
|
+
def generate_version_section(version)
|
|
721
|
+
lines = []
|
|
722
|
+
lines << "## Version #{version.version}"
|
|
723
|
+
lines << ""
|
|
724
|
+
|
|
725
|
+
if version.description
|
|
726
|
+
lines << version.description
|
|
727
|
+
lines << ""
|
|
728
|
+
end
|
|
729
|
+
|
|
730
|
+
if version.additions&.any?
|
|
731
|
+
lines << "### Additions"
|
|
732
|
+
version.additions.each do |item|
|
|
733
|
+
lines << "- #{item.type}: #{item.name}"
|
|
734
|
+
item.description&.each { |d| lines << " - #{d}" }
|
|
735
|
+
end
|
|
736
|
+
lines << ""
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
if version.modifications&.any?
|
|
740
|
+
lines << "### Modifications"
|
|
741
|
+
version.modifications.each do |item|
|
|
742
|
+
lines << "- #{item.type}: #{item.name}"
|
|
743
|
+
item.description&.each { |d| lines << " - #{d}" }
|
|
744
|
+
end
|
|
745
|
+
lines << ""
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
if version.deletions&.any?
|
|
749
|
+
lines << "### Deletions"
|
|
750
|
+
version.deletions.each do |item|
|
|
751
|
+
lines << "- #{item.type}: #{item.name}"
|
|
752
|
+
end
|
|
753
|
+
lines << ""
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
lines.join("\n")
|
|
757
|
+
end
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
# Usage
|
|
761
|
+
generator = ChangeReportGenerator.new("schema.changes.yaml")
|
|
762
|
+
report = generator.generate_report
|
|
763
|
+
File.write("CHANGELOG.md", report)
|
|
764
|
+
----
|
|
765
|
+
|
|
766
|
+
=== Comparing versions
|
|
767
|
+
|
|
768
|
+
Compare changes between versions:
|
|
769
|
+
|
|
770
|
+
[source,ruby]
|
|
771
|
+
----
|
|
772
|
+
require "expressir/changes"
|
|
773
|
+
|
|
774
|
+
def compare_versions(changes, version1, version2)
|
|
775
|
+
v1 = changes.versions&.find { |v| v.version == version1 }
|
|
776
|
+
v2 = changes.versions&.find { |v| v.version == version2 }
|
|
777
|
+
|
|
778
|
+
return nil unless v1 && v2
|
|
779
|
+
|
|
780
|
+
{
|
|
781
|
+
version1: version1,
|
|
782
|
+
version2: version2,
|
|
783
|
+
added_in_v2: (v2.additions&.size || 0) - (v1.additions&.size || 0),
|
|
784
|
+
modified_in_v2: (v2.modifications&.size || 0) -
|
|
785
|
+
(v1.modifications&.size || 0),
|
|
786
|
+
deleted_in_v2: (v2.deletions&.size || 0) - (v1.deletions&.size || 0)
|
|
787
|
+
}
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
# Usage
|
|
791
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
792
|
+
"schema.changes.yaml"
|
|
793
|
+
)
|
|
794
|
+
comparison = compare_versions(changes, 2, 3)
|
|
795
|
+
puts "Changes from v2 to v3: #{comparison}"
|
|
796
|
+
----
|
|
797
|
+
|
|
798
|
+
=== Batch processing
|
|
799
|
+
|
|
800
|
+
Process multiple Changes files:
|
|
801
|
+
|
|
802
|
+
[source,ruby]
|
|
803
|
+
----
|
|
804
|
+
require "expressir/changes"
|
|
805
|
+
|
|
806
|
+
def process_all_changes(directory)
|
|
807
|
+
Dir.glob("#{directory}/**/*.changes.yaml").each do |file|
|
|
808
|
+
begin
|
|
809
|
+
changes = Expressir::Changes::SchemaChange.from_file(file)
|
|
810
|
+
|
|
811
|
+
puts "File: #{file}"
|
|
812
|
+
puts " Schema: #{changes.schema}"
|
|
813
|
+
puts " Versions: #{changes.versions&.size || 0}"
|
|
814
|
+
|
|
815
|
+
# Process each version
|
|
816
|
+
changes.versions&.each do |version|
|
|
817
|
+
total_changes = (version.additions&.size || 0) +
|
|
818
|
+
(version.modifications&.size || 0) +
|
|
819
|
+
(version.deletions&.size || 0)
|
|
820
|
+
puts " v#{version.version}: #{total_changes} changes"
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
rescue StandardError => e
|
|
824
|
+
puts "Error processing #{file}: #{e.message}"
|
|
825
|
+
end
|
|
826
|
+
end
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
# Usage
|
|
830
|
+
process_all_changes("schemas/")
|
|
831
|
+
----
|
|
832
|
+
|
|
833
|
+
== Error handling
|
|
834
|
+
|
|
835
|
+
=== File loading errors
|
|
836
|
+
|
|
837
|
+
Handle file loading errors:
|
|
838
|
+
|
|
839
|
+
[source,ruby]
|
|
840
|
+
----
|
|
841
|
+
require "expressir/changes"
|
|
842
|
+
|
|
843
|
+
begin
|
|
844
|
+
changes = Expressir::Changes::SchemaChange.from_file(
|
|
845
|
+
"schema.changes.yaml"
|
|
846
|
+
)
|
|
847
|
+
rescue Errno::ENOENT
|
|
848
|
+
puts "File not found"
|
|
849
|
+
# Create new file
|
|
850
|
+
changes = Expressir::Changes::SchemaChange.new(
|
|
851
|
+
schema: "default_schema"
|
|
852
|
+
)
|
|
853
|
+
rescue Psych::SyntaxError => e
|
|
854
|
+
puts "Invalid YAML syntax: #{e.message}"
|
|
855
|
+
exit 1
|
|
856
|
+
rescue StandardError => e
|
|
857
|
+
puts "Error loading file: #{e.message}"
|
|
858
|
+
exit 1
|
|
859
|
+
end
|
|
860
|
+
----
|
|
861
|
+
|
|
862
|
+
=== Validation errors
|
|
863
|
+
|
|
864
|
+
Validate data before using:
|
|
865
|
+
|
|
866
|
+
[source,ruby]
|
|
867
|
+
----
|
|
868
|
+
def validate_change_item(item)
|
|
869
|
+
errors = []
|
|
870
|
+
|
|
871
|
+
errors << "Missing type" if item.type.nil? || item.type.empty?
|
|
872
|
+
errors << "Missing name" if item.name.nil? || item.name.empty?
|
|
873
|
+
|
|
874
|
+
valid_types = %w[
|
|
875
|
+
ENTITY TYPE FUNCTION PROCEDURE RULE CONSTANT
|
|
876
|
+
SUBTYPE_CONSTRAINT USE_FROM REFERENCE_FROM
|
|
877
|
+
]
|
|
878
|
+
|
|
879
|
+
unless valid_types.include?(item.type)
|
|
880
|
+
errors << "Invalid type: #{item.type}"
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
errors
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
# Usage
|
|
887
|
+
item = Expressir::Changes::ItemChange.new(type: "ENTITY", name: "test")
|
|
888
|
+
errors = validate_change_item(item)
|
|
889
|
+
|
|
890
|
+
if errors.any?
|
|
891
|
+
puts "Validation errors:"
|
|
892
|
+
errors.each { |err| puts " - #{err}" }
|
|
893
|
+
else
|
|
894
|
+
puts "Item is valid"
|
|
895
|
+
end
|
|
896
|
+
----
|
|
897
|
+
|
|
898
|
+
=== Safe file writing
|
|
899
|
+
|
|
900
|
+
Write files safely with error handling:
|
|
901
|
+
|
|
902
|
+
[source,ruby]
|
|
903
|
+
----
|
|
904
|
+
def save_changes_safely(changes, path)
|
|
905
|
+
# Create backup if file exists
|
|
906
|
+
if File.exist?(path)
|
|
907
|
+
backup_path = "#{path}.backup"
|
|
908
|
+
FileUtils.cp(path, backup_path)
|
|
909
|
+
puts "Created backup: #{backup_path}"
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
begin
|
|
913
|
+
changes.to_file(path)
|
|
914
|
+
puts "Saved to: #{path}"
|
|
915
|
+
|
|
916
|
+
# Remove backup on success
|
|
917
|
+
File.delete("#{path}.backup") if File.exist?("#{path}.backup")
|
|
918
|
+
|
|
919
|
+
rescue StandardError => e
|
|
920
|
+
puts "Error saving file: #{e.message}"
|
|
921
|
+
|
|
922
|
+
# Restore backup if it exists
|
|
923
|
+
if File.exist?("#{path}.backup")
|
|
924
|
+
FileUtils.mv("#{path}.backup", path)
|
|
925
|
+
puts "Restored from backup"
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
raise
|
|
929
|
+
end
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
# Usage
|
|
933
|
+
changes = Expressir::Changes::SchemaChange.new(schema: "test")
|
|
934
|
+
save_changes_safely(changes, "test.changes.yaml")
|
|
935
|
+
----
|
|
936
|
+
|
|
937
|
+
== Best practices
|
|
938
|
+
|
|
939
|
+
=== Use descriptive variable names
|
|
940
|
+
|
|
941
|
+
[source,ruby]
|
|
942
|
+
----
|
|
943
|
+
# Good
|
|
944
|
+
entity_addition = Expressir::Changes::ItemChange.new(...)
|
|
945
|
+
function_modification = Expressir::Changes::ItemChange.new(...)
|
|
946
|
+
|
|
947
|
+
# Avoid
|
|
948
|
+
item1 = Expressir::Changes::ItemChange.new(...)
|
|
949
|
+
x = Expressir::Changes::ItemChange.new(...)
|
|
950
|
+
----
|
|
951
|
+
|
|
952
|
+
=== Initialize collections
|
|
953
|
+
|
|
954
|
+
Always initialize arrays before use:
|
|
955
|
+
|
|
956
|
+
[source,ruby]
|
|
957
|
+
----
|
|
958
|
+
changes = Expressir::Changes::SchemaChange.new(schema: "test")
|
|
959
|
+
changes.versions ||= [] # Initialize if nil
|
|
960
|
+
----
|
|
961
|
+
|
|
962
|
+
=== Check for nil
|
|
963
|
+
|
|
964
|
+
Check for nil before accessing collections:
|
|
965
|
+
|
|
966
|
+
[source,ruby]
|
|
967
|
+
----
|
|
968
|
+
# Safe
|
|
969
|
+
if changes.versions&.any?
|
|
970
|
+
changes.versions.each { |v| ... }
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
# Unsafe (may raise error)
|
|
974
|
+
changes.versions.each { |v| ... }
|
|
975
|
+
----
|
|
976
|
+
|
|
977
|
+
=== Use consistent version format
|
|
978
|
+
|
|
979
|
+
Choose a version format and stick with it:
|
|
980
|
+
|
|
981
|
+
[source,ruby]
|
|
982
|
+
----
|
|
983
|
+
# Integer versions
|
|
984
|
+
changes.add_or_update_version(2, ...)
|
|
985
|
+
changes.add_or_update_version(3, ...)
|
|
986
|
+
|
|
987
|
+
# Or semantic versions
|
|
988
|
+
changes.add_or_update_version("1.0.0", ...)
|
|
989
|
+
changes.add_or_update_version("1.1.0", ...)
|
|
990
|
+
|
|
991
|
+
# Don't mix formats
|
|
992
|
+
----
|
|
993
|
+
|
|
994
|
+
=== Save after modifications
|
|
995
|
+
|
|
996
|
+
Always save after making changes:
|
|
997
|
+
|
|
998
|
+
[source,ruby]
|
|
999
|
+
----
|
|
1000
|
+
changes = Expressir::Changes::SchemaChange.from_file("file.yaml")
|
|
1001
|
+
changes.add_or_update_version(...)
|
|
1002
|
+
changes.to_file("file.yaml") # Don't forget to save!
|
|
1003
|
+
----
|
|
1004
|
+
|
|
1005
|
+
== Next steps
|
|
1006
|
+
|
|
1007
|
+
After mastering programmatic usage:
|
|
1008
|
+
|
|
1009
|
+
* link:changes-format.html[Changes Format] - Review format specification
|
|
1010
|
+
* link:validating-changes.html[Validating Changes] - Validate your changes
|
|
1011
|
+
* link:importing-eengine.html[Importing from Express Engine] - Import
|
|
1012
|
+
automation
|
|
1013
|
+
|
|
1014
|
+
== Summary
|
|
1015
|
+
|
|
1016
|
+
The Changes API provides comprehensive programmatic control:
|
|
1017
|
+
|
|
1018
|
+
* Four main classes: SchemaChange, VersionChange, ItemChange, MappingChange
|
|
1019
|
+
* Load from files with `from_file` method
|
|
1020
|
+
* Create changes programmatically with `new` and `add_or_update_version`
|
|
1021
|
+
* Save with `to_file` method
|
|
1022
|
+
* Version management strategies for different workflows
|
|
1023
|
+
* Integration patterns for automation
|
|
1024
|
+
* Proper error handling for robust applications
|
|
1025
|
+
* Best practices for maintainable code
|
|
1026
|
+
|
|
1027
|
+
Key takeaways:
|
|
1028
|
+
|
|
1029
|
+
* Use `SchemaChange.from_file` to load existing files
|
|
1030
|
+
* Use `add_or_update_version` for smart version handling
|
|
1031
|
+
* Always save with `to_file` after modifications
|
|
1032
|
+
* Check for nil before accessing collections
|
|
1033
|
+
* Handle errors appropriately
|
|
1034
|
+
* Use descriptive variable names
|
|
1035
|
+
* Initialize collections before use
|
|
1036
|
+
* Choose consistent version format
|
|
1037
|
+
* Validate data before using
|
|
1038
|
+
* Create backups before overwriting files
|