edoxen 0.7.2 → 0.8.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +26 -1
- data/.rubocop_todo.yml +1 -1
- data/CHANGELOG.md +133 -0
- data/README.adoc +414 -182
- data/edoxen.gemspec +10 -10
- data/lib/edoxen/action.rb +5 -4
- data/lib/edoxen/agenda.rb +4 -7
- data/lib/edoxen/agenda_item.rb +18 -5
- data/lib/edoxen/approval.rb +2 -2
- data/lib/edoxen/attendance.rb +16 -10
- data/lib/edoxen/body.rb +26 -0
- data/lib/edoxen/body_register.rb +17 -0
- data/lib/edoxen/body_vocabulary_entry.rb +24 -0
- data/lib/edoxen/body_vocabulary_host.rb +40 -0
- data/lib/edoxen/cli.rb +175 -115
- data/lib/edoxen/consideration.rb +6 -4
- data/lib/edoxen/contact.rb +37 -0
- data/lib/edoxen/contact_identifier.rb +13 -0
- data/lib/edoxen/contact_method.rb +16 -0
- data/lib/edoxen/contact_register.rb +26 -0
- data/lib/edoxen/date_time_range.rb +16 -0
- data/lib/edoxen/deadline.rb +1 -1
- data/lib/edoxen/decision.rb +57 -0
- data/lib/edoxen/decision_collection.rb +10 -0
- data/lib/edoxen/decision_date.rb +9 -0
- data/lib/edoxen/decision_metadata.rb +27 -0
- data/lib/edoxen/decision_relation.rb +11 -0
- data/lib/edoxen/declaration.rb +25 -0
- data/lib/edoxen/entity_ref.rb +74 -0
- data/lib/edoxen/entity_resolver.rb +68 -0
- data/lib/edoxen/enums.rb +123 -9
- data/lib/edoxen/error.rb +1 -1
- data/lib/edoxen/extension_attribute.rb +78 -0
- data/lib/edoxen/host_ref.rb +1 -1
- data/lib/edoxen/link_checker.rb +143 -34
- data/lib/edoxen/localized_name.rb +16 -0
- data/lib/edoxen/localized_string.rb +22 -0
- data/lib/edoxen/meeting.rb +36 -42
- data/lib/edoxen/meeting_collection.rb +1 -2
- data/lib/edoxen/meeting_collection_metadata.rb +4 -2
- data/lib/edoxen/meeting_component.rb +37 -0
- data/lib/edoxen/meeting_extension.rb +25 -0
- data/lib/edoxen/meeting_identifier.rb +1 -1
- data/lib/edoxen/meeting_series.rb +26 -0
- data/lib/edoxen/minutes.rb +3 -4
- data/lib/edoxen/minutes_section.rb +12 -13
- data/lib/edoxen/motion.rb +51 -0
- data/lib/edoxen/name.rb +29 -0
- data/lib/edoxen/officer.rb +19 -0
- data/lib/edoxen/officers_host.rb +19 -0
- data/lib/edoxen/person.rb +5 -9
- data/lib/edoxen/physical_venue.rb +15 -0
- data/lib/edoxen/recurrence.rb +27 -0
- data/lib/edoxen/recurrence_by_day.rb +10 -0
- data/lib/edoxen/reference.rb +1 -1
- data/lib/edoxen/reference_data.rb +34 -44
- data/lib/edoxen/schema_validator.rb +3 -4
- data/lib/edoxen/source_url.rb +4 -4
- data/lib/edoxen/statement.rb +21 -0
- data/lib/edoxen/structured_identifier.rb +2 -2
- data/lib/edoxen/topic.rb +39 -0
- data/lib/edoxen/topic_asset.rb +14 -0
- data/lib/edoxen/topic_document.rb +16 -0
- data/lib/edoxen/urn_for.rb +68 -0
- data/lib/edoxen/venue.rb +81 -0
- data/lib/edoxen/venue_register.rb +18 -0
- data/lib/edoxen/venue_validator.rb +74 -0
- data/lib/edoxen/version.rb +1 -1
- data/lib/edoxen/virtual_venue.rb +15 -0
- data/lib/edoxen/vote_record.rb +17 -13
- data/lib/edoxen/voting.rb +45 -0
- data/lib/edoxen/voting_counts.rb +23 -0
- data/lib/edoxen.rb +51 -15
- data/schema/edoxen.yaml +1427 -246
- data/schema/meeting.yaml +1311 -308
- data/sig/edoxen.rbs +581 -1
- metadata +66 -22
- data/lib/edoxen/_metadata.rb.deprecated +0 -57
- data/lib/edoxen/localization.rb +0 -18
- data/lib/edoxen/location.rb +0 -15
- data/lib/edoxen/meeting_localization.rb +0 -15
- data/lib/edoxen/resolution.rb +0 -43
- data/lib/edoxen/resolution_collection.rb +0 -10
- data/lib/edoxen/resolution_date.rb +0 -11
- data/lib/edoxen/resolution_metadata.rb +0 -30
- data/lib/edoxen/resolution_relation.rb +0 -11
- data/lib/edoxen/resolution_set.rb +0 -17
- data/lib/edoxen/schedule_item.rb +0 -27
- data/lib/edoxen/schedule_item_localization.rb +0 -21
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Edoxen
|
|
4
|
+
# VenueValidator — validates Venue instances using the `unlocodes`
|
|
5
|
+
# and `iata` gems. Returns a list of errors; empty list means valid.
|
|
6
|
+
#
|
|
7
|
+
# For a Venue with `kind: "physical"`, validates that any populated
|
|
8
|
+
# `unlocode` and `iata_code` exist in the canonical registries.
|
|
9
|
+
#
|
|
10
|
+
# `valid?` and `validate` are pure queries — they do not mutate the
|
|
11
|
+
# venue. Callers who want city/country_code back-filled from the
|
|
12
|
+
# UN/LOCODE registry use `populate_from_registry!`, a separate,
|
|
13
|
+
# explicitly-mutating method.
|
|
14
|
+
class VenueValidator
|
|
15
|
+
attr_reader :venue, :errors
|
|
16
|
+
|
|
17
|
+
def initialize(venue)
|
|
18
|
+
@venue = venue
|
|
19
|
+
@errors = []
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Pure query. Populates `errors` and returns it; does not modify
|
|
23
|
+
# the venue.
|
|
24
|
+
def validate
|
|
25
|
+
errors.clear
|
|
26
|
+
validate_physical if venue.physical?
|
|
27
|
+
errors
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Pure boolean wrapper around `validate`.
|
|
31
|
+
def valid?
|
|
32
|
+
validate
|
|
33
|
+
errors.empty?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Mutator: back-fill `venue.city` and `venue.country_code` from the
|
|
37
|
+
# UN/LOCODE entry. Raises `KeyError` when the unlocode is unknown
|
|
38
|
+
# or unset, so callers do not silently leave the venue untouched.
|
|
39
|
+
#
|
|
40
|
+
# Returns the venue (so callers can chain).
|
|
41
|
+
def populate_from_registry!
|
|
42
|
+
raise KeyError, "populate_from_registry! requires kind: physical" unless venue.physical?
|
|
43
|
+
raise KeyError, "populate_from_registry! requires unlocode" if venue.unlocode.nil? || venue.unlocode.to_s.empty?
|
|
44
|
+
|
|
45
|
+
entry = Edoxen::ReferenceData.find_unlocode(venue.unlocode)
|
|
46
|
+
raise KeyError, "Unknown UN/LOCODE: #{venue.unlocode}" if entry.nil?
|
|
47
|
+
|
|
48
|
+
venue.city ||= entry.name
|
|
49
|
+
venue.country_code ||= entry.country
|
|
50
|
+
venue
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def validate_physical
|
|
56
|
+
validate_unlocode if venue.unlocode && !venue.unlocode.to_s.empty?
|
|
57
|
+
validate_iata_code if venue.iata_code && !venue.iata_code.to_s.empty?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def validate_unlocode
|
|
61
|
+
entry = Edoxen::ReferenceData.find_unlocode(venue.unlocode)
|
|
62
|
+
return if entry
|
|
63
|
+
|
|
64
|
+
errors << "Unknown UN/LOCODE: #{venue.unlocode}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def validate_iata_code
|
|
68
|
+
entry = Edoxen::ReferenceData.find_iata(venue.iata_code)
|
|
69
|
+
return if entry
|
|
70
|
+
|
|
71
|
+
errors << "Unknown IATA code: #{venue.iata_code}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
data/lib/edoxen/version.rb
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Edoxen
|
|
4
|
+
# VirtualVenue — type marker for a Venue with kind == "virtual".
|
|
5
|
+
#
|
|
6
|
+
# The wire format is flat on Venue (all fields live there). This
|
|
7
|
+
# subclass exists for type-checking and to host virtual-only helpers
|
|
8
|
+
# so callers can ask `venue.is_a?(VirtualVenue)` and validators
|
|
9
|
+
# can dispatch by type.
|
|
10
|
+
class VirtualVenue < Venue
|
|
11
|
+
def initialize(attributes = {})
|
|
12
|
+
super(attributes.merge(kind: "virtual"))
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/edoxen/vote_record.rb
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Edoxen
|
|
4
|
-
# A single vote on a
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
4
|
+
# A single vote on a Decision, recorded against the Voting instance
|
|
5
|
+
# that captured it. `voting_ref` links to the Voting URN; `decision_ref`
|
|
6
|
+
# links to the Decision URN (often derivable from the Voting's motion,
|
|
7
|
+
# but explicit for clarity).
|
|
8
|
+
#
|
|
9
|
+
# `role` is open for adopter-defined values: teller (parliamentary
|
|
10
|
+
# division counter), proxy_holder, observer, etc.
|
|
10
11
|
class VoteRecord < Lutaml::Model::Serializable
|
|
11
|
-
attribute :
|
|
12
|
+
attribute :decision_ref, :string
|
|
13
|
+
attribute :voting_ref, :string
|
|
12
14
|
attribute :person, Person
|
|
13
15
|
attribute :affiliation, :string
|
|
14
16
|
attribute :vote, :string, values: Enums::VOTE_TYPE
|
|
17
|
+
attribute :role, :string
|
|
15
18
|
attribute :notes, :string
|
|
19
|
+
attribute :extensions, MeetingExtension, collection: true
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
def affirmative?
|
|
22
|
+
vote == "affirmative"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def teller?
|
|
26
|
+
role == "teller"
|
|
23
27
|
end
|
|
24
28
|
end
|
|
25
29
|
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Edoxen
|
|
4
|
+
# Voting — state machine for a single vote on a Motion.
|
|
5
|
+
# Multiple votings can occur on the same Motion (e.g., unclear voice
|
|
6
|
+
# vote → chair calls a formal division → second Voting instance).
|
|
7
|
+
#
|
|
8
|
+
# State machine (VotingStatus):
|
|
9
|
+
# called → in_progress → decided | withdrawn | deferred
|
|
10
|
+
class Voting < Lutaml::Model::Serializable
|
|
11
|
+
attribute :identifier, :string
|
|
12
|
+
attribute :urn, :string
|
|
13
|
+
attribute :on_motion, :string
|
|
14
|
+
attribute :status, :string, values: Enums::VOTING_STATUS
|
|
15
|
+
attribute :voting_method, :string, values: Enums::VOTING_METHOD
|
|
16
|
+
attribute :called_by, Person
|
|
17
|
+
attribute :called_at, :date_time
|
|
18
|
+
attribute :result_declared_at, :date_time
|
|
19
|
+
attribute :result, :string, values: Enums::VOTING_OUTCOME
|
|
20
|
+
attribute :counts, VotingCounts
|
|
21
|
+
attribute :casting_vote, VoteRecord
|
|
22
|
+
attribute :vote_records, VoteRecord, collection: true
|
|
23
|
+
attribute :extensions, MeetingExtension, collection: true
|
|
24
|
+
|
|
25
|
+
def decided?
|
|
26
|
+
status == "decided"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def in_progress?
|
|
30
|
+
status == "in_progress"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def passed?
|
|
34
|
+
decided? && result == "passed"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def negatived?
|
|
38
|
+
decided? && result == "negatived"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def tied?
|
|
42
|
+
decided? && result == "tied"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Edoxen
|
|
4
|
+
# VotingCounts — tally for a Voting instance.
|
|
5
|
+
class VotingCounts < Lutaml::Model::Serializable
|
|
6
|
+
attribute :ayes, :integer
|
|
7
|
+
attribute :noes, :integer
|
|
8
|
+
attribute :abstentions, :integer
|
|
9
|
+
attribute :absent, :integer
|
|
10
|
+
|
|
11
|
+
def total
|
|
12
|
+
(ayes || 0) + (noes || 0) + (abstentions || 0) + (absent || 0)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def margin
|
|
16
|
+
(ayes || 0) - (noes || 0)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def tied?
|
|
20
|
+
ayes == noes
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/edoxen.rb
CHANGED
|
@@ -18,36 +18,42 @@ module Edoxen
|
|
|
18
18
|
# There are intentionally NO `require_relative` calls in this gem —
|
|
19
19
|
# autoload keeps load-order semantics clean and lets us tolerate the
|
|
20
20
|
# extensive cross-references between model classes
|
|
21
|
-
# (
|
|
21
|
+
# (Decision <-> Localization, DecisionMetadata <-> Localization, etc.).
|
|
22
22
|
autoload :VERSION, "edoxen/version"
|
|
23
23
|
autoload :Error, "edoxen/error"
|
|
24
24
|
autoload :ValidationError, "edoxen/error"
|
|
25
25
|
autoload :Enums, "edoxen/enums"
|
|
26
26
|
autoload :ReferenceData, "edoxen/reference_data"
|
|
27
27
|
|
|
28
|
-
#
|
|
29
|
-
|
|
28
|
+
# --- Shared behaviours (mixed into entity + metadata classes) --------
|
|
29
|
+
autoload :OfficersHost, "edoxen/officers_host"
|
|
30
|
+
autoload :BodyVocabularyHost, "edoxen/body_vocabulary_host"
|
|
31
|
+
|
|
32
|
+
# --- Decision side ----------------------------------------------------
|
|
30
33
|
autoload :StructuredIdentifier, "edoxen/structured_identifier"
|
|
31
34
|
autoload :MeetingIdentifier, "edoxen/meeting_identifier"
|
|
32
|
-
autoload :
|
|
35
|
+
autoload :DecisionDate, "edoxen/decision_date"
|
|
33
36
|
autoload :Action, "edoxen/action"
|
|
34
37
|
autoload :Approval, "edoxen/approval"
|
|
35
38
|
autoload :Consideration, "edoxen/consideration"
|
|
36
39
|
autoload :SourceUrl, "edoxen/source_url"
|
|
37
|
-
autoload :Localization, "edoxen/localization"
|
|
38
40
|
autoload :Url, "edoxen/url"
|
|
39
|
-
autoload :
|
|
40
|
-
autoload :
|
|
41
|
-
autoload :
|
|
42
|
-
autoload :
|
|
41
|
+
autoload :UrnFor, "edoxen/urn_for"
|
|
42
|
+
autoload :DecisionRelation, "edoxen/decision_relation"
|
|
43
|
+
autoload :Decision, "edoxen/decision"
|
|
44
|
+
autoload :DecisionMetadata, "edoxen/decision_metadata"
|
|
45
|
+
autoload :DecisionCollection, "edoxen/decision_collection"
|
|
43
46
|
|
|
44
|
-
# Meeting
|
|
47
|
+
# --- Meeting/Agenda side ----------------------------------------------
|
|
45
48
|
autoload :DateRange, "edoxen/date_range"
|
|
46
|
-
autoload :
|
|
49
|
+
autoload :ContactMethod, "edoxen/contact_method"
|
|
50
|
+
autoload :ContactIdentifier, "edoxen/contact_identifier"
|
|
51
|
+
autoload :Name, "edoxen/name"
|
|
52
|
+
autoload :Contact, "edoxen/contact"
|
|
53
|
+
autoload :LocalizedString, "edoxen/localized_string"
|
|
54
|
+
autoload :LocalizedName, "edoxen/localized_name"
|
|
47
55
|
autoload :Person, "edoxen/person"
|
|
48
56
|
autoload :HostRef, "edoxen/host_ref"
|
|
49
|
-
autoload :ScheduleItemLocalization, "edoxen/schedule_item_localization"
|
|
50
|
-
autoload :ScheduleItem, "edoxen/schedule_item"
|
|
51
57
|
autoload :Deadline, "edoxen/deadline"
|
|
52
58
|
autoload :Reference, "edoxen/reference"
|
|
53
59
|
autoload :AgendaItem, "edoxen/agenda_item"
|
|
@@ -57,13 +63,43 @@ module Edoxen
|
|
|
57
63
|
autoload :MinutesSection, "edoxen/minutes_section"
|
|
58
64
|
autoload :Minutes, "edoxen/minutes"
|
|
59
65
|
autoload :MeetingRelation, "edoxen/meeting_relation"
|
|
60
|
-
autoload :MeetingLocalization, "edoxen/meeting_localization"
|
|
61
66
|
autoload :Meeting, "edoxen/meeting"
|
|
62
67
|
autoload :MeetingCollectionMetadata, "edoxen/meeting_collection_metadata"
|
|
63
68
|
autoload :MeetingCollection, "edoxen/meeting_collection"
|
|
64
69
|
|
|
65
|
-
#
|
|
70
|
+
# --- BS 0:2006 meeting-minutes concepts --------------------------------
|
|
71
|
+
autoload :Statement, "edoxen/statement"
|
|
72
|
+
autoload :Declaration, "edoxen/declaration"
|
|
73
|
+
autoload :DateTimeRange, "edoxen/date_time_range"
|
|
74
|
+
|
|
75
|
+
# --- v2 broadened-scope entities --------------------------------------
|
|
76
|
+
autoload :ExtensionAttribute, "edoxen/extension_attribute"
|
|
77
|
+
autoload :MeetingExtension, "edoxen/meeting_extension"
|
|
78
|
+
autoload :BodyVocabularyEntry, "edoxen/body_vocabulary_entry"
|
|
79
|
+
autoload :EntityRef, "edoxen/entity_ref"
|
|
80
|
+
autoload :Venue, "edoxen/venue"
|
|
81
|
+
autoload :PhysicalVenue, "edoxen/physical_venue"
|
|
82
|
+
autoload :VirtualVenue, "edoxen/virtual_venue"
|
|
83
|
+
autoload :Motion, "edoxen/motion"
|
|
84
|
+
autoload :VotingCounts, "edoxen/voting_counts"
|
|
85
|
+
autoload :Voting, "edoxen/voting"
|
|
86
|
+
autoload :TopicDocument, "edoxen/topic_document"
|
|
87
|
+
autoload :TopicAsset, "edoxen/topic_asset"
|
|
88
|
+
autoload :Topic, "edoxen/topic"
|
|
89
|
+
autoload :RecurrenceByDay, "edoxen/recurrence_by_day"
|
|
90
|
+
autoload :Recurrence, "edoxen/recurrence"
|
|
91
|
+
autoload :MeetingSeries, "edoxen/meeting_series"
|
|
92
|
+
autoload :MeetingComponent, "edoxen/meeting_component"
|
|
93
|
+
autoload :Officer, "edoxen/officer"
|
|
94
|
+
autoload :VenueValidator, "edoxen/venue_validator"
|
|
95
|
+
autoload :ContactRegister, "edoxen/contact_register"
|
|
96
|
+
autoload :VenueRegister, "edoxen/venue_register"
|
|
97
|
+
autoload :Body, "edoxen/body"
|
|
98
|
+
autoload :BodyRegister, "edoxen/body_register"
|
|
99
|
+
|
|
100
|
+
# --- Services ---------------------------------------------------------
|
|
66
101
|
autoload :SchemaValidator, "edoxen/schema_validator"
|
|
67
102
|
autoload :LinkChecker, "edoxen/link_checker"
|
|
103
|
+
autoload :EntityResolver, "edoxen/entity_resolver"
|
|
68
104
|
autoload :Cli, "edoxen/cli"
|
|
69
105
|
end
|