edoxen 0.1.1 → 0.1.2

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.
data/README.adoc CHANGED
@@ -23,7 +23,6 @@ This library is particularly useful for standards organizations, committees,
23
23
  and governance bodies that need to maintain structured records of their
24
24
  decision-making processes.
25
25
 
26
-
27
26
  == Origin
28
27
 
29
28
  "Edoxen" is how all resolutions of Ancient Athens started.
@@ -37,17 +36,18 @@ meaning "it was the opinion of" or "it seemed good to". This term was used in
37
36
  the context of formal resolutions and decisions made by the Athenian assembly,
38
37
  reflecting the collective will and judgment of the citizens.
39
38
 
40
-
41
39
  == Features
42
40
 
43
41
  * Classes for modeling resolutions, actions, considerations, and approvals
44
- * Support for resolution collections with metadata
42
+ * Support for resolution collections with rich metadata
43
+ * Structured date handling with semantic meaning (meeting, decision, effective dates)
45
44
  * YAML and JSON serialization with round-trip compatibility
46
45
  * Structured identifiers and meeting information
47
46
  * Resolution relationships and dependencies
48
47
  * Integration with the `lutaml-model` serialization framework
49
48
  * Comprehensive YAML schema for validation
50
- * Real-world data compatibility with ISO/TC 154 resolution formats
49
+ * Command-line interface for validation and processing
50
+ * Real-world compatibility with real-world resolutions (e.g., ISO/TCs, CIPM)
51
51
 
52
52
  == Installation
53
53
 
@@ -72,139 +72,181 @@ Or install it yourself as:
72
72
  $ gem install edoxen
73
73
  ----
74
74
 
75
- == Quick start
75
+ == Command Line Interface
76
76
 
77
- Here's a minimal example to get you started:
77
+ The `edoxen` command provides utilities for working with resolution data files.
78
78
 
79
- [source,ruby]
79
+ === Available Commands
80
+
81
+ Get help on available commands:
82
+
83
+ [source,sh]
84
+ ----
85
+ $ edoxen help
86
+ Commands:
87
+ edoxen help [COMMAND] # Describe available commands or one specific command
88
+ edoxen normalize YAML_FILE_PATTERN # Normalize YAML files using Edoxen schema
89
+ edoxen validate YAML_FILE_PATTERN # Validate YAML files against Edoxen schema
80
90
  ----
81
- require 'edoxen'
82
91
 
83
- # Create a simple resolution
84
- resolution = Edoxen::Resolution.new(
85
- title: "Adoption of new standard",
86
- type: "resolution",
87
- category: "Technical resolutions",
88
- identifier: "2024-01"
89
- )
92
+ === Validation
90
93
 
91
- # Add an action to the resolution
92
- action = Edoxen::Action.new(
93
- type: "resolves",
94
- message: "to adopt ISO 12345 as a new standard",
95
- date_effective: Date.new(2024, 1, 15)
96
- )
97
- resolution.actions = [action]
94
+ Validate resolution data files against the Edoxen schema:
98
95
 
99
- # Add a consideration
100
- consideration = Edoxen::Consideration.new(
101
- type: "having",
102
- message: "reviewed the technical specifications"
103
- )
104
- resolution.considerations = [consideration]
96
+ [source,sh]
97
+ ----
98
+ # Validate a single file
99
+ $ edoxen validate resolutions.yaml
100
+
101
+ # Validate multiple files
102
+ $ edoxen validate file1.yaml file2.yaml file3.yaml
103
+
104
+ # Validate files using patterns
105
+ $ edoxen validate "*.yaml"
106
+ $ edoxen validate "resolutions/*.yml"
107
+
108
+ # Example output
109
+ 🔍 Validating 3 file(s)...
110
+ resolutions.yaml... ✅ VALID
111
+ file1.yaml... ✅ VALID
112
+ file2.yaml... ❌ INVALID
113
+ - Line 15: Invalid action type 'invalid_type'
114
+
115
+ 📊 Validation Summary:
116
+ Valid files: 2
117
+ Invalid files: 1
118
+ Success rate: 66.7%
119
+ ----
105
120
 
