activefacts-compositions 1.9.5 → 1.9.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ #
2
+ # ActiveFacts Standard SQL Schema Generator
3
+ #
4
+ # Copyright (c) 2009-2016 Clifford Heath. Read the LICENSE file.
5
+ #
6
+ require 'digest/sha1'
7
+ require 'activefacts/metamodel'
8
+ require 'activefacts/registry'
9
+ require 'activefacts/compositions'
10
+ require 'activefacts/generator/sql'
11
+
12
+ module ActiveFacts
13
+ module Generators
14
+ # Options are comma or space separated:
15
+ # * underscore
16
+ class SQL
17
+ class Server < SQL
18
+ def boolean_type
19
+ 'BOOLEAN'
20
+ end
21
+
22
+ def surrogate_type
23
+ 'BIGINT IDENTITY NOT NULL'
24
+ end
25
+
26
+ def reserved_words
27
+ @reserved_words ||= %w{
28
+ ADD ALL ALTER AND ANY AS ASC AUTHORIZATION BACKUP BEGIN
29
+ BETWEEN BREAK BROWSE BULK BY CASCADE CASE CHECK CHECKPOINT
30
+ CLOSE CLUSTERED COALESCE COLLATE COLUMN COMMIT COMPUTE
31
+ CONSTRAINT CONTAINS CONTAINSTABLE CONTINUE CONVERT CREATE
32
+ CROSS CURRENT CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP
33
+ CURRENT_USER CURSOR DATABASE DBCC DEALLOCATE DECLARE
34
+ DEFAULT DELETE DENY DESC DISK DISTINCT DISTRIBUTED DOUBLE
35
+ DROP DUMMY DUMP ELSE END ERRLVL ESCAPE EXCEPT EXEC EXECUTE
36
+ EXISTS EXIT FETCH FILE FILLFACTOR FOR FOREIGN FREETEXT
37
+ FREETEXTTABLE FROM FULL FUNCTION GOTO GRANT GROUP HAVING
38
+ HOLDLOCK IDENTITY IDENTITYCOL IDENTITY_INSERT IF IN INDEX
39
+ INNER INSERT INTERSECT INTO IS JOIN KEY KILL LEFT LIKE
40
+ LINENO LOAD NATIONAL NOCHECK NONCLUSTERED NOT NULL NULLIF
41
+ OF OFF OFFSETS ON OPEN OPENDATASOURCE OPENQUERY OPENROWSET
42
+ OPENXML OPTION OR ORDER OUTER OVER PERCENT PLAN PRECISION
43
+ PRIMARY PRINT PROC PROCEDURE PUBLIC RAISERROR READ READTEXT
44
+ RECONFIGURE REFERENCES REPLICATION RESTORE RESTRICT RETURN
45
+ REVOKE RIGHT ROLLBACK ROWCOUNT ROWGUIDCOL RULE SAVE SCHEMA
46
+ SELECT SESSION_USER SET SETUSER SHUTDOWN SOME STATISTICS
47
+ SYSTEM_USER TABLE TEXTSIZE THEN TO TOP TRAN TRANSACTION
48
+ TRIGGER TRUNCATE TSEQUAL UNION UNIQUE UPDATE UPDATETEXT
49
+ USE USER VALUES VARYING VIEW WAITFOR WHEN WHERE WHILE
50
+ WITH WRITETEXT
51
+ }
52
+ end
53
+
54
+ def go s = ''
55
+ "#{s}\nGO\n" # REVISIT: This is an SQL-Serverism. Move it to a subclass.
56
+ end
57
+ end
58
+
59
+ end
60
+ publish_generator SQL::Server
61
+ end
62
+ end
@@ -0,0 +1,98 @@
1
+ #
2
+ # ActiveFacts Compositions, Metamodel aspect to create a textual summary of a composition and its Composites
3
+ #
4
+ # Copyright (c) 2015 Clifford Heath. Read the LICENSE file.
5
+ #
6
+ require "activefacts/metamodel"
7
+ require "activefacts/compositions/names"
8
+ require "activefacts/compositions/constraints"
9
+ require "activefacts/generator"
10
+
11
+ module ActiveFacts
12
+ module Metamodel
13
+ class Composition
14
+ def summary
15
+ classify_constraints
16
+ "Summary of #{name}\n" +
17
+ all_composite.
18
+ sort_by{|composite| composite.mapping.name}.
19
+ flat_map do |composite|
20
+ composite.summary
21
+ end*''
22
+ end
23
+ end
24
+
25
+ class Composite
26
+ def summary
27
+ indices = self.all_indices_by_rank
28
+
29
+ (
30
+ [mapping.name+"\n"] +
31
+ mapping.
32
+ leaves.
33
+ reject{|leaf| leaf.is_a?(Absorption) && leaf.forward_absorption}.
34
+ flat_map do |leaf|
35
+
36
+ # Build a display of the names in this absorption path, with FK and optional indicators
37
+ path_names = leaf.path.map do |component|
38
+ is_mandatory = case component
39
+ when Indicator
40
+ false
41
+ when Absorption
42
+ component.parent_role.is_mandatory
43
+ else
44
+ true
45
+ end
46
+
47
+ if component.is_a?(Absorption) && component.foreign_key
48
+ "[#{component.name}]"
49
+ else
50
+ component.name
51
+ end +
52
+ (is_mandatory ? '' : '?')
53
+ end*'->'
54
+
55
+ # Build a symbolic representation of the index participation of this leaf
56
+ pos = 0
57
+ indexing = indices.inject([]) do |a, index|
58
+ pos += 1
59
+ if part = index.position_in_index(leaf)
60
+ a << "#{pos}.#{part}"
61
+ end
62
+ a
63
+ end
64
+ if indexing.empty?
65
+ indexing = ''
66
+ else
67
+ indexing = "[#{indexing*','}]"
68
+ end
69
+
70
+ column_name = leaf.column_name.capwords*' '
71
+ ["\t#{path_names}#{indexing} as #{column_name.inspect}\n"] +
72
+ leaf.all_leaf_constraint.map{|leaf_constraint| "\t\t### #{leaf_constraint.leaf_constraint.describe}\n"}
73
+ end +
74
+ all_local_constraint.map do |local_constraint|
75
+ "\t### #{local_constraint.local_constraint.describe}\n"
76
+ end.sort +
77
+ all_spanning_constraint.map do |spanning_constraint|
78
+ "### #{spanning_constraint.spanning_constraint.describe}\n"
79
+ end.sort
80
+
81
+ )*''
82
+ end
83
+ end
84
+ end
85
+
86
+ module Generators
87
+ class Summary
88
+ def initialize composition
89
+ @composition = composition
90
+ end
91
+
92
+ def generate
93
+ @composition.summary
94
+ end
95
+ end
96
+ publish_generator Summary
97
+ end
98
+ end
@@ -1,138 +1,158 @@
1
1
  #
