activefacts-api 1.9.5 → 1.9.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2eb04777181f27abd89426727271654e04920e13
4
- data.tar.gz: e6aa614c3625cd3d91cfecf290769e4f6af00a04
3
+ metadata.gz: 9b00b0f6693a69f881f4348ef9229be637fc750d
4
+ data.tar.gz: fdd1c5ba81f7cc417d186f4bb854a7ec6949dcb3
5
5
  SHA512:
6
- metadata.gz: f80be8ab326dfa421361c4d2af569ec717e37d001b14a3167a91e64cbb8df5b75d2a446b40678441f94e1a126b03a277795e75daccaacf90bdb3864b16d3ee53
7
- data.tar.gz: 473e27c7bbeb18a3c04519208f51eabd9e51e5366bc603a2d40f36946348a37e412f8bcf4d490c14b464227aff6bfd5ff0bf5dfb74087f7fcc9e948401d6c787
6
+ metadata.gz: 67477e5379a3a4c49a5950fd4c07b78ec2e1e7515aedec529217f55c025c7b702ca7b97796a087901aa3b5c7b07f497910049be81d53fd22c4e6235e86f92d4c
7
+ data.tar.gz: 1253f8d25f5e66f4ee14642e197d3599ebc47827b08646a8bc727569319846597fbe83df41be0c74235eef867c7e6f88510d30e25a0fa77f8c3cd2b0e9372420
@@ -37,13 +37,13 @@ module ActiveFacts
37
37
  # Create a new empty Constellation over the given Vocabulary
38
38
  def initialize(vocabulary, options = {})
39
39
  @vocabulary = vocabulary
40
- @options = options
40
+ @options = options
41
41
  end
42
42
 
43
43
  def assert(klass, *args)
44
- with_candidates do
45
- klass.assert_instance self, args
46
- end
44
+ with_candidates do
45
+ klass.assert_instance self, args
46
+ end
47
47
  end
48
48
 
49
49
  # Delete instances from the constellation, nullifying (or cascading) the roles each plays
@@ -66,60 +66,60 @@ module ActiveFacts
66
66
  # With parameters, assert an instance of the object_type identified by the values passed as args.
67
67
  def method_missing(m, *args, &b)
68
68
  klass = @vocabulary.const_get(m)
69
- if invalid_object_type klass
70
- super
69
+ if invalid_object_type klass
70
+ super
71
71
  else
72
- define_class_accessor m, klass
72
+ define_class_accessor m, klass
73
73
  send(m, *args, &b)
74
74
  end
75
75
  end
76
76
 
77
77
  def define_class_accessor m, klass
78
- (class << self; self; end).
79
- send(:define_method, m) do |*args|
80
- if args.size == 0
81
- # Return the collection of all instances of this class in the constellation:
82
- instances[klass]
83
- else
84
- # Assert a new ground fact (object_type instance) of the specified class, identified by args:
85
- assert(klass, *args)
86
- end
87
- end
78
+ (class << self; self; end).
79
+ send(:define_method, m) do |*args|
80
+ if args.size == 0
81
+ # Return the collection of all instances of this class in the constellation:
82
+ instances[klass]
83
+ else
84
+ # Assert a new ground fact (object_type instance) of the specified class, identified by args:
85
+ assert(klass, *args)
86
+ end
87
+ end
88
88
  end
89
89
 
90
90
  def inspect #:nodoc:
91
- total = instances.values.map(&:size).inject(:+) || 0
91
+ total = instances.values.map(&:size).inject(:+) || 0
92
92
  "Constellation:#{object_id} over #{@vocabulary.name} with #{total}/#{instances.size}"
93
93
  end
94
94
 
95
95
  # Loggers is an array of callbacks
96
96
  def loggers
97
- @loggers ||= []
97
+ @loggers ||= []
98
98
  end
99
99
 
100
100
  def invalid_object_type klass