106
- # Serialize to YAML
107
- puts resolution.to_yaml
108
-
109
- # Create a resolution collection
110
- collection = Edoxen::ResolutionCollection.new(
111
- metadata: {
112
- title: "Resolutions of the 42nd plenary meeting",
113
- date: "2024-01-15",
114
- source: "ISO/TC 154 Secretariat"
115
- },
116
- resolutions: [resolution]
117
- )
121
+ Get detailed help for the validate command:
118
122
 
119
- # Serialize collection to YAML
120
- puts collection.to_yaml
123
+ [source,sh]
121
124
  ----
125
+ $ edoxen help validate
126
+ Usage:
127
+ edoxen validate YAML_FILE_PATTERN
122
128
 
123
- == Documentation
129
+ Description:
130
+ Validate YAML files against the Edoxen schema. Supports file patterns and multiple files.
124
131
 
125
- === Data models
132
+ Examples:
133
+ edoxen validate resolutions.yaml
134
+ edoxen validate *.yaml
135
+ edoxen validate "data/*.yml"
136
+ ----
126
137
 
127
- The library provides these main model classes:
138
+ === Normalization
128
139
 
129
- `Edoxen::Resolution`::
130
- Core model representing a formal resolution with title, type, category, and
131
- associated elements.
140
+ Normalize YAML files to ensure they conform to the Edoxen schema format.
132
141
 
133
- `Edoxen::ResolutionCollection`::
134
- Container for multiple resolutions with metadata about the meeting or
135
- collection context.
142
+ This command loads the YAML files, parses them through the Edoxen models, and
143
+ outputs clean, properly formatted YAML.
136
144
 
137
- `Edoxen::Action`::
138
- Represents actions taken within a resolution (e.g., "resolves", "requests",
139
- "thanks").
145
+ [source,sh]
146
+ ----
147
+ # Normalize files to a specific output directory
148
+ $ edoxen normalize resolutions.yaml --output /path/to/output
140
149
 
141
- `Edoxen::Consideration`::
142
- Models considerations that lead to a resolution (e.g., "having", "noting",
143
- "recognizing").
150
+ # Normalize multiple files
151
+ $ edoxen normalize "*.yaml" --output normalized/
144
152
 
145
- `Edoxen::Approval`::
146
- Captures approval information including type and degree of consensus.
153
+ # Normalize files in place (overwrites original files)
154
+ $ edoxen normalize resolutions.yaml --inplace
147
155
 
148
- `Edoxen::MeetingIdentifier`::
149
- Contains meeting identification information such as venue, date, and identifier.
156
+ # Example output
157
+ 🔄 Normalizing 2 file(s)...
158
+ resolutions.yaml... ✅ NORMALIZED → /path/to/output/resolutions.yaml
159
+ meeting-notes.yaml... ✅ NORMALIZED → /path/to/output/meeting-notes.yaml
150
160
 
151
- `Edoxen::ResolutionRelationship`::
152
- Defines relationships between resolutions (e.g., "supersedes", "amends").
161
+ 📊 Normalization Summary:
162
+ Successful: 2
163
+ Failed: 0
164
+ Success rate: 100.0%
165
+ Output directory: /path/to/output
166
+ ----
153
167
 
154
- === Architecture overview
168
+ Get detailed help for the normalize command:
155
169
 
156
- The library is built on `lutaml-model` and follows these design principles:
170
+ [source,sh]
171
+ ----
172
+ $ edoxen help normalize
173
+ Usage:
174
+ edoxen normalize YAML_FILE_PATTERN
175
+
176
+ Options:
177
+ [--output=OUTPUT] # Output directory for normalized files
178
+ [--inplace], [--no-inplace], [--skip-inplace] # Modify files in place (no backup)
179
+
180
+ Description:
181
+ Normalize YAML files using Edoxen schema. This ensures consistent formatting
182
+ and structure according to the Edoxen data models.
183
+
184
+ Examples:
185
+ edoxen normalize resolutions.yaml --output clean/
186
+ edoxen normalize "*.yaml" --inplace
187
+ edoxen normalize "data/*.yml" --output normalized/
188
+ ----
157
189
 
158
- **Model-based approach**::
159
- Each entity is represented as a Ruby class with defined attributes and
160
- serialization mappings.
190
+ === Common use cases
161
191
 
162
- **Flexible serialization**::
163
- Support for both YAML and JSON formats with automatic type conversion and
164
- round-trip compatibility.
192
+ ==== Validating resolution collections
165
193
 
166
- **Extensible structure**::
167
- Models allow additional properties beyond the core schema, enabling
168
- customization for specific organizational needs.
194
+ [source,sh]
195
+ ----
196
+ # Validate all YAML files in a directory
197
+ $ edoxen validate "resolutions/*.yaml"
169
198
 
170
- **Real-world compatibility**::
171
- Designed to work with existing resolution data formats used by standards
172
- organizations.
199
+ # Validate specific meeting files
200
+ $ edoxen validate "plenary-*.yaml" "ballots-*.yaml"
201
+ ----
173
202
 
174
- == Usage workflow
203
+ ==== Cleaning up legacy data
175
204
 
176
- The `edoxen` workflow follows a straightforward approach:
205
+ [source,sh]
206
+ ----
207
+ # Normalize legacy files to new schema format
208
+ $ edoxen normalize "legacy/*.yaml" --output clean/
177
209
 
178
- === 1. Data modeling
210
+ # Update files in place after backup
211
+ $ cp -r data/ data-backup/
212
+ $ edoxen normalize "data/*.yaml" --inplace
213
+ ----
179
214
 
180
- . **Create resolutions**: Instantiate `Resolution` objects with required
181
- attributes
182
- . **Add components**: Attach actions, considerations, approvals as needed
183
- . **Build collections**: Group resolutions into collections with metadata
215
+ ==== Batch processing
184
216
 
185
- === 2. Serialization and persistence
217
+ [source,sh]
218
+ ----
219
+ # Validate and normalize in sequence
220
+ $ edoxen validate "input/*.yaml" && edoxen normalize "input/*.yaml" --output output/
221
+ ----
186
222
 
187
- . **Export to YAML/JSON**: Use built-in serialization methods
188
- . **Validate structure**: Leverage the provided YAML schema for validation
189
- . **Round-trip processing**: Load and save data while preserving structure
223
+ == Usage
190
224
 
191
- == YAML format specification
225
+ === Parsing resolution data
192
226
 
193
- Edoxen uses a structured YAML format for resolution data. Here's an example:
227
+ ==== From YAML
194
228
 
195
229
  [source,yaml]
196
230
  ----
197
231
  metadata:
198
232
  title: "Resolutions of the 42nd plenary meeting of ISO/TC 154"
199
- date: "2024-01-15"
233
+ dates:
234
+ - kind: meeting
235
+ start: 2024-01-15
236
+ end: 2024-01-17
200
237
  source: "ISO/TC 154 Secretariat"
201
- venue: "Virtual meeting"
238
+ urls:
239
+ - href: "https://example.com/meeting"
240
+ title: "Meeting Information"
202
241
 
203
242
  resolutions:
204
243
  - identifier: "2024-01"
205
244
  title: "Adoption of new standard"
206
- type: "resolution"
207
245
  category: "Technical resolutions"
246
+ dates:
247
+ - kind: decision
248
+ start: 2024-01-16
249
+ subject: "ISO/TC 154"
208
250
 
209
251
  considerations:
210
252
  - type: "having"
@@ -212,47 +254,294 @@ resolutions:
212
254
 
213
255
  actions:
214
256
  - type: "resolves"
257
+ dates:
258
+ - kind: effective
259
+ start: 2024-01-16
215
260
  message: "to adopt ISO 12345 as a new standard"
216
- date_effective: "2024-01-15"
217
261
 
218
262
  approvals:
219
263
  - type: "affirmative"
220
264
  degree: "unanimous"
