aixm 0.3.8 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +33 -3
  5. data/README.md +166 -56
  6. data/exe/ckmid +14 -0
  7. data/exe/mkmid +14 -0
  8. data/lib/aixm.rb +16 -6
  9. data/lib/aixm/association.rb +369 -0
  10. data/lib/aixm/classes.rb +43 -0
  11. data/lib/aixm/component/fato.rb +45 -53
  12. data/lib/aixm/component/frequency.rb +11 -12
  13. data/lib/aixm/component/geometry.rb +36 -38
  14. data/lib/aixm/component/geometry/arc.rb +2 -2
  15. data/lib/aixm/component/geometry/border.rb +6 -3
  16. data/lib/aixm/component/geometry/circle.rb +8 -2
  17. data/lib/aixm/component/geometry/point.rb +8 -2
  18. data/lib/aixm/component/helipad.rb +30 -38
  19. data/lib/aixm/component/layer.rb +28 -19
  20. data/lib/aixm/component/lighting.rb +12 -13
  21. data/lib/aixm/component/runway.rb +44 -48
  22. data/lib/aixm/{feature → component}/service.rb +37 -36
  23. data/lib/aixm/component/surface.rb +3 -3
  24. data/lib/aixm/component/timetable.rb +2 -2
  25. data/lib/aixm/component/{vertical_limits.rb → vertical_limit.rb} +12 -6
  26. data/lib/aixm/config.rb +2 -1
  27. data/lib/aixm/document.rb +27 -50
  28. data/lib/aixm/executables.rb +85 -0
  29. data/lib/aixm/feature.rb +13 -3
  30. data/lib/aixm/feature/address.rb +12 -13
  31. data/lib/aixm/feature/airport.rb +103 -128
  32. data/lib/aixm/feature/airspace.rb +44 -17
  33. data/lib/aixm/feature/navigational_aid.rb +7 -9
  34. data/lib/aixm/feature/navigational_aid/designated_point.rb +13 -15
  35. data/lib/aixm/feature/navigational_aid/dme.rb +11 -12
  36. data/lib/aixm/feature/navigational_aid/marker.rb +7 -3
  37. data/lib/aixm/feature/navigational_aid/ndb.rb +7 -3
  38. data/lib/aixm/feature/navigational_aid/tacan.rb +7 -3
  39. data/lib/aixm/feature/navigational_aid/vor.rb +23 -15
  40. data/lib/aixm/feature/obstacle.rb +29 -43
  41. data/lib/aixm/feature/obstacle_group.rb +37 -34
  42. data/lib/aixm/feature/organisation.rb +21 -5
  43. data/lib/aixm/feature/unit.rb +36 -46
  44. data/lib/aixm/memoize.rb +89 -0
  45. data/lib/aixm/object.rb +9 -0
  46. data/lib/aixm/payload_hash.rb +114 -0
  47. data/lib/aixm/refinements.rb +29 -76
  48. data/lib/aixm/shortcuts.rb +5 -42
  49. data/lib/aixm/version.rb +1 -1
  50. data/lib/aixm/xy.rb +1 -1
  51. data/schemas/ofmx/0/OFMX-Features.xsd +152 -20
  52. data/schemas/ofmx/0/OFMX-Snapshot.xsd +0 -5
  53. metadata +107 -156
  54. metadata.gz.sig +2 -0
  55. data/.github/workflows/test.yml +0 -26
  56. data/.gitignore +0 -6
  57. data/.ruby-version +0 -1
  58. data/.yardopts +0 -3
  59. data/Guardfile +0 -8
  60. data/aixm.gemspec +0 -35
  61. data/gems.rb +0 -3
  62. data/lib/aixm/component.rb +0 -6
  63. data/rakefile.rb +0 -36
  64. data/spec/factory.rb +0 -559
  65. data/spec/lib/aixm/a_spec.rb +0 -203
  66. data/spec/lib/aixm/component/fato_spec.rb +0 -267
  67. data/spec/lib/aixm/component/frequency_spec.rb +0 -74
  68. data/spec/lib/aixm/component/geometry/arc_spec.rb +0 -73
  69. data/spec/lib/aixm/component/geometry/border_spec.rb +0 -38
  70. data/spec/lib/aixm/component/geometry/circle_spec.rb +0 -68
  71. data/spec/lib/aixm/component/geometry/point_spec.rb +0 -37
  72. data/spec/lib/aixm/component/geometry_spec.rb +0 -316
  73. data/spec/lib/aixm/component/helipad_spec.rb +0 -193
  74. data/spec/lib/aixm/component/layer_spec.rb +0 -135
  75. data/spec/lib/aixm/component/lighting_spec.rb +0 -94
  76. data/spec/lib/aixm/component/runway_spec.rb +0 -479
  77. data/spec/lib/aixm/component/surface_spec.rb +0 -124
  78. data/spec/lib/aixm/component/timetable_spec.rb +0 -47
  79. data/spec/lib/aixm/component/vertical_limits_spec.rb +0 -94
  80. data/spec/lib/aixm/config_spec.rb +0 -41
  81. data/spec/lib/aixm/d_spec.rb +0 -150
  82. data/spec/lib/aixm/document_spec.rb +0 -1884
  83. data/spec/lib/aixm/errors_spec.rb +0 -14
  84. data/spec/lib/aixm/f_spec.rb +0 -85
  85. data/spec/lib/aixm/feature/address_spec.rb +0 -60
  86. data/spec/lib/aixm/feature/airport_spec.rb +0 -776
  87. data/spec/lib/aixm/feature/airspace_spec.rb +0 -394
  88. data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +0 -103
  89. data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +0 -98
  90. data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +0 -85
  91. data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +0 -95
  92. data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +0 -94
  93. data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +0 -251
  94. data/spec/lib/aixm/feature/navigational_aid_spec.rb +0 -52
  95. data/spec/lib/aixm/feature/obstacle_group_spec.rb +0 -330
  96. data/spec/lib/aixm/feature/obstacle_spec.rb +0 -284
  97. data/spec/lib/aixm/feature/organisation_spec.rb +0 -83
  98. data/spec/lib/aixm/feature/service_spec.rb +0 -59
  99. data/spec/lib/aixm/feature/unit_spec.rb +0 -238
  100. data/spec/lib/aixm/feature_spec.rb +0 -38
  101. data/spec/lib/aixm/p_spec.rb +0 -189
  102. data/spec/lib/aixm/refinements_spec.rb +0 -430
  103. data/spec/lib/aixm/version_spec.rb +0 -7
  104. data/spec/lib/aixm/w_spec.rb +0 -150
  105. data/spec/lib/aixm/xy_spec.rb +0 -180
  106. data/spec/lib/aixm/z_spec.rb +0 -94
  107. data/spec/macros/marking.rb +0 -12
  108. data/spec/macros/organisation.rb +0 -11
  109. data/spec/macros/remarks.rb +0 -12
  110. data/spec/macros/timetable.rb +0 -11
  111. data/spec/macros/xy.rb +0 -11
  112. data/spec/macros/z_qnh.rb +0 -11
  113. data/spec/sounds/failure.mp3 +0 -0
  114. data/spec/sounds/success.mp3 +0 -0
  115. data/spec/spec_helper.rb +0 -62