2
- # ActiveFacts Compositions validator.
2
+ # ActiveFacts Compositions, Metamodel aspect to look for validation errors in a composition
3
3
  #
4
4
  # Quite a few constraints are not enforced during the construction of a composition.
5
5
  # This method does a post-validation to ensure that everything looks ok.
6
6
  #
7
7
  # Copyright (c) 2015 Clifford Heath. Read the LICENSE file.
8
8
  #
9
+ require "activefacts/metamodel"
9
10
  require "activefacts/compositions/compositor"
11
+ require "activefacts/generator"
10
12
 
11
13
  module ActiveFacts
12
- module Compositions
13
- class Compositor
14
+ module Generators
15
+ class Validate
16
+ def initialize composition, options = {}
17
+ @composition = composition
18
+ @options = options
19
+ end
20
+
21
+ def generate &b
22
+ @composition.validate &b
23
+ nil
24
+ end
25
+ end
26
+ publish_generator Validate
27
+ end
28
+
29
+ module Metamodel
30
+ class Composition
14
31
  def validate &report
32
+ trace.enable 'composition_validator'
15
33
  report ||= proc do |component, problem|
16
- raise "Problem with #{component.inspect}: #{problem}"
34
+ trace :composition_validator, "!!PROBLEM!! #{component.inspect}: #{problem}"
17
35
  end
