modspec 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/.rubocop_todo.yml +118 -0
  4. data/Gemfile +4 -2
  5. data/README.adoc +508 -17
  6. data/lib/modspec/conformance_class.rb +39 -10
  7. data/lib/modspec/conformance_test.rb +40 -13
  8. data/lib/modspec/identifier.rb +5 -3
  9. data/lib/modspec/normative_statement.rb +49 -14
  10. data/lib/modspec/normative_statements_class.rb +39 -12
  11. data/lib/modspec/suite.rb +242 -5
  12. data/lib/modspec/version.rb +1 -1
  13. data/lib/modspec.rb +14 -4
  14. data/modspec.gemspec +8 -14
  15. data/spec/conformance_class.liquid +98 -0
  16. data/spec/fixtures/advanced-cc.yaml +52 -0
  17. data/spec/fixtures/advanced-json-cc.yaml +24 -0
  18. data/spec/fixtures/advanced-json-rc.yaml +16 -0
  19. data/spec/fixtures/advanced-rc.yaml +43 -0
  20. data/spec/fixtures/basic-quaternion-cc.yaml +44 -0
  21. data/spec/fixtures/basic-quaternion-json-cc.yaml +24 -0
  22. data/spec/fixtures/basic-quaternion-json-rc.yaml +17 -0
  23. data/spec/fixtures/basic-quaternion-json-strict-cc.yaml +22 -0
  24. data/spec/fixtures/basic-quaternion-json-strict-rc.yaml +19 -0
  25. data/spec/fixtures/basic-quaternion-rc.yaml +34 -0
  26. data/spec/fixtures/basic-ypr-cc.yaml +39 -0
  27. data/spec/fixtures/basic-ypr-json-cc.yaml +23 -0
  28. data/spec/fixtures/basic-ypr-json-rc.yaml +21 -0
  29. data/spec/fixtures/basic-ypr-rc.yaml +32 -0
  30. data/spec/fixtures/chain-cc.yaml +50 -0
  31. data/spec/fixtures/chain-json-cc.yaml +24 -0
  32. data/spec/fixtures/chain-json-rc.yaml +20 -0
  33. data/spec/fixtures/chain-rc.yaml +36 -0
  34. data/spec/fixtures/frame-spec-cc.yaml +43 -0
  35. data/spec/fixtures/frame-spec-rc.yaml +27 -0
  36. data/spec/fixtures/global-cc.yaml +38 -0
  37. data/spec/fixtures/global-rc.yaml +23 -0
  38. data/spec/fixtures/graph-cc.yaml +48 -0
  39. data/spec/fixtures/graph-json-cc.yaml +24 -0
  40. data/spec/fixtures/graph-json-rc.yaml +20 -0
  41. data/spec/fixtures/graph-rc.yaml +38 -0
  42. data/spec/fixtures/series-irregular-cc.yaml +58 -0
  43. data/spec/fixtures/series-irregular-json-cc.yaml +24 -0
  44. data/spec/fixtures/series-irregular-json-rc.yaml +20 -0
  45. data/spec/fixtures/series-irregular-rc.yaml +41 -0
  46. data/spec/fixtures/series-regular-cc.yaml +63 -0
  47. data/spec/fixtures/series-regular-json-cc.yaml +24 -0
  48. data/spec/fixtures/series-regular-json-rc.yaml +20 -0
  49. data/spec/fixtures/series-regular-rc.yaml +46 -0
  50. data/spec/fixtures/stream-cc.yaml +49 -0
  51. data/spec/fixtures/stream-json-cc.yaml +48 -0
  52. data/spec/fixtures/stream-json-rc.yaml +32 -0
  53. data/spec/fixtures/stream-rc.yaml +36 -0
  54. data/spec/fixtures/tangent-point-cc.yaml +43 -0
  55. data/spec/fixtures/tangent-point-rc.yaml +38 -0
  56. data/spec/fixtures/time-cc.yaml +32 -0
  57. data/spec/fixtures/time-rc.yaml +20 -0
  58. data/spec/modspec/conformance_class_spec.rb +154 -0
  59. data/spec/modspec/conformance_test_spec.rb +76 -0
  60. data/spec/modspec/normative_statement_spec.rb +81 -0
  61. data/spec/modspec/normative_statements_class_spec.rb +61 -0
  62. data/spec/modspec/suite_spec.rb +109 -0
  63. data/spec/modspec_spec.rb +25 -0
  64. data/spec/requirements_class.liquid +93 -0
  65. data/spec/spec_helper.rb +16 -0
  66. metadata +67 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04b72356e376ccef5b03148c33e1c6a06d78d8ae64610c89eda67d8d68dbcb37
