modspec 0.1.4 → 0.2.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +4 -0
  3. data/.github/workflows/release.yml +5 -0
  4. data/.rubocop.yml +16 -7
  5. data/.rubocop_todo.yml +67 -80
  6. data/CLAUDE.md +61 -0
  7. data/Gemfile +4 -3
  8. data/lib/modspec/conformance_class.rb +4 -6
  9. data/lib/modspec/conformance_test.rb +19 -4
  10. data/lib/modspec/normative_statement.rb +2 -2
  11. data/lib/modspec/normative_statements_class.rb +3 -1
  12. data/lib/modspec/suite.rb +45 -38
  13. data/lib/modspec/version.rb +1 -1
  14. data/lib/modspec.rb +1 -12
  15. data/modspec.gemspec +3 -2
  16. data/spec/conformance_class.liquid +2 -2
  17. data/spec/fixtures/advanced-json-rc.yaml +5 -7
  18. data/spec/fixtures/advanced-rc.yaml +12 -14
  19. data/spec/fixtures/basic-quaternion-json-rc.yaml +5 -7
  20. data/spec/fixtures/basic-quaternion-json-strict-rc.yaml +4 -5
  21. data/spec/fixtures/basic-quaternion-rc.yaml +7 -8
  22. data/spec/fixtures/basic-ypr-json-rc.yaml +5 -8
  23. data/spec/fixtures/basic-ypr-rc.yaml +7 -7
  24. data/spec/fixtures/chain-json-rc.yaml +5 -7
  25. data/spec/fixtures/chain-rc.yaml +11 -13
  26. data/spec/fixtures/frame-spec-rc.yaml +10 -10
  27. data/spec/fixtures/global-rc.yaml +7 -4
  28. data/spec/fixtures/graph-json-rc.yaml +5 -7
  29. data/spec/fixtures/graph-rc.yaml +11 -13
  30. data/spec/fixtures/series-irregular-json-rc.yaml +5 -7
  31. data/spec/fixtures/series-irregular-rc.yaml +13 -15
  32. data/spec/fixtures/series-regular-json-rc.yaml +5 -7
  33. data/spec/fixtures/series-regular-rc.yaml +15 -17
  34. data/spec/fixtures/stream-json-rc.yaml +9 -11
  35. data/spec/fixtures/stream-rc.yaml +10 -12
  36. data/spec/fixtures/tangent-point-rc.yaml +10 -11
  37. data/spec/fixtures/time-rc.yaml +6 -8
  38. data/spec/modspec/conformance_class_spec.rb +29 -27
  39. data/spec/modspec/conformance_test_spec.rb +6 -5
  40. data/spec/modspec/normative_statement_spec.rb +16 -12
  41. data/spec/modspec/normative_statements_class_spec.rb +4 -4
  42. data/spec/modspec/suite_spec.rb +26 -22
  43. data/spec/modspec_spec.rb +7 -7
  44. data/spec/spec_helper.rb +1 -0
  45. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c39d089400518c8882fa0cfc55582fa27cd73c9358faf2224aeb5535a238fc55
4
- data.tar.gz: c7b5fcf2a9c36ab12751ac964b6d95528a21330228872c75851bdf2211a8d885
3
+ metadata.gz: 925062f2457c7aa978de3d2eabc679f4a33b9177e8ba2f3a80494c46377ff0b8
4
+ data.tar.gz: '083c357ffd578b297ae28753e48dccacd08a10d202f336299b037d1d6b08fe9a'
5
5
  SHA512:
6
- metadata.gz: d8e4371eea18c40f1b660841ff6d1723b8a8536acd248a65d87d6d4526bba35ea0b00970e7199bdeaee51114c1cd214233859c2265d1f43fb742831f19c71568
7
- data.tar.gz: 7f6f7f555aaa1ce91e300240ce57f37e69d77e1fb4f1ff0fb020e8afc69c195c3a287f2540bbcce31019481915a2fb2d1ba748670f1c9f6ce622eb6d4b720e58
6
+ metadata.gz: ce9246f0f6b4ce811bf498d52a59c25949ad0016b024ab215c332ce7e1e34fa311c2a78267a3a1b07cb1a2f0f468559c1aeaedb638c4552e9500016ad8a3235b
7
+ data.tar.gz: 7132a3d0194c87222d077752784d1d1d7197481d1db1ae356c9f959d8cccd8163f3ef268a2e4e6b75812095768e133ab6da81c629fd3d33b0122f7f2789079fe
@@ -2,6 +2,10 @@
2
2
  # See https://github.com/metanorma/cimas
3
3
  name: rake
4
4
 
5
+ permissions:
6
+ contents: write
7
+ packages: write
8
+
5
9
  on:
6
10
  push:
7
11
  branches: [ master, main ]
@@ -2,6 +2,11 @@
2
2
  # See https://github.com/metanorma/cimas
3
3
  name: release
4
4
 
5
+ permissions:
6
+ contents: write
7
+ packages: write
8
+ id-token: write
9
+
5
10
  on:
6
11
  workflow_dispatch:
7
12
  inputs:
data/.rubocop.yml CHANGED
@@ -1,10 +1,19 @@
1
- inherit_from: .rubocop_todo.yml
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ inherit_from:
4
+ - https://raw.githubusercontent.com/riboseinc/oss-guides/main/ci/rubocop.yml
5
+ - .rubocop_todo.yml
2
6
 
3
- AllCops:
4
- TargetRubyVersion: 3.0
7
+ inherit_mode:
8
+ merge:
9
+ - Exclude
5
10
 
6
- Style/StringLiterals:
7
- EnforcedStyle: double_quotes
11
+ # local repo-specific modifications
12
+ # ...
13
+ plugins:
14
+ - rubocop-rspec
15
+ - rubocop-performance
16
+ - rubocop-rake
8
17
 
9
- Style/StringLiteralsInInterpolation:
10
- EnforcedStyle: double_quotes
18
+ AllCops:
19
+ TargetRubyVersion: 3.0
data/.rubocop_todo.yml CHANGED
@@ -1,118 +1,105 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2024-09-11 00:07:51 UTC using RuboCop version 1.66.1.
3
+ # on 2026-05-05 14:09:35 UTC using RuboCop version 1.86.1.
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
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 4
10
- # This cop supports safe autocorrection (--autocorrect).
11
- # Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include.
12
- # Include: **/*.gemfile, **/Gemfile, **/gems.rb
13
- Bundler/OrderedGems:
14
- Exclude:
15
- - 'Gemfile'
16
-
17
9
  # Offense count: 1
18
- # Configuration parameters: Severity, Include.
19
- # Include: **/*.gemspec
20
10
  Gemspec/RequiredRubyVersion:
21
11
  Exclude:
22
12
  - 'modspec.gemspec'
23
13
 
24
- # Offense count: 10
14
+ # Offense count: 33
25
15
  # This cop supports safe autocorrection (--autocorrect).
26
- # Configuration parameters: EnforcedStyle, IndentationWidth.
27
- # SupportedStyles: aligned, indented, indented_relative_to_receiver
28
- Layout/MultilineMethodCallIndentation:
16
+ # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
17
+ # URISchemes: http, https
18
+ Layout/LineLength:
29
19
  Exclude:
30
- - 'modspec.gemspec'
20
+ - 'lib/modspec/conformance_class.rb'
21
+ - 'lib/modspec/conformance_test.rb'
22
+ - 'lib/modspec/normative_statement.rb'
23
+ - 'lib/modspec/normative_statements_class.rb'
24
+ - 'lib/modspec/suite.rb'
25
+ - 'spec/modspec/conformance_class_spec.rb'
26
+ - 'spec/modspec/conformance_test_spec.rb'
27
+ - 'spec/modspec/normative_statement_spec.rb'
28
+ - 'spec/modspec/normative_statements_class_spec.rb'
31
29
  - 'spec/modspec/suite_spec.rb'
32
30
 
33
31
  # Offense count: 4
