activefacts-generators 1.8.0 → 1.8.1
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/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
|