Module: ActiveFacts::API::Entity::ClassMethods
- Includes:
- Instance::ClassMethods
- Defined in:
- lib/activefacts/api/entity.rb
Overview
All classes that become Entity types receive the methods of this class as class methods:
Constant Summary
Constants included from ObjectType
ObjectType::CHECKED_IDENTIFYING_ROLE, ObjectType::SKIP_MUTUAL_PROPAGATION
Instance Attribute Summary collapse
-
#created_instances ⇒ Object
Returns the value of attribute created_instances.
-
#identification_inherited_from ⇒ Object
Returns the value of attribute identification_inherited_from.
-
#overrides_identification_of ⇒ Object
Returns the value of attribute overrides_identification_of.
Instance Method Summary collapse
- #assert_instance(constellation, args) ⇒ Object
-
#check_no_supertype_instance_exists(constellation, arg_hash) ⇒ Object
all its candidate keys must match those from the arg_hash.
- #check_supertype_identifiers_match(instance, arg_hash) ⇒ Object
- #find_inherited_role(role_name) ⇒ Object
-
#identified_by(*args) ⇒ Object
A object_type that isn’t a ValueType must have an identification scheme, which is a list of roles it plays.
-
#identifying_role_names ⇒ Object
Return the array of Role objects that define the identifying relationships of this Entity type:.
-
#identifying_role_values(constellation, args) ⇒ Object
This method receives an array (possibly including a trailing arguments hash) from which the values of identifying roles must be coerced.
- #identifying_roles ⇒ Object
-
#index_instance(constellation, instance) ⇒ Object
:nodoc:.
-
#inherited(other) ⇒ Object
:nodoc:.
-
#verbalise ⇒ Object
verbalise this object_type.
Methods included from ObjectType
#add_role, #all_role, #all_role_transitive, #check_identifying_role_has_valid_cardinality, #has_one, #maybe, #one_to_one, #realise_role, #subtypes, #subtypes_transitive, #supertypes, #supertypes_transitive, #vocabulary
Instance Attribute Details
#created_instances ⇒ Object
Returns the value of attribute created_instances.
237 238 239 |
# File 'lib/activefacts/api/entity.rb', line 237 def created_instances @created_instances end |
#identification_inherited_from ⇒ Object
Returns the value of attribute identification_inherited_from.
235 236 237 |
# File 'lib/activefacts/api/entity.rb', line 235 def identification_inherited_from @identification_inherited_from end |
#overrides_identification_of ⇒ Object
Returns the value of attribute overrides_identification_of.
236 237 238 |
# File 'lib/activefacts/api/entity.rb', line 236 def overrides_identification_of @overrides_identification_of end |
Instance Method Details
#assert_instance(constellation, args) ⇒ Object
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
# File 'lib/activefacts/api/entity.rb', line 359 def assert_instance(constellation, args) key = (constellation, args) # The args is now normalized to an array containing a single Hash element arg_hash = args[-1] # Find or make an instance of the class: instance_index = constellation.instances[self] # All instances of this class in this constellation instance = constellation.has_candidate(self, key) || instance_index[key] if (instance) # Check that all assertions about supertype keys are non-contradictory check_supertype_identifiers_match(instance, arg_hash) else # Check that no instance of any supertype matches the keys given check_no_supertype_instance_exists(constellation, arg_hash) instance = new_instance(constellation, arg_hash) constellation.candidate(instance) end # Assign any extra roles that may have been passed. # An exception here leaves the object indexed, # but without the offending role (re-)assigned. arg_hash.each do |k, v| role = instance.class.all_role(k) unless role. && role.object_type == self value = if v == nil nil elsif role.unary? (v && true) # Preserve nil and false else role.counterpart.object_type.assert_instance(constellation, Array(v)) end constellation.when_admitted { instance.send(:"#{k}=", value) } end end instance end |
#check_no_supertype_instance_exists(constellation, arg_hash) ⇒ Object
all its candidate keys must match those from the arg_hash.
291 292 293 294 295 296 297 298 |
# File 'lib/activefacts/api/entity.rb', line 291 def check_no_supertype_instance_exists constellation, arg_hash supertypes_transitive.each do |supertype| key = supertype.(constellation, [arg_hash]) if constellation.instances[supertype][key] raise TypeMigrationException.new(basename, supertype, key) end end end |
#check_supertype_identifiers_match(instance, arg_hash) ⇒ Object
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/activefacts/api/entity.rb', line 267 def check_supertype_identifiers_match instance, arg_hash supertypes_transitive.each do |supertype| supertype..each do |role| next unless arg_hash.include?(role.name) # No contradiction here new_value = arg_hash[role.name] existing_value = instance.send(role.name.to_sym) # Quick check for an exact match: counterpart_class = role.counterpart && role.counterpart.object_type next if existing_value == new_value or existing_value.(counterpart_class) == new_value # Coerce the new value to identifying values for the counterpart role's type: role = supertype.all_role(role.name) new_key = role.counterpart.object_type.(instance.constellation, [new_value]) next if existing_value == new_key # This can happen when the counterpart is a value type existing_key = existing_value.(counterpart_class) next if existing_key == new_key raise TypeConflictException.new(basename, supertype, new_key, existing_key) end end end |
#find_inherited_role(role_name) ⇒ Object
257 258 259 260 261 262 263 264 265 |
# File 'lib/activefacts/api/entity.rb', line 257 def find_inherited_role(role_name) if !superclass.is_entity_type false elsif superclass.all_role.has_key?(role_name) superclass.all_role[role_name] else superclass.find_inherited_role(role_name) end end |
#identified_by(*args) ⇒ Object
A object_type that isn’t a ValueType must have an identification scheme, which is a list of roles it plays. The identification scheme may be inherited from a superclass.
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/activefacts/api/entity.rb', line 419 def identified_by(*args) #:nodoc: = (args[-1].is_a?(Hash) ? args.pop : {}) .each do |key, value| raise UnrecognisedOptionsException.new('EntityType', basename, key) unless respond_to?(key) send(key, value) end raise MissingIdentificationException.new(self) unless args.size > 0 # Catch the case where we state the same identification as our superclass: inherited_role_names = if !inherited_role_names.empty? self.overrides_identification_of = superclass while from = self.overrides_identification_of.identification_inherited_from self.overrides_identification_of = from end end return if inherited_role_names == args self.identification_inherited_from = nil # @identifying_role_names here are the symbols passed in, not the Role # objects we should use. We'd need late binding to use Role objects... @identifying_role_names = args end |
#identifying_role_names ⇒ Object
Return the array of Role objects that define the identifying relationships of this Entity type:
240 241 242 243 244 245 246 |
# File 'lib/activefacts/api/entity.rb', line 240 def if identification_inherited_from superclass. else @identifying_role_names ||= [] end end |
#identifying_role_values(constellation, args) ⇒ Object
This method receives an array (possibly including a trailing arguments hash) from which the values of identifying roles must be coerced. Note that when a value which is not the corrent class is received, we recurse to ask that class to coerce what we do have. The return value is an array of (and arrays of) raw values, not object instances.
No new instances may be asserted, nor may any roles of objects in the constellation be changed
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/activefacts/api/entity.rb', line 307 def (constellation, args) irns = # Normalise positional arguments into an arguments hash (this changes the passed parameter) arg_hash = args[-1].is_a?(Hash) ? args.pop : {} # If the first parameter is an object of type self, its # identifying roles provide any values missing from the array/hash. if args[0].is_a?(self) proto = args.shift end # Following arguments provide identifying values in sequence; put them into the hash: irns.each do |role_name| break if args.size == 0 arg_hash[role_name] = args.shift end # Complain if we have left-over arguments if args.size > 0 raise UnexpectedIdentifyingValueException.new(self, irns, args) end # The arg_hash will be used to construct a new instance, if necessary args.push(arg_hash) irns.map do |role_name| all_role(role_name) end.map do |role| if arg_hash.include?(n = role.name) # Do it this way to avoid problems where nil or false is provided value = arg_hash[n] next (value && true) if (role.unary?) if value klass = role.counterpart.object_type value = klass.(constellation, Array(value)) end elsif proto value = proto.send(n) counterpart_class = role.counterpart && role.counterpart.object_type value = value.(counterpart_class) arg_hash[n] = value # Save the value for making a new instance next value if (role.unary?) else value = nil end raise MissingMandatoryRoleValueException.new(self, role) if value.nil? && role.mandatory value end end |
#identifying_roles ⇒ Object
248 249 250 251 252 253 254 255 |
# File 'lib/activefacts/api/entity.rb', line 248 def @identifying_roles ||= .map do |role_name| role = all_role[role_name] || find_inherited_role(role_name) raise "Illegal request for identifying_roles of #{self} before they're all defined" if role == false role end.freeze end |
#index_instance(constellation, instance) ⇒ Object
:nodoc:
402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/activefacts/api/entity.rb', line 402 def index_instance(constellation, instance) #:nodoc: # Index the instance in the constellation's InstanceIndex for this class: instance_index = constellation.instances[self] key = instance.(self) instance_index[key] = instance # Index the instance for each supertype: supertypes.each do |supertype| supertype.index_instance(constellation, instance) end instance end |
#inherited(other) ⇒ Object
:nodoc:
444 445 446 447 448 449 |
# File 'lib/activefacts/api/entity.rb', line 444 def inherited(other) #:nodoc: other.identification_inherited_from = self subtypes << other unless subtypes.include? other TypeInheritanceFactType.new(self, other) vocabulary.__add_object_type(other) end |
#verbalise ⇒ Object
verbalise this object_type
452 453 454 |
# File 'lib/activefacts/api/entity.rb', line 452 def verbalise "#{basename} is identified by #{.map{|role_sym| role_sym.to_s.camelcase}*" and "};" end |