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

#check_identification_change_legality(role, value) ⇒ Object

If this instance’s role is updated to the new value, does that cause a collision? We need to check each superclass that has a different identification pattern



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/activefacts/api/instance.rb', line 35

def check_identification_change_legality(role, value)
  return unless @constellation && role.is_identifying
  return if @constellation.send(:instance_variable_get, :@suspend_duplicate_key_check)

  klasses = [self.class] + self.class.supertypes_transitive
  last_identity = nil
  last_irns = nil
  counterpart_class = role.counterpart ? role.counterpart.object_type : value.class
  duplicate = klasses.detect do |klass|
    next false unless klass.identifying_roles.include?(role)
    irns = klass.identifying_role_names
    if last_irns != irns
      last_identity = identifying_role_values(klass)
      role_position = irns.index(role.name)
      last_identity[role_position] = value.identifying_role_values(counterpart_class)
    end
    @constellation.instances[klass][last_identity]
  end

  raise DuplicateIdentifyingValueException.new(self.class, role.name, value) if duplicate
end

#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



73
74
75
# File 'lib/activefacts/api/instance.rb', line 73

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.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/activefacts/api/instance.rb', line 58

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.



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
# File 'lib/activefacts/api/instance.rb', line 78

def retract
  # Delete from the constellation first, while we remember our identifying role values
  @constellation.deindex_instance(self) if @constellation

  # 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

  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.is_identifying && counterpart.mandatory
    # We play a mandatory identifying role in i; so retract that (it'll clear our instance variable)
    i.retract
 else
    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])
    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.name)
 counterpart_instances.to_a.each do |counterpart_instance|
    # These actions deconstruct the RoleValues as we go:
          if counterpart.is_identifying && counterpart.mandatory
            counterpart_instance.retract
          else
            counterpart_instance.send(counterpart.setter, nil, false)
          end
        end
 instance_variable_set(role.variable, nil)
      end
    end
  end
end