@@ -9,11 +9,12 @@ module AIXM
9
9
  # ===Cheat Sheet in Pseudo Code:
10
10
  # obstacle = AIXM.obstacle(
11
11
  # source: String or nil
12
+ # region: String or nil
12
13
  # name: String or nil
13
14
  # type: TYPES
14
15
  # xy: AIXM.xy
15
16
  # z: AIXM.z
16
- # radius: AIXM.d
17
+ # radius: AIXM.d or nil
17
18
  # )
18
19
  # obstacle.lighting = true or false (default for AIXM) or nil (means: unknown, default for OFMX)
19
20
  # obstacle.lighting_remarks = String or nil
@@ -32,12 +33,15 @@ module AIXM
32
33
  # See {AIXM::Feature::ObstacleGroup} for how to define physical links
33
34
  # between two obstacles (e.g. cables between powerline towers).
34
35
  #
35
- # Please note: As soon as an obstacle is added to an obstacle group, the
36
- # +xy_accuracy+ and +z_accuracy+ of the obstacle group overwrite whatever
37
- # is set on the individual obstacles!
36
+ # Please note: Accuracies (+xy_accuracy+ and +z_accuracy+) set on an
37
+ # obstacle group are implicitly applied to all obstacles of the group
38
+ # unless they have their own, different accuracies set.
38
39
  #
