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.
@@ -23,31 +23,31 @@ module ActiveFacts
23
23
 
24
24
  class InvalidEntityException < SchemaException
25
25
  def initialize klass
26
- super "#{klass.basename} may not be an entity type"
26
+ super "#{klass.basename} may not be an entity type"
27
27
  end
28
28
  end
29
29
 
30
30
  class InvalidIdentificationException < SchemaException
31
31
  def initialize object_type, role, is_single
32
- msg =
33
- if is_single
34
- "#{object_type} has a single identifying role '#{role}' which is has_one, but must be one_to_one"
35
- else
36
- "#{object_type} has an identifying role '#{role}' which is one_to_one, but must be has_one"
37
- end
38
- super msg
32
+ msg =
33
+ if is_single
34
+ "#{object_type} has a single identifying role '#{role}' which is has_one, but must be one_to_one"
35
+ else
36
+ "#{object_type} has an identifying role '#{role}' which is one_to_one, but must be has_one"
37
+ end
38
+ super msg
39
39
  end
40
40
  end
41
41
 
42
42
  class MissingIdentificationException < SchemaException
43
43
  def initialize klass
44
- super "You must list the roles which will identify #{klass.basename}"
44
+ super "You must list the roles which will identify #{klass.basename}"
45
45
  end
46
46
  end
47
47
 
48
48
  class InvalidObjectType < SchemaException
49
49
  def initialize vocabulary, klass, reason
50
- super "A constellation over #{vocabulary.name} cannot index instances of #{klass} because it #{reason}"
50
+ super "A constellation over #{vocabulary.name} cannot index instances of #{klass} because it #{reason}"
51
51
  end
52
52
  end
53
53
 
@@ -71,7 +71,7 @@ module ActiveFacts
71
71
 
72
72
  class UnexpectedIdentifyingValueException < RuntimeException
73
73
  def initialize object_type, identifying_role_names, extra_args
74
- super "#{object_type.basename} expects only (#{identifying_role_names*', '}) for its identifier, but you provided additional values #{extra_args.inspect}"
74
+ super "#{object_type.basename} expects only (#{identifying_role_names*', '}) for its identifier, but you provided additional values #{extra_args.inspect}"
75
75
  end
76
76
  end
77
77
 
@@ -92,14 +92,14 @@ module ActiveFacts
92
92
  # When an existing object having multiple identification patterns is re-asserted, all the keys must match the existing object
93
93
  class TypeConflictException < RuntimeException
94
94
  def initialize(klass, supertype, key, existing)
95
- super "#{klass} cannot be asserted to have #{supertype} identifier #{key.inspect} because the existing object has #{existing.inspect}"
95
+ super "#{klass} cannot be asserted to have #{supertype} identifier #{key.inspect} because the existing object has #{existing.inspect}"
96
96
  end
97
97
  end
98
98
 
99
99
  # When a new entity is asserted, but a supertype identifier matches an existing object of a different type, type migration is implied but unfortunately is impossible in Ruby
100
100
  class TypeMigrationException < RuntimeException
101
101
  def initialize(klass, supertype, key)
102
- super "#{klass} cannot be asserted due to the prior existence of a conflicting #{supertype} identified by #{key.inspect}"
102
+ super "#{klass} cannot be asserted due to the prior existence of a conflicting #{supertype} identified by #{key.inspect}"
103
103
  end
104
104
  end
105
105
 
@@ -13,7 +13,7 @@ module ActiveFacts
13
13
  # invariant { self.all_role.each {|role| self.is_a?(ObjectifiedFactType) ? role.counterpart.object_type == self.objectified_as : role.fact_type == self } }
14
14
 
15
15
  def initialize
16
- @all_role ||= []
16
+ @all_role ||= []
17
17
  end
18
18
  end
19
19
 
@@ -30,11 +30,11 @@ module ActiveFacts
30
30
  attr_reader :supertype_role, :subtype_role
31
31
 
32
32
  def initialize(supertype, subtype)
33
- super()
33
+ super()
34
34
 
