Module: ActiveFacts::API::Instance

Included in:
Entity, Value
Defined in:
lib/activefacts/api/instance.rb

Overview

Every Instance of a ObjectType (A Value type or an Entity type) includes the methods of this module:

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#constellationObject (readonly)

What constellation does this Instance belong to (if any):



12
13
14
# File 'lib/activefacts/api/instance.rb', line 12

def constellation
  @constellation
end

Instance Method Details

#initialize(args = []) ⇒ Object

:nodoc:



14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/activefacts/api/instance.rb', line 14

def initialize(args = []) #:nodoc:
  unless (self.class.is_entity_type)
    begin
      super(*args)
	  rescue TypeError => e
	    if trace(:debug)
 p e; puts e.backtrace*"\n\t"; debugger; true
	    end
    rescue ArgumentError => e
      e.message << " constructing a #{self.class}"
      raise
    end
  end
end

#instance_indexObject



49
50
51
# File 'lib/activefacts/api/instance.rb', line 49

def instance_index
  @constellation.send(self.class.basename.to_sym)
end

#is_a?(klass) ⇒ Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/activefacts/api/instance.rb', line 29

def is_a? klass
  super || self.class.supertypes_transitive.include?(klass)
end

List entities which have an identifying role played by this object.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/activefacts/api/instance.rb', line 34

def related_entities(indirectly = true, instances = [])
	# Check all roles of this instance
  self.class.all_role.each do |role_name, role|
	  # If the counterpart role is not identifying for its object type, skip it
	  next unless c = role.counterpart and c.is_identifying

	  identified_instances = Array(self.send(role.getter))
	  instances.concat(identified_instances)
	  identified_instances.each do |instance|
	    instance.related_entities(indirectly, instances) if indirectly
	  end
  end
  instances
end

#retractObject

De-assign all functional roles and remove from constellation, if any.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/activefacts/api/instance.rb', line 54

def retract
	return unless constellation = @constellation

	unless constellation.loggers.empty?
	  # An object may have multiple identifiers, with potentially overlapping role sets
	  # Get one copy of each role to use in asserting the instance
	  if self.class.is_entity_type
	    identifying_role_values = {}
	    ([self.class]+self.class.supertypes_transitive).each do |klass|
 klass.identifying_role_names.zip(identifying_role_values(klass)).each do |name, value|
		identifying_role_values[name] = value
 end
	    end
	  else
	    identifying_role_values = self
	  end
	end

  # Delete from the constellation first, while we remember our identifying role values
  constellation.deindex_instance(self)
	instance_variable_set(@@constellation_variable_name ||= "@constellation", nil)

  # Now, for all roles (from this class and all supertypes), assign nil to all functional roles
  # The counterpart roles get cleared automatically.
	klasses = [self.class]+self.class.supertypes_transitive

	irvrvs = {}  # identifying_role_values by RoleValues
	self.class.all_role_transitive.each do |_, role|
	  next unless role.counterpart and
	    role.unique and
	    !role.counterpart.unique and
	    counterpart = send(role.getter)
	  role_values = counterpart.send(role.counterpart.getter)
	  irvrvs[role_values] = role_values.index_values(self)
	end

	# Nullify the counterpart role of objects we identify first, before damaging our identifying_role_values:
	klasses.each do |klass|
    klass.all_role.each do |role_name, role|
	    next if role.unary?
	    next if !(counterpart = role.counterpart).is_identifying
	    next if role.fact_type.is_a?(TypeInheritanceFactType)

	    counterpart_instances = send(role.getter)
	    counterpart_instances.to_a.each do |counterpart_instance|
 # Allow nullifying non-mandatory roles, as long as they're not identifying.
 if counterpart.mandatory
		counterpart_instance.retract
 else
		counterpart_instance.send(counterpart.setter, nil, false)
 end
	    end
	  end
	end

	# Now deal with other roles:
	klasses.each do |klass|
    klass.all_role.each do |role_name, role|
      next if role.unary?
      counterpart = role.counterpart

	    # Objects being created do not have to have non-identifying mandatory roles,
	    # so we allow retracting to the same state.
      if role.unique
 next if role.fact_type.is_a?(TypeInheritanceFactType)
 i = send(role.getter)
 next unless i

 if (counterpart.unique)
		# REVISIT: This will incorrectly fail to propagate a key change for a non-mandatory role
		i.send(counterpart.setter, nil, false)
 else
		rv = i.send(role.counterpart.getter)
		rv.delete_instance(self, irvrvs[rv])

		if (rv.empty? && !i.class.is_entity_type)
		  i.retract if i.plays_no_role
		end

 end
 instance_variable_set(role.variable, nil)
      else
        # puts "Not removing role #{role_name} from counterpart RoleValues #{counterpart.name}"
        # Duplicate the array using to_a, as the RoleValues here will be modified as we traverse it:
 next if role.fact_type.is_a?(TypeInheritanceFactType)
 counterpart_instances = send(role.getter)
 counterpart_instances.to_a.each do |counterpart_instance|
		# This action deconstructs our RoleValues as we go:
		counterpart_instance.send(counterpart.setter, nil, false)
        end
 instance_variable_set(role.variable, nil)
      end
    end
  end

	constellation.loggers.each{|l| l.call(:retract, self.class, identifying_role_values) }

end