activefacts-api 1.9.5 → 1.9.6

Sign up to get free protection for your applications and to get access to all the features.
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