activefacts-generators 1.8.3 → 1.9.0
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/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
|