edoxen 0.3.0 → 0.5.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +24 -10
  3. data/README.adoc +170 -31
  4. data/TODO.meeting-agenda/01-design-decisions.md +132 -0
  5. data/TODO.meeting-agenda/02-lutaml-canonical.md +61 -0
  6. data/TODO.meeting-agenda/03-ruby-models.md +73 -0
  7. data/TODO.meeting-agenda/04-schema.md +34 -0
  8. data/TODO.meeting-agenda/05-fixtures.md +43 -0
  9. data/TODO.meeting-agenda/06-specs.md +52 -0
  10. data/TODO.meeting-agenda/07-cli.md +55 -0
  11. data/TODO.meeting-agenda/08-docs.md +35 -0
  12. data/TODO.meeting-agenda/09-verify-and-release.md +41 -0
  13. data/TODO.meeting-agenda/10-future-enhancements.md +72 -0
  14. data/TODO.meeting-agenda/README.md +30 -0
  15. data/lib/edoxen/action.rb +0 -6
  16. data/lib/edoxen/agenda.rb +26 -0
  17. data/lib/edoxen/agenda_item.rb +17 -0
  18. data/lib/edoxen/approval.rb +0 -7
  19. data/lib/edoxen/cli.rb +199 -95
  20. data/lib/edoxen/consideration.rb +0 -6
  21. data/lib/edoxen/date_range.rb +11 -0
  22. data/lib/edoxen/deadline.rb +10 -0
  23. data/lib/edoxen/enums.rb +24 -0
  24. data/lib/edoxen/error.rb +32 -2
  25. data/lib/edoxen/host_ref.rb +14 -0
  26. data/lib/edoxen/localization.rb +0 -12
  27. data/lib/edoxen/location.rb +15 -0
  28. data/lib/edoxen/meeting.rb +68 -0
  29. data/lib/edoxen/meeting_collection.rb +26 -0
  30. data/lib/edoxen/meeting_collection_metadata.rb +11 -0
  31. data/lib/edoxen/meeting_identifier.rb +0 -5
  32. data/lib/edoxen/meeting_localization.rb +15 -0
  33. data/lib/edoxen/meeting_relation.rb +12 -0
  34. data/lib/edoxen/person.rb +14 -0
  35. data/lib/edoxen/reference.rb +13 -0
  36. data/lib/edoxen/resolution.rb +21 -12
  37. data/lib/edoxen/resolution_collection.rb +0 -5
  38. data/lib/edoxen/resolution_date.rb +0 -5
  39. data/lib/edoxen/resolution_metadata.rb +5 -9
  40. data/lib/edoxen/resolution_relation.rb +0 -6
  41. data/lib/edoxen/schedule_item.rb +16 -0
  42. data/lib/edoxen/schema_validator.rb +12 -28
  43. data/lib/edoxen/source_url.rb +6 -8
  44. data/lib/edoxen/structured_identifier.rb +0 -5
  45. data/lib/edoxen/url.rb +0 -6
  46. data/lib/edoxen/version.rb +1 -1
  47. data/lib/edoxen.rb +17 -0
  48. data/schema/edoxen.yaml +7 -0
  49. data/schema/meeting.yaml +358 -0
  50. metadata +27 -2
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Edoxen
4
+ # Identity + role + affiliation + contact. Used for meeting officers
5
+ # (chair, secretary, local contact) and host-ref contacts.
6
+ class Person < Lutaml::Model::Serializable
7
+ attribute :name, :string
8
+ attribute :role, :string
9
+ attribute :affiliation, :string
10
+ attribute :email, :string
11
+ attribute :phone, :string
12
+ attribute :orcid, :string
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Edoxen
4
+ # Generic document reference (used by AgendaItem.references). `kind`
5
+ # is a free-form discriminator (e.g., "standard", "document",
6
+ # "ballot", "resolution"); the schema leaves it open deliberately so
7
+ # new reference kinds need no schema change.
8
+ class Reference < Lutaml::Model::Serializable
9
+ attribute :ref, :string
10
+ attribute :kind, :string
11
+ attribute :title, :string
12
+ end
13
+ end
@@ -4,6 +4,11 @@ module Edoxen
4
4
  # A formal Resolution. Language-agnostic admin fields live here; every