4
- data.tar.gz: 6a1960bee2e234b9ca5bb29e9619b3d802831c1660167a3d7730fea0a688bec5
3
+ metadata.gz: e872dc5ba6f3f5108de783fd4dffe75cdafda9c36e30fada467a0955003e21df
4
+ data.tar.gz: e1c98c303fa34c9f1d7565545031b95e96062dfd513ed4b378a13de3d216552c
5
5
  SHA512:
6
- metadata.gz: ce7873a1eaaea400d23e7f29cd8bc8c2e670d6857217424dced043454c863c081f783d6afb56e76dfb85b72f7fe4257ad6a96561fc7339d4b8a65b7b0c4d4d2e
7
- data.tar.gz: 8889bde3ccf4cb143d4528768cf0dc38773f2df7368777830f11d0ce7649e9dfc94fd04c8051cf390d4309cd514775932e030274815b71ad94bd81bf5851db5d
6
+ metadata.gz: 57e6d5c5e5d2300b464fecdf0ca7277c3c1da94739c89209b6ca8f158bd1002ea0de081f5da38342a4bbb714486c45e70a9beec588758d3bc12df80c80c5bcb1
7
+ data.tar.gz: bbd9e71cc21b306075d30c105043399ea94665e9b3e7ddcf56e942e240c97c254a908bd593bf3566e7b76c54c6dae61f78abd252bb80cfbb513c347ad76a0151
data/.rubocop.yml CHANGED
@@ -1,3 +1,5 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
1
3
  AllCops:
2
4
  TargetRubyVersion: 3.0
3
5
 
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,118 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2024-09-11 00:07:51 UTC using RuboCop version 1.66.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
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
+ # Offense count: 1
18
+ # Configuration parameters: Severity, Include.
19
+ # Include: **/*.gemspec
20
+ Gemspec/RequiredRubyVersion:
21
+ Exclude:
22
+ - 'modspec.gemspec'
23
+
24
+ # Offense count: 10
25
+ # This cop supports safe autocorrection (--autocorrect).
26
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
27
+ # SupportedStyles: aligned, indented, indented_relative_to_receiver
28
+ Layout/MultilineMethodCallIndentation:
29
+ Exclude:
30
+ - 'modspec.gemspec'
31
+ - 'spec/modspec/suite_spec.rb'
32
+
33
+ # 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
43
+
44
+ # Offense count: 1
45
+ # Configuration parameters: CountComments, CountAsOne.
46
+ Metrics/ClassLength:
47
+ Max: 204
48
+
49
+ # Offense count: 1
50
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
51
+ Metrics/CyclomaticComplexity:
52
+ Max: 12
53
+
54
+ # Offense count: 5
55
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
56
+ Metrics/MethodLength:
57
+ Max: 18
58
+
59
+ # Offense count: 1
60
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
61
+ 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
+ Exclude:
72
+ - 'spec/**/*'
73
+ - 'lib/modspec/normative_statement.rb'
74
+
75
+ # Offense count: 6
76
+ # Configuration parameters: AllowedConstants.
77
+ Style/Documentation:
78
+ 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
+ - 'lib/modspec/suite.rb'
86
+
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'
93
+
94
+ # Offense count: 27
95
+ # This cop supports safe autocorrection (--autocorrect).
96
+ # Configuration parameters: EnforcedStyleForMultiline.
97
+ # SupportedStylesForMultiline: comma, consistent_comma, no_comma
98
+ Style/TrailingCommaInArguments:
99
+ Exclude:
100
+ - 'spec/modspec/conformance_class_spec.rb'
101
+ - 'spec/modspec/conformance_test_spec.rb'
102
+ - 'spec/modspec/normative_statement_spec.rb'
103
+ - 'spec/modspec/normative_statements_class_spec.rb'
104
+
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:
110
+ Exclude:
111
+ - 'spec/modspec/conformance_class_spec.rb'
112
+
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
data/Gemfile CHANGED
@@ -5,5 +5,7 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in modspec.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
9
- gem "rspec", "~> 3.0"
8
+ gem "equivalent-xml"
9
+ gem "pry"
10
+ gem "rake"
11
+ gem "rspec"
data/README.adoc CHANGED
@@ -2,44 +2,535 @@
2
2
 
