aixm 1.2.1 → 1.3.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +14 -3
- data/README.md +30 -2
- data/exe/ckmid +1 -7
- data/exe/mkmid +1 -7
- data/lib/aixm/classes.rb +2 -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 +27 -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/version.rb +1 -1
- data/lib/aixm.rb +4 -3
- data/schemas/ofmx/0.1/OFMX-Snapshot.xsd +6 -1
- data.tar.gz.sig +3 -3
- metadata +7 -19
- metadata.gz.sig +0 -0
- data/lib/aixm/association.rb +0 -378
- data/lib/aixm/memoize.rb +0 -105
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.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sven Schwyn
|
@@ -30,22 +30,8 @@ cert_chain:
|
|
30
30
|
1+2Y1+i+4jd1B7qxIgOLxQTNIJiwE0sqU1itFfuesfgUACS7M0IV9u9Bp4hBGNEw
|
31
31
|
5JcY2h7owdMxXIvgk1oakgldFJc=
|
32
32
|
-----END CERTIFICATE-----
|
33
|
-
date: 2022-04
|
33
|
+
date: 2022-05-04 00:00:00.000000000 Z
|
34
34
|
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
35
|
- !ruby/object:Gem::Dependency
|
50
36
|
name: nokogiri
|
51
37
|
requirement: !ruby/object:Gem::Requirement
|
@@ -222,7 +208,6 @@ files:
|
|
222
208
|
- exe/mkmid
|
223
209
|
- lib/aixm.rb
|
224
210
|
- lib/aixm/a.rb
|
225
|
-
- lib/aixm/association.rb
|
226
211
|
- lib/aixm/classes.rb
|
227
212
|
- lib/aixm/component.rb
|
228
213
|
- lib/aixm/component/address.rb
|
@@ -245,11 +230,14 @@ files:
|
|
245
230
|
- lib/aixm/component/timetable.rb
|
246
231
|
- lib/aixm/component/vasis.rb
|
247
232
|
- lib/aixm/component/vertical_limit.rb
|
233
|
+
- lib/aixm/concerns/association.rb
|
248
234
|
- lib/aixm/concerns/hash_equality.rb
|
249
235
|
- lib/aixm/concerns/intensity.rb
|
250
236
|
- lib/aixm/concerns/marking.rb
|
237
|
+
- lib/aixm/concerns/memoize.rb
|
251
238
|
- lib/aixm/concerns/remarks.rb
|
252
239
|
- lib/aixm/concerns/timetable.rb
|
240
|
+
- lib/aixm/concerns/xml_builder.rb
|
253
241
|
- lib/aixm/config.rb
|
254
242
|
- lib/aixm/constants.rb
|
255
243
|
- lib/aixm/d.rb
|
@@ -260,6 +248,7 @@ files:
|
|
260
248
|
- lib/aixm/feature.rb
|
261
249
|
- lib/aixm/feature/airport.rb
|
262
250
|
- lib/aixm/feature/airspace.rb
|
251
|
+
- lib/aixm/feature/generic.rb
|
263
252
|
- lib/aixm/feature/navigational_aid.rb
|
264
253
|
- lib/aixm/feature/navigational_aid/designated_point.rb
|
265
254
|
- lib/aixm/feature/navigational_aid/dme.rb
|
@@ -271,7 +260,6 @@ files:
|
|
271
260
|
- lib/aixm/feature/obstacle_group.rb
|
272
261
|
- lib/aixm/feature/organisation.rb
|
273
262
|
- lib/aixm/feature/unit.rb
|
274
|
-
- lib/aixm/memoize.rb
|
275
263
|
- lib/aixm/object.rb
|
276
264
|
- lib/aixm/p.rb
|
277
265
|
- lib/aixm/payload_hash.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.13
|
328
316
|
signing_key:
|
329
317
|
specification_version: 4
|
330
318
|
summary: Builder for AIXM/OFMX aeronautical information
|
metadata.gz.sig
CHANGED
Binary file
|
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
|
data/lib/aixm/memoize.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
module AIXM
|
2
|
-
|
3
|
-
# Memoize the return value of a specific method across multiple instances for
|
4
|
-
# the duration of a block.
|
5
|
-
#
|
6
|
-
# The method signature is taken into account, therefore calls of the same
|
7
|
-
# method with different positional and/or keyword arguments are cached
|
8
|
-
# independently. On the other hand, when calling the method with a block,
|
9
|
-
# no memoization is performed at all.
|
10
|
-
#
|
11
|
-
# Nested memoization of the same method is allowed and won't reset the
|
12
|
-
# memoization cache.
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# class Either
|
16
|
-
# include AIXM::Memoize
|
17
|
-
#
|
18
|
-
# def either(argument=nil, keyword: nil, &block)
|
19
|
-
# $entropy || argument || keyword || (block.call if block)
|
20
|
-
# end
|
21
|
-
# memoize :either
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# a, b, c = Either.new, Either.new, Either.new
|
25
|
-
#
|
26
|
-
# # No memoization before the block
|
27
|
-
# $entropy = nil
|
28
|
-
# a.either(1) # => 1
|
29
|
-
# b.either(keyword: 2) # => 2
|
30
|
-
# c.either { 3 } # => 3
|
31
|
-
# $entropy = :not_nil
|
32
|
-
# a.either(1) # => :not_nil
|
33
|
-
# b.either(keyword: 2) # => :not_nil
|
34
|
-
# c.either { 3 } # => :not_nil
|
35
|
-
#
|
36
|
-
# # Memoization inside the block
|
37
|
-
# AIXM::Memoize.method :either do
|
38
|
-
# $entropy = nil
|
39
|
-
# a.either(1) # => 1
|
40
|
-
# b.either(keyword: 2) # => 2
|
41
|
-
# c.either { 3 } # => 3
|
42
|
-
# $entropy = :not_nil
|
43
|
-
# a.either(1) # => 1 (memoized)
|
44
|
-
# b.either(keyword: 2) # => 2 (memoized)
|
45
|
-
# c.either { 3 } # => :not_nil (cannot be memoized)
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# # No memoization after the block
|
49
|
-
# $entropy = nil
|
50
|
-
# a.either(1) # => 1
|
51
|
-
# $entropy = :not_nil
|
52
|
-
# a.either(1) # => :not_nil
|
53
|
-
module Memoize
|
54
|
-
module ClassMethods
|
55
|
-
def memoize(method)
|
56
|
-
unmemoized_method = :"unmemoized_#{method}"
|
57
|
-
alias_method unmemoized_method, method
|
58
|
-
define_method method do |*args, **kargs, &block|
|
59
|
-
if block || !AIXM::Memoize.cache.has_key?(method)
|
60
|
-
send(unmemoized_method, *args, **kargs, &block)
|
61
|
-
else
|
62
|
-
cache = AIXM::Memoize.cache[method]
|
63
|
-
id = object_id.hash ^ args.hash ^ kargs.hash
|
64
|
-
if cache.has_key?(id)
|
65
|
-
cache[id]
|
66
|
-
else
|
67
|
-
cache[id] = send(unmemoized_method, *args, **kargs)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class << self
|
75
|
-
attr_reader :cache
|
76
|
-
|
77
|
-
def included(base)
|
78
|
-
base.extend(ClassMethods)
|
79
|
-
@cache = {}
|
80
|
-
end
|
81
|
-
|
82
|
-
def method(method, &block) # TODO: [ruby-3.1] use anonymous block "&" on this and next line
|
83
|
-
send(:"call_with#{:out if cached?(method)}_cache", method, &block)
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def cached?(method)
|
89
|
-
cache.has_key?(method)
|
90
|
-
end
|
91
|
-
|
92
|
-
def call_without_cache(method)
|
93
|
-
yield
|
94
|
-
end
|
95
|
-
|
96
|
-
def call_with_cache(method)
|
97
|
-
cache[method] = {}
|
98
|
-
yield
|
99
|
-
ensure
|
100
|
-
cache.delete(method)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
end
|
105
|
-
end
|