101
- case
102
- when !klass.is_a?(Class)
103
- 'is not a Class'
104
- when klass.modspace != @vocabulary
105
- "is defined in #{klass.modspace}, not #{@vocabulary.name}"
106
- when !klass.respond_to?(:assert_instance)
107
- "is not declared as an object type"
108
- else
109
- nil
110
- end
101
+ case
102
+ when !klass.is_a?(Class)
103
+ 'is not a Class'
104
+ when klass.modspace != @vocabulary
105
+ "is defined in #{klass.modspace}, not #{@vocabulary.name}"
106
+ when !klass.respond_to?(:assert_instance)
107
+ "is not declared as an object type"
108
+ else
109
+ nil
110
+ end
111
111
  end
112
112
 
113
113
  # "instances" is an index (keyed by the Class object) of indexes to instances.
114
114
  # Each instance is indexed for every supertype it has (including multiply-inherited ones).
115
115
  # The method_missing definition supports the syntax: c.MyClass.each{|k, v| ... }
116
116
  def instances
117
- @instances ||= Hash.new do |h,k|
118
- if reason = invalid_object_type(k)
119
- raise InvalidObjectType.new(@vocabulary, k, reason)
120
- end
121
- h[k] = InstanceIndex.new(self, k, (@options.include?(:sort) ? @options[:sort] : API::sorted))
122
- end
117
+ @instances ||= Hash.new do |h,k|
118
+ if reason = invalid_object_type(k)
119
+ raise InvalidObjectType.new(@vocabulary, k, reason)
120
+ end
121
+ h[k] = InstanceIndex.new(self, k, (@options.include?(:sort) ? @options[:sort] : API::sorted))
122
+ end
123
123
  end
124
124
 
125
125
  # Candidates is an array of object instances that do not already exist
@@ -128,64 +128,64 @@ module ActiveFacts
128
128
  # in the constellation and in the counterparts of their identifying roles,
129
129
  # and the candidates array is nullified.
130
130
  def with_candidates &b
131
- # Multiple assignment reduces (s)teps while debugging
132
- outermost, @candidates, @on_admission = @candidates.nil?, (@candidates || []), (@on_admission || [])
133
- begin
134
- b.call
135
- rescue Exception
136
- # Do not accept any of these candidates, there was a problem:
137
- @candidates = [] if outermost
138
- raise
139
- ensure
140
- if outermost
141
- while @candidates
142
- # Index the accepted instances in the constellation:
143
- candidates = @candidates
144
- on_admission = @on_admission
145
- @candidates = nil
146
- @on_admission = nil
147
- candidates.each do |instance|
148
- instance.class.index_instance(self, instance)
149
- loggers.each{|l| l.call(:assert, instance.class, instance.identifying_role_values)}
150
- end
151
- on_admission.each do |b|
152
- b.call
153
- end
154
- end
155
- end
156
- end
131
+ # Multiple assignment reduces (s)teps while debugging
132
+ outermost, @candidates, @on_admission = @candidates.nil?, (@candidates || []), (@on_admission || [])
133
+ begin
134
+ b.call
135
+ rescue Exception
136
+ # Do not accept any of these candidates, there was a problem:
137
+ @candidates = [] if outermost
138
+ raise
139
+ ensure
140
+ if outermost
141
+ while @candidates
142
+ # Index the accepted instances in the constellation:
143
+ candidates = @candidates
144
+ on_admission = @on_admission
145
+ @candidates = nil
146
+ @on_admission = nil
147
+ candidates.each do |instance|
148
+ instance.class.index_instance(self, instance)
149
+ loggers.each{|l| l.call(:assert, instance.class, instance.identifying_role_values)}
150
+ end
151
+ on_admission.each do |b|
152
+ b.call
153
+ end
154
+ end
155
+ end
156
+ end
157
157
  end
158
158
 
159
159
  def when_admitted &b
160
- if @candidates.nil?
161
- b.call self
162
- else
163
- @on_admission << b
164
- end
160
+ if @candidates.nil?
161
+ b.call self
162
+ else
163
+ @on_admission << b
164
+ end
165
165
  end
166
166
 
167
167
  def candidate instance
168
- @candidates << instance unless @candidates[-1] == instance
168
+ @candidates << instance unless @candidates[-1] == instance
169
169
  end
170
170
 
171
171
  def has_candidate klass, key
