expressir 2.1.19 → 2.1.20

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: 4b68644d000b4b7d47a7e132922afa9b4e9f1d3fb19ba6c3b9e2a8db28c5fd33
4
- data.tar.gz: 132ecfd9ca85168335536626fea46c3648757ccd973823242b04b0744869376c
3
+ metadata.gz: b0e1c52810ce3b1361d9f8327c0c270ac3a7f366f16d3b3236a0ed3e559155a9
4
+ data.tar.gz: a852899cbf8d6a7747b8609ae7ec00736eddfcfad6a9fd8d410cd453811a4188
5
5
  SHA512:
6
- metadata.gz: 895f018faf2bbdd075991d45fa22061459b918f907e568e4481a98dd2e0eb96a312cb98d96e2e7de381c7c85841d05631119f7c26e1773ac634377cdac8e6fe2
7
- data.tar.gz: 025421a41b6463548b8ac099fe8b5bc94eb21ee58339f77a6ff028c59ebdb1ac27c5f24ea46050d1fa5b84ee5e80802efcb45b0a549bc733ea833f43c48e0e14
6
+ metadata.gz: f8db59aa54a5a1edd29165ec3b79e9e98a35ebd51d8d0184735417c96bbd9d178328ddad2feef11f177bc140bd514913d5581f0c01ba8f9ee25b5a3cdf35a7d2
7
+ data.tar.gz: fef82dcf757767e2a1eea5b252083f0b8f9db85226263f74c7979fde768caa25895df05cca29ac525b799f21ffd19dfd138e26087d3351e0a210b62746bd1867
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-04 17:31:42 UTC using RuboCop version 1.75.2.
3
+ # on 2025-06-05 12:41:11 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
@@ -21,6 +21,12 @@ Layout/LineLength:
21
21
  Exclude:
22
22
  - 'lib/expressir/express/parser.rb'
23
23
 
24
+ # Offense count: 1
25
+ # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
26
+ Lint/DuplicateBranch:
27
+ Exclude:
28
+ - 'lib/expressir/coverage.rb'
29
+
24
30
  # Offense count: 3
25
31
  Lint/ShadowingOuterLocalVariable:
26
32
  Exclude:
@@ -35,7 +41,7 @@ Lint/UnusedMethodArgument:
35
41
  - 'lib/expressir/express/cache.rb'
36
42
  - 'lib/expressir/express/parser.rb'
37
43
 
38
- # Offense count: 71
44
+ # Offense count: 75
39
45
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
40
46
  Metrics/AbcSize:
41
47
  Exclude:
@@ -60,7 +66,7 @@ Metrics/AbcSize:
60
66
  Metrics/BlockLength:
61
67
  Max: 143
62
68
 
63
- # Offense count: 51
69
+ # Offense count: 54
64
70
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
65
71
  Metrics/CyclomaticComplexity:
66
72
  Exclude:
@@ -75,12 +81,12 @@ Metrics/CyclomaticComplexity:
75
81
  - 'lib/expressir/model/model_element.rb'
76
82
  - 'spec/support/model_element_helper.rb'
77
83
 
78
- # Offense count: 94
84
+ # Offense count: 99
79
85
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
80
86
  Metrics/MethodLength:
81
- Max: 50
87
+ Max: 82
82
88
 
83
- # Offense count: 39
89
+ # Offense count: 43
84
90
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
85
91
  Metrics/PerceivedComplexity:
86
92
  Exclude:
@@ -97,6 +103,13 @@ Performance/FixedSize:
97
103
  Exclude:
98
104
  - 'lib/expressir/express/formatter.rb'
99
105
 
106
+ # Offense count: 6
107
+ # This cop supports unsafe autocorrection (--autocorrect-all).
108
+ # Configuration parameters: AllowRegexpMatch.
109
+ Performance/RedundantEqualityComparisonBlock:
110
+ Exclude:
111
+ - 'spec/expressir/coverage_spec.rb'
112
+
100
113
  # Offense count: 1
101
114
  Style/MissingRespondToMissing:
102
115
  Exclude:
data/README.adoc CHANGED
@@ -286,25 +286,154 @@ such as TYPE entities whose descriptions are generated by template strings.
286
286
  # Exclude TYPE entities from coverage analysis
287
287
  expressir coverage --exclude=TYPE schemas/resources/action_schema/action_schema.exp
288
288
 
289
+ # Exclude only SELECT type definitions (useful since TYPE descriptions are often template-generated)
290
+ expressir coverage --exclude=TYPE:SELECT schemas/resources/action_schema/action_schema.exp
291
+
289
292
  # Exclude multiple entity types
290
293
  expressir coverage --exclude=TYPE,CONSTANT,FUNCTION schemas/resources/action_schema/action_schema.exp
291
294
 
295
+ # Exclude parameters and variables (often don't require individual documentation)
296
+ expressir coverage --exclude=PARAMETER,VARIABLE schemas/resources/action_schema/action_schema.exp
297
+
292
298
  # Combine with output format options
