activefacts-generators 1.8.0 → 1.8.1
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/generators/scala.rb +184 -0
- data/lib/activefacts/generators/traits/scala.rb +442 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b8cf08b3a5a39113eb4e04697ee25b4f4abdb4f
|
4
|
+
data.tar.gz: aeed8fc142836d0d79321eff69c97b38d016dc45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13ce57f363db35fce13e217a916d17661fcfcd6349c0345d1873d0832a45fff625a5f656eb36cd8e758fb53d93df025234feade6defd6839ce50a9d2c9069f4f
|
7
|
+
data.tar.gz: b3a5c20cb3b066cb77774d88e1b55d3c95053672c079decf4f7f00b79a05e5da89a0c62d46a25a0b6f2ed13c58fe2a9aa1cabcfa0c178702f220db89a59f1e15
|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "activefacts-generators"
|
7
|
-
spec.version = "1.8.
|
7
|
+
spec.version = "1.8.1"
|
8
8
|
spec.authors = ["Clifford Heath"]
|
9
9
|
spec.email = ["clifford.heath@gmail.com"]
|
10
10
|
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.add_development_dependency "rake", "~> 10.0"
|
21
21
|
spec.add_development_dependency "rspec", "~> 3.3"
|
22
22
|
|
23
|
-
spec.add_runtime_dependency "activefacts-metamodel", ">= 1.8", "~> 1
|
24
|
-
spec.add_runtime_dependency "activefacts-rmap", ">= 1.8", "~> 1
|
23
|
+
spec.add_runtime_dependency "activefacts-metamodel", ">= 1.8", "~> 1"
|
24
|
+
spec.add_runtime_dependency "activefacts-rmap", ">= 1.8", "~> 1"
|
25
25
|
spec.add_runtime_dependency "activesupport", ">= 4.2", "~> 4.2.4"
|
26
26
|
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Generators.
|
3
|
+
# Generate a Scala module for the ActiveFacts API from an ActiveFacts vocabulary.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2013 Clifford Heath. Read the LICENSE file.
|
6
|
+
#
|
7
|
+
require 'activefacts'
|
8
|
+
require 'activefacts/metamodel'
|
9
|
+
require 'activefacts/generators/helpers/oo'
|
10
|
+
require 'activefacts/generators/traits/scala'
|
11
|
+
require 'activefacts/registry'
|
12
|
+
|
13
|
+
module ActiveFacts
|
14
|
+
module Generators
|
15
|
+
# Generate Scala module containing classes for an ActiveFacts vocabulary.
|
16
|
+
# Invoke as
|
17
|
+
# afgen --scala[=options] <file>.cql
|
18
|
+
# Options are comma or space separated:
|
19
|
+
# * help list available options
|
20
|
+
|
21
|
+
class Scala < Helpers::OO
|
22
|
+
|
23
|
+
def initialize(vocabulary, *options)
|
24
|
+
super
|
25
|
+
@constraints_used = {}
|
26
|
+
@fact_types_dumped = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def set_option(option)
|
32
|
+
@mapping = false
|
33
|
+
case option
|
34
|
+
when 'help', '?'
|
35
|
+
$stderr.puts "Usage:\t\tafgen --scala[=option,option] input_file.cql\n"+
|
36
|
+
"\t\tmeta\t\tModify the mapping to suit a metamodel"
|
37
|
+
exit 0
|
38
|
+
when /^meta/
|
39
|
+
@is_metamodel = true
|
40
|
+
else super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def fact_type_name(fact_type)
|
45
|
+
fact_type.default_reading.words
|
46
|
+
end
|
47
|
+
|
48
|
+
def vocabulary_start
|
49
|
+
puts @vocabulary.scala_prelude
|
50
|
+
|
51
|
+
@metamodel = @vocabulary.scala_prelude_metamodel
|
52
|
+
end
|
53
|
+
|
54
|
+
def vocabulary_end
|
55
|
+
puts @vocabulary.scala_finale
|
56
|
+
puts "#{@metamodel}\n}\n"
|
57
|
+
end
|
58
|
+
|
59
|
+
def data_type_dump(o)
|
60
|
+
end
|
61
|
+
|
62
|
+
def value_type_dump(o, super_type_name, facets)
|
63
|
+
puts o.scala_definition(super_type_name, facets)
|
64
|
+
|
65
|
+
@metamodel << o.scala_metamodel(super_type_name, facets)
|
66
|
+
end
|
67
|
+
|
68
|
+
def id_role_names o, id_roles
|
69
|
+
id_roles.map do |role|
|
70
|
+
# Ignore identification through a supertype
|
71
|
+
next if role.fact_type.kind_of?(ActiveFacts::Metamodel::TypeInheritance)
|
72
|
+
role.preferred_role_name(o).words.camelcase
|
73
|
+
end.compact
|
74
|
+
end
|
75
|
+
|
76
|
+
def id_role_types id_roles
|
77
|
+
id_roles.map do |role|
|
78
|
+
next if role.fact_type.kind_of?(ActiveFacts::Metamodel::TypeInheritance)
|
79
|
+
if !role.fact_type.entity_type && role.fact_type.all_role.size == 1
|
80
|
+
"Boolean"
|
81
|
+
else
|
82
|
+
role.object_type.name.words.titlecase
|
83
|
+
end
|
84
|
+
end.compact
|
85
|
+
end
|
86
|
+
|
87
|
+
def all_identifying_roles(o)
|
88
|
+
pis = []
|
89
|
+
# This places the subtype identifying roles before the supertype's. Reverse the list to change this.
|
90
|
+
id_roles = []
|
91
|
+
o.supertypes_transitive.each do |supertype|
|
92
|
+
pi = supertype.preferred_identifier
|
93
|
+
next if pis.include?(pi) # Seen this identifier already?
|
94
|
+
pis << pi
|
95
|
+
identifying_role_refs = pi.role_sequence.all_role_ref_in_order
|
96
|
+
identifying_role_refs.each do |id_role_ref|
|
97
|
+
# Have we seen this role in another identifier?
|
98
|
+
next if id_roles.detect{|idr| idr == id_role_ref.role }
|
99
|
+
id_roles << id_role_ref.role
|
100
|
+
end
|
101
|
+
end
|
102
|
+
[id_roles, pis]
|
103
|
+
end
|
104
|
+
|
105
|
+
def entity_object(o, title_name, id_names, id_types)
|
106
|
+
puts o.scala_object(title_name, id_names, id_types)
|
107
|
+
end
|
108
|
+
|
109
|
+
def entity_trait(o, title_name, primary_supertype, pis)
|
110
|
+
puts o.scala_trait(title_name, primary_supertype, pis)
|
111
|
+
end
|
112
|
+
|
113
|
+
def entity_model(o, title_name)
|
114
|
+
@metamodel << o.scala_metamodel(title_name)
|
115
|
+
end
|
116
|
+
|
117
|
+
def non_subtype_dump(o, pi)
|
118
|
+
subtype_dump(o, nil, pi)
|
119
|
+
end
|
120
|
+
|
121
|
+
def subtype_dump(o, supertypes, pi = nil)
|
122
|
+
if supertypes
|
123
|
+
primary_supertype = o && (o.identifying_supertype || o.supertypes[0])
|
124
|
+
end
|
125
|
+
title_name = o.name.words.titlecase
|
126
|
+
|
127
|
+
id_roles, pis = *all_identifying_roles(o)
|
128
|
+
id_names = id_role_names(o, id_roles)
|
129
|
+
id_types = id_role_types(id_roles)
|
130
|
+
identification = pi ? identified_by(o, pi) : nil
|
131
|
+
|
132
|
+
# REVISIT: We don't want an object for abstract classes,
|
133
|
+
# i.e. where subtypes have a disjoint mandatory constraint
|
134
|
+
entity_object(o, title_name, id_names, id_types)
|
135
|
+
|
136
|
+
entity_trait(o, title_name, primary_supertype, pis)
|
137
|
+
|
138
|
+
entity_model(o, title_name)
|
139
|
+
|
140
|
+
@constraints_used[pi] = true if pi
|
141
|
+
end
|
142
|
+
|
143
|
+
def identified_by_roles_and_facts(entity_type, identifying_role_refs, identifying_facts)
|
144
|
+
identifying_role_refs.map do |role_ref|
|
145
|
+
[ role_ref.role.scala_preferred_role_name(entity_type),
|
146
|
+
entity_type.name.words.titlecase
|
147
|
+
]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def skip_fact_type(f)
|
152
|
+
f.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Dump one fact type.
|
156
|
+
def fact_type_dump(fact_type, name)
|
157
|
+
@fact_types_dumped[fact_type] = true
|
158
|
+
return objectified_fact_type_dump(fact_type.entity_type) if fact_type.entity_type
|
159
|
+
|
160
|
+
puts fact_type.scala_definition
|
161
|
+
|
162
|
+
@metamodel << fact_type.scala_metamodel
|
163
|
+
end
|
164
|
+
|
165
|
+
def objectified_fact_type_dump o
|
166
|
+
puts o.scala_objectification
|
167
|
+
@metamodel << o.scala_objectification_metamodel
|
168
|
+
end
|
169
|
+
|
170
|
+
def unary_dump(role, role_name)
|
171
|
+
scala_role_name = role_name.words.camelcase
|
172
|
+
puts " val #{scala_role_name}: Boolean"
|
173
|
+
end
|
174
|
+
|
175
|
+
def role_dump(role)
|
176
|
+
puts role.scala_role_definition
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
ActiveFacts::Registry.generator('scala', ActiveFacts::Generators::Scala)
|
184
|
+
|
@@ -0,0 +1,442 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Generators.
|
3
|
+
#
|
4
|
+
# Metamodel Traits for mapping to Scala
|
5
|
+
#
|
6
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
7
|
+
#
|
8
|
+
module ActiveFacts
|
9
|
+
module Generators
|
10
|
+
module ScalaTraits
|
11
|
+
module Vocabulary
|
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
|
+
end
|
38
|
+
|
39
|
+
module ObjectType
|
40
|
+
# Map the ObjectType name to a Scala class name
|
41
|
+
def scala_type_name
|
42
|
+
oo_type_name
|
43
|
+
end
|
44
|
+
|
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
|
+
|
50
|
+
def absorbed_roles
|
51
|
+
all_role.
|
52
|
+
select do |role|
|
53
|
+
role.fact_type.all_role.size <= 2 &&
|
54
|
+
!role.fact_type.is_a?(ActiveFacts::Metamodel::LinkFactType)
|
55
|
+
end.
|
56
|
+
sort_by do |role|
|
57
|
+
r = role.fact_type.all_role.select{|r2| r2 != role}[0] || role
|
58
|
+
r.scala_preferred_role_name(self) + ':' + role.scala_preferred_role_name(r.object_type)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module Role
|
64
|
+
def scala_preferred_role_name(is_for = nil, &name_builder)
|
65
|
+
# REVISIT: Modify this to suit Scala
|
66
|
+
|
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
|
+
|
72
|
+
name_builder ||= proc {|names| names.map(&:downcase)*'_' } # Make snake_case by default
|
73
|
+
|
74
|
+
# Handle an objectified unary role:
|
75
|
+
if is_for && fact_type.entity_type == is_for && fact_type.all_role.size == 1
|
76
|
+
return name_builder.call(object_type.name.words)
|
77
|
+
end
|
78
|
+
|
79
|
+
# trace "Looking for preferred_role_name of #{describe_fact_type(fact_type, self)}"
|
80
|
+
reading = fact_type.preferred_reading
|
81
|
+
preferred_role_ref = reading.role_sequence.all_role_ref.detect{|reading_rr|
|
82
|
+
reading_rr.role == self
|
83
|
+
}
|
84
|
+
|
85
|
+
if fact_type.all_role.size == 1
|
86
|
+
return name_builder.call(
|
87
|
+
role_name ?
|
88
|
+
role_name.snakewords :
|
89
|
+
reading.text.gsub(/ *\{0\} */,' ').gsub(/[- ]+/,'_').words
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
if role_name && role_name != ""
|
94
|
+
role_words = [role_name]
|
95
|
+
else
|
96
|
+
role_words = []
|
97
|
+
|
98
|
+
la = preferred_role_ref.leading_adjective
|
99
|
+
role_words += la.words.snakewords if la && la != ""
|
100
|
+
|
101
|
+
role_words += object_type.name.words.snakewords
|
102
|
+
|
103
|
+
ta = preferred_role_ref.trailing_adjective
|
104
|
+
role_words += ta.words.snakewords if ta && ta != ""
|
105
|
+
end
|
106
|
+
|
107
|
+
# n = role_words.map{|w| w.gsub(/([a-z])([A-Z]+)/,'\1_\2').downcase}*"_"
|
108
|
+
n = role_words*'_'
|
109
|
+
# trace "\tresult=#{n}"
|
110
|
+
return name_builder.call(n.gsub(' ','_').split(/_/))
|
111
|
+
end
|
112
|
+
|
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
|
+
def all#{scala_role_name.words.titlecase}(implicit constellation: Constellation): Seq[#{other_type_name}] = {
|
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
|
+
}
|
173
|
+
END
|
174
|
+
else
|
175
|
+
<<"END"
|
176
|
+
/*
|
177
|
+
def all#{scala_role_name.words.titlecase}(implicit constellation: Constellation): Seq[#{other_type_name}] = {
|
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
|
+
}
|
184
|
+
*/
|
185
|
+
END
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
module ValueType
|
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
|
+
role.scala_role_definition
|
220
|
+
end.
|
221
|
+
compact*"\n" +
|
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
|
+
end
|
246
|
+
|
247
|
+
module EntityType
|
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
|
+
role.scala_role_definition
|
281
|
+
end.
|
282
|
+
compact*"\n" +
|
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
|
+
# primary_supertype = o && (o.identifying_supertype || o.supertypes[0])
|
357
|
+
# secondary_supertypes = o.supertypes-[primary_supertype]
|
358
|
+
|
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
|
+
role.scala_role_definition
|
376
|
+
end.
|
377
|
+
compact*"\n" +
|
378
|
+
" }"
|
379
|
+
end
|
380
|
+
|
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
|
+
end
|
386
|
+
|
387
|
+
module FactType
|
388
|
+
def scala_name
|
389
|
+
default_reading.words
|
390
|
+
end
|
391
|
+
|
392
|
+
def scala_definition
|
393
|
+
# Dump a non-objectified fact type
|
394
|
+
name_words = scala_name
|
395
|
+
role_names = preferred_reading.role_sequence.all_role_ref_in_order.map do |rr|
|
396
|
+
rr.role.scala_preferred_role_name.words.camelcase
|
397
|
+
end
|
398
|
+
role_types = preferred_reading.role_sequence.all_role_ref_in_order.map do |rr|
|
399
|
+
rr.role.object_type.name.words.camelcase
|
400
|
+
end
|
401
|
+
|
402
|
+
" case class #{name_words.titlecase}(#{role_names.zip(role_types).map{|n, t| n+': '+t}*', '})(implicit val constellation: Constellation) extends FBMModel.BinaryFact {\n" +
|
403
|
+
" def factType = metaModel.#{name_words.camelcase}\n" +
|
404
|
+
" def rolePlayers = (#{role_names*', '})\n" +
|
405
|
+
" }\n\n"
|
406
|
+
end
|
407
|
+
|
408
|
+
def scala_metamodel
|
409
|
+
name_words = scala_name
|
410
|
+
role_names = preferred_reading.role_sequence.all_role_ref_in_order.map do |rr|
|
411
|
+
rr.role.scala_preferred_role_name.words.camelcase
|
412
|
+
end
|
413
|
+
" val #{name_words.camelcase} = assertEntity(FBMModel.BinaryFactType(FBMModel.FactTypeName(\"#{name_words.titlecase}\"), (#{role_names*', '})))\n"
|
414
|
+
end
|
415
|
+
|
416
|
+
# An objectified fact type has internal roles that are always "has_one":
|
417
|
+
def fact_roles
|
418
|
+
raise "Fact #{describe} type is not objectified" unless entity_type
|
419
|
+
all_role.sort_by do |role|
|
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
|
+
end
|
438
|
+
|
439
|
+
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activefacts-generators
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.
|
4
|
+
version: 1.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clifford Heath
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
version: '1.8'
|
68
68
|
- - "~>"
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: 1
|
70
|
+
version: '1'
|
71
71
|
type: :runtime
|
72
72
|
prerelease: false
|
73
73
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -77,7 +77,7 @@ dependencies:
|
|
77
77
|
version: '1.8'
|
78
78
|
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version: 1
|
80
|
+
version: '1'
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: activefacts-rmap
|
83
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -87,7 +87,7 @@ dependencies:
|
|
87
87
|
version: '1.8'
|
88
88
|
- - "~>"
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version: 1
|
90
|
+
version: '1'
|
91
91
|
type: :runtime
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -97,7 +97,7 @@ dependencies:
|
|
97
97
|
version: '1.8'
|
98
98
|
- - "~>"
|
99
99
|
- !ruby/object:Gem::Version
|
100
|
-
version: 1
|
100
|
+
version: '1'
|
101
101
|
- !ruby/object:Gem::Dependency
|
102
102
|
name: activesupport
|
103
103
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- lib/activefacts/generators/rails/models.rb
|
151
151
|
- lib/activefacts/generators/rails/schema.rb
|
152
152
|
- lib/activefacts/generators/ruby.rb
|
153
|
+
- lib/activefacts/generators/scala.rb
|
153
154
|
- lib/activefacts/generators/sql/mysql.rb
|
154
155
|
- lib/activefacts/generators/sql/server.rb
|
155
156
|
- lib/activefacts/generators/stats.rb
|
@@ -158,6 +159,7 @@ files:
|
|
158
159
|
- lib/activefacts/generators/traits/oo.rb
|
159
160
|
- lib/activefacts/generators/traits/ordered.rb
|
160
161
|
- lib/activefacts/generators/traits/ruby.rb
|
162
|
+
- lib/activefacts/generators/traits/scala.rb
|
161
163
|
- lib/activefacts/generators/transform/datavault.rb
|
162
164
|
- lib/activefacts/generators/transform/surrogate.rb
|
163
165
|
- lib/activefacts/registry.rb
|