aixm 1.2.1 → 1.3.1
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +23 -3
- data/README.md +37 -2
- data/exe/ckmid +1 -7
- data/exe/mkmid +1 -7
- data/lib/aixm/classes.rb +3 -1
- data/lib/aixm/component/address.rb +12 -15
- data/lib/aixm/component/approach_lighting.rb +11 -16
- data/lib/aixm/component/fato.rb +22 -34
- data/lib/aixm/component/frequency.rb +10 -15
- data/lib/aixm/component/geometry/arc.rb +2 -3
- data/lib/aixm/component/geometry/border.rb +6 -10
- data/lib/aixm/component/geometry/circle.rb +4 -4
- data/lib/aixm/component/geometry/point.rb +4 -4
- data/lib/aixm/component/geometry/rhumb_line.rb +4 -4
- data/lib/aixm/component/geometry.rb +4 -4
- data/lib/aixm/component/helipad.rb +13 -20
- data/lib/aixm/component/layer.rb +6 -8
- data/lib/aixm/component/lighting.rb +12 -17
- data/lib/aixm/component/runway.rb +26 -38
- data/lib/aixm/component/service.rb +12 -16
- data/lib/aixm/component/surface.rb +8 -10
- data/lib/aixm/component/timesheet.rb +9 -10
- data/lib/aixm/component/timetable.rb +6 -7
- data/lib/aixm/component/vasis.rb +6 -8
- data/lib/aixm/component/vertical_limit.rb +8 -8
- data/lib/aixm/component.rb +3 -2
- data/lib/aixm/concerns/association.rb +381 -0
- data/lib/aixm/concerns/memoize.rb +107 -0
- data/lib/aixm/concerns/xml_builder.rb +34 -0
- data/lib/aixm/document.rb +52 -21
- data/lib/aixm/feature/airport.rb +44 -47
- data/lib/aixm/feature/airspace.rb +29 -34
- data/lib/aixm/feature/generic.rb +67 -0
- data/lib/aixm/feature/navigational_aid/designated_point.rb +11 -13
- data/lib/aixm/feature/navigational_aid/dme.rb +12 -15
- data/lib/aixm/feature/navigational_aid/marker.rb +12 -15
- data/lib/aixm/feature/navigational_aid/ndb.rb +13 -16
- data/lib/aixm/feature/navigational_aid/tacan.rb +15 -17
- data/lib/aixm/feature/navigational_aid/vor.rb +16 -19
- data/lib/aixm/feature/navigational_aid.rb +7 -7
- data/lib/aixm/feature/obstacle.rb +20 -21
- data/lib/aixm/feature/obstacle_group.rb +19 -20
- data/lib/aixm/feature/organisation.rb +11 -12
- data/lib/aixm/feature/unit.rb +16 -18
- data/lib/aixm/feature.rb +26 -7
- data/lib/aixm/object.rb +1 -1
- data/lib/aixm/refinements.rb +57 -0
- data/lib/aixm/schedule/date.rb +13 -1
- data/lib/aixm/schedule/date_time.rb +56 -0
- data/lib/aixm/schedule/time.rb +5 -1
- data/lib/aixm/shortcuts.rb +8 -2
- data/lib/aixm/version.rb +1 -1
- data/lib/aixm.rb +5 -3
- data/schemas/ofmx/0.1/OFMX-Snapshot.xsd +6 -1
- data.tar.gz.sig +2 -3
- metadata +26 -38
- metadata.gz.sig +2 -3
- data/lib/aixm/association.rb +0 -378
- data/lib/aixm/memoize.rb +0 -105
@@ -0,0 +1,56 @@
|
|
1
|
+
using AIXM::Refinements
|
2
|
+
|
3
|
+
module AIXM
|
4
|
+
module Schedule
|
5
|
+
|
6
|
+
# Datetimes suitable for schedules
|
7
|
+
#
|
8
|
+
# This class combines +AIXM::Schedule::Date+ and +AIXM::Schedule::Time+:
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# datetime = AIXM.datetime('2022-04-20', '20:00') # => 2022-04-20 20:00
|
12
|
+
# datetime.date # => 2022-04-20
|
13
|
+
# datetime.date.class # => AIXM::Schedule::Date
|
14
|
+
# datetime.time # => 20:00
|
15
|
+
# datetime.time.class # => AIXM::Schedule::Time
|
16
|
+
class DateTime
|
17
|
+
|
18
|
+
# Date part
|
19
|
+
#
|
20
|
+
# @return [AIXM::Schedule::Date]
|
21
|
+
attr_reader :date
|
22
|
+
|
23
|
+
# Time part
|
24
|
+
#
|
25
|
+
# @return [AIXM::Schedule::Time]
|
26
|
+
attr_reader :time
|
27
|
+
|
28
|
+
# Parse the given representation of date and time.
|
29
|
+
#
|
30
|
+
# @param date [AIXM::Schedule::Date]
|
31
|
+
# @param time [AIXM::Schedule::Time]
|
32
|
+
def initialize(date, time)
|
33
|
+
fail(ArgumentError, 'invalid date') unless date.instance_of? AIXM::Schedule::Date
|
34
|
+
fail(ArgumentError, 'invalid time') unless time.instance_of? AIXM::Schedule::Time
|
35
|
+
@date, @time = date, time
|
36
|
+
end
|
37
|
+
|
38
|
+
# Human readable representation such as "2002-05-19 20:00"
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
def to_s
|
42
|
+
[@date.to_s, @time.to_s].join(' ')
|
43
|
+
end
|
44
|
+
|
45
|
+
def inspect
|
46
|
+
%Q(#<#{self.class} #{to_s}>)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @see Object#hash
|
50
|
+
def hash
|
51
|
+
[@date.hash, @time.hash].hash
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/aixm/schedule/time.rb
CHANGED
@@ -19,6 +19,10 @@ module AIXM
|
|
19
19
|
# @example
|
20
20
|
# time = AIXM.time('21:30') # => 21:30
|
21
21
|
# time.covered_by?(AIXM.time('20:00')..AIXM.time('02:00')) # => true
|
22
|
+
#
|
23
|
+
# ===Shortcuts:
|
24
|
+
# * +AIXM::BEGINNING_OF_DAY+ - midnight expressed as "00:00"
|
25
|
+
# * +AIXM::END_OF_DAY+ - midnight expressed as "24:00"
|
22
26
|
class Time
|
23
27
|
include AIXM::Concerns::HashEquality
|
24
28
|
extend Forwardable
|
@@ -73,7 +77,7 @@ module AIXM
|
|
73
77
|
case time_or_event
|
74
78
|
when Symbol
|
75
79
|
self.event = time_or_event
|
76
|
-
when ::Time, DateTime
|
80
|
+
when ::Time, ::DateTime
|
77
81
|
time_or_event = time_or_event.to_time
|
78
82
|
set_time(time_or_event.hour, time_or_event.min, time_or_event.utc_offset)
|
79
83
|
when /\A(\d{2}):?(\d{2}) ?([+-]\d{2}:?\d{2}|UTC)?\z/
|
data/lib/aixm/shortcuts.rb
CHANGED
@@ -15,10 +15,16 @@ module AIXM
|
|
15
15
|
# Max flight level used to signal "no upper limit"
|
16
16
|
UNLIMITED = z(999, :qne).freeze
|
17
17
|
|
18
|
+
# Day to signal "whatever date or day"
|
19
|
+
ANY_DAY = AIXM.day(:any).freeze
|
20
|
+
|
18
21
|
# Timetable used to signal "always active"
|
19
22
|
H24 = timetable(code: :H24).freeze
|
20
23
|
|
21
|
-
#
|
22
|
-
|
24
|
+
# Time which marks midnight at beginning of the day
|
25
|
+
BEGINNING_OF_DAY = AIXM.time('00:00').freeze
|
26
|
+
|
27
|
+
# Time which marks midnight at end of the day
|
28
|
+
END_OF_DAY = AIXM.time('24:00').freeze
|
23
29
|
|
24
30
|
end
|
data/lib/aixm/version.rb
CHANGED
data/lib/aixm.rb
CHANGED
@@ -8,7 +8,6 @@ require 'forwardable'
|
|
8
8
|
require 'digest'
|
9
9
|
require 'optparse'
|
10
10
|
|
11
|
-
require 'builder'
|
12
11
|
require 'nokogiri'
|
13
12
|
require 'dry/inflector'
|
14
13
|
require 'sun'
|
@@ -22,10 +21,11 @@ require_relative 'aixm/errors'
|
|
22
21
|
|
23
22
|
require_relative 'aixm/classes'
|
24
23
|
require_relative 'aixm/constants'
|
25
|
-
require_relative 'aixm/memoize'
|
26
|
-
require_relative 'aixm/association'
|
27
24
|
require_relative 'aixm/payload_hash'
|
28
25
|
|
26
|
+
require_relative 'aixm/concerns/memoize'
|
27
|
+
require_relative 'aixm/concerns/association'
|
28
|
+
require_relative 'aixm/concerns/xml_builder'
|
29
29
|
require_relative 'aixm/concerns/hash_equality'
|
30
30
|
require_relative 'aixm/concerns/timetable'
|
31
31
|
require_relative 'aixm/concerns/intensity'
|
@@ -45,6 +45,7 @@ require_relative 'aixm/p'
|
|
45
45
|
require_relative 'aixm/schedule/date'
|
46
46
|
require_relative 'aixm/schedule/day'
|
47
47
|
require_relative 'aixm/schedule/time'
|
48
|
+
require_relative 'aixm/schedule/date_time'
|
48
49
|
|
49
50
|
require_relative 'aixm/component'
|
50
51
|
require_relative 'aixm/component/address'
|
@@ -82,6 +83,7 @@ require_relative 'aixm/feature/obstacle'
|
|
82
83
|
require_relative 'aixm/feature/obstacle_group'
|
83
84
|
require_relative 'aixm/feature/organisation'
|
84
85
|
require_relative 'aixm/feature/unit'
|
86
|
+
require_relative 'aixm/feature/generic'
|
85
87
|
|
86
88
|
require_relative 'aixm/shortcuts'
|
87
89
|
require_relative 'aixm/executables'
|
@@ -215,7 +215,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
215
215
|
</xsd:attribute>
|
216
216
|
<xsd:attribute name="effective" type="xsd:dateTime" use="required">
|
217
217
|
<xsd:annotation>
|
218
|
-
<xsd:documentation>The date and time used as criteria to select valid versions included in the message</xsd:documentation>
|
218
|
+
<xsd:documentation>The beginning date and time used as criteria to select valid versions included in the message</xsd:documentation>
|
219
|
+
</xsd:annotation>
|
220
|
+
</xsd:attribute>
|
221
|
+
<xsd:attribute name="expiration" type="xsd:dateTime">
|
222
|
+
<xsd:annotation>
|
223
|
+
<xsd:documentation>The optional end date and time used as criteria to select valid versions included in the message</xsd:documentation>
|
219
224
|
</xsd:annotation>
|
220
225
|
</xsd:attribute>
|
221
226
|
</xsd:complexType>
|
data.tar.gz.sig
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
|
2
|
-
�
|
3
|
-
uL��y4Du3��"�����jwnTT���m����O*���n�
|
1
|
+
��W���c�
|
2
|
+
滺P~��[�9�z'�:������w3w�41�S�/0�Н$f�t��w;�m�O[�l�ϭ�ώK�Wy��z6�t���L��3�����3xjB��d�!}P�9�hQe�-���%�*4��֎�_B��Ku�'Y���5�K��)4FX�}�����&���0�PR����B�ՠ�B32�cZ���ӎA8v^���w��Ӎ�����ɹ��M�7|&6;�%7\���4n�M��!�O����r�
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aixm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sven Schwyn
|
@@ -10,42 +10,27 @@ bindir: exe
|
|
10
10
|
cert_chain:
|
11
11
|
- |
|
12
12
|
-----BEGIN CERTIFICATE-----
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
5JcY2h7owdMxXIvgk1oakgldFJc=
|
13
|
+
MIIDODCCAiCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhydWJ5
|
14
|
+
L0RDPWJpdGNldGVyYS9EQz1jb20wHhcNMjIxMTA2MTIzNjUwWhcNMjMxMTA2MTIz
|
15
|
+
NjUwWjAjMSEwHwYDVQQDDBhydWJ5L0RDPWJpdGNldGVyYS9EQz1jb20wggEiMA0G
|
16
|
+
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcLg+IHjXYaUlTSU7R235lQKD8ZhEe
|
17
|
+
KMhoGlSUonZ/zo1OT3KXcqTCP1iMX743xYs6upEGALCWWwq+nxvlDdnWRjF3AAv7
|
18
|
+
ikC+Z2BEowjyeCCT/0gvn4ohKcR0JOzzRaIlFUVInlGSAHx2QHZ2N8ntf54lu7nd
|
19
|
+
L8CiDK8rClsY4JBNGOgH9UC81f+m61UUQuTLxyM2CXfAYkj/sGNTvFRJcNX+nfdC
|
20
|
+
hM9r2kH1+7wsa8yG7wJ2IkrzNACD8v84oE6qVusN8OLEMUI/NaEPVPbw2LUM149H
|
21
|
+
PVa0i729A4IhroNnFNmw4wOC93ARNbM1+LW36PLMmKjKudf5Exg8VmDVAgMBAAGj
|
22
|
+
dzB1MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSfK8MtR62mQ6oN
|
23
|
+
yoX/VKJzFjLSVDAdBgNVHREEFjAUgRJydWJ5QGJpdGNldGVyYS5jb20wHQYDVR0S
|
24
|
+
BBYwFIEScnVieUBiaXRjZXRlcmEuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAYG2na
|
25
|
+
ye8OE2DANQIFM/xDos/E4DaPWCJjX5xvFKNKHMCeQYPeZvLICCwyw2paE7Otwk6p
|
26
|
+
uvbg2Ks5ykXsbk5i6vxDoeeOLvmxCqI6m+tHb8v7VZtmwRJm8so0eSX0WvTaKnIf
|
27
|
+
CAn1bVUggczVdNoBXw9WAILKyw9bvh3Ft740XZrR74sd+m2pGwjCaM8hzLvrVbGP
|
28
|
+
DyYhlBeRWyQKQ0WDIsiTSRhzK8HwSTUWjvPwx7SEdIU/HZgyrk0ETObKPakVu6bH
|
29
|
+
kAyiRqgxF4dJviwtqI7mZIomWL63+kXLgjOjMe1SHxfIPo/0ji6+r1p4KYa7o41v
|
30
|
+
fwIwU1MKlFBdsjkd
|
32
31
|
-----END CERTIFICATE-----
|
33
|
-
date: 2022-
|
32
|
+
date: 2022-11-06 00:00:00.000000000 Z
|
34
33
|
dependencies:
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: builder
|
37
|
-
requirement: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - "~>"
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: '3'
|
42
|
-
type: :runtime
|
43
|
-
prerelease: false
|
44
|
-
version_requirements: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - "~>"
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: '3'
|
49
34
|
- !ruby/object:Gem::Dependency
|
50
35
|
name: nokogiri
|
51
36
|
requirement: !ruby/object:Gem::Requirement
|
@@ -222,7 +207,6 @@ files:
|
|
222
207
|
- exe/mkmid
|
223
208
|
- lib/aixm.rb
|
224
209
|
- lib/aixm/a.rb
|
225
|
-
- lib/aixm/association.rb
|
226
210
|
- lib/aixm/classes.rb
|
227
211
|
- lib/aixm/component.rb
|
228
212
|
- lib/aixm/component/address.rb
|
@@ -245,11 +229,14 @@ files:
|
|
245
229
|
- lib/aixm/component/timetable.rb
|
246
230
|
- lib/aixm/component/vasis.rb
|
247
231
|
- lib/aixm/component/vertical_limit.rb
|
232
|
+
- lib/aixm/concerns/association.rb
|
248
233
|
- lib/aixm/concerns/hash_equality.rb
|
249
234
|
- lib/aixm/concerns/intensity.rb
|
250
235
|
- lib/aixm/concerns/marking.rb
|
236
|
+
- lib/aixm/concerns/memoize.rb
|
251
237
|
- lib/aixm/concerns/remarks.rb
|
252
238
|
- lib/aixm/concerns/timetable.rb
|
239
|
+
- lib/aixm/concerns/xml_builder.rb
|
253
240
|
- lib/aixm/config.rb
|
254
241
|
- lib/aixm/constants.rb
|
255
242
|
- lib/aixm/d.rb
|
@@ -260,6 +247,7 @@ files:
|
|
260
247
|
- lib/aixm/feature.rb
|
261
248
|
- lib/aixm/feature/airport.rb
|
262
249
|
- lib/aixm/feature/airspace.rb
|
250
|
+
- lib/aixm/feature/generic.rb
|
263
251
|
- lib/aixm/feature/navigational_aid.rb
|
264
252
|
- lib/aixm/feature/navigational_aid/designated_point.rb
|
265
253
|
- lib/aixm/feature/navigational_aid/dme.rb
|
@@ -271,13 +259,13 @@ files:
|
|
271
259
|
- lib/aixm/feature/obstacle_group.rb
|
272
260
|
- lib/aixm/feature/organisation.rb
|
273
261
|
- lib/aixm/feature/unit.rb
|
274
|
-
- lib/aixm/memoize.rb
|
275
262
|
- lib/aixm/object.rb
|
276
263
|
- lib/aixm/p.rb
|
277
264
|
- lib/aixm/payload_hash.rb
|
278
265
|
- lib/aixm/r.rb
|
279
266
|
- lib/aixm/refinements.rb
|
280
267
|
- lib/aixm/schedule/date.rb
|
268
|
+
- lib/aixm/schedule/date_time.rb
|
281
269
|
- lib/aixm/schedule/day.rb
|
282
270
|
- lib/aixm/schedule/time.rb
|
283
271
|
- lib/aixm/shortcuts.rb
|
@@ -324,7 +312,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
324
312
|
- !ruby/object:Gem::Version
|
325
313
|
version: '0'
|
326
314
|
requirements: []
|
327
|
-
rubygems_version: 3.3.
|
315
|
+
rubygems_version: 3.3.25
|
328
316
|
signing_key:
|
329
317
|
specification_version: 4
|
330
318
|
summary: Builder for AIXM/OFMX aeronautical information
|
metadata.gz.sig
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
}
|
2
|
-
|
3
|
-
F}Ue�h�0
|
1
|
+
Z���%ى��Z�0�~2[}O-'�B<Rg�WG��Rf
|
2
|
+
���(����@B!�NB~�d,���~��q4�Q7W�w�V�E`fwA�`r�(e=���P��J�
|
data/lib/aixm/association.rb
DELETED
@@ -1,378 +0,0 @@
|
|
1
|
-
using AIXM::Refinements
|
2
|
-
|
3
|
-
module AIXM
|
4
|
-
|
5
|
-
# Associate features and components with a minimalistic implementation of
|
6
|
-
# +has_many+, +has_one+ and +belongs_to+ associations.
|
7
|
-
#
|
8
|
-
# When adding or assigning an object on the associator (where the +has_many+
|
9
|
-
# or +has_one+ declaration is made), the object is verified and must be an
|
10
|
-
# instance of the declared class or a superclass thereof.
|
11
|
-
#
|
12
|
-
# When assigning an object on the associated (where the +belongs_to+
|
13
|
-
# declaration is made), the object is not verified. However, since the actual
|
14
|
-
# assignment is always delegated to the associator, unacceptable objects will
|
15
|
-
# raise errors.
|
16
|
-
#
|
17
|
-
# @example Simple +has_many+ association
|
18
|
-
# class Blog
|
19
|
-
# has_many :posts # :post has to be a key in AIXM::CLASSES
|
20
|
-
# end
|
21
|
-
# class Post
|
22
|
-
# belongs_to :blog
|
23
|
-
# end
|
24
|
-
# blog, post = Blog.new, Post.new
|
25
|
-
# # --either--
|
26
|
-
# blog.add_post(post) # => Blog
|
27
|
-
# blog.posts.count # => 1
|
28
|
-
# blog.posts.first == post # => true
|
29
|
-
# post.blog == blog # => true
|
30
|
-
# blog.remove_post(post) # => Blog
|
31
|
-
# blog.posts.count # => 0
|
32
|
-
# # --or--
|
33
|
-
# post.blog = blog # => Blog
|
34
|
-
# blog.posts.count # => 1
|
35
|
-
# blog.posts.first == post # => true
|
36
|
-
# post.blog == blog # => true
|
37
|
-
# post.blog = nil # => nil
|
38
|
-
# blog.posts.count # => 0
|
39
|
-
# # --or--
|
40
|
-
# post_2 = Post.new
|
41
|
-
# blog.add_posts([post, post_2])
|
42
|
-
# blog.posts.count # => 2
|
43
|
-
# blog.posts == [post, post_2] # => true
|
44
|
-
# blog.remove_posts([post_2, post])
|
45
|
-
# blog.posts.count # => 0
|
46
|
-
#
|
47
|
-
# @example Simple +has_one+ association
|
48
|
-
# class Blog
|
49
|
-
# has_one :posts # :post has to be a key in AIXM::CLASSES
|
50
|
-
# end
|
51
|
-
# class Post
|
52
|
-
# belongs_to :blog
|
53
|
-
# end
|
54
|
-
# blog, post = Blog.new, Post.new
|
55
|
-
# # --either--
|
56
|
-
# blog.post = post # => Post (standard assignment)
|
57
|
-
# blog.add_post(post) # => Blog (alternative for chaining)
|
58
|
-
# blog.post == post # => true
|
59
|
-
# post.blog == blog # => true
|
60
|
-
# blog.post = nil # => nil
|
61
|
-
# blog.post # => nil
|
62
|
-
# post.blog # => nil
|
63
|
-
# # --or--
|
64
|
-
# post.blog = blog # => Blog (standard assignment)
|
65
|
-
# post.add_blog(blog) # => Post (alternative for chaining)
|
66
|
-
# post.blog == blog # => true
|
67
|
-
# blog.post == post # => true
|
68
|
-
# post.blog = nil # => nil
|
69
|
-
# post.blog # => nil
|
70
|
-
# blog.post # => nil
|
71
|
-
#
|
72
|
-
# @example Association with readonly +belongs_to+ (idem for +has_one+)
|
73
|
-
# class Blog
|
74
|
-
# has_many :posts # :post has to be a key in AIXM::CLASSES
|
75
|
-
# end
|
76
|
-
# class Post
|
77
|
-
# belongs_to :blog, readonly: true
|
78
|
-
# end
|
79
|
-
# blog, post = Blog.new, Post.new
|
80
|
-
# post.blog = blog # => NoMethodError
|
81
|
-
#
|
82
|
-
# @example Association with explicit class (idem for +has_one+)
|
83
|
-
# class Blog
|
84
|
-
# include AIXM::Association
|
85
|
-
# has_many :posts, accept: 'Picture'
|
86
|
-
# end
|
87
|
-
# class Picture
|
88
|
-
# include AIXM::Association
|
89
|
-
# belongs_to :blog
|
90
|
-
# end
|
91
|
-
# blog, picture = Blog.new, Picture.new
|
92
|
-
# blog.add_post(picture)
|
93
|
-
# blog.posts.first == picture # => true
|
94
|
-
#
|
95
|
-
# @example Polymorphic associator (idem for +has_one+)
|
96
|
-
# class Blog
|
97
|
-
# has_many :posts, as: :postable
|
98
|
-
# end
|
99
|
-
# class Feed
|
100
|
-
# has_many :posts, as: :postable
|
101
|
-
# end
|
102
|
-
# class Post
|
103
|
-
# belongs_to :postable
|
104
|
-
# end
|
105
|
-
# blog, feed, post_1, post_2, post_3 = Blog.new, Feed.new, Post.new, Post.new, Post.new
|
106
|
-
# blog.add_post(post_1)
|
107
|
-
# post_1.postable == blog # => true
|
108
|
-
# feed.add_post(post_2)
|
109
|
-
# post_2.postable == feed # => true
|
110
|
-
# post_3.postable = blog # => NoMethodError
|
111
|
-
#
|
112
|
-
# @example Polymorphic associated (idem for +has_one+)
|
113
|
-
# class Blog
|
114
|
-
# include AIXM::Association
|
115
|
-
# has_many :items, accept: ['Post', :picture]
|
116
|
-
# end
|
117
|
-
# class Post
|
118
|
-
# include AIXM::Association
|
119
|
-
# belongs_to :blog, as: :item
|
120
|
-
# end
|
121
|
-
# class Picture
|
122
|
-
# include AIXM::Association
|
123
|
-
# belongs_to :blog, as: :item
|
124
|
-
# end
|
125
|
-
# blog, post, picture = Blog.new, Post.new, Picture.new
|
126
|
-
# blog.add_item(post)
|
127
|
-
# blog.add_item(picture)
|
128
|
-
# blog.items.count # => 2
|
129
|
-
# blog.items.first == post # => true
|
130
|
-
# blog.items.last == picture # => true
|
131
|
-
# post.blog == blog # => true
|
132
|
-
# picture.blog == blog # => true
|
133
|
-
#
|
134
|
-
# @example Add method which enriches passed associated object (+has_many+ only)
|
135
|
-
# class Blog
|
136
|
-
# has_many :posts do |post, related_to: nil| # this defines the signature of add_post
|
137
|
-
# post.related_to = related_to || @posts.last # executes in the context of the current blog
|
138
|
-
# end
|
139
|
-
# end
|
140
|
-
# class Post
|
141
|
-
# belongs_to :blog
|
142
|
-
# attr_accessor :related_to
|
143
|
-
# end
|
144
|
-
# blog, post_1, post_2, post_3 = Blog.new, Post.new, Post.new, Post.new
|
145
|
-
# blog.add_post(post_1)
|
146
|
-
# post_1.related_to # => nil
|
147
|
-
# blog.add_post(post_2)
|
148
|
-
# post_2.related_to == post_1 # => true
|
149
|
-
# blog.add_post(post_3, related_to: post_1)
|
150
|
-
# post_3.related_to == post_1 # => true
|
151
|
-
#
|
152
|
-
# @example Add method which builds and yields new associated object (+has_many+ only)
|
153
|
-
# class Blog
|
154
|
-
# include AIXM::Association
|
155
|
-
# has_many :posts do |post, title:| end
|
156
|
-
# end
|
157
|
-
# class Post
|
158
|
-
# include AIXM::Association
|
159
|
-
# belongs_to :blog
|
160
|
-
# attr_accessor :title, :text
|
161
|
-
# def initialize(title:) # same signature as "has_many" block above
|
162
|
-
# @title = title
|
163
|
-
# end
|
164
|
-
# end
|
165
|
-
# blog = Blog.new
|
166
|
-
# blog.add_post(title: "title") do |post| # note that no post instance is passed
|
167
|
-
# post.text = "text"
|
168
|
-
# end
|
169
|
-
# blog.posts.first.title # => "title"
|
170
|
-
# blog.posts.first.text # => "text"
|
171
|
-
module Association
|
172
|
-
module ClassMethods
|
173
|
-
attr_reader :has_many_attributes, :has_one_attributes, :belongs_to_attributes
|
174
|
-
|
175
|
-
def has_many(attribute, as: nil, accept: nil, &association_block)
|
176
|
-
association = attribute.to_s.inflect(:singularize)
|
177
|
-
inversion = as || self.to_s.inflect(:demodulize, :tableize, :singularize)
|
178
|
-
class_names = [accept || association].flatten.map { AIXM::CLASSES[_1.to_sym] || _1 }
|
179
|
-
(@has_many_attributes ||= []) << attribute
|
180
|
-
# features
|
181
|
-
define_method(attribute) do
|
182
|
-
instance_variable_get(:"@#{attribute}") || AIXM::Association::Array.new
|
183
|
-
end
|
184
|
-
# add_feature
|
185
|
-
define_method(:"add_#{association}") do |object=nil, **options, &add_block|
|
186
|
-
unless object
|
187
|
-
fail(ArgumentError, "must pass object to add") if class_names.count > 1
|
188
|
-
object = class_names.first.to_class.new(**options)
|
189
|
-
add_block.call(object) if add_block
|
190
|
-
end
|
191
|
-
instance_exec(object, **options, &association_block) if association_block
|
192
|
-
fail(ArgumentError, "#{object.__class__} not allowed") unless class_names.any? { |c| object.is_a?(c.to_class) }
|
193
|
-
instance_eval("@#{attribute} ||= AIXM::Association::Array.new")
|
194
|
-
send(attribute).send(:push, object)
|
195
|
-
object.instance_variable_set(:"@#{inversion}", self)
|
196
|
-
self
|
197
|
-
end
|
198
|
-
# add_features
|
199
|
-
define_method(:"add_#{attribute}") do |objects=[], **options, &add_block|
|
200
|
-
objects.each { send(:"add_#{association}", _1, **options, &add_block) }
|
201
|
-
self
|
202
|
-
end
|
203
|
-
# remove_feature
|
204
|
-
define_method(:"remove_#{association}") do |object|
|
205
|
-
send(attribute).send(:delete, object)
|
206
|
-
object.instance_variable_set(:"@#{inversion}", nil)
|
207
|
-
self
|
208
|
-
end
|
209
|
-
# remove_features
|
210
|
-
define_method(:"remove_#{attribute}") do |objects=[]|
|
211
|
-
objects.each { send(:"remove_#{association}", _1) }
|
212
|
-
self
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def has_one(attribute, as: nil, accept: nil, allow_nil: false)
|
217
|
-
association = attribute.to_s
|
218
|
-
inversion = (as || self.to_s.inflect(:demodulize, :tableize, :singularize)).to_s
|
219
|
-
class_names = [accept || association].flatten.map { AIXM::CLASSES[_1.to_sym] || _1 }
|
220
|
-
class_names << 'NilClass' if allow_nil
|
221
|
-
(@has_one_attributes ||= []) << attribute
|
222
|
-
# feature
|
223
|
-
attr_reader attribute
|
224
|
-
# feature=
|
225
|
-
define_method(:"#{association}=") do |object|
|
226
|
-
fail(ArgumentError, "#{object.__class__} not allowed") unless class_names.any? { |c| object.is_a?(c.to_class) }
|
227
|
-
instance_variable_get(:"@#{attribute}")&.instance_variable_set(:"@#{inversion}", nil)
|
228
|
-
instance_variable_set(:"@#{attribute}", object)
|
229
|
-
object&.instance_variable_set(:"@#{inversion}", self)
|
230
|
-
object
|
231
|
-
end
|
232
|
-
# add_feature
|
233
|
-
define_method(:"add_#{association}") do |object|
|
234
|
-
send("#{association}=", object)
|
235
|
-
self
|
236
|
-
end
|
237
|
-
# remove_feature
|
238
|
-
define_method(:"remove_#{association}") do |_|
|
239
|
-
send(:"#{association}=", nil)
|
240
|
-
self
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
def belongs_to(attribute, as: nil, readonly: false)
|
245
|
-
association = self.to_s.inflect(:demodulize, :tableize, :singularize)
|
246
|
-
inversion = (as || association).to_s
|
247
|
-
(@belongs_to_attributes ||= []) << attribute
|
248
|
-
# feature
|
249
|
-
attr_reader attribute
|
250
|
-
unless readonly
|
251
|
-
# feature=
|
252
|
-
define_method(:"#{attribute}=") do |object|
|
253
|
-
instance_variable_get(:"@#{attribute}")&.send(:"remove_#{inversion}", self)
|
254
|
-
object&.send(:"add_#{inversion}", self)
|
255
|
-
object
|
256
|
-
end
|
257
|
-
# add_feature
|
258
|
-
define_method(:"add_#{attribute}") do |object|
|
259
|
-
send("#{attribute}=", object)
|
260
|
-
self
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def self.included(base)
|
267
|
-
base.extend(ClassMethods)
|
268
|
-
end
|
269
|
-
|
270
|
-
class Array < ::Array
|
271
|
-
private :<<, :push, :append, :unshift, :prepend
|
272
|
-
private :delete, :pop, :shift
|
273
|
-
|
274
|
-
# Find objects of the given class and optionally with the given
|
275
|
-
# attribute values on a has_many association.
|
276
|
-
#
|
277
|
-
# The class can either be declared by passing the class itself or by
|
278
|
-
# passing a shortcut symbol as listed in +AIXM::CLASSES+.
|
279
|
-
#
|
280
|
-
# @example
|
281
|
-
# class Blog
|
282
|
-
# include AIXM::Association
|
283
|
-
# has_many :items, accept: %i(post picture)
|
284
|
-
# end
|
285
|
-
# class Post
|
286
|
-
# include AIXM::Association
|
287
|
-
# belongs_to :blog, as: :item
|
288
|
-
# attr_accessor :title
|
289
|
-
# end
|
290
|
-
# class Picture
|
291
|
-
# include AIXM::Association
|
292
|
-
# belongs_to :blog, as: :item
|
293
|
-
# end
|
294
|
-
# blog, post, picture = Blog.new, Post.new, Picture.new
|
295
|
-
# post.title = "title"
|
296
|
-
# blog.add_item(post)
|
297
|
-
# blog.add_item(picture)
|
298
|
-
# blog.items.find_by(:post) == [post] # => true
|
299
|
-
# blog.items.find_by(Post) == [post] # => true
|
300
|
-
# blog.items.find_by(:post, title: "title") == [post] # => true
|
301
|
-
# blog.items.find_by(Object) == [post, picture] # => true
|
302
|
-
#
|
303
|
-
# @param klass [Class, Symbol] class (e.g. AIXM::Feature::Airport,
|
304
|
-
# AIXM::Feature::NavigationalAid::VOR) or shortcut symbol (e.g.
|
305
|
-
# :airport or :vor) as listed in AIXM::CLASSES
|
306
|
-
# @param attributes [Hash] search attributes by their values
|
307
|
-
# @return [AIXM::Association::Array]
|
308
|
-
def find_by(klass, attributes={})
|
309
|
-
if klass.is_a? Symbol
|
310
|
-
klass = AIXM::CLASSES[klass]&.to_class || fail(ArgumentError, "unknown class shortcut `#{klass}'")
|
311
|
-
end
|
312
|
-
self.class.new(
|
313
|
-
select do |element|
|
314
|
-
if element.kind_of? klass
|
315
|
-
attributes.all? { |a, v| element.send(a) == v }
|
316
|
-
end
|
317
|
-
end
|
318
|
-
)
|
319
|
-
end
|
320
|
-
|
321
|
-
# Find equal objects on a has_many association.
|
322
|
-
#
|
323
|
-
# This may seem redundant at first, but keep in mind that two instances
|
324
|
-
# of +AIXM::CLASSES+ which implement `#to_uid` are considered equal if
|
325
|
-
# they are instances of the same class and both their UIDs as calculated
|
326
|
-
# by `#to_uid` are equal. Attributes which are not part of the `#to_uid`
|
327
|
-
# calculation are irrelevant!
|
328
|
-
#
|
329
|
-
# @example
|
330
|
-
# class Blog
|
331
|
-
# include AIXM::Association
|
332
|
-
# has_many :items, accept: %i(post picture)
|
333
|
-
# end
|
334
|
-
# class Post
|
335
|
-
# include AIXM::Association
|
336
|
-
# belongs_to :blog, as: :item
|
337
|
-
# attr_accessor :title
|
338
|
-
# end
|
339
|
-
# blog, post = Blog.new, Post.new
|
340
|
-
# blog.add_item(post)
|
341
|
-
# blog.items.find(post) == [post] # => true
|
342
|
-
#
|
343
|
-
# @param object [Object] instance of class listed in AIXM::CLASSES
|
344
|
-
# @return [AIXM::Association::Array]
|
345
|
-
def find(object)
|
346
|
-
klass = object.__class__
|
347
|
-
self.class.new(
|
348
|
-
select do |element|
|
349
|
-
element.kind_of?(klass) && element == object
|
350
|
-
end
|
351
|
-
)
|
352
|
-
end
|
353
|
-
|
354
|
-
# Find equal or identical duplicates on a has_many association.
|
355
|
-
#
|
356
|
-
# @example
|
357
|
-
# class Blog
|
358
|
-
# include AIXM::Association
|
359
|
-
# has_many :posts
|
360
|
-
# end
|
361
|
-
# class Post
|
362
|
-
# include AIXM::Association
|
363
|
-
# belongs_to :blog
|
364
|
-
# end
|
365
|
-
# blog, post = Blog.new, Post.new
|
366
|
-
# duplicate_post = post.dup
|
367
|
-
# blog.add_posts([post, duplicate_post])
|
368
|
-
# blog.posts.duplicates # => [[post, duplicate_post]]
|
369
|
-
#
|
370
|
-
# @return [Array<Array<AIXM::Feature>>]
|
371
|
-
def duplicates
|
372
|
-
AIXM::Memoize.method :to_uid do
|
373
|
-
group_by(&:to_uid).select { |_, a| a.count > 1 }.map(&:last)
|
374
|
-
end
|
375
|
-
end
|
376
|
-
end
|
377
|
-
end
|
378
|
-
end
|