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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e1e81fd6c874b5767f07dcb7d2f508f1be29c693
|
4
|
+
data.tar.gz: 497cfd7d1abc379b424acdb3e61b4c2b19de4589
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 59851db95c25eba970ebb3da980838a2394a0de66d1fc8a24c004e002defbf87641f627e9be3e70f4abfa23e40ae02ce52cfe266f80cca47c2e40d1289cc1e99
|
7
|
+
data.tar.gz: f08d307b0a39c6dab0a6b267da237d04a45b3d820163da87fe90e9fe168971e128b232285dff8cd7e3664a17850d029203f33827194e7d598fad6ca5c7884527
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--format documentation
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in activefacts-generators.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
if ENV['PWD'] =~ %r{\A/Users/cjh/work/activefacts}
|
7
|
+
gem 'activefacts-api', path: '/Users/cjh/work/activefacts/api'
|
8
|
+
gem 'activefacts-metamodel', path: '/Users/cjh/work/activefacts/metamodel'
|
9
|
+
# gem 'activefacts-metamodel', git: 'git://github.com/cjheath/activefacts-metamodel.git'
|
10
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Clifford Heath
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Activefacts::Generators
|
2
|
+
|
3
|
+
Code generators for the ActiveFacts fact modeling suite, including the Constellation Query Language
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'activefacts-generators'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
After installation, the generators appear as options in the ActiveFacts generator <i>afgen</i>. Use
|
20
|
+
|
21
|
+
$ afgen --help
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/cjheath/activefacts-generators.
|
26
|
+
|
27
|
+
## License
|
28
|
+
|
29
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
30
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "activefacts-generators"
|
7
|
+
spec.version = "1.7.1"
|
8
|
+
spec.authors = ["Clifford Heath"]
|
9
|
+
spec.email = ["clifford.heath@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = %q{Code Generators for the ActiveFacts suite}
|
12
|
+
spec.description = %q{Code generators for the ActiveFacts Fact Modeling suite, including the Constellation Query Language}
|
13
|
+
spec.homepage = "http://github.com/cjheath/activefacts-generators"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_development_dependency "bundler", "~> 1.10.a"
|
20
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
21
|
+
spec.add_development_dependency "rspec"
|
22
|
+
|
23
|
+
spec.add_runtime_dependency(%q<activefacts-metamodel>, [">= 1.7.0", "~> 1.7"])
|
24
|
+
spec.add_runtime_dependency(%q<activefacts-rmap>, [">= 1.7.0", "~> 1.7"])
|
25
|
+
spec.add_runtime_dependency(%q<activesupport>)
|
26
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module ActiveFacts
|
2
|
+
class DependencyAnalyser
|
3
|
+
def initialize enumerable, &block
|
4
|
+
@enumerable = enumerable
|
5
|
+
analyse_precursors &block
|
6
|
+
end
|
7
|
+
|
8
|
+
def analyse_precursors &block
|
9
|
+
@precursors = {}
|
10
|
+
@enumerable.each do |item|
|
11
|
+
@precursors[item] = block.call(item)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def analyse_precursors_transitive
|
16
|
+
all_precursors = proc do |item|
|
17
|
+
p = @precursors[item]
|
18
|
+
all =
|
19
|
+
p + p.map do |precursor|
|
20
|
+
p.include?(precursor) ? [] : all_precursors.call(precursor)
|
21
|
+
end.flatten
|
22
|
+
all.uniq
|
23
|
+
end
|
24
|
+
|
25
|
+
@precursors_transitive = {}
|
26
|
+
@enumerable.each do |item|
|
27
|
+
@precursors_transitive[item] = all_precursors.call(item)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def analyse_followers
|
32
|
+
@followers = Hash.new{|h, k| h[k] = [] }
|
33
|
+
@enumerable.each do |item|
|
34
|
+
@precursors[item].each do |precursor|
|
35
|
+
@followers[precursor] << item
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def analyse_chasers
|
41
|
+
analyse_precursors_transitive unless @precursors_transitive
|
42
|
+
analyse_followers unless @followers
|
43
|
+
|
44
|
+
# A follower is an object with us as a precursor, that has no new precursors of its own
|
45
|
+
@chasers = {}
|
46
|
+
@enumerable.each do |item|
|
47
|
+
@chasers[item] =
|
48
|
+
@enumerable.select do |follower|
|
49
|
+
@precursors[follower].include?(item) and
|
50
|
+
(@precursors_transitive[follower] - @precursors_transitive[item] - [item]).size == 0
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def tsort &block
|
56
|
+
analyse_precursors unless @precursors
|
57
|
+
emitted = {}
|
58
|
+
pass = 0
|
59
|
+
until emitted.size == @enumerable.size
|
60
|
+
next_items = []
|
61
|
+
blocked =
|
62
|
+
@enumerable.inject({}) do |hash, item|
|
63
|
+
next hash if emitted[item]
|
64
|
+
blockers = item.precursors.select{|precursor| !emitted[precursor]}
|
65
|
+
if blockers.size > 0
|
66
|
+
hash[item] = blockers
|
67
|
+
else
|
68
|
+
next_items << item
|
69
|
+
end
|
70
|
+
hash
|
71
|
+
end
|
72
|
+
return blocked if next_items.size == 0 # Cannot make progress
|
73
|
+
# puts "PASS #{pass += 1}"
|
74
|
+
next_items.each do |item|
|
75
|
+
block.call(item)
|
76
|
+
emitted[item] = true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def each &b
|
83
|
+
if block_given?
|
84
|
+
@enumerable.each { |item| yield item}
|
85
|
+
else
|
86
|
+
@enumerable
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def precursors item = nil, &b
|
91
|
+
analyse_precursors unless @precursors
|
92
|
+
if item
|
93
|
+
if block_given?
|
94
|
+
Array(@precursors[item]).each { |precursor| yield precursor, item }
|
95
|
+
else
|
96
|
+
Array(@precursors[item])
|
97
|
+
end
|
98
|
+
else
|
99
|
+
@enumerable.each do |item|
|
100
|
+
precursors(item, &b)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def precursors_transitive item, &b
|
106
|
+
analyse_precursors_transitive unless @precursors_transitive
|
107
|
+
if item
|
108
|
+
if block_given?
|
109
|
+
Array(@precursors_transitive[item]).each { |precursor| yield precursor, item }
|
110
|
+
else
|
111
|
+
Array(@precursors_transitive[item])
|
112
|
+
end
|
113
|
+
else
|
114
|
+
@enumerable.each do |item|
|
115
|
+
precursors_transitive(item, &b)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def followers item = nil, &b
|
121
|
+
analyse_followers unless @followers
|
122
|
+
if item
|
123
|
+
if block_given?
|
124
|
+
Array(@followers[item]).each { |follower| yield follower, item }
|
125
|
+
else
|
126
|
+
Array(@followers[item])
|
127
|
+
end
|
128
|
+
else
|
129
|
+
@enumerable.each do |item|
|
130
|
+
followers(item, &b)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def chasers item, &b
|
136
|
+
analyse_chasers unless @chasers
|
137
|
+
if item
|
138
|
+
if block_given?
|
139
|
+
Array(@chasers[item]).each { |follower| yield follower, item }
|
140
|
+
else
|
141
|
+
Array(@chasers[item])
|
142
|
+
end
|
143
|
+
else
|
144
|
+
@enumerable.each do |item|
|
145
|
+
follower(item, &b)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Compute the page rank of the objects
|
151
|
+
# If used, the block shold return the starting weight
|
152
|
+
def page_rank damping = 0.85, &weight
|
153
|
+
weight ||= proc {|item| 1.0}
|
154
|
+
|
155
|
+
@total = 0
|
156
|
+
@rank = {}
|
157
|
+
@enumerable.each do |item|
|
158
|
+
@total +=
|
159
|
+
(@rank[item] = weight.call(item) * 1.0)
|
160
|
+
end
|
161
|
+
# Normalize:
|
162
|
+
@enumerable.each do |item|
|
163
|
+
@rank[item] /= @total
|
164
|
+
end
|
165
|
+
|
166
|
+
50.times do |iteration|
|
167
|
+
@enumerable.each do |item|
|
168
|
+
links = (precursors(item) + followers(item)).uniq
|
169
|
+
linked_rank = links.map do |l|
|
170
|
+
onward_links = (precursors(l) + followers(l)).uniq || @enumerable.size
|
171
|
+
@rank[l] / onward_links.size
|
172
|
+
end.inject(&:+) || 0
|
173
|
+
@rank[item] = (1.0-damping) + damping*linked_rank
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
@rank
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Generators.
|
3
|
+
# Absorption generator.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
|
+
#
|
7
|
+
require 'activefacts/metamodel'
|
8
|
+
require 'activefacts/rmap'
|
9
|
+
require 'activefacts/registry'
|
10
|
+
|
11
|
+
module ActiveFacts
|
12
|
+
module Generators
|
13
|
+
# Emit the absorption (Relational summary) for vocabulary.
|
14
|
+
# Not currently working, it relies on the old relational composition code.
|
15
|
+
# Invoke as
|
16
|
+
# afgen --absorption[=options] <file>.cql"
|
17
|
+
# Options are comma or space separated:
|
18
|
+
# * no_columns Don't emit the columns
|
19
|
+
# * all Show ObjectTypes that are not tables as well
|
20
|
+
# * paths Show the references paths through which each column was defined
|
21
|
+
# * no_identifier Don't show the identified_by columns for an EntityType
|
22
|
+
|
23
|
+
class Absorption
|
24
|
+
def initialize(vocabulary, *options) #:nodoc:
|
25
|
+
@vocabulary = vocabulary
|
26
|
+
@vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
|
27
|
+
@no_columns = options.include? "no_columns"
|
28
|
+
@paths = options.include? "paths"
|
29
|
+
@no_identifier = options.include? "no_identifier"
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate(out = $>) #:nodoc:
|
33
|
+
@out = out
|
34
|
+
no_absorption = 0
|
35
|
+
single_absorption_vts = 0
|
36
|
+
single_absorption_ets = 0
|
37
|
+
multi_absorption_vts = 0
|
38
|
+
multi_absorption_ets = 0
|
39
|
+
@vocabulary.tables
|
40
|
+
@vocabulary.all_object_type.sort_by{|c| c.name}.each do |o|
|
41
|
+
next if !o.is_table
|
42
|
+
show(o)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def show object_type #:nodoc:
|
47
|
+
indices = object_type.indices
|
48
|
+
pk = indices.select(&:is_primary)[0]
|
49
|
+
indices = indices.clone
|
50
|
+
indices.delete pk
|
51
|
+
@out.puts "#{object_type.name}: #{
|
52
|
+
# "[#{object_type.indices.size} indices] "
|
53
|
+
# } #{
|
54
|
+
object_type.columns.sort_by do |column|
|
55
|
+
column.name(nil)
|
56
|
+
end.map do |column|
|
57
|
+
index_nrs =
|
58
|
+
[pk && pk.columns.include?(column) ? "*" : nil] +
|
59
|
+
(0...indices.size).select{|i| indices[i].columns.include?(column)}.map{|i| (i+1).to_i }
|
60
|
+
index_nrs.compact!
|
61
|
+
(@paths ? column.references.map{|r| r.to_names}.flatten : column.name(nil)) * '.' +
|
62
|
+
(index_nrs.empty? ? "" : "["+index_nrs*""+"]")
|
63
|
+
end*", "
|
64
|
+
}"
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
ActiveFacts::Registry.generator('absorption', ActiveFacts::Generators::Absorption)
|
@@ -0,0 +1,119 @@
|
|
1
|
+
#
|
2
|
+
# ActiveFacts Generators.
|
3
|
+
# Generate a Relational Composition (for activefacts/composition).
|
4
|
+
#
|
5
|
+
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
6
|
+
#
|
7
|
+
require 'activefacts/metamodel'
|
8
|
+
require 'activefacts/generators/helpers/inject'
|
9
|
+
require 'activefacts/rmap'
|
10
|
+
require 'activefacts/generators/traits/ruby'
|
11
|
+
require 'activefacts/registry'
|
12
|
+
|
13
|
+
module ActiveFacts
|
14
|
+
module Generators
|
15
|
+
# afgen --composition[=options] <file>.cql
|
16
|
+
# Options are comma or space separated:
|
17
|
+
class Composition #:nodoc:
|
18
|
+
private
|
19
|
+
include RMap
|
20
|
+
|
21
|
+
def initialize(vocabulary, *options)
|
22
|
+
@vocabulary = vocabulary
|
23
|
+
@vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
|
24
|
+
@underscore = options.include?("underscore") ? "_" : ""
|
25
|
+
end
|
26
|
+
|
27
|
+
def puts s
|
28
|
+
@out.puts s
|
29
|
+
end
|
30
|
+
|
31
|
+
public
|
32
|
+
def generate(out = $>) #:nodoc:
|
33
|
+
@out = out
|
34
|
+
|
35
|
+
tables_emitted = {}
|
36
|
+
|
37
|
+
puts "require '#{@vocabulary.name}'"
|
38
|
+
puts "require 'activefacts/composition'"
|
39
|
+
puts "\n#{@vocabulary.name}_ER = ActiveFacts::Composition.new(#{@vocabulary.name}) do"
|
40
|
+
@vocabulary.tables.each do |table|
|
41
|
+
puts " composite :\"#{table.name.gsub(' ',@underscore)}\" do"
|
42
|
+
|
43
|
+
pk = table.identifier_columns
|
44
|
+
identity_column = pk[0] if pk[0].is_auto_assigned
|
45
|
+
|
46
|
+
fk_refs = table.references_from.select{|ref| ref.is_simple_reference }
|
47
|
+
fk_columns = table.columns.select do |column|
|
48
|
+
column.references[0].is_simple_reference
|
49
|
+
end
|
50
|
+
|
51
|
+
columns =
|
52
|
+
table.columns.map do |column|
|
53
|
+
[column, column.references.map{|r| r.to_names }]
|
54
|
+
end.sort_by do |column, refnames|
|
55
|
+
refnames
|
56
|
+
end
|
57
|
+
previous_flattening = []
|
58
|
+
ref_prefix = []
|
59
|
+
columns.each do |column, refnames|
|
60
|
+
ref_prefix = column.references[0...previous_flattening.size]
|
61
|
+
# Pop back. Not a succinct algorithm, but easy to check
|
62
|
+
while previous_flattening.size > ref_prefix.size
|
63
|
+
previous_flattening.pop
|
64
|
+
puts ' '+' '*previous_flattening.size+"end\n"
|
65
|
+
end
|
66
|
+
while ref_prefix.size > 0 and previous_flattening != ref_prefix
|
67
|
+
previous_flattening.pop
|
68
|
+
ref_prefix.pop
|
69
|
+
puts ' '+' '*previous_flattening.size+"end\n"
|
70
|
+
end
|
71
|
+
loop do
|
72
|
+
ref = column.references[ref_prefix.size]
|
73
|
+
if ref.is_self_value
|
74
|
+
# REVISIT: I think these should be 'insert :value, :as => "XYZ"'
|
75
|
+
role_name = "value".snakecase
|
76
|
+
reading = "Intrinsic value of #{role_name}"
|
77
|
+
elsif ref.is_to_objectified_fact
|
78
|
+
# REVISIT: It's ugly to have to handle these special cases here
|
79
|
+
role_name = ref.to.name.words.snakecase
|
80
|
+
reading = ref.from_role.link_fact_type.default_reading
|
81
|
+
else
|
82
|
+
if ref.is_unary && ref.is_from_objectified_fact && ref != column.references.last
|
83
|
+
# Use the name of the objectification on the path to other absorbed fact types:
|
84
|
+
role_name = ref.to_role.fact_type.entity_type.name.words.snakecase
|
85
|
+
else
|
86
|
+
role_name = ref.to_role.preferred_role_name
|
87
|
+
end
|
88
|
+
# puts ">>>>> #{ref.inspect}: #{role_name} <<<<<<"
|
89
|
+
reading = ref.fact_type.default_reading
|
90
|
+
end
|
91
|
+
if ref == column.references.last
|
92
|
+
# REVISIT: Avoid the "as" here when the value is implied by the role_name:
|
93
|
+
puts ' '+' '*ref_prefix.size+"nest :#{role_name}, :as => \"#{column.name}\"\t\t# #{reading}"
|
94
|
+
break
|
95
|
+
else
|
96
|
+
puts ' '+' '*ref_prefix.size+"flatten :#{role_name} do\t\t# #{reading}"
|
97
|
+
ref_prefix.push ref
|
98
|
+
end
|
99
|
+
end
|
100
|
+
previous_flattening = ref_prefix
|
101
|
+
end
|
102
|
+
|
103
|
+
while previous_flattening.size > 0
|
104
|
+
previous_flattening.pop
|
105
|
+
puts ' '+' '*previous_flattening.size+"end\n"
|
106
|
+
end
|
107
|
+
puts " end\n\n"
|
108
|
+
|
109
|
+
tables_emitted[table] = true
|
110
|
+
|
111
|
+
end
|
112
|
+
puts "end\n"
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
ActiveFacts::Registry.generator('composition', ActiveFacts::Generators::Composition)
|