34
- # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
35
- Metrics/AbcSize:
36
- Max: 33
37
-
38
- # Offense count: 6
39
- # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
40
- # AllowedMethods: refine
41
- Metrics/BlockLength:
42
- Max: 138
32
+ # Configuration parameters: AllowComments, AllowEmptyLambdas.
33
+ Lint/EmptyBlock:
34
+ Exclude:
35
+ - 'spec/modspec/conformance_class_spec.rb'
36
+ - 'spec/modspec/suite_spec.rb'
43
37
 
44
38
  # Offense count: 1
45
- # Configuration parameters: CountComments, CountAsOne.
46
- Metrics/ClassLength:
47
- Max: 204
39
+ # This cop supports safe autocorrection (--autocorrect).
40
+ # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
41
+ # NotImplementedExceptions: NotImplementedError
42
+ Lint/UnusedMethodArgument:
43
+ Exclude:
44
+ - 'lib/modspec/normative_statement.rb'
48
45
 
49
- # Offense count: 1
50
- # Configuration parameters: AllowedMethods, AllowedPatterns.
51
- Metrics/CyclomaticComplexity:
52
- Max: 12
46
+ # Offense count: 7
47
+ # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
48
+ Metrics/AbcSize:
49
+ Exclude:
50
+ - 'lib/modspec/suite.rb'
53
51
 
54
52
  # Offense count: 5
53
+ # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
54
+ Metrics/CyclomaticComplexity:
55
+ Exclude:
56
+ - 'lib/modspec/suite.rb'
57
+
58
+ # Offense count: 9
55
59
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
56
60
  Metrics/MethodLength:
57
- Max: 18
61
+ Max: 21
58
62
 
59
- # Offense count: 1
60
- # Configuration parameters: AllowedMethods, AllowedPatterns.
63
+ # Offense count: 3
64
+ # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
61
65
  Metrics/PerceivedComplexity:
62
- Max: 12
63
-
64
- # Offense count: 1
65
- # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros.
66
- # NamePrefix: is_, has_, have_
67
- # ForbiddenPrefixes: is_, has_, have_
68
- # AllowedMethods: is_a?
69
- # MethodDefinitionMacros: define_method, define_singleton_method
70
- Naming/PredicateName:
71
66
  Exclude:
72
- - 'spec/**/*'
73
- - 'lib/modspec/normative_statement.rb'
67
+ - 'lib/modspec/suite.rb'
74
68
 
75
- # Offense count: 6
76
- # Configuration parameters: AllowedConstants.
77
- Style/Documentation:
69
+ # Offense count: 1
70
+ # Configuration parameters: MinSize.
71
+ Performance/CollectionLiteralInLoop:
78
72
  Exclude:
79
- - 'spec/**/*'
80
- - 'test/**/*'
81
- - 'lib/modspec/conformance_class.rb'
82
- - 'lib/modspec/conformance_test.rb'
83
- - 'lib/modspec/normative_statement.rb'
84
- - 'lib/modspec/normative_statements_class.rb'
85
73
  - 'lib/modspec/suite.rb'
86
74
 
87
- # Offense count: 2
88
- # This cop supports safe autocorrection (--autocorrect).
89
- Style/IfUnlessModifier:
90
- Exclude:
91
- - 'lib/modspec/conformance_class.rb'
92
- - 'lib/modspec/normative_statements_class.rb'
75
+ # Offense count: 5
76
+ # Configuration parameters: CountAsOne.
77
+ RSpec/ExampleLength:
78
+ Max: 15
93
79
 
94
- # Offense count: 27
80
+ # Offense count: 1
95
81
  # This cop supports safe autocorrection (--autocorrect).
96
- # Configuration parameters: EnforcedStyleForMultiline.
97
- # SupportedStylesForMultiline: comma, consistent_comma, no_comma
98
- Style/TrailingCommaInArguments:
82
+ RSpec/ExpectActual:
99
83
  Exclude:
100
- - 'spec/modspec/conformance_class_spec.rb'
101
- - 'spec/modspec/conformance_test_spec.rb'
102
84
  - 'spec/modspec/normative_statement_spec.rb'
103
- - 'spec/modspec/normative_statements_class_spec.rb'
104
85
 
105
- # Offense count: 6
106
- # This cop supports safe autocorrection (--autocorrect).
107
- # Configuration parameters: EnforcedStyleForMultiline.
108
- # SupportedStylesForMultiline: comma, consistent_comma, no_comma
109
- Style/TrailingCommaInArrayLiteral:
86
+ # Offense count: 4
87
+ # Configuration parameters: Max, AllowedIdentifiers, AllowedPatterns.
88
+ RSpec/IndexedLet:
110
89
  Exclude:
111
- - 'spec/modspec/conformance_class_spec.rb'
90
+ - 'spec/modspec/normative_statements_class_spec.rb'
91
+ - 'spec/modspec/suite_spec.rb'
112
92
 
113
- # Offense count: 13
114
- # This cop supports safe autocorrection (--autocorrect).
115
- # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
116
- # URISchemes: http, https
117
- Layout/LineLength:
118
- Max: 247
93
+ # Offense count: 7
94
+ RSpec/MultipleExpectations:
95
+ Max: 9
96
+
97
+ # Offense count: 7
98
+ # Configuration parameters: AllowSubject.
99
+ RSpec/MultipleMemoizedHelpers:
100
+ Max: 12
101
+
102
+ # Offense count: 2
103
+ RSpec/RepeatedExample:
104
+ Exclude:
105
+ - 'spec/modspec_spec.rb'
data/CLAUDE.md ADDED
@@ -0,0 +1,61 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ `modspec` is a Ruby gem for working with OGC ModSpec — a specification format (OGC 08-131r3) for defining requirements and conformance tests for standards. All models use `lutaml-model` (`Lutaml::Model::Serializable`) for serialization to/from YAML, JSON, and XML.
8
+
9
+ ## Commands
10
+
11
+ - **Run all tests:** `bundle exec rake` or `bundle exec rspec`
12
+ - **Run a single test file:** `bundle exec rspec spec/modspec/suite_spec.rb`
13
+ - **Run a single example:** `bundle exec rspec spec/modspec/suite_spec.rb:42`
14
+ - **Lint:** RuboCop is configured but not in the default rake task. Run with `bundle exec rubocop` if needed.
15
+ - **Console:** `bin/console` (loads IRB with the gem)
16
+
17
+ ## Architecture
18
+
19
+ All model classes inherit from `Lutaml::Model::Serializable` and define attributes via the `attribute` DSL with serialization mappings in `xml do` blocks. YAML/JSON serialization comes from lutaml-model automatically.
20
+
21
+ ### Identifier convention (critical)
22
+
23
+ Identifiers are URIs with a specific structure:
24
+ - Class-level: `/<type>/<class>` (e.g., `/req/example`, `/conf/example`)
25
+ - Instance-level: `/<type>/<class>/<name>` (e.g., `/req/example/foo`)
26
+ - Type prefix: `req` = normative statements, `conf` = conformance tests
27
+
28
+ Validation enforces that children share their parent's identifier prefix.
29
+
30
+ ### Model hierarchy
31
+
32
+ ```
33
+ Suite
34
+ ├── NormativeStatementsClass (collection) → groups normative statements
35
+ │ └── NormativeStatement (collection)
36
+ │ └── NormativeStatementPart (collection) → sub-parts of a statement
37
+ ├── ConformanceClass (collection) → groups conformance tests
38
+ │ └── ConformanceTest (collection)
39
+ ```
40
+
41
+ - `NormativeStatement` has obligation (`requirement`/`recommendation`/`permission`), dependencies, inherit, indirect_dependency, implements, parts
42
+ - `ConformanceTest` has targets (referencing normative statement identifiers), abstract flag, method, purpose
43
+ - `ConformanceTest` uses runtime-only `corresponding_requirements` and `parent_class` attrs set by `Suite#setup_relationships`
44
+
45
+ ### Validation
46
+
47
+ Each model class has a `validate` method that returns an array of error strings. `Suite#validate` orchestrates full validation: cycles (dependency graph via DFS), label uniqueness, dependency resolution, and delegating to child class validators.
48
+
49
+ ### Key Suite operations
50
+
51
+ - `combine(other_suite)` — merges two suites, deduplicating by identifier
52
+ - `from_yaml_files(*files)` — loads and combines multiple YAML files
53
+ - `setup_relationships` — cross-links conformance tests to their target normative statements
54
+
55
+ ### Custom types
56
+
57
+ `Modspec::Identifier` extends `Lutaml::Model::Type::String` — used as the type for all identifier attributes and reference fields (dependencies, targets, inherit, etc.).
58
+
59
+ ## Key dependency
60
+
61
+ `lutaml-model ~> 0.7.7` — provides the `Serializable` base class, attribute DSL, and serialization adapters. Breaking changes in lutaml-model may affect this gem.
data/Gemfile CHANGED
@@ -2,11 +2,12 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- # Specify your gem's dependencies in modspec.gemspec
6
5
  gemspec
7
6
 
8
- gem "equivalent-xml"
9
- gem "pry"
7
+ gem "canon"
10
8
  gem "rake"
11
9
  gem "rspec"
12
10
  gem "rubocop"
11
+ gem "rubocop-performance"
12
+ gem "rubocop-rake"
13
+ gem "rubocop-rspec"
@@ -18,7 +18,7 @@ module Modspec
18
18
  attribute :reference, :string
19
19
 
20
20
  xml do
21
- root "conformance-class"
21
+ element "conformance-class"
22
22
  map_attribute "identifier", to: :identifier
23
23
  map_element "name", to: :name
24
24
  map_element "dependencies", to: :dependencies
@@ -32,7 +32,7 @@ module Modspec
32
32
  end
33
33
 
34
34
  def validate
35
- errors = super()
35
+ errors = super
36
36
  errors.concat(validate_identifier_prefix)
37
37
  errors.concat(validate_class_children_mapping)
38
38
  errors.concat(tests.flat_map(&:validate))
@@ -52,10 +52,8 @@ module Modspec
52
52
  def validate_identifier_prefix
53
53
  errors = []
54
54
  expected_prefix = "#{identifier}/"
55
- if tests
56
- tests.each do |test|
57
- errors << "Conformance test #{test.identifier} does not share the expected prefix #{expected_prefix}" unless test.identifier.to_s.start_with?(expected_prefix)
58
- end
55
+ tests&.each do |test|
56
+ errors << "Conformance test #{test.identifier} does not share the expected prefix #{expected_prefix}" unless test.identifier.to_s.start_with?(expected_prefix)
59
57
  end
60
58
  errors
61
59
  end
@@ -13,13 +13,13 @@ module Modspec
13
13
  attribute :description, :string
14
14
  attribute :guidance, :string, collection: true
15
15
  attribute :purpose, :string
16
- attribute :method, :string # Inspection, etc.
16
+ attribute :test_method, :string
17
17
  attribute :type, :string
18
18
  attribute :reference, :string
19
19
  attribute :abstract, :boolean
20
20
 
21
21
  xml do
22
- root "conformance-test"
22
+ element "conformance-test"
23
23
  map_attribute "identifier", to: :identifier
24
24
  map_attribute "abstract", to: :abstract
25
25
  map_element "name", to: :name
@@ -29,15 +29,30 @@ module Modspec
29
29
  map_element "description", to: :description
30
30
  map_element "guidance", to: :guidance
31
31
  map_element "purpose", to: :purpose
32
- map_element "method", to: :method
32
+ map_element "method", to: :test_method
33
33
  map_element "type", to: :type
34
34
  map_element "reference", to: :reference
35
35
  end
36
36
 
37
+ key_value do
38
+ map "identifier", to: :identifier
39
+ map "name", to: :name
40
+ map "dependencies", to: :dependencies
41
+ map "targets", to: :targets
42
+ map "belongs_to", to: :belongs_to
43
+ map "description", to: :description
44
+ map "guidance", to: :guidance
45
+ map "purpose", to: :purpose
46
+ map "method", to: :test_method
47
+ map "type", to: :type
48
+ map "reference", to: :reference
49
+ map "abstract", to: :abstract
50
+ end
51
+
37
52
  attr_accessor :corresponding_requirements, :parent_class
38
53
 
39
54
  def validate
40
- errors = super()
55
+ errors = super
41
56
  errors.concat(validate_requirement_mapping)
42
57
  errors.concat(validate_class_mapping)
43
58
  errors
@@ -29,7 +29,7 @@ module Modspec
29
29
  default: -> { "requirement" }
30
30
 
31
31
  xml do
32
- root "normative-statement"
32
+ element "normative-statement"
33
33
  map_attribute "identifier", to: :identifier
34
34
  map_element "name", to: :name
35
35
  map_element "subject", to: :subject
@@ -46,7 +46,7 @@ module Modspec
46
46
  map_element "parts", to: :parts
47
47
  end
48
48
 
49
- def validate(suite = nil)
49
+ def validate(suite = nil, register: Lutaml::Model::Config.default_register)
50
50
  errors = super()
51
51
  errors.concat(validate_dependencies(suite)) if suite
52
52
  errors.concat(validate_nested_requirement)
@@ -12,19 +12,21 @@ module Modspec
12
12
  attribute :subject, :string
13
13
  attribute :guidance, :string, collection: true
14
14
  attribute :dependencies, Identifier, collection: true
15
+ attribute :implements, Identifier, collection: true
15
16
  attribute :normative_statements, NormativeStatement, collection: true
16
17
  attribute :belongs_to, Identifier, collection: true
17
18
  attribute :reference, :string
18
19
  attribute :source, :string
19
20
 
20
21
  xml do
21
- root "normative-statements-class"
22
+ element "normative-statements-class"
22
23
  map_attribute "identifier", to: :identifier
23
24
  map_element "name", to: :name
24
25
  map_element "description", to: :description
25
26
  map_element "subject", to: :subject
26
27
  map_element "guidance", to: :guidance
27
28
  map_element "dependencies", to: :dependencies
29
+ map_element "implements", to: :implements
28
30
  map_element "normative-statements", to: :normative_statements
29
31
  map_element "belongs_to", to: :belongs_to
30
32
  map_element "reference", to: :reference
data/lib/modspec/suite.rb CHANGED
@@ -6,14 +6,16 @@ module Modspec
6
6
  class Suite < Lutaml::Model::Serializable
7
7
  attribute :identifier, Identifier
8
8
  attribute :name, :string
9
- attribute :normative_statements_classes, NormativeStatementsClass, collection: true
9
+ attribute :normative_statements_classes, NormativeStatementsClass,
10
+ collection: true
10
11
  attribute :conformance_classes, ConformanceClass, collection: true
11
12
 
12
13
  xml do
13
- root "suite"
14
+ element "suite"
14
15
  map_attribute "identifier", to: :identifier
15
16
  map_element "name", to: :name
16
- map_element "normative-statements-classes", to: :normative_statements_classes
17
+ map_element "normative-statements-classes",
18
+ to: :normative_statements_classes
17
19
  map_element "conformance-classes", to: :conformance_classes
18
20
  end
19
21
 
@@ -24,13 +26,20 @@ module Modspec
24
26
  errors.concat(validate_cycles)
25
27
  errors.concat(validate_label_uniqueness)
26
28
  errors.concat(validate_dependencies)
27
- errors.concat(normative_statements_classes.flat_map { |n| n.validate(self) }) unless normative_statements_classes.nil?
29
+ unless normative_statements_classes.nil?
30
+ errors.concat(normative_statements_classes.flat_map do |n|
31
+ n.validate(self)
32
+ end)
33
+ end
28
34
  errors.concat(conformance_classes.flat_map(&:validate)) unless conformance_classes.nil?
29
35
  errors