39
- # @see https://github.com/openflightmaps/ofmx/wiki/Obstacle
40
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Obstacle
40
41
  class Obstacle < Feature
42
+ include AIXM::Association
43
+ include AIXM::Memoize
44
+
41
45
  public_class_method :new
42
46
 
43
47
  TYPES = {
@@ -57,6 +61,10 @@ module AIXM
57
61
  OTHER: :other
58
62
  }.freeze
59
63
 
64
+ # @!method obstacle_group
65
+ # @return [AIXM::Feature::ObstacleGroup] group this obstacle belongs to
66
+ belongs_to :obstacle_group
67
+
60
68
  # @return [String] full name
61
69
  attr_reader :name
62
70
 
@@ -108,19 +116,16 @@ module AIXM
108
116
  # @return [String, nil] free text remarks
109
117
  attr_reader :remarks
110
118
 
111
- # @return [AIXM::Feature::ObstacleGroup] group this obstacle belongs to
112
- attr_reader :obstacle_group
113
-
114
119
  # @return [Symbol, nil] another obstacle to which a physical link exists
115
120
  attr_reader :linked_to
116
121
 
117
122
  # @return [Symbol, nil] type of physical link between this and another obstacle
118
123
  attr_reader :link_type
119
124
 
120
- def initialize(source: nil, name: nil, type:, xy:, z:, radius:)
121
- super(source: source)
125
+ def initialize(source: nil, region: nil, name: nil, type:, xy:, z:, radius: nil)
126
+ super(source: source, region: region)
122
127
  self.name, self.type, self.xy, self.z, self.radius = name, type, xy, z, radius
123
- @lighting = @marking = @height_accurate = false
128
+ @lighting = @marking = false
124
129
  end
125
130
 
126
131
  # @return [String]
@@ -202,12 +207,6 @@ module AIXM
202
207
  @remarks = value&.to_s
203
208
  end
204
209
 
205
- def obstacle_group=(value)
206
- fail(ArgumentError, "invalid obstacle group") unless value.is_a?(AIXM::Feature::ObstacleGroup)
207
- @obstacle_group = value
208
- end
209
- private :obstacle_group=
210
-
211
210
  def linked_to=(value)
212
211
  fail(ArgumentError, "invalid linked to") unless value.is_a?(AIXM::Feature::Obstacle)
213
212
  @linked_to = value
@@ -219,11 +218,6 @@ module AIXM
219
218
  end
220
219
  private :link_type=
221
220
 
222
- # @return [Boolean] whether part of an obstacle group
223
- def grouped?
224
- obstacle_group && obstacle_group.obstacles.count > 1
225
- end
226
-
227
221
  # @return [Boolean] whether obstacle is linked to another one
228
222
  def linked?
229
223
  !!linked_to
@@ -231,30 +225,29 @@ module AIXM
231
225
 
232
226
  # @return [String] UID markup
233
227
  def to_uid(as: :ObsUid)
234
- self.obstacle_group ||= singleton_obstacle_group
235
228
  builder = Builder::XmlMarkup.new(indent: 2)