5
5
  # translatable field is wrapped inside `localizations[]` (one entry per
6
6
  # available language; at least one is required by the schema).
7
+ #
8
+ # Wire names follow lutaml-model's default convention: each declared
9
+ # attribute serializes to its snake_case name on the wire. Override
10
+ # with an explicit `key_value do; map "wire", to: :attr; end` block
11
+ # only when the wire name differs.
7
12
  class Resolution < Lutaml::Model::Serializable
8
13
  attribute :identifier, StructuredIdentifier, collection: true
9
14
  attribute :type, :string, values: Enums::RESOLUTION_TYPE
@@ -17,18 +22,22 @@ module Edoxen
17
22
  attribute :urls, Url, collection: true
18
23
  attribute :localizations, Localization, collection: true
19
24
 
20
- key_value do
21
- map "identifier", to: :identifier
22
- map "type", to: :type
23
- map "doi", to: :doi
24
- map "urn", to: :urn
25
- map "agenda_item", to: :agenda_item
26
- map "dates", to: :dates
27
- map "categories", to: :categories
28
- map "meeting", to: :meeting
29
- map "relations", to: :relations
30
- map "urls", to: :urls
31
- map "localizations", to: :localizations
25
+ # Lookup by ISO 639-3 language code. Returns nil when no exact match
26
+ # exists and `fallback:` is false (the default); returns the first
27
+ # localization otherwise. Keeps the language-preference policy in
28
+ # one place so callers stop reimplementing `find { |l| ... }`.
29
+ def in_language(code, fallback: false)
30
+ match = localizations&.find { |loc| loc.language_code == code.to_s }
31
+ return match if match
32
+
33
+ fallback ? localizations&.first : nil
34
+ end
35
+
36
+ # The canonical rendering — English when available, else the first
37
+ # declared localization. Mirrors the glossarist LocalizedConcept
38
+ # "preferred language" notion.
39
+ def primary_localization
40
+ in_language("eng", fallback: true)
32
41
  end
33
42
  end
34
43
  end
@@ -6,10 +6,5 @@ module Edoxen
6
6
  class ResolutionCollection < Lutaml::Model::Serializable
7
7
  attribute :metadata, ResolutionMetadata
8
8
  attribute :resolutions, Resolution, collection: true
9
-
10
- key_value do
11
- map "metadata", to: :metadata
12
- map "resolutions", to: :resolutions
13
- end
14
9
  end
15
10
  end
@@ -7,10 +7,5 @@ module Edoxen
7
7
  class ResolutionDate < Lutaml::Model::Serializable
8
8
  attribute :date, :date
9
9
  attribute :type, :string, values: Enums::RESOLUTION_DATE_TYPE
10
-
11
- key_value do
12
- map "date", to: :date
13
- map "type", to: :type
14
- end
15
10
  end
16
11
  end
@@ -13,14 +13,10 @@ module Edoxen
13
13
  attribute :city, :string
14
14
  attribute :country_code, :string
15
15
 
16
- key_value do
17
- map "title", to: :title
18
- map "title_localized", to: :title_localized
19
- map "date", to: :date
20
- map "source", to: :source
21
- map "source_urls", to: :source_urls
22
- map "city", to: :city
23
- map "country_code", to: :country_code
24
- end
16
+ # URN back-reference to the Meeting that produced this collection.
17
+ # Join key for the Meeting ↔ ResolutionCollection link. Optional —
18
+ # collections without a parent meeting (e.g., ad-hoc resolution
19
+ # sets) simply omit it.
20
+ attribute :meeting_urn, :string
25
21
  end
26
22
  end
@@ -7,11 +7,5 @@ module Edoxen
7
7
  attribute :source, StructuredIdentifier
8
8
  attribute :destination, StructuredIdentifier
9
9
  attribute :type, :string, values: Enums::RESOLUTION_RELATION_TYPE
10
-
11
- key_value do
12
- map "source", to: :source
13
- map "destination", to: :destination
14
- map "type", to: :type
15
- end
16
10
  end