265
+ message: "UNANIMOUS"
266
+ ----
267
+
268
+ [source,ruby]
269
+ ----
270
+ require 'edoxen'
271
+
272
+ # Parse from YAML string
273
+ yaml_content = File.read('resolutions.yaml')
274
+ resolution_set = Edoxen::ResolutionSet.from_yaml(yaml_content)
275
+
276
+ # Access metadata
277
+ puts "Title: #{resolution_set.metadata.title}"
278
+ puts "Meeting dates: #{resolution_set.metadata.dates.first.start} to #{resolution_set.metadata.dates.first.end}"
279
+ puts "Source: #{resolution_set.metadata.source}"
280
+
281
+ # Access resolutions
282
+ resolution_set.resolutions.each do |resolution|
283
+ puts "Resolution: #{resolution.identifier} - #{resolution.title}"
284
+ puts "Category: #{resolution.category}"
285
+ puts "Subject: #{resolution.subject}"
286
+
287
+ # Access structured dates
288
+ resolution.dates.each do |date|
289
+ puts " #{date.kind.capitalize} date: #{date.start}"
290
+ end
291
+
292
+ # Access considerations
293
+ resolution.considerations.each do |consideration|
294
+ puts " Consideration (#{consideration.type}): #{consideration.message}"
295
+ end
296
+
297
+ # Access actions
298
+ resolution.actions.each do |action|
299
+ puts " Action (#{action.type}): #{action.message}"
300
+ action.dates.each do |date|
301
+ puts " #{date.kind.capitalize} date: #{date.start}"
302
+ end
303
+ end
304
+
305
+ # Access approvals
306
+ resolution.approvals.each do |approval|
307
+ puts " Approval: #{approval.type} (#{approval.degree})"
308
+ end
309
+ end
310
+ ----
311
+
312
+ ==== From JSON
313
+
314
+ [source,ruby]
315
+ ----
316
+ require 'edoxen'
317
+
318
+ # Parse from JSON string
319
+ json_content = File.read('resolutions.json')
320
+ resolution_set = Edoxen::ResolutionSet.from_json(json_content)
321
+
322
+ # Access data (same as with YAML)
323
+ ----
324
+
325
+ === Creating resolution data
326
+
327
+ ==== Basic resolution
328
+
329
+ [source,ruby]
330
+ ----
331
+ require 'edoxen'
332
+
333
+ # Create structured dates
334
+ meeting_date = Edoxen::ResolutionDate.new(
335
+ kind: "meeting",
336
+ start: Date.new(2024, 1, 15),
337
+ end: Date.new(2024, 1, 17)
338
+ )
339
+
340
+ decision_date = Edoxen::ResolutionDate.new(
341
+ kind: "decision",
342
+ start: Date.new(2024, 1, 16)
343
+ )
344
+
345
+ effective_date = Edoxen::ResolutionDate.new(
346
+ kind: "effective",
347
+ start: Date.new(2024, 1, 16)
348
+ )
349
+
350
+ # Create metadata
351
+ metadata = Edoxen::Metadata.new(
352
+ title: "Resolutions of the 42nd plenary meeting of ISO/TC 154",
353
+ dates: [meeting_date],
354
+ source: "ISO/TC 154 Secretariat",
355
+ urls: [
356
+ Edoxen::Url.new(
357
+ href: "https://example.com/meeting",
358
+ title: "Meeting Information"
359
+ )
360
+ ]
361
+ )
362
+
363
+ # Create a resolution
364
+ resolution = Edoxen::Resolution.new(
365
+ identifier: "2024-01",
366
+ title: "Adoption of new standard",
367
+ category: "Technical resolutions",
368
+ subject: "ISO/TC 154",
369
+ dates: [decision_date]
370
+ )
371
+
372
+ # Add considerations
373
+ consideration = Edoxen::Consideration.new(
374
+ type: "having",
375
+ message: "reviewed the technical specifications"
376
+ )
377
+ resolution.considerations = [consideration]
378
+
379
+ # Add actions
380
+ action = Edoxen::Action.new(
381
+ type: "resolves",
382
+ dates: [effective_date],
383
+ message: "to adopt ISO 12345 as a new standard"
384
+ )
385
+ resolution.actions = [action]
386
+
387
+ # Add approvals
388
+ approval = Edoxen::Approval.new(
389
+ type: "affirmative",
390
+ degree: "unanimous",
391
+ message: "UNANIMOUS"
392
+ )
393
+ resolution.approvals = [approval]
394
+
395
+ # Create resolution set
396
+ resolution_set = Edoxen::ResolutionSet.new(
397
+ metadata: metadata,
398
+ resolutions: [resolution]
399
+ )
400
+ ----
401
+
402
+ ==== Multiple action types
403
+
404
+ [source,ruby]
405
+ ----
406
+ # Actions can have multiple types
407
+ action = Edoxen::Action.new(
408
+ type: ["resolves", "requests"],
409
+ dates: [effective_date],
410
+ message: "to adopt the standard and request implementation guidance"
411
+ )
221
412
  ----