236
- builder.tag!(as) do |tag|
237
- tag << obstacle_group.to_uid.indent(2) if AIXM.ofmx?
229
+ builder.tag!(as, { region: (region if AIXM.ofmx?) }.compact) do |tag|
238
230
  tag.geoLat((xy.lat(AIXM.schema)))
239
231
  tag.geoLong((xy.long(AIXM.schema)))
240
- end.insert_payload_hash(region: AIXM.config.mid_region)
232
+ end
241
233
  end
234
+ memoize :to_uid
242
235
 
243
236
  # @return [String] AIXM or OFMX markup
244
237
  def to_xml(delegate: true)
245
- self.obstacle_group ||= singleton_obstacle_group
246
- return obstacle_group.to_xml if delegate && AIXM.ofmx?
238
+ return obstacle_group.to_xml if delegate && obstacle_group && AIXM.ofmx?
247
239
  builder = Builder::XmlMarkup.new(indent: 2)
248
240
  builder.comment! "Obstacle: [#{type}] #{xy.to_s} #{name}".strip
249
241
  builder.Obs do |obs|
250
242
  obs << to_uid.indent(2)
243
+ obs << obstacle_group.to_uid.indent(2) if obstacle_group && AIXM.ofmx?
251
244
  obs.txtName(name) if name
252
245
  if AIXM.ofmx?
253
246
  obs.codeType(TYPES.key(type).to_s)
254
247
  else
255
248
  obs.txtDescrType(TYPES.key(type).to_s)
256
249
  end
257
- obs.codeGroup(grouped? ? 'Y' : 'N')
250
+ obs.codeGroup(obstacle_group ? 'Y' : 'N') if AIXM.aixm?
258
251
  if AIXM.ofmx?
259
252
  obs.codeLgt(lighting ? 'Y' : 'N') unless lighting.nil?
260
253
  obs.codeMarking(marking ? 'Y' : 'N') unless marking.nil?
@@ -264,13 +257,14 @@ module AIXM
264
257
  obs.txtDescrLgt(lighting_remarks) if lighting_remarks
265
258
  obs.txtDescrMarking(marking_remarks) if marking_remarks
266
259
  obs.codeDatum('WGE')
267
- if AIXM.aixm? && obstacle_group.xy_accuracy
268
- obs.valGeoAccuracy(obstacle_group.xy_accuracy.dist.trim)
269
- obs.uomGeoAccuracy(obstacle_group.xy_accuracy.unit.upcase.to_s)
260
+ if accuracy = (xy_accuracy || (obstacle_group&.xy_accuracy if AIXM.aixm?))
261
+ obs.valGeoAccuracy(accuracy.dist.trim)
262
+ obs.uomGeoAccuracy(accuracy.unit.upcase.to_s)
270
263
  end
271
264
  obs.valElev(z.alt)
272
- if AIXM.aixm? && obstacle_group.z_accuracy
273
- obs.valElevAccuracy(obstacle_group.z_accuracy.to_ft.dist.round)
265
+ if accuracy = (z_accuracy || (obstacle_group&.z_accuracy if AIXM.aixm?))
266
+ obs.valElevAccuracy(accuracy.to_ft.dist.round)
267
+ obs.uomElevAccuracy('FT') if AIXM.ofmx?
274
268
  end
275
269
  obs.valHgt(height.to_ft.dist.round) if height
276
270
  obs.uomDistVer('FT')
@@ -282,7 +276,7 @@ module AIXM
282
276
  obs.valRadius(radius.dist.trim)
283
277
  obs.uomRadius(radius.unit.upcase.to_s)
284
278
  end
285
- if grouped? && linked?
279
+ if linked?
286
280
  obs << linked_to.to_uid(as: :ObsUidLink).indent(2)
287
281
  obs.codeLinkType(LINK_TYPES.key(link_type).to_s)
288
282
  end
@@ -293,14 +287,6 @@ module AIXM
293
287
  end
294
288
  end
295
289
 