293
- expressir coverage --exclude=TYPE --format=json schemas/resources/action_schema/action_schema.exp
299
+ expressir coverage --exclude=TYPE:SELECT --format=json schemas/resources/action_schema/action_schema.exp
300
+ ----
301
+
302
+ ==== Elements checked in documentation coverage
303
+
304
+ Expressir checks documentation coverage for all EXPRESS elements (ModelElement
305
+ subclasses), including:
306
+
307
+ Schema-level entities:
308
+
309
+ `TYPE`:: Type definitions (supports subtype exclusion, see below)
310
+ `ENTITY`:: Entity definitions
311
+ `CONSTANT`:: Constant definitions
312
+ `FUNCTION`:: Function definitions
313
+ `RULE`:: Rule definitions
314
+ `PROCEDURE`:: Procedure definitions
315
+ `SUBTYPE_CONSTRAINT`:: Subtype constraint definitions
316
+ `INTERFACE`:: Interface definitions
317
+
318
+ Nested entities within other constructs:
319
+
320
+ `PARAMETER`:: Function and procedure parameters
321
+ `VARIABLE`:: Variables within functions, rules, and procedures
322
+ `ATTRIBUTE`:: Entity attributes
323
+ `DERIVED_ATTRIBUTE`:: Derived attributes in entities
324
+ `INVERSE_ATTRIBUTE`:: Inverse attributes in entities
325
+ `UNIQUE_RULE`:: Unique rules within entities
326
+ `WHERE_RULE`:: Where rules within entities and types
327
+ `ENUMERATION_ITEM`:: Items within enumeration types
328
+ `INTERFACE_ITEM`:: Items within interfaces
329
+ `INTERFACED_ITEM`:: Interfaced items
330
+ `SCHEMA_VERSION`:: Schema version information
331
+ `SCHEMA_VERSION_ITEM`:: Schema version items
332
+
333
+ ==== TYPE subtype exclusion
334
+
335
+ For TYPE elements, you can exclude specific subtypes using the `TYPE:SUBTYPE`
336
+ syntax:
337
+
338
+ [source, sh]
339
+ ----
340
+ # Exclude only SELECT types
341
+ expressir coverage --exclude=TYPE:SELECT schemas/resources/action_schema/action_schema.exp
342
+
343
+ # Exclude multiple TYPE subtypes
344
+ expressir coverage --exclude=TYPE:SELECT,TYPE:ENUMERATION schemas/resources/action_schema/action_schema.exp
345
+ ----
346
+
347
+ Valid TYPE subtypes that can be excluded:
348
+
349
+ `AGGREGATE`:: Aggregate type
350
+ `ARRAY`:: Array type
351
+ `BAG`:: Bag type
352
+ `BINARY`:: Binary type
353
+ `BOOLEAN`:: Boolean type
354
+ `ENUMERATION`:: Enumeration type
355
+ +
356
+ [example]
357
+ ====
358
+ ----
359
+ TYPE uuid_relationship_role = ENUMERATION OF
360
+ (supersedes,
361
+ merge,
362
+ split,
363
+ derive_from,
364
+ same_as,
365
+ similar_to);
366
+ END_TYPE;
367
+ ----
368
+ ====
369
+
370
+ `GENERIC`:: Generic type
371
+ `GENERIC_ENTITY`:: Generic entity type
372
+ +
373
+ [example]
374
+ ====
294
375
  ----
376
+ TYPE uuid_attribute_select = EXTENSIBLE GENERIC_ENTITY SELECT;
377
+ END_TYPE;
378
+ ----
379
+ ====
380
+
381
+ `INTEGER`:: Integer type
382
+ `LIST`:: List type
383
+ +
384
+ [example]
385
+ ====
386
+ ----
387
+ TYPE uuid_list_item = LIST [1:?] OF UNIQUE LIST [1:?] OF UNIQUE uuid_attribute_select;
388
+ END_TYPE;
389
+ ----
390
+ ====
391
+
392
+ `LOGICAL`:: Logical type
393
+ `NUMBER`:: Number type
394
+ `REAL`:: Real type
395
+ `SELECT`:: Select type
396
+ +
397
+ [example]
398
+ ====
399
+ ----
400
+ TYPE uuid_set_or_list_attribute_select = SELECT
401
+ (uuid_list_item,
402
+ uuid_set_item);
403
+ END_TYPE;
404
+ ----
405
+ ====
406
+
407
+ `SET`:: Set type
408
+ +
409
+ [example]
410
+ ====
411
+ ----
412
+ TYPE uuid_set_item = SET [1:?] OF uuid_attribute_select;
413
+ END_TYPE;
414
+ ----
415
+ ====
416
+
417
+ `STRING`::
418
+ String type
419
+ +
420
+ [example]
421
+ ====
422
+ ----
423
+ TYPE uuid = STRING (36) FIXED;
424
+ END_TYPE;
425
+ ----
426
+ ====
295
427
 
296
- Valid entity types that can be excluded:
428
+ This is particularly useful since TYPE entities with certain subtypes (like
429
+ SELECT) often have descriptions generated by template strings and may not
430
+ require individual remark item coverage.
297
431
 
298
- * `TYPE` - Type definitions
299
- * `ENTITY` - Entity definitions
300
- * `CONSTANT` - Constant definitions
301
- * `FUNCTION` - Function definitions
302
- * `RULE` - Rule definitions
303
- * `PROCEDURE` - Procedure definitions
304
- * `SUBTYPE_CONSTRAINT` - Subtype constraint definitions
432
+ NOTE: ISO 10303 excludes documentation coverage for TYPE:SELECT and
433
+ TYPE:ENUMERATION.
305
434
 
306
- If you specify an invalid entity type, the command will display an error message
307
- with the list of valid types.
435
+ If you specify an invalid entity type or subtype, the command will display an
436
+ error message with the list of valid options.
308
437
 
309
438
  .Example with JSON output:
310
439
  [example]
data/expressir.gemspec CHANGED
@@ -42,5 +42,4 @@ Gem::Specification.new do |spec|
42
42
  spec.add_dependency "ruby-progressbar", "~> 1.11"
43
43
  spec.add_dependency "terminal-table", "~> 3.0"
44
44
  spec.add_dependency "thor", "~> 1.0"
45
- spec.add_dependency "zeitwerk", "~> 2.6"
46
45
  end
data/lib/expressir/cli.rb CHANGED
@@ -55,7 +55,8 @@ module Expressir
55
55
 
56
56
  desc "coverage *PATH", "List EXPRESS entities and check documentation coverage"
57
57
  method_option :format, type: :string, desc: "Output format (text, json, yaml)", default: "text"
58
- method_option :exclude, type: :string, desc: "Comma-separated list of EXPRESS entity types to skip from coverage (e.g., TYPE,CONSTANT)"
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
+ method_option :output, type: :string, desc: "Output file path for JSON/YAML formats (defaults to coverage_report.json/yaml)"
59
60
  def coverage(*paths)