35
- # The supertype role is not mandatory, but the subtype role is. Both are unique.
36
- @supertype_role = Role.new(self, supertype, subtype.name.gsub(/.*::/,'').to_sym, false, true)
37
- @subtype_role = Role.new(self, subtype, supertype.name.gsub(/.*::/,'').to_sym, true, true)
35
+ # The supertype role is not mandatory, but the subtype role is. Both are unique.
36
+ @supertype_role = Role.new(self, supertype, subtype.name.gsub(/.*::/,'').to_sym, false, true)
37
+ @subtype_role = Role.new(self, subtype, supertype.name.gsub(/.*::/,'').to_sym, true, true)
38
38
  end
39
39
  end
40
40
  end
@@ -24,17 +24,17 @@ class Guid
24
24
  if i == :new
25
25
  case @@sequence
26
26
  when 'fixed'
27
- @@counter ||= 0
28
- @value = SecureRandom.format_uuid('%032x' % (@@counter += 1))
27
+ @@counter ||= 0
28
+ @value = SecureRandom.format_uuid('%032x' % (@@counter += 1))
29
29
  when 'record'
30
- @@sequence_file ||= File.open(SEQ_FILE_NAME, 'w')
31
- @value = SecureRandom.uuid.freeze
32
- @@sequence_file.puts(@value)
30
+ @@sequence_file ||= File.open(SEQ_FILE_NAME, 'w')
31
+ @value = SecureRandom.uuid.freeze
32
+ @@sequence_file.puts(@value)
33
33
  when 'replay'
34
- @@sequence_file ||= File.open(SEQ_FILE_NAME, 'r')
35
- @value = @@sequence_file.gets.chomp
34
+ @@sequence_file ||= File.open(SEQ_FILE_NAME, 'r')
35
+ @value = @@sequence_file.gets.chomp
36
36
  else
37
- @value = SecureRandom.uuid.freeze
37
+ @value = SecureRandom.uuid.freeze
38
38
  end
39
39
  elsif (v = i.to_s).length == 36 and !(v !~ /[^0-9a-f]/i)
40
40
  @value = v.clone.freeze
@@ -68,7 +68,7 @@ class Guid
68
68
  to_s.eql?(o.to_s)
69
69
  end
70
70
 
71
- def <=>(o) #:nodoc:
71
+ def <=>(o) #:nodoc:
72
72
  to_s.<=>(o.to_s)
73
73
  end
74
74
 
@@ -15,10 +15,10 @@ module ActiveFacts
15
15
  unless (self.class.is_entity_type)
16
16
  begin
17
17
  super(*args)
18
- rescue TypeError => e
19
- if trace(:debug)
20
- p e; puts e.backtrace*"\n\t"; debugger; true
21
- end
18
+ rescue TypeError => e
19
+ if trace(:debug)
20
+ p e; puts e.backtrace*"\n\t"; debugger; true
21
+ end
22
22
  rescue ArgumentError => e
23
23
  e.message << " constructing a #{self.class}"
24
24
  raise
@@ -32,16 +32,16 @@ module ActiveFacts
32
32
 
33
33
  # List entities which have an identifying role played by this object.
34
34
  def related_entities(indirectly = true, instances = [])
35
- # Check all roles of this instance
35
+ # Check all roles of this instance
36
36
  self.class.all_role.each do |role_name, role|
37
- # If the counterpart role is not identifying for its object type, skip it
38
- next unless c = role.counterpart and c.is_identifying
39
-
40
- identified_instances = Array(self.send(role.getter))
41
- instances.concat(identified_instances)
42
- identified_instances.each do |instance|
43
- instance.related_entities(indirectly, instances) if indirectly
44
- end
37
+ # If the counterpart role is not identifying for its object type, skip it
38
+ next unless c = role.counterpart and c.is_identifying
39
+
40
+ identified_instances = Array(self.send(role.getter))
41
+ instances.concat(identified_instances)
42
+ identified_instances.each do |instance|
43
+ instance.related_entities(indirectly, instances) if indirectly
44
+ end
45
45
  end
46
46
  instances
47
47
  end
@@ -52,101 +52,106 @@ module ActiveFacts
52
52
 
53
53
  # De-assign all functional roles and remove from constellation, if any.
54
54
  def retract
