activefacts-generators 1.7.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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +30 -0
- data/Rakefile +6 -0
- data/activefacts-generators.gemspec +26 -0
- data/lib/activefacts/dependency_analyser.rb +182 -0
- data/lib/activefacts/generators/absorption.rb +71 -0
- data/lib/activefacts/generators/composition.rb +119 -0
- data/lib/activefacts/generators/cql.rb +715 -0
- data/lib/activefacts/generators/diagrams/json.rb +340 -0
- data/lib/activefacts/generators/help.rb +64 -0
- data/lib/activefacts/generators/helpers/inject.rb +16 -0
- data/lib/activefacts/generators/helpers/oo.rb +162 -0
- data/lib/activefacts/generators/helpers/ordered.rb +605 -0
- data/lib/activefacts/generators/helpers/rails.rb +57 -0
- data/lib/activefacts/generators/html/glossary.rb +462 -0
- data/lib/activefacts/generators/metadata/json.rb +204 -0
- data/lib/activefacts/generators/null.rb +32 -0
- data/lib/activefacts/generators/rails/models.rb +247 -0
- data/lib/activefacts/generators/rails/schema.rb +217 -0
- data/lib/activefacts/generators/ruby.rb +134 -0
- data/lib/activefacts/generators/sql/mysql.rb +281 -0
- data/lib/activefacts/generators/sql/server.rb +274 -0
- data/lib/activefacts/generators/stats.rb +70 -0
- data/lib/activefacts/generators/text.rb +29 -0
- data/lib/activefacts/generators/traits/datavault.rb +241 -0
- data/lib/activefacts/generators/traits/oo.rb +73 -0
- data/lib/activefacts/generators/traits/ordered.rb +33 -0
- data/lib/activefacts/generators/traits/ruby.rb +210 -0
- data/lib/activefacts/generators/transform/datavault.rb +303 -0
- data/lib/activefacts/generators/transform/surrogate.rb +215 -0
- data/lib/activefacts/registry.rb +11 -0
- metadata +176 -0
@@ -0,0 +1,340 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Generators.
|
3
|
+
# Generate json output from a vocabulary, for loading into APRIMO
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
|
+
#
|
7
|
+
require 'json'
|
8
|
+
require 'digest/sha1'
|
9
|
+
require 'activefacts/registry'
|
10
|
+
|
11
|
+
module ActiveFacts
|
12
|
+
module Generators
|
13
|
+
module Diagrams
|
14
|
+
# Generate json output from a vocabulary, for loading into APRIMO.
|
15
|
+
# Invoke as
|
16
|
+
# afgen --diagrams/json <file>.cql=diagrams
|
17
|
+
class JSON
|
18
|
+
private
|
19
|
+
def initialize(vocabulary)
|
20
|
+
@vocabulary = vocabulary
|
21
|
+
@vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
|
22
|
+
end
|
23
|
+
|
24
|
+
def puts(*a)
|
25
|
+
@out.puts *a
|
26
|
+
end
|
27
|
+
|
28
|
+
public
|
29
|
+
def generate(out = $>)
|
30
|
+
@out = out
|
31
|
+
uuids = {}
|
32
|
+
|
33
|
+
puts "{ model: '#{@vocabulary.name}',\n" +
|
34
|
+
"diagrams: [\n#{
|
35
|
+
@vocabulary.all_diagram.sort_by{|o| o.name.gsub(/ /,'')}.map do |d|
|
36
|
+
j = {:uuid => (uuids[d] ||= uuid_from_id(d)), :name => d.name}
|
37
|
+
" #{j.to_json}"
|
38
|
+
end*",\n"
|
39
|
+
}\n ],"
|
40
|
+
|
41
|
+
object_types = @vocabulary.all_object_type.sort_by{|o| o.name.gsub(/ /,'')}
|
42
|
+
puts " object_types: [\n#{
|
43
|
+
object_types.sort_by{|o|o.identifying_role_values.inspect}.map do |o|
|
44
|
+
uuids[o] ||= uuid_from_id(o)
|
45
|
+
ref_mode = nil
|
46
|
+
if o.is_a?(ActiveFacts::Metamodel::EntityType) and
|
47
|
+
p = o.preferred_identifier and
|
48
|
+
(rrs = p.role_sequence.all_role_ref).size == 1 and
|
49
|
+
(r = rrs.single.role).fact_type != o.fact_type and
|
50
|
+
r.object_type.is_a?(ActiveFacts::Metamodel::ValueType) and
|
51
|
+
!r.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
52
|
+
ref_mode = "#{r.object_type.name}"
|
53
|
+
ref_mode.sub!(%r{#{o.name} *}, '.')
|
54
|
+
end
|
55
|
+
j = {
|
56
|
+
:uuid => uuids[o],
|
57
|
+
:name => o.name,
|
58
|
+
:shapes => o.all_object_type_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
|
59
|
+
x = { :diagram => uuids[shape.orm_diagram],
|
60
|
+
:is_expanded => shape.is_expanded,
|
61
|
+
:uuid => uuid_from_id(shape),
|
62
|
+
:x => shape.location.x,
|
63
|
+
:y => shape.location.y
|
64
|
+
}
|
65
|
+
x[:is_expanded] = true if ref_mode && shape.is_expanded # Don't show the reference mode
|
66
|
+
x
|
67
|
+
end
|
68
|
+
}
|
69
|
+
j[:ref_mode] = ref_mode if ref_mode
|
70
|
+
j[:independent] = true if o.is_independent
|
71
|
+
|
72
|
+
if o.is_a?(ActiveFacts::Metamodel::EntityType)
|
73
|
+
# Entity Type may be objectified, and may have supertypes:
|
74
|
+
if o.fact_type
|
75
|
+
uuid = (uuids[o.fact_type] ||= uuid_from_id(o.fact_type))
|
76
|
+
j[:objectifies] = uuid
|
77
|
+
j[:implicit] = true if o.concept.implication_rule
|
78
|
+
end
|
79
|
+
if o.all_type_inheritance_as_subtype.size > 0
|
80
|
+
j[:supertypes] = o.
|
81
|
+
all_type_inheritance_as_subtype.
|
82
|
+
sort_by{|ti| ti.provides_identification ? 0 : 1}.
|
83
|
+
map{|ti|
|
84
|
+
[ uuids[ti.supertype] ||= uuid_from_id(ti.supertype),
|
85
|
+
uuids[ti.supertype_role] = uuid_from_id(ti.supertype_role)
|
86
|
+
]
|
87
|
+
}
|
88
|
+
end
|
89
|
+
else
|
90
|
+
# ValueType usually has a supertype:
|
91
|
+
if (o.supertype)
|
92
|
+
j[:supertype] = (uuids[o.supertype] ||= uuid_from_id(o.supertype))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
# REVISIT: Place a ValueConstraint and shape
|
96
|
+
" #{j.to_json}"
|
97
|
+
end*",\n"
|
98
|
+
}\n ],"
|
99
|
+
|
100
|
+
fact_types = @vocabulary.constellation.
|
101
|
+
FactType.values.
|
102
|
+
reject{|ft|
|
103
|
+
ActiveFacts::Metamodel::LinkFactType === ft || ActiveFacts::Metamodel::TypeInheritance === ft
|
104
|
+
}
|
105
|
+
puts " fact_types: [\n#{
|
106
|
+
fact_types.sort_by{|f| f.identifying_role_values.inspect}.map do |f|
|
107
|
+
uuids[f] ||= uuid_from_id(f)
|
108
|
+
j = {:uuid => uuids[f]}
|
109
|
+
|
110
|
+
if f.entity_type
|
111
|
+
j[:objectified_as] = uuids[f.entity_type]
|
112
|
+
end
|
113
|
+
|
114
|
+
# Emit roles
|
115
|
+
roles = f.all_role.sort_by{|r| r.ordinal }
|
116
|
+
j[:roles] = roles.map do |role|
|
117
|
+
uuid = (uuids[role] ||= uuid_from_id(role))
|
118
|
+
# REVISIT: Internal Mandatory Constraints
|
119
|
+
# REVISIT: Place a ValueConstraint and shape
|
120
|
+
# REVISIT: Place a RoleName shape
|
121
|
+
{:uuid => uuid, :player => uuids[role.object_type]}
|
122
|
+
# N.B. The object_type shape to which this role is attached is not in the meta-model
|
123
|
+
# Attach to the closest instance on this diagram (if any)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Emit readings. Each is a [role_order, text] pair
|
127
|
+
j[:readings] = f.all_reading.map do |r|
|
128
|
+
role_refs = r.role_sequence.all_role_ref_in_order
|
129
|
+
[
|
130
|
+
role_order(uuids, role_refs.map{|rr| rr.role}, roles),
|
131
|
+
r.text.gsub(/\{([0-9])\}/) do |insert|
|
132
|
+
role_ref = role_refs[$1.to_i]
|
133
|
+
la = role_ref.leading_adjective
|
134
|
+
la = nil if la == ''
|
135
|
+
ta = role_ref.trailing_adjective
|
136
|
+
ta = nil if ta == ''
|
137
|
+
(la ? la+'-' : '') +
|
138
|
+
(la && la.index(' ') ? ' ' : '') +
|
139
|
+
insert +
|
140
|
+
(ta && ta.index(' ') ? ' ' : '') +
|
141
|
+
(ta ? '-'+ta : '')
|
142
|
+
end
|
143
|
+
]
|
144
|
+
end.sort_by{|(ro,text)| ro }.map do |(ro,text)|
|
145
|
+
[ ro, text ]
|
146
|
+
end
|
147
|
+
|
148
|
+
# Emit shapes
|
149
|
+
j[:shapes] = f.all_fact_type_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
|
150
|
+
sj = {
|
151
|
+
:diagram => uuids[shape.orm_diagram],
|
152
|
+
:uuid => uuid_from_id(shape),
|
153
|
+
:x => shape.location.x,
|
154
|
+
:y => shape.location.y
|
155
|
+
}
|
156
|
+
|
157
|
+
# Add the role_order, if specified
|
158
|
+
if shape.all_role_display.size > 0
|
159
|
+
if shape.all_role_display.size != roles.size
|
160
|
+
raise "Invalid RoleDisplay for #{f.default_reading} in #{shape.orm_diagram.name} diagram"
|
161
|
+
end
|
162
|
+
ro = role_order(
|
163
|
+
uuids,
|
164
|
+
shape.all_role_display.sort_by{|rd| rd.ordinal }.map{|rd| rd.role },
|
165
|
+
roles
|
166
|
+
)
|
167
|
+
sj[:role_order] = ro if ro
|
168
|
+
end
|
169
|
+
|
170
|
+
# REVISIT: Place the ReadingShape
|
171
|
+
|
172
|
+
# Emit the location of the name, if objectified
|
173
|
+
if n = shape.objectified_fact_type_name_shape
|
174
|
+
sj[:name_shape] = {:x => n.location.x, :y => n.location.y}
|
175
|
+
end
|
176
|
+
sj
|
177
|
+
end
|
178
|
+
|
179
|
+
# Emit Internal Presence Constraints
|
180
|
+
f.internal_presence_constraints.to_a.sort_by{|ipc, z|
|
181
|
+
[ipc.is_preferred_identifier ? 0 : 1, ipc.is_mandatory ? 0 : 1, ipc.min_frequency || 0, ipc.max_frequency || 1_000]
|
182
|
+
}.each do |ipc|
|
183
|
+
uuid = (uuids[ipc] ||= uuid_from_id(ipc))
|
184
|
+
|
185
|
+
constraint = {
|
186
|
+
:uuid => uuid,
|
187
|
+
:min => ipc.min_frequency,
|
188
|
+
:max => ipc.max_frequency,
|
189
|
+
:is_preferred => ipc.is_preferred_identifier,
|
190
|
+
:mandatory => ipc.is_mandatory
|
191
|
+
}
|
192
|
+
|
193
|
+
# Get the role (or excluded role, for a UC)
|
194
|
+
roles = ipc.role_sequence.all_role_ref_in_order.map{|r| r.role}
|
195
|
+
if roles.size > 1 || (!ipc.is_mandatory && ipc.max_frequency == 1)
|
196
|
+
# This can be only a uniqueness constraint. Record the missing role, if any
|
197
|
+
role = (f.all_role.to_a - roles)[0]
|
198
|
+
constraint[:uniqueExcept] = uuids[role]
|
199
|
+
else
|
200
|
+
# An internal mandatory or frequency constraint applies to only one role.
|
201
|
+
# If it's also unique (max == 1), that applies on the counterpart role.
|
202
|
+
# You can also have a mandatory frequency constraint, but that applies on this role.
|
203
|
+
constraint[:role] = uuids[roles[0]]
|
204
|
+
end
|
205
|
+
(j[:constraints] ||= []) << constraint
|
206
|
+
end
|
207
|
+
|
208
|
+
# Add ring constraints
|
209
|
+
f.all_role_in_order.
|
210
|
+
map{|r| r.all_ring_constraint.to_a+r.all_ring_constraint_as_other_role.to_a }.
|
211
|
+
flatten.uniq.each do |ring|
|
212
|
+
(j[:constraints] ||= []) << {
|
213
|
+
:uuid => (uuids[ring] ||= uuid_from_id(ring)),
|
214
|
+
:shapes => ring.all_constraint_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
|
215
|
+
{ :diagram => uuids[shape.orm_diagram],
|
216
|
+
:uuid => uuid_from_id(shape),
|
217
|
+
:x => shape.location.x,
|
218
|
+
:y => shape.location.y
|
219
|
+
}
|
220
|
+
end,
|
221
|
+
:ringKind => ring.ring_type,
|
222
|
+
:roles => [uuids[ring.role], uuids[ring.other_role]]
|
223
|
+
# REVISIT: Deontic, enforcement
|
224
|
+
}
|
225
|
+
end
|
226
|
+
|
227
|
+
# REVISIT: RotationSetting
|
228
|
+
|
229
|
+
" #{j.to_json}"
|
230
|
+
end*",\n"
|
231
|
+
}\n ],"
|
232
|
+
|
233
|
+
constraints = @vocabulary.constellation.
|
234
|
+
Constraint.values
|
235
|
+
puts " constraints: [\n#{
|
236
|
+
constraints.sort_by{|c|c.identifying_role_values.inspect}.select{|c| !uuids[c]}.map do |c|
|
237
|
+
uuid = uuids[c] ||= uuid_from_id(c)
|
238
|
+
j = {
|
239
|
+
:uuid => uuid,
|
240
|
+
:type => c.class.basename,
|
241
|
+
:shapes => c.all_constraint_shape.sort_by{|s| [s.location.x, s.location.y]}.map do |shape|
|
242
|
+
{ :diagram => uuids[shape.orm_diagram],
|
243
|
+
:uuid => uuid_from_id(shape),
|
244
|
+
:x => shape.location.x,
|
245
|
+
:y => shape.location.y
|
246
|
+
}
|
247
|
+
end
|
248
|
+
}
|
249
|
+
|
250
|
+
if (c.enforcement)
|
251
|
+
# REVISIT: Deontic constraint
|
252
|
+
end
|
253
|
+
if (c.concept.all_context_note_as_relevant_concept.size > 0)
|
254
|
+
# REVISIT: Context Notes
|
255
|
+
end
|
256
|
+
|
257
|
+
case c
|
258
|
+
when ActiveFacts::Metamodel::PresenceConstraint
|
259
|
+
j[:min_frequency] = c.min_frequency
|
260
|
+
j[:max_frequency] = c.max_frequency
|
261
|
+
j[:is_mandatory] = c.is_mandatory
|
262
|
+
j[:is_preferred_identifier] = c.is_preferred_identifier
|
263
|
+
rss = [c.role_sequence.all_role_ref_in_order.map(&:role)]
|
264
|
+
|
265
|
+
# Ignore internal presence constraints on TypeInheritance fact types
|
266
|
+
next nil if !c.role_sequence.all_role_ref.
|
267
|
+
detect{|rr|
|
268
|
+
!rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
269
|
+
}
|
270
|
+
|
271
|
+
when ActiveFacts::Metamodel::RingConstraint
|
272
|
+
next nil # These are emitted with the corresponding fact type
|
273
|
+
|
274
|
+
when ActiveFacts::Metamodel::SetComparisonConstraint
|
275
|
+
rss = c.
|
276
|
+
all_set_comparison_roles.sort_by{|scr| scr.ordinal}.
|
277
|
+
map{|scr| scr.role_sequence.all_role_ref_in_order.map(&:role) }
|
278
|
+
if (ActiveFacts::Metamodel::SetExclusionConstraint === c)
|
279
|
+
j[:is_mandatory] = c.is_mandatory
|
280
|
+
end
|
281
|
+
|
282
|
+
when ActiveFacts::Metamodel::SubsetConstraint
|
283
|
+
rss = [c.subset_role_sequence, c.superset_role_sequence].
|
284
|
+
map{|rs| rs.all_role_ref_in_order.map(&:role) }
|
285
|
+
|
286
|
+
when ActiveFacts::Metamodel::ValueConstraint
|
287
|
+
next nil # REVISIT: Should have been handled elsewhere
|
288
|
+
if (c.role)
|
289
|
+
# Should have been handled as role.role_value_constraint
|
290
|
+
elsif (c.value_type)
|
291
|
+
# Should have been handled as object_type.value_constraint
|
292
|
+
end
|
293
|
+
j[:allowed_ranges] = c.all_allowed_range.map{|ar|
|
294
|
+
[ ar.value_range.minimum_bound, ar.value_range.maximum_bound ].
|
295
|
+
map{|b| [b.value.literal, b.value.unit.name, b.is_inclusive] }
|
296
|
+
}
|
297
|
+
|
298
|
+
else
|
299
|
+
raise "REVISIT: Constraint type not yet dumped to JSON"
|
300
|
+
end
|
301
|
+
|
302
|
+
# rss contains the constrained role sequences; map to uuids
|
303
|
+
j[:role_sequences] = rss.map{|rs|
|
304
|
+
rs.map do |role|
|
305
|
+
uuids[role]
|
306
|
+
end
|
307
|
+
}
|
308
|
+
|
309
|
+
" #{j.to_json}"
|
310
|
+
end.compact*",\n"
|
311
|
+
}\n ]"
|
312
|
+
|
313
|
+
puts "}"
|
314
|
+
end
|
315
|
+
|
316
|
+
def role_order(uuids, roles, order)
|
317
|
+
if (roles.size > 9)
|
318
|
+
roles.map{|r| uuids[r] }
|
319
|
+
else
|
320
|
+
roles.map{|r| order.index(r).to_s }*''
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def uuid_from_id o
|
325
|
+
irvs = o.identifying_role_values.inspect
|
326
|
+
d = Digest::SHA1.digest irvs
|
327
|
+
# $stderr.puts "#{o.class.basename}: #{irvs}"
|
328
|
+
d[0,4].unpack("H8")[0]+'-'+
|
329
|
+
d[4,2].unpack("H4")[0]+'-'+
|
330
|
+
d[6,2].unpack("H4")[0]+'-'+
|
331
|
+
d[8,2].unpack("H4")[0]+'-'+
|
332
|
+
d[10,6].unpack("H6")[0]
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
ActiveFacts::Registry.generator('diagrams/json', ActiveFacts::Generators::Diagrams::JSON)
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Generators.
|
3
|
+
# Provides help for afgen - from afgen --help
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
|
+
#
|
7
|
+
require 'activefacts/registry'
|
8
|
+
|
9
|
+
module ActiveFacts
|
10
|
+
module Generators
|
11
|
+
# Generate nothing from an ActiveFacts vocabulary. This is useful to check the file can be read ok.
|
12
|
+
# Invoke as
|
13
|
+
# afgen --null <file>.cql
|
14
|
+
class HELP
|
15
|
+
private
|
16
|
+
def initialize(vocabulary, *options)
|
17
|
+
generators = $:.
|
18
|
+
map{|path|
|
19
|
+
Dir[path+"/activefacts/generators/**/*.rb"].
|
20
|
+
reject{|p|
|
21
|
+
p =~ %r{/(transform|helpers)/}
|
22
|
+
}.
|
23
|
+
map{|p|
|
24
|
+
p.sub(%r{.*/activefacts/generators/}, '').sub(/\.rb/,'')
|
25
|
+
}
|
26
|
+
}
|
27
|
+
transformers = $:.
|
28
|
+
map{|path|
|
29
|
+
Dir[path+"/activefacts/generators/transform/**/*.rb"].
|
30
|
+
map{|p|
|
31
|
+
p.sub(%r{.*/activefacts/generators/}, '').sub(/\.rb/,'')
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
puts %Q{
|
36
|
+
Usage: afgen [ --transformer[=options] ... ] [ --generator[=options] ... ] file.inp[=options]
|
37
|
+
options are comma-separated lists. Use =help to get more information.
|
38
|
+
|
39
|
+
Available generators are:
|
40
|
+
#{generators.flatten.uniq.sort.join("\n\t")
|
41
|
+
}
|
42
|
+
|
43
|
+
Available transformers are:
|
44
|
+
#{transformers.flatten.uniq.sort.join("\n\t")
|
45
|
+
}
|
46
|
+
|
47
|
+
inp is the name of a file input handler. Available input handlers are:
|
48
|
+
#{$:.map{|path|
|
49
|
+
Dir[path+"/activefacts/input/**.rb"].map{|p|
|
50
|
+
p.sub(%r{.*/}, '').sub(/\.rb/,'')
|
51
|
+
}
|
52
|
+
}.flatten.uniq.sort.join("\n\t")
|
53
|
+
}
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
public
|
58
|
+
def generate(out = $>)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
ActiveFacts::Registry.generator('help', ActiveFacts::Generators::HELP)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'activefacts/metamodel'
|
2
|
+
|
3
|
+
module ActiveFacts
|
4
|
+
module TraitInjector
|
5
|
+
def self.included other
|
6
|
+
overlap = Metamodel.constants & other.constants
|
7
|
+
overlap.each do |const|
|
8
|
+
mix_into = Metamodel.const_get(const)
|
9
|
+
mix_in = other.const_get(const)
|
10
|
+
mix_into.instance_exec {
|
11
|
+
include(mix_in)
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Generators.
|
3
|
+
# Base class for generators of class libraries in any object-oriented language that supports the ActiveFacts API.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
|
+
#
|
7
|
+
require 'activefacts/metamodel'
|
8
|
+
require 'activefacts/generators/helpers/ordered'
|
9
|
+
require 'activefacts/generators/traits/oo'
|
10
|
+
|
11
|
+
module ActiveFacts
|
12
|
+
module Generators
|
13
|
+
|
14
|
+
module Helpers
|
15
|
+
# Base class for generators of object-oriented class libraries for an ActiveFacts vocabulary.
|
16
|
+
class OO < OrderedDumper #:nodoc:
|
17
|
+
def constraints_dump
|
18
|
+
# Stub, not needed.
|
19
|
+
end
|
20
|
+
|
21
|
+
def value_type_banner
|
22
|
+
end
|
23
|
+
|
24
|
+
def value_type_end
|
25
|
+
end
|
26
|
+
|
27
|
+
def entity_type_dump(o)
|
28
|
+
o.ordered_dumped!
|
29
|
+
pi = o.preferred_identifier
|
30
|
+
|
31
|
+
supers = o.supertypes
|
32
|
+
if (supers.size > 0)
|
33
|
+
# Ignore identification by a supertype:
|
34
|
+
pi = nil if pi && pi.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) }
|
35
|
+
subtype_dump(o, supers, pi)
|
36
|
+
else
|
37
|
+
non_subtype_dump(o, pi)
|
38
|
+
end
|
39
|
+
pi.ordered_dumped! if pi
|
40
|
+
end
|
41
|
+
|
42
|
+
# Dump the roles for an object type (excluding the roles of a fact type which is objectified)
|
43
|
+
def roles_dump(o)
|
44
|
+
o.all_role.
|
45
|
+
select{|role|
|
46
|
+
role.fact_type.all_role.size <= 2 &&
|
47
|
+
!role.fact_type.is_a?(ActiveFacts::Metamodel::LinkFactType)
|
48
|
+
}.
|
49
|
+
sort_by{|role|
|
50
|
+
other_role = role.fact_type.all_role.select{|r2| r2 != role}[0] || role
|
51
|
+
other_role.preferred_role_name(o) + ':' + role.preferred_role_name(other_role.object_type)
|
52
|
+
}.each{|role|
|
53
|
+
role_dump(role)
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def role_dump(role)
|
58
|
+
fact_type = role.fact_type
|
59
|
+
if fact_type.all_role.size == 1
|
60
|
+
unary_dump(role, role.preferred_role_name)
|
61
|
+
return
|
62
|
+
end
|
63
|
+
return if role.fact_type.entity_type
|
64
|
+
|
65
|
+
if fact_type.all_role.size != 2
|
66
|
+
# Shouldn't come here, except perhaps for an invalid model
|
67
|
+
return # ternaries and higher are always objectified
|
68
|
+
end
|
69
|
+
|
70
|
+
# REVISIT: TypeInheritance
|
71
|
+
if fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
72
|
+
# trace "Ignoring role #{role} in #{fact_type}, subtype fact type"
|
73
|
+
# REVISIT: What about secondary subtypes?
|
74
|
+
# REVISIT: What about dumping the relational mapping when using separate tables?
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
return unless role.is_functional
|
79
|
+
|
80
|
+
other_role = fact_type.all_role.select{|r| r != role}[0]
|
81
|
+
other_role_name = other_role.preferred_role_name
|
82
|
+
other_player = other_role.object_type
|
83
|
+
|
84
|
+
# It's a one_to_one if there's a uniqueness constraint on the other role:
|
85
|
+
one_to_one = other_role.is_functional
|
86
|
+
return if one_to_one &&
|
87
|
+
!other_role.object_type.ordered_dumped
|
88
|
+
|
89
|
+
# Find role name:
|
90
|
+
role_method = role.preferred_role_name
|
91
|
+
other_role_method = one_to_one ? role_method : "all_"+role_method
|
92
|
+
# puts "---"+role.role_name if role.role_name
|
93
|
+
if other_role_name != other_player.oo_default_role_name and
|
94
|
+
role_method == role.object_type.oo_default_role_name
|
95
|
+
# debugger
|
96
|
+
other_role_method += "_as_#{other_role_name}"
|
97
|
+
end
|
98
|
+
|
99
|
+
role_name = role_method
|
100
|
+
role_name = nil if role_name == role.object_type.oo_default_role_name
|
101
|
+
|
102
|
+
b = role.ruby_role_definition
|
103
|
+
puts b
|
104
|
+
|
105
|
+
# binary_dump(role, other_role_name, other_player, role.is_mandatory, one_to_one, nil, role_name, other_role_method)
|
106
|
+
end
|
107
|
+
|
108
|
+
def skip_fact_type(f)
|
109
|
+
# REVISIT: There might be constraints we have to merge into the nested entity or subtype. These will come up as un-handled constraints.
|
110
|
+
!f.entity_type ||
|
111
|
+
f.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
112
|
+
end
|
113
|
+
|
114
|
+
# An objectified fact type has internal roles that are always "has_one":
|
115
|
+
def fact_roles_dump(fact_type)
|
116
|
+
fact_type.all_role.sort_by{|role|
|
117
|
+
role.preferred_role_name(fact_type.entity_type)
|
118
|
+
}.each{|role|
|
119
|
+
role_name = role.preferred_role_name(fact_type.entity_type)
|
120
|
+
one_to_one = role.is_unique
|
121
|
+
as = role_name != role.object_type.oo_default_role_name ? "_as_#{role_name}" : ""
|
122
|
+
# debugger if as != ''
|
123
|
+
raise "Fact #{fact_type.describe} type is not objectified" unless fact_type.entity_type
|
124
|
+
other_role_method = (one_to_one ? "" : "all_") +
|
125
|
+
fact_type.entity_type.oo_default_role_name +
|
126
|
+
as
|
127
|
+
binary_dump(role, role_name, role.object_type, true, one_to_one, nil, nil, other_role_method)
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def entity_type_banner
|
132
|
+
end
|
133
|
+
|
134
|
+
def entity_type_group_end
|
135
|
+
end
|
136
|
+
|
137
|
+
def append_ring_to_reading(reading, ring)
|
138
|
+
# REVISIT: trace "Should override append_ring_to_reading"
|
139
|
+
end
|
140
|
+
|
141
|
+
def fact_type_banner
|
142
|
+
end
|
143
|
+
|
144
|
+
def fact_type_end
|
145
|
+
end
|
146
|
+
|
147
|
+
def constraint_banner
|
148
|
+
# trace "Should override constraint_banner"
|
149
|
+
end
|
150
|
+
|
151
|
+
def constraint_end
|
152
|
+
# trace "Should override constraint_end"
|
153
|
+
end
|
154
|
+
|
155
|
+
def constraint_dump(c)
|
156
|
+
# trace "Should override constraint_dump"
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|