30
36
  end
31
37
 
32
38
  def combine(other_suite)
33
- raise ArgumentError, "Argument must be a Modspec::Suite" unless other_suite.is_a?(Modspec::Suite)
39
+ unless other_suite.is_a?(Modspec::Suite)
40
+ raise ArgumentError,
41
+ "Argument must be a Modspec::Suite"
42
+ end
34
43
 
35
44
  combined_suite = dup
36
45
  combined_suite.all_identifiers = nil
@@ -45,9 +54,9 @@ module Modspec
45
54
  end
46
55
 
47
56
  # Ensure uniqueness of identifiers
48
- combined_suite.normative_statements_classes.uniq!(&:identifier) if combined_suite.normative_statements_classes
57
+ combined_suite.normative_statements_classes&.uniq!(&:identifier)
49
58
 
50
- combined_suite.conformance_classes.uniq!(&:identifier) if combined_suite.conformance_classes
59
+ combined_suite.conformance_classes&.uniq!(&:identifier)
51
60
 
52
61
  combined_suite.name = "#{name} + #{other_suite.name}"
53
62
 
@@ -69,8 +78,10 @@ module Modspec
69
78
  attr_writer :all_identifiers
70
79
 
71
80
  def resolve_conflicts(other_suite)
72
- resolve_conflicts_for(normative_statements_classes, other_suite.normative_statements_classes)
73
- resolve_conflicts_for(conformance_classes, other_suite.conformance_classes)
81
+ resolve_conflicts_for(normative_statements_classes,
82
+ other_suite.normative_statements_classes)
83
+ resolve_conflicts_for(conformance_classes,
84
+ other_suite.conformance_classes)
74
85
  end
75
86
 
76
87
  def self.from_yaml_files(*files)
@@ -95,7 +106,7 @@ module Modspec
95
106
  conformance_classes.each do |cc|
96
107
  cc.tests.each do |ct|
97
108
  ct.corresponding_requirements = all_requirements.select do |r|
98
- ct.targets.map(&:to_s).include?(r.identifier.to_s)
109
+ Array(ct.targets).map(&:to_s).include?(r.identifier.to_s)
99
110
  end
100
111
  ct.parent_class = cc
101
112
  end
@@ -108,7 +119,9 @@ module Modspec
108
119
  return if self_collection.nil? || other_collection.nil?
109
120
 
110
121
  other_collection.each do |other_item|
111
- existing_item = self_collection.find { |item| item.identifier == other_item.identifier }
122
+ existing_item = self_collection.find do |item|
123
+ item.identifier == other_item.identifier
124
+ end
112
125
  if existing_item
113
126
  # Merge attributes of conflicting items
114
127
  merge_attributes(existing_item, other_item)
@@ -133,7 +146,7 @@ module Modspec
133
146
  def validate_cycles
134
147
  graph = build_dependency_graph
135
148
  cycles = detect_cycles(graph)
136
- cycles.map { |cycle| "Cycle detected: #{cycle.join(" -> ")}" }
149
+ cycles.map { |cycle| "Cycle detected: #{cycle.join(' -> ')}" }
137
150
  end
138
151
 
139
152
  # Combine all statements into a single array
@@ -161,7 +174,8 @@ module Modspec
161
174
  graph[id] = Set.new
162
175
 
163
176
  # Define all dependency-like properties to check
164
- dependency_properties = %i[dependencies indirect_dependency implements targets]
177
+ dependency_properties = %i[dependencies indirect_dependency implements
178
+ targets]
165
179
 
166
180
  dependency_properties.each do |property|
167
181
  graph[id].merge(statement.send(property).map(&:to_s)) if statement.respond_to?(property) && !statement.send(property).nil?
@@ -195,7 +209,8 @@ module Modspec
195
209
  if graph[node]
196
210
  graph[node].each do |neighbor|
197
211
  if !visited.include?(neighbor)
198
- cycle = detect_cycle_util(neighbor, graph, visited, recursion_stack, path)
212
+ cycle = detect_cycle_util(neighbor, graph, visited,
213
+ recursion_stack, path)
199
214
  return cycle if cycle
