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,795 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Documentation Coverage
|
|
3
|
+
nav_order: 7
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Documentation Coverage Analysis
|
|
7
|
+
|
|
8
|
+
=== Prerequisites
|
|
9
|
+
|
|
10
|
+
Before starting this tutorial, ensure you have:
|
|
11
|
+
|
|
12
|
+
* Completed link:liquid-templates.html[Liquid Templates]
|
|
13
|
+
* EXPRESS schemas with varying documentation levels
|
|
14
|
+
* Understanding of EXPRESS remarks
|
|
15
|
+
* Expressir CLI and Ruby access
|
|
16
|
+
|
|
17
|
+
=== Learning Objectives
|
|
18
|
+
|
|
19
|
+
By the end of this tutorial, you will be able to:
|
|
20
|
+
|
|
21
|
+
* Analyze documentation coverage of schemas
|
|
22
|
+
* Use the coverage CLI tool
|
|
23
|
+
* Identify undocumented elements
|
|
24
|
+
* Generate coverage reports
|
|
25
|
+
* Exclude specific element types
|
|
26
|
+
* Set documentation standards
|
|
27
|
+
* Improve schema documentation systematically
|
|
28
|
+
|
|
29
|
+
=== What You'll Build
|
|
30
|
+
|
|
31
|
+
You'll create documentation coverage reports and tools to improve and maintain high-quality EXPRESS schema documentation.
|
|
32
|
+
|
|
33
|
+
=== Step 1: Understanding Documentation Coverage
|
|
34
|
+
|
|
35
|
+
==== What is Coverage?
|
|
36
|
+
|
|
37
|
+
Documentation coverage measures how well your EXPRESS schemas are documented through remarks (comments).
|
|
38
|
+
|
|
39
|
+
**Covered element**::
|
|
40
|
+
Has at least one remark
|
|
41
|
+
+
|
|
42
|
+
[source,express]
|
|
43
|
+
----
|
|
44
|
+
(* A person in the system *)
|
|
45
|
+
ENTITY person;
|
|
46
|
+
(* Full name of the person *)
|
|
47
|
+
name : STRING;
|
|
48
|
+
END_ENTITY;
|
|
49
|
+
----
|
|
50
|
+
|
|
51
|
+
**Uncovered element**::
|
|
52
|
+
Has no remarks
|
|
53
|
+
+
|
|
54
|
+
[source,express]
|
|
55
|
+
----
|
|
56
|
+
ENTITY person;
|
|
57
|
+
name : STRING; -- No documentation!
|
|
58
|
+
END_ENTITY;
|
|
59
|
+
----
|
|
60
|
+
|
|
61
|
+
==== Why Coverage Matters
|
|
62
|
+
|
|
63
|
+
* **Maintainability**: Documented code is easier to maintain
|
|
64
|
+
* **Standards compliance**: ISO standards require documentation
|
|
65
|
+
* **User experience**: Developers need clear documentation
|
|
66
|
+
* **Quality assurance**: Coverage metrics track quality
|
|
67
|
+
|
|
68
|
+
=== Step 2: Create Test Schemas
|
|
69
|
+
|
|
70
|
+
Let's create schemas with different coverage levels.
|
|
71
|
+
|
|
72
|
+
==== Well-Documented Schema
|
|
73
|
+
|
|
74
|
+
Create `documented.exp`:
|
|
75
|
+
|
|
76
|
+
[source,express]
|
|
77
|
+
----
|
|
78
|
+
SCHEMA documented_schema;
|
|
79
|
+
|
|
80
|
+
(* Unique identifier for entities *)
|
|
81
|
+
TYPE identifier = STRING;
|
|
82
|
+
END_TYPE;
|
|
83
|
+
|
|
84
|
+
(* A person in the organization *)
|
|
85
|
+
ENTITY person;
|
|
86
|
+
(* Unique identifier *)
|
|
87
|
+
id : identifier;
|
|
88
|
+
(* Full name *)
|
|
89
|
+
name : STRING;
|
|
90
|
+
(* Email address *)
|
|
91
|
+
email : OPTIONAL STRING;
|
|
92
|
+
END_ENTITY;
|
|
93
|
+
|
|
94
|
+
(* An organizational unit *)
|
|
95
|
+
ENTITY organization;
|
|
96
|
+
(* Organization identifier *)
|
|
97
|
+
org_id : identifier;
|
|
98
|
+
(* Organization name *)
|
|
99
|
+
org_name : STRING;
|
|
100
|
+
(* List of employees *)
|
|
101
|
+
employees : SET [0:?] OF person;
|
|
102
|
+
END_ENTITY;
|
|
103
|
+
|
|
104
|
+
END_SCHEMA;
|
|
105
|
+
----
|
|
106
|
+
|
|
107
|
+
==== Poorly-Documented Schema
|
|
108
|
+
|
|
109
|
+
Create `undocumented.exp`:
|
|
110
|
+
|
|
111
|
+
[source,express]
|
|
112
|
+
----
|
|
113
|
+
SCHEMA undocumented_schema;
|
|
114
|
+
|
|
115
|
+
TYPE identifier = STRING;
|
|
116
|
+
END_TYPE;
|
|
117
|
+
|
|
118
|
+
ENTITY person;
|
|
119
|
+
id : identifier;
|
|
120
|
+
name : STRING;
|
|
121
|
+
email : OPTIONAL STRING;
|
|
122
|
+
END_ENTITY;
|
|
123
|
+
|
|
124
|
+
ENTITY organization;
|
|
125
|
+
org_id : identifier;
|
|
126
|
+
org_name : STRING;
|
|
127
|
+
employees : SET [0:?] OF person;
|
|
128
|
+
END_ENTITY;
|
|
129
|
+
|
|
130
|
+
END_SCHEMA;
|
|
131
|
+
----
|
|
132
|
+
|
|
133
|
+
=== Step 3: Basic Coverage Analysis
|
|
134
|
+
|
|
135
|
+
==== Using the CLI
|
|
136
|
+
|
|
137
|
+
[source,bash]
|
|
138
|
+
----
|
|
139
|
+
# Check single file
|
|
140
|
+
expressir coverage documented.exp
|
|
141
|
+
|
|
142
|
+
# Check multiple files
|
|
143
|
+
expressir coverage documented.exp undocumented.exp
|
|
144
|
+
|
|
145
|
+
# Check directory recursively
|
|
146
|
+
expressir coverage schemas/
|
|
147
|
+
----
|
|
148
|
+
|
|
149
|
+
**Output for documented.exp**:
|
|
150
|
+
[source]
|
|
151
|
+
----
|
|
152
|
+
File: documented.exp
|
|
153
|
+
|
|
154
|
+
✓ All elements documented
|
|
155
|
+
|
|
156
|
+
Coverage: 100.00%
|
|
157
|
+
Total: 9
|
|
158
|
+
Documented: 9
|
|
159
|
+
Undocumented: 0
|
|
160
|
+
----
|
|
161
|
+
|
|
162
|
+
**Output for undocumented.exp**:
|
|
163
|
+
[source]
|
|
164
|
+
----
|
|
165
|
+
File: undocumented.exp
|
|
166
|
+
|
|
167
|
+
Undocumented elements:
|
|
168
|
+
TYPE: identifier
|
|
169
|
+
ENTITY: person
|
|
170
|
+
ATTRIBUTE: person.id
|
|
171
|
+
ATTRIBUTE: person.name
|
|
172
|
+
ATTRIBUTE: person.email
|
|
173
|
+
ENTITY: organization
|
|
174
|
+
ATTRIBUTE: organization.org_id
|
|
175
|
+
ATTRIBUTE: organization.org_name
|
|
176
|
+
ATTRIBUTE: organization.employees
|
|
177
|
+
|
|
178
|
+
Coverage: 0.00%
|
|
179
|
+
Total: 9
|
|
180
|
+
Documented: 0
|
|
181
|
+
Undocumented: 9
|
|
182
|
+
----
|
|
183
|
+
|
|
184
|
+
=== Step 4: Coverage Output Formats
|
|
185
|
+
|
|
186
|
+
==== Text Format (Default)
|
|
187
|
+
|
|
188
|
+
[source,bash]
|
|
189
|
+
----
|
|
190
|
+
expressir coverage schemas/ --format text
|
|
191
|
+
----
|
|
192
|
+
|
|
193
|
+
Human-readable table with:
|
|
194
|
+
* File paths
|
|
195
|
+
* Undocumented elements
|
|
196
|
+
* Coverage percentages
|
|
197
|
+
* Summary statistics
|
|
198
|
+
|
|
199
|
+
==== JSON Format
|
|
200
|
+
|
|
201
|
+
[source,bash]
|
|
202
|
+
----
|
|
203
|
+
expressir coverage schemas/ --format json > coverage.json
|
|
204
|
+
----
|
|
205
|
+
|
|
206
|
+
Programmatically parseable output:
|
|
207
|
+
|
|
208
|
+
[source,json]
|
|
209
|
+
----
|
|
210
|
+
{
|
|
211
|
+
"overall": {
|
|
212
|
+
"coverage_percentage": 50.0,
|
|
213
|
+
"total_entities": 18,
|
|
214
|
+
"documented_entities": 9,
|
|
215
|
+
"undocumented_entities": 9
|
|
216
|
+
},
|
|
217
|
+
"files": [
|
|
218
|
+
{
|
|
219
|
+
"file": "schemas/documented.exp",
|
|
220
|
+
"coverage": 100.0,
|
|
221
|
+
"total": 9,
|
|
222
|
+
"documented": 9,
|
|
223
|
+
"undocumented": []
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"file": "schemas/undocumented.exp",
|
|
227
|
+
"coverage": 0.0,
|
|
228
|
+
"total": 9,
|
|
229
|
+
"documented": 0,
|
|
230
|
+
"undocumented": ["identifier", "person", "person.id", ...]
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
----
|
|
235
|
+
|
|
236
|
+
==== YAML Format
|
|
237
|
+
|
|
238
|
+
[source,bash]
|
|
239
|
+
----
|
|
240
|
+
expressir coverage schemas/ --format yaml > coverage.yaml
|
|
241
|
+
----
|
|
242
|
+
|
|
243
|
+
YAML output for easy reading and processing:
|
|
244
|
+
|
|
245
|
+
[source,yaml]
|
|
246
|
+
----
|
|
247
|
+
overall:
|
|
248
|
+
coverage_percentage: 50.0
|
|
249
|
+
total_entities: 18
|
|
250
|
+
documented_entities: 9
|
|
251
|
+
undocumented_entities: 9
|
|
252
|
+
files:
|
|
253
|
+
- file: schemas/documented.exp
|
|
254
|
+
coverage: 100.0
|
|
255
|
+
total: 9
|
|
256
|
+
documented: 9
|
|
257
|
+
undocumented: []
|
|
258
|
+
- file: schemas/undocumented.exp
|
|
259
|
+
coverage: 0.0
|
|
260
|
+
total: 9
|
|
261
|
+
documented: 0
|
|
262
|
+
undocumented:
|
|
263
|
+
- identifier
|
|
264
|
+
- person
|
|
265
|
+
- person.id
|
|
266
|
+
----
|
|
267
|
+
|
|
268
|
+
=== Step 5: Excluding Element Types
|
|
269
|
+
|
|
270
|
+
==== Why Exclude?
|
|
271
|
+
|
|
272
|
+
Some element types may not require documentation:
|
|
273
|
+
* Auto-generated TYPE descriptions
|
|
274
|
+
* Simple type aliases
|
|
275
|
+
* Internal helper functions
|
|
276
|
+
|
|
277
|
+
==== Basic Exclusions
|
|
278
|
+
|
|
279
|
+
[source,bash]
|
|
280
|
+
----
|
|
281
|
+
# Exclude all TYPE definitions
|
|
282
|
+
expressir coverage schemas/ --exclude=TYPE
|
|
283
|
+
|
|
284
|
+
# Exclude multiple types
|
|
285
|
+
expressir coverage schemas/ --exclude=TYPE,CONSTANT,FUNCTION
|
|
286
|
+
|
|
287
|
+
# Exclude parameters and variables
|
|
288
|
+
expressir coverage schemas/ --exclude=PARAMETER,VARIABLE
|
|
289
|
+
----
|
|
290
|
+
|
|
291
|
+
==== Type-Specific Exclusions
|
|
292
|
+
|
|
293
|
+
[source,bash]
|
|
294
|
+
----
|
|
295
|
+
# Exclude only SELECT types
|
|
296
|
+
expressir coverage schemas/ --exclude=TYPE:SELECT
|
|
297
|
+
|
|
298
|
+
# Exclude SELECT and ENUMERATION types
|
|
299
|
+
expressir coverage schemas/ --exclude=TYPE:SELECT,TYPE:ENUMERATION
|
|
300
|
+
|
|
301
|
+
# Exclude inner functions
|
|
302
|
+
expressir coverage schemas/ --exclude=FUNCTION:INNER
|
|
303
|
+
----
|
|
304
|
+
|
|
305
|
+
==== ISO 10303 Standard Exclusions
|
|
306
|
+
|
|
307
|
+
ISO 10303 excludes SELECT and ENUMERATION types:
|
|
308
|
+
|
|
309
|
+
[source,bash]
|
|
310
|
+
----
|
|
311
|
+
expressir coverage schemas/ --exclude=TYPE:SELECT,TYPE:ENUMERATION
|
|
312
|
+
----
|
|
313
|
+
|
|
314
|
+
=== Step 6: Ignoring Files
|
|
315
|
+
|
|
316
|
+
==== Create Ignore List
|
|
317
|
+
|
|
318
|
+
Create `coverage_ignore.yaml`:
|
|
319
|
+
|
|
320
|
+
[source,yaml]
|
|
321
|
+
----
|
|
322
|
+
# Test and example schemas
|
|
323
|
+
- examples/test_*.exp
|
|
324
|
+
- examples/demo_*.exp
|
|
325
|
+
|
|
326
|
+
# Legacy schemas
|
|
327
|
+
- legacy/*.exp
|
|
328
|
+
|
|
329
|
+
# Generated schemas
|
|
330
|
+
- generated/auto_*.exp
|
|
331
|
+
|
|
332
|
+
# Specific files
|
|
333
|
+
- temp/temporary_schema.exp
|
|
334
|
+
----
|
|
335
|
+
|
|
336
|
+
==== Use Ignore List
|
|
337
|
+
|
|
338
|
+
[source,bash]
|
|
339
|
+
----
|
|
340
|
+
expressir coverage schemas/ --ignore-files coverage_ignore.yaml
|
|
341
|
+
----
|
|
342
|
+
|
|
343
|
+
Ignored files:
|
|
344
|
+
* Still appear in reports (marked as ignored)
|
|
345
|
+
* Don't affect overall coverage percentage
|
|
346
|
+
* Useful for partial documentation efforts
|
|
347
|
+
|
|
348
|
+
=== Step 7: Programmatic Coverage Analysis
|
|
349
|
+
|
|
350
|
+
==== Basic Coverage Check
|
|
351
|
+
|
|
352
|
+
Create `check_coverage.rb`:
|
|
353
|
+
|
|
354
|
+
[source,ruby]
|
|
355
|
+
----
|
|
356
|
+
require 'expressir'
|
|
357
|
+
|
|
358
|
+
# Parse schema
|
|
359
|
+
repo = Expressir::Express::Parser.from_file('documented.exp')
|
|
360
|
+
|
|
361
|
+
# Create coverage report
|
|
362
|
+
report = Expressir::Coverage::Report.from_repository(repo)
|
|
363
|
+
|
|
364
|
+
puts "Coverage Analysis"
|
|
365
|
+
puts "=" * 60
|
|
366
|
+
puts "Overall: #{report.coverage_percentage.round(2)}%"
|
|
367
|
+
puts "Total: #{report.total_entities.size}"
|
|
368
|
+
puts "Documented: #{report.documented_entities.size}"
|
|
369
|
+
puts "Undocumented: #{report.undocumented_entities.size}"
|
|
370
|
+
|
|
371
|
+
if report.undocumented_entities.any?
|
|
372
|
+
puts "\nUndocumented elements:"
|
|
373
|
+
report.undocumented_entities.take(10).each do |entity|
|
|
374
|
+
puts " - #{entity}"
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
----
|
|
378
|
+
|
|
379
|
+
==== Detailed File Reports
|
|
380
|
+
|
|
381
|
+
[source,ruby]
|
|
382
|
+
----
|
|
383
|
+
# Get per-file breakdown
|
|
384
|
+
report.file_reports.each do |file_report|
|
|
385
|
+
puts "\nFile: #{file_report[:file]}"
|
|
386
|
+
puts " Coverage: #{file_report[:coverage]}%"
|
|
387
|
+
puts " Total: #{file_report[:total]}"
|
|
388
|
+
puts " Documented: #{file_report[:documented]}"
|
|
389
|
+
|
|
390
|
+
if file_report[:undocumented].any?
|
|
391
|
+
puts " Undocumented:"
|
|
392
|
+
file_report[:undocumented].each do |item|
|
|
393
|
+
puts " - #{item}"
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
----
|
|
398
|
+
|
|
399
|
+
==== Check Individual Elements
|
|
400
|
+
|
|
401
|
+
[source,ruby]
|
|
402
|
+
----
|
|
403
|
+
# Check if entity is documented
|
|
404
|
+
schema = repo.schemas.first
|
|
405
|
+
entity = schema.entities.first
|
|
406
|
+
|
|
407
|
+
if Expressir::Coverage.entity_documented?(entity)
|
|
408
|
+
puts "✓ #{entity.id} is documented"
|
|
409
|
+
else
|
|
410
|
+
puts "✗ #{entity.id} lacks documentation"
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# Check all entities
|
|
414
|
+
schema.entities.each do |entity|
|
|
415
|
+
status = Expressir::Coverage.entity_documented?(entity) ? "✓" : "✗"
|
|
416
|
+
puts "#{status} #{entity.id}"
|
|
417
|
+
end
|
|
418
|
+
----
|
|
419
|
+
|
|
420
|
+
=== Step 8: Coverage Enforcement
|
|
421
|
+
|
|
422
|
+
==== Create Coverage Checker
|
|
423
|
+
|
|
424
|
+
Create `enforce_coverage.rb`:
|
|
425
|
+
|
|
426
|
+
[source,ruby]
|
|
427
|
+
----
|
|
428
|
+
require 'expressir'
|
|
429
|
+
|
|
430
|
+
class CoverageEnforcer
|
|
431
|
+
MINIMUM_COVERAGE = 80.0 # 80% required
|
|
432
|
+
|
|
433
|
+
def initialize(files)
|
|
434
|
+
@files = files
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def check
|
|
438
|
+
repos = @files.map { |f| Expressir::Express::Parser.from_file(f) }
|
|
439
|
+
|
|
440
|
+
all_pass = true
|
|
441
|
+
repos.each do |repo|
|
|
442
|
+
report = Expressir::Coverage::Report.from_repository(repo)
|
|
443
|
+
|
|
444
|
+
file = repo.schemas.first.file
|
|
445
|
+
coverage = report.coverage_percentage
|
|
446
|
+
|
|
447
|
+
if coverage < MINIMUM_COVERAGE
|
|
448
|
+
puts "❌ #{file}: #{coverage.round(2)}% (minimum: #{MINIMUM_COVERAGE}%)"
|
|
449
|
+
|
|
450
|
+
puts " Undocumented:"
|
|
451
|
+
report.undocumented_entities.take(5).each do |item|
|
|
452
|
+
puts " - #{item}"
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
all_pass = false
|
|
456
|
+
else
|
|
457
|
+
puts "✓ #{file}: #{coverage.round(2)}%"
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
all_pass
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# Usage
|
|
466
|
+
files = Dir.glob('schemas/**/*.exp')
|
|
467
|
+
enforcer = CoverageEnforcer.new(files)
|
|
468
|
+
|
|
469
|
+
unless enforcer.check
|
|
470
|
+
puts "\n❌ Coverage check failed!"
|
|
471
|
+
exit 1
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
puts "\n✓ All files meet coverage requirements!"
|
|
475
|
+
----
|
|
476
|
+
|
|
477
|
+
==== CI/CD Integration
|
|
478
|
+
|
|
479
|
+
Create `.github/workflows/coverage.yml`:
|
|
480
|
+
|
|
481
|
+
[source,yaml]
|
|
482
|
+
----
|
|
483
|
+
name: Documentation Coverage
|
|
484
|
+
|
|
485
|
+
on: [push, pull_request]
|
|
486
|
+
|
|
487
|
+
jobs:
|
|
488
|
+
coverage:
|
|
489
|
+
runs-on: ubuntu-latest
|
|
490
|
+
|
|
491
|
+
steps:
|
|
492
|
+
- uses: actions/checkout@v2
|
|
493
|
+
|
|
494
|
+
- name: Set up Ruby
|
|
495
|
+
uses: ruby/setup-ruby@v1
|
|
496
|
+
with:
|
|
497
|
+
ruby-version: 3.0
|
|
498
|
+
|
|
499
|
+
- name: Install Expressir
|
|
500
|
+
run: gem install expressir
|
|
501
|
+
|
|
502
|
+
- name: Check Coverage
|
|
503
|
+
run: |
|
|
504
|
+
expressir coverage schemas/ --format json > coverage.json
|
|
505
|
+
|
|
506
|
+
# Extract coverage percentage
|
|
507
|
+
COVERAGE=$(cat coverage.json | jq '.overall.coverage_percentage')
|
|
508
|
+
echo "Coverage: ${COVERAGE}%"
|
|
509
|
+
|
|
510
|
+
# Fail if below 80%
|
|
511
|
+
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
|
|
512
|
+
echo "❌ Coverage below 80%"
|
|
513
|
+
exit 1
|
|
514
|
+
fi
|
|
515
|
+
|
|
516
|
+
echo "✓ Coverage check passed"
|
|
517
|
+
|
|
518
|
+
- name: Upload Coverage Report
|
|
519
|
+
uses: actions/upload-artifact@v2
|
|
520
|
+
with:
|
|
521
|
+
name: coverage-report
|
|
522
|
+
path: coverage.json
|
|
523
|
+
----
|
|
524
|
+
|
|
525
|
+
=== Step 9: Improving Coverage
|
|
526
|
+
|
|
527
|
+
==== Find Low-Coverage Files
|
|
528
|
+
|
|
529
|
+
Create `find_low_coverage.rb`:
|
|
530
|
+
|
|
531
|
+
[source,ruby]
|
|
532
|
+
----
|
|
533
|
+
require 'expressir'
|
|
534
|
+
require 'json'
|
|
535
|
+
|
|
536
|
+
files = Dir.glob('schemas/**/*.exp')
|
|
537
|
+
results = []
|
|
538
|
+
|
|
539
|
+
files.each do |file|
|
|
540
|
+
repo = Expressir::Express::Parser.from_file(file)
|
|
541
|
+
report = Expressir::Coverage::Report.from_repository(repo)
|
|
542
|
+
|
|
543
|
+
results << {
|
|
544
|
+
file: file,
|
|
545
|
+
coverage: report.coverage_percentage,
|
|
546
|
+
undocumented: report.undocumented_entities.size
|
|
547
|
+
}
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
# Sort by coverage (worst first)
|
|
551
|
+
results.sort_by! { |r| r[:coverage] }
|
|
552
|
+
|
|
553
|
+
puts "Low Coverage Files"
|
|
554
|
+
puts "=" * 60
|
|
555
|
+
|
|
556
|
+
results.take(10).each do |result|
|
|
557
|
+
puts "\n#{result[:file]}"
|
|
558
|
+
puts " Coverage: #{result[:coverage].round(2)}%"
|
|
559
|
+
puts " Undocumented: #{result[:undocumented]}"
|
|
560
|
+
end
|
|
561
|
+
----
|
|
562
|
+
|
|
563
|
+
==== Generate Documentation Templates
|
|
564
|
+
|
|
565
|
+
Create `generate_doc_templates.rb`:
|
|
566
|
+
|
|
567
|
+
[source,ruby]
|
|
568
|
+
----
|
|
569
|
+
require 'expressir'
|
|
570
|
+
|
|
571
|
+
def generate_template(entity)
|
|
572
|
+
template = "(* TODO: Document #{entity.id} *)\n"
|
|
573
|
+
template += "ENTITY #{entity.id};\n"
|
|
574
|
+
|
|
575
|
+
entity.attributes.each do |attr|
|
|
576
|
+
template += " (* TODO: Document #{attr.id} *)\n"
|
|
577
|
+
template += " #{attr.id} : #{attr.type};\n"
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
template += "END_ENTITY;\n"
|
|
581
|
+
template
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Usage
|
|
585
|
+
repo = Expressir::Express::Parser.from_file('undocumented.exp')
|
|
586
|
+
schema = repo.schemas.first
|
|
587
|
+
|
|
588
|
+
puts "Documentation Templates for Undocumented Entities"
|
|
589
|
+
puts "=" * 60
|
|
590
|
+
|
|
591
|
+
schema.entities.each do |entity|
|
|
592
|
+
next if Expressir::Coverage.entity_documented?(entity)
|
|
593
|
+
|
|
594
|
+
puts "\n#{generate_template(entity)}"
|
|
595
|
+
end
|
|
596
|
+
----
|
|
597
|
+
|
|
598
|
+
=== Step 10: Coverage Dashboard
|
|
599
|
+
|
|
600
|
+
==== Generate HTML Report
|
|
601
|
+
|
|
602
|
+
Create `coverage_dashboard.rb`:
|
|
603
|
+
|
|
604
|
+
[source,ruby]
|
|
605
|
+
----
|
|
606
|
+
require 'expressir'
|
|
607
|
+
require 'erb'
|
|
608
|
+
|
|
609
|
+
files = Dir.glob('schemas/**/*.exp')
|
|
610
|
+
reports_data = []
|
|
611
|
+
|
|
612
|
+
files.each do |file|
|
|
613
|
+
repo = Expressir::Express::Parser.from_file(file)
|
|
614
|
+
report = Expressir::Coverage::Report.from_repository(repo)
|
|
615
|
+
|
|
616
|
+
reports_data << {
|
|
617
|
+
file: file,
|
|
618
|
+
coverage: report.coverage_percentage,
|
|
619
|
+
total: report.total_entities.size,
|
|
620
|
+
documented: report.documented_entities.size,
|
|
621
|
+
undocumented: report.undocumented_entities
|
|
622
|
+
}
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
template = ERB.new(<<~HTML)
|
|
626
|
+
<!DOCTYPE html>
|
|
627
|
+
<html>
|
|
628
|
+
<head>
|
|
629
|
+
<title>Coverage Dashboard</title>
|
|
630
|
+
<style>
|
|
631
|
+
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
632
|
+
table { border-collapse: collapse; width: 100%; }
|
|
633
|
+
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
634
|
+
th { background-color: #4CAF50; color: white; }
|
|
635
|
+
.high { color: green; }
|
|
636
|
+
.medium { color: orange; }
|
|
637
|
+
.low { color: red; }
|
|
638
|
+
</style>
|
|
639
|
+
</head>
|
|
640
|
+
<body>
|
|
641
|
+
<h1>Documentation Coverage Dashboard</h1>
|
|
642
|
+
|
|
643
|
+
<h2>Summary</h2>
|
|
644
|
+
<table>
|
|
645
|
+
<tr>
|
|
646
|
+
<th>File</th>
|
|
647
|
+
<th>Coverage</th>
|
|
648
|
+
<th>Total</th>
|
|
649
|
+
<th>Documented</th>
|
|
650
|
+
<th>Undocumented</th>
|
|
651
|
+
</tr>
|
|
652
|
+
<% reports_data.each do |report| %>
|
|
653
|
+
<tr>
|
|
654
|
+
<td><%= report[:file] %></td>
|
|
655
|
+
<td class="<%= report[:coverage] >= 80 ? 'high' : report[:coverage] >= 50 ? 'medium' : 'low' %>">
|
|
656
|
+
<%= report[:coverage].round(2) %>%
|
|
657
|
+
</td>
|
|
658
|
+
<td><%= report[:total] %></td>
|
|
659
|
+
<td><%= report[:documented] %></td>
|
|
660
|
+
<td><%= report[:total] - report[:documented] %></td>
|
|
661
|
+
</tr>
|
|
662
|
+
<% end %>
|
|
663
|
+
</table>
|
|
664
|
+
|
|
665
|
+
<h2>Undocumented Elements</h2>
|
|
666
|
+
<% reports_data.each do |report| %>
|
|
667
|
+
<% if report[:undocumented].any? %>
|
|
668
|
+
<h3><%= report[:file] %></h3>
|
|
669
|
+
<ul>
|
|
670
|
+
<% report[:undocumented].each do |item| %>
|
|
671
|
+
<li><%= item %></li>
|
|
672
|
+
<% end %>
|
|
673
|
+
</ul>
|
|
674
|
+
<% end %>
|
|
675
|
+
<% end %>
|
|
676
|
+
</body>
|
|
677
|
+
</html>
|
|
678
|
+
HTML
|
|
679
|
+
|
|
680
|
+
File.write('coverage_dashboard.html', template.result(binding))
|
|
681
|
+
puts "Dashboard generated: coverage_dashboard.html"
|
|
682
|
+
----
|
|
683
|
+
|
|
684
|
+
=== Step 11: Practice Exercises
|
|
685
|
+
|
|
686
|
+
==== Exercise 1: Coverage Trends
|
|
687
|
+
|
|
688
|
+
Track coverage over time:
|
|
689
|
+
* Store coverage results with timestamps
|
|
690
|
+
* Generate trend graphs
|
|
691
|
+
* Identify improving/declining files
|
|
692
|
+
|
|
693
|
+
==== Exercise 2: Smart Exclusions
|
|
694
|
+
|
|
695
|
+
Create a configuration system that:
|
|
696
|
+
* Defines project-specific exclusions
|
|
697
|
+
* Supports per-directory rules
|
|
698
|
+
* Allows temporary exemptions with expiry
|
|
699
|
+
|
|
700
|
+
==== Exercise 3: Documentation Generator
|
|
701
|
+
|
|
702
|
+
Build a tool that:
|
|
703
|
+
* Identifies undocumented elements
|
|
704
|
+
* Suggests documentation based on element names
|
|
705
|
+
* Generates documentation templates
|
|
706
|
+
* Validates documentation quality
|
|
707
|
+
|
|
708
|
+
=== Best Practices
|
|
709
|
+
|
|
710
|
+
**Set Realistic Targets**::
|
|
711
|
+
* Start with current coverage baseline
|
|
712
|
+
* Improve gradually (e.g., +5% per sprint)
|
|
713
|
+
* Different standards for different schema types
|
|
714
|
+
|
|
715
|
+
**Exclude Appropriately**::
|
|
716
|
+
* Document exclusion rationale
|
|
717
|
+
* Review exclusions periodically
|
|
718
|
+
* Don't exclude to inflate numbers
|
|
719
|
+
|
|
720
|
+
**Integrate Early**::
|
|
721
|
+
* Add coverage checks to CI/CD
|
|
722
|
+
* Review coverage in code reviews
|
|
723
|
+
* Track coverage metrics over time
|
|
724
|
+
|
|
725
|
+
**Quality Over Quantity**::
|
|
726
|
+
* Brief, clear remarks are better than verbose ones
|
|
727
|
+
* Explain *why*, not just *what*
|
|
728
|
+
* Keep documentation up-to-date
|
|
729
|
+
|
|
730
|
+
=== Common Issues
|
|
731
|
+
|
|
732
|
+
**False Positives**
|
|
733
|
+
|
|
734
|
+
**Problem**: Element marked as undocumented but has remarks
|
|
735
|
+
|
|
736
|
+
**Cause**: Remarks may not be properly formatted
|
|
737
|
+
|
|
738
|
+
**Solution**: Ensure remarks use EXPRESS comment syntax:
|
|
739
|
+
[source,express]
|
|
740
|
+
----
|
|
741
|
+
(* This is a valid remark *)
|
|
742
|
+
ENTITY person;
|
|
743
|
+
END_ENTITY;
|
|
744
|
+
----
|
|
745
|
+
|
|
746
|
+
**High Coverage, Poor Quality**
|
|
747
|
+
|
|
748
|
+
**Problem**: 100% coverage but unhelpful documentation
|
|
749
|
+
|
|
750
|
+
**Solution**:
|
|
751
|
+
* Review documentation quality manually
|
|
752
|
+
* Use specific, descriptive remarks
|
|
753
|
+
* Explain purpose and constraints
|
|
754
|
+
|
|
755
|
+
**Coverage Varies by Tool**
|
|
756
|
+
|
|
757
|
+
**Problem**: Different tools report different coverage
|
|
758
|
+
|
|
759
|
+
**Cause**: Different element types counted
|
|
760
|
+
|
|
761
|
+
**Solution**:
|
|
762
|
+
* Use consistent tool and exclusions
|
|
763
|
+
* Document counting methodology
|
|
764
|
+
* Track relative changes, not absolute numbers
|
|
765
|
+
|
|
766
|
+
=== Next Steps
|
|
767
|
+
|
|
768
|
+
Congratulations! You can now analyze and improve documentation coverage.
|
|
769
|
+
|
|
770
|
+
**Continue learning**:
|
|
771
|
+
|
|
772
|
+
* link:../guides/cli/coverage-analysis.html[Coverage Analysis Guide] - Advanced techniques
|
|
773
|
+
* link:../guides/ruby-api/[Ruby API Guides] - Programmatic coverage tools
|
|
774
|
+
* link:../references/[References] - Complete API documentation
|
|
775
|
+
|
|
776
|
+
**Read more**:
|
|
777
|
+
|
|
778
|
+
* ISO 10303 documentation standards
|
|
779
|
+
* Technical writing best practices
|
|
780
|
+
|
|
781
|
+
=== Summary
|
|
782
|
+
|
|
783
|
+
In this tutorial, you learned to:
|
|
784
|
+
|
|
785
|
+
* ✅ Analyze documentation coverage
|
|
786
|
+
* ✅ Use the coverage CLI tool
|
|
787
|
+
* ✅ Generate coverage reports in multiple formats
|
|
788
|
+
* ✅ Exclude specific element types
|
|
789
|
+
* ✅ Ignore files from coverage calculation
|
|
790
|
+
* ✅ Check coverage programmatically
|
|
791
|
+
* ✅ Enforce coverage standards
|
|
792
|
+
* ✅ Track and improve coverage over time
|
|
793
|
+
* ✅ Create coverage dashboards
|
|
794
|
+
|
|
795
|
+
You're now equipped to maintain high-quality EXPRESS schema documentation!
|