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:
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
REVISIT: This method should verify that all identifying roles (including those required to identify any superclass) are present (if mandatory) and are unique…
- #assign_additional_roles(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(*args) ⇒ Object
Convert the passed arguments into an array of raw values (or arrays of values, transitively) that identify an instance of this Entity type:.
- #identifying_roles ⇒ Object
-
#index_instance(instance, key = nil, key_roles = nil) ⇒ Object
:nodoc:.
-
#inherited(other) ⇒ Object
:nodoc:.
-
#verbalise ⇒ Object
verbalise this object_type.
Methods included from ObjectType
#detect_fact_type_collision, #has_one, #is_a?, #maybe, #one_to_one, #realise_role, #roles, #subtypes, #supertypes, #supertypes_transitive, #vocabulary
Instance Attribute Details
#created_instances ⇒ Object
Returns the value of attribute created_instances.
135 136 137 |
# File 'lib/activefacts/api/entity.rb', line 135 def created_instances @created_instances end |
#identification_inherited_from ⇒ Object
Returns the value of attribute identification_inherited_from.
133 134 135 |
# File 'lib/activefacts/api/entity.rb', line 133 def identification_inherited_from @identification_inherited_from end |
#overrides_identification_of ⇒ Object
Returns the value of attribute overrides_identification_of.
134 135 136 |
# File 'lib/activefacts/api/entity.rb', line 134 def overrides_identification_of @overrides_identification_of end |
Instance Method Details
#assert_instance(constellation, args) ⇒ Object
REVISIT: This method should verify that all identifying roles (including those required to identify any superclass) are present (if mandatory) and are unique… BEFORE it creates any new object(s) This is a hard problem because it’s recursive.
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/activefacts/api/entity.rb', line 211 def assert_instance(constellation, args) #:nodoc: # Build the key for this instance from the args # The key of an instance is the value or array of keys of the identifying values. # The key values aren't necessarily present in the constellation, even after this. key = (*args) # Find and return an existing instance matching this key instances = constellation.instances[self] # All instances of this class in this constellation instance = instances[key] # REVISIT: This ignores any additional attribute assignments if instance # raise "Additional role values are ignored when asserting an existing instance" if args[-1].is_a? Hash and !args[-1].empty? assign_additional_roles(instance, args[-1]) if args[-1].is_a? Hash and !args[-1].empty? return instance, key # A matching instance of this class end # Now construct each of this object's identifying roles irns = @created_instances ||= [] has_hash = args[-1].is_a?(Hash) if args.size == 1+(has_hash ? 1 : 0) and args[0].is_a?(self) # We received a single argument of a compatible type # With a secondary supertype or a type having separate identification, # we would get the wrong identifier from arg.identifying_role_values: key = values = (args[0]) values = values + [arg_hash = args.pop] if has_hash else args, arg_hash = ActiveFacts::extract_hash_args(irns, args) roles_and_values = irns.map{|role_sym| roles(role_sym)}.zip(args) key = [] # Gather the actual key (AutoCounters are special) values = roles_and_values.map do |role, arg| if role.unary? # REVISIT: This could be absorbed into a special counterpart.object_type.assert_instance value = role_key = arg ? true : arg # Preserve false and nil elsif !arg value = role_key = nil else if role.counterpart.object_type.is_entity_type add = !constellation.send(role.counterpart.object_type.basename.to_sym).include?([arg]) else add = !constellation.send(role.counterpart.object_type.basename.to_sym).include?(arg) end value, role_key = role.counterpart.object_type.assert_instance(constellation, Array(arg)) @created_instances << [role.counterpart, value] if add end key << role_key value end values << arg_hash if arg_hash and !arg_hash.empty? end #trace :assert, "Constructing new #{self} with #{values.inspect}" do values << { :constellation => constellation } instance = new(*values) #end assign_additional_roles(instance, arg_hash) return *index_instance(instance, key, irns) rescue DuplicateIdentifyingValueException @created_instances.each do |role, v| if !v.respond_to?(:retract) v = constellation.send(role.object_type.basename.to_sym)[[v]] end v.retract if v end @created_instances = [] raise end |
#assign_additional_roles(instance, arg_hash) ⇒ Object
284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/activefacts/api/entity.rb', line 284 def assign_additional_roles(instance, arg_hash) # Now assign any extra args in the hash which weren't identifiers (extra identifiers will be assigned again) (arg_hash ? arg_hash.entries : []).each do |role_name, value| role = roles(role_name) if !instance.instance_index_counterpart(role).include?(value) @created_instances << [role, value] end instance.send(role.setter, value) end end |
#find_inherited_role(role_name) ⇒ Object
155 156 157 158 159 160 161 162 163 |
# File 'lib/activefacts/api/entity.rb', line 155 def find_inherited_role(role_name) if !superclass.is_entity_type false elsif superclass.roles.has_key?(role_name) superclass.roles[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.
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/activefacts/api/entity.rb', line 320 def identified_by(*args) #:nodoc: raise "You must list the roles which will identify #{self.basename}" 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:
138 139 140 141 142 143 144 |
# File 'lib/activefacts/api/entity.rb', line 138 def if identification_inherited_from superclass. else @identifying_role_names ||= [] end end |
#identifying_role_values(*args) ⇒ Object
Convert the passed arguments into an array of raw values (or arrays of values, transitively) that identify an instance of this Entity type:
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/activefacts/api/entity.rb', line 167 def (*args) irns = # If the single arg is an instance of the correct class or a subclass, # use the instance's identifying_role_values has_hash = args[-1].is_a?(Hash) if (args.size == 1+(has_hash ? 1 : 0) and (arg = args[0]).is_a?(self)) # With a secondary supertype or a subtype having separate identification, # we would get the wrong identifier from arg.identifying_role_values: return irns.map do |role_name| # Use the identifier for the class expected, not the actual: value = arg.send(role_name) value && arg.class.roles(role_name).counterpart_object_type.(value) end end args, arg_hash = ActiveFacts::extract_hash_args(irns, args) if args.size > irns.size raise "#{basename} expects only (#{irns*', '}) for its identifier, but you provided the extra values #{args[irns.size..-1].inspect}" end role_args = irns.map{|role_sym| roles(role_sym)}.zip(args) role_args.map do |role, arg| next !!arg unless role.counterpart # Unary if arg.is_a?(role.counterpart.object_type) # includes secondary supertypes # With a secondary supertype or a type having separate identification, # we would get the wrong identifier from arg.identifying_role_values: next role.counterpart_object_type.(arg) end if arg == nil # But not false if role.mandatory raise "You must provide a #{role.counterpart.object_type.name} to identify a #{basename}" end else role.counterpart_object_type.(*arg) end end end |
#identifying_roles ⇒ Object
146 147 148 149 150 151 152 153 |
# File 'lib/activefacts/api/entity.rb', line 146 def # REVISIT: Should this return nil if identification_inherited_from? @identifying_roles ||= .map do |role_name| role = roles[role_name] || find_inherited_role(role_name) role end end |
#index_instance(instance, key = nil, key_roles = nil) ⇒ Object
:nodoc:
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/activefacts/api/entity.rb', line 296 def index_instance(instance, key = nil, key_roles = nil) #:nodoc: # Derive a new key if we didn't receive one or if the roles are different: unless key && key_roles && key_roles == key = (key_roles = ).map do |role_name| instance.send role_name end raise "You must pass values for #{key_roles.inspect} to identify a #{self.name}" if key.compact == [] end # Index the instance for this class in the constellation instances = instance.constellation.instances[self] instances[key] = instance # Index the instance for each supertype: supertypes.each do |supertype| supertype.index_instance(instance, key, key_roles) end return instance, key end |
#inherited(other) ⇒ Object
:nodoc:
339 340 341 342 343 |
# File 'lib/activefacts/api/entity.rb', line 339 def inherited(other) #:nodoc: other.identification_inherited_from = self subtypes << other unless subtypes.include? other vocabulary.__add_object_type(other) end |
#verbalise ⇒ Object
verbalise this object_type
346 347 348 |
# File 'lib/activefacts/api/entity.rb', line 346 def verbalise "#{basename} is identified by #{.map{|role_sym| role_sym.to_s.camelcase}*" and "};" end |