3
3
  == Purpose
4
4
 
5
- The `modspec` Ruby gem allows you to work with OGC ModSpec instances.
5
+ The `modspec` Ruby library allows you to work with OGC ModSpec instances
6
+ and export/load them from/to YAML.
6
7
 
7
- NOTE: This is a work-in-progress.
8
+ OGC ModSpec is a specification for specifying requirements and conformance tests
9
+ for standards, described in OGC 08-131r3.
8
10
 
11
+ == Features
9
12
 
10
- == Library
13
+ This library allows you to:
11
14
 
12
- === Usage
15
+ * Create and manipulate ModSpec instances:
16
+ ** normative statements
17
+ ** conformance tests
18
+ ** normative statements classes
19
+ ** conformance classes
20
+ ** unified ModSpec suite
13
21
 
14
- The following code generates OGC ModSpec instances in XML and YAML.
22
+ * Load and save objects from/to YAML
23
+ * Perform validations on ModSpec instances
24
+ * Combine ModSpec suites
25
+
26
+
27
+ == Installation
28
+
29
+ Add this line to your application's Gemfile:
15
30
 
16
31
  [source,ruby]
17
32
  ----
18
- require 'modspec'
19
- doc = IO.read('spec/fixtures/chain-rc.yaml')
20
- ms = Modspec::Suite.from_yaml(doc)
21
- puts ms.to_yaml
33
+ gem 'modspec'
34
+ ----
35
+
36
+ Then execute:
37
+
38
+ [source,shell]
39
+ ----
40
+ $ bundle install
41
+ ----
42
+
43
+ Or install it yourself:
44
+
45
+ [source,shell]
46
+ ----
47
+ $ gem install modspec
48
+ ----
49
+
50
+ == Basics
51
+
52
+ ModSpec instances all have the following core attributes:
53
+
54
+ `identifier`:: A unique identifier for the instance, as a URI.
55
+
56
+ ** The pattern for a ModSpec class is `/<type>/<class>`, where
57
+ *** `<type>` is the type of the instance (`req` for normative statement, `conf` for conformance test)
58
+ *** `<class>` is the name of the class (normative statements class or conformance class)
59
+
60
+ ** The pattern for a normative statement or conformance test is `/<type>/<class>/<name>`, where
61
+
62
+ *** `<type>` is the type of the instance (`req` for normative statement, `conf` for conformance test)
63
+ *** `<class>` is the name of the class (normative statements class or conformance class)
64
+ *** `<name>` is the name of the instance
65
+
66
+ `name`::
67
+ A human-readable name for the instance
68
+
69
+ `description`::
70
+ A description of the instance
71
+
72
+ `guidance`::
73
+ Guidance on how to implement the instance
74
+
75
+
76
+
77
+ == Usage
78
+
79
+ === Normative statements class
80
+
81
+ A normative statements class groups related normative statements.
82
+
83
+ A normative statements class has the following attributes in addition to the core attributes:
84
+
85
+ `subject`::
86
+ The subject of the normative statements class
87
+
88
+ `dependencies`::
89
+ URI(s) of normative statement classes that this class depends on
90
+
91
+ `normative_statements`::
92
+ A list of normative statements that belong to this class
93
+
94
+ `belongs_to`::
95
+ The normative statements class that this class belongs to
96
+
97
+ `reference`::
98
+ A reference to an external document or resource
99
+
100
+ `source`::
101
+ The source of the normative statements class
102
+
103
+
104
+ .Working with normative statements classes
105
+ [example]
106
+ ====
107
+ [source,ruby]
108
+ ----
109
+ normative_statements_class = Modspec::NormativeStatementsClass.new(
110
+ identifier: "/req/example",
111
+ name: "Requirements class",
112
+ dependencies: ["/req/baf"],
113
+ normative_statements: [normative_statement]
114
+ )
22
115
  ----
