Edoxen
Purpose
Edoxen is a set of information models used for representing resolution and decision information. They are designed to provide a structured way to model formal resolutions, including their metadata, actions, considerations, and approvals.
The edoxen
gem provides a Ruby library for working with these 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.
This library is particularly useful for standards organizations, committees, and governance bodies that need to maintain structured records of their decision-making processes.
Origin
"Edoxen" is how all resolutions of Ancient Athens started.
"It was the opinion of… (the people and city that…)"
The word "edoxen" originates from the Ancient Greek word edokeō (ἔδοξεν), meaning "it was the opinion of" or "it seemed good to". This term was used in the context of formal resolutions and decisions made by the Athenian assembly, reflecting the collective will and judgment of the citizens.
Features
-
Classes for modeling resolutions, actions, considerations, and approvals
-
Support for resolution collections with rich metadata
-
Structured date handling with semantic meaning (meeting, decision, effective dates)
-
YAML and JSON serialization with round-trip compatibility
-
Structured identifiers and meeting information
-
Resolution relationships and dependencies
-
Integration with the
lutaml-model
serialization framework -
Comprehensive YAML schema for validation
-
Command-line interface for validation and processing
-
Real-world compatibility with real-world resolutions (e.g., ISO/TCs, CIPM)
Installation
Add this line to your application’s Gemfile:
gem 'edoxen'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install edoxen
Command Line Interface
The edoxen
command provides utilities for working with resolution data files.
Available Commands
Get help on available commands:
$ edoxen help
Commands:
edoxen help [COMMAND] # Describe available commands or one specific command
edoxen normalize YAML_FILE_PATTERN # Normalize YAML files using Edoxen schema
edoxen validate YAML_FILE_PATTERN # Validate YAML files against Edoxen schema
Validation
Validate resolution data files against the Edoxen schema:
# Validate a single file
$ edoxen validate resolutions.yaml
# Validate multiple files
$ edoxen validate file1.yaml file2.yaml file3.yaml
# Validate files using patterns
$ edoxen validate "*.yaml"
$ edoxen validate "resolutions/*.yml"
# Example output
🔍 Validating 3 file(s)...
resolutions.yaml... ✅ VALID
file1.yaml... ✅ VALID
file2.yaml... ❌ INVALID
- Line 15: Invalid action type 'invalid_type'
📊 Validation Summary:
Valid files: 2
Invalid files: 1
Success rate: 66.7%
Get detailed help for the validate command:
$ edoxen help validate
Usage:
edoxen validate YAML_FILE_PATTERN
Description:
Validate YAML files against the Edoxen schema. Supports file patterns and multiple files.
Examples:
edoxen validate resolutions.yaml
edoxen validate *.yaml
edoxen validate "data/*.yml"
Normalization
Normalize YAML files to ensure they conform to the Edoxen schema format.
This command loads the YAML files, parses them through the Edoxen models, and outputs clean, properly formatted YAML.
# Normalize files to a specific output directory
$ edoxen normalize resolutions.yaml --output /path/to/output
# Normalize multiple files
$ edoxen normalize "*.yaml" --output normalized/
# Normalize files in place (overwrites original files)
$ edoxen normalize resolutions.yaml --inplace
# Example output
🔄 Normalizing 2 file(s)...
resolutions.yaml... ✅ NORMALIZED → /path/to/output/resolutions.yaml
meeting-notes.yaml... ✅ NORMALIZED → /path/to/output/meeting-notes.yaml
📊 Normalization Summary:
Successful: 2
Failed: 0
Success rate: 100.0%
Output directory: /path/to/output
Get detailed help for the normalize command:
$ edoxen help normalize
Usage:
edoxen normalize YAML_FILE_PATTERN
Options:
[--output=OUTPUT] # Output directory for normalized files
[--inplace], [--no-inplace], [--skip-inplace] # Modify files in place (no backup)
Description:
Normalize YAML files using Edoxen schema. This ensures consistent formatting
and structure according to the Edoxen data models.
Examples:
edoxen normalize resolutions.yaml --output clean/
edoxen normalize "*.yaml" --inplace
edoxen normalize "data/*.yml" --output normalized/
Common use cases
Validating resolution collections
# Validate all YAML files in a directory
$ edoxen validate "resolutions/*.yaml"
# Validate specific meeting files
$ edoxen validate "plenary-*.yaml" "ballots-*.yaml"
Cleaning up legacy data
# Normalize legacy files to new schema format
$ edoxen normalize "legacy/*.yaml" --output clean/
# Update files in place after backup
$ cp -r data/ data-backup/
$ edoxen normalize "data/*.yaml" --inplace
Batch processing
# Validate and normalize in sequence
$ edoxen validate "input/*.yaml" && edoxen normalize "input/*.yaml" --output output/
Usage
Parsing resolution data
From YAML
metadata:
title: "Resolutions of the 42nd plenary meeting of ISO/TC 154"
dates:
- kind: meeting
start: 2024-01-15
end: 2024-01-17
source: "ISO/TC 154 Secretariat"
urls:
- href: "https://example.com/meeting"
title: "Meeting Information"
resolutions:
- identifier: "2024-01"
title: "Adoption of new standard"
category: "Technical resolutions"
dates:
- kind: decision
start: 2024-01-16
subject: "ISO/TC 154"
considerations:
- type: "having"
message: "reviewed the technical specifications"
actions:
- type: "resolves"
dates:
- kind: effective
start: 2024-01-16
message: "to adopt ISO 12345 as a new standard"
approvals:
- type: "affirmative"
degree: "unanimous"
message: "UNANIMOUS"
require 'edoxen'
# Parse from YAML string
yaml_content = File.read('resolutions.yaml')
resolution_set = Edoxen::ResolutionSet.from_yaml(yaml_content)
# Access metadata
puts "Title: #{resolution_set.metadata.title}"
puts "Meeting dates: #{resolution_set.metadata.dates.first.start} to #{resolution_set.metadata.dates.first.end}"
puts "Source: #{resolution_set.metadata.source}"
# Access resolutions
resolution_set.resolutions.each do |resolution|
puts "Resolution: #{resolution.identifier} - #{resolution.title}"
puts "Category: #{resolution.category}"
puts "Subject: #{resolution.subject}"
# Access structured dates
resolution.dates.each do |date|
puts " #{date.kind.capitalize} date: #{date.start}"
end
# Access considerations
resolution.considerations.each do |consideration|
puts " Consideration (#{consideration.type}): #{consideration.message}"
end
# Access actions
resolution.actions.each do |action|
puts " Action (#{action.type}): #{action.message}"
action.dates.each do |date|
puts " #{date.kind.capitalize} date: #{date.start}"
end
end
# Access approvals
resolution.approvals.each do |approval|
puts " Approval: #{approval.type} (#{approval.degree})"
end
end
From JSON
require 'edoxen'
# Parse from JSON string
json_content = File.read('resolutions.json')
resolution_set = Edoxen::ResolutionSet.from_json(json_content)
# Access data (same as with YAML)
Creating resolution data
Basic resolution
require 'edoxen'
# Create structured dates
meeting_date = Edoxen::ResolutionDate.new(
kind: "meeting",
start: Date.new(2024, 1, 15),
end: Date.new(2024, 1, 17)
)
decision_date = Edoxen::ResolutionDate.new(
kind: "decision",
start: Date.new(2024, 1, 16)
)
effective_date = Edoxen::ResolutionDate.new(
kind: "effective",
start: Date.new(2024, 1, 16)
)
# Create metadata
metadata = Edoxen::Metadata.new(
title: "Resolutions of the 42nd plenary meeting of ISO/TC 154",
dates: [meeting_date],
source: "ISO/TC 154 Secretariat",
urls: [
Edoxen::Url.new(
href: "https://example.com/meeting",
title: "Meeting Information"
)
]
)
# Create a resolution
resolution = Edoxen::Resolution.new(
identifier: "2024-01",
title: "Adoption of new standard",
category: "Technical resolutions",
subject: "ISO/TC 154",
dates: [decision_date]
)
# Add considerations
consideration = Edoxen::Consideration.new(
type: "having",
message: "reviewed the technical specifications"
)
resolution.considerations = [consideration]
# Add actions
action = Edoxen::Action.new(
type: "resolves",
dates: [effective_date],
message: "to adopt ISO 12345 as a new standard"
)
resolution.actions = [action]
# Add approvals
approval = Edoxen::Approval.new(
type: "affirmative",
degree: "unanimous",
message: "UNANIMOUS"
)
resolution.approvals = [approval]
# Create resolution set
resolution_set = Edoxen::ResolutionSet.new(
metadata: metadata,
resolutions: [resolution]
)
Multiple action types
# Actions can have multiple types
action = Edoxen::Action.new(
type: ["resolves", "requests"],
dates: [effective_date],
message: "to adopt the standard and request implementation guidance"
)
Serializing resolution data
To YAML
# Serialize to YAML
yaml_content = resolution_set.to_yaml
File.write('resolutions.yaml', yaml_content)
To JSON
# Serialize to JSON
json_content = resolution_set.to_json
File.write('resolutions.json', json_content)
Data model
The Edoxen gem provides the following models:
┌─────────────────────────┐
│ ResolutionSet │
│ │
│ ◊metadata │
│ ◊resolutions │
└───────────┬─────────────┘
│ 1..*
┌───────────────┴────────────────┐
┌───────────▼─────────────┐ ┌────────────▼───────────┐
│ Resolution │ │ Metadata │
│ │ │ │
│ •identifier │ │ •title │
│ •title │ │ ◊dates │
│ •category │ │ •source │
│ •subject │ │ ◊urls │
│ ◊dates │ └────────────────────────┘
│ ◊considerations │
│ ◊actions │
│ ◊approvals │
└────────────┬────────────┘
├────────────────────┬────────────────────┐
│ 1..* │ 1..* │ 1..*
┌────────▼────────┐ ┌────────▼────────┐ ┌────────▼────────┐
│ Consideration │ │ Action │ │ Approval │
│ │ │ │ │ │
│ •type │ │ •type │ │ •type │
│ •message │ │ •message │ │ •degree │
│ •date_effective │ │ •subject │ │ •message │
└─────────────────┘ └─────────────────┘ └─────────────────┘
ResolutionSet
The main container for resolution collections with metadata.
metadata
-
A
Metadata
object containing collection information resolutions
-
A collection of
Resolution
objects
Metadata
Contains metadata about the resolution collection.
title
-
The collection title as a string
dates
-
A collection of
ResolutionDate
objects for meeting dates source
-
The source organization as a string
urls
-
A collection of
Url
objects for reference links
ResolutionDate
Represents structured date information with semantic meaning.
kind
-
The type of date as a string
start
-
The start date as a Date object
end
-
The end date as a Date object (optional, for date ranges)
Url
Represents a URL reference with optional title.
href
-
The URL as a string
title
-
The link title as a string (optional)
Resolution
Represents a single formal resolution.
identifier
-
The resolution identifier as a string
title
-
The resolution title as a string
category
-
The resolution category as a string (optional)
subject
-
The subject body as a string (optional)
dates
-
A collection of
ResolutionDate
objects considerations
-
A collection of
Consideration
objects actions
-
A collection of
Action
objects approvals
-
A collection of
Approval
objects
Action
Represents actions taken within a resolution.
type
-
The action type(s). Can be a string or array of strings
dates
-
A collection of
ResolutionDate
objects message
-
The action description as a string
subject
-
The action subject as a string (optional)
Consideration
Represents considerations that lead to a resolution.
type
-
The consideration type as a string
message
-
The consideration description as a string
date_effective
-
The effective date as a Date object (optional)
Approval
Represents approval information for a resolution.
type
-
The approval type as a string
degree
-
The degree of approval as a string (optional)
message
-
The approval message as a string (optional)
Copyright
Copyright Ribose.
License
The gem is available as open source under the terms of the 2-Clause BSD License.