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.
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
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
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
4
+ before_install: gem install bundler -v 1.10.0.rc
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,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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)