activefacts-compositions 1.9.6 → 1.9.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|