17
11
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Edoxen
4
+ # One entry in a meeting timetable. Structural fields (date, time,
5
+ # room) are language-agnostic; descriptive fields (event,
6
+ # description) live here as plain strings in v1 — see
7
+ # TODO.meeting-agenda/10-future-enhancements.md P2.1 for per-item
8
+ # localization.
9
+ class ScheduleItem < Lutaml::Model::Serializable
10
+ attribute :date, :date
11
+ attribute :time, :string
12
+ attribute :event, :string
13
+ attribute :description, :string
14
+ attribute :room, :string
15
+ end
16
+ end
@@ -21,46 +21,28 @@ module Edoxen
21
21
  # hard-coded path shapes) so adding new collection fields never requires
22
22
  # touching this class.
23
23
  class SchemaValidator
24
- class ValidationError < StandardError
25
- attr_reader :file, :line, :column, :pointer, :message_text
26
-
27
- def initialize(file:, line:, column:, pointer:, message_text:)
28
- @file = file
29
- @line = line
30
- @column = column
31
- @pointer = pointer
32
- @message_text = message_text
33
- super(format_line(file, line, column, message_text, pointer))
34
- end
35
-
36
- def to_clickable_format
37
- format_line(@file, @line, @column, @message_text, @pointer)
38
- end
39
-
40
- private
41
-
42
- def format_line(file, line, column, message_text, pointer)
43
- suffix = pointer.to_s.empty? ? "" : " at `#{pointer}`"
44
- "#{file}:#{line}:#{column}: #{message_text}#{suffix}"
45
- end
46
- end
24
+ # Back-compat alias. The canonical type is Edoxen::ValidationError;
25
+ # this constant lets existing callers keep writing
26
+ # `SchemaValidator::ValidationError` after the unification.
27
+ ValidationError = Edoxen::ValidationError
47
28
 
48
29
  def initialize(schema_path = default_schema_path)
49
30
  @schema_path = schema_path
50
31
  @schemer = load_schemer(schema_path)
51
32
  end
52
33
 
53
- # Validate a YAML file. Returns an array of ValidationError (empty = ok).
34
+ # Validate a YAML file. Returns an array of Edoxen::ValidationError
35
+ # (empty = ok).
54
36
  def validate_file(file_path)
55
37
  validate_content(File.read(file_path), file_path)
56
38
  rescue Errno::ENOENT
57
39
  [ValidationError.new(
58
40
  file: file_path, line: 1, column: 1,
59
- pointer: "", message_text: "File not found"
41
+ message_text: "File not found", source: Edoxen::ValidationError::SOURCE_SCHEMA
60
42
  )]
61
43
  end
62
44
 
63
- # Validate a YAML string. Returns an array of ValidationError.
45
+ # Validate a YAML string. Returns an array of Edoxen::ValidationError.
64
46
  def validate_content(content, file_path)
65
47
  data = normalize_dates(YAML.safe_load(content, permitted_classes: [Date, Time]))
66
48
  line_map = LineMap.build(content)
@@ -71,13 +53,15 @@ module Edoxen
71
53
  line, column = LineMap.locate(pointer, line_map)
72
54
  ValidationError.new(
73
55
  file: file_path, line: line, column: column,
74
- pointer: pointer, message_text: message
56
+ message_text: message, pointer: pointer,
57
+ source: Edoxen::ValidationError::SOURCE_SCHEMA
75
58
  )
76
59
  end
77
60
  rescue Psych::SyntaxError => e
78
61
  [ValidationError.new(
79
62
  file: file_path, line: e.line || 1, column: e.column || 1,
80
- pointer: "", message_text: "YAML syntax error: #{e.problem}"
63
+ message_text: "YAML syntax error: #{e.problem}",
64
+ source: Edoxen::ValidationError::SOURCE_SYNTAX
81
65
  )]
82
66
  end
83
67
 
@@ -2,17 +2,15 @@
2
2
 
3
3
  module Edoxen
4
4
  # Per-language canonical source URL (e.g. one PDF per language).
5
- # Carries the URL ref, its format, and the ISO 639-3 language_code the URL
6
- # is the canonical source for.
5
+ # Carries the URL ref, its format, the ISO 639-3 language_code the URL
6
+ # is the canonical source for, and an optional `kind` discriminator
7
+ # (agenda_pdf, minutes_pdf, resolutions_pdf, ...) used by the Meeting
8
+ # model. Existing Resolution fixtures without `kind` still parse —
9
+ # the field is optional.
7
10
  class SourceUrl < Lutaml::Model::Serializable
