lenex-parser 3.0.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.
- checksums.yaml +7 -0
- data/.rubocop.yml +21 -0
- data/.yardopts +2 -0
- data/LICENSE +21 -0
- data/README.md +796 -0
- data/Rakefile +43 -0
- data/bin/console +8 -0
- data/bin/setup +5 -0
- data/lenex-parser.gemspec +35 -0
- data/lib/lenex/document/serializer.rb +191 -0
- data/lib/lenex/document.rb +163 -0
- data/lib/lenex/parser/objects/age_date.rb +53 -0
- data/lib/lenex/parser/objects/age_group.rb +86 -0
- data/lib/lenex/parser/objects/athlete.rb +93 -0
- data/lib/lenex/parser/objects/bank.rb +56 -0
- data/lib/lenex/parser/objects/club.rb +101 -0
- data/lib/lenex/parser/objects/constructor.rb +51 -0
- data/lib/lenex/parser/objects/contact.rb +55 -0
- data/lib/lenex/parser/objects/entry.rb +70 -0
- data/lib/lenex/parser/objects/entry_schedule.rb +40 -0
- data/lib/lenex/parser/objects/event.rb +114 -0
- data/lib/lenex/parser/objects/facility.rb +58 -0
- data/lib/lenex/parser/objects/fee.rb +54 -0
- data/lib/lenex/parser/objects/fee_schedule.rb +26 -0
- data/lib/lenex/parser/objects/handicap.rb +86 -0
- data/lib/lenex/parser/objects/heat.rb +58 -0
- data/lib/lenex/parser/objects/host_club.rb +34 -0
- data/lib/lenex/parser/objects/judge.rb +55 -0
- data/lib/lenex/parser/objects/lenex.rb +72 -0
- data/lib/lenex/parser/objects/meet.rb +175 -0
- data/lib/lenex/parser/objects/meet_info.rb +60 -0
- data/lib/lenex/parser/objects/official.rb +70 -0
- data/lib/lenex/parser/objects/organizer.rb +34 -0
- data/lib/lenex/parser/objects/point_table.rb +54 -0
- data/lib/lenex/parser/objects/pool.rb +44 -0
- data/lib/lenex/parser/objects/qualify.rb +55 -0
- data/lib/lenex/parser/objects/ranking.rb +54 -0
- data/lib/lenex/parser/objects/record.rb +107 -0
- data/lib/lenex/parser/objects/record_athlete.rb +92 -0
- data/lib/lenex/parser/objects/record_list.rb +106 -0
- data/lib/lenex/parser/objects/record_relay.rb +62 -0
- data/lib/lenex/parser/objects/record_relay_position.rb +62 -0
- data/lib/lenex/parser/objects/relay.rb +93 -0
- data/lib/lenex/parser/objects/relay_entry.rb +81 -0
- data/lib/lenex/parser/objects/relay_position.rb +74 -0
- data/lib/lenex/parser/objects/relay_result.rb +85 -0
- data/lib/lenex/parser/objects/result.rb +76 -0
- data/lib/lenex/parser/objects/session.rb +107 -0
- data/lib/lenex/parser/objects/split.rb +53 -0
- data/lib/lenex/parser/objects/swim_style.rb +58 -0
- data/lib/lenex/parser/objects/time_standard.rb +55 -0
- data/lib/lenex/parser/objects/time_standard_list.rb +98 -0
- data/lib/lenex/parser/objects/time_standard_ref.rb +63 -0
- data/lib/lenex/parser/objects.rb +52 -0
- data/lib/lenex/parser/sax/document_handler.rb +184 -0
- data/lib/lenex/parser/version.rb +8 -0
- data/lib/lenex/parser/zip_source.rb +111 -0
- data/lib/lenex/parser.rb +184 -0
- data/lib/lenex-parser.rb +16 -0
- metadata +132 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a RELAY element.
|
|
7
|
+
class Relay
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'agemax' => { key: :age_max, required: true },
|
|
10
|
+
'agemin' => { key: :age_min, required: true },
|
|
11
|
+
'agetotalmax' => { key: :age_total_max, required: true },
|
|
12
|
+
'agetotalmin' => { key: :age_total_min, required: true },
|
|
13
|
+
'gender' => { key: :gender, required: true },
|
|
14
|
+
'handicap' => { key: :handicap, required: false },
|
|
15
|
+
'name' => { key: :name, required: false },
|
|
16
|
+
'number' => { key: :number, required: false }
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
20
|
+
private_constant :ATTRIBUTE_KEYS
|
|
21
|
+
|
|
22
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
23
|
+
attr_reader :relay_positions, :entries, :results
|
|
24
|
+
|
|
25
|
+
def initialize(relay_positions: [], entries: [], results: [], **attributes)
|
|
26
|
+
ATTRIBUTES.each_value do |definition|
|
|
27
|
+
key = definition[:key]
|
|
28
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
29
|
+
end
|
|
30
|
+
@relay_positions = Array(relay_positions)
|
|
31
|
+
@entries = Array(entries)
|
|
32
|
+
@results = Array(results)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.from_xml(element)
|
|
36
|
+
raise ::Lenex::Parser::ParseError, 'RELAY element is required' unless element
|
|
37
|
+
|
|
38
|
+
attributes = extract_attributes(element)
|
|
39
|
+
relay_positions = extract_relay_positions(element.at_xpath('RELAYPOSITIONS'))
|
|
40
|
+
entries = extract_entries(element.at_xpath('ENTRIES'))
|
|
41
|
+
results = extract_results(element.at_xpath('RESULTS'))
|
|
42
|
+
|
|
43
|
+
new(**attributes, relay_positions:, entries:, results:)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.extract_attributes(element)
|
|
47
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
48
|
+
value = element.attribute(attribute_name)&.value
|
|
49
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
50
|
+
collected[definition[:key]] = value if value
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
private_class_method :extract_attributes
|
|
54
|
+
|
|
55
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
56
|
+
return unless definition[:required]
|
|
57
|
+
return unless value.nil? || value.strip.empty?
|
|
58
|
+
|
|
59
|
+
message = "RELAY #{attribute_name} attribute is required"
|
|
60
|
+
raise ::Lenex::Parser::ParseError, message
|
|
61
|
+
end
|
|
62
|
+
private_class_method :ensure_required_attribute!
|
|
63
|
+
|
|
64
|
+
def self.extract_relay_positions(collection_element)
|
|
65
|
+
return [] unless collection_element
|
|
66
|
+
|
|
67
|
+
collection_element.xpath('RELAYPOSITION').map do |position_element|
|
|
68
|
+
RelayPosition.from_xml(position_element)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
private_class_method :extract_relay_positions
|
|
72
|
+
|
|
73
|
+
def self.extract_entries(collection_element)
|
|
74
|
+
return [] unless collection_element
|
|
75
|
+
|
|
76
|
+
collection_element.xpath('ENTRY').map do |entry_element|
|
|
77
|
+
RelayEntry.from_xml(entry_element)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
private_class_method :extract_entries
|
|
81
|
+
|
|
82
|
+
def self.extract_results(collection_element)
|
|
83
|
+
return [] unless collection_element
|
|
84
|
+
|
|
85
|
+
collection_element.xpath('RESULT').map do |result_element|
|
|
86
|
+
RelayResult.from_xml(result_element)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
private_class_method :extract_results
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a relay ENTRY element.
|
|
7
|
+
class RelayEntry
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'agegroupid' => { key: :age_group_id, required: false },
|
|
10
|
+
'entrycourse' => { key: :entry_course, required: false },
|
|
11
|
+
'entrydistance' => { key: :entry_distance, required: false },
|
|
12
|
+
'entrytime' => { key: :entry_time, required: false },
|
|
13
|
+
'eventid' => { key: :event_id, required: true },
|
|
14
|
+
'handicap' => { key: :handicap, required: false },
|
|
15
|
+
'heatid' => { key: :heat_id, required: false },
|
|
16
|
+
'lane' => { key: :lane, required: false },
|
|
17
|
+
'status' => { key: :status, required: false }
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
21
|
+
private_constant :ATTRIBUTE_KEYS
|
|
22
|
+
|
|
23
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
24
|
+
attr_reader :meet_info, :relay_positions
|
|
25
|
+
|
|
26
|
+
def initialize(meet_info: nil, relay_positions: [], **attributes)
|
|
27
|
+
ATTRIBUTES.each_value do |definition|
|
|
28
|
+
key = definition[:key]
|
|
29
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
30
|
+
end
|
|
31
|
+
@meet_info = meet_info
|
|
32
|
+
@relay_positions = Array(relay_positions)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.from_xml(element)
|
|
36
|
+
raise ::Lenex::Parser::ParseError, 'ENTRY element is required' unless element
|
|
37
|
+
|
|
38
|
+
attributes = extract_attributes(element)
|
|
39
|
+
meet_info = meet_info_from(element.at_xpath('MEETINFO'))
|
|
40
|
+
relay_positions = extract_relay_positions(element.at_xpath('RELAYPOSITIONS'))
|
|
41
|
+
|
|
42
|
+
new(**attributes, meet_info:, relay_positions:)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.extract_attributes(element)
|
|
46
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
47
|
+
value = element.attribute(attribute_name)&.value
|
|
48
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
49
|
+
collected[definition[:key]] = value if value
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
private_class_method :extract_attributes
|
|
53
|
+
|
|
54
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
55
|
+
return unless definition[:required]
|
|
56
|
+
return unless value.nil? || value.strip.empty?
|
|
57
|
+
|
|
58
|
+
message = "ENTRY #{attribute_name} attribute is required"
|
|
59
|
+
raise ::Lenex::Parser::ParseError, message
|
|
60
|
+
end
|
|
61
|
+
private_class_method :ensure_required_attribute!
|
|
62
|
+
|
|
63
|
+
def self.meet_info_from(element)
|
|
64
|
+
return unless element
|
|
65
|
+
|
|
66
|
+
MeetInfo.from_xml(element)
|
|
67
|
+
end
|
|
68
|
+
private_class_method :meet_info_from
|
|
69
|
+
|
|
70
|
+
def self.extract_relay_positions(collection_element)
|
|
71
|
+
return [] unless collection_element
|
|
72
|
+
|
|
73
|
+
collection_element.xpath('RELAYPOSITION').map do |position_element|
|
|
74
|
+
RelayPosition.from_xml(position_element)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
private_class_method :extract_relay_positions
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a RELAYPOSITION element.
|
|
7
|
+
class RelayPosition
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'athleteid' => { key: :athlete_id, required: false },
|
|
10
|
+
'number' => { key: :number, required: true },
|
|
11
|
+
'reactiontime' => { key: :reaction_time, required: false },
|
|
12
|
+
'status' => { key: :status, required: false }
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
16
|
+
private_constant :ATTRIBUTE_KEYS
|
|
17
|
+
|
|
18
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
19
|
+
attr_reader :athlete, :meet_info
|
|
20
|
+
|
|
21
|
+
def initialize(athlete: nil, meet_info: nil, **attributes)
|
|
22
|
+
ATTRIBUTES.each_value do |definition|
|
|
23
|
+
key = definition[:key]
|
|
24
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
25
|
+
end
|
|
26
|
+
@athlete = athlete
|
|
27
|
+
@meet_info = meet_info
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.from_xml(element)
|
|
31
|
+
raise ::Lenex::Parser::ParseError, 'RELAYPOSITION element is required' unless element
|
|
32
|
+
|
|
33
|
+
attributes = extract_attributes(element)
|
|
34
|
+
athlete = athlete_from(element.at_xpath('ATHLETE'))
|
|
35
|
+
meet_info = meet_info_from(element.at_xpath('MEETINFO'))
|
|
36
|
+
|
|
37
|
+
new(**attributes, athlete:, meet_info:)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.extract_attributes(element)
|
|
41
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
42
|
+
value = element.attribute(attribute_name)&.value
|
|
43
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
44
|
+
collected[definition[:key]] = value if value
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
private_class_method :extract_attributes
|
|
48
|
+
|
|
49
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
50
|
+
return unless definition[:required]
|
|
51
|
+
return unless value.nil? || value.strip.empty?
|
|
52
|
+
|
|
53
|
+
message = "RELAYPOSITION #{attribute_name} attribute is required"
|
|
54
|
+
raise ::Lenex::Parser::ParseError, message
|
|
55
|
+
end
|
|
56
|
+
private_class_method :ensure_required_attribute!
|
|
57
|
+
|
|
58
|
+
def self.athlete_from(element)
|
|
59
|
+
return unless element
|
|
60
|
+
|
|
61
|
+
Athlete.from_xml(element)
|
|
62
|
+
end
|
|
63
|
+
private_class_method :athlete_from
|
|
64
|
+
|
|
65
|
+
def self.meet_info_from(element)
|
|
66
|
+
return unless element
|
|
67
|
+
|
|
68
|
+
MeetInfo.from_xml(element)
|
|
69
|
+
end
|
|
70
|
+
private_class_method :meet_info_from
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a relay RESULT element.
|
|
7
|
+
class RelayResult
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'comment' => { key: :comment, required: false },
|
|
10
|
+
'eventid' => { key: :event_id, required: false },
|
|
11
|
+
'handicap' => { key: :handicap, required: false },
|
|
12
|
+
'heatid' => { key: :heat_id, required: false },
|
|
13
|
+
'lane' => { key: :lane, required: false },
|
|
14
|
+
'points' => { key: :points, required: false },
|
|
15
|
+
'reactiontime' => { key: :reaction_time, required: false },
|
|
16
|
+
'resultid' => { key: :result_id, required: true },
|
|
17
|
+
'status' => { key: :status, required: false },
|
|
18
|
+
'swimdistance' => { key: :swim_distance, required: false },
|
|
19
|
+
'swimtime' => { key: :swim_time, required: true }
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
23
|
+
private_constant :ATTRIBUTE_KEYS
|
|
24
|
+
|
|
25
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
26
|
+
attr_reader :relay_positions, :splits
|
|
27
|
+
|
|
28
|
+
def initialize(relay_positions: [], splits: [], **attributes)
|
|
29
|
+
ATTRIBUTES.each_value do |definition|
|
|
30
|
+
key = definition[:key]
|
|
31
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
32
|
+
end
|
|
33
|
+
@relay_positions = Array(relay_positions)
|
|
34
|
+
@splits = Array(splits)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.from_xml(element)
|
|
38
|
+
raise ::Lenex::Parser::ParseError, 'RESULT element is required' unless element
|
|
39
|
+
|
|
40
|
+
attributes = extract_attributes(element)
|
|
41
|
+
relay_positions = extract_relay_positions(element.at_xpath('RELAYPOSITIONS'))
|
|
42
|
+
splits = extract_splits(element.at_xpath('SPLITS'))
|
|
43
|
+
|
|
44
|
+
new(**attributes, relay_positions:, splits:)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.extract_attributes(element)
|
|
48
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
49
|
+
value = element.attribute(attribute_name)&.value
|
|
50
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
51
|
+
collected[definition[:key]] = value if value
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
private_class_method :extract_attributes
|
|
55
|
+
|
|
56
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
57
|
+
return unless definition[:required]
|
|
58
|
+
return unless value.nil? || value.strip.empty?
|
|
59
|
+
|
|
60
|
+
message = "RESULT #{attribute_name} attribute is required"
|
|
61
|
+
raise ::Lenex::Parser::ParseError, message
|
|
62
|
+
end
|
|
63
|
+
private_class_method :ensure_required_attribute!
|
|
64
|
+
|
|
65
|
+
def self.extract_relay_positions(collection_element)
|
|
66
|
+
return [] unless collection_element
|
|
67
|
+
|
|
68
|
+
collection_element.xpath('RELAYPOSITION').map do |position_element|
|
|
69
|
+
RelayPosition.from_xml(position_element)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
private_class_method :extract_relay_positions
|
|
73
|
+
|
|
74
|
+
def self.extract_splits(collection_element)
|
|
75
|
+
return [] unless collection_element
|
|
76
|
+
|
|
77
|
+
collection_element.xpath('SPLIT').map do |split_element|
|
|
78
|
+
Split.from_xml(split_element)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
private_class_method :extract_splits
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a RESULT element.
|
|
7
|
+
class Result
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'comment' => { key: :comment, required: false },
|
|
10
|
+
'entrycourse' => { key: :entry_course, required: false },
|
|
11
|
+
'entrytime' => { key: :entry_time, required: false },
|
|
12
|
+
'eventid' => { key: :event_id, required: false },
|
|
13
|
+
'handicap' => { key: :handicap, required: false },
|
|
14
|
+
'heatid' => { key: :heat_id, required: false },
|
|
15
|
+
'lane' => { key: :lane, required: false },
|
|
16
|
+
'points' => { key: :points, required: false },
|
|
17
|
+
'reactiontime' => { key: :reaction_time, required: false },
|
|
18
|
+
'resultid' => { key: :result_id, required: true },
|
|
19
|
+
'status' => { key: :status, required: false },
|
|
20
|
+
'swimdistance' => { key: :swim_distance, required: false },
|
|
21
|
+
'swimtime' => { key: :swim_time, required: true }
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
25
|
+
private_constant :ATTRIBUTE_KEYS
|
|
26
|
+
|
|
27
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
28
|
+
attr_reader :splits
|
|
29
|
+
|
|
30
|
+
def initialize(splits: [], **attributes)
|
|
31
|
+
ATTRIBUTES.each_value do |definition|
|
|
32
|
+
key = definition[:key]
|
|
33
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
34
|
+
end
|
|
35
|
+
@splits = Array(splits)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.from_xml(element)
|
|
39
|
+
raise ::Lenex::Parser::ParseError, 'RESULT element is required' unless element
|
|
40
|
+
|
|
41
|
+
attributes = extract_attributes(element)
|
|
42
|
+
splits = extract_splits(element.at_xpath('SPLITS'))
|
|
43
|
+
|
|
44
|
+
new(**attributes, splits:)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.extract_attributes(element)
|
|
48
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
49
|
+
value = element.attribute(attribute_name)&.value
|
|
50
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
51
|
+
collected[definition[:key]] = value if value
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
private_class_method :extract_attributes
|
|
55
|
+
|
|
56
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
57
|
+
return unless definition[:required]
|
|
58
|
+
return unless value.nil? || value.strip.empty?
|
|
59
|
+
|
|
60
|
+
message = "RESULT #{attribute_name} attribute is required"
|
|
61
|
+
raise ::Lenex::Parser::ParseError, message
|
|
62
|
+
end
|
|
63
|
+
private_class_method :ensure_required_attribute!
|
|
64
|
+
|
|
65
|
+
def self.extract_splits(collection_element)
|
|
66
|
+
return [] unless collection_element
|
|
67
|
+
|
|
68
|
+
collection_element.xpath('SPLIT').map do |split_element|
|
|
69
|
+
Split.from_xml(split_element)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
private_class_method :extract_splits
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a SESSION element.
|
|
7
|
+
class Session
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'course' => { key: :course, required: false },
|
|
10
|
+
'date' => { key: :date, required: true },
|
|
11
|
+
'daytime' => { key: :daytime, required: false },
|
|
12
|
+
'endtime' => { key: :endtime, required: false },
|
|
13
|
+
'maxentriesathlete' => { key: :max_entries_athlete, required: false },
|
|
14
|
+
'maxentriesrelay' => { key: :max_entries_relay, required: false },
|
|
15
|
+
'name' => { key: :name, required: false },
|
|
16
|
+
'number' => { key: :number, required: true },
|
|
17
|
+
'officialmeeting' => { key: :official_meeting, required: false },
|
|
18
|
+
'remarksjudge' => { key: :remarks_judge, required: false },
|
|
19
|
+
'teamleadermeeting' => { key: :team_leader_meeting, required: false },
|
|
20
|
+
'timing' => { key: :timing, required: false },
|
|
21
|
+
'touchpadmode' => { key: :touchpad_mode, required: false },
|
|
22
|
+
'warmupfrom' => { key: :warmup_from, required: false },
|
|
23
|
+
'warmupuntil' => { key: :warmup_until, required: false }
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
26
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
27
|
+
private_constant :ATTRIBUTE_KEYS
|
|
28
|
+
|
|
29
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
30
|
+
attr_reader :fee_schedule, :pool, :judges, :events
|
|
31
|
+
|
|
32
|
+
def initialize(fee_schedule: nil, pool: nil, judges: [], events: [], **attributes)
|
|
33
|
+
ATTRIBUTES.each_value do |definition|
|
|
34
|
+
key = definition[:key]
|
|
35
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
36
|
+
end
|
|
37
|
+
@fee_schedule = fee_schedule
|
|
38
|
+
@pool = pool
|
|
39
|
+
@judges = Array(judges)
|
|
40
|
+
@events = Array(events)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.from_xml(element)
|
|
44
|
+
raise ::Lenex::Parser::ParseError, 'SESSION element is required' unless element
|
|
45
|
+
|
|
46
|
+
attributes = extract_attributes(element)
|
|
47
|
+
|
|
48
|
+
fee_schedule = FeeSchedule.from_xml(element.at_xpath('FEES'))
|
|
49
|
+
pool = pool_from(element.at_xpath('POOL'))
|
|
50
|
+
judges = extract_judges(element.at_xpath('JUDGES'))
|
|
51
|
+
events = extract_events(element.at_xpath('EVENTS'))
|
|
52
|
+
|
|
53
|
+
new(**attributes, fee_schedule:, pool:, judges:, events:)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.extract_attributes(element)
|
|
57
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
58
|
+
value = element.attribute(attribute_name)&.value
|
|
59
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
60
|
+
collected[definition[:key]] = value if value
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
private_class_method :extract_attributes
|
|
64
|
+
|
|
65
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
66
|
+
return unless definition[:required]
|
|
67
|
+
return unless value.nil? || value.strip.empty?
|
|
68
|
+
|
|
69
|
+
message = "SESSION #{attribute_name} attribute is required"
|
|
70
|
+
raise ::Lenex::Parser::ParseError, message
|
|
71
|
+
end
|
|
72
|
+
private_class_method :ensure_required_attribute!
|
|
73
|
+
|
|
74
|
+
def self.pool_from(element)
|
|
75
|
+
return unless element
|
|
76
|
+
|
|
77
|
+
Pool.from_xml(element)
|
|
78
|
+
end
|
|
79
|
+
private_class_method :pool_from
|
|
80
|
+
|
|
81
|
+
def self.extract_judges(collection_element)
|
|
82
|
+
return [] unless collection_element
|
|
83
|
+
|
|
84
|
+
collection_element.xpath('JUDGE').map do |judge_element|
|
|
85
|
+
Judge.from_xml(judge_element)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
private_class_method :extract_judges
|
|
89
|
+
|
|
90
|
+
def self.extract_events(collection_element)
|
|
91
|
+
unless collection_element
|
|
92
|
+
raise ::Lenex::Parser::ParseError, 'SESSION EVENTS element is required'
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
events = collection_element.xpath('EVENT').map do |event_element|
|
|
96
|
+
Event.from_xml(event_element)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
return events unless events.empty?
|
|
100
|
+
|
|
101
|
+
raise ::Lenex::Parser::ParseError, 'SESSION must include at least one EVENT element'
|
|
102
|
+
end
|
|
103
|
+
private_class_method :extract_events
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a SPLIT element.
|
|
7
|
+
class Split
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'distance' => { key: :distance, required: true },
|
|
10
|
+
'swimtime' => { key: :swim_time, required: true }
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
14
|
+
private_constant :ATTRIBUTE_KEYS
|
|
15
|
+
|
|
16
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
17
|
+
|
|
18
|
+
def initialize(**attributes)
|
|
19
|
+
ATTRIBUTES.each_value do |definition|
|
|
20
|
+
key = definition[:key]
|
|
21
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.from_xml(element)
|
|
26
|
+
raise ::Lenex::Parser::ParseError, 'SPLIT element is required' unless element
|
|
27
|
+
|
|
28
|
+
attributes = extract_attributes(element)
|
|
29
|
+
|
|
30
|
+
new(**attributes)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.extract_attributes(element)
|
|
34
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
35
|
+
value = element.attribute(attribute_name)&.value
|
|
36
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
37
|
+
collected[definition[:key]] = value if value
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
private_class_method :extract_attributes
|
|
41
|
+
|
|
42
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
43
|
+
return unless definition[:required]
|
|
44
|
+
return unless value.nil? || value.strip.empty?
|
|
45
|
+
|
|
46
|
+
message = "SPLIT #{attribute_name} attribute is required"
|
|
47
|
+
raise ::Lenex::Parser::ParseError, message
|
|
48
|
+
end
|
|
49
|
+
private_class_method :ensure_required_attribute!
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a SWIMSTYLE element.
|
|
7
|
+
class SwimStyle
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'code' => { key: :code, required: false },
|
|
10
|
+
'distance' => { key: :distance, required: true },
|
|
11
|
+
'name' => { key: :name, required: false },
|
|
12
|
+
'relaycount' => { key: :relay_count, required: true },
|
|
13
|
+
'stroke' => { key: :stroke, required: true },
|
|
14
|
+
'swimstyleid' => { key: :swim_style_id, required: false },
|
|
15
|
+
'technique' => { key: :technique, required: false }
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
19
|
+
private_constant :ATTRIBUTE_KEYS
|
|
20
|
+
|
|
21
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
22
|
+
|
|
23
|
+
def initialize(**attributes)
|
|
24
|
+
ATTRIBUTES.each_value do |definition|
|
|
25
|
+
key = definition[:key]
|
|
26
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.from_xml(element)
|
|
31
|
+
raise ::Lenex::Parser::ParseError, 'SWIMSTYLE element is required' unless element
|
|
32
|
+
|
|
33
|
+
attributes = extract_attributes(element)
|
|
34
|
+
|
|
35
|
+
new(**attributes)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.extract_attributes(element)
|
|
39
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
40
|
+
value = element.attribute(attribute_name)&.value
|
|
41
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
42
|
+
collected[definition[:key]] = value if value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
private_class_method :extract_attributes
|
|
46
|
+
|
|
47
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
48
|
+
return unless definition[:required]
|
|
49
|
+
return unless value.nil? || value.strip.empty?
|
|
50
|
+
|
|
51
|
+
message = "SWIMSTYLE #{attribute_name} attribute is required"
|
|
52
|
+
raise ::Lenex::Parser::ParseError, message
|
|
53
|
+
end
|
|
54
|
+
private_class_method :ensure_required_attribute!
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lenex
|
|
4
|
+
module Parser
|
|
5
|
+
module Objects
|
|
6
|
+
# Value object representing a TIMESTANDARD element.
|
|
7
|
+
class TimeStandard
|
|
8
|
+
ATTRIBUTES = {
|
|
9
|
+
'swimtime' => { key: :swim_time, required: true }
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
ATTRIBUTE_KEYS = ATTRIBUTES.values.map { |definition| definition[:key] }.freeze
|
|
13
|
+
private_constant :ATTRIBUTE_KEYS
|
|
14
|
+
|
|
15
|
+
ATTRIBUTE_KEYS.each { |attribute| attr_reader attribute }
|
|
16
|
+
attr_reader :swim_style
|
|
17
|
+
|
|
18
|
+
def initialize(swim_style:, **attributes)
|
|
19
|
+
ATTRIBUTES.each_value do |definition|
|
|
20
|
+
key = definition[:key]
|
|
21
|
+
instance_variable_set(:"@#{key}", attributes[key])
|
|
22
|
+
end
|
|
23
|
+
@swim_style = swim_style
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.from_xml(element)
|
|
27
|
+
raise ::Lenex::Parser::ParseError, 'TIMESTANDARD element is required' unless element
|
|
28
|
+
|
|
29
|
+
attributes = extract_attributes(element)
|
|
30
|
+
swim_style = SwimStyle.from_xml(element.at_xpath('SWIMSTYLE'))
|
|
31
|
+
|
|
32
|
+
new(**attributes, swim_style:)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.extract_attributes(element)
|
|
36
|
+
ATTRIBUTES.each_with_object({}) do |(attribute_name, definition), collected|
|
|
37
|
+
value = element.attribute(attribute_name)&.value
|
|
38
|
+
ensure_required_attribute!(attribute_name, definition, value)
|
|
39
|
+
collected[definition[:key]] = value if value
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
private_class_method :extract_attributes
|
|
43
|
+
|
|
44
|
+
def self.ensure_required_attribute!(attribute_name, definition, value)
|
|
45
|
+
return unless definition[:required]
|
|
46
|
+
return unless value.nil? || value.strip.empty?
|
|
47
|
+
|
|
48
|
+
message = "TIMESTANDARD #{attribute_name} attribute is required"
|
|
49
|
+
raise ::Lenex::Parser::ParseError, message
|
|
50
|
+
end
|
|
51
|
+
private_class_method :ensure_required_attribute!
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|