18
36
 
19
- @composition.all_composite.each do |composite|
20
- validate_composite composite, &report
37
+ all_composite.each do |composite|
38
+ composite.validate &report
21
39
  end
22
40
  end
41
+ end
23
42
 
24
- private
25
- MM = ActiveFacts::Metamodel
26
-
27
- def validate_composite composite, &report
28
- trace :composition_validator?, "Validating #{composite.inspect}" do
29
- report.call(composite, "Has no Mapping") unless composite.mapping
30
- report.call(composite, "Mapping is not a mapping") unless composite.mapping.class == MM::Mapping
31
- report.call(composite.mapping, "Has no ObjectType") unless composite.mapping.object_type
32
- report.call(composite.mapping, "Has no Name") unless composite.mapping.name
33
- report.call(composite.mapping, "Should not have an Ordinal rank") if composite.mapping.ordinal
34
- report.call(composite.mapping, "Should not have a parent mapping") if composite.mapping.parent
35
- report.call(composite.mapping, "Should be the root of its mapping") if composite.mapping.root != composite
36
-
37
- validate_members composite.mapping, &report
38
- validate_access_paths composite, &report
43
+ class Composite
44
+ def validate &report
45
+ trace :composition_validator?, "Validating #{inspect}" do
46
+ report.call(self, "Has no Mapping") unless mapping
47
+ report.call(self, "Mapping is not a mapping") unless mapping.class == Mapping
48
+ report.call(mapping, "Has no ObjectType") unless mapping.object_type
49
+ report.call(mapping, "Has no Name") unless mapping.name
50
+ report.call(mapping, "Should not have an Ordinal rank") if mapping.ordinal
51
+ report.call(mapping, "Should not have a parent mapping") if mapping.parent
52
+ report.call(mapping, "Should be the root of its mapping") if mapping.root != self
53
+
54
+ mapping.validate_members &report
55
+ validate_access_paths &report
56
+ end
57
+ end
58
+
59
+ def validate_access_paths &report
60
+ all_access_path.each do |access_path|
61
+ report.call(access_path, "Must contain at least one IndexField") unless access_path.all_index_field.size > 0
62
+ access_path.all_index_field.each do |index_field|
63
+ report.call(access_path, "#{index_field.inspect} must be an Indicator or played by a ValueType") unless index_field.component.is_a?(Indicator) || index_field.component.object_type.is_a?(ValueType)
64
+ report.call(access_path, "#{index_field.inspect} must be within its composite") unless index_field.component.root == self
65
+ end
66
+ if ForeignKey === access_path
67
+ if access_path.all_index_field.size == access_path.all_foreign_key_field.size
68
+ access_path.all_index_field.to_a.zip(access_path.all_foreign_key_field.to_a).each do |index_field, foreign_key_field|
69
+ report.call(access_path, "#{index_field.inspect} must have matching target type") unless index_field.component.class == foreign_key_field.component.class
70
+ unless index_field.component.class == foreign_key_field.component.class
71
+ report.call(access_path, "#{index_field.inspect} must have component type matching #{foreign_key_field.inspect}")
72
+ else
73
+ report.call(access_path, "#{index_field.inspect} must have matching target type") unless !index_field.component.is_a?(Absorption) or index_field.component.object_type == foreign_key_field.component.object_type
74
+ end
75
+ report.call(access_path, "#{foreign_key_field.inspect} must be within the target composite") unless foreign_key_field.component.root == access_path.source_composite
76
+ end
77
+ else
78
+ report.call(access_path, "has #{access_path.all_index_field.size} index fields but #{access_path.all_foreign_key_field.size} ForeignKeyField")
79
+ end
80
+ end
39
81
  end
40
82
  end
83
+ end
41
84
 
42
- def validate_members mapping, &report
85
+ class Mapping
86
+ def validate_members &report
43
87
  # Names (except of subtype/supertype absorption) must be unique:
44
- names = mapping.
45
- all_member.
46
- reject{|m| m.is_a?(MM::Absorption) && m.parent_role.fact_type.is_a?(MM::TypeInheritance)}.
88
+ names = all_member.
89
+ reject{|m| m.is_a?(Absorption) && m.parent_role.fact_type.is_a?(TypeInheritance)}.
47
90
  map(&:name).