222
413
 
223
- === Schema validation
414
+ === Serializing resolution data
415
+
416
+ ==== To YAML
417
+
418
+ [source,ruby]
419
+ ----
420
+ # Serialize to YAML
421
+ yaml_content = resolution_set.to_yaml
422
+ File.write('resolutions.yaml', yaml_content)
423
+ ----
424
+
425
+ ==== To JSON
426
+
427
+ [source,ruby]
428
+ ----
429
+ # Serialize to JSON
430
+ json_content = resolution_set.to_json
431
+ File.write('resolutions.json', json_content)
432
+ ----
433
+
434
+ == Data model
435
+
436
+ The Edoxen gem provides the following models:
437
+
438
+ [source]
439
+ ----
440
+ ┌─────────────────────────┐
441
+ │ ResolutionSet │
442
+ │ │
443
+ │ ◊metadata │
444
+ │ ◊resolutions │
445
+ └───────────┬─────────────┘
446
+ │ 1..*
447
+ ┌───────────────┴────────────────┐
448
+ ┌───────────▼─────────────┐ ┌────────────▼───────────┐
449
+ │ Resolution │ │ Metadata │
450
+ │ │ │ │
451
+ │ •identifier │ │ •title │
452
+ │ •title │ │ ◊dates │
453
+ │ •category │ │ •source │
454
+ │ •subject │ │ ◊urls │
455
+ │ ◊dates │ └────────────────────────┘
456
+ │ ◊considerations │
457
+ │ ◊actions │
458
+ │ ◊approvals │
459
+ └────────────┬────────────┘
460
+ ├────────────────────┬────────────────────┐
461
+ │ 1..* │ 1..* │ 1..*
462
+ ┌────────▼────────┐ ┌────────▼────────┐ ┌────────▼────────┐
463
+ │ Consideration │ │ Action │ │ Approval │
464
+ │ │ │ │ │ │
465
+ │ •type │ │ •type │ │ •type │
466
+ │ •message │ │ •message │ │ •degree │
467
+ │ •date_effective │ │ •subject │ │ •message │
468
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
469
+ ----
470
+
471
+ === ResolutionSet
472
+
473
+ The main container for resolution collections with metadata.
474
+
475
+ `metadata`:: A `Metadata` object containing collection information
476
+ `resolutions`:: A collection of `Resolution` objects
477
+
478
+ === Metadata
479
+
480
+ Contains metadata about the resolution collection.
481
+
482
+ `title`:: The collection title as a string
483
+ `dates`:: A collection of `ResolutionDate` objects for meeting dates
484
+ `source`:: The source organization as a string
485
+ `urls`:: A collection of `Url` objects for reference links
486
+
487
+ === ResolutionDate
488
+
489
+ Represents structured date information with semantic meaning.
490
+
491
+ `kind`:: The type of date as a string
492
+ `start`:: The start date as a Date object
493
+ `end`:: The end date as a Date object (optional, for date ranges)
494
+
495
+ === Url
496
+
497
+ Represents a URL reference with optional title.
498
+
499
+ `href`:: The URL as a string
500
+ `title`:: The link title as a string (optional)
501
+
502
+ === Resolution
503
+
504
+ Represents a single formal resolution.
505
+
506
+ `identifier`:: The resolution identifier as a string
507
+ `title`:: The resolution title as a string
508
+ `category`:: The resolution category as a string (optional)
509
+ `subject`:: The subject body as a string (optional)
510
+ `dates`:: A collection of `ResolutionDate` objects
511
+ `considerations`:: A collection of `Consideration` objects
512
+ `actions`:: A collection of `Action` objects
513
+ `approvals`:: A collection of `Approval` objects
514
+
515
+ === Action
516
+
517
+ Represents actions taken within a resolution.
224
518
 
