activefacts-api 1.9.10 → 1.9.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/activefacts-api.gemspec +2 -2
- data/lib/activefacts/api/constellation.rb +3 -2
- data/lib/activefacts/api/entity.rb +16 -15
- data/lib/activefacts/api/guid.rb +7 -5
- data/lib/activefacts/api/instance.rb +11 -3
- data/lib/activefacts/api/numeric.rb +3 -1
- data/lib/activefacts/api/object_type.rb +8 -8
- data/lib/activefacts/api/role_values.rb +21 -11
- data/lib/activefacts/api/standard_types.rb +1 -1
- data/lib/activefacts/api/support.rb +0 -6
- data/lib/activefacts/api/value.rb +1 -1
- data/lib/activefacts/api/version.rb +1 -1
- metadata +10 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8c3ae722ceb4f264e163be7c166507f6ab3ab328cea1513ff0599ea0c54a3270
|
4
|
+
data.tar.gz: '096701429372fe651503a58c4631c0f6090f21493555a3c2705ec2cbd71c1f04'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbb093b3faaa2c8f31e5c9f33c6afd076e3d72e803beb57272eb6769e6a44af9a98c909f9643c5d08da3f9fe0e0815ed76b90cecd9de524a6453497485d79346
|
7
|
+
data.tar.gz: 8f349dca05234d1b24c2408eb81ee5fbc3d0a3458021c099374cf4da6118c349d7dbc32c5e82a86c462da06acb878f6de8ab1f43a8de58cdcced608ec8b79979
|
data/activefacts-api.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = ActiveFacts::API::VERSION
|
9
9
|
spec.authors = ["Clifford Heath"]
|
10
10
|
spec.email = ["clifford.heath@gmail.com"]
|
11
|
-
spec.date
|
11
|
+
spec.date = "2022-06-15"
|
12
12
|
|
13
13
|
spec.summary = "A fact-based data model DSL and API"
|
14
14
|
spec.description = %q{
|
@@ -35,7 +35,7 @@ over the fact population.
|
|
35
35
|
spec.add_runtime_dependency 'tracing', ["~> 2", ">= 2.0.4"]
|
36
36
|
|
37
37
|
spec.add_development_dependency "bundler", ">= 1.10"
|
38
|
-
spec.add_development_dependency "rake", "
|
38
|
+
spec.add_development_dependency "rake", ">= 10"
|
39
39
|
spec.add_development_dependency "rspec", "~> 3.3"
|
40
40
|
end
|
41
41
|
|
@@ -65,7 +65,7 @@ module ActiveFacts
|
|
65
65
|
# With no parameters, return the collection of all instances of that object_type.
|
66
66
|
# With parameters, assert an instance of the object_type identified by the values passed as args.
|
67
67
|
def method_missing(m, *args, &b)
|
68
|
-
klass = @vocabulary.const_get(m)
|
68
|
+
klass = @vocabulary.const_get(m) rescue nil # Catch missing lower-case names (wrong constant) and use super
|
69
69
|
if invalid_object_type klass
|
70
70
|
super
|
71
71
|
else
|
@@ -75,7 +75,8 @@ module ActiveFacts
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def define_class_accessor m, klass
|
78
|
-
singleton_class.
|
78
|
+
singleton_class.
|
79
|
+
send(:define_method, m) do |*args|
|
79
80
|
if args.size == 0
|
80
81
|
# Return the collection of all instances of this class in the constellation:
|
81
82
|
instances[klass]
|
@@ -32,9 +32,9 @@ module ActiveFacts
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def initialize_existential_roles(klass, arg_hash)
|
35
|
-
#
|
36
|
-
|
37
|
-
initialize_existential_roles(
|
35
|
+
# Assign the identifying attributes of all superclasses first
|
36
|
+
klass.supertypes_transitive.each do |supertype|
|
37
|
+
initialize_existential_roles(supertype, arg_hash)
|
38
38
|
end
|
39
39
|
|
40
40
|
irns = klass.identifying_role_names
|
@@ -159,9 +159,9 @@ module ActiveFacts
|
|
159
159
|
# identified by this entity. Save the current key and
|
160
160
|
# class for each such instance.
|
161
161
|
# This function is transitive!
|
162
|
-
def
|
163
|
-
|
164
|
-
|
162
|
+
def collect_instance_index_updates role
|
163
|
+
instance_index_updates = []
|
164
|
+
propagation_roles = []
|
165
165
|
|
166
166
|
# Consider the object itself and all its supertypes
|
167
167
|
([self.class]+self.class.supertypes_transitive).map do |supertype|
|
@@ -169,7 +169,7 @@ module ActiveFacts
|
|
169
169
|
|
170
170
|
old_key = identifying_role_values(supertype)
|
171
171
|
# puts "Need to reindex #{self.class} as #{supertype} from #{old_key.inspect}"
|
172
|
-
|
172
|
+
instance_index_updates << [constellation.instances[supertype], self, old_key]
|
173
173
|
|
174
174
|
supertype.
|
175
175
|
all_role.
|
@@ -178,29 +178,29 @@ module ActiveFacts
|
|
178
178
|
next unless counterpart = propagation_role.counterpart # And the role is not unary
|
179
179
|
if counterpart.is_identifying # This object identifies another
|
180
180
|
# puts "Changing #{propagation_role.inspect} affects #{counterpart.inspect}"
|
181
|
-
|
181
|
+
propagation_roles << propagation_role
|
182
182
|
else
|
183
183
|
next if counterpart.unique # But a one-to-many
|
184
184
|
next unless value = send(propagation_role.getter) # A value is set
|
185
185
|
role_values = value.send(counterpart.getter) # This is the index we have to change
|
186
186
|
# puts "Changing #{role.inspect} of a #{self.class} requires updating #{propagation_role.counterpart.inspect}"
|
187
|
-
|
187
|
+
instance_index_updates << [role_values, self, old_key]
|
188
188
|
end
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
|
-
|
192
|
+
propagation_roles.each do |role|
|
193
193
|
affected_instances = Array(send(role.getter))
|
194
194
|
# puts "considering #{affected_instances.size} #{role.object_type.name} instances that include #{role.inspect}: #{affected_instances.map(&:identifying_role_values).inspect}"
|
195
195
|
affected_instances.each do |counterpart|
|
196
|
-
|
196
|
+
instance_index_updates.concat(counterpart.collect_instance_index_updates(role.counterpart))
|
197
197
|
end
|
198
198
|
end
|
199
|
-
|
199
|
+
instance_index_updates
|
200
200
|
end
|
201
201
|
|
202
|
-
def
|
203
|
-
|
202
|
+
def apply_instance_index_updates instance_index_updates
|
203
|
+
instance_index_updates.each do |index, entity, old_key|
|
204
204
|
new_key = entity.identifying_role_values(index.object_type)
|
205
205
|
# puts "Reindexing #{klass} from #{old_key.inspect} to #{new_key.inspect}"
|
206
206
|
|
@@ -390,6 +390,7 @@ module ActiveFacts
|
|
390
390
|
unless role.is_identifying && role.object_type == self
|
391
391
|
value =
|
392
392
|
if v == nil
|
393
|
+
raise "nil value passed for mandatory #{role.name} of #{role.object_type.name}" if role.mandatory
|
393
394
|
nil
|
394
395
|
elsif role.unary?
|
395
396
|
(v && true) # Preserve nil and false
|
@@ -465,7 +466,7 @@ module ActiveFacts
|
|
465
466
|
|
466
467
|
def other.new_instance constellation, *args
|
467
468
|
instance = allocate
|
468
|
-
instance.instance_variable_set(
|
469
|
+
instance.instance_variable_set(constellation_variable_name, constellation)
|
469
470
|
instance.send(:initialize, *args)
|
470
471
|
instance
|
471
472
|
end
|
data/lib/activefacts/api/guid.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'delegate'
|
2
2
|
require 'securerandom'
|
3
3
|
|
4
|
-
|
5
|
-
hex32
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
module SecureRandom
|
5
|
+
def self.format_uuid hex32
|
6
|
+
hex32.sub(
|
7
|
+
@@format_pattern ||= /(........)(....)(....)(....)(............)/,
|
8
|
+
@@format_string ||= '\1-\2-\3-\4-\5'
|
9
|
+
)
|
10
|
+
end
|
9
11
|
end
|
10
12
|
|
11
13
|
unless defined? SecureRandom.uuid
|
@@ -26,6 +26,10 @@ module ActiveFacts
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def constellation_variable_name
|
30
|
+
@@constellation_variable_name ||= "@constellation"
|
31
|
+
end
|
32
|
+
|
29
33
|
def is_a? klass
|
30
34
|
super || self.class.supertypes_transitive.include?(klass)
|
31
35
|
end
|
@@ -77,14 +81,14 @@ module ActiveFacts
|
|
77
81
|
# The counterpart roles get cleared automatically.
|
78
82
|
klasses = [self.class]+self.class.supertypes_transitive
|
79
83
|
|
80
|
-
|
84
|
+
key_by_type = {}
|
81
85
|
self.class.all_role_transitive.each do |_, role|
|
82
86
|
next unless role.counterpart and
|
83
87
|
role.unique and
|
84
88
|
!role.counterpart.unique and
|
85
89
|
counterpart = send(role.getter)
|
86
90
|
role_values = counterpart.send(role.counterpart.getter)
|
87
|
-
|
91
|
+
key_by_type[role.object_type] ||= identifying_role_values(role.object_type)
|
88
92
|
end
|
89
93
|
|
90
94
|
# Nullify the counterpart role of objects we identify first, before damaging our identifying_role_values:
|
@@ -124,7 +128,7 @@ module ActiveFacts
|
|
124
128
|
counterpart_instance.send(counterpart.setter, nil, false)
|
125
129
|
else
|
126
130
|
rv = counterpart_instance.send(role.counterpart.getter)
|
127
|
-
rv.delete_instance(self,
|
131
|
+
rv.delete_instance(self, key_by_type[role.object_type])
|
128
132
|
|
129
133
|
if (rv.empty? && !counterpart_instance.class.is_entity_type)
|
130
134
|
counterpart_instance.retract if counterpart_instance.plays_no_role
|
@@ -158,6 +162,10 @@ module ActiveFacts
|
|
158
162
|
module ClassMethods #:nodoc:
|
159
163
|
include ObjectType
|
160
164
|
# Add Instance class methods here
|
165
|
+
|
166
|
+
def constellation_variable_name
|
167
|
+
@@constellation_variable_name ||= "@constellation"
|
168
|
+
end
|
161
169
|
end
|
162
170
|
end
|
163
171
|
end
|
@@ -62,7 +62,9 @@ class Decimal < SimpleDelegator #:nodoc:
|
|
62
62
|
include ActiveFacts::API::SimpleDelegation
|
63
63
|
|
64
64
|
def delegate_new(v)
|
65
|
-
if
|
65
|
+
if RUBY_VERSION >= "3"
|
66
|
+
BigDecimal(v)
|
67
|
+
elsif v.is_a?(BigDecimal) || v.is_a?(Integer)
|
66
68
|
BigDecimal.new(v.to_s)
|
67
69
|
else
|
68
70
|
BigDecimal.new(v)
|
@@ -260,16 +260,16 @@ module ActiveFacts
|
|
260
260
|
|
261
261
|
if role.is_identifying and (options&CHECKED_IDENTIFYING_ROLE) == 0
|
262
262
|
check_identification_change_legality(role, value)
|
263
|
-
|
263
|
+
instance_index_updates = collect_instance_index_updates(role)
|
264
264
|
end
|
265
265
|
|
266
266
|
instance_variable_set(role.variable, value)
|
267
267
|
|
268
|
-
if
|
268
|
+
if instance_index_updates
|
269
269
|
@constellation.when_admitted do
|
270
270
|
# REVISIT: Consider whether we want to provide a way to find all instances
|
271
271
|
# playing/not playing this boolean role, analogous to true.all_thing_as_role_name...
|
272
|
-
|
272
|
+
apply_instance_index_updates(instance_index_updates) # Propagate dependent key changes
|
273
273
|
end
|
274
274
|
end
|
275
275
|
|
@@ -314,7 +314,7 @@ module ActiveFacts
|
|
314
314
|
check_identification_change_legality(role, value)
|
315
315
|
|
316
316
|
# puts "Starting to analyse impact of changing 1-1 #{role.inspect} to #{value.inspect}"
|
317
|
-
|
317
|
+
instance_index_updates = collect_instance_index_updates(role)
|
318
318
|
end
|
319
319
|
|
320
320
|
instance_variable_set(role_var, value)
|
@@ -328,7 +328,7 @@ module ActiveFacts
|
|
328
328
|
# Assign self to the new counterpart
|
329
329
|
value.send(role.counterpart.setter, self, options) if value && (options&SKIP_MUTUAL_PROPAGATION) == 0
|
330
330
|
|
331
|
-
|
331
|
+
apply_instance_index_updates(instance_index_updates) if instance_index_updates # Propagate dependent key changes
|
332
332
|
end
|
333
333
|
|
334
334
|
unless @constellation.loggers.empty? or options != 0
|
@@ -363,12 +363,12 @@ module ActiveFacts
|
|
363
363
|
check_identification_change_legality(role, value)
|
364
364
|
|
365
365
|
# puts "Starting to analyse impact of changing 1-N #{role.inspect} to #{value.inspect}"
|
366
|
-
|
366
|
+
instance_index_updates = collect_instance_index_updates(role)
|
367
367
|
end
|
368
368
|
|
369
369
|
if old and (options&SKIP_MUTUAL_PROPAGATION) == 0
|
370
370
|
old_role_values = old.send(getter = role.counterpart.getter)
|
371
|
-
old_key =
|
371
|
+
old_key = identifying_role_values(role.object_type)
|
372
372
|
end
|
373
373
|
|
374
374
|
instance_variable_set(role_var, value)
|
@@ -388,7 +388,7 @@ module ActiveFacts
|
|
388
388
|
rv.add_instance(self, identifying_role_values(role.object_type))
|
389
389
|
end
|
390
390
|
|
391
|
-
|
391
|
+
apply_instance_index_updates(instance_index_updates) if instance_index_updates # Propagate dependent key changes
|
392
392
|
end
|
393
393
|
|
394
394
|
unless @constellation.loggers.empty? or options != 0
|
@@ -11,6 +11,7 @@ module ActiveFacts
|
|
11
11
|
attr_accessor :role
|
12
12
|
attr_accessor :sort
|
13
13
|
attr_accessor :index_roles
|
14
|
+
|
14
15
|
def object_type
|
15
16
|
@role.object_type
|
16
17
|
end
|
@@ -21,7 +22,11 @@ module ActiveFacts
|
|
21
22
|
@sort = API::sorted
|
22
23
|
@excluded_role = excluded_role
|
23
24
|
@a = @sort ? RBTree.new : []
|
24
|
-
|
25
|
+
if @excluded_role
|
26
|
+
@index_roles = role.object_type.identifying_roles.dup
|
27
|
+
@index_roles.delete_at(@excluded_role)
|
28
|
+
@index_roles.freeze
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
32
|
def +(a)
|
@@ -68,17 +73,19 @@ module ActiveFacts
|
|
68
73
|
KeyArray.new(a)
|
69
74
|
end
|
70
75
|
|
76
|
+
# Return the full key for the object according to the object_type of this role
|
71
77
|
def index_values object
|
72
|
-
if @
|
73
|
-
@index_roles.map
|
78
|
+
if @excluded_role
|
79
|
+
@index_roles.map do |r|
|
74
80
|
role_value = object.send(r.name)
|
75
81
|
role_value.identifying_role_values((c = r.counterpart) ? c.object_type : role_value.class)
|
76
|
-
|
82
|
+
end
|
77
83
|
else
|
78
|
-
object.identifying_role_values
|
84
|
+
object.identifying_role_values(role.object_type)
|
79
85
|
end
|
80
86
|
end
|
81
87
|
|
88
|
+
# The key must include the excluded role, if any
|
82
89
|
def add_instance(value, key)
|
83
90
|
if @sort
|
84
91
|
# Exclude the excluded role, if any:
|
@@ -89,9 +96,12 @@ module ActiveFacts
|
|
89
96
|
end
|
90
97
|
end
|
91
98
|
|
99
|
+
# The key must include the excluded role, if any
|
92
100
|
def delete_instance(value, key)
|
93
101
|
if @sort
|
94
|
-
|
102
|
+
if key.size != role.object_type.identifying_roles.size
|
103
|
+
raise "Internal error: incorrectly-sized key #{key.inspect} to delete_instance"
|
104
|
+
end
|
95
105
|
(key = key.dup).delete_at(@excluded_role) if @excluded_role
|
96
106
|
deleted = @a.delete(form_key(key))
|
97
107
|
else
|
@@ -134,16 +144,16 @@ module ActiveFacts
|
|
134
144
|
def_single_delegator :@a, :empty?
|
135
145
|
def_single_delegator :@a, :include?
|
136
146
|
def_single_delegator :@a, :inject, 2
|
137
|
-
def_single_delegator :@a, :select, -
|
138
|
-
def_single_delegator :@a, :reject, -
|
147
|
+
def_single_delegator :@a, :select, -2, 1
|
148
|
+
def_single_delegator :@a, :reject, -2, 1
|
139
149
|
def_single_delegator :@a, :size
|
140
|
-
def_single_delegator :@a, :sort_by, -
|
150
|
+
def_single_delegator :@a, :sort_by, -2, 1
|
141
151
|
def_single_delegator :@a, :to_a
|
142
152
|
def_single_delegator :@a, :-
|
143
153
|
# These delegators allow a negative arity in RSpec because the tests test it (to make sure the code doesn't pass too many args)
|
144
|
-
def_single_delegator :@a, :each, *([-
|
154
|
+
def_single_delegator :@a, :each, *([-2, 1] + Array(defined?(::RSpec) ? -2 : nil))
|
145
155
|
def_single_delegator :@a, :detect, 1, *([-1, 1] + Array(defined?(::RSpec) ? -2 : nil))
|
146
|
-
def_single_delegator :@a, :map, -
|
156
|
+
def_single_delegator :@a, :map, -2, 1
|
147
157
|
end
|
148
158
|
end
|
149
159
|
end
|
@@ -17,7 +17,7 @@ module ActiveFacts
|
|
17
17
|
module ValueClass #:nodoc:
|
18
18
|
def value_type *args, &block #:nodoc:
|
19
19
|
# The inclusion of instance methods triggers ClassMethods to be included in the class too
|
20
|
-
include ActiveFacts::API::Value
|
20
|
+
include ::ActiveFacts::API::Value
|
21
21
|
value_type(*args, &block)
|
22
22
|
end
|
23
23
|
end
|
@@ -11,12 +11,6 @@ unless Object.const_defined?("Infinity")
|
|
11
11
|
Infinity = 1.0/0.0
|
12
12
|
end
|
13
13
|
|
14
|
-
class Symbol #:nodoc:
|
15
|
-
def to_proc
|
16
|
-
Proc.new{|*args| args.shift.__send__(self, *args)}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
14
|
class String #:nodoc:
|
21
15
|
# This may be overridden by a version from ActiveSupport. For our purposes, either will work.
|
22
16
|
def camelcase(first_letter = :upper)
|
@@ -155,7 +155,7 @@ module ActiveFacts
|
|
155
155
|
class << klass
|
156
156
|
def new_instance constellation, *args
|
157
157
|
instance = allocate
|
158
|
-
instance.instance_variable_set(
|
158
|
+
instance.instance_variable_set(constellation_variable_name, constellation)
|
159
159
|
instance.send(:initialize, *args)
|
160
160
|
instance
|
161
161
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activefacts-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.9.
|
4
|
+
version: 1.9.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clifford Heath
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbtree-pure
|
@@ -68,16 +68,16 @@ dependencies:
|
|
68
68
|
name: rake
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
|
-
- - "
|
71
|
+
- - ">="
|
72
72
|
- !ruby/object:Gem::Version
|
73
|
-
version: '10
|
73
|
+
version: '10'
|
74
74
|
type: :development
|
75
75
|
prerelease: false
|
76
76
|
version_requirements: !ruby/object:Gem::Requirement
|
77
77
|
requirements:
|
78
|
-
- - "
|
78
|
+
- - ">="
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version: '10
|
80
|
+
version: '10'
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: rspec
|
83
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,7 +139,7 @@ homepage: https://github.com/cjheath/activefacts-api
|
|
139
139
|
licenses:
|
140
140
|
- MIT
|
141
141
|
metadata: {}
|
142
|
-
post_install_message:
|
142
|
+
post_install_message:
|
143
143
|
rdoc_options: []
|
144
144
|
require_paths:
|
145
145
|
- lib
|
@@ -154,9 +154,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
154
|
- !ruby/object:Gem::Version
|
155
155
|
version: '0'
|
156
156
|
requirements: []
|
157
|
-
|
158
|
-
|
159
|
-
signing_key:
|
157
|
+
rubygems_version: 3.2.22
|
158
|
+
signing_key:
|
160
159
|
specification_version: 4
|
161
160
|
summary: A fact-based data model DSL and API
|
162
161
|
test_files: []
|