expressir 2.1.21 → 2.1.22

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5523a9cdb1e5b8168a0d2d7262cdd8a5e849b066a3eeaaad90a3bcb3a640fe38
4
- data.tar.gz: 293acbebeecc50a22ba8bc56aa8413f7e156dac17fa4fa872380aff5a9bf320c
3
+ metadata.gz: fab262d4a8c290f1dc292ff8ea22e9f631356945fb76bed736594dad060078b0
4
+ data.tar.gz: 45e33a9920262038833f1f00113b12527eb9dc64a71d29d8e0b5f36bd89842ff
5
5
  SHA512:
6
- metadata.gz: b756fab7be254dc71ab78ce9ffdb220c727cc1ef8599c2e293ee2edb35d8fb7f2ab9e127683e7621d5a0ac2df4379efa5ff1c2aeaa8dd7623b94b18d5e778d7e
7
- data.tar.gz: cb767afb4bef0a7555b9519a29b1cefa14ba3c96278d5154e2c2b5af29e813ba0824ffb7efbfd2e601f2e606f0a5800595b8a97b7998a83dd80c4d99448e7546
6
+ metadata.gz: 3bbc6a59dc02947a9c2ed5971900094ce183a4bbe0bdc4e3e762906d8d0675bc5c3ed145c37f17a406c406db783d4dcac1055938cdef2f54382bf1647bd57a61
7
+ data.tar.gz: ae2c40bc87334138a4ce2cbfdc04bf699da520f62483bf9a8760117ba00b7d45dde639e0c292b5cdb8a285c1d01bd59aef4f5bf70f976ded713c1d7fb4ec5a61
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2025-06-07 05:08:55 UTC using RuboCop version 1.75.2.
3
+ # on 2025-06-07 07:39:56 UTC using RuboCop version 1.75.2.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -13,6 +13,24 @@ Gemspec/RequiredRubyVersion:
13
13
  Exclude:
14
14
  - 'expressir.gemspec'
15
15
 
16
+ # Offense count: 2
17
+ # This cop supports safe autocorrection (--autocorrect).
18
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
19
+ # SupportedStyles: special_inside_parentheses, consistent, align_braces
20
+ Layout/FirstHashElementIndentation:
21
+ Exclude:
22
+ - 'spec/expressir/commands/coverage_ignore_files_spec.rb'
23
+
24
+ # Offense count: 1
25
+ # This cop supports safe autocorrection (--autocorrect).
26
+ # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
27
+ # SupportedHashRocketStyles: key, separator, table
28
+ # SupportedColonStyles: key, separator, table
29
+ # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
30
+ Layout/HashAlignment:
31
+ Exclude:
32
+ - 'spec/expressir/commands/coverage_ignore_files_spec.rb'
33
+
16
34
  # Offense count: 2
17
35
  # This cop supports safe autocorrection (--autocorrect).
18
36
  # Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
@@ -27,25 +45,11 @@ Lint/DuplicateBranch:
27
45
  Exclude:
28
46
  - 'lib/expressir/coverage.rb'
29
47
 
30
- # Offense count: 1
31
- # This cop supports safe autocorrection (--autocorrect).
32
- Lint/ScriptPermission:
33
- Exclude:
34
- - 'update_yaml_fixtures.rb'
35
-
36
48
  # Offense count: 3
37
49
  Lint/ShadowingOuterLocalVariable:
38
50
  Exclude:
39
51
  - 'lib/expressir/express/visitor.rb'
40
52
 
41
- # Offense count: 2
42
- # This cop supports safe autocorrection (--autocorrect).
43
- # Configuration parameters: AutoCorrect, IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
44
- Lint/UnusedBlockArgument:
45
- Exclude:
46
- - 'lib/expressir/express/visitor.rb'
47
- - 'spec/support/yaml_matchers.rb'
48
-
49
53
  # Offense count: 2
50
54
  # This cop supports safe autocorrection (--autocorrect).
51
55
  # Configuration parameters: AutoCorrect, AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
@@ -55,7 +59,7 @@ Lint/UnusedMethodArgument:
55
59
  - 'lib/expressir/express/cache.rb'
56
60
  - 'lib/expressir/express/parser.rb'
57
61
 
58
- # Offense count: 76
62
+ # Offense count: 79
59
63
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
60
64
  Metrics/AbcSize:
61
65
  Exclude:
@@ -80,7 +84,7 @@ Metrics/AbcSize:
80
84
  Metrics/BlockLength:
81
85
  Max: 143
82
86
 
83
- # Offense count: 56
87
+ # Offense count: 57
84
88
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
85
89
  Metrics/CyclomaticComplexity:
86
90
  Exclude:
@@ -95,12 +99,12 @@ Metrics/CyclomaticComplexity:
95
99
  - 'lib/expressir/model/model_element.rb'
96
100
  - 'spec/support/model_element_helper.rb'
97
101
 
98
- # Offense count: 100
102
+ # Offense count: 103
99
103
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
100
104
  Metrics/MethodLength:
101
105
  Max: 82
102
106
 
103
- # Offense count: 44
107
+ # Offense count: 45
104
108
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
105
109
  Metrics/PerceivedComplexity:
106
110
  Exclude:
@@ -133,8 +137,18 @@ Style/MissingRespondToMissing:
133
137
  Exclude:
134
138
  - 'lib/expressir/express/visitor.rb'
135
139
 
136
- # Offense count: 2
137
- # This cop supports unsafe autocorrection (--autocorrect-all).
138
- Style/SlicingWithRange:
140
+ # Offense count: 1
141
+ # This cop supports safe autocorrection (--autocorrect).
142
+ # Configuration parameters: EnforcedStyleForMultiline.
143
+ # SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
144
+ Style/TrailingCommaInArrayLiteral:
139
145
  Exclude:
140
- - 'lib/expressir/express/visitor.rb'
146
+ - 'spec/expressir/commands/coverage_ignore_files_spec.rb'
147
+
148
+ # Offense count: 1
149
+ # This cop supports safe autocorrection (--autocorrect).
150
+ # Configuration parameters: EnforcedStyleForMultiline.
151
+ # SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
152
+ Style/TrailingCommaInHashLiteral:
153
+ Exclude:
154
+ - 'spec/expressir/commands/coverage_ignore_files_spec.rb'
data/README.adoc CHANGED
@@ -271,6 +271,7 @@ The coverage command supports different output formats and exclusion options:
271
271
  | `--format json` | Output in JSON format for programmatic processing
272
272
  | `--format yaml` | Output in YAML format for programmatic processing
273
273
  | `--exclude TYPES` | Comma-separated list of EXPRESS entity types to exclude from coverage analysis
274
+ | `--ignore-files PATH` | Path to YAML file containing array of files to ignore from overall coverage calculation
274
275
  |===
275
276
 
276
277
  ==== Excluding entity types from coverage
@@ -360,11 +361,12 @@ expressir coverage --exclude=TYPE:SELECT,FUNCTION:INNER schemas/resources/action
360
361
 
361
362
  This is useful when you want to focus documentation coverage on top-level
362
363
  functions while excluding nested helper functions that may not require
363
- individual documentation.
364
+ individual documentation. The exclusion works recursively, excluding functions
365
+ at any nesting level within other constructs.
364
366
 
365
367
  Valid FUNCTION subtypes that can be excluded:
366
368
 
367
- `INNER`:: Inner functions nested within other functions, rules, or procedures
369
+ `INNER`:: Inner functions nested within other functions, rules, or procedures (at any depth)
368
370
  +
369
371
  [example]
370
372
  ====
@@ -372,14 +374,172 @@ Valid FUNCTION subtypes that can be excluded:
372
374
  FUNCTION outer_function : BOOLEAN;
373
375
  -- This inner function would be excluded with FUNCTION:INNER
374
376
  FUNCTION inner_helper_function : BOOLEAN;
377
+ -- Even deeply nested functions are excluded
378
+ FUNCTION deeply_nested_function : BOOLEAN;
379
+ RETURN (TRUE);
380
+ END_FUNCTION;
375
381
  RETURN (TRUE);
376
382
  END_FUNCTION;
377
383
 