23
116
 
117
+ [source,ruby]
118
+ ----
119
+ normative_statements_class.to_yaml
120
+ ----
121
+
122
+ [source,yaml]
123
+ ----
124
+ identifier: "/req/example"
125
+ name: "Requirements class"
126
+ dependencies:
127
+ - "/req/baf"
128
+ normative_statements:
129
+ - identifier: "/req/example/foo"
130
+ name: "Example requirement"
131
+ statement: "This is an example requirement."
132
+ dependencies:
133
+ - "/req/bar"
134
+ - "/req/baz/2"
135
+ ----
24
136
 
25
137
  [source,ruby]
26
138
  ----
27
- require 'modspec'
28
- doc = IO.read('spec/fixtures/chain-cc.yaml')
29
- ms = Modspec::Suite.from_yaml(doc)
30
- puts ms.to_yaml
139
+ > yaml = IO.read('example.yaml')
140
+ > normative_statements_class = Modspec::NormativeStatementsClass.from_yaml(yaml)
141
+ > <#Modspec::NormativeStatementsClass:0x00007f8b1b8b3d08 @identifier="/req/example", @name="Requirements class", @dependencies=["/req/baf"], @normative_statements=[<#Modspec::NormativeStatement:0x00007f8b1b8b3d08 @identifier="/req/example/foo", @name="Example requirement", @statement="This is an example requirement.", @dependencies=["/req/bar", "/req/baz/2"]>]>
142
+ > normative_statements_class.name
143
+ > "Requirements class"
144
+ ----
145
+ ====
146
+
147
+ Validations:
148
+
149
+ * *Identifier prefix*: All normative statements within a normative statements
150
+ class must share the same identifier prefix as the class itself, followed by a
151
+ slash and then the statement's own identifier.
152
+
153
+
154
+ === Normative statement
155
+
156
+ A normative statement represents a single requirement in the specification.
157
+
158
+ A normative statement has the following attributes in addition to the core attributes:
159
+
160
+ `subject`::
161
+ The subject of the normative statement
162
+
163
+ `obligation`::
164
+ The obligation level of the class, one of `requirement`, `recommendation`, `permission`. Defaults to `requirement`.
165
+
166
+ `statement`::
167
+ The text of the normative statement
168
+
169
+ `condition`::
170
+ Conditions that must be met for the statement to apply
171
+
172
+ `inherit`::
173
+ URI(s) of normative statement(s) that this statement inherits from
174
+
175
+ `indirect_dependency`::
176
+ URI(s) of normative statement(s) that this statement indirectly depends on
177
+
178
+ `implements`::
179
+ The higher-level normative statement that this statement implements
180
+
181
+ `dependencies`::
182
+ A list of identifiers for other normative statements that this statement depends on.
183
+
184
+ `belongs_to`::
185
+ The normative statements class that this statement belongs to.
186
+
187
+ `reference`::
188
+ A reference to an external document or resource
189
+
190
+ `parts`::
191
+ A list of normative statements classes that this class is composed
192
+
193
+
194
+ .Working with normative statements
195
+ [example]
196
+ ====
197
+ [source,ruby]
198
+ ----
199
+ normative_statement = Modspec::NormativeStatement.new(
200
+ identifier: "/req/example/foo",
201
+ name: "Example requirement",
202
+ statement: "This is an example requirement statement.",
203
+ obligation: "requirement", # default
204
+ parts: [
205
+ "This is a part of the requirement.",
206
+ "This is another part of the requirement."
207
+ ]
208
+ dependencies: ["/req/bar", "/req/baz/2"]
209
+ )
210
+ ----
211
+
212
+ [source,ruby]
213
+ ----
214
+ normative_statement.to_yaml
215
+ ----
216
+
217
+ Will give out:
218
+
219
+ [source,yaml]
220
+ ----
221
+ identifier: /req/example/foo
222
+ name: Example requirement
223
+ statement: This is an example requirement statement.
224
+ dependencies:
225
+ - /req/bar
226
+ - /req/baz/2
227
+ ----
228
+
229
+ And to load a normative statement from a YAML file:
230
+
231
+ [source,ruby]
232
+ ----
233
+ > yaml = IO.read('example-foo.yaml')
234
+ > normative_statement = Modspec::NormativeStatement.from_yaml(yaml)
235
+ > <#Modspec::NormativeStatement:0x00007f8b1b8b3d08 @identifier="/req/example/foo", @name="Example requirement", @statement="This is an example requirement statement.", @dependencies=["/req/bar", "/req/baz/2"]>
236
+ > normative_statement.name
237
+ > "Example requirement"
238
+ ----
239
+ ====
240
+
241
+
242
+ Validations:
243
+
244
+ * *Unique identifier*: Each normative statement must have a unique identifier
245
+ within its parent normative statements class.
246
+
247
+ * *Valid dependencies*: The dependencies listed for a normative statement must
248
+ refer to valid identifiers of other normative statements.
249
+
250
+
251
+ === Conformance class
252
+
253
+ A conformance class groups related conformance tests.
254
+
255
+ A conformance class has the following attributes in addition to the core attributes:
256
+
257
+ `tests`::
258
+ A set of conformance tests that belong to this class
259
+
260
+ `classification`::
261
+ A classification of the conformance class
262
+
263
+ `dependencies`::
264
+ A list of identifiers for other conformance classes that this class depends on
265
+
266
+ `target`::
267
+ A list of identifiers of normative statement(s) that this class targets
268
+
269
+ `belongs_to`::
270
+ A conformance class that this class belongs to
271
+
272
+ `reference`::
273
+ A reference to an external document or resource
274
+
275
+
276
+ .Working with conformance classes
277
+ [example]
278
+ ====
279
+ [source,ruby]
280
+ ----
281
+ conformance_class = Modspec::ConformanceClass.new(
282
+ identifier: "/conf/example",
283
+ name: "Conformance class",
284
+ tests: [conformance_test]
285
+ )
286
+ conformance_class.to_yaml
287
+ ----
288
+
289
+ [source,yaml]
290
+ ----
291
+ identifier: "/conf/example"
292
+ name: "Conformance class"
293
+ tests:
294
+ - identifier: "/conf/example/foo"
295
+ name: "Example test"
296
+ description: "This is an example conformance test."
297
+ targets:
298
+ - "/req/example/foo"
299
+ ----
300
+
301
+ [source,ruby]
302
+ ----
303
+ > yaml = IO.read('example.yaml')
304
+ > conformance_class = Modspec::ConformanceClass.from_yaml(yaml)
305
+ > <#Modspec::ConformanceClass:0x00007f8b1b8b3d08 @identifier="/conf/example", @name="Conformance class", @tests=[<#Modspec::ConformanceTest:0x00007f8b1b8b3d08 @identifier="/conf/example/foo", @name="Example test", @description="This is an example conformance test.", @targets=["/req/example/foo"]>], @abstract=false>
306
+ > conformance_class.name
307
+ > "Conformance class"
308
+ ----
309
+ ====
310
+
311
+
312
+ Validations:
313
+
314
+ * *Identifier prefix*: All conformance tests within a conformance class must
315
+ share the same identifier prefix as the class itself, followed by a slash and
316
+ then the test's own identifier.
317
+
318
+ * *Valid targets*: The targets listed for a conformance test must refer to valid
319
+ identifiers of existing normative statements.
320
+
321
+
322
+
323
+ === Conformance test
324
+
325
+ A conformance test verifies compliance with one or more normative statements.
326
+
327
+ A conformance test has the following attributes in addition to the core attributes:
328
+
329
+ `targets`::
330
+ A list of identifiers for normative statements that this test targets
331
+
332
+ `belongs_to`::
333
+ The conformance class that this test belongs to
334
+
335
+ `guidance`::
336
+ Guidance on how to perform the test
337
+
338
+ `purpose`::
339
+ The purpose of the test
340
+
341
+ `method`::
342
+ The method used to perform the test
343
+
344
+ `type`::
345
+ The type of the test
346
+
347
+ `reference`::
348
+ A reference to an external document or resource
349
+
350
+ `abstract`::
351
+ A boolean indicating whether this test is abstract
352
+
353
+
354
+
355
+ .Working with conformance tests
356
+ [example]
357
+ ====
358
+ [source,ruby]
359
+ ----
360
+ conformance_test = Modspec::ConformanceTest.new(
361
+ identifier: "/conf/example/foo",
362
+ name: "Example test",
363
+ description: "This is an example conformance test.",
364
+ targets: ["/req/example/foo"],
365
+ test_method: "manual",
366
+ abstract: false
367
+ )
368
+ conformance_test.to_yaml
31
369
  ----