60
61
  Commands::Coverage.new(options).run(paths)
61
62
  end
@@ -275,33 +275,68 @@ module Expressir
275
275
  end
276
276
 
277
277
  def display_json_output(reports)
278
- say JSON.pretty_generate(build_structured_report(reports))
278
+ output_file = options[:output] || "coverage_report.json"
279
+ File.write(output_file, JSON.pretty_generate(build_structured_report(reports)))
280
+ say "JSON coverage report written to: #{output_file}"
279
281
  end
280
282
 
281
283
  def display_yaml_output(reports)
282
- say build_structured_report(reports).to_yaml
284
+ output_file = options[:output] || "coverage_report.yaml"
285
+ File.write(output_file, build_structured_report(reports).to_yaml)
286
+ say "YAML coverage report written to: #{output_file}"
283
287
  end
284
288
 
285
289
  # Parse and validate the skip_types option
286
290
  # @return [Array<String>] Array of validated entity type names
287
291
  def parse_skip_types
288
- skip_types_option = options["exclude"]
292
+ skip_types_option = options["exclude"] || options[:exclude]
289
293
  return [] unless skip_types_option
290
294
 
291
- # Split by comma and clean up whitespace
292
- requested_types = skip_types_option.split(",").map(&:strip).map(&:upcase)
295
+ # Handle both string (comma-separated) and array inputs
296
+ requested_types = if skip_types_option.is_a?(Array)
297
+ skip_types_option.map(&:to_s).map(&:strip).map(&:upcase)
298
+ else
299
+ skip_types_option.split(",").map(&:strip).map(&:upcase)
300
+ end
293
301
 
294
- # Validate against known entity types
295
- valid_types = Expressir::Coverage::ENTITY_TYPE_MAP.keys
296
- invalid_types = requested_types - valid_types
297
-
298
- unless invalid_types.empty?
299
- exit_with_error "Invalid entity types: #{invalid_types.join(', ')}. " \
300
- "Valid types are: #{valid_types.join(', ')}"
302
+ # Validate each type (supports both TYPE and TYPE:SUBTYPE formats)
303
+ requested_types.each do |type|
304
+ validate_skip_type(type)
301
305
  end
302
306
 
303
307
  requested_types
304
308
  end
309
+
310
+ # Validate a single skip type (supports TYPE:SUBTYPE syntax)
311
+ # @param type [String] The type to validate
312
+ def validate_skip_type(type)
313
+ if type.include?(":")
314
+ # Handle TYPE:SUBTYPE format
315
+ main_type, subtype = type.split(":", 2)
316
+
317
+ # Validate main type
318
+ unless Expressir::Coverage::ENTITY_TYPE_MAP.key?(main_type)
319
+ exit_with_error "Invalid entity type: #{main_type}. " \
320
+ "Valid types are: #{Expressir::Coverage::ENTITY_TYPE_MAP.keys.join(', ')}"
321
+ end
322
+
323
+ # For TYPE, validate subtype
324
+ if main_type == "TYPE"
325
+ unless Expressir::Coverage::TYPE_SUBTYPES.include?(subtype)
326
+ exit_with_error "Invalid TYPE subtype: #{subtype}. " \
327
+ "Valid TYPE subtypes are: #{Expressir::Coverage::TYPE_SUBTYPES.join(', ')}"
328
+ end
329
+ else
330
+ exit_with_error "Subtype syntax (#{type}) is only supported for TYPE entities"
331
+ end
332
+ else
333
+ # Handle simple type format
334
+ unless Expressir::Coverage::ENTITY_TYPE_MAP.key?(type)
335
+ exit_with_error "Invalid entity type: #{type}. " \
336
+ "Valid types are: #{Expressir::Coverage::ENTITY_TYPE_MAP.keys.join(', ')}"
337
+ end
338
+ end
339
+ end
305
340
  end
306
341
  end
307
342
  end
@@ -12,7 +12,50 @@ module Expressir
12
12
  "RULE" => "Expressir::Model::Declarations::Rule",
13
13
  "PROCEDURE" => "Expressir::Model::Declarations::Procedure",
14
14
  "SUBTYPE_CONSTRAINT" => "Expressir::Model::Declarations::SubtypeConstraint",
15
+ "PARAMETER" => "Expressir::Model::Declarations::Parameter",
16
+ "VARIABLE" => "Expressir::Model::Declarations::Variable",
17
+ "ATTRIBUTE" => "Expressir::Model::Declarations::Attribute",
18
+ "DERIVED_ATTRIBUTE" => "Expressir::Model::Declarations::DerivedAttribute",
19
+ "INVERSE_ATTRIBUTE" => "Expressir::Model::Declarations::InverseAttribute",
20
+ "UNIQUE_RULE" => "Expressir::Model::Declarations::UniqueRule",
21
+ "WHERE_RULE" => "Expressir::Model::Declarations::WhereRule",
22
+ "ENUMERATION_ITEM" => "Expressir::Model::DataTypes::EnumerationItem",
23
+ "INTERFACE" => "Expressir::Model::Declarations::Interface",
24
+ "INTERFACE_ITEM" => "Expressir::Model::Declarations::InterfaceItem",
25
+ "INTERFACED_ITEM" => "Expressir::Model::Declarations::InterfacedItem",
26
+ "SCHEMA_VERSION" => "Expressir::Model::Declarations::SchemaVersion",
27
+ "SCHEMA_VERSION_ITEM" => "Expressir::Model::Declarations::SchemaVersionItem",
15
28
  }.freeze