378
384
  RETURN (TRUE);
379
385
  END_FUNCTION;
386
+
387
+ RULE example_rule FOR (some_entity);
388
+ -- Inner functions in rules are also excluded
389
+ FUNCTION inner_function_in_rule : BOOLEAN;
390
+ RETURN (TRUE);
391
+ END_FUNCTION;
392
+ WHERE
393
+ WR1: inner_function_in_rule();
394
+ END_RULE;
395
+
396
+ PROCEDURE example_procedure;
397
+ -- Inner functions in procedures are also excluded
398
+ FUNCTION inner_function_in_procedure : BOOLEAN;
399
+ RETURN (TRUE);
400
+ END_FUNCTION;
401
+ END_PROCEDURE;
380
402
  ----
381
403
  ====
382
404
 
405
+ The `FUNCTION:INNER` exclusion helps maintain focus on documenting the primary
406
+ API functions while ignoring implementation details of nested helper functions.
407
+
408
+ ==== Ignoring files from coverage calculation
409
+
410
+ You can exclude entire files from the overall coverage calculation using the
411
+ `--ignore-files` option. This is useful when you have files that should not
412
+ contribute to the overall documentation coverage statistics, such as test
413
+ schemas, example files, or legacy schemas.
414
+
415
+ [source, sh]
416
+ ----
417
+ # Use ignore files to exclude specific files from coverage calculation
418
+ expressir coverage --ignore-files ignore_list.yaml schemas/resources/
419
+
420
+ # Combine with other options
421
+ expressir coverage --ignore-files ignore_list.yaml --exclude=TYPE:SELECT --format=json schemas/resources/
422
+ ----
423
+
424
+ ===== Ignore files YAML format
425
+
426
+ The ignore files YAML should contain an array of file patterns. Each pattern
427
+ can be either an exact file path or use glob patterns for matching multiple files.
428
+
429
+ .ignore_list.yaml
430
+ [source, yaml]
431
+ ----
432
+ # Array of file patterns to ignore
433
+ - examples/test_schema.exp # Exact file path
434
+ - examples/*_test_*.exp # Glob pattern for test files
435
+ - legacy/old_*.exp # Glob pattern for legacy files
436
+ - temp/temporary_schema.exp # Another exact path
437
+ ----
438
+
439
+ ===== Pattern matching behavior
440
+
441
+ File patterns in the ignore files YAML support:
442
+
443
+ * **Exact paths**: Match specific files exactly
444
+ * **Glob patterns**: Use `*` for wildcard matching
445
+ * **Relative paths**: Patterns are resolved relative to the YAML file's directory
446
+ * **Absolute paths**: Full system paths are also supported
447
+
448
+ [source, yaml]
449
+ ----
450
+ # Examples of different pattern types
451
+ - schemas/action_schema/action_schema.exp # Exact relative path
452
+ - /full/path/to/schema.exp # Absolute path
453
+ - schemas/**/test_*.exp # Recursive glob pattern
454
+ - temp/*.exp # All .exp files in temp directory
455
+ ----
456
+
457
+ ===== Behavior of ignored files
458
+
459
+ When files are ignored using the `--ignore-files` option:
460
+
461
+ . **Excluded from overall statistics**: Ignored files do not contribute to the
462
+ overall coverage percentage calculation
463
+
464
+ . **Still processed and reported**: Ignored files are still analyzed and appear
465
+ in the output, but marked with an `ignored: true` flag
466
+
467
+ . **Separate reporting section**: In JSON/YAML output formats, ignored files
468
+ appear in both the main `files` section (with the ignored flag) and in a
469
+ separate `ignored_files` section
470
+
471
+ . **Overall statistics updated**: The overall statistics include additional
472
+ fields showing the count of ignored files and entities
473
+
474
+ .Example JSON output with ignored files:
475
+ [source, json]
476
+ ----
477
+ {
478
+ "overall": {
479
+ "coverage_percentage": 75.0,
480
+ "total_entities": 100,
481
+ "documented_entities": 75,
482
+ "undocumented_entities": 25,
483
+ "ignored_files_count": 2,
484
+ "ignored_entities_count": 15
485
+ },
486
+ "files": [
487
+ {
488
+ "file": "schemas/main_schema.exp",
489
+ "ignored": false,
490
+ "coverage": 80.0,
491
+ "total": 50,
492
+ "documented": 40,
493
+ "undocumented": ["entity1", "entity2"]
494
+ },
495
+ {
496
+ "file": "examples/test_schema.exp",
497
+ "ignored": true,
498
+ "matched_pattern": "examples/*_test_*.exp",
499
+ "coverage": 20.0,
500
+ "total": 10,
501
+ "documented": 2,
502
+ "undocumented": ["test_entity1", "test_entity2"]
503
+ }
504
+ ],
505
+ "ignored_files": [
506
+ {
507
+ "file": "examples/test_schema.exp",
508
+ "matched_pattern": "examples/*_test_*.exp",
509
+ "coverage": 20.0,
510
+ "total": 10,
511
+ "documented": 2,
512
+ "undocumented": ["test_entity1", "test_entity2"]
513
+ }
514
+ ]
515
+ }
516
+ ----
517
+
518
+ ===== Error handling
519
+
520
+ The ignore files functionality handles various error conditions gracefully:
521
+
522
+ * **Missing YAML file**: If the specified ignore files YAML doesn't exist, a
523
+ warning is displayed and coverage analysis continues normally
524
+
525
+ * **Invalid YAML format**: If the YAML file is malformed or doesn't contain an
526
+ array, a warning is displayed and the file is ignored
527
+
528
+ * **Non-matching patterns**: Patterns that don't match any files are silently
529
+ ignored (no error or warning)
530
+
531
+ * **Permission errors**: File access errors are reported as warnings
532
+
533
+ ===== Use cases for ignore files
534
+
535
+ Common scenarios where ignore files are useful:
536
+
537
+ * **Test schemas**: Exclude test or example schemas from production coverage metrics
538
+ * **Legacy files**: Ignore old schemas that are being phased out
539
+ * **Generated files**: Exclude automatically generated schemas
540
+ * **Work-in-progress**: Temporarily ignore files under development
541
+ * **Different coverage standards**: Apply different documentation standards to different file sets
542
+
383
543
  Valid TYPE subtypes that can be excluded:
384
544
 
385
545
  `AGGREGATE`:: Aggregate type
data/lib/expressir/cli.rb CHANGED
@@ -57,6 +57,7 @@ module Expressir
57
57
  method_option :format, type: :string, desc: "Output format (text, json, yaml)", default: "text"
58
58
  method_option :exclude, type: :string, desc: "Comma-separated list of EXPRESS entity types to skip from coverage (e.g., TYPE,CONSTANT,TYPE:SELECT)"
59
59
  method_option :output, type: :string, desc: "Output file path for JSON/YAML formats (defaults to coverage_report.json/yaml)"
60
+ method_option :ignore_files, type: :string, desc: "Path to YAML file containing array of files to ignore from overall coverage calculation"
60
61
  def coverage(*paths)
61
62
  Commands::Coverage.new(options).run(paths)
62
63
  end
@@ -32,27 +32,28 @@ module Expressir
32
32
 
33
33
  def collect_reports(paths)
34
34
  reports = []
35
+ ignored_files = parse_ignore_files
35
36
 
36
37
  paths.each do |path|
37
- handle_path(path, reports)
38
+ handle_path(path, reports, ignored_files)
38
39
  end
39
40
 
40
41
  reports
41
42
  end
42
43
 
43
- def handle_path(path, reports)
44
+ def handle_path(path, reports, ignored_files)
44
45
  if File.directory?(path)
45
- handle_directory(path, reports)
46
+ handle_directory(path, reports, ignored_files)
46
47
  elsif File.extname(path).downcase == ".exp"
47
- handle_express_file(path, reports)
48
+ handle_express_file(path, reports, ignored_files)
48
49
  elsif [".yml", ".yaml"].include?(File.extname(path).downcase)
49
- handle_yaml_manifest(path, reports)
50
+ handle_yaml_manifest(path, reports, ignored_files)
50
51
  else
51
52
  say "Unsupported file type: #{path}"
52
53
  end
53
54
  end
54
55
 
55
- def handle_directory(path, reports)
56
+ def handle_directory(path, reports, ignored_files)
56
57
  say "Processing directory: #{path}"
57
58
  exp_files = Dir.glob(File.join(path, "**", "*.exp"))
58
59
  if exp_files.empty?
@@ -79,26 +80,26 @@ module Expressir
79
80
  progress.increment
80
81
  end
81
82
  skip_types = parse_skip_types
82
- report = Expressir::Coverage::Report.from_repository(repository, skip_types)
83
+ report = Expressir::Coverage::Report.from_repository(repository, skip_types, ignored_files)
83
84
  reports << report
84
85
  rescue StandardError => e
85
86
  say "Error processing directory #{path}: #{e.message}"
86
87
  end
87
88
  end
88
89
 
89
- def handle_express_file(path, reports)
90
+ def handle_express_file(path, reports, ignored_files)
90
91
  say "Processing file: #{path}"
91
92
  begin
92
93
  # For a single file, we don't need a progress bar
93
94
  skip_types = parse_skip_types
94
- report = Expressir::Coverage::Report.from_file(path, skip_types)
95
+ report = Expressir::Coverage::Report.from_file(path, skip_types, ignored_files)
95
96
  reports << report
96
97
  rescue StandardError => e
97
98
  say "Error processing file #{path}: #{e.message}"
98
99
  end
99
100
  end
100
101
 
101
- def handle_yaml_manifest(path, reports)
102
+ def handle_yaml_manifest(path, reports, ignored_files)
102
103
  say "Processing YAML manifest: #{path}"
103
104
  begin
104
105
  schema_list = YAML.load_file(path)
@@ -149,7 +150,7 @@ module Expressir
149
150
 
150
151
  # Create and add the report
151
152
  skip_types = parse_skip_types
152
- report = Expressir::Coverage::Report.from_repository(repository, skip_types)
153
+ report = Expressir::Coverage::Report.from_repository(repository, skip_types, ignored_files)
153
154
  reports << report
154
155
  end
155
156
  rescue StandardError => e
@@ -258,20 +259,39 @@ module Expressir
258
259
  end
259
260
 
260
261
  def build_structured_report(reports)
261
- {
262
- "overall" => {
263
- "total_entities" => reports.sum { |r| r.total_entities.size },
264
- "documented_entities" => reports.sum { |r| r.documented_entities.size },
265
- "undocumented_entities" => reports.sum { |r| r.undocumented_entities.size },
266
- "coverage_percentage" => if reports.sum { |r| r.total_entities.size }.positive?
267
- (reports.sum { |r| r.documented_entities.size }.to_f / reports.sum { |r| r.total_entities.size } * 100).round(2)
268
- else
269
- 100.0
270
- end,
271
- },
262
+ # Calculate ignored file statistics
263
+ ignored_files = reports.flat_map(&:ignored_file_reports)
264
+ ignored_entities_count = ignored_files.sum { |f| f["total"] }
265
+
266
+ overall_stats = {
267
+ "total_entities" => reports.sum { |r| r.total_entities.size },
268
+ "documented_entities" => reports.sum { |r| r.documented_entities.size },
269
+ "undocumented_entities" => reports.sum { |r| r.undocumented_entities.size },
270
+ "coverage_percentage" => if reports.sum { |r| r.total_entities.size }.positive?
271
+ (reports.sum { |r| r.documented_entities.size }.to_f / reports.sum { |r| r.total_entities.size } * 100).round(2)
272
+ else
273
+ 100.0
274
+ end,
275
+ }
276
+
277
+ # Add ignored file information if there are any
278
+ if ignored_files.any?
279
+ overall_stats["ignored_files_count"] = ignored_files.size
280
+ overall_stats["ignored_entities_count"] = ignored_entities_count
281
+ end
282
+
283
+ structured_report = {
284
+ "overall" => overall_stats,
272
285
  "files" => reports.flat_map(&:file_reports),
273
286
  "directories" => reports.flat_map(&:directory_reports),
274
287
  }
288
+
289
+ # Add ignored files section if there are any
290
+ if ignored_files.any?
291
+ structured_report["ignored_files"] = ignored_files
292
+ end
293
+
294
+ structured_report
275
295
  end
276
296
 
277
297
  def display_json_output(reports)
@@ -343,6 +363,55 @@ module Expressir
343
363
  end
344
364
  end
345
365
  end
366
+
367
+ # Parse and expand ignore files from YAML
368
+ # @return [Hash] Hash mapping absolute file paths to their matched patterns
369
+ def parse_ignore_files
370
+ ignore_files_option = options["ignore_files"] || options[:ignore_files]
371
+ return {} unless ignore_files_option
372
+
373
+ unless File.exist?(ignore_files_option)
374
+ say "Warning: Ignore files YAML not found: #{ignore_files_option}"
375
+ return {}
376
+ end
377
+
378
+ begin
379
+ patterns = YAML.load_file(ignore_files_option)
380
+ unless patterns.is_a?(Array)
381
+ say "Warning: Invalid ignore files YAML format. Expected an array of file patterns."
382
+ return {}
383
+ end
384
+
385
+ ignore_files_dir = File.dirname(File.expand_path(ignore_files_option))
386
+ expanded_files = {}
387
+
388
+ patterns.each do |pattern|
389
+ # Resolve pattern relative to the YAML file's directory
390
+ full_pattern = File.expand_path(pattern, ignore_files_dir)
391
+
392
+ # Expand glob pattern
393
+ matched_files = Dir.glob(full_pattern)
394
+
395
+ if matched_files.empty?
396
+ say "Warning: No files matched pattern: #{pattern}"
397
+ else
398
+ matched_files.each do |file_path|
399
+ # Store absolute path and the original pattern that matched it
400
+ expanded_files[File.expand_path(file_path)] = pattern
401
+ end
402
+ end
403
+ end
404
+
405
+ if expanded_files.any?
406
+ say "Found #{expanded_files.size} files to ignore from patterns"
407
+ end
408
+
409
+ expanded_files
410
+ rescue StandardError => e
411
+ say "Warning: Error processing ignore files YAML #{ignore_files_option}: #{e.message}"
412
+ {}
413
+ end
414
+ end
346
415
  end
347
416
  end
348
417
  end
@@ -59,14 +59,16 @@ module Expressir
59
59
  # Represents a documentation coverage report for EXPRESS schemas
60
60
  class Report
61
61
  attr_reader :repository, :schema_reports, :total_entities, :documented_entities,
62
- :undocumented_entities
62
+ :undocumented_entities, :ignored_files
63
63
 
64
64
  # Initialize a coverage report
65
65
  # @param repository [Expressir::Model::Repository] The repository to analyze
66
66
  # @param skip_types [Array<String>] Array of entity type names to skip from coverage
67
- def initialize(repository, skip_types = [])
67
+ # @param ignored_files [Hash] Hash mapping absolute file paths to their matched patterns
68
+ def initialize(repository, skip_types = [], ignored_files = {})
68
69
  @repository = repository
69
70
  @skip_types = skip_types
71
+ @ignored_files = ignored_files
70
72
  @schema_reports = []
71
73
  @total_entities = []
72
74
  @documented_entities = []
@@ -78,18 +80,20 @@ module Expressir
78
80
  # Create a report from a repository
79
81
  # @param repository [Expressir::Model::Repository] The repository to analyze
80
82
  # @param skip_types [Array<String>] Array of entity type names to skip from coverage
83
+ # @param ignored_files [Hash] Hash mapping absolute file paths to their matched patterns
81
84
  # @return [Report] The coverage report
82
- def self.from_repository(repository, skip_types = [])
83
- new(repository, skip_types)
85
+ def self.from_repository(repository, skip_types = [], ignored_files = {})
86
+ new(repository, skip_types, ignored_files)
84
87
  end
85
88
 
86
89
  # Create a report from a schema file
87
90
  # @param path [String] Path to the schema file
88
91
  # @param skip_types [Array<String>] Array of entity type names to skip from coverage
92
+ # @param ignored_files [Hash] Hash mapping absolute file paths to their matched patterns
89
93
  # @return [Report] The coverage report
90
- def self.from_file(path, skip_types = [])
94
+ def self.from_file(path, skip_types = [], ignored_files = {})
91
95
  repository = Expressir::Express::Parser.from_file(path)
92
- new(repository, skip_types)
96
+ new(repository, skip_types, ignored_files)
93
97
  end
94
98
 
95
99
  # Calculate the overall coverage percentage
@@ -113,6 +117,39 @@ module Expressir
113
117
  absolute_path
114
118
  end
115
119
 
120
+ file_report = {
121
+ "file" => relative_path,
122
+ "file_basename" => File.basename(absolute_path),
123
+ "directory" => File.dirname(absolute_path),
124
+ "total" => report[:total].size,
125
+ "documented" => report[:documented].size,
126
+ "undocumented" => report[:undocumented],
127
+ "coverage" => report[:coverage],
128
+ "ignored" => report[:ignored] || false,
129
+ }
130
+
131
+ # Add matched pattern for ignored files
132
+ if report[:ignored] && report[:matched_pattern]
133
+ file_report["matched_pattern"] = report[:matched_pattern]
134
+ end
135
+
136
+ file_report
137
+ end
138
+ end
139
+
140
+ # Get ignored file reports
141
+ # @return [Array<Hash>] Array of ignored file report hashes
142
+ def ignored_file_reports
143
+ @schema_reports.select { |report| report[:ignored] }.map do |report|
144
+ absolute_path = report[:schema].file
145
+ relative_path = begin
146
+ Pathname.new(absolute_path).relative_path_from(Pathname.pwd).to_s
147
+ rescue ArgumentError
148
+ # If paths are on different drives or otherwise incompatible,
149
+ # fall back to the absolute path
150
+ absolute_path
151
+ end
152
+
116
153
  {
117
154
  "file" => relative_path,
118
155
  "file_basename" => File.basename(absolute_path),
@@ -121,6 +158,7 @@ module Expressir
121
158
  "documented" => report[:documented].size,
122
159
  "undocumented" => report[:undocumented],
123
160
  "coverage" => report[:coverage],
161
+ "matched_pattern" => report[:matched_pattern],
124
162
  }
125
163
  end
126
164
  end
@@ -182,11 +220,14 @@ module Expressir
182
220
  schema_report = process_schema(schema)
183
221
  @schema_reports << schema_report
184
222
 
185
- @total_entities.concat(schema_report[:total])
186
- @documented_entities.concat(schema_report[:documented])
187
- @undocumented_entities.concat(schema_report[:undocumented].map do |entity|
188
- { schema: schema.id, entity: entity }
189
- end)
223
+ # Only include non-ignored files in overall statistics
224
+ unless schema_report[:ignored]
225
+ @total_entities.concat(schema_report[:total])
226
+ @documented_entities.concat(schema_report[:documented])
227
+ @undocumented_entities.concat(schema_report[:undocumented].map do |entity|
228
+ { schema: schema.id, entity: entity }
229
+ end)
230
+ end
190
231
  end
191
232
  end
192
233
 
@@ -200,12 +241,19 @@ module Expressir
200
241
 
201
242
  coverage = entities.empty? ? 100.0 : (documented.size.to_f / entities.size) * 100
202
243
 
244
+ # Check if this schema file is ignored
245
+ schema_file = File.expand_path(schema.file) if schema.file
246
+ ignored = @ignored_files.key?(schema_file)
247
+ matched_pattern = @ignored_files[schema_file] if ignored
248
+
203
249
  {
204
250
  schema: schema,
205
251
  total: entities,
206
252
  documented: documented,
207
253
  undocumented: undocumented.map { |e| format_entity(e) },
208
254
  coverage: coverage,
255
+ ignored: ignored,
256
+ matched_pattern: matched_pattern,
209
257
  }
210
258
  end
211
259
 
@@ -1,3 +1,3 @@
1
1
  module Expressir
2
- VERSION = "2.1.21".freeze
2
+ VERSION = "2.1.22".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: expressir
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.21
4
+ version: 2.1.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.