32
370
 
371
+ [source,yaml]
372
+ ----
373
+ identifier: "/conf/example/foo"
374
+ name: "Example test"
375
+ description: "This is an example conformance test."
376
+ abstract: false
377
+ test_method: "manual"
378
+ targets:
379
+ - "/req/example/foo"
380
+ ----
381
+
382
+ [source,ruby]
383
+ ----
384
+ > yaml = IO.read('example.yaml')
385
+ > conformance_test = Modspec::ConformanceTest.from_yaml(yaml)
386
+ > <#Modspec::ConformanceTest:0x00007f8b1b8b3d08 @identifier="/conf/example/foo", @name="Example test", @description="This is an example conformance test.", @targets=["/req/example/foo"], @test_method="manual", @abstract=false>
387
+ > conformance_test.name
388
+ > "Example test"
389
+ ----
390
+ ====
391
+
392
+
393
+ Validations:
394
+
395
+ * *Valid targets*: The targets listed for a conformance test must refer to valid
396
+ identifiers of existing normative statements.
397
+
398
+
399
+ === Suite
400
+
401
+ A suite represents the entire specification, including all normative statements
402
+ and conformance tests.
403
+
404
+ NOTE: This is not defined in the ModSpec specification.
405
+
406
+ .Working with suites
407
+ [example]
408
+ ====
409
+ [source,ruby]
410
+ ----
411
+ suite = Modspec::Suite.new(
412
+ identifier: "example-suite",
413
+ name: "Example suite",
414
+ normative_statements_classes: [normative_statements_class],
415
+ conformance_classes: [conformance_class]
416
+ )
417
+ suite.to_yaml
418
+ ----
419
+
420
+ [source,yaml]
421
+ ----
422
+ identifier: "example-suite"
423
+ name: "Example suite"
424
+ normative_statements_classes:
425
+ - identifier: "/req/example"
426
+ name: "Requirements class"
427
+ normative_statements:
428
+ - identifier: "/req/example/foo"
429
+ name: "Example requirement"
430
+ statement: "This is an example requirement statement."
431
+ dependencies:
432
+ - "/req/bar"
433
+ - "/req/baz/2"
434
+ conformance_classes:
435
+ - identifier: "/conf/example"
436
+ name: "Conformance class"
437
+ tests:
438
+ - identifier: "/conf/example/foo"
439
+ name: "Example test"
440
+ description: "This is an example conformance test."
441
+ targets:
442
+ - "/req/example/foo"
443
+ ----
444
+
445
+ [source,ruby]
446
+ ----
447
+ > yaml = IO.read('example-suite.yaml')
448
+ > suite = Modspec::Suite.from_yaml(yaml)
449
+ > <#Modspec::Suite:0x00007f8b1b8b3d08 @identifier="example-suite", @name="Example suite", @normative_statements_classes=[<#Modspec::NormativeStatementsClass:0x00007f8b1b8b3d08 @identifier="/req/example", @name="Requirements class", @dependencies=["/req/baf"], @normative_statements=[<#Modspec::NormativeStatement:0x00007f8b1b8b3d08 @identifier="/req/example/foo", @name="Example requirement", @statement="This is an example requirement statement.", @dependencies=["/req/bar", "/req/baz/2"]>]>], @conformance_classes=[<#Modspec::ConformanceClass:0x00007f8b1b8b3d08 @identifier="/conf/example", @name="Conformance class", @tests=[<#Modspec::ConformanceTest:0x00007f8b1b8b3d08 @identifier="/conf/example/foo", @name="Example test", @description="This is an example conformance test.", @targets=["/req/example/foo"]>], @abstract=false>]>
450
+ > suite.normative_statements_classes.first.name
451
+ > "Requirements class"
452
+ ----
453
+ ====
454
+
455
+ Validations:
456
+
457
+ * *No cyclic dependencies*: The suite ensures that there are no circular
458
+ dependencies among normative statements.
459
+
460
+ * *Label uniqueness*: Labels must be unique across all classes within the suite.
461
+
462
+ * *Dependency validation*: The suite verifies that all dependencies between
463
+ normative statements and conformance tests are valid and refer to existing
464
+ elements.
465
+
466
+
467
+ The Suite class provides a `from_yaml_files` method to load a Suite instance
468
+ from multiple YAML files. This is particularly useful when your specification is
469
+ split across several files for better organization and maintainability.
470
+
471
+ To load a Suite from multiple YAML files:
33
472
 