29
+
30
+ # Mapping of class names to EXPRESS entity type names (for proper formatting)
31
+ CLASS_TO_EXPRESS_TYPE_MAP = {
32
+ "Type" => "TYPE",
33
+ "Entity" => "ENTITY",
34
+ "Constant" => "CONSTANT",
35
+ "Function" => "FUNCTION",
36
+ "Rule" => "RULE",
37
+ "Procedure" => "PROCEDURE",
38
+ "SubtypeConstraint" => "SUBTYPE_CONSTRAINT",
39
+ "Parameter" => "PARAMETER",
40
+ "Variable" => "VARIABLE",
41
+ "Attribute" => "ATTRIBUTE",
42
+ "DerivedAttribute" => "DERIVED_ATTRIBUTE",
43
+ "InverseAttribute" => "INVERSE_ATTRIBUTE",
44
+ "UniqueRule" => "UNIQUE_RULE",
45
+ "WhereRule" => "WHERE_RULE",
46
+ "EnumerationItem" => "ENUMERATION_ITEM",
47
+ "Interface" => "INTERFACE",
48
+ "InterfaceItem" => "INTERFACE_ITEM",
49
+ "InterfacedItem" => "INTERFACED_ITEM",
50
+ "SchemaVersion" => "SCHEMA_VERSION",
51
+ "SchemaVersionItem" => "SCHEMA_VERSION_ITEM",
52
+ }.freeze
53
+
54
+ # Available TYPE subtypes based on data types
55
+ TYPE_SUBTYPES = %w[
56
+ AGGREGATE ARRAY BAG BINARY BOOLEAN ENUMERATION GENERIC GENERIC_ENTITY
57
+ INTEGER LIST LOGICAL NUMBER REAL SELECT SET STRING
58
+ ].freeze
16
59
  # Represents a documentation coverage report for EXPRESS schemas
17
60
  class Report
18
61
  attr_reader :repository, :schema_reports, :total_entities, :documented_entities,
@@ -173,8 +216,8 @@ module Expressir
173
216
  # Get class name (e.g., "Type" from "Expressir::Model::Declarations::Type")
174
217
  type_name = entity.class.name.split("::").last
175
218
 
176
- # Convert to EXPRESS convention (e.g., "TYPE")
177
- express_type = type_name.upcase
219
+ # Use proper mapping to EXPRESS convention
220
+ express_type = CLASS_TO_EXPRESS_TYPE_MAP[type_name] || type_name.upcase
178
221
 
179
222
  # Return structured format