48
91
  compact
49
92
  duplicate_names = names.select{|name| names.count(name) > 1}.uniq
50
- report.call(mapping, "Contains duplicated names #{duplicate_names.map(&:inspect)*', '}") unless duplicate_names.empty?
93
+ report.call(self, "Contains duplicated names #{duplicate_names.map(&:inspect)*', '}") unless duplicate_names.empty?
51
94
 
52
- mapping.all_member.each do |member|
95
+ all_member.each do |member|
53
96
  trace :composition_validator?, "Validating #{member.inspect}" do
54
- report.call(member, "Requires a name") unless MM::Absorption === member && member.flattens or member.name && !member.name.empty?
97
+ report.call(member, "Requires a name") unless Absorption === member && member.flattens or member.name && !member.name.empty?
55
98
  case member
56
- when MM::Absorption
99
+ when Absorption
57
100
  p = member.parent_role
58
101
  c = member.child_role
59
102
  report.call(member, "Roles should belong to the same fact type, but instead we have #{p.name} in #{p.fact_type.default_reading} and #{c.name} in #{c.fact_type.default_reading}") unless p.fact_type == c.fact_type
60
103
  report.call(member, "Object type #{member.object_type.name} should play the child role #{c.name}") unless member.object_type == c.object_type
61
- report.call(member, "Parent mapping object type #{mapping.object_type.name} should play the parent role #{p.name}") unless mapping.object_type == p.object_type
62
-
63
- validate_reverse member, &report
64
- validate_nesting member, &report if member.all_nesting.size > 0
104
+ report.call(member, "Parent mapping object type #{object_type.name} should play the parent role #{p.name}") unless object_type == p.object_type
65
105
 
66
- validate_members member, &report
106
+ member.validate_reverse &report
107
+ member.validate_nesting &report if member.all_nesting.size > 0
108
+ member.validate_members &report
67
109
 
68
- when MM::Scoping
110
+ when Scoping
69
111
  report.call(member, "REVISIT: Unexpected and unchecked Scoping")
70
112
 
71
- when MM::ValueField
113
+ when ValueField
72
114
  # Nothing to check here
73
115
 
74
- when MM::SurrogateKey
116
+ when SurrogateKey
75
117
  # Nothing to check here
76
118
 
77
- when MM::Injection
119
+ when Injection
78
120
  report.call(member, "REVISIT: Unexpected and unchecked Injection")
79
121
 
80
- when MM::Mapping
122
+ when Mapping
81
123
  report.call(member, "A child Component should not be a bare Mapping")
82
124
 
83
- when MM::Indicator
125
+ when Indicator
84
126
  report.call(member, "Indicator requires a Role") unless member.role
85
127
 
86
- when MM::Discriminator
128
+ when Discriminator
87
129
  report.call(member, "Discriminator requires at least one Discriminated Role") if member.all_discriminated_role.empty?
88
130
  member.all_discriminated_role.each do |role|
89
- report.call(member, "Discriminated Role #{role.name} is not played by parent object type #{mapping.object_type.name}") unless role.object_type == mapping.object_type
131
+ report.call(member, "Discriminated Role #{role.name} is not played by parent object type #{object_type.name}") unless role.object_type == object_type
90
132
  end
91
133
  # REVISIT: Discriminated Roles must have distinct values matching the type of the Role
92
134
  end
93
135
  end
94
136
  end
95
137
  end
138
+ end
96
139
 
97
- def validate_reverse absorption, &report
98
- reverse = absorption.forward_absorption || absorption.reverse_absorption
140
+ class Absorption
141
+ def validate_reverse &report
142
+ reverse = forward_absorption || reverse_absorption
99
143
  return unless reverse
100
- report.call(absorption, "Opposite absorption's child role #{reverse.child_role.name} should match parent role #{absorption.parent_role.name}") unless reverse.child_role == absorption.parent_role
101
- report.call(absorption, "Opposite absorption's parent role #{reverse.parent_role.name} should match child role #{absorption.child_role.name}") unless reverse.parent_role == absorption.child_role
144
+ report.call(self, "Opposite absorption's child role #{reverse.child_role.name} should match parent role #{parent_role.name}") unless reverse.child_role == parent_role
145
+ report.call(self, "Opposite absorption's parent role #{reverse.parent_role.name} should match child role #{child_role.name}") unless reverse.parent_role == child_role
102
146
  end
103
147
 
104
- def validate_nesting absorption, &report
105
- report.call(absorption, "REVISIT: Unexpected and unchecked Nesting")
106
- report.call(absorption, "Nesting Mode must be specified") unless absorption.nesting_mode
148
+ def validate_nesting &report
149
+ report.call(self, "REVISIT: Unexpected and unchecked Nesting")
150
+ report.call(self, "Nesting Mode must be specified") unless self.nesting_mode
107
151
  # REVISIT: Nesting names must be unique
108
152
  # REVISIT: Nesting roles must be played by...
109
153
  # REVISIT: Nesting roles must be value types
110
154
  end
111
-
112
- def validate_access_paths composite, &report
113
- composite.all_access_path.each do |access_path|
114
- report.call(access_path, "Must contain at least one IndexField") unless access_path.all_index_field.size > 0
115
- access_path.all_index_field.each do |index_field|
116
- report.call(access_path, "#{index_field.inspect} must be an Indicator or played by a ValueType") unless index_field.component.is_a?(MM::Indicator) || index_field.component.object_type.is_a?(MM::ValueType)
117
- report.call(access_path, "#{index_field.inspect} must be within its composite") unless index_field.component.root == composite
118
- end
119
- if MM::ForeignKey === access_path
120
- if access_path.all_index_field.size == access_path.all_foreign_key_field.size
121
- access_path.all_index_field.to_a.zip(access_path.all_foreign_key_field.to_a).each do |index_field, foreign_key_field|
122
- report.call(access_path, "#{index_field.inspect} must have matching target type") unless index_field.component.class == foreign_key_field.component.class
123
- unless index_field.component.class == foreign_key_field.component.class
124
- report.call(access_path, "#{index_field.inspect} must have component type matching #{foreign_key_field.inspect}")
125
- else
126
- report.call(access_path, "#{index_field.inspect} must have matching target type") unless !index_field.component.is_a?(MM::Absorption) or index_field.component.object_type == foreign_key_field.component.object_type
127
- end
128
- report.call(access_path, "#{foreign_key_field.inspect} must be within the target composite") unless foreign_key_field.component.root == access_path.source_composite
129
- end
130
- else
131
- report.call(access_path, "has #{access_path.all_index_field.size} index fields but #{access_path.all_foreign_key_field.size} ForeignKeyField")
132
- end
133
- end
134
- end
135
- end
136
155
  end
156
+
137
157
  end
138
158
  end
