Documentation Coverage Analysis
Prerequisites
Before starting this tutorial, ensure you have:
-
Completed Liquid Templates
-
EXPRESS schemas with varying documentation levels
-
Understanding of EXPRESS remarks
-
Expressir CLI and Ruby access
Learning Objectives
By the end of this tutorial, you will be able to:
-
Analyze documentation coverage of schemas
-
Use the coverage CLI tool
-
Identify undocumented elements
-
Generate coverage reports
-
Exclude specific element types
-
Set documentation standards
-
Improve schema documentation systematically
What You’ll Build
You’ll create documentation coverage reports and tools to improve and maintain high-quality EXPRESS schema documentation.
Step 1: Understanding Documentation Coverage
What is Coverage?
Documentation coverage measures how well your EXPRESS schemas are documented through remarks (comments).
- Covered element
-
Has at least one remark
(* A person in the system *) ENTITY person; (* Full name of the person *) name : STRING; END_ENTITY; - Uncovered element
-
Has no remarks
ENTITY person; name : STRING; -- No documentation! END_ENTITY;
Step 2: Create Test Schemas
Let’s create schemas with different coverage levels.
Well-Documented Schema
Create documented.exp:
SCHEMA documented_schema;
(* Unique identifier for entities *)
TYPE identifier = STRING;
END_TYPE;
(* A person in the organization *)
ENTITY person;
(* Unique identifier *)
id : identifier;
(* Full name *)
name : STRING;
(* Email address *)
email : OPTIONAL STRING;
END_ENTITY;
(* An organizational unit *)
ENTITY organization;
(* Organization identifier *)
org_id : identifier;
(* Organization name *)
org_name : STRING;
(* List of employees *)
employees : SET [0:?] OF person;
END_ENTITY;
END_SCHEMA;
Poorly-Documented Schema
Create undocumented.exp:
SCHEMA undocumented_schema;
TYPE identifier = STRING;
END_TYPE;
ENTITY person;
id : identifier;
name : STRING;
email : OPTIONAL STRING;
END_ENTITY;
ENTITY organization;
org_id : identifier;
org_name : STRING;
employees : SET [0:?] OF person;
END_ENTITY;
END_SCHEMA;
Step 3: Basic Coverage Analysis
Using the CLI
# Check single file
expressir coverage documented.exp
# Check multiple files
expressir coverage documented.exp undocumented.exp
# Check directory recursively
expressir coverage schemas/
Output for documented.exp:
File: documented.exp
✓ All elements documented
Coverage: 100.00%
Total: 9
Documented: 9
Undocumented: 0
Output for undocumented.exp:
File: undocumented.exp
Undocumented elements:
TYPE: identifier
ENTITY: person
ATTRIBUTE: person.id
ATTRIBUTE: person.name
ATTRIBUTE: person.email
ENTITY: organization
ATTRIBUTE: organization.org_id
ATTRIBUTE: organization.org_name
ATTRIBUTE: organization.employees
Coverage: 0.00%
Total: 9
Documented: 0
Undocumented: 9
Step 4: Coverage Output Formats
Text Format (Default)
expressir coverage schemas/ --format text
Human-readable table with: * File paths * Undocumented elements * Coverage percentages * Summary statistics
JSON Format
expressir coverage schemas/ --format json > coverage.json
Programmatically parseable output:
{
"overall": {
"coverage_percentage": 50.0,
"total_entities": 18,
"documented_entities": 9,
"undocumented_entities": 9
},
"files": [
{
"file": "schemas/documented.exp",
"coverage": 100.0,
"total": 9,
"documented": 9,
"undocumented": []
},
{
"file": "schemas/undocumented.exp",
"coverage": 0.0,
"total": 9,
"documented": 0,
"undocumented": ["identifier", "person", "person.id", ...]
}
]
}
YAML Format
expressir coverage schemas/ --format yaml > coverage.yaml
YAML output for easy reading and processing:
overall:
coverage_percentage: 50.0
total_entities: 18
documented_entities: 9
undocumented_entities: 9
files:
- file: schemas/documented.exp
coverage: 100.0
total: 9
documented: 9
undocumented: []
- file: schemas/undocumented.exp
coverage: 0.0
total: 9
documented: 0
undocumented:
- identifier
- person
- person.id
Step 5: Excluding Element Types
Why Exclude?
Some element types may not require documentation: * Auto-generated TYPE descriptions * Simple type aliases * Internal helper functions
Basic Exclusions
# Exclude all TYPE definitions
expressir coverage schemas/ --exclude=TYPE
# Exclude multiple types
expressir coverage schemas/ --exclude=TYPE,CONSTANT,FUNCTION
# Exclude parameters and variables
expressir coverage schemas/ --exclude=PARAMETER,VARIABLE
Step 6: Ignoring Files
Step 7: Programmatic Coverage Analysis
Basic Coverage Check
Create check_coverage.rb:
require 'expressir'
# Parse schema
repo = Expressir::Express::Parser.from_file('documented.exp')
# Create coverage report
report = Expressir::Coverage::Report.from_repository(repo)
puts "Coverage Analysis"
puts "=" * 60
puts "Overall: #{report.coverage_percentage.round(2)}%"
puts "Total: #{report.total_entities.size}"
puts "Documented: #{report.documented_entities.size}"
puts "Undocumented: #{report.undocumented_entities.size}"
if report.undocumented_entities.any?
puts "\nUndocumented elements:"
report.undocumented_entities.take(10).each do |entity|
puts " - #{entity}"
end
end
Detailed File Reports
# Get per-file breakdown
report.file_reports.each do |file_report|
puts "\nFile: #{file_report[:file]}"
puts " Coverage: #{file_report[:coverage]}%"
puts " Total: #{file_report[:total]}"
puts " Documented: #{file_report[:documented]}"
if file_report[:undocumented].any?
puts " Undocumented:"
file_report[:undocumented].each do |item|
puts " - #{item}"
end
end
end
Check Individual Elements
# Check if entity is documented
schema = repo.schemas.first
entity = schema.entities.first
if Expressir::Coverage.entity_documented?(entity)
puts "✓ #{entity.id} is documented"
else
puts "✗ #{entity.id} lacks documentation"
end
# Check all entities
schema.entities.each do |entity|
status = Expressir::Coverage.entity_documented?(entity) ? "✓" : "✗"
puts "#{status} #{entity.id}"
end
Step 8: Coverage Enforcement
Create Coverage Checker
Create enforce_coverage.rb:
require 'expressir'
class CoverageEnforcer
MINIMUM_COVERAGE = 80.0 # 80% required
def initialize(files)
@files = files
end
def check
repos = @files.map { |f| Expressir::Express::Parser.from_file(f) }
all_pass = true
repos.each do |repo|
report = Expressir::Coverage::Report.from_repository(repo)
file = repo.schemas.first.file
coverage = report.coverage_percentage
if coverage < MINIMUM_COVERAGE
puts "❌ #{file}: #{coverage.round(2)}% (minimum: #{MINIMUM_COVERAGE}%)"
puts " Undocumented:"
report.undocumented_entities.take(5).each do |item|
puts " - #{item}"
end
all_pass = false
else
puts "✓ #{file}: #{coverage.round(2)}%"
end
end
all_pass
end
end
# Usage
files = Dir.glob('schemas/**/*.exp')
enforcer = CoverageEnforcer.new(files)
unless enforcer.check
puts "\n❌ Coverage check failed!"
exit 1
end
puts "\n✓ All files meet coverage requirements!"
CI/CD Integration
Create .github/workflows/coverage.yml:
name: Documentation Coverage
on: [push, pull_request]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.0
- name: Install Expressir
run: gem install expressir
- name: Check Coverage
run: |
expressir coverage schemas/ --format json > coverage.json
# Extract coverage percentage
COVERAGE=$(cat coverage.json | jq '.overall.coverage_percentage')
echo "Coverage: ${COVERAGE}%"
# Fail if below 80%
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "❌ Coverage below 80%"
exit 1
fi
echo "✓ Coverage check passed"
- name: Upload Coverage Report
uses: actions/upload-artifact@v2
with:
name: coverage-report
path: coverage.json
Step 9: Improving Coverage
Find Low-Coverage Files
Create find_low_coverage.rb:
require 'expressir'
require 'json'
files = Dir.glob('schemas/**/*.exp')
results = []
files.each do |file|
repo = Expressir::Express::Parser.from_file(file)
report = Expressir::Coverage::Report.from_repository(repo)
results << {
file: file,
coverage: report.coverage_percentage,
undocumented: report.undocumented_entities.size
}
end
# Sort by coverage (worst first)
results.sort_by! { |r| r[:coverage] }
puts "Low Coverage Files"
puts "=" * 60
results.take(10).each do |result|
puts "\n#{result[:file]}"
puts " Coverage: #{result[:coverage].round(2)}%"
puts " Undocumented: #{result[:undocumented]}"
end
Generate Documentation Templates
Create generate_doc_templates.rb:
require 'expressir'
def generate_template(entity)
template = "(* TODO: Document #{entity.id} *)\n"
template += "ENTITY #{entity.id};\n"
entity.attributes.each do |attr|
template += " (* TODO: Document #{attr.id} *)\n"
template += " #{attr.id} : #{attr.type};\n"
end
template += "END_ENTITY;\n"
template
end
# Usage
repo = Expressir::Express::Parser.from_file('undocumented.exp')
schema = repo.schemas.first
puts "Documentation Templates for Undocumented Entities"
puts "=" * 60
schema.entities.each do |entity|
next if Expressir::Coverage.entity_documented?(entity)
puts "\n#{generate_template(entity)}"
end
Step 10: Coverage Dashboard
Generate HTML Report
Create coverage_dashboard.rb:
require 'expressir'
require 'erb'
files = Dir.glob('schemas/**/*.exp')
reports_data = []
files.each do |file|
repo = Expressir::Express::Parser.from_file(file)
report = Expressir::Coverage::Report.from_repository(repo)
reports_data << {
file: file,
coverage: report.coverage_percentage,
total: report.total_entities.size,
documented: report.documented_entities.size,
undocumented: report.undocumented_entities
}
end
template = ERB.new(<<~HTML)
<!DOCTYPE html>
<html>
<head>
<title>Coverage Dashboard</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #4CAF50; color: white; }
.high { color: green; }
.medium { color: orange; }
.low { color: red; }
</style>
</head>
<body>
<h1>Documentation Coverage Dashboard</h1>
<h2>Summary</h2>
<table>
<tr>
<th>File</th>
<th>Coverage</th>
<th>Total</th>
<th>Documented</th>
<th>Undocumented</th>
</tr>
<% reports_data.each do |report| %>
<tr>
<td><%= report[:file] %></td>
<td class="<%= report[:coverage] >= 80 ? 'high' : report[:coverage] >= 50 ? 'medium' : 'low' %>">
<%= report[:coverage].round(2) %>%
</td>
<td><%= report[:total] %></td>
<td><%= report[:documented] %></td>
<td><%= report[:total] - report[:documented] %></td>
</tr>
<% end %>
</table>
<h2>Undocumented Elements</h2>
<% reports_data.each do |report| %>
<% if report[:undocumented].any? %>
<h3><%= report[:file] %></h3>
<ul>
<% report[:undocumented].each do |item| %>
<li><%= item %></li>
<% end %>
</ul>
<% end %>
<% end %>
</body>
</html>
HTML
File.write('coverage_dashboard.html', template.result(binding))
puts "Dashboard generated: coverage_dashboard.html"
Step 11: Practice Exercises
Exercise 1: Coverage Trends
Track coverage over time: * Store coverage results with timestamps * Generate trend graphs * Identify improving/declining files
Best Practices
- Set Realistic Targets
-
-
Start with current coverage baseline
-
Improve gradually (e.g., +5% per sprint)
-
Different standards for different schema types
-
- Exclude Appropriately
-
-
Document exclusion rationale
-
Review exclusions periodically
-
Don’t exclude to inflate numbers
-
- Integrate Early
-
-
Add coverage checks to CI/CD
-
Review coverage in code reviews
-
Track coverage metrics over time
-
- Quality Over Quantity
-
-
Brief, clear remarks are better than verbose ones
-
Explain why, not just what
-
Keep documentation up-to-date
-
Common Issues
False Positives
Problem: Element marked as undocumented but has remarks
Cause: Remarks may not be properly formatted
Solution: Ensure remarks use EXPRESS comment syntax:
(* This is a valid remark *)
ENTITY person;
END_ENTITY;
High Coverage, Poor Quality
Problem: 100% coverage but unhelpful documentation
Solution: * Review documentation quality manually * Use specific, descriptive remarks * Explain purpose and constraints
Coverage Varies by Tool
Problem: Different tools report different coverage
Cause: Different element types counted
Solution: * Use consistent tool and exclusions * Document counting methodology * Track relative changes, not absolute numbers
Next Steps
Congratulations! You can now analyze and improve documentation coverage.
Continue learning:
-
Coverage Analysis Guide - Advanced techniques
-
Ruby API Guides - Programmatic coverage tools
-
References - Complete API documentation
Read more:
-
ISO 10303 documentation standards
-
Technical writing best practices
Summary
In this tutorial, you learned to:
-
✅ Analyze documentation coverage
-
✅ Use the coverage CLI tool
-
✅ Generate coverage reports in multiple formats
-
✅ Exclude specific element types
-
✅ Ignore files from coverage calculation
-
✅ Check coverage programmatically
-
✅ Enforce coverage standards
-
✅ Track and improve coverage over time
-
✅ Create coverage dashboards
You’re now equipped to maintain high-quality EXPRESS schema documentation!