34
473
  [source,ruby]
35
474
  ----
36
475
  require 'modspec'
37
- doc = YAML.load(IO.read('spec/fixtures/chain-rc.yaml'))['normative-statements-classes'].first
38
- ms = Modspec::NormativeStatementsClass.from_hash(doc)
39
- puts ms.to_yaml
476
+
477
+ # Specify the paths to your YAML files
478
+ yaml_files = [
479
+ 'path/to/normative_statements.yaml',
480
+ 'path/to/conformance_tests.yaml'
481
+ ]
482
+
483
+ # Create a Suite instance from the YAML files
484
+ suite = Modspec::Suite.from_yaml_files(yaml_files)
485
+
486
+ # Now you can work with the suite object
487
+ puts suite.name
488
+ puts suite.normative_statements_classes.count
489
+ puts suite.conformance_classes.count
490
+ ----
491
+
492
+
493
+ The `Suite` class provides a `combine` method to merge two suites:
494
+
495
+ [source,ruby]
496
+ ----
497
+ combined_suite = suite1.combine(suite2)
498
+ ----
499
+
500
+ This method merges the two suites into a single suite, ensuring that the
501
+ resulting suite is consistent and free of conflicts.
502
+
503
+
504
+ === Validation process
505
+
506
+ Validations are typically performed when:
507
+
508
+ . Creating or modifying individual elements (normative statements, conformance tests, etc.)
509
+ . Adding elements to their respective classes
510
+ . Combining suites
511
+ . Loading a suite from YAML or other formats
512
+
513
+ If any validation fails, an error or a collection of errors is returned,
514
+ describing the specific validation issues encountered.
515
+
516
+ To manually trigger validation on a suite:
517
+
518
+ [source,ruby]
519
+ ----
520
+ errors = suite.validate_all
521
+ if errors.any?
522
+ puts "Validation errors:"
523
+ errors.each { |error| puts "- #{error}" }
524
+ else
525
+ puts "Suite is valid."
526
+ end
40
527
  ----
41
528
 
42
- == Credits
529
+ These validation mechanisms help ensure that the created ModSpec instances are
530
+ consistent, well-formed, and adhere to the expected structure and relationships.
531
+
532
+
533
+ == Copyright
43
534
 
44
535
  This gem is developed, maintained and funded by
45
536
  https://www.ribose.com[Ribose Inc.]