225
- A comprehensive YAML schema is provided at `schema/edoxen.yaml` for validating
226
- resolution data files. The schema follows JSON Schema Draft 7 conventions and
227
- includes:
519
+ `type`:: The action type(s). Can be a string or array of strings
520
+ `dates`:: A collection of `ResolutionDate` objects
521
+ `message`:: The action description as a string
522
+ `subject`:: The action subject as a string (optional)
228
523
 
229
- * Complete structure definitions for all model types
230
- * Enumerated values for type validation
231
- * Date format validation
232
- * Flexible extensibility with `additionalProperties`
524
+ === Consideration
233
525
 
234
- The schema can be used with standard JSON Schema validators to ensure data
235
- integrity and compliance.
526
+ Represents considerations that lead to a resolution.
236
527
 
237
- == Real-world examples
528
+ `type`:: The consideration type as a string
529
+ `message`:: The consideration description as a string
530
+ `date_effective`:: The effective date as a Date object (optional)
238
531
 
239
- The library has been tested with real resolution data from ISO/TC 154 and
240
- other standards organizations. It successfully handles:
532
+ === Approval
241
533
 
242
- * Complex resolution structures with multiple actions and considerations
243
- * Various resolution types (resolutions, recommendations, decisions)
244
- * Meeting metadata and organizational information
245
- * Cross-references and relationships between resolutions
246
- * Historical data migration and format conversion
534
+ Represents approval information for a resolution.
247
535
 
248
- == Contributing
536
+ `type`:: The approval type as a string
537
+ `degree`:: The degree of approval as a string (optional)
538
+ `message`:: The approval message as a string (optional)
249
539
 
250
- Bug reports and pull requests are welcome on GitHub at
251
- https://github.com/metanorma/edoxen.
540
+ == Copyright
252
541
 
253
- == License and Copyright
542
+ Copyright https://www.ribose.com[Ribose].
254
543
 
255
- This project is licensed under the BSD 2-clause License.
256
- See the link:LICENSE[] file for details.
544
+ == License
257
545
 
258
- Copyright Ribose.
546
+ The gem is available as open source under the terms of the
547
+ https://opensource.org/licenses/BSD-2-Clause[2-Clause BSD License].
data/edoxen.gemspec CHANGED
@@ -10,7 +10,11 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = "Edoxen is a set of information models used for representing resolution and decision information."
12
12
  spec.description = <<~HEREDOC
13
- Edoxen provides a Ruby library for working with resolution models, allowing users to create, manipulate, and serialize resolution data in a structured format. It is built on top of the lutaml-model serialization framework, which provides a flexible and extensible way to define data models and serialize them to YAML or JSON formats.
13
+ Edoxen provides a Ruby library for working with resolution models, allowing
14
+ users to create, manipulate, and serialize resolution data in a structured
15
+ format. It is built on top of the lutaml-model serialization framework,
16
+ which provides a flexible and extensible way to define data models and
17
+ serialize them to YAML or JSON formats.
14
18
  HEREDOC
15
19
 
16
20
  spec.homepage = "https://github.com/metanorma/edoxen"
@@ -32,5 +36,7 @@ Gem::Specification.new do |spec|
32
36
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
33
37
  spec.require_paths = ["lib"]
34
38
 
39
+ spec.add_dependency "json_schemer", "~> 2.0"
35
40
  spec.add_dependency "lutaml-model", "~> 0.7"
41
+ spec.add_dependency "thor", "~> 1.0"
36
42
  end
data/exe/edoxen ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/edoxen"
5
+
6
+ Edoxen::Cli.start(ARGV)