172
- @candidates && @candidates.detect{|c| c.is_a?(klass) && c.identifying_role_values(klass) == key }
172
+ @candidates && @candidates.detect{|c| c.is_a?(klass) && c.identifying_role_values(klass) == key }
173
173
  end
174
174
 
175
175
  # This method removes the given instance from this constellation's indexes
176
176
  # It must be called before the identifying roles get deleted or nullified.
177
177
  def deindex_instance(instance) #:nodoc:
178
- last_irns = nil
179
- last_irvs = instance
178
+ last_irns = nil
179
+ last_irvs = instance
180
180
  ([instance.class]+instance.class.supertypes_transitive).each do |klass|
181
- if instance.is_a?(Entity) and last_irns != (n = klass.identifying_role_names)
182
- # Build new identifying_role_values only when the identifying_role_names change:
183
- last_irvs = instance.identifying_role_values(klass)
184
- last_irns = n
185
- end
181
+ if instance.is_a?(Entity) and last_irns != (n = klass.identifying_role_names)
182
+ # Build new identifying_role_values only when the identifying_role_names change:
183
+ last_irvs = instance.identifying_role_values(klass)
184
+ last_irns = n
185
+ end
186
186
  deleted = instances[klass].delete(last_irvs)
187
- # The RBTree class sometimes returns a different object than what was deleted! Check non-nil:
188
- raise "Internal error: deindex #{instance.class} as #{klass} failed" if deleted == nil
187
+ # The RBTree class sometimes returns a different object than what was deleted! Check non-nil:
188
+ raise "Internal error: deindex #{instance.class} as #{klass} failed" if deleted == nil
189
189
  end
190
190
  end
191
191
 
@@ -197,15 +197,15 @@ module ActiveFacts
197
197
  klass = vocabulary.const_get(object_type)
198
198
 
199
199
  single_roles, multiple_roles = klass.all_role.
200
- partition do |n, r|
201
- r.unique && # Show only single-valued roles
202
- !r.is_identifying && # Unless identifying
203
- (r.unary? || !r.counterpart.is_identifying) # Or identifies a counterpart
204
- end.
205
- map do |rs|
206
- rs.map{|n, r| n}.
207
- sort_by(&:to_s)
208
- end
200
+ partition do |n, r|
201
+ r.unique && # Show only single-valued roles
202
+ !r.is_identifying && # Unless identifying
203
+ (r.unary? || !r.counterpart.is_identifying) # Or identifies a counterpart
204
+ end.
205
+ map do |rs|
206
+ rs.map{|n, r| n}.
207
+ sort_by(&:to_s)
208
+ end
209
209
 
210
210
  instances = send(object_type.to_sym)
211
211
  next nil unless instances.size > 0
@@ -215,15 +215,15 @@ module ActiveFacts
215
215
  if (single_roles.size > 0)
216
216
  role_values =
217
217
  single_roles.map do |role_name|
218
- #p klass, klass.all_role.keys; exit
219
- next nil if klass.all_role(role_name).fact_type.is_a?(TypeInheritanceFactType)
220
- value =
221
- if instance.respond_to?(role_name)
222
- value = instance.send(role_name)
223
- else
224
- instance.class.all_role(role_name) # This role has not yet been realised
225
- end
226
- [ role_name.to_s.camelcase, value ]
218
+ #p klass, klass.all_role.keys; exit
219
+ next nil if klass.all_role(role_name).fact_type.is_a?(TypeInheritanceFactType)
220
+ value =
221
+ if instance.respond_to?(role_name)
222
+ value = instance.send(role_name)
223
+ else
224
+ instance.class.all_role(role_name) # This role has not yet been realised
225
+ end
226
+ [ role_name.to_s.camelcase, value ]
227
227
  end.compact.select do |role_name, value|
228
228
  value
229
229
  end.map do |role_name, value|
@@ -240,109 +240,109 @@ module ActiveFacts
240
240
  # All identifiers should overall be different from the forked instance, and
241
241
  # all one-to-ones must be assigned new values (otherwise we change old objects)
242
242
  def fork instance, attrs = {}