296
- private
297
-
298
- # OFMX requires single, ungrouped obstacles to be the only member of a
299
- # singleton obstacle group.
300
- def singleton_obstacle_group
301
- AIXM.obstacle_group.add_obstacle self
302
- end
303
-
304
290
  end
305
291
  end
306
292
  end
@@ -6,9 +6,15 @@ module AIXM
6
6
  # Groups of obstacles which consist of either linked (e.g. power line
7
7
  # towers) or unlinked (e.g. wind turbines) members.
8
8
  #
9
+ # Obstacle group should contain at least two obstacles. However, if the
10
+ # details of each obstacle of the group are unknown, you may add only one
11
+ # virtual obstacle to the group and mention the number of real obstacles
12
+ # in it's remarks.
13
+ #
9
14
  # ===Cheat Sheet in Pseudo Code:
10
15
  # obstacle_group = AIXM.obstacle_group(
11
16
  # source: String or nil # see remarks below
17
+ # region: String or nil
12
18
  # name: String or nil
13
19
  # ).tap do |obstacle_group|
14
20
  # obstacle_group.xy_accuracy = AIXM.d or nil
@@ -29,14 +35,34 @@ module AIXM
29
35
  # link_type: LINK_TYPES
30
36
  # )
31
37
  #
32
- # Please note: As soon as an obstacle is added to an obstacle group, the
33
- # +xy_accuracy+ and +z_accuracy+ of the obstacle group overwrite whatever
34
- # is set on the individual obstacles!
38
+ # Please note: Accuracies (+xy_accuracy+ and +z_accuracy+) set on an
39
+ # obstacle group are implicitly applied to all obstacles of the group
40
+ # unless they have their own, different accuracies set.
35
41
  #
36
- # @see https://github.com/openflightmaps/ofmx/wiki/Obstacle
42
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Obstacle
37
43
  class ObstacleGroup < Feature
44
+ include AIXM::Association
45
+ include AIXM::Memoize
46
+
38
47
  public_class_method :new
39
48
 
49
+ # @!method obstacles
50
+ # @return [Array<AIXM::Feature::Obstacle>] obstacles in this obstacle group
51
+ # @!method add_obstacle(obstacle, linked_to: nil, link_type: nil)
52
+ # @param obstacle [AIXM::Feature::Obstacle] obstacle instance
53
+ # @param linked_to [Symbol, AIXM::Feature::Obstacle, nil] Either:
54
+ # * :previous - link to the obstacle last added to the obstacle group
55
+ # * AIXM::Feature::Obstacle - link to this specific obstacle
56
+ # @param link_type [Symbol, nil] type of link (see
57
+ # {AIXM::Feature::Obstacle::LINK_TYPES})
58
+ # @return [self]
59
+ has_many :obstacles do |obstacle, linked_to: nil, link_type: nil|
60
+ if linked_to
61
+ obstacle.send(:linked_to=, linked_to == :previous ? @obstacles.last : linked_to)
62
+ obstacle.send(:link_type=, (link_type || :other))
63
+ end
64
+ end
65
+
40
66
  # @!method source
41
67
  # @return [String] reference to source of the feature data
42
68
  # @!method name
@@ -54,13 +80,9 @@ module AIXM
54
80
  # @return [String, nil] free text remarks
55
81
  attr_reader :remarks
56
82
 
57
- # @return [Array<AIXM::Feature::Obstacle>] obstacles in this obstacle group
58
- attr_reader :obstacles
59
-
60
- def initialize(source: nil, name: nil)
61
- super(source: source)
83
+ def initialize(source: nil, region: nil, name: nil)
84
+ super(source: source, region: region)
62
85
  self.name = name
63
- @obstacles = []
64
86
  end
65
87
 
66
88
  # @return [String]
@@ -87,35 +109,15 @@ module AIXM
87
109
  @remarks = value&.to_s
88
110
  end
89
111
 
