activefacts-generators 1.8.3 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/activefacts-generators.gemspec +3 -3
- data/lib/activefacts/dependency_analyser.rb +80 -80
- data/lib/activefacts/generators/absorption.rb +1 -1
- data/lib/activefacts/generators/composition.rb +76 -76
- data/lib/activefacts/generators/cql.rb +73 -73
- data/lib/activefacts/generators/diagrams/json.rb +313 -313
- data/lib/activefacts/generators/help.rb +10 -10
- data/lib/activefacts/generators/helpers/inject.rb +5 -5
- data/lib/activefacts/generators/helpers/oo.rb +5 -5
- data/lib/activefacts/generators/helpers/ordered.rb +51 -51
- data/lib/activefacts/generators/html/glossary.rb +241 -241
- data/lib/activefacts/generators/metadata/json.rb +155 -155
- data/lib/activefacts/generators/ruby.rb +4 -4
- data/lib/activefacts/generators/scala.rb +48 -48
- data/lib/activefacts/generators/sql/server.rb +3 -3
- data/lib/activefacts/generators/stats.rb +37 -37
- data/lib/activefacts/generators/traits/datavault.rb +217 -217
- data/lib/activefacts/generators/traits/oo.rb +13 -13
- data/lib/activefacts/generators/traits/ordered.rb +8 -8
- data/lib/activefacts/generators/traits/ruby.rb +145 -145
- data/lib/activefacts/generators/traits/scala.rb +319 -319
- data/lib/activefacts/generators/transform/datavault.rb +282 -282
- metadata +6 -12
@@ -8,23 +8,23 @@ module ActiveFacts
|
|
8
8
|
module Generators
|
9
9
|
module OOTraits
|
10
10
|
module ObjectType
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
# Map the ObjectType name to an OO class name
|
12
|
+
def oo_type_name
|
13
|
+
name.words.capcase
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
# Map the OO class name to a default role name
|
17
|
+
def oo_default_role_name
|
18
18
|
name.words.snakecase
|
19
|
-
|
19
|
+
end
|
20
20
|
end
|
21
21
|
|
22
22
|
module Role
|
23
|
-
|
23
|
+
def oo_role_definition
|
24
24
|
return if fact_type.entity_type
|
25
25
|
|
26
26
|
if fact_type.all_role.size == 1
|
27
|
-
|
27
|
+
return " maybe :#{preferred_role_name}\n"
|
28
28
|
elsif fact_type.all_role.size != 2
|
29
29
|
# Shouldn't come here, except perhaps for an invalid model
|
30
30
|
return # ternaries and higher are always objectified
|
@@ -55,8 +55,8 @@ module ActiveFacts
|
|
55
55
|
counterpart_role_method = one_to_one ? role_method : "all_"+role_method
|
56
56
|
# puts "---"+role.role_name if role.role_name
|
57
57
|
if counterpart_role_name != counterpart_type.oo_default_role_name and
|
58
|
-
|
59
|
-
#
|
58
|
+
role_method == self.object_type.oo_default_role_name
|
59
|
+
# debugger
|
60
60
|
counterpart_role_method += "_as_#{counterpart_role_name}"
|
61
61
|
end
|
62
62
|
|
@@ -64,10 +64,10 @@ module ActiveFacts
|
|
64
64
|
role_name = nil if role_name == object_type.oo_default_role_name
|
65
65
|
|
66
66
|
as_binary(counterpart_role_name, counterpart_type, is_mandatory, one_to_one, nil, role_name, counterpart_role_method)
|
67
|
-
|
67
|
+
end
|
68
68
|
end
|
69
69
|
|
70
|
-
include ActiveFacts::TraitInjector
|
70
|
+
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
@@ -8,26 +8,26 @@ module ActiveFacts
|
|
8
8
|
module Generators #:nodoc:
|
9
9
|
module OrderedTraits
|
10
10
|
module DumpedFlag
|
11
|
-
|
11
|
+
attr_reader :ordered_dumped
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
def ordered_dumped!
|
14
|
+
@ordered_dumped = true
|
15
|
+
end
|
16
16
|
end
|
17
17
|
|
18
18
|
module ObjectType
|
19
|
-
|
19
|
+
include DumpedFlag
|
20
20
|
end
|
21
21
|
|
22
22
|
module FactType
|
23
|
-
|
23
|
+
include DumpedFlag
|
24
24
|
end
|
25
25
|
|
26
26
|
module Constraint
|
27
|
-
|
27
|
+
include DumpedFlag
|
28
28
|
end
|
29
29
|
|
30
|
-
include ActiveFacts::TraitInjector
|
30
|
+
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -8,24 +8,24 @@ module ActiveFacts
|
|
8
8
|
module Generators
|
9
9
|
module RubyTraits
|
10
10
|
module Vocabulary
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
11
|
+
def prelude
|
12
|
+
if @mapping == 'sql'
|
13
|
+
require 'activefacts/rmap'
|
14
|
+
@tables = self.tables
|
15
|
+
end
|
16
|
+
|
17
|
+
"require 'activefacts/api'\n" +
|
18
|
+
(@mapping == 'sql' ? "require 'activefacts/rmap'\n" : '') +
|
19
|
+
"\nmodule ::#{self.name.words.capcase}\n\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
def finale
|
23
|
+
"end"
|
24
|
+
end
|
25
25
|
end
|
26
26
|
|
27
27
|
module ObjectType
|
28
|
-
|
28
|
+
def absorbed_roles
|
29
29
|
all_role.
|
30
30
|
select do |role|
|
31
31
|
role.fact_type.all_role.size <= 2 &&
|
@@ -33,41 +33,41 @@ module ActiveFacts
|
|
33
33
|
end.
|
34
34
|
sort_by do |role|
|
35
35
|
r = role.fact_type.all_role.select{|r2| r2 != role}[0] || role
|
36
|
-
|
36
|
+
r.preferred_role_name(self) + ':' + role.preferred_role_name(r.object_type)
|
37
37
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
38
|
+
end
|
39
|
+
|
40
|
+
# Map the ObjectType name to a Ruby class name
|
41
|
+
def ruby_type_name
|
42
|
+
oo_type_name
|
43
|
+
end
|
44
|
+
|
45
|
+
# Map the Ruby class name to a default role name
|
46
|
+
def ruby_default_role_name
|
47
|
+
oo_default_role_name
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def ruby_type_reference
|
52
|
+
if !ordered_dumped
|
53
|
+
'"'+name.gsub(/ /,'')+'"'
|
54
|
+
else
|
55
|
+
role_reference = name.gsub(/ /,'')
|
56
|
+
end
|
57
|
+
end
|
58
58
|
end
|
59
59
|
|
60
60
|
module Role
|
61
61
|
def preferred_role_name(is_for = nil, &name_builder)
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
if fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
64
|
+
# Subtype and Supertype roles default to TitleCase names, and have no role_name to worry about:
|
65
|
+
return (name_builder || proc {|names| names.titlecase}).call(object_type.name.words)
|
66
|
+
end
|
67
67
|
|
68
|
-
|
68
|
+
name_builder ||= proc {|names| names.map(&:downcase)*'_' } # Make snake_case by default
|
69
69
|
|
70
|
-
|
70
|
+
# Handle an objectified unary role:
|
71
71
|
if is_for && fact_type.entity_type == is_for && fact_type.all_role.size == 1
|
72
72
|
return name_builder.call(object_type.name.words)
|
73
73
|
end
|
@@ -80,131 +80,131 @@ module ActiveFacts
|
|
80
80
|
|
81
81
|
if fact_type.all_role.size == 1
|
82
82
|
return name_builder.call(
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
role_name ?
|
84
|
+
role_name.words.snakewords :
|
85
|
+
reading.text.gsub(/ *\{0\} */,' ').gsub(/[- ]+/,'_').words
|
86
|
+
)
|
87
87
|
end
|
88
88
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
if role_name && role_name != ""
|
90
|
+
role_words = [role_name]
|
91
|
+
else
|
92
|
+
role_words = []
|
93
93
|
|
94
|
-
|
95
|
-
|
94
|
+
la = preferred_role_ref.leading_adjective
|
95
|
+
role_words += la.words.snakewords if la && la != ""
|
96
96
|
|
97
|
-
|
97
|
+
role_words += object_type.name.words.snakewords
|
98
98
|
|
99
|
-
|
100
|
-
|
101
|
-
|
99
|
+
ta = preferred_role_ref.trailing_adjective
|
100
|
+
role_words += ta.words.snakewords if ta && ta != ""
|
101
|
+
end
|
102
102
|
|
103
103
|
# n = role_words.map{|w| w.gsub(/([a-z])([A-Z]+)/,'\1_\2').downcase}*"_"
|
104
|
-
|
104
|
+
n = role_words*'_'
|
105
105
|
# trace "\tresult=#{n}"
|
106
106
|
return name_builder.call(n.gsub(' ','_').split(/_/))
|
107
107
|
end
|
108
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
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
109
|
+
def as_binary(role_name, role_player, mandatory = nil, one_to_one = nil, readings = nil, other_role_name = nil, other_method_name = nil)
|
110
|
+
ruby_role_name = ":"+role_name.words.snakecase
|
111
|
+
|
112
|
+
# Find whether we need the name of the other role player, and whether it's defined yet:
|
113
|
+
implied_role_name = role_player.name.gsub(/ /,'').sub(/^[a-z]/) {|i| i.upcase}
|
114
|
+
if role_name.camelcase != implied_role_name
|
115
|
+
# Only use Class name if it's not implied by the rolename
|
116
|
+
role_reference = ":class => "+role_player.ruby_type_reference
|
117
|
+
end
|
118
|
+
|
119
|
+
other_role_name = ":counterpart => :"+other_role_name.gsub(/ /,'_') if other_role_name
|
120
|
+
|
121
|
+
if vr = role_value_constraint
|
122
|
+
value_restriction = ":restrict => #{vr}"
|
123
|
+
end
|
124
|
+
|
125
|
+
options = [
|
126
|
+
ruby_role_name,
|
127
|
+
role_reference,
|
128
|
+
mandatory ? ":mandatory => true" : nil,
|
129
|
+
readings,
|
130
|
+
other_role_name,
|
131
|
+
value_restriction
|
132
|
+
].compact
|
133
|
+
|
134
|
+
debugger if ruby_role_name == 'astronomicalobject'
|
135
|
+
|
136
|
+
line = " #{one_to_one ? "one_to_one" : "has_one" } #{options*', '} "
|
137
|
+
if other_method_name
|
138
|
+
line += " "*(48-line.length) if line.length < 48
|
139
|
+
line += "\# See #{role_player.name.gsub(/ /,'')}.#{other_method_name}"
|
140
|
+
end
|
141
|
+
line+"\n"
|
142
|
+
end
|
143
|
+
|
144
|
+
def ruby_role_definition
|
145
|
+
oo_role_definition
|
146
|
+
end
|
147
147
|
end
|
148
148
|
|
149
149
|
module ValueType
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
150
|
+
def ruby_definition
|
151
|
+
return if name == "_ImplicitBooleanValueType"
|
152
|
+
|
153
|
+
ruby_length = length && length > 0 ? ":length => #{length}" : nil
|
154
|
+
ruby_scale = scale && scale > 0 ? ":scale => #{scale}" : nil
|
155
|
+
params = [ruby_length,ruby_scale].compact * ", "
|
156
|
+
|
157
|
+
base_type = supertype || self
|
158
|
+
base_type_name = base_type.ruby_type_name
|
159
|
+
ruby_name = ruby_type_name
|
160
|
+
if base_type_name == ruby_name
|
161
|
+
base_type_name = '::'+base_type_name
|
162
|
+
end
|
163
|
+
|
164
|
+
" class #{ruby_name} < #{base_type_name}\n" +
|
165
|
+
" value_type #{params}\n" +
|
166
|
+
#emit_mapping self if is_table
|
167
|
+
(value_constraint ?
|
168
|
+
" restrict #{value_constraint.all_allowed_range_sorted.map{|ar| ar.to_s}*", "}\n" :
|
169
|
+
""
|
170
|
+
) +
|
171
|
+
(unit ?
|
172
|
+
" \# REVISIT: #{ruby_name} is in units of #{unit.name}\n" :
|
173
|
+
""
|
174
|
+
) +
|
175
|
+
absorbed_roles.map do |role|
|
176
|
+
role.ruby_role_definition
|
177
|
+
end.
|
178
|
+
compact*"" +
|
179
|
+
" end\n\n"
|
180
|
+
end
|
181
181
|
end
|
182
182
|
|
183
183
|
module FactType
|
184
184
|
# An objectified fact type has internal roles that are always "has_one":
|
185
185
|
def fact_roles
|
186
|
-
|
186
|
+
raise "Fact #{describe} type is not objectified" unless entity_type
|
187
187
|
all_role.sort_by do |role|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
188
|
+
role.preferred_role_name(entity_type)
|
189
|
+
end.
|
190
|
+
map do |role|
|
191
|
+
role_name = role.preferred_role_name(entity_type)
|
192
|
+
one_to_one = role.all_role_ref.detect{|rr|
|
193
|
+
rr.role_sequence.all_role_ref.size == 1 &&
|
194
|
+
rr.role_sequence.all_presence_constraint.detect{|pc|
|
195
|
+
pc.max_frequency == 1
|
196
|
+
}
|
197
|
+
}
|
198
|
+
counterpart_role_method = (one_to_one ? "" : "all_") +
|
199
|
+
entity_type.oo_default_role_name +
|
200
|
+
(role_name != role.object_type.oo_default_role_name ? "_as_#{role_name}" : '')
|
201
|
+
role.as_binary(role_name, role.object_type, true, one_to_one, nil, nil, counterpart_role_method)
|
202
|
+
end.
|
203
|
+
join('')
|
204
|
+
end
|
205
205
|
end
|
206
206
|
|
207
|
-
include ActiveFacts::TraitInjector
|
207
|
+
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
208
208
|
end
|
209
209
|
end
|
210
210
|
end
|
@@ -9,43 +9,43 @@ module ActiveFacts
|
|
9
9
|
module Generators
|
10
10
|
module ScalaTraits
|
11
11
|
module Vocabulary
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
12
|
+
def scala_prelude
|
13
|
+
title_name = name.words.titlecase
|
14
|
+
|
15
|
+
"package model\n"+
|
16
|
+
"\n"+
|
17
|
+
"import scala.language.implicitConversions\n" +
|
18
|
+
"\n" +
|
19
|
+
"object #{title_name} extends LocalStorageConstellation with #{title_name}\n" +
|
20
|
+
"\n" +
|
21
|
+
"trait #{title_name} extends Model {\n" +
|
22
|
+
# REVISIT: I think this next line should be model, not metaModel
|
23
|
+
" val metaModel = new #{title_name}Model()\n" +
|
24
|
+
"\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
def scala_prelude_metamodel
|
28
|
+
title_name = name.words.titlecase
|
29
|
+
"class #{title_name}Model extends FBMModel with LocalStorageConstellation {\n" +
|
30
|
+
" implicit val constellation: Constellation = this\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
def scala_finale
|
34
|
+
"}\n"+
|
35
|
+
"\n"
|
36
|
+
end
|
37
37
|
end
|
38
38
|
|
39
39
|
module ObjectType
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
# Map the ObjectType name to a Scala class name
|
41
|
+
def scala_type_name
|
42
|
+
oo_type_name
|
43
|
+
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
# Map the Scala class name to a default role name
|
46
|
+
def scala_default_role_name
|
47
|
+
oo_default_role_name
|
48
|
+
end
|
49
49
|
|
50
50
|
def absorbed_roles
|
51
51
|
all_role.
|
@@ -62,16 +62,16 @@ module ActiveFacts
|
|
62
62
|
|
63
63
|
module Role
|
64
64
|
def scala_preferred_role_name(is_for = nil, &name_builder)
|
65
|
-
|
65
|
+
# REVISIT: Modify this to suit Scala
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
if fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
68
|
+
# Subtype and Supertype roles default to TitleCase names, and have no role_name to worry about:
|
69
|
+
return (name_builder || proc {|names| names.titlecase}).call(object_type.name.words)
|
70
|
+
end
|
71
71
|
|
72
|
-
|
72
|
+
name_builder ||= proc {|names| names.map(&:downcase)*'_' } # Make snake_case by default
|
73
73
|
|
74
|
-
|
74
|
+
# Handle an objectified unary role:
|
75
75
|
if is_for && fact_type.entity_type == is_for && fact_type.all_role.size == 1
|
76
76
|
return name_builder.call(object_type.name.words)
|
77
77
|
end
|
@@ -84,304 +84,304 @@ module ActiveFacts
|
|
84
84
|
|
85
85
|
if fact_type.all_role.size == 1
|
86
86
|
return name_builder.call(
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
role_name ?
|
88
|
+
role_name.snakewords :
|
89
|
+
reading.text.gsub(/ *\{0\} */,' ').gsub(/[- ]+/,'_').words
|
90
|
+
)
|
91
91
|
end
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
if role_name && role_name != ""
|
94
|
+
role_words = [role_name]
|
95
|
+
else
|
96
|
+
role_words = []
|
97
97
|
|
98
|
-
|
99
|
-
|
98
|
+
la = preferred_role_ref.leading_adjective
|
99
|
+
role_words += la.words.snakewords if la && la != ""
|
100
100
|
|
101
|
-
|
101
|
+
role_words += object_type.name.words.snakewords
|
102
102
|
|
103
|
-
|
104
|
-
|
105
|
-
|
103
|
+
ta = preferred_role_ref.trailing_adjective
|
104
|
+
role_words += ta.words.snakewords if ta && ta != ""
|
105
|
+
end
|
106
106
|
|
107
107
|
# n = role_words.map{|w| w.gsub(/([a-z])([A-Z]+)/,'\1_\2').downcase}*"_"
|
108
|
-
|
108
|
+
n = role_words*'_'
|
109
109
|
# trace "\tresult=#{n}"
|
110
110
|
return name_builder.call(n.gsub(' ','_').split(/_/))
|
111
111
|
end
|
112
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
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
113
|
+
def scala_role_definition
|
114
|
+
return if fact_type.entity_type
|
115
|
+
|
116
|
+
if fact_type.all_role.size == 1
|
117
|
+
scala_role_name = scala_preferred_role_name.words.camelcase
|
118
|
+
return " val #{scala_role_name}: Boolean"
|
119
|
+
elsif fact_type.all_role.size != 2
|
120
|
+
# Shouldn't come here, except perhaps for an invalid model
|
121
|
+
return # ternaries and higher are always objectified
|
122
|
+
end
|
123
|
+
|
124
|
+
return if fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
125
|
+
|
126
|
+
other_role = fact_type.all_role.select{|r| r != self}[0]
|
127
|
+
other_role_name = other_role.scala_preferred_role_name
|
128
|
+
scala_role_name = other_role_name.words.camelcase
|
129
|
+
other_type_name = other_role.object_type.name.words.titlecase
|
130
|
+
|
131
|
+
if is_functional
|
132
|
+
if is_mandatory
|
133
|
+
# Define a getter for a mandatory value:
|
134
|
+
" val #{scala_role_name}: #{other_type_name}"
|
135
|
+
if !fact_type.is_existential
|
136
|
+
" def #{scala_role_name}_=(_value: #{other_type_name}) = { #{scala_role_name} = _value }"
|
137
|
+
end
|
138
|
+
else
|
139
|
+
# Define a getter for an optional value:
|
140
|
+
# REVISIT: The role number here depends on the metamodel ordering of the fact type roles.
|
141
|
+
# This likely should follow the role order of the preferred reading, from which the fact name is derived.
|
142
|
+
# The code here collows the order of definition of the roles in the fact type,
|
143
|
+
# which might not be the same as the order of the preferred reading:
|
144
|
+
fact_name = fact_type.scala_name.titlecase
|
145
|
+
role_number = fact_type.all_role_in_order.index(other_role)+1
|
146
|
+
|
147
|
+
" def #{scala_role_name}: Option[#{other_type_name}] = {\n" +
|
148
|
+
" constellation.getBinaryFact(metaModel.#{fact_name.words.camelcase}, this).map(x => {\n" +
|
149
|
+
" x.head.asInstanceOf[FBMModel.BinaryFact].rolePlayers._#{role_number}.asInstanceOf[#{other_type_name}]\n" +
|
150
|
+
" })\n" +
|
151
|
+
" }\n" +
|
152
|
+
if !fact_type.is_existential
|
153
|
+
# Define a setter for an optional value:
|
154
|
+
" def #{scala_role_name}_=(value: Option[#{other_type_name}]) = {\n" +
|
155
|
+
" value match {\n" +
|
156
|
+
" case None =>\n" +
|
157
|
+
" case Some(m) => constellation.assertBinaryFact(#{fact_name.words.titlecase}(this, m))\n" +
|
158
|
+
" }\n" +
|
159
|
+
" }"
|
160
|
+
else
|
161
|
+
''
|
162
|
+
end
|
163
|
+
end
|
164
|
+
elsif other_role.object_type.fact_type
|
165
|
+
# An objectified fact type
|
166
|
+
<<"END"
|
167
167
|
def all#{scala_role_name.words.titlecase}(implicit constellation: Constellation): Seq[#{other_type_name}] = {
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
168
|
+
constellation.getObjectifiedFact(metaModel.#{scala_role_name.words.camelcase}, this).getOrElse(Nil).flatMap(x => x match {
|
169
|
+
case o: #{other_type_name} => Some(o)
|
170
|
+
case _ => None
|
171
|
+
})
|
172
172
|
}
|
173
173
|
END
|
174
|
-
|
175
|
-
|
174
|
+
else
|
175
|
+
<<"END"
|
176
176
|
/*
|
177
177
|
def all#{scala_role_name.words.titlecase}(implicit constellation: Constellation): Seq[#{other_type_name}] = {
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
178
|
+
constellation.getFact(metaModel.#{scala_role_name.words.camelcase}, this).getOrElse(Nil).flatMap(x => x match {
|
179
|
+
# REVISIT: This is incorrect; we want to return the other role player in the fact
|
180
|
+
case o: #{other_type_name} => Some(o)
|
181
|
+
case _ => None
|
182
|
+
})
|
183
183
|
}
|
184
184
|
*/
|
185
185
|
END
|
186
|
-
|
187
|
-
|
186
|
+
end
|
187
|
+
end
|
188
188
|
end
|
189
189
|
|
190
190
|
module ValueType
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
|
191
|
+
DataTypeMap = {
|
192
|
+
"Signed Integer" => "Int",
|
193
|
+
"Unsigned Integer" => "Int",
|
194
|
+
"Real" => "Double",
|
195
|
+
"Char" => "String",
|
196
|
+
# REVISIT: More will be needed here.
|
197
|
+
}
|
198
|
+
LengthTypes = [ "String", "Decimal" ]
|
199
|
+
ScaleTypes = [ "Decimal" ]
|
200
|
+
|
201
|
+
def scala_definition(super_type_name, facets)
|
202
|
+
vt_name = name.words.titlecase
|
203
|
+
if d = DataTypeMap[super_type_name]
|
204
|
+
super_type_name = d
|
205
|
+
end
|
206
|
+
super_type_title = super_type_name.words.titlecase
|
207
|
+
super_type_camel = super_type_name.words.camelcase
|
208
|
+
|
209
|
+
sometimes_optional = all_role.detect do |r|
|
210
|
+
r.fact_type.all_role.size == 2 && (c = (r.fact_type.all_role.to_a-[r])[0]) and !c.is_mandatory
|
211
|
+
end
|
212
|
+
|
213
|
+
" case class #{vt_name}(value: #{super_type_title})(implicit val constellation: Constellation) extends FBMModel.ValueTypeValue[#{super_type_title}] {\n" +
|
214
|
+
" val objectType = metaModel.#{vt_name.words.camelcase}\n" +
|
215
|
+
# REVISIT: scala_type_params +
|
216
|
+
# REVISIT: scala_value_restriction + # puts " restrict #{value_constraint.all_allowed_range_sorted.map{|ar| ar.to_s}*", "}\n" if value_constraint
|
217
|
+
# REVISIT: scala_units + # puts " \# REVISIT: #{vt_name} is in units of #{unit.name}\n" if unit
|
218
|
+
absorbed_roles.map do |role|
|
219
219
|
role.scala_role_definition
|
220
220
|
end.
|
221
221
|
compact*"\n" +
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
222
|
+
" }\n" +
|
223
|
+
|
224
|
+
# Add implicit casts for the underlying data type:
|
225
|
+
" implicit def #{super_type_camel}2#{vt_name}(value: #{super_type_title})(implicit constellation: Constellation): #{vt_name} = #{vt_name}(value)\n" +
|
226
|
+
if sometimes_optional
|
227
|
+
" implicit def #{super_type_camel}2#{vt_name}Option(value: #{super_type_title})(implicit constellation: Constellation): Option[#{vt_name}] = Some(#{vt_name}(value))\n"
|
228
|
+
else
|
229
|
+
""
|
230
|
+
end +
|
231
|
+
"\n"
|
232
|
+
end
|
233
|
+
|
234
|
+
def scala_metamodel(super_type_name, facets)
|
235
|
+
vt_name = name.words.titlecase
|
236
|
+
super_type_title = super_type_name.words.titlecase
|
237
|
+
# REVISIT: Remove facets that do not apply to the Scala data types
|
238
|
+
params = [
|
239
|
+
LengthTypes.include?(super_type_name) ? facets[:length] : nil,
|
240
|
+
ScaleTypes.include?(super_type_name) ? facets[:scale] : nil
|
241
|
+
].compact * ", "
|
242
|
+
|
243
|
+
" val #{name.words.camelcase} = assertEntity(FBMModel.ValueType(FBMModel.DomainObjectTypeName(\"#{vt_name}\"), FBMModel.#{super_type_title}Type(#{params}), Nil))\n"
|
244
|
+
end
|
245
245
|
end
|
246
246
|
|
247
247
|
module EntityType
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
248
|
+
def scala_object(title_name, id_names, id_types)
|
249
|
+
" object #{title_name} {\n" +
|
250
|
+
" def apply(" +
|
251
|
+
(id_names.zip(id_types).map do |(name, type_name)|
|
252
|
+
"#{name}: #{type_name}"
|
253
|
+
end * ', '
|
254
|
+
) +
|
255
|
+
")(implicit constellation: Constellation) = {\n" +
|
256
|
+
|
257
|
+
# Define the constant storage for the identifying role values:
|
258
|
+
id_names.map do |name|
|
259
|
+
" val _#{name} = #{name}"
|
260
|
+
end*"\n" +
|
261
|
+
" val _constellation = constellation\n" +
|
262
|
+
" assertEntity(new #{title_name} {\n" +
|
263
|
+
id_names.map do |name|
|
264
|
+
" val #{name} = _#{name}"
|
265
|
+
end*"\n" +
|
266
|
+
" val constellation = _constellation\n" +
|
267
|
+
" })\n" + # Ends new block and assertEntity
|
268
|
+
" }\n" + # Ends apply()
|
269
|
+
" }\n" + # Ends object{}
|
270
|
+
"\n"
|
271
|
+
end
|
272
|
+
|
273
|
+
def scala_trait(title_name, primary_supertype, pis)
|
274
|
+
s = 'override ' unless supertypes.empty?
|
275
|
+
|
276
|
+
" trait #{title_name} extends #{primary_supertype ? primary_supertype.name.words.titlecase : 'FBMModel.Entity'} {\n" +
|
277
|
+
" #{s}val objectType = metaModel.#{name.words.camelcase}\n" +
|
278
|
+
(fact_type ? " // REVISIT: Here, we should use fact_roles_dump(fact_type)\n\n" : '') +
|
279
|
+
absorbed_roles.map do |role|
|
280
280
|
role.scala_role_definition
|
281
281
|
end.
|
282
282
|
compact*"\n" +
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
283
|
+
" #{s}val identifier: Seq[Seq[FBMModel.Identifier[_]]] = Seq(#{
|
284
|
+
pis.map do |pi|
|
285
|
+
'Seq(' +
|
286
|
+
pi.role_sequence.all_role_ref_in_order.map do |id_role_ref|
|
287
|
+
id_role_ref.role.object_type.name.words.camelcase
|
288
|
+
end*', ' +
|
289
|
+
')'
|
290
|
+
end*', '
|
291
|
+
})\n" +
|
292
|
+
" }\n" + # Ends trait{}
|
293
|
+
"\n"
|
294
|
+
end
|
295
|
+
|
296
|
+
def scala_metamodel(title_name)
|
297
|
+
pi = preferred_identifier
|
298
|
+
# The following finds the closest non-inheritance identifier
|
299
|
+
#while pi.role_sequence.all_role_ref.size == 1 and
|
300
|
+
# (role = pi.role_sequence.all_role_ref.single.role).fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
301
|
+
# pi = role.fact_type.supertype_role.object_type.preferred_identifier
|
302
|
+
#end
|
303
|
+
identifying_parameters =
|
304
|
+
pi.role_sequence.all_role_ref_in_order.map{|rr| rr.role.object_type.name.words.camelcase }*', '
|
305
|
+
|
306
|
+
supertypes_list =
|
307
|
+
if supertypes.empty?
|
308
|
+
'Nil'
|
309
|
+
else
|
310
|
+
"List(#{supertypes.map{|s| s.name.words.camelcase}*', '})"
|
311
|
+
end
|
312
|
+
" val #{name.words.camelcase} = assertEntity(FBMModel.EntityType(FBMModel.DomainObjectTypeName(\"#{title_name}\"), #{supertypes_list}, Seq(#{identifying_parameters})))\n"
|
313
|
+
end
|
314
|
+
|
315
|
+
def scala_shared(o, supertypes, pi = nil)
|
316
|
+
if supertypes
|
317
|
+
primary_supertype = o && (o.identifying_supertype || o.supertypes[0])
|
318
|
+
end
|
319
|
+
title_name = o.name.words.titlecase
|
320
|
+
|
321
|
+
id_roles, pis = *all_identifying_roles(o)
|
322
|
+
id_names = id_role_names(o, id_roles)
|
323
|
+
id_types = id_role_types(id_roles)
|
324
|
+
identification = pi ? identified_by(o, pi) : nil
|
325
|
+
|
326
|
+
# REVISIT: We don't want an object for abstract classes,
|
327
|
+
# i.e. where subtypes have a disjoint mandatory constraint
|
328
|
+
entity_object(title_name, id_names, id_types)
|
329
|
+
|
330
|
+
entity_trait(o, title_name, primary_supertype, pis)
|
331
|
+
|
332
|
+
entity_model(o, title_name)
|
333
|
+
end
|
334
|
+
|
335
|
+
def id_role_names id_roles
|
336
|
+
id_roles.map do |role|
|
337
|
+
# Ignore identification through a supertype
|
338
|
+
next if role.fact_type.kind_of?(ActiveFacts::Metamodel::TypeInheritance)
|
339
|
+
role.scala_preferred_role_name(self).words.camelcase
|
340
|
+
end.compact
|
341
|
+
end
|
342
|
+
|
343
|
+
def id_role_types id_roles
|
344
|
+
id_roles.map do |role|
|
345
|
+
next if role.fact_type.kind_of?(ActiveFacts::Metamodel::TypeInheritance)
|
346
|
+
if !role.fact_type.entity_type && role.fact_type.all_role.size == 1
|
347
|
+
"Boolean"
|
348
|
+
else
|
349
|
+
role.object_type.name.words.titlecase
|
350
|
+
end
|
351
|
+
end.compact
|
352
|
+
end
|
353
|
+
|
354
|
+
def scala_objectification
|
355
|
+
# REVISIT: This disregards any supertypes and their identifiers
|
356
356
|
# primary_supertype = o && (o.identifying_supertype || o.supertypes[0])
|
357
357
|
# secondary_supertypes = o.supertypes-[primary_supertype]
|
358
358
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
359
|
+
pi = preferred_identifier
|
360
|
+
id_roles = []
|
361
|
+
identifying_role_refs = pi.role_sequence.all_role_ref_in_order
|
362
|
+
identifying_role_refs.each do |id_role_ref|
|
363
|
+
id_roles << id_role_ref.role
|
364
|
+
end
|
365
|
+
id_names = id_role_names id_roles
|
366
|
+
id_types = id_role_types id_roles
|
367
|
+
|
368
|
+
" case class #{name.words.titlecase}(#{
|
369
|
+
id_names.zip(id_types).map {|(n, t)|
|
370
|
+
"#{n}: #{t}"
|
371
|
+
}*', '
|
372
|
+
}) extends FBMModel.ObjectifiedFact {\n" +
|
373
|
+
" // REVISIT: Here, we should use fact_roles_dump(fact_type)\n" +
|
374
|
+
absorbed_roles.map do |role|
|
375
375
|
role.scala_role_definition
|
376
376
|
end.
|
377
377
|
compact*"\n" +
|
378
|
-
|
379
|
-
|
378
|
+
" }"
|
379
|
+
end
|
380
380
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
381
|
+
def scala_objectification_metamodel
|
382
|
+
identifying_parameters = preferred_identifier.role_sequence.all_role_ref_in_order.map{|rr| rr.role.object_type.name.words.camelcase }*', '
|
383
|
+
" val #{name.words.camelcase} = assertEntity(FBMModel.ObjectifiedType(FBMModel.DomainObjectTypeName(\"#{name.words.titlecase}\"), Nil, Seq(#{identifying_parameters})))\n"
|
384
|
+
end
|
385
385
|
end
|
386
386
|
|
387
387
|
module FactType
|
@@ -415,28 +415,28 @@ END
|
|
415
415
|
|
416
416
|
# An objectified fact type has internal roles that are always "has_one":
|
417
417
|
def fact_roles
|
418
|
-
|
418
|
+
raise "Fact #{describe} type is not objectified" unless entity_type
|
419
419
|
all_role.sort_by do |role|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
420
|
+
role.scala_preferred_role_name(entity_type)
|
421
|
+
end.
|
422
|
+
map do |role|
|
423
|
+
role_name = role.scala_preferred_role_name(entity_type)
|
424
|
+
one_to_one = role.all_role_ref.detect{|rr|
|
425
|
+
rr.role_sequence.all_role_ref.size == 1 &&
|
426
|
+
rr.role_sequence.all_presence_constraint.detect{|pc|
|
427
|
+
pc.max_frequency == 1
|
428
|
+
}
|
429
|
+
}
|
430
|
+
counterpart_role_method = (one_to_one ? "" : "all_") +
|
431
|
+
entity_type.oo_default_role_name +
|
432
|
+
(role_name != role.object_type.oo_default_role_name ? "_as_#{role_name}" : '')
|
433
|
+
role.as_binary(role_name, role.object_type, true, one_to_one, nil, nil, counterpart_role_method)
|
434
|
+
end.
|
435
|
+
join('')
|
436
|
+
end
|
437
437
|
end
|
438
438
|
|
439
|
-
include ActiveFacts::TraitInjector
|
439
|
+
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
440
440
|
end
|
441
441
|
end
|
442
442
|
end
|