activefacts-compositions 1.9.6 → 1.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Rakefile +33 -0
- data/activefacts-compositions.gemspec +3 -3
- data/bin/schema_compositor +142 -85
- data/lib/activefacts/compositions/binary.rb +19 -15
- data/lib/activefacts/compositions/compositor.rb +126 -125
- data/lib/activefacts/compositions/constraints.rb +74 -54
- data/lib/activefacts/compositions/datavault.rb +545 -0
- data/lib/activefacts/compositions/names.rb +58 -58
- data/lib/activefacts/compositions/relational.rb +801 -692
- data/lib/activefacts/compositions/traits/rails.rb +180 -0
- data/lib/activefacts/compositions/version.rb +1 -1
- data/lib/activefacts/generator/doc/css/ldm.css +45 -0
- data/lib/activefacts/generator/doc/cwm.rb +764 -0
- data/lib/activefacts/generator/doc/glossary.rb +473 -0
- data/lib/activefacts/generator/doc/graphviz.rb +134 -0
- data/lib/activefacts/generator/doc/ldm.rb +698 -0
- data/lib/activefacts/generator/oo.rb +130 -124
- data/lib/activefacts/generator/rails/models.rb +237 -0
- data/lib/activefacts/generator/rails/schema.rb +273 -0
- data/lib/activefacts/generator/ruby.rb +75 -67
- data/lib/activefacts/generator/sql.rb +333 -351
- data/lib/activefacts/generator/sql/server.rb +100 -39
- data/lib/activefacts/generator/summary.rb +67 -59
- data/lib/activefacts/generator/validate.rb +19 -134
- metadata +18 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3f30aa198a18c360d4fee63de36a3764df7d799
|
4
|
+
data.tar.gz: 28db19dcd307a9ab3ab1e7a50fada7023651d6e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b179e371a8f8b47a308d5790c6a21e4dec2c490eb7bd76da9bab58a0c8ae201fbf50c27a6a6b882e3395a9118b75ab16568353e076a17be1fd5197c4b78ae2f
|
7
|
+
data.tar.gz: cb28e3eb273607b31fb7e55fa2e826a5cc965764345a4b80c8096531d33be0dc97e05b7103424b5afd9bee1bc68d7fb9d51341a87967909eba52eaddd1964ed7
|
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -21,3 +21,36 @@ task :bump do
|
|
21
21
|
)
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
desc "Display differences between expected and actual from the last test run"
|
26
|
+
task :actual do
|
27
|
+
system <<-END
|
28
|
+
for actual in `find spec -type d -name actual`
|
29
|
+
do
|
30
|
+
base=`dirname "$actual"`
|
31
|
+
files="`ls $base/actual/* 2>/dev/null`"
|
32
|
+
if [ x"$files" != x"" ]
|
33
|
+
then
|
34
|
+
echo "=================================== $base ==================================="
|
35
|
+
diff -rub $base/expected/ $base/actual |grep -v '^Only in .*expected'
|
36
|
+
fi
|
37
|
+
done
|
38
|
+
END
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Accept the last actual test output, making it expected for the next test run"
|
42
|
+
task :accept do
|
43
|
+
system <<-END
|
44
|
+
for actual_dir in `find spec -type d -name actual`
|
45
|
+
do
|
46
|
+
base=`dirname "$actual_dir"`
|
47
|
+
expected=`cd "$base/expected"; git ls-files`
|
48
|
+
actual=`cd "$base/actual"; ls $expected 2>/dev/null`
|
49
|
+
if [ x"$actual" != x"" ]
|
50
|
+
then
|
51
|
+
echo "Accepting $actual"
|
52
|
+
(cd "$base/actual"; mv $actual ../expected)
|
53
|
+
fi
|
54
|
+
done
|
55
|
+
END
|
56
|
+
end
|
@@ -19,14 +19,14 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_development_dependency "bundler", ">= 1.
|
22
|
+
spec.add_development_dependency "bundler", ">= 1.11"
|
23
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
24
|
spec.add_development_dependency "rspec", "~> 3.3"
|
25
25
|
|
26
26
|
spec.add_development_dependency "activefacts", "~> 1", ">= 1.8"
|
27
27
|
|
28
|
-
spec.add_runtime_dependency("activefacts-api", "~> 1", ">= 1.9.
|
29
|
-
spec.add_runtime_dependency("activefacts-metamodel", "~> 1", ">= 1.9.
|
28
|
+
spec.add_runtime_dependency("activefacts-api", "~> 1", ">= 1.9.11")
|
29
|
+
spec.add_runtime_dependency("activefacts-metamodel", "~> 1", ">= 1.9.10")
|
30
30
|
spec.add_runtime_dependency "tracing", "~> 2", ">= 2.0.6"
|
31
31
|
|
32
32
|
spec.add_runtime_dependency "activefacts-cql", "~> 1", ">= 1.8"
|
data/bin/schema_compositor
CHANGED
@@ -5,111 +5,168 @@
|
|
5
5
|
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
6
|
#
|
7
7
|
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
8
|
-
require 'bundler/setup' # Set up gems listed in the Gemfile.
|
9
8
|
$:.unshift File.dirname(File.expand_path(__FILE__))+"/../lib"
|
10
9
|
|
10
|
+
require 'pathname'
|
11
11
|
require 'activefacts/loadable'
|
12
12
|
require 'activefacts/metamodel'
|
13
13
|
require 'activefacts/compositions'
|
14
14
|
require 'activefacts/generator'
|
15
15
|
|
16
|
-
|
17
|
-
options
|
18
|
-
|
19
|
-
|
20
|
-
options[option.sub(/^-*/,'')] =
|
21
|
-
(value =~ /,/ ? value.split(',') : Array(value)).
|
22
|
-
inject({}){|h,s| k, v = s.split(/=/, 2); h[k] = v || true; h }
|
23
|
-
end
|
16
|
+
class SchemaCompositor
|
17
|
+
attr_reader :options
|
18
|
+
attr_reader :compositors
|
19
|
+
attr_reader :generators
|
24
20
|
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
puts "Can't load #{pathname}: #{e.class}: #{e.message} #{e.backtrace[0]}"
|
21
|
+
# Parse options into a hash, and values for each option into a hash
|
22
|
+
def initialize argv
|
23
|
+
@options = {}
|
24
|
+
while argv[0] =~ /^-/
|
25
|
+
option, value = argv.shift.split(/=/, 2)
|
26
|
+
@options[option.sub(/^-*/,'')] =
|
27
|
+
(value =~ /,/ ? value.split(',') : Array(value)).
|
28
|
+
inject({}){|h,s| k, v = s.split(/=/, 2); h[k] = v || true; h }
|
29
|
+
end
|
35
30
|
end
|
36
|
-
end
|
37
31
|
|
38
|
-
# Load and enumerate all available
|
39
|
-
|
40
|
-
Loadable.new(
|
41
|
-
enumerate.
|
42
|
-
select do |filename|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
32
|
+
# Load and enumerate all available modules in this path
|
33
|
+
def enumerate_available path
|
34
|
+
Loadable.new(path).
|
35
|
+
enumerate.
|
36
|
+
select do |filename|
|
37
|
+
begin
|
38
|
+
require(pathname = path+"/"+filename)
|
39
|
+
rescue LoadError => e
|
40
|
+
rescue Exception => e
|
41
|
+
$stderr.puts "Can't load #{pathname}: #{e.class}: #{e.message} #{e.backtrace[0]}"
|
42
|
+
end
|
43
|
+
end
|
48
44
|
end
|
49
|
-
end
|
50
45
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
46
|
+
def arrange_actions
|
47
|
+
# Arrange the requested compositors and generators:
|
48
|
+
@compositors = []
|
49
|
+
@generators = []
|
50
|
+
@options.clone.each do |option, mode|
|
51
|
+
if action = ActiveFacts::Compositions.compositors[option]
|
52
|
+
options.delete(option)
|
53
|
+
check_options(action, mode)
|
54
|
+
@compositors << [action, mode]
|
55
|
+
elsif action = ActiveFacts::Generators.generators[option]
|
56
|
+
options.delete(option)
|
57
|
+
check_options(action, mode)
|
58
|
+
@generators << [action, mode]
|
59
|
+
else
|
60
|
+
$stderr.puts "Action --#{option} is not recognised"
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
if mode && mode['help']
|
64
|
+
puts "Help for #{option} is not yet available"
|
65
|
+
end
|
66
|
+
end
|
70
67
|
end
|
71
|
-
end
|
72
68
|
|
73
|
-
|
74
|
-
|
75
|
-
|
69
|
+
def process_files argv
|
70
|
+
# Process each input file:
|
71
|
+
argv.each do |arg|
|
72
|
+
filename, input_options = *arg.split(/=/, 2)
|
76
73
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
74
|
+
# Load the correct file type input method
|
75
|
+
pathname, basename, extension = * /(?:(.*)[\/\\])?(.*)\.([^.]*)$/.match(filename).captures
|
76
|
+
input_handler = "activefacts/input/#{extension}"
|
77
|
+
require input_handler
|
81
78
|
|
82
|
-
|
83
|
-
|
84
|
-
|
79
|
+
input_class = extension.upcase
|
80
|
+
input_klass = ActiveFacts::Input.const_get(input_class.to_sym)
|
81
|
+
raise "Expected #{input_handler} to define #{input_class}" unless input_klass
|
85
82
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
83
|
+
# Read the input file:
|
84
|
+
vocabulary =
|
85
|
+
if input_klass
|
86
|
+
begin
|
87
|
+
input_klass.readfile(filename, *input_options)
|
88
|
+
rescue => e
|
89
|
+
$stderr.puts "#{e.message}"
|
90
|
+
if trace :exception
|
91
|
+
$stderr.puts "\t#{e.backtrace*"\n\t"}"
|
92
|
+
else
|
93
|
+
$stderr.puts "\t#{e.backtrace[0]}"
|
94
|
+
end
|
95
|
+
exit 1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
exit 0 unless vocabulary
|
99
|
+
vocabulary.finalise unless vocabulary == true
|
100
|
+
|
101
|
+
# Run each compositor
|
102
|
+
@compositors.each do |compositor_klass, mode|
|
103
|
+
compositor = compositor_klass.new(vocabulary.constellation, basename, mode||{})
|
104
|
+
compositor.generate
|
105
|
+
|
106
|
+
# Run each generator
|
107
|
+
@generators.each do |generator, mode|
|
108
|
+
output = generator.new(compositor.composition, mode||{}).generate
|
109
|
+
puts output if output
|
97
110
|
end
|
98
|
-
exit 1
|
99
111
|
end
|
100
112
|
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
+
end
|
114
|
+
|
115
|
+
def action_name action
|
116
|
+
action.name.sub(/ActiveFacts::[^:]+::/,'').gsub(/::/,'/').downcase
|
117
|
+
end
|
118
|
+
|
119
|
+
def display_options action, stream = $stdout
|
120
|
+
options = action.options
|
121
|
+
name = action.name.sub(/ActiveFacts::[^:]+::/,'').gsub(/::/,'/').downcase
|
122
|
+
if options.empty?
|
123
|
+
stream.puts "There are no options for --#{action_name action}"
|
124
|
+
else
|
125
|
+
stream.puts "Options for --#{name} (say e.g. --#{action_name action}=option1=value,option2)"
|
126
|
+
options.keys.sort.each do |key|
|
127
|
+
type, description = *options[key]
|
128
|
+
tag =
|
129
|
+
key.to_s +
|
130
|
+
case type
|
131
|
+
when NilClass,'Boolean', TrueClass
|
132
|
+
''
|
133
|
+
when Numeric
|
134
|
+
' num'
|
135
|
+
when Pathname
|
136
|
+
' file'
|
137
|
+
else
|
138
|
+
' str'
|
139
|
+
end
|
140
|
+
|
141
|
+
stream.puts "\t#{tag}#{' '*(24-tag.size)}#{description}"
|
142
|
+
end
|
113
143
|
end
|
114
144
|
end
|
145
|
+
|
146
|
+
# Ensure that the options provided are supported by the action
|
147
|
+
def check_options action, mode
|
148
|
+
if mode['help']
|
149
|
+
display_options(action)
|
150
|
+
exit
|
151
|
+
end
|
152
|
+
options = action.options
|
153
|
+
unsupported = mode.keys.select{|k| !options.has_key?(k.to_sym)}
|
154
|
+
return if unsupported.empty?
|
155
|
+
$stderr.puts "Action --#{action_name action} does not support #{unsupported.size >1 ? 'these options' : 'this option'}: #{unsupported*', '}"
|
156
|
+
display_options(action, $stderr)
|
157
|
+
exit 1
|
158
|
+
end
|
115
159
|
end
|
160
|
+
|
161
|
+
sc = SchemaCompositor.new(ARGV)
|
162
|
+
sc.enumerate_available('activefacts/compositions')
|
163
|
+
sc.enumerate_available('activefacts/generator')
|
164
|
+
if sc.options['help']
|
165
|
+
puts "Available compositors:\n\t#{ActiveFacts::Compositions.compositors.keys.sort*"\n\t"}\n\n"
|
166
|
+
puts "Available generators:\n\t#{ActiveFacts::Generators.generators.keys.sort*"\n\t"}\n\n"
|
167
|
+
puts "To get help for a particular action, follow it by =help, e.g. --relational=help"
|
168
|
+
exit
|
169
|
+
end
|
170
|
+
|
171
|
+
sc.arrange_actions
|
172
|
+
sc.process_files ARGV
|
@@ -1,7 +1,7 @@
|
|
1
1
|
### Composition
|
2
2
|
# ActiveFacts Compositions, Binary Compositor.
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# Fans of RDF will like this one.
|
5
5
|
#
|
6
6
|
# Copyright (c) 2015 Clifford Heath. Read the LICENSE file.
|
7
7
|
#
|
@@ -10,23 +10,27 @@ require "activefacts/compositions"
|
|
10
10
|
module ActiveFacts
|
11
11
|
module Compositions
|
12
12
|
class Binary < Compositor
|
13
|
+
def self.options
|
14
|
+
{}
|
15
|
+
end
|
16
|
+
|
13
17
|
def generate
|
14
|
-
|
18
|
+
super
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
trace :binary!, "Constructing Binary Composition" do
|
21
|
+
@binary_mappings.keys.sort_by(&:name).each do |object_type|
|
22
|
+
mapping = @binary_mappings[object_type]
|
23
|
+
mapping.re_rank
|
24
|
+
composite = @constellation.Composite(mapping, composition: @composition)
|
25
|
+
end
|
26
|
+
end
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
trace :binary!, "Full binary composition" do
|
29
|
+
@binary_mappings.keys.sort_by(&:name).each do |object_type|
|
30
|
+
mapping = @binary_mappings[object_type]
|
31
|
+
mapping.show_trace
|
32
|
+
end
|
33
|
+
end
|
30
34
|
|
31
35
|
end
|
32
36
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
#
|
2
2
|
# ActiveFacts Compositions, Fundamental Compositor
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# All Compositors derive from this one, which can calculate the basic binary bi-directional mapping
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# The term "reference" used here means either an Absorption
|
7
|
+
# (one direction of a binary fact type relating two object types),
|
8
|
+
# or an Indicator (for a unary fact type).
|
9
9
|
#
|
10
|
-
#
|
10
|
+
# n-ary fact types and other objectified fact types are factored out by using the associated LinkFactTypes.
|
11
11
|
#
|
12
12
|
# Copyright (c) 2015 Clifford Heath. Read the LICENSE file.
|
13
13
|
#
|
@@ -15,141 +15,142 @@ require "activefacts/metamodel"
|
|
15
15
|
|
16
16
|
module ActiveFacts
|
17
17
|
module Compositions
|
18
|
-
private
|
19
|
-
MM = ActiveFacts::Metamodel
|
20
18
|
class Compositor
|
21
19
|
attr_reader :options, :name, :composition
|
22
20
|
|
21
|
+
def self.options
|
22
|
+
{}
|
23
|
+
end
|
24
|
+
|
23
25
|
def initialize constellation, name, options = {}
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
$stderr.puts "Unknown options: #{options.inspect}" unless options.empty?
|
26
|
+
@constellation = constellation
|
27
|
+
@name = name
|
28
|
+
@options = options
|
28
29
|
end
|
29
30
|
|
30
31
|
# Generate all Mappings into @binary_mappings for a binary composition of all ObjectTypes in this constellation
|
31
32
|
def generate
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
33
|
+
# Retract an existing composition by this name
|
34
|
+
if existing = @constellation.Name[[@name]] and
|
35
|
+
@composition = existing.composition
|
36
|
+
@composition.all_composite.to_a.each{|composite| composite.retract}
|
37
|
+
@composition.retract
|
38
|
+
end
|
39
|
+
|
40
|
+
@composition = @constellation.Composition(:new, :name => @name)
|
41
|
+
preload_preferred_identifiers
|
42
|
+
populate_references
|
42
43
|
end
|
43
44
|
|
44
45
|
private
|
45
46
|
# Preferred identifiers are cached, but the process produces trace output
|
46
47
|
# that appears in the "tutti" mode used in testing. This precludes that.
|
47
48
|
def preload_preferred_identifiers
|
48
|
-
|
49
|
+
@constellation.EntityType.map{|k, et| et.preferred_identifier }
|
49
50
|
end
|
50
51
|
|
51
52
|
def populate_reference object_type, role
|
52
|
-
|
53
|
-
|
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
|
-
|
53
|
+
parent = @binary_mappings[role.object_type]
|
54
|
+
|
55
|
+
return if role.fact_type.all_role.size > 2
|
56
|
+
if role.fact_type.all_role.size != 1
|
57
|
+
counterpart = role.counterpart
|
58
|
+
rt = role_type(counterpart)
|
59
|
+
if rt == :many_many
|
60
|
+
raise "Fact type must be objectified: #{role.fact_type.default_reading}"
|
61
|
+
end
|
62
|
+
|
63
|
+
a = @constellation.Absorption(
|
64
|
+
:new,
|
65
|
+
name: role_name(counterpart),
|
66
|
+
parent: parent,
|
67
|
+
object_type: counterpart.object_type,
|
68
|
+
parent_role: role,
|
69
|
+
child_role: counterpart
|
70
|
+
)
|
71
|
+
# Populate the absorption/reverse_absorption (putting the "many" or optional side as reverse)
|
72
|
+
if r = @component_by_fact[role.fact_type]
|
73
|
+
# Second occurrence of this fact type, set the direction:
|
74
|
+
if a.is_preferred_direction
|
75
|
+
a.reverse_absorption = r
|
76
|
+
else # Set this as the reverse absorption
|
77
|
+
a.forward_absorption = r
|
78
|
+
end
|
79
|
+
else
|
80
|
+
# First occurrence of this fact type
|
81
|
+
@component_by_fact[role.fact_type] = a
|
82
|
+
end
|
83
|
+
else # It's an indicator
|
84
|
+
a = @constellation.Indicator(
|
85
|
+
:new,
|
86
|
+
name: role.name,
|
87
|
+
parent: parent,
|
88
|
+
role: role
|
89
|
+
)
|
90
|
+
@component_by_fact[role.fact_type] = a # For completeness, in case a subclass uses it
|
91
|
+
end
|
92
|
+
trace :binarize, "Populating #{a.inspect}"
|
92
93
|
end
|
93
94
|
|
94
95
|
def populate_references
|
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
|
-
|
96
|
+
# A table of Mappings by object type, with a default Mapping for each:
|
97
|
+
@binary_mappings = Hash.new do |h, object_type|
|
98
|
+
h[object_type] = @constellation.Mapping(
|
99
|
+
:new,
|
100
|
+
name: object_type.name,
|
101
|
+
object_type: object_type
|
102
|
+
)
|
103
|
+
end
|
104
|
+
@component_by_fact = {}
|
105
|
+
|
106
|
+
@constellation.ObjectType.each do |key, object_type|
|
107
|
+
trace :binarize, "Populating possible absorptions for #{object_type.name}" do
|
108
|
+
@binary_mappings[object_type] # Ensure we create the top Mapping even if it has no references
|
109
|
+
|
110
|
+
object_type.all_role.each do |role|
|
111
|
+
# Exclude base roles in objectified fact types (unless unary); just use link fact types
|
112
|
+
next if role.fact_type.entity_type && role.fact_type.all_role.size != 1
|
113
|
+
next if role.variable # REVISIT: Continue to ignore roles in derived fact types?
|
114
|
+
populate_reference object_type, role
|
115
|
+
end
|
116
|
+
if object_type.is_a?(ActiveFacts::Metamodel::ValueType)
|
117
|
+
# This requires a change in the metamodel to use TypeInheritance for ValueTypes
|
118
|
+
if object_type.supertype
|
119
|
+
trace :binarize, "REVISIT: Eliding supertype #{object_type.supertype.name} for #{object_type.name}"
|
120
|
+
end
|
121
|
+
object_type.all_value_type_as_supertype.each do |subtype|
|
122
|
+
trace :binarize, "REVISIT: Eliding subtype #{subtype.name} for #{object_type.name}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
126
127
|
end
|
127
128
|
|
128
129
|
def role_name role
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
|
133
|
-
|
130
|
+
# if role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) && role == role.fact_type.subtype_role
|
131
|
+
# return "Is "+role.object_type.name
|
132
|
+
# end
|
133
|
+
role = role.base_role unless role.base_role.fact_type.all_role.size == 1
|
134
|
+
String::Words.new(role.preferred_reference.role_name(nil)).capwords*' '
|
134
135
|
end
|
135
136
|
|
136
137
|
def role_type role
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
138
|
+
fact_type = role.fact_type
|
139
|
+
if fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
140
|
+
return role.object_type == fact_type.supertype ? :supertype : :subtype
|
141
|
+
end
|
142
|
+
|
143
|
+
return :unary if fact_type.all_role.size == 1
|
144
|
+
|
145
|
+
if fact_type.is_a?(ActiveFacts::Metamodel::LinkFactType)
|
146
|
+
# Prevent an unnecessary from-1 search:
|
147
|
+
from_1 = true
|
148
|
+
# Change the to_1 search to detect a one-to-one:
|
149
|
+
role = fact_type.implying_role
|
150
|
+
fact_type = role.fact_type
|
151
|
+
end
|
152
|
+
|
153
|
+
# List the UCs on this fact type:
|
153
154
|
all_uniqueness_constraints =
|
154
155
|
fact_type.all_role.map do |fact_role|
|
155
156
|
fact_role.all_role_ref.map do |rr|
|
@@ -159,7 +160,7 @@ module ActiveFacts
|
|
159
160
|
end
|
160
161
|
end.flatten.uniq
|
161
162
|
|
162
|
-
|
163
|
+
# It's to-1 if a UC exists over exactly this role:
|
163
164
|
to_1 =
|
164
165
|
all_uniqueness_constraints.
|
165
166
|
detect do |c|
|
@@ -186,16 +187,16 @@ module ActiveFacts
|
|
186
187
|
|
187
188
|
# Display the primitive binary mapping:
|
188
189
|
def show_references
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
190
|
+
trace :composition, "Displaying the mappings:" do
|
191
|
+
@binary_mappings.keys.sort_by(&:name).each do |object_type|
|
192
|
+
mapping = @binary_mappings[object_type]
|
193
|
+
trace :composition, "#{object_type.name}" do
|
194
|
+
mapping.all_member.each do |component|
|
195
|
+
trace :composition, component.inspect
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
199
200
|
end
|
200
201
|
|
201
202
|
end
|