90
- # Add an obstacle to the obstacle group and optionally link it to another
91
- # obstacle from the obstacle group.
92
- #
93
- # @param obstacle [AIXM::Feature::Obstacle] obstacle instance
94
- # @param linked_to [Symbol, AIXM::Feature::Obstacle, nil] Either:
95
- # * :previous - link to the obstacle last added to the obstacle group
96
- # * AIXM::Feature::Obstacle - link to this specific obstacle
97
- # @param link_type [Symbol, nil] type of link (see
98
- # {AIXM::Feature::Obstacle::LINK_TYPES})
99
- # @return [self]
100
- def add_obstacle(obstacle, linked_to: nil, link_type: :other)
101
- obstacle.send(:obstacle_group=, self)
102
- if linked_to && link_type
103
- obstacle.send(:linked_to=, linked_to == :previous ? @obstacles.last : linked_to)
104
- obstacle.send(:link_type=, link_type)
105
- end
106
- @obstacles << obstacle
107
- self
108
- end
109
-
110
112
  # @return [String] UID markup
111
113
  def to_uid
112
114
  builder = Builder::XmlMarkup.new(indent: 2)
113
- builder.OgrUid do |ogr_uid|
114
- ogr_uid.txtName(name)
115
+ builder.OgrUid({ region: (region if AIXM.ofmx?) }.compact) do |ogr_uid|
115
116
  ogr_uid.geoLat(obstacles.first.xy.lat(AIXM.schema))
116
117
  ogr_uid.geoLong(obstacles.first.xy.long(AIXM.schema))
117
- end.insert_payload_hash(region: AIXM.config.mid_region)
118
+ end
118
119
  end
120
+ memoize :to_uid
119
121
 
120
122
  # @return [String] AIXM or OFMX markup
121
123
  def to_xml
@@ -124,6 +126,7 @@ module AIXM
124
126
  builder.comment! "Obstacle group: #{name}".strip
125
127
  builder.Ogr({ source: (source if AIXM.ofmx?) }.compact) do |ogr|
126
128
  ogr << to_uid.indent(2)
129
+ ogr.txtName(name)
127
130
  ogr.codeDatum('WGE')
128
131
  if xy_accuracy
129
132
  ogr.valGeoAccuracy(xy_accuracy.dist.trim)
@@ -136,7 +139,7 @@ module AIXM
136
139
  ogr.txtRmk(remarks) if remarks
137
140
  end
138
141
  end
139
- obstacles.each { |o| builder << o.to_xml(delegate: false) }
142
+ obstacles.each { builder << _1.to_xml(delegate: false) }
140
143
  builder.target!
141
144
  end
142
145
  end
@@ -9,14 +9,18 @@ module AIXM
9
9
  # ===Cheat Sheet in Pseudo Code:
10
10
  # organisation = AIXM.organisation(
11
11
  # source: String or nil
12
+ # region: String or nil
12
13
  # name: String
13
14
  # type: TYPES
14
15
  # )
15
16
  # organisation.id = String or nil
16
17
  # organisation.remarks = String or nil
17
18
  #
18
- # @see https://github.com/openflightmaps/ofmx/wiki/Organisation#org-organisation
19
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Organisation#org-organisation
19
20
  class Organisation < Feature
21
+ include AIXM::Association
22
+ include AIXM::Memoize
23
+
20
24
  public_class_method :new
21
25
 
22
26
  TYPES = {
@@ -31,6 +35,17 @@ module AIXM
31
35
  OTHER: :other # specify in remarks
32
36
  }.freeze
33
37
 
38
+ # @!method members
39
+ # @return [Array<AIXM::Feature::Airport,
40
+ # AIXM::Feature::Unit,
41
+ # AIXM::Feature::NavigationalAid>] aiports, units or navigational aids
42
+ # @!method add_member(member)
43
+ # @param member [AIXM::Feature::Airport,
44
+ # AIXM::Feature::Unit,
45
+ # AIXM::Feature::NavigationalAid]
46
+ # @return [self]
47
+ has_many :members, accept: [:airport, :unit, 'AIXM::Feature::NavigationalAid']
48
+
34
49
  # @return [String] name of organisation (e.g. "FRANCE")