180
223
  {
@@ -209,11 +252,35 @@ module Expressir
209
252
  end
210
253
  end
211
254
 
212
- # Find all entities in a schema
213
- # @param schema [Expressir::Model::Declarations::Schema] The schema to analyze
255
+ # Find all entities in a schema or repository
256
+ # @param schema_or_repo [Expressir::Model::Declarations::Schema, Expressir::Model::Repository] The schema or repository to analyze
214
257
  # @param skip_types [Array<String>] Array of entity type names to skip from coverage
215
258
  # @return [Array<Expressir::Model::ModelElement>] Array of entities
216
- def self.find_entities(schema, skip_types = [])
259
+ def self.find_entities(schema_or_repo, skip_types = [])
260
+ entities = []
261
+
262
+ # Handle both repository and schema inputs
263
+ if schema_or_repo.is_a?(Expressir::Model::Repository)
264
+ # If it's a repository, process all schemas
265
+ schema_or_repo.schemas.each do |schema|
266
+ entities.concat(find_entities_in_schema(schema))
267
+ end
268
+ else
269
+ # If it's a schema, process it directly
270
+ entities.concat(find_entities_in_schema(schema_or_repo))
271
+ end
272
+
273
+ # Filter out any nil elements and ensure all have IDs
274
+ entities = entities.compact.select { |e| e.respond_to?(:id) && e.id }
275
+
276
+ # Filter out skipped entity types
277
+ apply_exclusions(entities, skip_types)
278
+ end
279
+
280
+ # Find all entities in a single schema
281
+ # @param schema [Expressir::Model::Declarations::Schema] The schema to analyze
282
+ # @return [Array<Expressir::Model::ModelElement>] Array of entities
283
+ def self.find_entities_in_schema(schema)
217
284
  entities = []
218
285
 
219
286
  # Add all schema-level entities
@@ -224,26 +291,184 @@ module Expressir
224
291
  entities.concat(schema.rules) if schema.rules
225
292
  entities.concat(schema.procedures) if schema.procedures
226
293
  entities.concat(schema.subtype_constraints) if schema.subtype_constraints
294
+ entities.concat(schema.interfaces) if schema.interfaces
227
295
 
228
- # Add enumeration items from types (only if TYPE is not being skipped)
229
- unless skip_types.include?("TYPE")
230
- schema.types&.each do |type|
231
- if type.respond_to?(:enumeration_items) && type.enumeration_items
232
- entities.concat(type.enumeration_items)
233
- end
296
+ # Add nested entities recursively
297
+ entities.concat(find_nested_entities(schema))
298
+
299
+ entities
300
+ end
301
+
302
+ # Find all nested entities within a container (schema, entity, function, etc.)
303
+ # @param container [Expressir::Model::ModelElement] The container to search
304
+ # @return [Array<Expressir::Model::ModelElement>] Array of nested entities
305
+ def self.find_nested_entities(container)
306
+ entities = []
307
+
308
+ # Handle different container types
309
+ case container
310
+ when Expressir::Model::Declarations::Schema
311
+ # Schema-level nested entities
312
+ container.types&.each do |type|
313
+ entities.concat(find_nested_entities(type))
314
+ end
315
+ container.entities&.each do |entity|
316
+ entities.concat(find_nested_entities(entity))
317
+ end
318
+ container.functions&.each do |function|
319
+ entities.concat(find_nested_entities(function))
320
+ end
321
+ container.rules&.each do |rule|
322
+ entities.concat(find_nested_entities(rule))
323
+ end
324
+ container.procedures&.each do |procedure|
325
+ entities.concat(find_nested_entities(procedure))
326
+ end
327
+ container.interfaces&.each do |interface|
328
+ entities.concat(find_nested_entities(interface))
234
329
  end
235
- end
236
330
 
237
- # Filter out any nil elements and ensure all have IDs
238
- entities = entities.compact.select { |e| e.respond_to?(:id) && e.id }
331
+ when Expressir::Model::Declarations::Type
332
+ # Type nested entities
333
+ if container.respond_to?(:enumeration_items) && container.enumeration_items
334
+ entities.concat(container.enumeration_items)
335
+ end
239
336
 
240
- # Filter out skipped entity types
241
- if skip_types.any?
242
- skip_classes = skip_types.map { |type| ENTITY_TYPE_MAP[type] }.compact
243
- entities = entities.reject { |entity| skip_classes.include?(entity.class.name) }
337
+ when Expressir::Model::Declarations::Entity
338
+ # Entity nested entities
339
+ entities.concat(container.attributes) if container.attributes
340
+ entities.concat(container.unique_rules) if container.unique_rules
341
+ entities.concat(container.where_rules) if container.where_rules
342
+
343
+ when Expressir::Model::Declarations::Function
344
+ # Function nested entities
345
+ entities.concat(container.parameters) if container.parameters
346
+ entities.concat(container.variables) if container.variables
347
+ entities.concat(container.constants) if container.constants
348
+ entities.concat(container.types) if container.types
349
+ entities.concat(container.entities) if container.entities
350
+ entities.concat(container.functions) if container.functions
351
+ entities.concat(container.procedures) if container.procedures
352
+ entities.concat(container.subtype_constraints) if container.subtype_constraints
353
+
354
+ # Recursively find nested entities in nested containers
355
+ container.types&.each { |type| entities.concat(find_nested_entities(type)) }
356
+ container.entities&.each { |entity| entities.concat(find_nested_entities(entity)) }
357
+ container.functions&.each { |function| entities.concat(find_nested_entities(function)) }
358
+ container.procedures&.each { |procedure| entities.concat(find_nested_entities(procedure)) }
359
+
360
+ when Expressir::Model::Declarations::Rule
361
+ # Rule nested entities
362
+ entities.concat(container.variables) if container.variables
363
+ entities.concat(container.constants) if container.constants
364
+ entities.concat(container.types) if container.types
365
+ entities.concat(container.entities) if container.entities
366
+ entities.concat(container.functions) if container.functions
367
+ entities.concat(container.procedures) if container.procedures
368
+ entities.concat(container.subtype_constraints) if container.subtype_constraints
369
+
370
+ # Recursively find nested entities in nested containers
371
+ container.types&.each { |type| entities.concat(find_nested_entities(type)) }
372
+ container.entities&.each { |entity| entities.concat(find_nested_entities(entity)) }
373
+ container.functions&.each { |function| entities.concat(find_nested_entities(function)) }
374
+ container.procedures&.each { |procedure| entities.concat(find_nested_entities(procedure)) }
375
+
376
+ when Expressir::Model::Declarations::Procedure
377
+ # Procedure nested entities
378
+ entities.concat(container.parameters) if container.parameters
379
+ entities.concat(container.variables) if container.variables
380
+ entities.concat(container.constants) if container.constants
381
+ entities.concat(container.types) if container.types
382
+ entities.concat(container.entities) if container.entities
383
+ entities.concat(container.functions) if container.functions
384
+ entities.concat(container.procedures) if container.procedures
385
+ entities.concat(container.subtype_constraints) if container.subtype_constraints
386
+
387
+ # Recursively find nested entities in nested containers
388
+ container.types&.each { |type| entities.concat(find_nested_entities(type)) }
389
+ container.entities&.each { |entity| entities.concat(find_nested_entities(entity)) }
390
+ container.functions&.each { |function| entities.concat(find_nested_entities(function)) }
391
+ container.procedures&.each { |procedure| entities.concat(find_nested_entities(procedure)) }
392
+
393
+ when Expressir::Model::Declarations::Interface
394
+ # Interface nested entities
395
+ entities.concat(container.items) if container.items
244
396
  end
245
397
 
246
398
  entities
247
399
  end
400
+
401
+ # Apply exclusions to filter out entities based on skip_types (supports both simple and TYPE:SUBTYPE syntax)
402
+ # @param entities [Array<Expressir::Model::ModelElement>] The entities to filter
403
+ # @param exclusions [Array<String>] Array of entity type names to exclude from coverage
404
+ # @return [Array<Expressir::Model::ModelElement>] Filtered entities
405
+ def self.apply_exclusions(entities, exclusions)
406
+ filter_skipped_entities(entities, exclusions)
407
+ end
408
+
409
+ # Filter out entities based on skip_types (supports both simple and TYPE:SUBTYPE syntax)
410
+ # @param entities [Array<Expressir::Model::ModelElement>] The entities to filter
411
+ # @param skip_types [Array<String>] Array of entity type names to skip from coverage
412
+ # @return [Array<Expressir::Model::ModelElement>] Filtered entities
413
+ def self.filter_skipped_entities(entities, skip_types)
414
+ return entities if skip_types.empty?
415
+
416
+ # Parse skip_types into simple types and TYPE subtypes
417
+ simple_skips = []
418
+ type_subtype_skips = []
419
+
420
+ skip_types.each do |skip_type|
421
+ if skip_type.include?(":")
422
+ # Handle TYPE:SUBTYPE format
423
+ main_type, subtype = skip_type.split(":", 2)
424
+ if main_type == "TYPE" && TYPE_SUBTYPES.include?(subtype)
425
+ type_subtype_skips << subtype
426
+ end
427
+ else
428
+ # Handle simple type format
429
+ simple_skips << skip_type
430
+ end
431
+ end
432
+
433
+ # Filter entities
434
+ entities.reject do |entity|
435
+ entity_class = entity.class.name
436
+
437
+ # Check simple type exclusions
438
+ # Convert entity class to EXPRESS type name for comparison
439
+ class_name = entity_class.split("::").last
440
+ express_type = CLASS_TO_EXPRESS_TYPE_MAP[class_name] || class_name.upcase
441
+
442
+ if simple_skips.include?(express_type)
443
+ true
444
+ # Check TYPE subtype exclusions
445
+ elsif entity_class == "Expressir::Model::Declarations::Type" && type_subtype_skips.any?
446
+ entity_subtype = get_type_subtype(entity)
447
+ type_subtype_skips.include?(entity_subtype)
448
+ else
449
+ false
450
+ end
451
+ end
452
+ end
453
+
454
+ # Get the subtype of a TYPE entity based on its underlying_type
455
+ # @param type_entity [Expressir::Model::Declarations::Type] The TYPE entity
456
+ # @return [String] The subtype name (e.g., "SELECT", "ENUMERATION")
457
+ def self.get_type_subtype(type_entity)
458
+ return nil unless type_entity.respond_to?(:underlying_type) && type_entity.underlying_type
459
+
460
+ # Get the class name of the underlying type
461
+ underlying_class = type_entity.underlying_type.class.name
462
+
463
+ # Extract the data type name (e.g., "Select" from "Expressir::Model::DataTypes::Select")
464
+ if underlying_class.start_with?("Expressir::Model::DataTypes::")
465
+ data_type_name = underlying_class.split("::").last
466
+ # Convert to uppercase (e.g., "Select" -> "SELECT")
467
+ data_type_name.upcase
468
+ else
469
+ # For other types, try to extract the last part of the class name
470
+ underlying_class.split("::").last&.upcase
471
+ end
472
+ end
248
473
  end
249
474
  end
@@ -1,72 +1,95 @@
1
- require_relative "model/model_element"
2
- require_relative "model/cache"
3
- require_relative "model/identifier"
4
- require_relative "model/repository"
1
+ # This file is kept for backward compatibility and to ensure all model classes are loaded
2
+ # when explicitly requiring 'expressir/model'. The actual autoload definitions are in the main
3
+ # expressir.rb file.
5
4
 
6
- require_relative "model/data_types/aggregate"
7
- require_relative "model/data_types/array"
8
- require_relative "model/data_types/bag"
9
- require_relative "model/data_types/binary"
10
- require_relative "model/data_types/boolean"
11
- require_relative "model/data_types/enumeration"
12
- require_relative "model/data_types/enumeration_item"
13
- require_relative "model/data_types/generic_entity"
14
- require_relative "model/data_types/generic"
15
- require_relative "model/data_types/integer"
16
- require_relative "model/data_types/list"
17
- require_relative "model/data_types/logical"
18
- require_relative "model/data_types/number"
19
- require_relative "model/data_types/real"
20
- require_relative "model/data_types/set"
21
- require_relative "model/data_types/select"
22
- require_relative "model/data_types/string"
23
- require_relative "model/declarations/attribute"
24
- require_relative "model/declarations/constant"
25
- require_relative "model/declarations/entity"
26
- require_relative "model/declarations/function"
27
- require_relative "model/declarations/interface"
28
- require_relative "model/declarations/interface_item"
29
- require_relative "model/declarations/interfaced_item"
30
- require_relative "model/declarations/parameter"
31
- require_relative "model/declarations/procedure"
32
- require_relative "model/declarations/remark_item"
33
- require_relative "model/declarations/rule"
34
- require_relative "model/declarations/schema"
35
- require_relative "model/declarations/schema_version"
36
- require_relative "model/declarations/schema_version_item"
37
- require_relative "model/declarations/subtype_constraint"
38
- require_relative "model/declarations/type"
39
- require_relative "model/declarations/unique_rule"
40
- require_relative "model/declarations/variable"
41
- require_relative "model/declarations/where_rule"
42
- require_relative "model/expressions/aggregate_initializer"
43
- require_relative "model/expressions/aggregate_initializer_item"
44
- require_relative "model/expressions/binary_expression"
45
- require_relative "model/expressions/entity_constructor"
46
- require_relative "model/expressions/function_call"
47
- require_relative "model/expressions/interval"
48
- require_relative "model/expressions/query_expression"
49
- require_relative "model/expressions/unary_expression"
50
- require_relative "model/literals/binary"
51
- require_relative "model/literals/integer"
52
- require_relative "model/literals/logical"
53
- require_relative "model/literals/real"
54
- require_relative "model/literals/string"
55
- require_relative "model/references/attribute_reference"
56
- require_relative "model/references/group_reference"
57
- require_relative "model/references/index_reference"
58
- require_relative "model/references/simple_reference"
59
- require_relative "model/statements/alias"
60
- require_relative "model/statements/assignment"
61
- require_relative "model/statements/case"
62
- require_relative "model/statements/case_action"
63
- require_relative "model/statements/compound"
64
- require_relative "model/statements/escape"
65
- require_relative "model/statements/if"
66
- require_relative "model/statements/null"
67
- require_relative "model/statements/procedure_call"
68
- require_relative "model/statements/repeat"
69
- require_relative "model/statements/return"
70
- require_relative "model/statements/skip"
71
- require_relative "model/supertype_expressions/binary_supertype_expression"
72
- require_relative "model/supertype_expressions/oneof_supertype_expression"
5
+ # Ensure all model classes are loaded by referencing them
6
+ # This triggers the autoload mechanism for each class
7
+
8
+ # Core model classes
9
+ Expressir::Model::ModelElement
10
+ Expressir::Model::Cache
11
+ Expressir::Model::Identifier
12
+ Expressir::Model::Repository
13
+
14
+ # Data types
15
+ Expressir::Model::DataTypes::Aggregate
16
+ Expressir::Model::DataTypes::Array
17
+ Expressir::Model::DataTypes::Bag
18
+ Expressir::Model::DataTypes::Binary
19
+ Expressir::Model::DataTypes::Boolean
20
+ Expressir::Model::DataTypes::Enumeration
21
+ Expressir::Model::DataTypes::EnumerationItem
22
+ Expressir::Model::DataTypes::GenericEntity
23
+ Expressir::Model::DataTypes::Generic
24
+ Expressir::Model::DataTypes::Integer
25
+ Expressir::Model::DataTypes::List
26
+ Expressir::Model::DataTypes::Logical
27
+ Expressir::Model::DataTypes::Number
28
+ Expressir::Model::DataTypes::Real
29
+ Expressir::Model::DataTypes::Select
30
+ Expressir::Model::DataTypes::Set
31
+ Expressir::Model::DataTypes::String
32
+
33
+ # Declarations
34
+ Expressir::Model::Declarations::Attribute
35
+ Expressir::Model::Declarations::Constant
36
+ Expressir::Model::Declarations::DerivedAttribute
37
+ Expressir::Model::Declarations::Entity
38
+ Expressir::Model::Declarations::Function
39
+ Expressir::Model::Declarations::Interface
40
+ Expressir::Model::Declarations::InterfaceItem
41
+ Expressir::Model::Declarations::InterfacedItem
42
+ Expressir::Model::Declarations::InverseAttribute
43
+ Expressir::Model::Declarations::Parameter
44
+ Expressir::Model::Declarations::Procedure
45
+ Expressir::Model::Declarations::RemarkItem
46
+ Expressir::Model::Declarations::Rule
47
+ Expressir::Model::Declarations::Schema
48
+ Expressir::Model::Declarations::SchemaVersion
49
+ Expressir::Model::Declarations::SchemaVersionItem
50
+ Expressir::Model::Declarations::SubtypeConstraint
51
+ Expressir::Model::Declarations::Type
52
+ Expressir::Model::Declarations::UniqueRule
53
+ Expressir::Model::Declarations::Variable
54
+ Expressir::Model::Declarations::WhereRule
55
+
56
+ # Expressions
57
+ Expressir::Model::Expressions::AggregateInitializer
58
+ Expressir::Model::Expressions::AggregateInitializerItem
59
+ Expressir::Model::Expressions::BinaryExpression
60
+ Expressir::Model::Expressions::EntityConstructor
61
+ Expressir::Model::Expressions::FunctionCall
62
+ Expressir::Model::Expressions::Interval
63
+ Expressir::Model::Expressions::QueryExpression
64
+ Expressir::Model::Expressions::UnaryExpression
65
+
66
+ # Literals
67
+ Expressir::Model::Literals::Binary
68
+ Expressir::Model::Literals::Integer
69
+ Expressir::Model::Literals::Logical
70
+ Expressir::Model::Literals::Real
71
+ Expressir::Model::Literals::String
72
+
73
+ # References
74
+ Expressir::Model::References::AttributeReference
75
+ Expressir::Model::References::GroupReference
76
+ Expressir::Model::References::IndexReference
77
+ Expressir::Model::References::SimpleReference
78
+
79
+ # Statements
80
+ Expressir::Model::Statements::Alias
81
+ Expressir::Model::Statements::Assignment
82
+ Expressir::Model::Statements::Case
83
+ Expressir::Model::Statements::CaseAction
84
+ Expressir::Model::Statements::Compound
85
+ Expressir::Model::Statements::Escape
86
+ Expressir::Model::Statements::If
87
+ Expressir::Model::Statements::Null
88
+ Expressir::Model::Statements::ProcedureCall
89
+ Expressir::Model::Statements::Repeat
90
+ Expressir::Model::Statements::Return
91
+ Expressir::Model::Statements::Skip
92
+
93
+ # Supertype expressions
94
+ Expressir::Model::SupertypeExpressions::BinarySupertypeExpression
95
+ Expressir::Model::SupertypeExpressions::OneofSupertypeExpression
@@ -1,3 +1,3 @@
1
1
  module Expressir
2
- VERSION = "2.1.19".freeze
2
+ VERSION = "2.1.20".freeze
3
3
  end
data/lib/expressir.rb CHANGED
@@ -1,4 +1,3 @@
1
- require "zeitwerk"
2
1
  require_relative "expressir/version"
3
2
  require_relative "expressir/cli"
4
3
  require_relative "expressir/config"
@@ -36,13 +35,129 @@ module Expressir
36
35
  def self.root_path
37
36
  @root_path ||= Pathname.new(Expressir.root)
38
37
  end
39
- end
40
38
 
41
- loader = Zeitwerk::Loader.for_gem
42
- loader.setup
39
+ # Autoload for Express module classes
40
+ module Express
41
+ autoload :Cache, "expressir/express/cache"
42
+ autoload :Error, "expressir/express/error"
43
+ autoload :Formatter, "expressir/express/formatter"
44
+ autoload :HyperlinkFormatter, "expressir/express/hyperlink_formatter"
45
+ autoload :ModelVisitor, "expressir/express/model_visitor"
46
+ autoload :Parser, "expressir/express/parser"
47
+ autoload :ResolveReferencesModelVisitor, "expressir/express/resolve_references_model_visitor"
48
+ autoload :SchemaHeadFormatter, "expressir/express/schema_head_formatter"
49
+ autoload :Visitor, "expressir/express/visitor"
50
+ end
51
+
52
+ # Autoload for Model module classes
53
+ module Model
54
+ autoload :ModelElement, "expressir/model/model_element"
55
+ autoload :Cache, "expressir/model/cache"
56
+ autoload :Identifier, "expressir/model/identifier"
57
+ autoload :Repository, "expressir/model/repository"
58
+
59
+ module DataTypes
60
+ autoload :Aggregate, "expressir/model/data_types/aggregate"
61
+ autoload :Array, "expressir/model/data_types/array"
62
+ autoload :Bag, "expressir/model/data_types/bag"
63
+ autoload :Binary, "expressir/model/data_types/binary"
64
+ autoload :Boolean, "expressir/model/data_types/boolean"
65
+ autoload :Enumeration, "expressir/model/data_types/enumeration"
66
+ autoload :EnumerationItem, "expressir/model/data_types/enumeration_item"
67
+ autoload :GenericEntity, "expressir/model/data_types/generic_entity"
68
+ autoload :Generic, "expressir/model/data_types/generic"
69
+ autoload :Integer, "expressir/model/data_types/integer"
70
+ autoload :List, "expressir/model/data_types/list"
71
+ autoload :Logical, "expressir/model/data_types/logical"
72
+ autoload :Number, "expressir/model/data_types/number"
73
+ autoload :Real, "expressir/model/data_types/real"
74
+ autoload :Select, "expressir/model/data_types/select"
75
+ autoload :Set, "expressir/model/data_types/set"
76
+ autoload :String, "expressir/model/data_types/string"
77
+ end
78
+
79
+ module Declarations
80
+ autoload :Attribute, "expressir/model/declarations/attribute"
81
+ autoload :Constant, "expressir/model/declarations/constant"
82
+ autoload :DerivedAttribute, "expressir/model/declarations/derived_attribute"
83
+ autoload :Entity, "expressir/model/declarations/entity"
84
+ autoload :Function, "expressir/model/declarations/function"
85
+ autoload :Interface, "expressir/model/declarations/interface"
86
+ autoload :InterfaceItem, "expressir/model/declarations/interface_item"
87
+ autoload :InterfacedItem, "expressir/model/declarations/interfaced_item"
88
+ autoload :InverseAttribute, "expressir/model/declarations/inverse_attribute"
89
+ autoload :Parameter, "expressir/model/declarations/parameter"
90
+ autoload :Procedure, "expressir/model/declarations/procedure"
91
+ autoload :RemarkItem, "expressir/model/declarations/remark_item"
92
+ autoload :Rule, "expressir/model/declarations/rule"
93
+ autoload :Schema, "expressir/model/declarations/schema"
94
+ autoload :SchemaVersion, "expressir/model/declarations/schema_version"
95
+ autoload :SchemaVersionItem, "expressir/model/declarations/schema_version_item"
96
+ autoload :SubtypeConstraint, "expressir/model/declarations/subtype_constraint"
97
+ autoload :Type, "expressir/model/declarations/type"
98
+ autoload :UniqueRule, "expressir/model/declarations/unique_rule"
99
+ autoload :Variable, "expressir/model/declarations/variable"
100
+ autoload :WhereRule, "expressir/model/declarations/where_rule"
101
+ end
43
102
 
44
- Dir[File.join(__dir__, "expressir", "express", "*.rb")].sort.each do |fea|
45
- require fea
103
+ module Expressions
104
+ autoload :AggregateInitializer, "expressir/model/expressions/aggregate_initializer"
105
+ autoload :AggregateInitializerItem, "expressir/model/expressions/aggregate_initializer_item"
106
+ autoload :BinaryExpression, "expressir/model/expressions/binary_expression"
107
+ autoload :EntityConstructor, "expressir/model/expressions/entity_constructor"
108
+ autoload :FunctionCall, "expressir/model/expressions/function_call"
109
+ autoload :Interval, "expressir/model/expressions/interval"
110
+ autoload :QueryExpression, "expressir/model/expressions/query_expression"
111
+ autoload :UnaryExpression, "expressir/model/expressions/unary_expression"
112
+ end
113
+
114
+ module Literals
115
+ autoload :Binary, "expressir/model/literals/binary"
116
+ autoload :Integer, "expressir/model/literals/integer"
117
+ autoload :Logical, "expressir/model/literals/logical"
118
+ autoload :Real, "expressir/model/literals/real"
119
+ autoload :String, "expressir/model/literals/string"
120
+ end
121
+
122
+ module References
123
+ autoload :AttributeReference, "expressir/model/references/attribute_reference"
124
+ autoload :GroupReference, "expressir/model/references/group_reference"
125
+ autoload :IndexReference, "expressir/model/references/index_reference"
126
+ autoload :SimpleReference, "expressir/model/references/simple_reference"
127
+ end
128
+
129
+ module Statements
130
+ autoload :Alias, "expressir/model/statements/alias"
131
+ autoload :Assignment, "expressir/model/statements/assignment"
132
+ autoload :Case, "expressir/model/statements/case"
133
+ autoload :CaseAction, "expressir/model/statements/case_action"
134
+ autoload :Compound, "expressir/model/statements/compound"
135
+ autoload :Escape, "expressir/model/statements/escape"
136
+ autoload :If, "expressir/model/statements/if"
137
+ autoload :Null, "expressir/model/statements/null"
138
+ autoload :ProcedureCall, "expressir/model/statements/procedure_call"
139
+ autoload :Repeat, "expressir/model/statements/repeat"
140
+ autoload :Return, "expressir/model/statements/return"
141
+ autoload :Skip, "expressir/model/statements/skip"
142
+ end
143
+
144
+ module SupertypeExpressions
145
+ autoload :BinarySupertypeExpression, "expressir/model/supertype_expressions/binary_supertype_expression"
146
+ autoload :OneofSupertypeExpression, "expressir/model/supertype_expressions/oneof_supertype_expression"
147
+ end
148
+ end
149
+
150
+ # Autoload for Commands module classes
151
+ module Commands
152
+ autoload :Base, "expressir/commands/base"
153
+ autoload :Benchmark, "expressir/commands/benchmark"
154
+ autoload :BenchmarkCache, "expressir/commands/benchmark_cache"
155
+ autoload :Clean, "expressir/commands/clean"
156
+ autoload :Coverage, "expressir/commands/coverage"
157
+ autoload :Format, "expressir/commands/format"
158
+ autoload :Validate, "expressir/commands/validate"
159
+ autoload :Version, "expressir/commands/version"
160
+ end
46
161
  end
47
162
 
48
163
  require_relative "expressir/model"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: expressir
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.19
4
+ version: 2.1.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-06-04 00:00:00.000000000 Z
11
+ date: 2025-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -136,20 +136,6 @@ dependencies:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: '1.0'
139
- - !ruby/object:Gem::Dependency
140
- name: zeitwerk
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '2.6'
146
- type: :runtime
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '2.6'
153
139
  description: Expressir ("EXPRESS in Ruby") is a Ruby parser for EXPRESS and a set
154
140
  of tools for accessing EXPRESS data models.
155
141
  email: