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,57 @@
|
|
1
|
+
module ActiveFacts
|
2
|
+
module Generators
|
3
|
+
module Rails
|
4
|
+
module Helpers
|
5
|
+
def rails_plural_name name
|
6
|
+
# Crunch spaces and pluralise the first part, all in snake_case
|
7
|
+
name.pop if name.is_a?(Array) and name.last == []
|
8
|
+
name = name[0]*'_' if name.is_a?(Array) and name.size == 1
|
9
|
+
if name.is_a?(Array)
|
10
|
+
name = ActiveSupport::Inflector.tableize((name[0]*'_').gsub(/\s+/, '_')) +
|
11
|
+
'_' +
|
12
|
+
ActiveSupport::Inflector.underscore((name[1..-1].flatten*'_').gsub(/\s+/, '_'))
|
13
|
+
else
|
14
|
+
ActiveSupport::Inflector.tableize(name.gsub(/\s+/, '_'))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def rails_singular_name name
|
19
|
+
# Crunch spaces and convert to snake_case
|
20
|
+
name = name.flatten*'_' if name.is_a?(Array)
|
21
|
+
ActiveSupport::Inflector.underscore(name.gsub(/\s+/, '_'))
|
22
|
+
end
|
23
|
+
|
24
|
+
def rails_class_name name
|
25
|
+
name = name*'_' if name.is_a?(Array)
|
26
|
+
ActiveSupport::Inflector.camelize(name.gsub(/\s+/, '_'))
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module Metamodel
|
34
|
+
class ObjectType
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module RMap
|
39
|
+
class ForeignKey
|
40
|
+
include Generate::Rails::Helpers
|
41
|
+
|
42
|
+
def rails_from_association_name
|
43
|
+
rails_singular_name(to_name.join('_'))
|
44
|
+
end
|
45
|
+
|
46
|
+
def rails_to_association
|
47
|
+
jump = jump_reference
|
48
|
+
if jump.is_one_to_one
|
49
|
+
[ "has_one", rails_singular_name(from_name)]
|
50
|
+
else
|
51
|
+
[ "has_many", rails_plural_name(from_name)]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,462 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Generators.
|
3
|
+
#
|
4
|
+
# Generate a glossary in HTML
|
5
|
+
#
|
6
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
7
|
+
#
|
8
|
+
require 'activefacts/api'
|
9
|
+
require 'activefacts/registry'
|
10
|
+
|
11
|
+
module ActiveFacts
|
12
|
+
module Generators #:nodoc:
|
13
|
+
class HTML #:nodoc:
|
14
|
+
class GLOSSARY #:nodoc:
|
15
|
+
# Base class for generators of object-oriented class libraries for an ActiveFacts vocabulary.
|
16
|
+
def initialize(vocabulary, *options)
|
17
|
+
@vocabulary = vocabulary
|
18
|
+
@vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
|
19
|
+
options.each{|option| set_option(option) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_option(option)
|
23
|
+
@gen_bootstrap = false
|
24
|
+
case option
|
25
|
+
when 'help', '?'
|
26
|
+
$stderr.puts "Usage:\t\tafgen --html/glossary[=option] input_file.cql\n"+
|
27
|
+
"\t\tbootstrap\tGenerate bootstrap styled glossary html"
|
28
|
+
exit 0
|
29
|
+
when /bootstrap/
|
30
|
+
@gen_bootstrap = true
|
31
|
+
else super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def puts(*a)
|
36
|
+
@out.puts *a
|
37
|
+
end
|
38
|
+
|
39
|
+
def print(*a)
|
40
|
+
@out.print *a
|
41
|
+
end
|
42
|
+
|
43
|
+
def generate(out = $>)
|
44
|
+
@out = out
|
45
|
+
|
46
|
+
@all_object_type =
|
47
|
+
@vocabulary.
|
48
|
+
all_object_type.
|
49
|
+
sort_by{|o| o.name.gsub(/ /,'').downcase}
|
50
|
+
|
51
|
+
vocabulary_start
|
52
|
+
|
53
|
+
if @gen_bootstrap
|
54
|
+
object_types_dump_toc()
|
55
|
+
object_types_dump_def()
|
56
|
+
else
|
57
|
+
object_types_dump_def()
|
58
|
+
object_types_dump_toc()
|
59
|
+
end
|
60
|
+
vocabulary_end
|
61
|
+
end
|
62
|
+
|
63
|
+
def vocabulary_start
|
64
|
+
if !@gen_bootstrap
|
65
|
+
# puts "<link rel='stylesheet' href='css/orm2.css' media='screen' type='text/css'/>"
|
66
|
+
css_file = "/../../../../css/orm2.css"
|
67
|
+
|
68
|
+
File.open(File.dirname(__FILE__)+css_file) do |f|
|
69
|
+
puts "<style media='screen' type='text/css'>"
|
70
|
+
puts f.read
|
71
|
+
puts %Q{
|
72
|
+
.glossary-facttype, .glossary-constraints { display: block; }
|
73
|
+
.glossary-doc.hide-alternates .glossary-alternates { display: none; }
|
74
|
+
.glossary-doc.hide-constraints .glossary-constraints { display: none; }
|
75
|
+
.glossary-doc.hide-examples .glossary-example { display: none; }
|
76
|
+
}.gsub(/^\s+/, '')
|
77
|
+
puts "</style>"
|
78
|
+
end
|
79
|
+
|
80
|
+
puts %Q{
|
81
|
+
<style media='print' type='text/css'>
|
82
|
+
.keyword { color: #0000CC; font-style: italic; display: inline; }
|
83
|
+
.vocabulary, .object_type { color: #8A0092; font-weight: bold; }
|
84
|
+
.copula { color: #0E5400; }
|
85
|
+
.value { color: #FF990E; display: inline; }
|
86
|
+
.glossary-toc { display: none; }
|
87
|
+
.glossary-facttype, .glossary-reading { display: inline; }
|
88
|
+
</style>
|
89
|
+
}.gsub(/^\s+/, '')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def vocabulary_end
|
94
|
+
if !@gen_bootstrap
|
95
|
+
puts %Q{
|
96
|
+
<script type="text/javascript">
|
97
|
+
function toggle_class(e, c) {
|
98
|
+
if (!e) return;
|
99
|
+
var n = e.className;
|
100
|
+
var i = n.indexOf(c);
|
101
|
+
if (i == -1) {
|
102
|
+
e.className = n+' '+c;
|
103
|
+
} else {
|
104
|
+
e.className = n.slice(0, i)+n.slice(i+c.length);
|
105
|
+
}
|
106
|
+
if (document.location.toString().indexOf('#') >= 0)
|
107
|
+
document.location = document.location; // Re-scroll to the current fragment
|
108
|
+
}
|
109
|
+
function toggle_constraints() {
|
110
|
+
toggle_class(document.getElementById('glossary-doc'), 'hide-constraints');
|
111
|
+
}
|
112
|
+
function toggle_alternates() {
|
113
|
+
toggle_class(document.getElementById('glossary-doc'), 'hide-alternates');
|
114
|
+
}
|
115
|
+
function toggle_examples() {
|
116
|
+
toggle_class(document.getElementById('glossary-doc'), 'hide-examples');
|
117
|
+
}
|
118
|
+
</script>
|
119
|
+
}.gsub(/^\s+/, '')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def object_types_dump_toc
|
124
|
+
if @gen_bootstrap
|
125
|
+
puts '<div class="col-md-3 glossary-sidebar">'
|
126
|
+
else
|
127
|
+
puts '<div class="glossary-sidebar">'
|
128
|
+
end
|
129
|
+
puts '<h1 style="visibility: hidden">X</h1>'
|
130
|
+
puts '<ol class="glossary-toc">'
|
131
|
+
@all_object_type.
|
132
|
+
reject do |o|
|
133
|
+
o.name == '_ImplicitBooleanValueType' or
|
134
|
+
o.kind_of?(ActiveFacts::Metamodel::ValueType) && o.all_role.size == 0 or
|
135
|
+
o.kind_of?(ActiveFacts::Metamodel::TypeInheritance)
|
136
|
+
end.
|
137
|
+
each do |o|
|
138
|
+
puts "<li>#{termref(o.name)}</li>"
|
139
|
+
end
|
140
|
+
puts '</ol>'
|
141
|
+
puts '<div class="glossary-controls">'
|
142
|
+
puts ' <input type="button" onclick="toggle_constraints()" value="Constraints" class="glossary-toggle-constraint">'
|
143
|
+
puts ' <input type="button" onclick="toggle_alternates()" value="Alternates" class="glossary-toggle-alternates">'
|
144
|
+
puts ' <input type="button" onclick="toggle_examples()" value="Examples" class="glossary-toggle-examples">'
|
145
|
+
puts '</div>'
|
146
|
+
puts '</div>'
|
147
|
+
end
|
148
|
+
|
149
|
+
def object_types_dump_def
|
150
|
+
if @gen_bootstrap
|
151
|
+
puts '<div class="col-md-5 glossary-doc hide-alternates hide-constraints" id="glossary-doc">'
|
152
|
+
else
|
153
|
+
puts '<div class="glossary-doc hide-alternates hide-constraints" id="glossary-doc">'
|
154
|
+
end
|
155
|
+
puts "<h1>#{@vocabulary.name}</h1>"
|
156
|
+
puts '<dl>'
|
157
|
+
@all_object_type.
|
158
|
+
each do |o|
|
159
|
+
case o
|
160
|
+
when ActiveFacts::Metamodel::TypeInheritance
|
161
|
+
nil
|
162
|
+
when ActiveFacts::Metamodel::ValueType
|
163
|
+
value_type_dump(o)
|
164
|
+
else
|
165
|
+
if o.fact_type
|
166
|
+
objectified_fact_type_dump(o)
|
167
|
+
else
|
168
|
+
entity_type_dump(o)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
puts '</dl>'
|
173
|
+
puts '</div>'
|
174
|
+
end
|
175
|
+
|
176
|
+
def element(text, attrs, tag = 'span')
|
177
|
+
"<#{tag}#{attrs.empty? ? '' : attrs.map{|k,v| " #{k}='#{v}'"}*''}>#{text}</#{tag}>"
|
178
|
+
end
|
179
|
+
|
180
|
+
def span(text, klass = nil)
|
181
|
+
element(text, klass ? {:class => klass} : {})
|
182
|
+
end
|
183
|
+
|
184
|
+
def div(text, klass = nil)
|
185
|
+
element(text, klass ? {:class => klass} : {}, 'div')
|
186
|
+
end
|
187
|
+
|
188
|
+
def h1(text, klass = nil)
|
189
|
+
element(text, klass ? {:class => klass} : {}, 'h1')
|
190
|
+
end
|
191
|
+
|
192
|
+
def dl(text, klass = nil)
|
193
|
+
element(text, klass ? {:class => klass} : {}, 'dl')
|
194
|
+
end
|
195
|
+
|
196
|
+
# A definition of a term
|
197
|
+
def termdef(name)
|
198
|
+
element(name, {:name => name, :class => 'object_type'}, 'a')
|
199
|
+
end
|
200
|
+
|
201
|
+
# A reference to a defined term (excluding role adjectives)
|
202
|
+
def termref(name, role_name = nil)
|
203
|
+
role_name ||= name
|
204
|
+
element(role_name, {:href=>'#'+name, :class=>:object_type}, 'a')
|
205
|
+
end
|
206
|
+
|
207
|
+
# Text that should appear as part of a term (including role adjectives)
|
208
|
+
def term(name)
|
209
|
+
element(name, :class=>:object_type)
|
210
|
+
end
|
211
|
+
|
212
|
+
def value_type_dump(o)
|
213
|
+
return if o.all_role.size == 0 or # Skip value types that are only used as supertypes
|
214
|
+
o.name == '_ImplicitBooleanValueType'
|
215
|
+
puts " <dt>" +
|
216
|
+
"#{termdef(o.name)} " +
|
217
|
+
(if o.supertype
|
218
|
+
span('is written as ', :keyword) + termref(o.supertype.name)
|
219
|
+
else
|
220
|
+
" (a fundamental data type)"
|
221
|
+
end) +
|
222
|
+
"</dt>"
|
223
|
+
|
224
|
+
puts " <dd>"
|
225
|
+
value_sub_types(o)
|
226
|
+
relevant_facts_and_constraints(o)
|
227
|
+
values(o)
|
228
|
+
puts " </dd>"
|
229
|
+
end
|
230
|
+
|
231
|
+
def value_sub_types(o)
|
232
|
+
o.
|
233
|
+
all_value_type_as_supertype. # All value types for which o is a supertype
|
234
|
+
sort_by{|sub| sub.name}.
|
235
|
+
each do |sub|
|
236
|
+
puts div(
|
237
|
+
"#{termref(sub.name)} #{span('is written as', 'keyword')} #{termref(o.name)}",
|
238
|
+
'glossary-facttype'
|
239
|
+
)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def values(o)
|
244
|
+
o.all_instance.
|
245
|
+
sort_by{|i|
|
246
|
+
[i.population.name, i.value.literal]
|
247
|
+
}.
|
248
|
+
each do |i|
|
249
|
+
v = i.value
|
250
|
+
puts div(
|
251
|
+
(i.population.name.empty? ? '' : i.population.name+': ') +
|
252
|
+
termref(o.name) + ' ' +
|
253
|
+
div(
|
254
|
+
# v.is_literal_string ? v.literal.inspect : v.literal,
|
255
|
+
v.literal.inspect,
|
256
|
+
'value'
|
257
|
+
),
|
258
|
+
'glossary-example'
|
259
|
+
)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def relevant_facts_and_constraints(o)
|
264
|
+
puts(
|
265
|
+
o.
|
266
|
+
all_role.
|
267
|
+
map{|r| r.fact_type}.
|
268
|
+
uniq.
|
269
|
+
reject do |ft|
|
270
|
+
ft.is_a?(ActiveFacts::Metamodel::LinkFactType)
|
271
|
+
end.
|
272
|
+
map { |ft| [ft, " #{fact_type_with_constraints(ft, o)}"] }.
|
273
|
+
sort_by{|ft, text|
|
274
|
+
[ ft.is_a?(ActiveFacts::Metamodel::TypeInheritance) ? 0 : 1, text]
|
275
|
+
}.
|
276
|
+
map{|ft, text| text}.
|
277
|
+
join "\n"
|
278
|
+
)
|
279
|
+
end
|
280
|
+
|
281
|
+
def role_ref(rr, freq_con, l_adj, name, t_adj, role_name_def, literal)
|
282
|
+
term_parts = [l_adj, termref(name), t_adj].compact
|
283
|
+
[
|
284
|
+
freq_con ? element(freq_con, :class=>:keyword) : nil,
|
285
|
+
term_parts.size > 1 ? term([l_adj, termref(name), t_adj].compact*' ') : term_parts[0],
|
286
|
+
role_name_def,
|
287
|
+
literal
|
288
|
+
]
|
289
|
+
end
|
290
|
+
|
291
|
+
def expand_reading(reading, include_rolenames = true)
|
292
|
+
element(
|
293
|
+
reading.expand([], include_rolenames) do |rr, freq_con, l_adj, name, t_adj, role_name_def, literal|
|
294
|
+
if role_name_def
|
295
|
+
role_name_def = role_name_def.gsub(/\(as ([^)]+)\)/) {
|
296
|
+
span("(as #{ termref(rr.role.object_type.name, $1) })", 'keyword')
|
297
|
+
}
|
298
|
+
end
|
299
|
+
role_ref rr, freq_con, l_adj, name, t_adj, role_name_def, literal
|
300
|
+
end,
|
301
|
+
{:class => 'copula'}
|
302
|
+
)
|
303
|
+
end
|
304
|
+
|
305
|
+
def fact_type_block(ft, include_alternates = true, wrt = nil, include_rolenames = true)
|
306
|
+
div(fact_type(ft, include_alternates, wrt, include_rolenames), 'glossary-facttype')
|
307
|
+
end
|
308
|
+
|
309
|
+
def fact_type(ft, include_alternates = true, wrt = nil, include_rolenames = true)
|
310
|
+
role = ft.all_role.detect{|r| r.object_type == wrt}
|
311
|
+
preferred_reading = ft.reading_preferably_starting_with_role(role)
|
312
|
+
alternate_readings = ft.all_reading.reject{|r| r == preferred_reading}
|
313
|
+
|
314
|
+
div(
|
315
|
+
expand_reading(preferred_reading, include_rolenames),
|
316
|
+
'glossary-reading'
|
317
|
+
)+
|
318
|
+
(if include_alternates and alternate_readings.size > 0
|
319
|
+
div(
|
320
|
+
"(alternatively: " +
|
321
|
+
alternate_readings.map do |reading|
|
322
|
+
div(
|
323
|
+
expand_reading(reading, include_rolenames),
|
324
|
+
'glossary-reading'
|
325
|
+
)
|
326
|
+
end*",\n"+')',
|
327
|
+
'glossary-alternates'
|
328
|
+
)
|
329
|
+
else
|
330
|
+
''
|
331
|
+
end
|
332
|
+
)
|
333
|
+
end
|
334
|
+
|
335
|
+
def fact_type_with_constraints(ft, wrt = nil)
|
336
|
+
if ft.entity_type
|
337
|
+
div(
|
338
|
+
termref(ft.entity_type.name) +
|
339
|
+
div(' is where ', 'keyword') +
|
340
|
+
fact_type(ft, true, wrt),
|
341
|
+
'glossary-objectification'
|
342
|
+
)
|
343
|
+
else
|
344
|
+
fact_type_block(ft, true, wrt)
|
345
|
+
end +
|
346
|
+
%Q{\n<ul class="glossary-constraints">\n}+
|
347
|
+
(unless ft.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
348
|
+
fact_type_constraints(ft)
|
349
|
+
else
|
350
|
+
''
|
351
|
+
end) +
|
352
|
+
"</ul>"
|
353
|
+
end
|
354
|
+
|
355
|
+
def fact_type_constraints(ft)
|
356
|
+
ft.internal_presence_constraints.map do |pc|
|
357
|
+
residual_role = ft.all_role.detect{|r| !pc.role_sequence.all_role_ref.detect{|rr| rr.role == r}}
|
358
|
+
next nil unless residual_role
|
359
|
+
reading = ft.all_reading.detect{|reading|
|
360
|
+
reading.role_sequence.all_role_ref_in_order[reading.role_numbers[-1]].role == residual_role
|
361
|
+
}
|
362
|
+
next nil unless reading
|
363
|
+
div(
|
364
|
+
element(
|
365
|
+
reading.expand_with_final_presence_constraint { |*a| role_ref(*a) },
|
366
|
+
{:class => 'copula'}
|
367
|
+
),
|
368
|
+
'glossary-constraint'
|
369
|
+
)+"\n"
|
370
|
+
end.compact*''
|
371
|
+
end
|
372
|
+
|
373
|
+
def objectified_fact_type_dump(o)
|
374
|
+
puts " <dt>" +
|
375
|
+
"#{termdef(o.name)}" +
|
376
|
+
# " (#{span('in which', 'keyword')} #{fact_type(o.fact_type, false, nil, nil)})" +
|
377
|
+
"</dt>"
|
378
|
+
# REVISIT: Handle separate identification
|
379
|
+
|
380
|
+
puts " <dd>"
|
381
|
+
puts fact_type_with_constraints(o.fact_type)
|
382
|
+
|
383
|
+
o.fact_type.all_role_in_order.each do |r|
|
384
|
+
n = r.object_type.name
|
385
|
+
puts div("#{termref(o.name)} involves #{span('one', 'keyword')} #{termref(r.role_name || n, n)}", "glossary-facttype")
|
386
|
+
end
|
387
|
+
relevant_facts_and_constraints(o)
|
388
|
+
puts " </dd>"
|
389
|
+
end
|
390
|
+
|
391
|
+
def entity_type_dump(o)
|
392
|
+
pi = o.preferred_identifier
|
393
|
+
supers = o.supertypes
|
394
|
+
if (supers.size > 0) # Ignore identification by a supertype:
|
395
|
+
pi = nil if pi && pi.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) }
|
396
|
+
end
|
397
|
+
|
398
|
+
puts " <dt>" +
|
399
|
+
"#{termdef(o.name)} " +
|
400
|
+
[
|
401
|
+
(supers.size > 0 ? "#{span('is a kind of', 'keyword')} #{supers.map{|s| termref(s.name)}*', '}" : nil),
|
402
|
+
(if pi
|
403
|
+
"#{span('is identified by', 'keyword')} " +
|
404
|
+
pi.role_sequence.all_role_ref_in_order.map do |rr|
|
405
|
+
termref(
|
406
|
+
rr.role.object_type.name,
|
407
|
+
[ rr.leading_adjective,
|
408
|
+
rr.role.role_name || rr.role.object_type.name,
|
409
|
+
rr.trailing_adjective
|
410
|
+
].compact*'-'
|
411
|
+
)
|
412
|
+
end*", "
|
413
|
+
else
|
414
|
+
nil
|
415
|
+
end)
|
416
|
+
].compact*', '
|
417
|
+
"</dt>"
|
418
|
+
|
419
|
+
puts " <dd>"
|
420
|
+
relevant_facts_and_constraints(o)
|
421
|
+
entities(o)
|
422
|
+
puts " </dd>"
|
423
|
+
end
|
424
|
+
|
425
|
+
def entities(o)
|
426
|
+
return if o.preferred_identifier.role_sequence.all_role_ref.size > 1 # REVISIT: Composite identification
|
427
|
+
o.all_instance.each do |i|
|
428
|
+
v = i.value
|
429
|
+
ii = i # The identifying instance
|
430
|
+
|
431
|
+
until v
|
432
|
+
pi = ii.object_type.preferred_identifier # ii is an Entity Type
|
433
|
+
break if pi.role_sequence.all_role_ref.size > 1 # REVISIT: Composite identification
|
434
|
+
|
435
|
+
identifying_fact_type = pi.role_sequence.all_role_ref.single.role.fact_type
|
436
|
+
# Find the role played by this instance through which it is identified:
|
437
|
+
irv = i.all_role_value.detect{|rv| rv.fact.fact_type == identifying_fact_type }
|
438
|
+
# Get the other RoleValue in what must be a binary fact type:
|
439
|
+
orv = irv.fact.all_role_value.detect{|rv| rv != irv}
|
440
|
+
ii = orv.instance
|
441
|
+
v = ii.value # Does this instance have a value? If so, we're done.
|
442
|
+
end
|
443
|
+
|
444
|
+
next unless v
|
445
|
+
puts div(
|
446
|
+
(i.population.name.empty? ? '' : i.population.name+': ') +
|
447
|
+
termref(o.name) + ' ' +
|
448
|
+
div(
|
449
|
+
# v.is_literal_string ? v.literal.inspect : v.literal,
|
450
|
+
v.literal.inspect,
|
451
|
+
'value'),
|
452
|
+
'glossary-example'
|
453
|
+
)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
ActiveFacts::Registry.generator('html/glossary', ActiveFacts::Generators::HTML::GLOSSARY)
|