aixm 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.yardopts +3 -0
- data/CHANGELOG.md +34 -14
- data/Guardfile +1 -0
- data/README.md +64 -257
- data/lib/aixm.rb +16 -7
- data/lib/aixm/component.rb +6 -0
- data/lib/aixm/component/frequency.rb +135 -0
- data/lib/aixm/component/geometry.rb +34 -23
- data/lib/aixm/component/geometry/arc.rb +37 -22
- data/lib/aixm/component/geometry/border.rb +29 -20
- data/lib/aixm/component/geometry/circle.rb +39 -22
- data/lib/aixm/component/geometry/point.rb +29 -13
- data/lib/aixm/component/helipad.rb +154 -0
- data/lib/aixm/component/layer.rb +91 -0
- data/lib/aixm/component/runway.rb +294 -0
- data/lib/aixm/component/service.rb +170 -0
- data/lib/aixm/component/timetable.rb +65 -0
- data/lib/aixm/component/vertical_limits.rb +65 -29
- data/lib/aixm/config.rb +87 -0
- data/lib/aixm/document.rb +66 -42
- data/lib/aixm/errors.rb +11 -0
- data/lib/aixm/f.rb +34 -20
- data/lib/aixm/feature.rb +38 -0
- data/lib/aixm/feature/airport.rb +473 -0
- data/lib/aixm/feature/airspace.rb +145 -92
- data/lib/aixm/feature/navigational_aid.rb +94 -0
- data/lib/aixm/feature/navigational_aid/designated_point.rb +50 -54
- data/lib/aixm/feature/navigational_aid/dme.rb +48 -40
- data/lib/aixm/feature/navigational_aid/marker.rb +55 -45
- data/lib/aixm/feature/navigational_aid/ndb.rb +54 -50
- data/lib/aixm/feature/navigational_aid/tacan.rb +38 -31
- data/lib/aixm/feature/navigational_aid/vor.rb +84 -76
- data/lib/aixm/feature/organisation.rb +97 -0
- data/lib/aixm/feature/unit.rb +152 -0
- data/lib/aixm/refinements.rb +132 -47
- data/lib/aixm/shortcuts.rb +11 -6
- data/lib/aixm/version.rb +1 -1
- data/lib/aixm/xy.rb +64 -20
- data/lib/aixm/z.rb +51 -22
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-DataTypes.xsd +0 -0
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Features.xsd +0 -0
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Snapshot.xsd +0 -0
- data/schemas/ofmx/0/OFMX-DataTypes.xsd +5077 -0
- data/schemas/ofmx/0/OFMX-Features.xsd +9955 -0
- data/schemas/ofmx/0/OFMX-Snapshot.xsd +217 -0
- data/spec/factory.rb +209 -33
- data/spec/lib/aixm/component/frequency_spec.rb +75 -0
- data/spec/lib/aixm/component/geometry/arc_spec.rb +28 -22
- data/spec/lib/aixm/component/geometry/border_spec.rb +23 -20
- data/spec/lib/aixm/component/geometry/circle_spec.rb +31 -22
- data/spec/lib/aixm/component/geometry/point_spec.rb +11 -14
- data/spec/lib/aixm/component/geometry_spec.rb +150 -69
- data/spec/lib/aixm/component/helipad_spec.rb +136 -0
- data/spec/lib/aixm/component/layer_spec.rb +110 -0
- data/spec/lib/aixm/component/runway_spec.rb +402 -0
- data/spec/lib/aixm/component/service_spec.rb +61 -0
- data/spec/lib/aixm/component/timetable_spec.rb +49 -0
- data/spec/lib/aixm/component/vertical_limits_spec.rb +39 -20
- data/spec/lib/aixm/config_spec.rb +41 -0
- data/spec/lib/aixm/document_spec.rb +637 -147
- data/spec/lib/aixm/errors_spec.rb +14 -0
- data/spec/lib/aixm/f_spec.rb +17 -10
- data/spec/lib/aixm/feature/airport_spec.rb +546 -0
- data/spec/lib/aixm/feature/airspace_spec.rb +349 -226
- data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +47 -36
- data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +61 -36
- data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +61 -113
- data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +65 -79
- data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +57 -36
- data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +86 -112
- data/spec/lib/aixm/feature/navigational_aid_spec.rb +52 -0
- data/spec/lib/aixm/feature/organisation_spec.rb +77 -0
- data/spec/lib/aixm/feature/unit_spec.rb +227 -0
- data/spec/lib/aixm/feature_spec.rb +58 -0
- data/spec/lib/aixm/refinements_spec.rb +187 -178
- data/spec/lib/aixm/xy_spec.rb +45 -34
- data/spec/lib/aixm/z_spec.rb +19 -21
- data/spec/macros/organisation.rb +11 -0
- data/spec/macros/remarks.rb +12 -0
- data/spec/macros/timetable.rb +11 -0
- data/spec/macros/xy.rb +11 -0
- data/spec/macros/z_qnh.rb +11 -0
- data/spec/spec_helper.rb +26 -0
- metadata +60 -19
- data/lib/aixm/base.rb +0 -10
- data/lib/aixm/component/base.rb +0 -6
- data/lib/aixm/component/class_layer.rb +0 -46
- data/lib/aixm/component/geometry/base.rb +0 -8
- data/lib/aixm/component/schedule.rb +0 -43
- data/lib/aixm/feature/base.rb +0 -6
- data/lib/aixm/feature/navigational_aid/base.rb +0 -79
- data/spec/lib/aixm/component/class_layer_spec.rb +0 -74
- data/spec/lib/aixm/component/schedule_spec.rb +0 -33
- data/spec/lib/aixm/feature/navigational_aid/base_spec.rb +0 -41
@@ -0,0 +1,170 @@
|
|
1
|
+
using AIXM::Refinements
|
2
|
+
|
3
|
+
module AIXM
|
4
|
+
class Component
|
5
|
+
|
6
|
+
# Service provided by a unit.
|
7
|
+
#
|
8
|
+
# ===Cheat Sheet in Pseudo Code:
|
9
|
+
# service = AIXM.service(
|
10
|
+
# name: String
|
11
|
+
# type: TYPES
|
12
|
+
# )
|
13
|
+
# service.timetable = AIXM.timetable or nil
|
14
|
+
# service.remarks = String or nil
|
15
|
+
# service.add_frequency(AIXM.frequency)
|
16
|
+
#
|
17
|
+
# @see https://github.com/openflightmaps/ofmx/wiki/Organisation#ser-service
|
18
|
+
class Service
|
19
|
+
TYPES = {
|
20
|
+
ACS: :area_control_service,
|
21
|
+
ADS: :automatic_dependent_surveillance_service,
|
22
|
+
ADVS: :advisory_service,
|
23
|
+
AFIS: :aerodrome_flight_information_service,
|
24
|
+
AFS: :aeronautical_fixed_service,
|
25
|
+
AIS: :aeronautical_information_service,
|
26
|
+
ALRS: :alerting_service,
|
27
|
+
AMS: :aeronautical_mobile_service,
|
28
|
+
AMSS: :aeronautical_mobile_satellite_service,
|
29
|
+
APP: :approach_control_service,
|
30
|
+
'APP-ARR': :approach_control_service_for_arrival,
|
31
|
+
'APP-DEP': :approach_control_service_for_departure,
|
32
|
+
ARTCC: :air_route_traffic_control_centre_service,
|
33
|
+
ATC: :air_traffic_control_service,
|
34
|
+
ATFM: :air_traffic_flow_management_service,
|
35
|
+
ATIS: :automated_terminal_information_service,
|
36
|
+
'ATIS-ARR': :automated_terminal_information_service_for_arrival,
|
37
|
+
'ATIS-DEP': :automated_terminal_information_service_for_departure,
|
38
|
+
ATM: :air_traffic_management_service,
|
39
|
+
ATS: :air_traffic_service,
|
40
|
+
BOF: :briefing_service,
|
41
|
+
BS: :commercial_broadcasting_service,
|
42
|
+
COM: :communications_service,
|
43
|
+
CTAF: :common_traffic_advisory_frequency_service,
|
44
|
+
DVDF: :doppler_vdf_service,
|
45
|
+
EFAS: :en_route_flight_advisory_service,
|
46
|
+
ENTRY: :entry_clearance_service,
|
47
|
+
EXIT: :exit_clearance_service,
|
48
|
+
FCST: :forecasting_service,
|
49
|
+
FIS: :flight_information_service,
|
50
|
+
FISA: :automated_flight_information_service,
|
51
|
+
FSS: :flight_service_station_service,
|
52
|
+
GCA: :ground_controlled_approach_service,
|
53
|
+
INFO: :information_provision_service,
|
54
|
+
MET: :meteorological_service,
|
55
|
+
NOF: :international_notam_service,
|
56
|
+
OAC: :oceanic_area_control_service,
|
57
|
+
OVERFLT: :overflight_clearance_service,
|
58
|
+
PAR: :precision_approach_radar_service,
|
59
|
+
RAC: :rules_of_the_air_and_air_traffic_services,
|
60
|
+
RADAR: :radar_service,
|
61
|
+
RAF: :regional_area_forecasting_service,
|
62
|
+
RCC: :rescue_coordination_service,
|
63
|
+
SAR: :search_and_rescue_service,
|
64
|
+
SIGMET: :sigmet_service,
|
65
|
+
SMC: :surface_movement_control_service,
|
66
|
+
SMR: :surface_movement_radar_service,
|
67
|
+
SRA: :surveillance_radar_approach_service,
|
68
|
+
SSR: :secondary_surveillance_radar_service,
|
69
|
+
TAR: :terminal_area_radar_service,
|
70
|
+
TWEB: :transcribed_weather_broadcast_service,
|
71
|
+
TWR: :aerodrome_control_tower_service,
|
72
|
+
UAC: :upper_area_control_service,
|
73
|
+
UDF: :uhf_direction_finding_service,
|
74
|
+
VDF: :vhf_direction_finding_service,
|
75
|
+
VOLMET: :volmet_service,
|
76
|
+
VOT: :vor_test_facility,
|
77
|
+
OTHER: :other # specify in remarks
|
78
|
+
}.freeze
|
79
|
+
|
80
|
+
# @return [AIXM::Feature::Unit] unit providing this service
|
81
|
+
attr_reader :unit
|
82
|
+
|
83
|
+
# @return [String] full name
|
84
|
+
attr_reader :name
|
85
|
+
|
86
|
+
# @return [Symbol] type of service (see {TYPES})
|
87
|
+
attr_reader :type
|
88
|
+
|
89
|
+
# @return [AIXM::Component::Timetable, nil] operating hours
|
90
|
+
attr_reader :timetable
|
91
|
+
|
92
|
+
# @return [String, nil] free text remarks
|
93
|
+
attr_reader :remarks
|
94
|
+
|
95
|
+
# @return [Array<AIXM::Component::Frequency>] frequencies used by this service
|
96
|
+
attr_reader :frequencies
|
97
|
+
|
98
|
+
def initialize(name:, type:)
|
99
|
+
self.name, self.type = name, type
|
100
|
+
@frequencies = []
|
101
|
+
end
|
102
|
+
|
103
|
+
# @return [String]
|
104
|
+
def inspect
|
105
|
+
%Q(#<#{self.class} type=#{type.inspect}>)
|
106
|
+
end
|
107
|
+
|
108
|
+
def unit=(value)
|
109
|
+
fail(ArgumentError, "invalid unit") unless value.is_a? AIXM::Feature::Unit
|
110
|
+
@unit = value
|
111
|
+
end
|
112
|
+
private :unit=
|
113
|
+
|
114
|
+
def name=(value)
|
115
|
+
fail(ArgumentError, "invalid name") unless value.is_a? String
|
116
|
+
@name = value.uptrans
|
117
|
+
end
|
118
|
+
|
119
|
+
def type=(value)
|
120
|
+
@type = TYPES.lookup(value&.to_s&.to_sym, nil) || fail(ArgumentError, "invalid type")
|
121
|
+
end
|
122
|
+
|
123
|
+
def timetable=(value)
|
124
|
+
fail(ArgumentError, "invalid timetable") unless value.nil? || value.is_a?(AIXM::Component::Timetable)
|
125
|
+
@timetable = value
|
126
|
+
end
|
127
|
+
|
128
|
+
def remarks=(value)
|
129
|
+
@remarks = value&.to_s
|
130
|
+
end
|
131
|
+
|
132
|
+
# Add a frequency used by this service.
|
133
|
+
#
|
134
|
+
# @param frequency [AIXM::Component::Frequency] frequency instance
|
135
|
+
# @return [self]
|
136
|
+
def add_frequency(frequency)
|
137
|
+
fail(ArgumentError, "invalid frequency") unless frequency.is_a? AIXM::Component::Frequency
|
138
|
+
frequency.send(:service=, self)
|
139
|
+
@frequencies << frequency
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
# @return [String] UID markup
|
144
|
+
def to_uid
|
145
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
146
|
+
builder.SerUid do |ser_uid|
|
147
|
+
ser_uid << unit.to_uid.indent(2)
|
148
|
+
ser_uid.codeType(TYPES.key(type).to_s)
|
149
|
+
ser_uid.noSeq(@sequence)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# @return [String] AIXM or OFMX markup
|
154
|
+
def to_xml(sequence=1)
|
155
|
+
@sequence = sequence
|
156
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
157
|
+
builder.Ser do |ser|
|
158
|
+
ser << to_uid.indent(2)
|
159
|
+
ser << timetable.to_xml(as: :Stt).indent(2) if timetable
|
160
|
+
ser.txtRmk(remarks) if remarks
|
161
|
+
end
|
162
|
+
frequencies.each do |frequency|
|
163
|
+
builder << frequency.to_xml
|
164
|
+
end
|
165
|
+
builder.target!
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
using AIXM::Refinements
|
2
|
+
|
3
|
+
module AIXM
|
4
|
+
class Component
|
5
|
+
|
6
|
+
# Timetables define activity time windows.
|
7
|
+
#
|
8
|
+
# @note As of now, only predefined timetables (see {CODES}) are imlemented.
|
9
|
+
#
|
10
|
+
# ===Cheat Sheat in Pseudo Code:
|
11
|
+
# timetable = AIXM.timetable(
|
12
|
+
# code: String or Symbol
|
13
|
+
# )
|
14
|
+
# timetable.remarks = String or nil
|
15
|
+
#
|
16
|
+
# ===Shortcuts:
|
17
|
+
# * +AIXM::H24+ - continuous, all day and all night
|
18
|
+
#
|
19
|
+
# @see https://github.com/openflightmaps/ofmx/wiki/Timetable#predefined-timetable
|
20
|
+
class Timetable
|
21
|
+
CODES = {
|
22
|
+
H24: :continuous, # all day and all night
|
23
|
+
HJ: :sunrise_to_sunset, # all day
|
24
|
+
HN: :sunset_to_sunrise, # all night
|
25
|
+
HX: :unspecified,
|
26
|
+
HO: :operational_request, # on request only
|
27
|
+
NOTAM: :notam, # see NOTAM
|
28
|
+
OTHER: :other # specify in remarks
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
# @return [Symbol] predefined timetable code (see {CODES})
|
32
|
+
attr_reader :code
|
33
|
+
|
34
|
+
# @return [String, nil] free text remarks
|
35
|
+
attr_reader :remarks
|
36
|
+
|
37
|
+
def initialize(code:)
|
38
|
+
self.code = code
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String]
|
42
|
+
def inspect
|
43
|
+
%Q(#<#{self.class} code=#{code.inspect}>)
|
44
|
+
end
|
45
|
+
|
46
|
+
def code=(value)
|
47
|
+
@code = CODES.lookup(value&.to_s&.to_sym, nil) || fail(ArgumentError, "invalid code")
|
48
|
+
end
|
49
|
+
|
50
|
+
def remarks=(value)
|
51
|
+
@remarks = value&.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [String] AIXM or OFMX markup
|
55
|
+
def to_xml(as: :Timetable)
|
56
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
57
|
+
builder.tag!(as) do |tag|
|
58
|
+
tag.codeWorkHr(CODES.key(code).to_s)
|
59
|
+
tag.txtRmkWorkHr(remarks) if remarks
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -1,49 +1,85 @@
|
|
1
|
+
using AIXM::Refinements
|
2
|
+
|
1
3
|
module AIXM
|
2
|
-
|
4
|
+
class Component
|
3
5
|
|
4
|
-
|
5
|
-
#
|
6
|
-
# as follows:
|
6
|
+
# Vertical limits define a 3D airspace vertically. They are often noted in
|
7
|
+
# AIP as follows:
|
7
8
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
9
|
+
# upper_z (or max_z whichever is higher)
|
10
|
+
# -------
|
11
|
+
# lower_z (or min_z whichever is lower)
|
11
12
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
# ===Cheat Sheet in Pseudo Code:
|
14
|
+
# vertical_limits = AIXM.vertical_limits(
|
15
|
+
# upper_z: AIXM.z
|
16
|
+
# lower_z: AIXM.z
|
17
|
+
# max_z: AIXM.z or nil
|
18
|
+
# min_z: AIXM.z or nil
|
19
|
+
# )
|
20
|
+
#
|
21
|
+
# ===Shortcuts:
|
22
|
+
# * +AIXM::GROUND+ - surface expressed as "0 ft QFE"
|
23
|
+
# * +AIXM::UNLIMITED+ - no upper limit expressed as "FL 999"
|
24
|
+
#
|
25
|
+
# @see https://github.com/openflightmaps/ofmx/wiki/Airspace#ase-airspace
|
26
|
+
class VerticalLimits
|
27
|
+
# @api private
|
18
28
|
TAGS = { upper: :Upper, lower: :Lower, max: :Max, min: :Mnm }.freeze
|
29
|
+
|
30
|
+
# @api private
|
19
31
|
CODES = { qfe: :HEI, qnh: :ALT, qne: :STD }.freeze
|
20
32
|
|
21
|
-
|
33
|
+
# @return [AIXM::Z] upper limit
|
34
|
+
attr_reader :upper_z
|
35
|
+
|
36
|
+
# @return [AIXM::Z] lower limit
|
37
|
+
attr_reader :lower_z
|
38
|
+
|
39
|
+
# @return [AIXM::Z] alternative upper limit ("whichever is higher")
|
40
|
+
attr_reader :max_z
|
41
|
+
|
42
|
+
# @return [AIXM::Z] alternative lower limit ("whichever is lower")
|
43
|
+
attr_reader :min_z
|
44
|
+
|
45
|
+
def initialize(upper_z:, lower_z:, max_z: nil, min_z: nil)
|
46
|
+
self.upper_z, self.lower_z, self.max_z, self.min_z = upper_z, lower_z, max_z, min_z
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [String]
|
50
|
+
def inspect
|
51
|
+
%Q(#<#{self.class} upper_z="#{upper_z.to_s}" lower_z="#{lower_z.to_s}">)
|
52
|
+
end
|
53
|
+
|
54
|
+
def upper_z=(value)
|
55
|
+
fail(ArgumentError, "invalid upper_z") unless value.is_a? AIXM::Z
|
56
|
+
@upper_z = value
|
57
|
+
end
|
58
|
+
|
59
|
+
def lower_z=(value)
|
60
|
+
fail(ArgumentError, "invalid lower_z") unless value.is_a? AIXM::Z
|
61
|
+
@lower_z = value
|
62
|
+
end
|
22
63
|
|
23
|
-
def
|
24
|
-
fail(ArgumentError, "invalid
|
25
|
-
|
26
|
-
fail(ArgumentError, "invalid max_z") unless max_z.nil? || max_z.is_a?(AIXM::Z)
|
27
|
-
fail(ArgumentError, "invalid min_z") unless min_z.nil? || min_z.is_a?(AIXM::Z)
|
28
|
-
@upper_z, @lower_z, @max_z, @min_z = upper_z, lower_z, max_z, min_z
|
64
|
+
def max_z=(value)
|
65
|
+
fail(ArgumentError, "invalid max_z") unless value.nil? || value.is_a?(AIXM::Z)
|
66
|
+
@max_z = value
|
29
67
|
end
|
30
68
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
[upper_z.alt, upper_z.code, lower_z.alt, lower_z.code, max_z&.alt, max_z&.code, min_z&.alt, min_z&.code].to_digest
|
69
|
+
def min_z=(value)
|
70
|
+
fail(ArgumentError, "invalid min_z") unless value.nil? || value.is_a?(AIXM::Z)
|
71
|
+
@min_z = value
|
35
72
|
end
|
36
73
|
|
37
|
-
|
38
|
-
|
39
|
-
def to_aixm(*extensions)
|
74
|
+
# @return [String] AIXM or OFMX markup
|
75
|
+
def to_xml
|
40
76
|
%i(upper lower max min).each_with_object(Builder::XmlMarkup.new(indent: 2)) do |limit, builder|
|
41
77
|
if z = send(:"#{limit}_z")
|
42
78
|
builder.tag!(:"codeDistVer#{TAGS[limit]}", CODES[z.code].to_s)
|
43
79
|
builder.tag!(:"valDistVer#{TAGS[limit]}", z.alt.to_s)
|
44
|
-
builder.tag!(:"uomDistVer#{TAGS[limit]}", z.unit.to_s)
|
80
|
+
builder.tag!(:"uomDistVer#{TAGS[limit]}", z.unit.upcase.to_s)
|
45
81
|
end
|
46
|
-
end.target!
|
82
|
+
end.target!
|
47
83
|
end
|
48
84
|
end
|
49
85
|
|
data/lib/aixm/config.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
module AIXM
|
2
|
+
|
3
|
+
SCHEMAS = {
|
4
|
+
aixm: {
|
5
|
+
version: '4.5',
|
6
|
+
namespace: 'http://www.aixm.aero/schema/4.5/AIXM-Snapshot.xsd',
|
7
|
+
xsd: Pathname(__dir__).join('..', '..', 'schemas', 'aixm', '4.5', 'AIXM-Snapshot.xsd'),
|
8
|
+
root: 'AIXM-Snapshot'
|
9
|
+
},
|
10
|
+
ofmx: {
|
11
|
+
version: '0',
|
12
|
+
namespace: 'http://openflightmaps.org/schema/0/OFMX-Snapshot.xsd',
|
13
|
+
xsd: Pathname(__dir__).join('..', '..', 'schemas', 'ofmx', '0', 'OFMX-Snapshot.xsd'),
|
14
|
+
root: 'OFMX-Snapshot'
|
15
|
+
}
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
# Access the configuration (e.g. +AIXM.config.schema+)
|
21
|
+
# @return [OpenStruct] configuration struct
|
22
|
+
def config
|
23
|
+
@@config
|
24
|
+
end
|
25
|
+
|
26
|
+
# Currently active schema
|
27
|
+
#
|
28
|
+
# @example Get the schema identifyer
|
29
|
+
# AIXM.schema # => :aixm
|
30
|
+
#
|
31
|
+
# @example Get schema details
|
32
|
+
# AIXM.schema(:version) # => '4.5'
|
33
|
+
# AIXM.schema(:root) # => 'AIXM-Snapshot'
|
34
|
+
#
|
35
|
+
# @param key [Symbol, nil] schema detail key (see {SCHEMAS})
|
36
|
+
# @return [Object] schema detail value
|
37
|
+
def schema(key = nil)
|
38
|
+
key ? SCHEMAS.dig(@@config.schema, key) : @@config.schema
|
39
|
+
end
|
40
|
+
|
41
|
+
# Shortcuts to set the schema.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# AIXM.aixm! # => :aixm
|
45
|
+
# AIXM.ofmx? # => false
|
46
|
+
# AIXM.ofmx! # => :ofmx
|
47
|
+
# AIXM.ofmx? # => true
|
48
|
+
#
|
49
|
+
# @!method aixm!
|
50
|
+
# @!method ofmx!
|
51
|
+
# @return [Symbol] schema key
|
52
|
+
SCHEMAS.each_key do |schema|
|
53
|
+
define_method("#{schema}!") { @@config.schema = schema }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Shortcuts to query the schema.
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# AIXM.aixm! # => :aixm
|
60
|
+
# AIXM.ofmx? # => false
|
61
|
+
# AIXM.ofmx! # => :ofmx
|
62
|
+
# AIXM.ofmx? # => true
|
63
|
+
#
|
64
|
+
# @!method aixm?
|
65
|
+
# @!method ofmx?
|
66
|
+
# @return [Boolean]
|
67
|
+
SCHEMAS.each_key do |schema|
|
68
|
+
define_method("#{schema}?") { @@config.schema == schema }
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Configuration defaults (view source for more).
|
74
|
+
#
|
75
|
+
# @!visibility public
|
76
|
+
# @api private
|
77
|
+
# @return [OpenStruct]
|
78
|
+
def initialize_config
|
79
|
+
@@config = OpenStruct.new(
|
80
|
+
schema: :aixm
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
AIXM.send(:initialize_config)
|
data/lib/aixm/document.rb
CHANGED
@@ -1,63 +1,89 @@
|
|
1
|
+
using AIXM::Refinements
|
2
|
+
|
1
3
|
module AIXM
|
2
|
-
class Document < Base
|
3
|
-
using AIXM::Refinements
|
4
4
|
|
5
|
-
|
5
|
+
# The AIXM-Snapshot or OFMX-Snapshot document is the root container for
|
6
|
+
# aeronautical information such as airports or airspaces.
|
7
|
+
#
|
8
|
+
# ===Cheat Sheet in Pseudo Code:
|
9
|
+
# document = AIXM.document(
|
10
|
+
# namespace: String (UUID)
|
11
|
+
# created_at: Time or Date or String
|
12
|
+
# effective_at: Time or Date or String
|
13
|
+
# )
|
14
|
+
# document.features << AIXM::Feature
|
15
|
+
#
|
16
|
+
# @see https://github.com/openflightmaps/ofmx/wiki/Snapshot
|
17
|
+
class Document
|
18
|
+
NAMESPACE_PATTERN = /\A[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}\z/.freeze
|
19
|
+
|
20
|
+
# @return [String] UUID to namespace the data contained in this document
|
21
|
+
attr_reader :namespace
|
22
|
+
|
23
|
+
# @return [Time] creation date and time (default: {#effective_at} or now)
|
24
|
+
attr_reader :created_at
|
25
|
+
|
26
|
+
# @return [Time] effective after date and time (default: {#created_at} or now)
|
27
|
+
attr_reader :effective_at
|
6
28
|
|
7
|
-
|
29
|
+
# @return [Array<AIXM::Feature>] airspaces, airports and other features
|
8
30
|
attr_accessor :features
|
9
31
|
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
# Options:
|
14
|
-
# * +created_at+ - creation date and time (default: now)
|
15
|
-
# * +effective_at+ - snapshot effective after date and time (default: now)
|
16
|
-
def initialize(created_at: nil, effective_at: nil)
|
17
|
-
@created_at, @effective_at = parse_time(created_at), parse_time(effective_at)
|
32
|
+
def initialize(namespace: nil, created_at: nil, effective_at: nil)
|
33
|
+
self.namespace, self.created_at, self.effective_at = namespace, created_at, effective_at
|
18
34
|
@features = []
|
19
35
|
end
|
20
36
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
37
|
+
# @return [String]
|
38
|
+
def inspect
|
39
|
+
%Q(#<#{self.class} created_at=#{created_at.inspect}>)
|
40
|
+
end
|
41
|
+
|
42
|
+
def namespace=(value)
|
43
|
+
fail(ArgumentError, "invalid namespace") unless value.nil? || value.match?(NAMESPACE_PATTERN)
|
44
|
+
@namespace = value || SecureRandom.uuid
|
25
45
|
end
|
26
46
|
|
27
|
-
|
28
|
-
|
47
|
+
def created_at=(value)
|
48
|
+
@created_at = parse_time(value) || effective_at || Time.now
|
49
|
+
end
|
50
|
+
|
51
|
+
def effective_at=(value)
|
52
|
+
@effective_at = parse_time(value) || created_at || Time.now
|
53
|
+
end
|
54
|
+
|
55
|
+
# Validate the generated AIXM or OFMX atainst it's XSD.
|
56
|
+
#
|
57
|
+
# @return [Boolean] whether valid or not
|
29
58
|
def valid?
|
30
59
|
errors.none?
|
31
60
|
end
|
32
61
|
|
33
|
-
|
34
|
-
#
|
62
|
+
# Validate the generated AIXM or OFMX atainst it's XSD and return the
|
63
|
+
# errors found.
|
64
|
+
#
|
65
|
+
# @return [Array<String>] validation errors
|
35
66
|
def errors
|
36
|
-
xsd = Nokogiri::XML::Schema(File.open(AIXM
|
37
|
-
xsd.validate(Nokogiri::XML(
|
38
|
-
error.message
|
67
|
+
xsd = Nokogiri::XML::Schema(File.open(AIXM.schema(:xsd)))
|
68
|
+
xsd.validate(Nokogiri::XML(to_xml)).reject do |error|
|
69
|
+
AIXM.config.ignored_errors && error.message.match?(AIXM.config.ignored_errors)
|
39
70
|
end
|
40
71
|
end
|
41
72
|
|
42
|
-
|
43
|
-
|
44
|
-
#
|
45
|
-
# Extensions:
|
46
|
-
# * +:ofm+ - Open Flightmaps
|
47
|
-
def to_aixm(*extensions)
|
48
|
-
now = Time.now.xmlschema
|
73
|
+
# @return [String] AIXM or OFMX markup
|
74
|
+
def to_xml
|
49
75
|
meta = {
|
50
|
-
'xmlns:xsi':
|
51
|
-
version:
|
52
|
-
origin: "
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
76
|
+
'xmlns:xsi': AIXM.schema(:namespace),
|
77
|
+
version: AIXM.schema(:version),
|
78
|
+
origin: "rubygem aixm-#{AIXM::VERSION}",
|
79
|
+
namespace: (namespace if AIXM.ofmx?),
|
80
|
+
created: @created_at.xmlschema,
|
81
|
+
effective: @effective_at.xmlschema
|
82
|
+
}.compact
|
57
83
|
builder = Builder::XmlMarkup.new(indent: 2)
|
58
84
|
builder.instruct!
|
59
|
-
builder.tag!(
|
60
|
-
|
85
|
+
builder.tag!(AIXM.schema(:root), meta) do |root|
|
86
|
+
root << features.map { |f| f.to_xml }.join.indent(2)
|
61
87
|
end
|
62
88
|
end
|
63
89
|
|
@@ -69,10 +95,8 @@ module AIXM
|
|
69
95
|
when Date then value.to_time
|
70
96
|
when Time then value
|
71
97
|
when nil then nil
|
72
|
-
else fail
|
98
|
+
else fail(ArgumentError, "invalid date or time")
|
73
99
|
end
|
74
|
-
rescue ArgumentError
|
75
|
-
raise(ArgumentError, "`#{value}' is not a valid date and time")
|
76
100
|
end
|
77
101
|
|
78
102
|
end
|