35
50
  attr_reader :name
36
51
 
@@ -43,8 +58,8 @@ module AIXM
43
58
  # @return [String, nil] free text remarks
44
59
  attr_reader :remarks
45
60
 
46
- def initialize(source: nil, name:, type:)
47
- super(source: source)
61
+ def initialize(source: nil, region: nil, name:, type:)
62
+ super(source: source, region: region)
48
63
  self.name, self.type = name, type
49
64
  end
50
65
 
@@ -74,10 +89,11 @@ module AIXM
74
89
  # @return [String] UID markup
75
90
  def to_uid
76
91
  builder = Builder::XmlMarkup.new(indent: 2)
77
- builder.OrgUid do |org_uid|
92
+ builder.OrgUid({ region: (region if AIXM.ofmx?) }.compact) do |org_uid|
78
93
  org_uid.txtName(name)
79
- end.insert_payload_hash(region: AIXM.config.mid_region)
94
+ end
80
95
  end
96
+ memoize :to_uid
81
97
 
82
98
  # @return [String] AIXM or OFMX markup
83
99
  def to_xml
@@ -9,6 +9,7 @@ module AIXM
9
9
  # ===Cheat Sheet in Pseudo Code:
10
10
  # unit = AIXM.unit(
11
11
  # source: String or nil
12
+ # region: String or nil
12
13
  # organisation: AIXM.organisation
13
14
  # name: String
14
15
  # type: TYPES
@@ -18,8 +19,11 @@ module AIXM
18
19
  # unit.remarks = String or nil
19
20
  # unit.add_service(AIXM.service)
20
21
  #
21
- # @see https://github.com/openflightmaps/ofmx/wiki/Organisation#uni-unit
22
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Organisation#uni-unit
22
23
  class Unit < Feature
24
+ include AIXM::Association
25
+ include AIXM::Memoize
26
+
23
27
  public_class_method :new
24
28
 
25
29
  TYPES = {
@@ -76,8 +80,19 @@ module AIXM
76
80
  OTHER: :other # specify in remarks
77
81
  }.freeze
78
82
 
79
- # @return [AIXM::Feature::Organisation] superior organisation
80
- attr_reader :organisation
83
+ # @!method services
84
+ # @return [Array<AIXM::Component::Service>] services provided by this unit
85
+ # @!method add_service(service)
86
+ # @param service [AIXM::Component::Service]
87
+ has_many :services
88
+
89
+ # @!method organisation
90
+ # @return [AIXM::Feature::Organisation] superior organisation
91
+ belongs_to :organisation, as: :member
92
+
93
+ # @!method airport
94
+ # @return [AIXM::Feature::Airport, nil] airport
95
+ belongs_to :airport
81
96
 
82
97
  # @return [String] name of unit (e.g. "MARSEILLE ACS")
83
98
  attr_reader :name
@@ -85,27 +100,18 @@ module AIXM
85
100
  # @return [Symbol] type of unit (see {TYPES})
86
101
  attr_reader :type
87
102
 
88
- # @return [AIXM::Feature::Airport, nil] airport
89
- attr_reader :airport
90
-
91
103
  # @return [String, nil] free text remarks
92
104
  attr_reader :remarks
93
105
 
94
- def initialize(source: nil, organisation:, name:, type:, class:)
95
- super(source: source)
106
+ def initialize(source: nil, region: nil, organisation:, name:, type:, class:)
107
+ super(source: source, region: region)
96
108
  self.organisation, self.name, self.type = organisation, name, type
97
109
  self.class = binding.local_variable_get(:class)
98
- @services = []
99
110
  end
100
111
 
101
112
  # @return [String]
102
113
  def inspect