243
- object_type = instance.class
244
-
245
- role_value_map =
246
- object_type.all_role_transitive.inject({}) do |hash, (role_name, role)|
247
- next hash if !role.unique
248
- next hash if role.fact_type.class == ActiveFacts::API::TypeInheritanceFactType
249
- old_value = instance.send(role.getter)
250
- if role.counterpart && role.counterpart.unique && old_value != nil
251
- # It's a one-to-one which is populated. We must not change the counterpart
252
- if role.mandatory && !attrs.include?(role.name)
253
- # and cannot just nullify the value
254
- raise "#{object_type.basename} cannot be forked unless a replacement value for #{role.name} is provided"
255
- end
256
- value = attrs[role_name]
257
- else
258
- value = attrs.include?(role_name) ? attrs[role_name] : instance.send(role.getter)
259
- end
260
- hash[role_name] = value if value != nil
261
- hash
262
- end
263
-
264
- assert(object_type, role_value_map)
243
+ object_type = instance.class
244
+
245
+ role_value_map =
246
+ object_type.all_role_transitive.inject({}) do |hash, (role_name, role)|
247
+ next hash if !role.unique
248
+ next hash if role.fact_type.class == ActiveFacts::API::TypeInheritanceFactType
249
+ old_value = instance.send(role.getter)
250
+ if role.counterpart && role.counterpart.unique && old_value != nil
251
+ # It's a one-to-one which is populated. We must not change the counterpart
252
+ if role.mandatory && !attrs.include?(role.name)
253
+ # and cannot just nullify the value
254
+ raise "#{object_type.basename} cannot be forked unless a replacement value for #{role.name} is provided"
255
+ end
256
+ value = attrs[role_name]
257
+ else
258
+ value = attrs.include?(role_name) ? attrs[role_name] : instance.send(role.getter)
259
+ end
260
+ hash[role_name] = value if value != nil
261
+ hash
262
+ end
263
+
264
+ assert(object_type, role_value_map)
265
265
  end
266
266
 
267
267
  def clone