55
- return unless constellation = @constellation
56
-
57
- unless constellation.loggers.empty?
58
- # An object may have multiple identifiers, with potentially overlapping role sets
59
- # Get one copy of each role to use in asserting the instance
60
- if self.class.is_entity_type
61
- identifying_role_values = {}
62
- ([self.class]+self.class.supertypes_transitive).each do |klass|
63
- klass.identifying_role_names.zip(identifying_role_values(klass)).each do |name, value|
64
- identifying_role_values[name] = value
65
- end
66
- end
67
- else
68
- identifying_role_values = self
69
- end
70
- end
55
+ return unless constellation = @constellation
56
+
57
+ unless constellation.loggers.empty?
58
+ # An object may have multiple identifiers, with potentially overlapping role sets
59
+ # Get one copy of each role to use in asserting the instance
60
+ if self.class.is_entity_type
61
+ identifying_role_values = {}
62
+ ([self.class]+self.class.supertypes_transitive).each do |klass|
63
+ klass.identifying_role_names.zip(identifying_role_values(klass)).each do |name, value|
64
+ identifying_role_values[name] = value
65
+ end
66
+ end
67
+ else
68
+ identifying_role_values = self
69
+ end
70
+ end
71
71
 
72
72
  # Delete from the constellation first, while we remember our identifying role values
73
73
  constellation.deindex_instance(self)
74
- instance_variable_set(@@constellation_variable_name ||= "@constellation", nil)
74
+ instance_variable_set(@@constellation_variable_name ||= "@constellation", nil)
75
75
 
76
76
  # Now, for all roles (from this class and all supertypes), assign nil to all functional roles
77
77
  # The counterpart roles get cleared automatically.
78
- klasses = [self.class]+self.class.supertypes_transitive
79
-
80
- irvrvs = {} # identifying_role_values by RoleValues
81
- self.class.all_role_transitive.each do |_, role|
82
- next unless role.counterpart and
83
- role.unique and
84
- !role.counterpart.unique and
85
- counterpart = send(role.getter)
86
- role_values = counterpart.send(role.counterpart.getter)
87
- irvrvs[role_values] = role_values.index_values(self)
88
- end
89
-
90
- # Nullify the counterpart role of objects we identify first, before damaging our identifying_role_values:
91
- klasses.each do |klass|
78
+ klasses = [self.class]+self.class.supertypes_transitive
79
+
80
+ irvrvs = {} # identifying_role_values by RoleValues
81
+ self.class.all_role_transitive.each do |_, role|
82
+ next unless role.counterpart and
83
+ role.unique and
84
+ !role.counterpart.unique and
85
+ counterpart = send(role.getter)
86
+ role_values = counterpart.send(role.counterpart.getter)
87
+ irvrvs[role_values] = role_values.index_values(self)
88
+ end
89
+
90
+ # Nullify the counterpart role of objects we identify first, before damaging our identifying_role_values:
91
+ klasses.each do |klass|
92
92
  klass.all_role.each do |role_name, role|
93
- next if role.unary?
94
- next if !(counterpart = role.counterpart).is_identifying
95
- next if role.fact_type.is_a?(TypeInheritanceFactType)
96
-
97
- counterpart_instances = send(role.getter)
98
- counterpart_instances.to_a.each do |counterpart_instance|
99
- # Allow nullifying non-mandatory roles, as long as they're not identifying.
100
- if counterpart.mandatory
101
- counterpart_instance.retract
102
- else
103
- counterpart_instance.send(counterpart.setter, nil, false)
104
- end
105
- end
106
- end
107
- end
108
-
109
- # Now deal with other roles:
110
- klasses.each do |klass|
93
+ next if role.unary?
94
+ next if !(counterpart = role.counterpart).is_identifying
95
+ next if role.fact_type.is_a?(TypeInheritanceFactType)
96
+
97
+ counterpart_instances = send(role.getter)
98
+ counterpart_instances.to_a.each do |counterpart_instance|
99
+ # Allow nullifying non-mandatory roles, as long as they're not identifying.
100
+ if counterpart.mandatory
101
+ counterpart_instance.retract
102
+ else
103
+ counterpart_instance.send(counterpart.setter, nil, false)
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ # Now deal with other roles:
110
+ klasses.each do |klass|
111
111
  klass.all_role.each do |role_name, role|
112
112
  next if role.unary?
113
113
  counterpart = role.counterpart
114
114
 
115
- # Objects being created do not have to have non-identifying mandatory roles,
116
- # so we allow retracting to the same state.
115
+ # Objects being created do not have to have non-identifying mandatory roles,
116
+ # so we allow retracting to the same state.
117
117
  if role.unique
118
- next if role.fact_type.is_a?(TypeInheritanceFactType)
119
- i = send(role.getter)
120
- next unless i
121
-
122
- if (counterpart.unique)
123
- # REVISIT: This will incorrectly fail to propagate a key change for a non-mandatory role
124
- i.send(counterpart.setter, nil, false)
125
- else
126
- rv = i.send(role.counterpart.getter)
127
- rv.delete_instance(self, irvrvs[rv])
128
-
129
- if (rv.empty? && !i.class.is_entity_type)
130
- i.retract if i.plays_no_role
131
- end
132
-
133
- end
134
- instance_variable_set(role.variable, nil)
118
+ next if role.fact_type.is_a?(TypeInheritanceFactType)
119
+ counterpart_instance = send(role.getter)
120
+ next unless counterpart_instance && counterpart_instance.constellation
121
+
122
+ if (counterpart.unique)
123
+ # REVISIT: This will incorrectly fail to propagate a key change for a non-mandatory role
124
+ counterpart_instance.send(counterpart.setter, nil, false)
125
+ else
126
+ rv = counterpart_instance.send(role.counterpart.getter)
127
+ rv.delete_instance(self, irvrvs[rv])
128
+
129
+ if (rv.empty? && !counterpart_instance.class.is_entity_type)
130
+ counterpart_instance.retract if counterpart_instance.plays_no_role
131
+ end
132
+
133
+ end
134
+ instance_variable_set(role.variable, nil)
135
135
  else
136
136
  # puts "Not removing role #{role_name} from counterpart RoleValues #{counterpart.name}"
137
137
  # Duplicate the array using to_a, as the RoleValues here will be modified as we traverse it:
138
- next if role.fact_type.is_a?(TypeInheritanceFactType)
139
- counterpart_instances = send(role.getter)
140
- counterpart_instances.to_a.each do |counterpart_instance|
141
- # This action deconstructs our RoleValues as we go:
142
- counterpart_instance.send(counterpart.setter, nil, false)
138
+ next if role.fact_type.is_a?(TypeInheritanceFactType)
139
+ counterpart_instances = send(role.getter)
140
+ counterpart_instances.to_a.each do |counterpart_instance|
141
+ next unless counterpart_instance.constellation
142
+ # This action deconstructs our RoleValues as we go:
143
+ if counterpart.mandatory
144
+ counterpart_instance.retract
145
+ else
146
+ counterpart_instance.send(counterpart.setter, nil, false)
147
+ end
143
148
  end
144
- instance_variable_set(role.variable, nil)
149
+ instance_variable_set(role.variable, nil)
145
150
  end
146
151
  end
147
152
  end
148
153
 
149
- constellation.loggers.each{|l| l.call(:retract, self.class, identifying_role_values) }
154
+ constellation.loggers.each{|l| l.call(:retract, self.class, identifying_role_values) }
150
155
 
151
156
  end
152
157
 
@@ -10,48 +10,48 @@ module ActiveFacts
10
10
  module API
11
11
  class KeyArray < Array
12
12
  def initialize(a)
13
- super(
14
- a.map do |e|
15
- if e.is_a?(Array) && e.class != self.class
16
- KeyArray.new(e)
17
- elsif e.eql?(nil)
18
- []
19
- else
20
- e
21
- end
22
- end
23
- )
13
+ super(
14
+ a.map do |e|
15
+ if e.is_a?(Array) && e.class != self.class
16
+ KeyArray.new(e)
17
+ elsif e.eql?(nil)
18
+ []
19
+ else
20
+ e
21
+ end
22
+ end
23
+ )
24
24
  end
25
25
 
26
26
  def inspect
27
- "KeyArray"+super
27
+ "KeyArray"+super
28
28
  end
29
29
 
30
30
  # This is used by RBTree for searching, and we need it to use eql? semantics to be like a Hash
31
31
  def ==(other)
32
- self.eql? other
32
+ self.eql? other
33
33
  end
34
34
 
35
35
  def <=>(other)
36
- unless other.is_a?(Array) # Any kind of Array, not just KeyArray
37
- return 1
38
- end
39
-
40
- 0.upto(size-1) do |i|
41
- diff = ((s = self[i]) <=> (o = other[i]) rescue nil)
42
- case diff
43
- when 0 # Same value, whether exactly the same class or not
44
- next
45
- when nil # Non-comparable values
46
- return -1 if s == nil # Ensure that nil values come before other values
47
- return 1 if o == nil
48
- diff = s.class.name <=> o.class.name # Otherwise just ensure stable sorting
49
- return diff if diff != 0
50
- else
51
- return diff
52
- end
53
- end
54
- 0
36
+ unless other.is_a?(Array) # Any kind of Array, not just KeyArray
37
+ return 1
38
+ end
39
+
40
+ 0.upto(size-1) do |i|
41
+ diff = ((s = self[i]) <=> (o = other[i]) rescue nil)
42
+ case diff
43
+ when 0 # Same value, whether exactly the same class or not
44
+ next
45
+ when nil # Non-comparable values
46
+ return -1 if s == nil # Ensure that nil values come before other values
47
+ return 1 if o == nil
48
+ diff = s.class.name <=> o.class.name # Otherwise just ensure stable sorting
49
+ return diff if diff != 0
50
+ else
51
+ return diff
52
+ end
53
+ end
54
+ 0
55
55
  end
56
56
  end
57
57
 
@@ -65,15 +65,15 @@ module ActiveFacts
65
65
 
66
66
  # Should be in module ForwardableWithArityChecking
67
67
  def self.def_single_delegator(accessor, method, *expected_arities)
68
- str = %{
69
- def #{method}(*args, &block)
70
- if #{expected_arities.size == 0 ? "block" : "!block || !#{expected_arities.inspect}.include?(block.arity)" }
71
- raise ArgumentError.new("Arity mismatch on #{name}\##{method}, got \#{block ? block.arity : 'none'} want #{expected_arities.inspect} at \#{caller*"\n\t"})")
72
- end
73
- #{accessor}.__send__(:#{method}, *args, &block)
74
- end
75
- }
76
- eval(str)
68
+ str = %{
69
+ def #{method}(*args, &block)
70
+ if #{expected_arities.size == 0 ? "block" : "!block || !#{expected_arities.inspect}.include?(block.arity)" }
71
+ raise ArgumentError.new("Arity mismatch on #{name}\##{method}, got \#{block ? block.arity : 'none'} want #{expected_arities.inspect} at \#{caller*"\n\t"})")
72
+ end
73
+ #{accessor}.__send__(:#{method}, *args, &block)
74
+ end
75
+ }
76
+ eval(str)
77
77
  end
78
78
 
79
79
  def_single_delegator :@hash, :size
@@ -87,7 +87,7 @@ module ActiveFacts
87
87
  def initialize(constellation, klass, sort)
88
88
  @constellation = constellation
89
89
  @klass = klass
90
- @sort = sort
90
+ @sort = sort
91
91
  @hash = sort ? RBTree.new : {}
92
92
  end
93
93
 
@@ -96,7 +96,7 @@ module ActiveFacts
96
96
  end
97
97
 
98
98
  def delete(k)
99
- @hash.delete(@sort ? form_key(k) : k)
99
+ @hash.delete(@sort ? form_key(k) : k)
100
100
  end
101
101
 
102
102
  def detect &b
@@ -109,7 +109,7 @@ module ActiveFacts
109
109
  end
110
110
 
111
111
  def [](key)
112
- @hash[@sort ? form_key(key) : key]
112
+ @hash[@sort ? form_key(key) : key]
113
113
  end
114
114
 
115
115
  def refresh_key(old_key)
@@ -119,14 +119,14 @@ module ActiveFacts
119
119
  end
120
120
 
121
121
  def form_key key
122
- case key
123
- when Array
124
- KeyArray.new(key)
125
- when nil
126
- []
127
- else
128
- key
129
- end
122
+ case key
123
+ when Array
124
+ KeyArray.new(key)
125
+ when nil
126
+ []
127
+ else
128
+ key
129
+ end
130
130
  end
131
131
  end
132
132
  end