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
@@ -24,27 +24,27 @@ module ActiveFacts
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def generate(out = $>)
|
27
|
-
|
27
|
+
@metadata = {"types" => {}}
|
28
28
|
|
29
29
|
object_types_dump
|
30
30
|
|
31
|
-
|
31
|
+
out.puts ::JSON.pretty_generate(@metadata)
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
# Store the metadata for all types into the types section of the @metadata hash
|
35
|
+
def object_types_dump
|
36
|
+
types = @metadata["types"]
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
# Compute the relational mapping if not already done:
|
39
|
+
@tables ||= @vocabulary.tables
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
@vocabulary.all_object_type.
|
42
|
+
sort_by{|c| c.name}.each do |o|
|
43
|
+
object_type = o.as_json_metadata
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
types[o.name] = object_type if object_type
|
46
|
+
end
|
47
|
+
end
|
48
48
|
|
49
49
|
end
|
50
50
|
end
|
@@ -53,149 +53,149 @@ module ActiveFacts
|
|
53
53
|
module Metamodel
|
54
54
|
class ObjectType
|
55
55
|
def as_json_metadata
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
# Using proc avoids polluting the object's namespace with these little methods
|
57
|
+
verbalise_role = proc do |role, plural|
|
58
|
+
fc = Array.new(role.fact_type.all_role.size, plural ? 'some' : 'one')
|
59
|
+
reading = role.fact_type.reading_preferably_starting_with_role(role)
|
60
60
|
fc.reverse! unless reading.role_sequence.all_role_ref.to_a[0].role == role
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
61
|
+
fc[reading.role_sequence.all_role_ref_in_order.to_a.index{|rr| rr.role == role}] = 'this'
|
62
|
+
reading.expand(fc, false)
|
63
|
+
end
|
64
|
+
|
65
|
+
titlize_words = proc do |phrase|
|
66
|
+
phrase && phrase.split(/\s+/).map{|w| w.sub(/^[a-z]/) {|i| i.upcase}}*' '
|
67
|
+
end
|
68
|
+
|
69
|
+
role_name = proc do |role|
|
70
|
+
if role.role_name
|
71
|
+
role.role_name
|
72
|
+
else
|
73
|
+
ref = role.preferred_reference
|
74
|
+
[ titlize_words.call(ref.leading_adjective), role.object_type.name, titlize_words.call(ref.trailing_adjective)].compact*' '
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
return nil if name == '_ImplicitBooleanValueType'
|
79
|
+
|
80
|
+
object_type = {}
|
81
|
+
object_type["is_main"] = is_table
|
82
|
+
object_type["id"] = concept.guid.to_s
|
83
|
+
functions = object_type["functions"] = []
|
84
|
+
|
85
|
+
if is_a?(ActiveFacts::Metamodel::EntityType)
|
86
|
+
|
87
|
+
# Don't emit a binary objectified fact type that plays no roles (except in implicit fact types:
|
88
|
+
if fact_type and fact_type.all_role.size == 2 and all_role.size == 2
|
89
|
+
return nil
|
90
|
+
end
|
91
|
+
|
92
|
+
# Export the supertypes
|
93
|
+
(supertypes_transitive-[self]).sort_by{|t| t.name}.each do |supertype|
|
94
|
+
functions <<
|
95
|
+
{
|
96
|
+
"title" => "as #{supertype.name}",
|
97
|
+
"type" => "#{supertype.name}"
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
# Export the subtypes
|
102
|
+
(subtypes_transitive-[self]).sort_by{|t| t.name}.each do |subtype|
|
103
|
+
functions <<
|
104
|
+
{
|
105
|
+
"title" => "as #{subtype.name}",
|
106
|
+
"type" => "#{subtype.name}"
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
# If an objectified fact type, export the fact type's roles
|
111
|
+
if fact_type
|
112
|
+
fact_type.preferred_reading.role_sequence.all_role_ref_in_order.map(&:role).each do |role|
|
113
|
+
functions <<
|
114
|
+
{
|
115
|
+
"title" => "involving #{role_name.call(role)}",
|
116
|
+
"type" => "#{role.object_type.name}",
|
117
|
+
"where" => verbalise_role.call(role, true) # REVISIT: Need plural setting here!
|
118
|
+
}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Now export the ordinary roles. Get a sorted list first:
|
124
|
+
roles = all_role.reject do |role|
|
125
|
+
# supertype and subtype roles get handled separately
|
126
|
+
role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) ||
|
127
|
+
role.fact_type.is_a?(ActiveFacts::Metamodel::LinkFactType)
|
128
|
+
end.sort_by do |role|
|
129
|
+
# Where this object type plays two roles in the same fact type,
|
130
|
+
# we order them by the position of that role in the preferred reading:
|
131
|
+
[role.fact_type.default_reading, role.fact_type.preferred_reading.role_sequence.all_role_ref_in_order.map(&:role).index(role)]
|
132
|
+
end
|
133
|
+
|
134
|
+
# For binary fact types, collect the count of the times the unadorned counterpart role name occurs, so we can adorn it
|
135
|
+
plural_counterpart_counts = roles.inject(Hash.new{0}) do |h, role|
|
136
|
+
next h unless role.fact_type.all_role.size == 2
|
137
|
+
uc = role.all_role_ref.detect do |rr|
|
138
|
+
rs = rr.role_sequence
|
139
|
+
next false if rs.all_role_ref.size != 1 # Looking for a UC over just this one role
|
140
|
+
rs.all_presence_constraint.detect do |pc|
|
141
|
+
next false unless pc.max_frequency == 1 # It's a uniqueness constraint
|
142
|
+
true
|
143
|
+
end
|
144
|
+
end
|
145
|
+
next h if uc # Not a plural role
|
146
|
+
|
147
|
+
counterpart_role = (role.fact_type.all_role.to_a - [role])[0]
|
148
|
+
h[role_name.call(counterpart_role)] += 1
|
149
|
+
h
|
150
|
+
end
|
151
|
+
|
152
|
+
roles.each do |role|
|
153
|
+
type_name = nil
|
154
|
+
counterpart_name = nil
|
155
|
+
|
156
|
+
if role.fact_type.entity_type and # Role is in an objectified fact type
|
157
|
+
# For binary objectified fact types, we traverse directly to the other role, not just to the objectification
|
158
|
+
!(role.fact_type.entity_type.all_role.size == 2 and role.fact_type.all_role.size == 2)
|
159
|
+
|
160
|
+
type_name = role.fact_type.entity_type.name
|
161
|
+
counterpart_name = type_name # If self plays more than one role in OFT, need to construct a role name
|
162
|
+
plural = true
|
163
|
+
elsif role.fact_type.all_role.size == 1
|
164
|
+
# Handle unary roles
|
165
|
+
type_name = 'boolean'
|
166
|
+
counterpart_name = role.fact_type.default_reading
|
167
|
+
plural = false
|
168
|
+
else
|
169
|
+
# Handle binary roles
|
170
|
+
counterpart_role = (role.fact_type.all_role.to_a - [role])[0]
|
171
|
+
type_name = counterpart_role.object_type.name
|
172
|
+
counterpart_name = role_name.call(counterpart_role)
|
173
|
+
# Figure out whether the counterpart is plural (say "all ..." if so)
|
174
|
+
uc = role.all_role_ref.detect do |rr|
|
175
|
+
rs = rr.role_sequence
|
176
|
+
next false if rs.all_role_ref.size != 1 # Looking for a UC over just this one role
|
177
|
+
rs.all_presence_constraint.detect do |pc|
|
178
|
+
next false unless pc.max_frequency == 1 # It's a uniqueness constraint
|
179
|
+
true
|
180
|
+
end
|
181
|
+
end
|
182
|
+
plural = !uc
|
183
|
+
if plural_counterpart_counts[counterpart_name] > 1
|
184
|
+
counterpart_name += " as " + role_name.call(role)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
node = {
|
189
|
+
"title" => "#{plural ? 'all ' : ''}#{counterpart_name}",
|
190
|
+
"type" => "#{type_name}",
|
191
|
+
"where" => verbalise_role.call(role, plural),
|
192
|
+
"role_id" => role.concept.guid.to_s
|
193
|
+
}
|
194
|
+
node["is_list"] = true if plural
|
195
|
+
functions << node
|
196
|
+
|
197
|
+
end
|
198
|
+
functions.size > 0 ? object_type : nil
|
199
199
|
end
|
200
200
|
end
|
201
201
|
end
|
@@ -45,7 +45,7 @@ module ActiveFacts
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def emit_mapping o
|
48
|
-
|
48
|
+
return
|
49
49
|
case @mapping
|
50
50
|
when 'sql'
|
51
51
|
puts " table"
|
@@ -55,11 +55,11 @@ module ActiveFacts
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def data_type_dump(o)
|
58
|
-
|
58
|
+
value_type_dump(o, o.name, {}) if o.all_role.size > 0
|
59
59
|
end
|
60
60
|
|
61
61
|
def value_type_dump(o, super_type_name, facets)
|
62
|
-
|
62
|
+
puts o.ruby_definition
|
63
63
|
end
|
64
64
|
|
65
65
|
def subtype_dump(o, supertypes, pi = nil)
|
@@ -124,7 +124,7 @@ module ActiveFacts
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def binary_dump(role, role_name, role_player, mandatory = nil, one_to_one = nil, readings = nil, counterpart_role_name = nil, counterpart_method_name = nil)
|
127
|
-
|
127
|
+
puts role.as_binary(role_name, role_player, mandatory, one_to_one, readings, counterpart_role_name, counterpart_method_name)
|
128
128
|
end
|
129
129
|
|
130
130
|
end
|
@@ -21,8 +21,8 @@ module ActiveFacts
|
|
21
21
|
class Scala < Helpers::OO
|
22
22
|
|
23
23
|
def initialize(vocabulary, *options)
|
24
|
-
|
25
|
-
|
24
|
+
super
|
25
|
+
@constraints_used = {}
|
26
26
|
@fact_types_dumped = {}
|
27
27
|
end
|
28
28
|
|
@@ -35,14 +35,14 @@ module ActiveFacts
|
|
35
35
|
$stderr.puts "Usage:\t\tafgen --scala[=option,option] input_file.cql\n"+
|
36
36
|
"\t\tmeta\t\tModify the mapping to suit a metamodel"
|
37
37
|
exit 0
|
38
|
-
|
39
|
-
|
38
|
+
when /^meta/
|
39
|
+
@is_metamodel = true
|
40
40
|
else super
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
def fact_type_name(fact_type)
|
45
|
-
|
45
|
+
fact_type.default_reading.words
|
46
46
|
end
|
47
47
|
|
48
48
|
def vocabulary_start
|
@@ -52,7 +52,7 @@ module ActiveFacts
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def vocabulary_end
|
55
|
-
|
55
|
+
puts @vocabulary.scala_finale
|
56
56
|
puts "#{@metamodel}\n}\n"
|
57
57
|
end
|
58
58
|
|
@@ -60,9 +60,9 @@ module ActiveFacts
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def value_type_dump(o, super_type_name, facets)
|
63
|
-
|
63
|
+
puts o.scala_definition(super_type_name, facets)
|
64
64
|
|
65
|
-
|
65
|
+
@metamodel << o.scala_metamodel(super_type_name, facets)
|
66
66
|
end
|
67
67
|
|
68
68
|
def id_role_names o, id_roles
|
@@ -85,57 +85,57 @@ module ActiveFacts
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def all_identifying_roles(o)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
95
|
identifying_role_refs = pi.role_sequence.all_role_ref_in_order
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
103
|
end
|
104
104
|
|
105
105
|
def entity_object(o, title_name, id_names, id_types)
|
106
|
-
|
106
|
+
puts o.scala_object(title_name, id_names, id_types)
|
107
107
|
end
|
108
108
|
|
109
109
|
def entity_trait(o, title_name, primary_supertype, pis)
|
110
|
-
|
110
|
+
puts o.scala_trait(title_name, primary_supertype, pis)
|
111
111
|
end
|
112
112
|
|
113
113
|
def entity_model(o, title_name)
|
114
|
-
|
114
|
+
@metamodel << o.scala_metamodel(title_name)
|
115
115
|
end
|
116
116
|
|
117
117
|
def non_subtype_dump(o, pi)
|
118
|
-
|
118
|
+
subtype_dump(o, nil, pi)
|
119
119
|
end
|
120
120
|
|
121
121
|
def subtype_dump(o, supertypes, pi = nil)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
122
|
+
if supertypes
|
123
|
+
primary_supertype = o && (o.identifying_supertype || o.supertypes[0])
|
124
|
+
end
|
125
|
+
title_name = o.name.words.titlecase
|
126
126
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
131
|
|
132
|
-
|
133
|
-
|
134
|
-
|
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
135
|
|
136
|
-
|
136
|
+
entity_trait(o, title_name, primary_supertype, pis)
|
137
137
|
|
138
|
-
|
138
|
+
entity_model(o, title_name)
|
139
139
|
|
140
140
|
@constraints_used[pi] = true if pi
|
141
141
|
end
|
@@ -149,31 +149,31 @@ module ActiveFacts
|
|
149
149
|
end
|
150
150
|
|
151
151
|
def skip_fact_type(f)
|
152
|
-
|
152
|
+
f.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
153
153
|
end
|
154
154
|
|
155
155
|
# Dump one fact type.
|
156
156
|
def fact_type_dump(fact_type, name)
|
157
157
|
@fact_types_dumped[fact_type] = true
|
158
|
-
|
158
|
+
return objectified_fact_type_dump(fact_type.entity_type) if fact_type.entity_type
|
159
159
|
|
160
|
-
|
160
|
+
puts fact_type.scala_definition
|
161
161
|
|
162
|
-
|
162
|
+
@metamodel << fact_type.scala_metamodel
|
163
163
|
end
|
164
164
|
|
165
165
|
def objectified_fact_type_dump o
|
166
|
-
|
167
|
-
|
166
|
+
puts o.scala_objectification
|
167
|
+
@metamodel << o.scala_objectification_metamodel
|
168
168
|
end
|
169
169
|
|
170
170
|
def unary_dump(role, role_name)
|
171
|
-
|
172
|
-
|
171
|
+
scala_role_name = role_name.words.camelcase
|
172
|
+
puts " val #{scala_role_name}: Boolean"
|
173
173
|
end
|
174
174
|
|
175
175
|
def role_dump(role)
|
176
|
-
|
176
|
+
puts role.scala_role_definition
|
177
177
|
end
|
178
178
|
|
179
179
|
end
|