200
215
  elsif recursion_stack.include?(neighbor)
201
216
  return path[path.index(neighbor)..] + [neighbor]
@@ -228,21 +243,17 @@ module Modspec
228
243
  all_identifiers = collect_all_identifiers
229
244
 
230
245
  errors = []
231
- if normative_statements_classes
232
- normative_statements_classes.each do |nsc|
233
- errors.concat(validate_class_dependencies(nsc, all_identifiers))
234
- nsc.normative_statements.each do |ns|
235
- errors.concat(validate_statement_dependencies(ns, all_identifiers))
236
- end
246
+ normative_statements_classes&.each do |nsc|
247
+ errors.concat(validate_class_dependencies(nsc, all_identifiers))
248
+ nsc.normative_statements.each do |ns|
249
+ errors.concat(validate_statement_dependencies(ns, all_identifiers))
237
250
  end
238
251
  end
239
252
 
240
- if conformance_classes
241
- conformance_classes.each do |cc|
242
- errors.concat(validate_class_dependencies(cc, all_identifiers))
243
- cc.tests.each do |ct|
244
- errors.concat(validate_test_targets(ct, all_identifiers))
245
- end
253
+ conformance_classes&.each do |cc|
254
+ errors.concat(validate_class_dependencies(cc, all_identifiers))
255
+ cc.tests.each do |ct|
256
+ errors.concat(validate_test_targets(ct, all_identifiers))
246
257
  end
247
258
  end
248
259
 
@@ -252,21 +263,17 @@ module Modspec
252
263
  def collect_all_identifiers
253
264
  identifiers = {}
254
265
 
255
- if normative_statements_classes
256
- normative_statements_classes.each do |nsc|
257
- identifiers[nsc.identifier.to_s] = nsc
258
- nsc.normative_statements.each do |ns|
259
- identifiers[ns.identifier.to_s] = ns
260
- end
266
+ normative_statements_classes&.each do |nsc|
267
+ identifiers[nsc.identifier.to_s] = nsc
268
+ nsc.normative_statements.each do |ns|
269
+ identifiers[ns.identifier.to_s] = ns
261
270
  end
262
271
  end
263
272
 
264
- if conformance_classes
265
- conformance_classes.each do |cc|
266
- identifiers[cc.identifier.to_s] = cc
267
- cc.tests.each do |ct|
268
- identifiers[ct.identifier.to_s] = ct
269
- end
273
+ conformance_classes&.each do |cc|
274
+ identifiers[cc.identifier.to_s] = cc
275
+ cc.tests.each do |ct|
276
+ identifiers[ct.identifier.to_s] = ct
270
277
  end
271
278
  end
272
279
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Modspec
4
- VERSION = "0.1.4"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/modspec.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "modspec/version"
4
4
  require "lutaml/model"
5
+ require "set"
5
6
 
6
7
  module Modspec
7
8
  class Error < StandardError; end
@@ -15,15 +16,3 @@ require_relative "modspec/normative_statements_class"
15
16
  require_relative "modspec/conformance_test"
16
17
  require_relative "modspec/conformance_class"
17
18
  require_relative "modspec/suite"
18
-
19
- require "lutaml/model/xml_adapter/nokogiri_adapter"
20
- require "lutaml/model/json_adapter/standard_json_adapter"
21
- require "lutaml/model/toml_adapter/toml_rb_adapter"
22
- require "lutaml/model/yaml_adapter/standard_yaml_adapter"
23
-
24
- Lutaml::Model::Config.configure do |config|
25
- config.xml_adapter = Lutaml::Model::XmlAdapter::NokogiriAdapter
26
- config.yaml_adapter = Lutaml::Model::YamlAdapter::StandardYamlAdapter
27
- config.json_adapter = Lutaml::Model::JsonAdapter::StandardJsonAdapter
28
- config.toml_adapter = Lutaml::Model::TomlAdapter::TomlRbAdapter
29
- end