activefacts 1.6.0 → 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 +4 -4
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +21 -0
- data/README.md +60 -0
- data/Rakefile +3 -80
- data/activefacts.gemspec +36 -0
- data/bin/afgen +4 -2
- data/bin/cql +5 -1
- data/lib/activefacts.rb +3 -12
- data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
- data/lib/activefacts/version.rb +2 -2
- metadata +48 -296
- data/History.txt +0 -4
- data/LICENSE +0 -19
- data/Manifest.txt +0 -165
- data/README.rdoc +0 -81
- data/css/offline.css +0 -3
- data/css/orm2.css +0 -124
- data/css/print.css +0 -8
- data/css/style-print.css +0 -357
- data/css/style.css +0 -387
- data/download.html +0 -110
- data/examples/CQL/Address.cql +0 -44
- data/examples/CQL/Blog.cql +0 -54
- data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
- data/examples/CQL/Death.cql +0 -17
- data/examples/CQL/Diplomacy.cql +0 -48
- data/examples/CQL/Genealogy.cql +0 -98
- data/examples/CQL/Insurance.cql +0 -320
- data/examples/CQL/Marriage.cql +0 -18
- data/examples/CQL/Metamodel.cql +0 -493
- data/examples/CQL/Monogamy.cql +0 -24
- data/examples/CQL/MultiInheritance.cql +0 -22
- data/examples/CQL/NonRoleId.cql +0 -14
- data/examples/CQL/OddIdentifier.cql +0 -18
- data/examples/CQL/OilSupply.cql +0 -53
- data/examples/CQL/OneToOnes.cql +0 -17
- data/examples/CQL/Orienteering.cql +0 -111
- data/examples/CQL/PersonPlaysGame.cql +0 -18
- data/examples/CQL/RedundantDependency.cql +0 -34
- data/examples/CQL/SchoolActivities.cql +0 -33
- data/examples/CQL/SeparateSubtype.cql +0 -30
- data/examples/CQL/ServiceDirector.cql +0 -276
- data/examples/CQL/SimplestUnary.cql +0 -12
- data/examples/CQL/Supervision.cql +0 -34
- data/examples/CQL/WaiterTips.cql +0 -33
- data/examples/CQL/Warehousing.cql +0 -101
- data/examples/CQL/WindowInRoomInBldg.cql +0 -28
- data/examples/CQL/unit.cql +0 -474
- data/examples/index.html +0 -420
- data/examples/intro.html +0 -327
- data/examples/local.css +0 -24
- data/index.html +0 -111
- data/lib/activefacts/cql.rb +0 -35
- data/lib/activefacts/cql/CQLParser.treetop +0 -158
- data/lib/activefacts/cql/Context.treetop +0 -48
- data/lib/activefacts/cql/Expressions.treetop +0 -67
- data/lib/activefacts/cql/FactTypes.treetop +0 -358
- data/lib/activefacts/cql/Language/English.treetop +0 -315
- data/lib/activefacts/cql/LexicalRules.treetop +0 -253
- data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
- data/lib/activefacts/cql/Rakefile +0 -14
- data/lib/activefacts/cql/Terms.treetop +0 -183
- data/lib/activefacts/cql/ValueTypes.treetop +0 -202
- data/lib/activefacts/cql/compiler.rb +0 -156
- data/lib/activefacts/cql/compiler/clause.rb +0 -1137
- data/lib/activefacts/cql/compiler/constraint.rb +0 -581
- data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
- data/lib/activefacts/cql/compiler/expression.rb +0 -443
- data/lib/activefacts/cql/compiler/fact.rb +0 -390
- data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
- data/lib/activefacts/cql/compiler/query.rb +0 -106
- data/lib/activefacts/cql/compiler/shared.rb +0 -161
- data/lib/activefacts/cql/compiler/value_type.rb +0 -174
- data/lib/activefacts/cql/nodes.rb +0 -49
- data/lib/activefacts/cql/parser.rb +0 -241
- data/lib/activefacts/dependency_analyser.rb +0 -182
- data/lib/activefacts/generate/absorption.rb +0 -70
- data/lib/activefacts/generate/composition.rb +0 -118
- data/lib/activefacts/generate/cql.rb +0 -714
- data/lib/activefacts/generate/dm.rb +0 -279
- data/lib/activefacts/generate/help.rb +0 -64
- data/lib/activefacts/generate/helpers/inject.rb +0 -16
- data/lib/activefacts/generate/helpers/oo.rb +0 -162
- data/lib/activefacts/generate/helpers/ordered.rb +0 -605
- data/lib/activefacts/generate/helpers/rails.rb +0 -57
- data/lib/activefacts/generate/html/glossary.rb +0 -461
- data/lib/activefacts/generate/json.rb +0 -337
- data/lib/activefacts/generate/null.rb +0 -32
- data/lib/activefacts/generate/rails/models.rb +0 -246
- data/lib/activefacts/generate/rails/schema.rb +0 -216
- data/lib/activefacts/generate/records.rb +0 -46
- data/lib/activefacts/generate/ruby.rb +0 -133
- data/lib/activefacts/generate/sql/mysql.rb +0 -280
- data/lib/activefacts/generate/sql/server.rb +0 -273
- data/lib/activefacts/generate/stats.rb +0 -69
- data/lib/activefacts/generate/text.rb +0 -27
- data/lib/activefacts/generate/topics.rb +0 -265
- data/lib/activefacts/generate/traits/datavault.rb +0 -241
- data/lib/activefacts/generate/traits/oo.rb +0 -73
- data/lib/activefacts/generate/traits/ordered.rb +0 -33
- data/lib/activefacts/generate/traits/ruby.rb +0 -210
- data/lib/activefacts/generate/transform/datavault.rb +0 -266
- data/lib/activefacts/generate/transform/surrogate.rb +0 -214
- data/lib/activefacts/generate/version.rb +0 -26
- data/lib/activefacts/input/cql.rb +0 -43
- data/lib/activefacts/input/orm.rb +0 -1636
- data/lib/activefacts/mapping/rails.rb +0 -132
- data/lib/activefacts/persistence.rb +0 -15
- data/lib/activefacts/persistence/columns.rb +0 -446
- data/lib/activefacts/persistence/foreignkey.rb +0 -187
- data/lib/activefacts/persistence/index.rb +0 -240
- data/lib/activefacts/persistence/object_type.rb +0 -198
- data/lib/activefacts/persistence/reference.rb +0 -434
- data/lib/activefacts/persistence/tables.rb +0 -380
- data/lib/activefacts/registry.rb +0 -11
- data/lib/activefacts/support.rb +0 -132
- data/lib/activefacts/vocabulary.rb +0 -9
- data/lib/activefacts/vocabulary/extensions.rb +0 -1348
- data/lib/activefacts/vocabulary/metamodel.rb +0 -570
- data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
- data/script/txt2html +0 -71
- data/spec/absorption_spec.rb +0 -95
- data/spec/cql/comparison_spec.rb +0 -89
- data/spec/cql/context_spec.rb +0 -94
- data/spec/cql/contractions_spec.rb +0 -224
- data/spec/cql/deontic_spec.rb +0 -88
- data/spec/cql/entity_type_spec.rb +0 -320
- data/spec/cql/expressions_spec.rb +0 -66
- data/spec/cql/fact_type_matching_spec.rb +0 -338
- data/spec/cql/french_spec.rb +0 -21
- data/spec/cql/parser/bad_literals_spec.rb +0 -86
- data/spec/cql/parser/constraints_spec.rb +0 -19
- data/spec/cql/parser/entity_types_spec.rb +0 -106
- data/spec/cql/parser/expressions_spec.rb +0 -199
- data/spec/cql/parser/fact_types_spec.rb +0 -44
- data/spec/cql/parser/literals_spec.rb +0 -312
- data/spec/cql/parser/pragmas_spec.rb +0 -89
- data/spec/cql/parser/value_types_spec.rb +0 -42
- data/spec/cql/role_matching_spec.rb +0 -148
- data/spec/cql/samples_spec.rb +0 -244
- data/spec/cql_cql_spec.rb +0 -73
- data/spec/cql_dm_spec.rb +0 -136
- data/spec/cql_mysql_spec.rb +0 -69
- data/spec/cql_parse_spec.rb +0 -34
- data/spec/cql_ruby_spec.rb +0 -73
- data/spec/cql_sql_spec.rb +0 -72
- data/spec/cql_symbol_tables_spec.rb +0 -261
- data/spec/cqldump_spec.rb +0 -170
- data/spec/helpers/array_matcher.rb +0 -23
- data/spec/helpers/ctrl_c_support.rb +0 -52
- data/spec/helpers/diff_matcher.rb +0 -39
- data/spec/helpers/file_matcher.rb +0 -34
- data/spec/helpers/parse_to_ast_matcher.rb +0 -80
- data/spec/helpers/string_matcher.rb +0 -30
- data/spec/helpers/test_parser.rb +0 -15
- data/spec/norma_cql_spec.rb +0 -66
- data/spec/norma_ruby_spec.rb +0 -62
- data/spec/norma_ruby_sql_spec.rb +0 -107
- data/spec/norma_sql_spec.rb +0 -57
- data/spec/norma_tables_spec.rb +0 -95
- data/spec/ruby_api_spec.rb +0 -23
- data/spec/spec_helper.rb +0 -35
- data/spec/transform_surrogate_spec.rb +0 -59
- data/status.html +0 -138
- data/why.html +0 -60
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts Schema Transform
|
|
3
|
-
# Transform a loaded ActiveFacts vocabulary to suit ActiveRecord
|
|
4
|
-
#
|
|
5
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
6
|
-
#
|
|
7
|
-
require 'activefacts/generate/helpers/inject'
|
|
8
|
-
|
|
9
|
-
module ActiveFacts
|
|
10
|
-
module Generate
|
|
11
|
-
module DataVaultTraits
|
|
12
|
-
|
|
13
|
-
module ObjectType
|
|
14
|
-
|
|
15
|
-
def dv_add_surrogate type_name = 'Auto Counter', suffix = 'ID'
|
|
16
|
-
# Find or assert the surrogate value type
|
|
17
|
-
auto_counter = vocabulary.valid_value_type_name(type_name) ||
|
|
18
|
-
constellation.ValueType(:vocabulary => vocabulary, :name => type_name, :concept => :new)
|
|
19
|
-
|
|
20
|
-
# Create a subtype to identify this entity type:
|
|
21
|
-
vt_name = self.name + ' '+suffix
|
|
22
|
-
my_id = @vocabulary.valid_value_type_name(vt_name) ||
|
|
23
|
-
constellation.ValueType(:vocabulary => vocabulary, :name => vt_name, :concept => :new, :supertype => auto_counter)
|
|
24
|
-
|
|
25
|
-
# Create a fact type
|
|
26
|
-
identifying_fact_type = constellation.FactType(:concept => :new)
|
|
27
|
-
my_role = constellation.Role(:concept => :new, :fact_type => identifying_fact_type, :ordinal => 0, :object_type => self)
|
|
28
|
-
self.injected_surrogate_role = my_role
|
|
29
|
-
id_role = constellation.Role(:concept => :new, :fact_type => identifying_fact_type, :ordinal => 1, :object_type => my_id)
|
|
30
|
-
|
|
31
|
-
# Create a reading (which needs a RoleSequence)
|
|
32
|
-
reading = constellation.Reading(
|
|
33
|
-
:fact_type => identifying_fact_type,
|
|
34
|
-
:ordinal => 0,
|
|
35
|
-
:role_sequence => [:new],
|
|
36
|
-
:text => "{0} has {1}"
|
|
37
|
-
)
|
|
38
|
-
constellation.RoleRef(:role_sequence => reading.role_sequence, :ordinal => 0, :role => my_role)
|
|
39
|
-
constellation.RoleRef(:role_sequence => reading.role_sequence, :ordinal => 1, :role => id_role)
|
|
40
|
-
|
|
41
|
-
# Create two uniqueness constraints for the one-to-one. Each needs a RoleSequence (two RoleRefs)
|
|
42
|
-
one_id = constellation.PresenceConstraint(
|
|
43
|
-
:concept => :new,
|
|
44
|
-
:vocabulary => vocabulary,
|
|
45
|
-
:name => self.name+'HasOne'+suffix,
|
|
46
|
-
:role_sequence => [:new],
|
|
47
|
-
:is_mandatory => true,
|
|
48
|
-
:min_frequency => 1,
|
|
49
|
-
:max_frequency => 1,
|
|
50
|
-
:is_preferred_identifier => false
|
|
51
|
-
)
|
|
52
|
-
@constellation.RoleRef(:role_sequence => one_id.role_sequence, :ordinal => 0, :role => my_role)
|
|
53
|
-
|
|
54
|
-
one_me = constellation.PresenceConstraint(
|
|
55
|
-
:concept => :new,
|
|
56
|
-
:vocabulary => vocabulary,
|
|
57
|
-
:name => self.name+suffix+'IsOfOne'+self.name,
|
|
58
|
-
:role_sequence => [:new],
|
|
59
|
-
:is_mandatory => false,
|
|
60
|
-
:min_frequency => 0,
|
|
61
|
-
:max_frequency => 1,
|
|
62
|
-
:is_preferred_identifier => true
|
|
63
|
-
)
|
|
64
|
-
@constellation.RoleRef(:role_sequence => one_me.role_sequence, :ordinal => 0, :role => id_role)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
module ValueType
|
|
69
|
-
def dv_needs_surrogate
|
|
70
|
-
!is_auto_assigned
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def dv_inject_surrogate
|
|
74
|
-
trace :transform_surrogate, "Adding surrogate ID to Value Type #{name}"
|
|
75
|
-
add_surrogate('Auto Counter', 'ID')
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
module EntityType
|
|
80
|
-
def dv_identifying_refs_from
|
|
81
|
-
pi = preferred_identifier
|
|
82
|
-
rrs = pi.role_sequence.all_role_ref
|
|
83
|
-
|
|
84
|
-
# REVISIT: This is actually a ref to us, not from
|
|
85
|
-
# if absorbed_via
|
|
86
|
-
# return [absorbed_via]
|
|
87
|
-
# end
|
|
88
|
-
|
|
89
|
-
rrs.map do |rr|
|
|
90
|
-
r = references_from.detect{|ref| rr.role == ref.to_role }
|
|
91
|
-
unless r
|
|
92
|
-
debugger
|
|
93
|
-
raise "failed to find #{name} identifying reference for #{rr.role.object_type.name} in #{references_from.inspect}"
|
|
94
|
-
end
|
|
95
|
-
r
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def dv_needs_surrogate
|
|
100
|
-
|
|
101
|
-
# A recursive proc to replace any reference to an Entity Type by its identifying references:
|
|
102
|
-
trace :transform_surrogate_expansion, "Expanding key for #{name}"
|
|
103
|
-
substitute_identifying_refs = proc do |object|
|
|
104
|
-
if ref = object.absorbed_via
|
|
105
|
-
# This shouldn't be necessary, but see the absorbed_via comment above.
|
|
106
|
-
absorbed_into = ref.from
|
|
107
|
-
trace :transform_surrogate_expansion, "recursing to handle absorption of #{object.name} into #{absorbed_into.name}"
|
|
108
|
-
[substitute_identifying_refs.call(absorbed_into)]
|
|
109
|
-
else
|
|
110
|
-
irf = object.dv_identifying_refs_from
|
|
111
|
-
trace :transform_surrogate_expansion, "Iterating for #{object.name} over #{irf.inspect}" do
|
|
112
|
-
irf.each_with_index do |ref, i|
|
|
113
|
-
next if ref.is_unary
|
|
114
|
-
next if ref.to_role.object_type.kind_of?(ActiveFacts::Metamodel::ValueType)
|
|
115
|
-
recurse_to = ref.to_role.object_type
|
|
116
|
-
|
|
117
|
-
trace :transform_surrogate_expansion, "#{i}: recursing to expand #{recurse_to.name} key in #{ref}" do
|
|
118
|
-
irf[i] = substitute_identifying_refs.call(recurse_to)
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
irf
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
irf = substitute_identifying_refs.call(self)
|
|
126
|
-
|
|
127
|
-
trace :transform_surrogate, "Does #{name} need a surrogate? it's identified by #{irf.inspect}" do
|
|
128
|
-
|
|
129
|
-
pk_fks = dv_identifying_refs_from.map do |ref|
|
|
130
|
-
ref.to && ref.to.is_table ? ref.to : nil
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
irf.flatten!
|
|
134
|
-
|
|
135
|
-
# Multi-part identifiers are only allowed if:
|
|
136
|
-
# * each part is a foreign key (i.e. it's a join table),
|
|
137
|
-
# * there are no other columns (that might require updating) and
|
|
138
|
-
# * the object is not the target of a foreign key:
|
|
139
|
-
if irf.size >= 2
|
|
140
|
-
if pk_fks.include?(nil)
|
|
141
|
-
trace :transform_surrogate, "#{self.name} needs a surrogate because its multi-part key contains a non-table"
|
|
142
|
-
return true
|
|
143
|
-
elsif references_to.size != 0
|
|
144
|
-
trace :transform_surrogate, "#{self.name} is a join table between #{pk_fks.map(&:name).inspect} but is also an FK target"
|
|
145
|
-
return true
|
|
146
|
-
elsif (references_from-dv_identifying_refs_from).size > 0
|
|
147
|
-
# There are other attributes to worry about
|
|
148
|
-
return true
|
|
149
|
-
else
|
|
150
|
-
trace :transform_surrogate, "#{self.name} is a join table between #{pk_fks.map(&:name).inspect}"
|
|
151
|
-
return false
|
|
152
|
-
end
|
|
153
|
-
return true
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# Single-part key. It must be an Auto Counter, or we will add a surrogate
|
|
157
|
-
|
|
158
|
-
identifying_type = irf[0].to
|
|
159
|
-
if identifying_type.dv_needs_surrogate
|
|
160
|
-
trace :transform_surrogate, "#{self.name} needs a surrogate because #{irf[0].to.name} is not an AutoCounter, but #{identifying_type.supertypes_transitive.map(&:name).inspect}"
|
|
161
|
-
return true
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
false
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def dv_inject_surrogate
|
|
169
|
-
trace :transform_surrogate, "Injecting a surrogate key into #{self.name}"
|
|
170
|
-
|
|
171
|
-
# Disable the preferred identifier:
|
|
172
|
-
pi = preferred_identifier
|
|
173
|
-
trace :transform_surrogate, "pi for #{name} was '#{pi.describe}'"
|
|
174
|
-
pi.is_preferred_identifier = false
|
|
175
|
-
@preferred_identifier = nil # Kill the cache
|
|
176
|
-
|
|
177
|
-
dv_add_surrogate
|
|
178
|
-
|
|
179
|
-
trace :transform_surrogate, "pi for #{name} is now '#{preferred_identifier.describe}'"
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def dv_add_surrogate type_name = 'Auto Counter', suffix = 'ID'
|
|
183
|
-
# Find or assert the surrogate value type
|
|
184
|
-
auto_counter = vocabulary.valid_value_type_name(type_name) ||
|
|
185
|
-
constellation.ValueType(:vocabulary => vocabulary, :name => type_name, :concept => :new)
|
|
186
|
-
|
|
187
|
-
# Create a subtype to identify this entity type:
|
|
188
|
-
vt_name = self.name + ' '+suffix
|
|
189
|
-
my_id = @vocabulary.valid_value_type_name(vt_name) ||
|
|
190
|
-
constellation.ValueType(:vocabulary => vocabulary, :name => vt_name, :concept => :new, :supertype => auto_counter)
|
|
191
|
-
|
|
192
|
-
# Create a fact type
|
|
193
|
-
identifying_fact_type = constellation.FactType(:concept => :new)
|
|
194
|
-
my_role = constellation.Role(:concept => :new, :fact_type => identifying_fact_type, :ordinal => 0, :object_type => self)
|
|
195
|
-
@injected_surrogate_role = my_role
|
|
196
|
-
id_role = constellation.Role(:concept => :new, :fact_type => identifying_fact_type, :ordinal => 1, :object_type => my_id)
|
|
197
|
-
|
|
198
|
-
# Create a reading (which needs a RoleSequence)
|
|
199
|
-
reading = constellation.Reading(
|
|
200
|
-
:fact_type => identifying_fact_type,
|
|
201
|
-
:ordinal => 0,
|
|
202
|
-
:role_sequence => [:new],
|
|
203
|
-
:text => "{0} has {1}"
|
|
204
|
-
)
|
|
205
|
-
constellation.RoleRef(:role_sequence => reading.role_sequence, :ordinal => 0, :role => my_role)
|
|
206
|
-
constellation.RoleRef(:role_sequence => reading.role_sequence, :ordinal => 1, :role => id_role)
|
|
207
|
-
|
|
208
|
-
# Create two uniqueness constraints for the one-to-one. Each needs a RoleSequence (two RoleRefs)
|
|
209
|
-
one_id = constellation.PresenceConstraint(
|
|
210
|
-
:concept => :new,
|
|
211
|
-
:vocabulary => vocabulary,
|
|
212
|
-
:name => self.name+'HasOne'+suffix,
|
|
213
|
-
:role_sequence => [:new],
|
|
214
|
-
:is_mandatory => true,
|
|
215
|
-
:min_frequency => 1,
|
|
216
|
-
:max_frequency => 1,
|
|
217
|
-
:is_preferred_identifier => false
|
|
218
|
-
)
|
|
219
|
-
@constellation.RoleRef(:role_sequence => one_id.role_sequence, :ordinal => 0, :role => my_role)
|
|
220
|
-
|
|
221
|
-
one_me = constellation.PresenceConstraint(
|
|
222
|
-
:concept => :new,
|
|
223
|
-
:vocabulary => vocabulary,
|
|
224
|
-
:name => self.name+suffix+'IsOfOne'+self.name,
|
|
225
|
-
:role_sequence => [:new],
|
|
226
|
-
:is_mandatory => false,
|
|
227
|
-
:min_frequency => 0,
|
|
228
|
-
:max_frequency => 1,
|
|
229
|
-
:is_preferred_identifier => true
|
|
230
|
-
)
|
|
231
|
-
@constellation.RoleRef(:role_sequence => one_me.role_sequence, :ordinal => 0, :role => id_role)
|
|
232
|
-
|
|
233
|
-
return my_id
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
end
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts Generators.
|
|
3
|
-
# Base class for generators of class libraries in any object-oriented language that supports the ActiveFacts API.
|
|
4
|
-
#
|
|
5
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
6
|
-
#
|
|
7
|
-
module ActiveFacts
|
|
8
|
-
module Generate
|
|
9
|
-
module OOTraits
|
|
10
|
-
module ObjectType
|
|
11
|
-
# Map the ObjectType name to an OO class name
|
|
12
|
-
def oo_type_name
|
|
13
|
-
name.words.capcase
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Map the OO class name to a default role name
|
|
17
|
-
def oo_default_role_name
|
|
18
|
-
name.words.snakecase
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
module Role
|
|
23
|
-
def oo_role_definition
|
|
24
|
-
return if fact_type.entity_type
|
|
25
|
-
|
|
26
|
-
if fact_type.all_role.size == 1
|
|
27
|
-
return " maybe :#{preferred_role_name}\n"
|
|
28
|
-
elsif fact_type.all_role.size != 2
|
|
29
|
-
# Shouldn't come here, except perhaps for an invalid model
|
|
30
|
-
return # ternaries and higher are always objectified
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# REVISIT: TypeInheritance
|
|
34
|
-
if fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
|
35
|
-
# trace "Ignoring role #{self} in #{fact_type}, subtype fact type"
|
|
36
|
-
# REVISIT: What about secondary subtypes?
|
|
37
|
-
# REVISIT: What about dumping the relational mapping when using separate tables?
|
|
38
|
-
return
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
return unless is_functional
|
|
42
|
-
|
|
43
|
-
counterpart_role = fact_type.all_role.select{|r| r != self}[0]
|
|
44
|
-
counterpart_type = counterpart_role.object_type
|
|
45
|
-
counterpart_role_name = counterpart_role.preferred_role_name
|
|
46
|
-
counterpart_type_default_role_name = counterpart_type.oo_default_role_name
|
|
47
|
-
|
|
48
|
-
# It's a one_to_one if there's a uniqueness constraint on the other role:
|
|
49
|
-
one_to_one = counterpart_role.is_functional
|
|
50
|
-
return if one_to_one &&
|
|
51
|
-
false # REVISIT: !@object_types_dumped[counterpart_role.object_type]
|
|
52
|
-
|
|
53
|
-
# Find role name:
|
|
54
|
-
role_method = preferred_role_name
|
|
55
|
-
counterpart_role_method = one_to_one ? role_method : "all_"+role_method
|
|
56
|
-
# puts "---"+role.role_name if role.role_name
|
|
57
|
-
if counterpart_role_name != counterpart_type.oo_default_role_name and
|
|
58
|
-
role_method == self.object_type.oo_default_role_name
|
|
59
|
-
# debugger
|
|
60
|
-
counterpart_role_method += "_as_#{counterpart_role_name}"
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
role_name = role_method
|
|
64
|
-
role_name = nil if role_name == object_type.oo_default_role_name
|
|
65
|
-
|
|
66
|
-
as_binary(counterpart_role_name, counterpart_type, is_mandatory, one_to_one, nil, role_name, counterpart_role_method)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts Generators.
|
|
3
|
-
# Generation support superclass that sequences entity types to avoid forward references.
|
|
4
|
-
#
|
|
5
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
6
|
-
#
|
|
7
|
-
module ActiveFacts
|
|
8
|
-
module Generate #:nodoc:
|
|
9
|
-
module OrderedTraits
|
|
10
|
-
module DumpedFlag
|
|
11
|
-
attr_reader :ordered_dumped
|
|
12
|
-
|
|
13
|
-
def ordered_dumped!
|
|
14
|
-
@ordered_dumped = true
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
module ObjectType
|
|
19
|
-
include DumpedFlag
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
module FactType
|
|
23
|
-
include DumpedFlag
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
module Constraint
|
|
27
|
-
include DumpedFlag
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# ActiveFacts Generators.
|
|
3
|
-
# Generate Ruby classes for the ActiveFacts API from an ActiveFacts vocabulary.
|
|
4
|
-
#
|
|
5
|
-
# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
|
|
6
|
-
#
|
|
7
|
-
module ActiveFacts
|
|
8
|
-
module Generate
|
|
9
|
-
module RubyTraits
|
|
10
|
-
module Vocabulary
|
|
11
|
-
def prelude
|
|
12
|
-
if @mapping == 'sql'
|
|
13
|
-
require 'activefacts/persistence'
|
|
14
|
-
@tables = self.tables
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
"require 'activefacts/api'\n" +
|
|
18
|
-
(@mapping == 'sql' ? "require 'activefacts/persistence'\n" : '') +
|
|
19
|
-
"\nmodule ::#{self.name}\n\n"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def finale
|
|
23
|
-
"end"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
module ObjectType
|
|
28
|
-
def absorbed_roles
|
|
29
|
-
all_role.
|
|
30
|
-
select do |role|
|
|
31
|
-
role.fact_type.all_role.size <= 2 &&
|
|
32
|
-
!role.fact_type.is_a?(ActiveFacts::Metamodel::LinkFactType)
|
|
33
|
-
end.
|
|
34
|
-
sort_by do |role|
|
|
35
|
-
r = role.fact_type.all_role.select{|r2| r2 != role}[0] || role
|
|
36
|
-
r.preferred_role_name(self) + ':' + role.preferred_role_name(r.object_type)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Map the ObjectType name to a Ruby class name
|
|
41
|
-
def ruby_type_name
|
|
42
|
-
oo_type_name
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Map the Ruby class name to a default role name
|
|
46
|
-
def ruby_default_role_name
|
|
47
|
-
oo_default_role_name
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def ruby_type_reference
|
|
52
|
-
if !ordered_dumped
|
|
53
|
-
'"'+name.gsub(/ /,'')+'"'
|
|
54
|
-
else
|
|
55
|
-
role_reference = name.gsub(/ /,'')
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
module Role
|
|
61
|
-
def preferred_role_name(is_for = nil, &name_builder)
|
|
62
|
-
|
|
63
|
-
if fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance)
|
|
64
|
-
# Subtype and Supertype roles default to TitleCase names, and have no role_name to worry about:
|
|
65
|
-
return (name_builder || proc {|names| names.titlecase}).call(object_type.name.words)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
name_builder ||= proc {|names| names.map(&:downcase)*'_' } # Make snake_case by default
|
|
69
|
-
|
|
70
|
-
# Handle an objectified unary role:
|
|
71
|
-
if is_for && fact_type.entity_type == is_for && fact_type.all_role.size == 1
|
|
72
|
-
return name_builder.call(object_type.name.words)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# trace "Looking for preferred_role_name of #{describe_fact_type(fact_type, self)}"
|
|
76
|
-
reading = fact_type.preferred_reading
|
|
77
|
-
preferred_role_ref = reading.role_sequence.all_role_ref.detect{|reading_rr|
|
|
78
|
-
reading_rr.role == self
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if fact_type.all_role.size == 1
|
|
82
|
-
return name_builder.call(
|
|
83
|
-
role_name ?
|
|
84
|
-
role_name.snakewords :
|
|
85
|
-
reading.text.gsub(/ *\{0\} */,' ').gsub(/[- ]+/,'_').words
|
|
86
|
-
)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
if role_name && role_name != ""
|
|
90
|
-
role_words = [role_name]
|
|
91
|
-
else
|
|
92
|
-
role_words = []
|
|
93
|
-
|
|
94
|
-
la = preferred_role_ref.leading_adjective
|
|
95
|
-
role_words += la.words.snakewords if la && la != ""
|
|
96
|
-
|
|
97
|
-
role_words += object_type.name.words.snakewords
|
|
98
|
-
|
|
99
|
-
ta = preferred_role_ref.trailing_adjective
|
|
100
|
-
role_words += ta.words.snakewords if ta && ta != ""
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# n = role_words.map{|w| w.gsub(/([a-z])([A-Z]+)/,'\1_\2').downcase}*"_"
|
|
104
|
-
n = role_words*'_'
|
|
105
|
-
# trace "\tresult=#{n}"
|
|
106
|
-
return name_builder.call(n.gsub(' ','_').split(/_/))
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def as_binary(role_name, role_player, mandatory = nil, one_to_one = nil, readings = nil, other_role_name = nil, other_method_name = nil)
|
|
110
|
-
ruby_role_name = ":"+role_name.words.snakecase
|
|
111
|
-
|
|
112
|
-
# Find whether we need the name of the other role player, and whether it's defined yet:
|
|
113
|
-
implied_role_name = role_player.name.gsub(/ /,'').sub(/^[a-z]/) {|i| i.upcase}
|
|
114
|
-
if role_name.camelcase != implied_role_name
|
|
115
|
-
# Only use Class name if it's not implied by the rolename
|
|
116
|
-
role_reference = ":class => "+role_player.ruby_type_reference
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
other_role_name = ":counterpart => :"+other_role_name.gsub(/ /,'_') if other_role_name
|
|
120
|
-
|
|
121
|
-
if vr = role_value_constraint
|
|
122
|
-
value_restriction = ":restrict => #{vr}"
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
options = [
|
|
126
|
-
ruby_role_name,
|
|
127
|
-
role_reference,
|
|
128
|
-
mandatory ? ":mandatory => true" : nil,
|
|
129
|
-
readings,
|
|
130
|
-
other_role_name,
|
|
131
|
-
value_restriction
|
|
132
|
-
].compact
|
|
133
|
-
|
|
134
|
-
debugger if ruby_role_name == 'astronomicalobject'
|
|
135
|
-
|
|
136
|
-
line = " #{one_to_one ? "one_to_one" : "has_one" } #{options*', '} "
|
|
137
|
-
if other_method_name
|
|
138
|
-
line += " "*(48-line.length) if line.length < 48
|
|
139
|
-
line += "\# See #{role_player.name.gsub(/ /,'')}.#{other_method_name}"
|
|
140
|
-
end
|
|
141
|
-
line+"\n"
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def ruby_role_definition
|
|
145
|
-
oo_role_definition
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
module ValueType
|
|
150
|
-
def ruby_definition
|
|
151
|
-
return if name == "_ImplicitBooleanValueType"
|
|
152
|
-
|
|
153
|
-
ruby_length = length && length > 0 ? ":length => #{length}" : nil
|
|
154
|
-
ruby_scale = scale && scale > 0 ? ":scale => #{scale}" : nil
|
|
155
|
-
params = [ruby_length,ruby_scale].compact * ", "
|
|
156
|
-
|
|
157
|
-
base_type = supertype || self
|
|
158
|
-
base_type_name = base_type.ruby_type_name
|
|
159
|
-
ruby_name = ruby_type_name
|
|
160
|
-
if base_type_name == ruby_name
|
|
161
|
-
base_type_name = '::'+base_type_name
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
" class #{ruby_name} < #{base_type_name}\n" +
|
|
165
|
-
" value_type #{params}\n" +
|
|
166
|
-
#emit_mapping self if is_table
|
|
167
|
-
(value_constraint ?
|
|
168
|
-
" restrict #{value_constraint.all_allowed_range_sorted.map{|ar| ar.to_s}*", "}\n" :
|
|
169
|
-
""
|
|
170
|
-
) +
|
|
171
|
-
(unit ?
|
|
172
|
-
" \# REVISIT: #{ruby_name} is in units of #{unit.name}\n" :
|
|
173
|
-
""
|
|
174
|
-
) +
|
|
175
|
-
absorbed_roles.map do |role|
|
|
176
|
-
role.ruby_role_definition
|
|
177
|
-
end.
|
|
178
|
-
compact*"" +
|
|
179
|
-
" end\n\n"
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
module FactType
|
|
184
|
-
# An objectified fact type has internal roles that are always "has_one":
|
|
185
|
-
def fact_roles
|
|
186
|
-
raise "Fact #{describe} type is not objectified" unless entity_type
|
|
187
|
-
all_role.sort_by do |role|
|
|
188
|
-
role.preferred_role_name(entity_type)
|
|
189
|
-
end.
|
|
190
|
-
map do |role|
|
|
191
|
-
role_name = role.preferred_role_name(entity_type)
|
|
192
|
-
one_to_one = role.all_role_ref.detect{|rr|
|
|
193
|
-
rr.role_sequence.all_role_ref.size == 1 &&
|
|
194
|
-
rr.role_sequence.all_presence_constraint.detect{|pc|
|
|
195
|
-
pc.max_frequency == 1
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
counterpart_role_method = (one_to_one ? "" : "all_") +
|
|
199
|
-
entity_type.oo_default_role_name +
|
|
200
|
-
(role_name != role.object_type.oo_default_role_name ? "_as_#{role_name}" : '')
|
|
201
|
-
role.as_binary(role_name, role.object_type, true, one_to_one, nil, nil, counterpart_role_method)
|
|
202
|
-
end.
|
|
203
|
-
join('')
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
include ActiveFacts::TraitInjector # Must be last in this module, after all submodules have been defined
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
end
|