@@ -0,0 +1,28 @@
1
+ #
2
+ # Enumerate files with "extension" in directories called "path" anywhere in the Ruby LOAD_PATH
3
+ #
4
+ class Loadable
5
+ def initialize path = "", extension = '.rb'
6
+ @path = path
7
+ @extension = extension
8
+ end
9
+
10
+ def enumerate
11
+ $LOAD_PATH.
12
+ flat_map do |dir|
13
+ dir_path = (dir+"/"+@path).gsub(%r{//+}, '/')
14
+ pattern = dir_path+"/**/*"+@extension
15
+ Dir[pattern].
16
+ map do |p|
17
+ p.
18
+ sub(%r{#{Regexp.escape(dir_path)}/}, '').
19
+ sub(%r{#{@extension}}, '')
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+
26
+ if __FILE__ == $0
27
+ p Loadable.new(*ARGV).enumerate
28
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activefacts-compositions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.5
4
+ version: 1.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clifford Heath
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-29 00:00:00.000000000 Z
11
+ date: 2016-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -59,7 +59,7 @@ dependencies:
59
59
  - !ruby/object:Gem::Version
60
60
  version: '3.3'
61
61
  - !ruby/object:Gem::Dependency
62
- name: activefacts-api
62
+ name: activefacts
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
@@ -67,8 +67,8 @@ dependencies:
67
67
  version: '1'
68
68
  - - ">="
69
69
  - !ruby/object:Gem::Version
70
- version: 1.9.4
71
- type: :runtime
70
+ version: '1.8'
71
+ type: :development
72
72
  prerelease: false
73
73
  version_requirements: !ruby/object:Gem::Requirement
74
74
  requirements:
@@ -77,9 +77,9 @@ dependencies:
77
77
  version: '1'
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
- version: 1.9.4
80
+ version: '1.8'
81
81
  - !ruby/object:Gem::Dependency
82
- name: activefacts-metamodel
82
+ name: activefacts-api
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
85
  - - "~>"
@@ -99,45 +99,45 @@ dependencies:
99
99
  - !ruby/object:Gem::Version
100
100
  version: 1.9.5
101
101
  - !ruby/object:Gem::Dependency
102
- name: tracing
102
+ name: activefacts-metamodel
103
103
  requirement: !ruby/object:Gem::Requirement
104
104
  requirements:
105
105
  - - "~>"
106
106
  - !ruby/object:Gem::Version
107
- version: '2'
107
+ version: '1'
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 2.0.6
110
+ version: 1.9.6
111
111
  type: :runtime
112
112
  prerelease: false
113
113
  version_requirements: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '2'
117
+ version: '1'
118
118
  - - ">="
119
119
  - !ruby/object:Gem::Version
120
- version: 2.0.6
120
+ version: 1.9.6
121
121
  - !ruby/object:Gem::Dependency
122
- name: activefacts
122
+ name: tracing
123
123
  requirement: !ruby/object:Gem::Requirement
124
124
  requirements:
125
125
  - - "~>"
126
126
  - !ruby/object:Gem::Version
127
- version: '1'
127
+ version: '2'
128
128
  - - ">="
129
129
  - !ruby/object:Gem::Version
130
- version: '1.8'
131
- type: :development
130
+ version: 2.0.6
131
+ type: :runtime
132
132
  prerelease: false
133
133
  version_requirements: !ruby/object:Gem::Requirement
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: '1'
137
+ version: '2'
138
138
  - - ">="
139
139
  - !ruby/object:Gem::Version
140
- version: '1.8'
140
+ version: 2.0.6
141
141
  - !ruby/object:Gem::Dependency
142
142
  name: activefacts-cql
143
143
  requirement: !ruby/object:Gem::Requirement
@@ -148,7 +148,7 @@ dependencies:
148
148
  - - ">="
149
149
  - !ruby/object:Gem::Version
150
150
  version: '1.8'
151
- type: :development
151
+ type: :runtime
152
152
  prerelease: false
153
153
  version_requirements: !ruby/object:Gem::Requirement
154
154
  requirements:
@@ -162,7 +162,8 @@ description: Create and represent composite schemas, schema transforms and data
162
162
  over a fact-based model
163
163
  email:
164
164
  - clifford.heath@gmail.com
165
- executables: []
165
+ executables:
166
+ - schema_compositor
166
167
  extensions: []
167
168
  extra_rdoc_files: []
168
169
  files:
@@ -178,9 +179,18 @@ files:
178
179
  - lib/activefacts/compositions.rb
179
180
  - lib/activefacts/compositions/binary.rb
180
181
  - lib/activefacts/compositions/compositor.rb
182
+ - lib/activefacts/compositions/constraints.rb
183
+ - lib/activefacts/compositions/names.rb
181
184
  - lib/activefacts/compositions/relational.rb
182
- - lib/activefacts/compositions/validator.rb
183
185
  - lib/activefacts/compositions/version.rb
186
+ - lib/activefacts/generator.rb
187
+ - lib/activefacts/generator/oo.rb
188
+ - lib/activefacts/generator/ruby.rb
189
+ - lib/activefacts/generator/sql.rb
190
+ - lib/activefacts/generator/sql/server.rb
191
+ - lib/activefacts/generator/summary.rb
192
+ - lib/activefacts/generator/validate.rb
193
+ - lib/activefacts/loadable.rb
184
194
  homepage: https://github.com/cjheath/activefacts-compositions
185
195
  licenses:
186
196
  - MIT