8
11
  attribute :ref, :string
9
12
  attribute :format, :string
10
13
  attribute :language_code, :string
11
-
12
- key_value do
13
- map "ref", to: :ref
14
- map "format", to: :format
15
- map "language_code", to: :language_code
16
- end
14
+ attribute :kind, :string, values: Enums::SOURCE_URL_KIND
17
15
  end
18
16
  end
@@ -8,10 +8,5 @@ module Edoxen
8
8
  class StructuredIdentifier < Lutaml::Model::Serializable
9
9
  attribute :prefix, :string
10
10
  attribute :number, :string
11
-
12
- key_value do
13
- map "prefix", to: :prefix
14
- map "number", to: :number
15
- end
16
11
  end
17
12
  end
data/lib/edoxen/url.rb CHANGED
@@ -6,11 +6,5 @@ module Edoxen
6
6
  attribute :kind, :string, values: Enums::URL_KIND
7
7
  attribute :ref, :string
8
8
  attribute :format, :string
9
-
10
- key_value do
11
- map "kind", to: :kind
12
- map "ref", to: :ref
13
- map "format", to: :format
14
- end
15
9
  end
16
10
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Edoxen
4
- VERSION = "0.3.0"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/edoxen.rb CHANGED
@@ -21,6 +21,7 @@ module Edoxen
21
21
  # (Resolution <-> Localization, ResolutionMetadata <-> Localization, etc.).
22
22
  autoload :VERSION, "edoxen/version"
23
23
  autoload :Error, "edoxen/error"
24
+ autoload :ValidationError, "edoxen/error"
24
25
  autoload :Enums, "edoxen/enums"
25
26
 
26
27
  # Information-model classes (one per file, one concept per class).
@@ -39,6 +40,22 @@ module Edoxen
39
40
  autoload :ResolutionMetadata, "edoxen/resolution_metadata"
40
41
  autoload :ResolutionCollection, "edoxen/resolution_collection"
41
42
 
43
+ # Meeting / Agenda side. Mirrors edoxen-model/models/meeting*.lutaml.
44
+ autoload :DateRange, "edoxen/date_range"
45
+ autoload :Location, "edoxen/location"
46
+ autoload :Person, "edoxen/person"
47
+ autoload :HostRef, "edoxen/host_ref"
48
+ autoload :ScheduleItem, "edoxen/schedule_item"
49
+ autoload :Deadline, "edoxen/deadline"
50
+ autoload :Reference, "edoxen/reference"
51
+ autoload :AgendaItem, "edoxen/agenda_item"
52
+ autoload :Agenda, "edoxen/agenda"
53
+ autoload :MeetingRelation, "edoxen/meeting_relation"
54
+ autoload :MeetingLocalization, "edoxen/meeting_localization"
55
+ autoload :Meeting, "edoxen/meeting"
56
+ autoload :MeetingCollectionMetadata, "edoxen/meeting_collection_metadata"
57
+ autoload :MeetingCollection, "edoxen/meeting_collection"
58
+
42
59
  # Services.
43
60
  autoload :SchemaValidator, "edoxen/schema_validator"
44
61
  autoload :Cli, "edoxen/cli"
data/schema/edoxen.yaml CHANGED
@@ -207,6 +207,10 @@ $defs:
207
207
  language_code:
208
208
  type: string
209
209
  pattern: "^[a-z]{3}$"
210
+ kind:
211
+ type: string
212
+ description: "Optional discriminator (agenda_pdf, minutes_pdf, ...)."
213
+ enum: [agenda_pdf, minutes_pdf, resolutions_pdf, report_pdf, register_url, landing_page]
210
214
 
211
215
  # ====================================================================
212
216
  # Top-level structures.
@@ -289,6 +293,9 @@ $defs:
289
293
  country_code:
290
294
  type: string
291
295
  description: "ISO 3166-1 alpha-2 country code (2-letter, e.g. DE, FR, JP) of the host country."
296
+ meeting_urn:
297
+ type: string
298
+ description: "URN back-reference to the Meeting that produced this collection."
292
299
 
293
300
  # ====================================================================
294
301
  # Enums. Each is referenced by its $ref name above. The schema