268
- remaining_object_types = vocabulary.object_type.clone
269
- constellation = self.class.new(vocabulary, @options)
270
- correlates = {}
271
- other_attribute_assignments = []
272
- until remaining_object_types.empty?
273
- count = 0
274
- # Choose an object type we can clone now:
275
- name, object_type = *remaining_object_types.detect do |name, o|
276
- (count = @instances[o].size) == 0 or # There are no instances of this object type; clone is ok
277
- !o.is_entity_type or # It's a value type
278
- (
279
- !o.subtypes_transitive.detect do |subtype|# All its subtypes have been cloned
280
- remaining_object_types.has_key?(subtype.basename)
281
- end and
282
- !o.identifying_roles.detect do |role| # The players of its identifying roles have all been dumped
283
- next unless role.counterpart # Unary role, no player
284
- counterpart = role.counterpart.object_type # counterpart object
285
-
286
- # The identifying type and its subtypes have been dumped
287
- ([counterpart]+counterpart.subtypes_transitive).detect do |subtype|
288
- remaining_object_types.has_key?(subtype.basename)
289
- end
290
- end
291
- )
292
- end
293
- # puts "Cloning #{count} instances of #{name}" if count > 0
294
- remaining_object_types.delete(name)
295
-
296
- key_role_names =
297
- if object_type.is_entity_type
298
- ([object_type]+object_type.supertypes_transitive).map { |t| t.identifying_role_names }.flatten.uniq
299
- else
300
- nil
301
- end
302
- other_roles = object_type.all_role_transitive.map do |role_name, role|
303
- next if !role.unique or
304
- role.fact_type.class == ActiveFacts::API::TypeInheritanceFactType or
305
- role.fact_type.all_role[0] != role or # Only the first role in a one-to-one pair
306
- key_role_names.include?(role_name)
307
- role
308
- end.compact - Array(key_role_names)
309
-
310
- @instances[object_type].each do |key, object|
311
- next if object.class != object_type
312
-
313
- # Clone this object
314
-
315
- # Get the identifying values:
316
- key = object
317
- if (key_role_names)
318
- key = key_role_names.inject({}) do |h, krn|
319
- h[krn] = object.send(krn)
320
- h
321
- end
322
- end
323
- # puts "\tcloning #{object.class} #{key.inspect}"
324
- # puts "\t\talso copy #{other_roles.map(&:name)*', '}"
325
-
326
- new_object = constellation.assert(object_type, key)
327
- correlates[object] = new_object
328
-
329
- other_roles.each do |role|
330
- value = object.send(role.getter)
331
- next unless value
332
- other_attribute_assignments << proc do
333
- new_object.send(role.setter, correlates[value])
334
- end
335
- end
336
- end
337
- end
338
-
339
- # Now, assign all non-identifying facts
340
- # puts "Assigning #{other_attribute_assignments.size} additional roles"
341
- other_attribute_assignments.each do |assignment|
342
- assignment.call
343
- end
344
-
345
- constellation
268
+ remaining_object_types = vocabulary.object_type.clone
269
+ constellation = self.class.new(vocabulary, @options)
270
+ correlates = {}
271
+ other_attribute_assignments = []
272
+ until remaining_object_types.empty?
273
+ count = 0
274
+ # Choose an object type we can clone now:
275
+ name, object_type = *remaining_object_types.detect do |name, o|
276
+ (count = @instances[o].size) == 0 or # There are no instances of this object type; clone is ok
277
+ !o.is_entity_type or # It's a value type
278
+ (
279
+ !o.subtypes_transitive.detect do |subtype|# All its subtypes have been cloned
280
+ remaining_object_types.has_key?(subtype.basename)
281
+ end and
282
+ !o.identifying_roles.detect do |role| # The players of its identifying roles have all been dumped
283
+ next unless role.counterpart # Unary role, no player
284
+ counterpart = role.counterpart.object_type # counterpart object
285
+
286
+ # The identifying type and its subtypes have been dumped
287
+ ([counterpart]+counterpart.subtypes_transitive).detect do |subtype|
288
+ remaining_object_types.has_key?(subtype.basename)
289
+ end
290
+ end
291
+ )
292
+ end
293
+ # puts "Cloning #{count} instances of #{name}" if count > 0
294
+ remaining_object_types.delete(name)
295
+
296
+ key_role_names =
297
+ if object_type.is_entity_type
298
+ ([object_type]+object_type.supertypes_transitive).map { |t| t.identifying_role_names }.flatten.uniq
299
+ else
300
+ nil
301
+ end
302
+ other_roles = object_type.all_role_transitive.map do |role_name, role|
303
+ next if !role.unique or
304
+ role.fact_type.class == ActiveFacts::API::TypeInheritanceFactType or
305
+ role.fact_type.all_role[0] != role or # Only the first role in a one-to-one pair
306
+ key_role_names.include?(role_name)
307
+ role
308
+ end.compact - Array(key_role_names)
309
+
310
+ @instances[object_type].each do |key, object|
311
+ next if object.class != object_type
312
+
313
+ # Clone this object
314
+
315
+ # Get the identifying values:
316
+ key = object
317
+ if (key_role_names)
318
+ key = key_role_names.inject({}) do |h, krn|
319
+ h[krn] = object.send(krn)
320
+ h
321
+ end
322
+ end
323
+ # puts "\tcloning #{object.class} #{key.inspect}"
324
+ # puts "\t\talso copy #{other_roles.map(&:name)*', '}"
325
+
326
+ new_object = constellation.assert(object_type, key)
327
+ correlates[object] = new_object
328
+
329
+ other_roles.each do |role|
330
+ value = object.send(role.getter)
331
+ next unless value
332
+ other_attribute_assignments << proc do
333
+ new_object.send(role.setter, correlates[value])
334
+ end
335
+ end
336
+ end
337
+ end
338
+
339
+ # Now, assign all non-identifying facts
340
+ # puts "Assigning #{other_attribute_assignments.size} additional roles"
341
+ other_attribute_assignments.each do |assignment|
342
+ assignment.call
343
+ end
344
+
345
+ constellation
346
346
  end
347
347
 
348
348
  end