103
- %Q(#<#{original_class} name=#{name.inspect} type=#{type.inspect}>)
104
- end
105
-
106
- def organisation=(value)
107
- fail(ArgumentError, "invalid organisation") unless value.is_a? AIXM::Feature::Organisation
108
- @organisation = value
114
+ %Q(#<#{__class__} name=#{name.inspect} type=#{type.inspect}>)
109
115
  end
110
116
 
111
117
  def name=(value)
@@ -118,9 +124,8 @@ module AIXM
118
124
  end
119
125
 
120
126
  # @!attribute class
121
- # @note Use +original_class+ to query the Ruby object class.
127
+ # @note Use +Object#__class__+ alias to query the Ruby object class.
122
128
  # @return [Symbol] class of unit (see {CLASSES})
123
- alias_method :original_class, :class
124
129
  def class
125
130
  @klass
126
131
  end
@@ -129,58 +134,43 @@ module AIXM
129
134
  @klass = CLASSES.lookup(value&.to_s&.to_sym, nil) || fail(ArgumentError, "invalid class")
130
135
  end
131
136
 
132
- def airport=(value)
133
- fail(ArgumentError, "invalid airport") unless value.nil? || value.is_a?(AIXM::Feature::Airport)
134
- @airport = value
135
- end
136
-
137
137
  def remarks=(value)
138
138
  @remarks = value&.to_s
139
139
  end
140
140
 
141
- # Add a service provided by this unit.
142
- #
143
- # @param service [AIXM::Feature::Service] service instance
144
- # @return [self]
145
- def add_service(service)
146
- fail(ArgumentError, "invalid service") unless service.is_a? AIXM::Feature::Service
147
- service.send(:unit=, self)
148
- @services << service
149
- self
150
- end
151
-
152
- # @!attribute [r] services
153
- # @return [Array<AIXM::Feature::Service>] services provided by this unit
154
- def services
155
- @services.sort { |a, b| a.type <=> b.type }
156
- end
157
-
158
141
  # @return [String] UID markup
159
142
  def to_uid
160
143
  builder = Builder::XmlMarkup.new(indent: 2)
161
- builder.UniUid do |uni_uid|
144
+ builder.UniUid({ region: (region if AIXM.ofmx?) }.compact) do |uni_uid|
162
145
  uni_uid.txtName(name)
163
- end.insert_payload_hash(region: AIXM.config.mid_region)
146
+ uni_uid.codeType(TYPES.key(type).to_s) if AIXM.ofmx?
147
+ end
164
148
  end
149
+ memoize :to_uid
165
150
 
166
151
  # @return [String] AIXM or OFMX markup
167
152
  def to_xml
168
153
  builder = Builder::XmlMarkup.new(indent: 2)
169
- builder.comment! "Unit: #{name}"
154
+ builder.comment! "Unit: #{name_with_type}"
170
155
  builder.Uni({ source: (source if AIXM.ofmx?) }.compact) do |uni|
171
156
  uni << to_uid.indent(2)
172
157
  uni << organisation.to_uid.indent(2)
173
158
  uni << airport.to_uid.indent(2) if airport
174
- uni.codeType(TYPES.key(type).to_s)
159
+ uni.codeType(TYPES.key(type).to_s) unless AIXM.ofmx?
175
160
  uni.codeClass(CLASSES.key(self.class).to_s)
176
161
  uni.txtRmk(remarks) if remarks
177
162
  end
178
- services.each.with_object({}) do |service, sequences|
179
- sequences[service.type] = (sequences[service.type] || 0) + 1
180
- builder << service.to_xml(sequence: sequences[service.type])
163
+ services.sort { |a, b| a.type <=> b.type }.each do |service|
164
+ builder << service.to_xml
181
165
  end
182
166
  builder.target!
183
167
  end
168
+
169
+ private
170
+
171
+ def name_with_type
172
+ [name, TYPES.key(type)].join(' ')
173
+ end
184
174
  end
185
175
 
186
176
  end