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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f40edd413e3910347f03b39b1fd1cd36513c15a8
4
- data.tar.gz: 0ace4f714d8e1ba990a3d8f81fdf6ac50ec812dd
3
+ metadata.gz: 1b8cf08b3a5a39113eb4e04697ee25b4f4abdb4f
4
+ data.tar.gz: aeed8fc142836d0d79321eff69c97b38d016dc45
5
5
  SHA512:
6
- metadata.gz: 641e9a5ce19aa07e807cde79708ed740ab1b810c913255fe94580fcec9660bdae247f5e49325b39193b3ed2c69e803873730be884c05c82e940eaf5c65b5454b
7
- data.tar.gz: 99448103bb436f51228565c94ddc7dd8103f2a014aa4a76bbabdf7844972c97a10fcf0af429f25c16afb1d43a71fd63c29f63f559ea6d1128957c1d952c87a6a
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.0"
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.8.0"
24
- spec.add_runtime_dependency "activefacts-rmap", ">= 1.8", "~> 1.8.0"
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.0
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-04 00:00:00.000000000 Z
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.8.0
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.8.0
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.8.0
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.8.0
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