activefacts-generators 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +10 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +30 -0
  8. data/Rakefile +6 -0
  9. data/activefacts-generators.gemspec +26 -0
  10. data/lib/activefacts/dependency_analyser.rb +182 -0
  11. data/lib/activefacts/generators/absorption.rb +71 -0
  12. data/lib/activefacts/generators/composition.rb +119 -0
  13. data/lib/activefacts/generators/cql.rb +715 -0
  14. data/lib/activefacts/generators/diagrams/json.rb +340 -0
  15. data/lib/activefacts/generators/help.rb +64 -0
  16. data/lib/activefacts/generators/helpers/inject.rb +16 -0
  17. data/lib/activefacts/generators/helpers/oo.rb +162 -0
  18. data/lib/activefacts/generators/helpers/ordered.rb +605 -0
  19. data/lib/activefacts/generators/helpers/rails.rb +57 -0
  20. data/lib/activefacts/generators/html/glossary.rb +462 -0
  21. data/lib/activefacts/generators/metadata/json.rb +204 -0
  22. data/lib/activefacts/generators/null.rb +32 -0
  23. data/lib/activefacts/generators/rails/models.rb +247 -0
  24. data/lib/activefacts/generators/rails/schema.rb +217 -0
  25. data/lib/activefacts/generators/ruby.rb +134 -0
  26. data/lib/activefacts/generators/sql/mysql.rb +281 -0
  27. data/lib/activefacts/generators/sql/server.rb +274 -0
  28. data/lib/activefacts/generators/stats.rb +70 -0
  29. data/lib/activefacts/generators/text.rb +29 -0
  30. data/lib/activefacts/generators/traits/datavault.rb +241 -0
  31. data/lib/activefacts/generators/traits/oo.rb +73 -0
  32. data/lib/activefacts/generators/traits/ordered.rb +33 -0
  33. data/lib/activefacts/generators/traits/ruby.rb +210 -0
  34. data/lib/activefacts/generators/transform/datavault.rb +303 -0
  35. data/lib/activefacts/generators/transform/surrogate.rb +215 -0
  36. data/lib/activefacts/registry.rb +11 -0
  37. 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)