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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +60 -0
  8. data/Rakefile +3 -80
  9. data/activefacts.gemspec +36 -0
  10. data/bin/afgen +4 -2
  11. data/bin/cql +5 -1
  12. data/lib/activefacts.rb +3 -12
  13. data/lib/activefacts/{vocabulary/query_evaluator.rb → query/evaluator.rb} +0 -0
  14. data/lib/activefacts/version.rb +2 -2
  15. metadata +48 -296
  16. data/History.txt +0 -4
  17. data/LICENSE +0 -19
  18. data/Manifest.txt +0 -165
  19. data/README.rdoc +0 -81
  20. data/css/offline.css +0 -3
  21. data/css/orm2.css +0 -124
  22. data/css/print.css +0 -8
  23. data/css/style-print.css +0 -357
  24. data/css/style.css +0 -387
  25. data/download.html +0 -110
  26. data/examples/CQL/Address.cql +0 -44
  27. data/examples/CQL/Blog.cql +0 -54
  28. data/examples/CQL/CompanyDirectorEmployee.cql +0 -56
  29. data/examples/CQL/Death.cql +0 -17
  30. data/examples/CQL/Diplomacy.cql +0 -48
  31. data/examples/CQL/Genealogy.cql +0 -98
  32. data/examples/CQL/Insurance.cql +0 -320
  33. data/examples/CQL/Marriage.cql +0 -18
  34. data/examples/CQL/Metamodel.cql +0 -493
  35. data/examples/CQL/Monogamy.cql +0 -24
  36. data/examples/CQL/MultiInheritance.cql +0 -22
  37. data/examples/CQL/NonRoleId.cql +0 -14
  38. data/examples/CQL/OddIdentifier.cql +0 -18
  39. data/examples/CQL/OilSupply.cql +0 -53
  40. data/examples/CQL/OneToOnes.cql +0 -17
  41. data/examples/CQL/Orienteering.cql +0 -111
  42. data/examples/CQL/PersonPlaysGame.cql +0 -18
  43. data/examples/CQL/RedundantDependency.cql +0 -34
  44. data/examples/CQL/SchoolActivities.cql +0 -33
  45. data/examples/CQL/SeparateSubtype.cql +0 -30
  46. data/examples/CQL/ServiceDirector.cql +0 -276
  47. data/examples/CQL/SimplestUnary.cql +0 -12
  48. data/examples/CQL/Supervision.cql +0 -34
  49. data/examples/CQL/WaiterTips.cql +0 -33
  50. data/examples/CQL/Warehousing.cql +0 -101
  51. data/examples/CQL/WindowInRoomInBldg.cql +0 -28
  52. data/examples/CQL/unit.cql +0 -474
  53. data/examples/index.html +0 -420
  54. data/examples/intro.html +0 -327
  55. data/examples/local.css +0 -24
  56. data/index.html +0 -111
  57. data/lib/activefacts/cql.rb +0 -35
  58. data/lib/activefacts/cql/CQLParser.treetop +0 -158
  59. data/lib/activefacts/cql/Context.treetop +0 -48
  60. data/lib/activefacts/cql/Expressions.treetop +0 -67
  61. data/lib/activefacts/cql/FactTypes.treetop +0 -358
  62. data/lib/activefacts/cql/Language/English.treetop +0 -315
  63. data/lib/activefacts/cql/LexicalRules.treetop +0 -253
  64. data/lib/activefacts/cql/ObjectTypes.treetop +0 -210
  65. data/lib/activefacts/cql/Rakefile +0 -14
  66. data/lib/activefacts/cql/Terms.treetop +0 -183
  67. data/lib/activefacts/cql/ValueTypes.treetop +0 -202
  68. data/lib/activefacts/cql/compiler.rb +0 -156
  69. data/lib/activefacts/cql/compiler/clause.rb +0 -1137
  70. data/lib/activefacts/cql/compiler/constraint.rb +0 -581
  71. data/lib/activefacts/cql/compiler/entity_type.rb +0 -457
  72. data/lib/activefacts/cql/compiler/expression.rb +0 -443
  73. data/lib/activefacts/cql/compiler/fact.rb +0 -390
  74. data/lib/activefacts/cql/compiler/fact_type.rb +0 -421
  75. data/lib/activefacts/cql/compiler/query.rb +0 -106
  76. data/lib/activefacts/cql/compiler/shared.rb +0 -161
  77. data/lib/activefacts/cql/compiler/value_type.rb +0 -174
  78. data/lib/activefacts/cql/nodes.rb +0 -49
  79. data/lib/activefacts/cql/parser.rb +0 -241
  80. data/lib/activefacts/dependency_analyser.rb +0 -182
  81. data/lib/activefacts/generate/absorption.rb +0 -70
  82. data/lib/activefacts/generate/composition.rb +0 -118
  83. data/lib/activefacts/generate/cql.rb +0 -714
  84. data/lib/activefacts/generate/dm.rb +0 -279
  85. data/lib/activefacts/generate/help.rb +0 -64
  86. data/lib/activefacts/generate/helpers/inject.rb +0 -16
  87. data/lib/activefacts/generate/helpers/oo.rb +0 -162
  88. data/lib/activefacts/generate/helpers/ordered.rb +0 -605
  89. data/lib/activefacts/generate/helpers/rails.rb +0 -57
  90. data/lib/activefacts/generate/html/glossary.rb +0 -461
  91. data/lib/activefacts/generate/json.rb +0 -337
  92. data/lib/activefacts/generate/null.rb +0 -32
  93. data/lib/activefacts/generate/rails/models.rb +0 -246
  94. data/lib/activefacts/generate/rails/schema.rb +0 -216
  95. data/lib/activefacts/generate/records.rb +0 -46
  96. data/lib/activefacts/generate/ruby.rb +0 -133
  97. data/lib/activefacts/generate/sql/mysql.rb +0 -280
  98. data/lib/activefacts/generate/sql/server.rb +0 -273
  99. data/lib/activefacts/generate/stats.rb +0 -69
  100. data/lib/activefacts/generate/text.rb +0 -27
  101. data/lib/activefacts/generate/topics.rb +0 -265
  102. data/lib/activefacts/generate/traits/datavault.rb +0 -241
  103. data/lib/activefacts/generate/traits/oo.rb +0 -73
  104. data/lib/activefacts/generate/traits/ordered.rb +0 -33
  105. data/lib/activefacts/generate/traits/ruby.rb +0 -210
  106. data/lib/activefacts/generate/transform/datavault.rb +0 -266
  107. data/lib/activefacts/generate/transform/surrogate.rb +0 -214
  108. data/lib/activefacts/generate/version.rb +0 -26
  109. data/lib/activefacts/input/cql.rb +0 -43
  110. data/lib/activefacts/input/orm.rb +0 -1636
  111. data/lib/activefacts/mapping/rails.rb +0 -132
  112. data/lib/activefacts/persistence.rb +0 -15
  113. data/lib/activefacts/persistence/columns.rb +0 -446
  114. data/lib/activefacts/persistence/foreignkey.rb +0 -187
  115. data/lib/activefacts/persistence/index.rb +0 -240
  116. data/lib/activefacts/persistence/object_type.rb +0 -198
  117. data/lib/activefacts/persistence/reference.rb +0 -434
  118. data/lib/activefacts/persistence/tables.rb +0 -380
  119. data/lib/activefacts/registry.rb +0 -11
  120. data/lib/activefacts/support.rb +0 -132
  121. data/lib/activefacts/vocabulary.rb +0 -9
  122. data/lib/activefacts/vocabulary/extensions.rb +0 -1348
  123. data/lib/activefacts/vocabulary/metamodel.rb +0 -570
  124. data/lib/activefacts/vocabulary/verbaliser.rb +0 -804
  125. data/script/txt2html +0 -71
  126. data/spec/absorption_spec.rb +0 -95
  127. data/spec/cql/comparison_spec.rb +0 -89
  128. data/spec/cql/context_spec.rb +0 -94
  129. data/spec/cql/contractions_spec.rb +0 -224
  130. data/spec/cql/deontic_spec.rb +0 -88
  131. data/spec/cql/entity_type_spec.rb +0 -320
  132. data/spec/cql/expressions_spec.rb +0 -66
  133. data/spec/cql/fact_type_matching_spec.rb +0 -338
  134. data/spec/cql/french_spec.rb +0 -21
  135. data/spec/cql/parser/bad_literals_spec.rb +0 -86
  136. data/spec/cql/parser/constraints_spec.rb +0 -19
  137. data/spec/cql/parser/entity_types_spec.rb +0 -106
  138. data/spec/cql/parser/expressions_spec.rb +0 -199
  139. data/spec/cql/parser/fact_types_spec.rb +0 -44
  140. data/spec/cql/parser/literals_spec.rb +0 -312
  141. data/spec/cql/parser/pragmas_spec.rb +0 -89
  142. data/spec/cql/parser/value_types_spec.rb +0 -42
  143. data/spec/cql/role_matching_spec.rb +0 -148
  144. data/spec/cql/samples_spec.rb +0 -244
  145. data/spec/cql_cql_spec.rb +0 -73
  146. data/spec/cql_dm_spec.rb +0 -136
  147. data/spec/cql_mysql_spec.rb +0 -69
  148. data/spec/cql_parse_spec.rb +0 -34
  149. data/spec/cql_ruby_spec.rb +0 -73
  150. data/spec/cql_sql_spec.rb +0 -72
  151. data/spec/cql_symbol_tables_spec.rb +0 -261
  152. data/spec/cqldump_spec.rb +0 -170
  153. data/spec/helpers/array_matcher.rb +0 -23
  154. data/spec/helpers/ctrl_c_support.rb +0 -52
  155. data/spec/helpers/diff_matcher.rb +0 -39
  156. data/spec/helpers/file_matcher.rb +0 -34
  157. data/spec/helpers/parse_to_ast_matcher.rb +0 -80
  158. data/spec/helpers/string_matcher.rb +0 -30
  159. data/spec/helpers/test_parser.rb +0 -15
  160. data/spec/norma_cql_spec.rb +0 -66
  161. data/spec/norma_ruby_spec.rb +0 -62
  162. data/spec/norma_ruby_sql_spec.rb +0 -107
  163. data/spec/norma_sql_spec.rb +0 -57
  164. data/spec/norma_tables_spec.rb +0 -95
  165. data/spec/ruby_api_spec.rb +0 -23
  166. data/spec/spec_helper.rb +0 -35
  167. data/spec/transform_surrogate_spec.rb +0 -59
  168. data/status.html +0 -138
  169. data/why.html +0 -60
@@ -1,182 +0,0 @@
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
-
@@ -1,70 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Absorption generator.
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- require 'activefacts/vocabulary'
8
- require 'activefacts/persistence'
9
-
10
- module ActiveFacts
11
- module Generate
12
- # Emit the absorption (Relational summary) for vocabulary.
13
- # Not currently working, it relies on the old relational composition code.
14
- # Invoke as
15
- # afgen --absorption[=options] <file>.cql"
16
- # Options are comma or space separated:
17
- # * no_columns Don't emit the columns
18
- # * all Show ObjectTypes that are not tables as well
19
- # * paths Show the references paths through which each column was defined
20
- # * no_identifier Don't show the identified_by columns for an EntityType
21
-
22
- class Absorption
23
- def initialize(vocabulary, *options) #:nodoc:
24
- @vocabulary = vocabulary
25
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
26
- @no_columns = options.include? "no_columns"
27
- @paths = options.include? "paths"
28
- @no_identifier = options.include? "no_identifier"
29
- end
30
-
31
- def generate(out = $>) #:nodoc:
32
- @out = out
33
- no_absorption = 0
34
- single_absorption_vts = 0
35
- single_absorption_ets = 0
36
- multi_absorption_vts = 0
37
- multi_absorption_ets = 0
38
- @vocabulary.tables
39
- @vocabulary.all_object_type.sort_by{|c| c.name}.each do |o|
40
- next if !o.is_table
41
- show(o)
42
- end
43
- end
44
-
45
- def show object_type #:nodoc:
46
- indices = object_type.indices
47
- pk = indices.select(&:is_primary)[0]
48
- indices = indices.clone
49
- indices.delete pk
50
- @out.puts "#{object_type.name}: #{
51
- # "[#{object_type.indices.size} indices] "
52
- # } #{
53
- object_type.columns.sort_by do |column|
54
- column.name(nil)
55
- end.map do |column|
56
- index_nrs =
57
- [pk && pk.columns.include?(column) ? "*" : nil] +
58
- (0...indices.size).select{|i| indices[i].columns.include?(column)}.map{|i| (i+1).to_i }
59
- index_nrs.compact!
60
- (@paths ? column.references.map{|r| r.to_names}.flatten : column.name(nil)) * '.' +
61
- (index_nrs.empty? ? "" : "["+index_nrs*""+"]")
62
- end*", "
63
- }"
64
-
65
- end
66
- end
67
- end
68
- end
69
-
70
- ActiveFacts::Registry.generator('absorption', ActiveFacts::Generate::Absorption)
@@ -1,118 +0,0 @@
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/vocabulary'
8
- require 'activefacts/generate/helpers/inject'
9
- require 'activefacts/persistence'
10
- require 'activefacts/generate/traits/ruby'
11
-
12
- module ActiveFacts
13
- module Generate
14
- # afgen --composition[=options] <file>.cql
15
- # Options are comma or space separated:
16
- class Composition #:nodoc:
17
- private
18
- include Persistence
19
-
20
- def initialize(vocabulary, *options)
21
- @vocabulary = vocabulary
22
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
23
- @underscore = options.include?("underscore") ? "_" : ""
24
- end
25
-
26
- def puts s
27
- @out.puts s
28
- end
29
-
30
- public
31
- def generate(out = $>) #:nodoc:
32
- @out = out
33
-
34
- tables_emitted = {}
35
-
36
- puts "require '#{@vocabulary.name}'"
37
- puts "require 'activefacts/composition'"
38
- puts "\n#{@vocabulary.name}_ER = ActiveFacts::Composition.new(#{@vocabulary.name}) do"
39
- @vocabulary.tables.each do |table|
40
- puts " composite :\"#{table.name.gsub(' ',@underscore)}\" do"
41
-
42
- pk = table.identifier_columns
43
- identity_column = pk[0] if pk[0].is_auto_assigned
44
-
45
- fk_refs = table.references_from.select{|ref| ref.is_simple_reference }
46
- fk_columns = table.columns.select do |column|
47
- column.references[0].is_simple_reference
48
- end
49
-
50
- columns =
51
- table.columns.map do |column|
52
- [column, column.references.map{|r| r.to_names }]
53
- end.sort_by do |column, refnames|
54
- refnames
55
- end
56
- previous_flattening = []
57
- ref_prefix = []
58
- columns.each do |column, refnames|
59
- ref_prefix = column.references[0...previous_flattening.size]
60
- # Pop back. Not a succinct algorithm, but easy to check
61
- while previous_flattening.size > ref_prefix.size
62
- previous_flattening.pop
63
- puts ' '+' '*previous_flattening.size+"end\n"
64
- end
65
- while ref_prefix.size > 0 and previous_flattening != ref_prefix
66
- previous_flattening.pop
67
- ref_prefix.pop
68
- puts ' '+' '*previous_flattening.size+"end\n"
69
- end
70
- loop do
71
- ref = column.references[ref_prefix.size]
72
- if ref.is_self_value
73
- # REVISIT: I think these should be 'insert :value, :as => "XYZ"'
74
- role_name = "value".snakecase
75
- reading = "Intrinsic value of #{role_name}"
76
- elsif ref.is_to_objectified_fact
77
- # REVISIT: It's ugly to have to handle these special cases here
78
- role_name = ref.to.name.words.snakecase
79
- reading = ref.from_role.link_fact_type.default_reading
80
- else
81
- if ref.is_unary && ref.is_from_objectified_fact && ref != column.references.last
82
- # Use the name of the objectification on the path to other absorbed fact types:
83
- role_name = ref.to_role.fact_type.entity_type.name.words.snakecase
84
- else
85
- role_name = ref.to_role.preferred_role_name
86
- end
87
- # puts ">>>>> #{ref.inspect}: #{role_name} <<<<<<"
88
- reading = ref.fact_type.default_reading
89
- end
90
- if ref == column.references.last
91
- # REVISIT: Avoid the "as" here when the value is implied by the role_name:
92
- puts ' '+' '*ref_prefix.size+"nest :#{role_name}, :as => \"#{column.name}\"\t\t# #{reading}"
93
- break
94
- else
95
- puts ' '+' '*ref_prefix.size+"flatten :#{role_name} do\t\t# #{reading}"
96
- ref_prefix.push ref
97
- end
98
- end
99
- previous_flattening = ref_prefix
100
- end
101
-
102
- while previous_flattening.size > 0
103
- previous_flattening.pop
104
- puts ' '+' '*previous_flattening.size+"end\n"
105
- end
106
- puts " end\n\n"
107
-
108
- tables_emitted[table] = true
109
-
110
- end
111
- puts "end\n"
112
- end
113
-
114
- end
115
- end
116
- end
117
-
118
- ActiveFacts::Registry.generator('composition', ActiveFacts::Generate::Composition)
@@ -1,714 +0,0 @@
1
- #
2
- # ActiveFacts Generators.
3
- # Generate CQL from an ActiveFacts vocabulary.
4
- #
5
- # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
- #
7
- require 'activefacts/vocabulary'
8
- require 'activefacts/registry'
9
- require 'activefacts/generate/helpers/ordered'
10
-
11
- module ActiveFacts
12
- module Generate #:nodoc:
13
- # Generate CQL for an ActiveFacts vocabulary.
14
- # Invoke as
15
- # afgen --cql <file>.cql
16
- class CQL < Helpers::OrderedDumper
17
- private
18
- def vocabulary_start
19
- puts "vocabulary #{@vocabulary.name};\n\n"
20
- build_indices
21
- end
22
-
23
- def vocabulary_end
24
- end
25
-
26
- def units_banner
27
- puts "/*\n * Units\n */"
28
- end
29
-
30
- def unit_dump unit
31
- puts unit.as_cql
32
- end
33
-
34
- def units_end
35
- puts "\n"
36
- end
37
-
38
- def value_type_banner
39
- puts "/*\n * Value Types\n */"
40
- end
41
-
42
- def value_type_end
43
- puts "\n"
44
- end
45
-
46
- def data_type_dump(o)
47
- value_type_dump(o, o.name, {}) if o.all_role.size > 0
48
- end
49
-
50
- def value_type_dump(o, super_type_name, facets)
51
- # No need to dump it if the only thing it does is be a supertype; it'll be created automatically
52
- # return if o.all_value_type_as_supertype.size == 0
53
-
54
- # REVISIT: A ValueType that is only used as a reference mode need not be emitted here.
55
-
56
- puts o.as_cql
57
- end
58
-
59
- def entity_type_dump(o)
60
- o.ordered_dumped!
61
- pi = o.preferred_identifier
62
-
63
- supers = o.supertypes
64
- if (supers.size > 0)
65
- # Ignore identification by a supertype:
66
- pi = nil if pi && pi.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) }
67
- subtype_dump(o, supers, pi)
68
- else
69
- non_subtype_dump(o, pi)
70
- end
71
- pi.ordered_dumped! if pi
72
- end
73
-
74
- def append_ring_to_reading(reading, ring)
75
- reading << " [#{(ring.ring_type.scan(/StronglyIntransitive|[A-Z][a-z]*/)*", ").downcase}]"
76
- end
77
-
78
- def mapping_pragma(entity_type, ignore_independence = false)
79
- ti = entity_type.all_type_inheritance_as_subtype
80
- assimilation = ti.map{|t| t.assimilation }.compact[0]
81
- return "" unless (entity_type.is_independent && !ignore_independence) || assimilation
82
- " [" +
83
- [
84
- entity_type.is_independent && !ignore_independence ? "independent" : nil,
85
- assimilation || nil
86
- ].compact*", " +
87
- "]"
88
- end
89
-
90
- # If this entity_type is identified by a single value, return four relevant objects:
91
- def value_role_identification(entity_type, identifying_facts)
92
- external_identifying_facts = identifying_facts - [entity_type.fact_type]
93
- fact_type = external_identifying_facts[0]
94
- ftr = fact_type && fact_type.all_role.sort_by{|role| role.ordinal}
95
- if external_identifying_facts.size == 1 and
96
- entity_role = ftr[n = (ftr[0].object_type == entity_type ? 0 : 1)] and
97
- value_role = ftr[1-n] and
98
- value_player = value_role.object_type and
99
- value_player.is_a?(ActiveFacts::Metamodel::ValueType) and
100
- value_name = value_player.name and
101
- value_residual = value_name.sub(%r{^#{entity_role.object_type.name} ?},'') and
102
- value_residual != '' and
103
- value_residual != value_name
104
- [fact_type, entity_role, value_role, value_residual]
105
- else
106
- []
107
- end
108
- end
109
-
110
- # This entity is identified by a single value, so find whether standard refmode readings were used
111
- def detect_standard_refmode_readings fact_type, entity_role, value_role
112
- forward_reading = reverse_reading = nil
113
- fact_type.all_reading.each do |reading|
114
- if reading.text =~ /^\{(\d)\} has \{\d\}$/
115
- if reading.role_sequence.all_role_ref.detect{|rr| rr.ordinal == $1.to_i}.role == entity_role
116
- forward_reading = reading
117
- else
118
- reverse_reading = reading
119
- end
120
- elsif reading.text =~ /^\{(\d)\} is of \{\d\}$/
121
- if reading.role_sequence.all_role_ref.detect{|rr| rr.ordinal == $1.to_i}.role == value_role
122
- reverse_reading = reading
123
- else
124
- forward_reading = reading
125
- end
126
- end
127
- end
128
- trace :mode, "Didn't find standard forward reading" unless forward_reading
129
- trace :mode, "Didn't find standard reverse reading" unless reverse_reading
130
- [forward_reading, reverse_reading]
131
- end
132
-
133
- # If this entity_type is identified by a reference mode, return the verbalisation
134
- def identified_by_ref_mode(entity_type, identifying_facts)
135
- fact_type, entity_role, value_role, value_residual =
136
- *value_role_identification(entity_type, identifying_facts)
137
- return nil unless fact_type
138
-
139
- # This EntityType is identified by its association with a single ValueType
140
- # whose name is an extension (the value_residual) of the EntityType's name.
141
- # If we have at least one of the standard refmode readings, dump it that way,
142
- # else exit and use the long-hand verbalisation instead.
143
-
144
- forward_reading, reverse_reading =
145
- *detect_standard_refmode_readings(fact_type, entity_role, value_role)
146
- return nil unless (forward_reading || reverse_reading)
147
-
148
- # We can't subscript reference modes.
149
- # If an objectified fact type has a role played by its identifying player, go long-hand.
150
- return nil if entity_type.fact_type and
151
- entity_type.fact_type.all_role.detect{|role| role.object_type == value_role.object_type }
152
-
153
- fact_type.ordered_dumped! # We've covered this fact type
154
-
155
- # Elide the constraints that would have been emitted on the standard readings.
156
- # If there is a UC that's not in the standard form for a reference mode,
157
- # we have to emit the standard reading anyhow.
158
- fact_constraints = @presence_constraints_by_fact[fact_type]
159
- fact_constraints.each do |pc|
160
- if (pc.role_sequence.all_role_ref.size == 1 and pc.max_frequency == 1)
161
- # It's a uniqueness constraint, and will be regenerated
162
- pc.ordered_dumped!
163
- end
164
- end
165
-
166
- # Figure out which non-standard readings exist, if any:
167
- nonstandard_readings = fact_type.all_reading - [forward_reading, reverse_reading]
168
- trace :mode, "--- nonstandard_readings.size now = #{nonstandard_readings.size}" if nonstandard_readings.size > 0
169
-
170
- verbaliser = ActiveFacts::Metamodel::Verbaliser.new
171
-
172
- # The verbaliser needs to have a Player for the roles of entity_type, so it doesn't get subscripted.
173
- entity_roles =
174
- nonstandard_readings.map{|r| r.role_sequence.all_role_ref.detect{|rr| rr.role.object_type == entity_type}}.compact
175
- verbaliser.role_refs_have_same_player entity_roles
176
-
177
- verbaliser.alternate_readings nonstandard_readings
178
- if entity_type.fact_type
179
- verbaliser.alternate_readings entity_type.fact_type.all_reading
180
- end
181
-
182
- verbaliser.create_subscripts(:rolenames) # Ok, the Verbaliser is ready to fly
183
-
184
- fact_readings =
185
- nonstandard_readings.map { |reading| expanded_reading(verbaliser, reading, fact_constraints, true) }
186
- fact_readings +=
187
- fact_readings_with_constraints(verbaliser, entity_type.fact_type) if entity_type.fact_type
188
-
189
- # If we emitted a reading for the refmode, it'll include any role_value_constraint already
190
- if nonstandard_readings.size == 0 and c = value_role.role_value_constraint
191
- constraint_text = " "+c.as_cql
192
- end
193
- (entity_type.is_independent ? ' independent' : '') +
194
- " identified by its #{value_residual}#{constraint_text}#{mapping_pragma(entity_type, true)}" +
195
- entity_type.concept.all_context_note_as_relevant_concept.map do |cn|
196
- cn.verbalise
197
- end.join("\n") +
198
- (fact_readings.size > 0 ? " where\n\t" : "") +
199
- fact_readings*",\n\t"
200
- end
201
-
202
- def identified_by_roles_and_facts(entity_type, identifying_role_refs, identifying_facts)
203
- # Detect standard reference-mode scenarios:
204
- if srm = identified_by_ref_mode(entity_type, identifying_facts)
205
- return srm
206
- end
207
-
208
- verbaliser = ActiveFacts::Metamodel::Verbaliser.new
209
-
210
- # Announce all the identifying fact roles to the verbaliser so it can decide on any necessary subscripting.
211
- # The verbaliser needs to have a Player for the roles of entity_type, so it doesn't get subscripted.
212
- entity_roles =
213
- identifying_facts.map{|ft| ft.preferred_reading.role_sequence.all_role_ref.detect{|rr| rr.role.object_type == entity_type}}.compact
214
- verbaliser.role_refs_have_same_player entity_roles
215
- identifying_facts.each do |fact_type|
216
- # The RoleRefs for corresponding roles across all readings are for the same player.
217
- verbaliser.alternate_readings fact_type.all_reading
218
- fact_type.ordered_dumped! unless fact_type.entity_type # Must dump objectification still!
219
- end
220
- verbaliser.create_subscripts(:rolenames)
221
-
222
- irn = verbaliser.identifying_role_names identifying_role_refs
223
-
224
- identifying_fact_text =
225
- identifying_facts.map{|f|
226
- fact_readings_with_constraints(verbaliser, f)
227
- }.flatten*",\n\t"
228
-
229
- (entity_type.is_independent ? ' independent' : '') +
230
- " identified by #{ irn*" and " }" +
231
- mapping_pragma(entity_type, true) +
232
- entity_type.concept.all_context_note_as_relevant_concept.map do |cn|
233
- cn.verbalise
234
- end.join("\n") +
235
- " where\n\t"+identifying_fact_text
236
- end
237
-
238
- def entity_type_banner
239
- puts "/*\n * Entity Types\n */"
240
- end
241
-
242
- def entity_type_group_end
243
- puts "\n"
244
- end
245
-
246
- def subtype_dump(o, supertypes, pi)
247
- print "#{o.name} is a kind of #{
248
- o.is_independent ? 'independent ' : ''
249
- }#{ o.supertypes.map(&:name)*", " }"
250
- if pi
251
- puts identified_by(o, pi)+';'
252
- return
253
- end
254
-
255
- print mapping_pragma(o, true)
256
-
257
- if o.fact_type
258
- verbaliser = ActiveFacts::Metamodel::Verbaliser.new
259
- # Announce all the objectified fact roles to the verbaliser so it can decide on any necessary subscripting.
260
- # The RoleRefs for corresponding roles across all readings are for the same player.
261
- verbaliser.alternate_readings o.fact_type.all_reading
262
- verbaliser.create_subscripts(:rolenames)
263
-
264
- print " where\n\t" + fact_readings_with_constraints(verbaliser, o.fact_type)*",\n\t"
265
- end
266
- puts ";\n"
267
- end
268
-
269
- def non_subtype_dump(o, pi)
270
- puts "#{o.name} is" + identified_by(o, pi) + ';'
271
- end
272
-
273
- def naiive_expand(reading)
274
- role_refs = reading.role_sequence.all_role_ref_in_order
275
- reading.text.gsub(/\{(\d+)\}/) do
276
- role_refs[$1.to_i].role.object_type.name
277
- end
278
- end
279
-
280
- def fact_type_dump(fact_type, name)
281
-
282
- if (o = fact_type.entity_type)
283
- print "#{o.name} is"
284
- supertypes = o.supertypes
285
- if supertypes.empty?
286
- print ' independent' if o.is_independent
287
- else
288
- print " a kind of#{
289
- o.is_independent ? ' independent' : ''
290
- } #{ supertypes.map(&:name)*', ' }"
291
- end
292
-
293
- # Alternate identification of objectified fact type?
294
- primary_supertype = supertypes[0]
295
- pi = fact_type.entity_type.preferred_identifier
296
- if pi && primary_supertype && primary_supertype.preferred_identifier != pi
297
- puts identified_by(o, pi) + ';'
298
- return
299
- end
300
- print " where\n\t"
301
- end
302
-
303
- # Check whether this fact type has readings which could be confused for a previously-dumped one:
304
- reading_texts = fact_type.all_reading.map{|r| naiive_expand(r)}
305
- if reading_texts.size > 1
306
- ambiguity =
307
- fact_type.all_role.to_a[0].object_type.all_role.map{|r| r.fact_type}.
308
- select{|f| f != fact_type && f.ordered_dumped }.
309
- detect do |dft|
310
- ambiguous_readings =
311
- reading_texts & dft.all_reading.map{|r| naiive_expand(r)}
312
- ambiguous_readings.size > 0
313
- end
314
- if ambiguity
315
- puts fact_type.default_reading([], true)+'; // Avoid ambiguity; this is a new fact type'
316
- end
317
- end
318
-
319
- # There can be no roles of the objectified fact type in the readings, so no need to tell the Verbaliser anything special
320
- verbaliser = ActiveFacts::Metamodel::Verbaliser.new
321
- verbaliser.alternate_readings fact_type.all_reading
322
- pr = fact_type.preferred_reading
323
- if (pr.role_sequence.all_role_ref.to_a[0].play)
324
- verbaliser.prepare_role_sequence pr.role_sequence
325
- end
326
- verbaliser.create_subscripts(:rolenames)
327
-
328
- print(fact_readings_with_constraints(verbaliser, fact_type)*",\n\t")
329
- if (pr.role_sequence.all_role_ref.to_a[0].play)
330
- print " where\n\t"+verbaliser.verbalise_over_role_sequence(pr.role_sequence)
331
- end
332
- puts(';')
333
- end
334
-
335
- def fact_type_banner
336
- puts "/*\n * Fact Types\n */"
337
- end
338
-
339
- def fact_type_end
340
- puts "\n"
341
- end
342
-
343
- def constraint_banner
344
- puts "/*\n * Constraints:"
345
- puts " */"
346
- end
347
-
348
- def constraint_end
349
- end
350
-
351
- # Of the players of a set of roles, return the one that's a subclass of (or same as) all others, else nil
352
- def roleplayer_subclass(roles)
353
- roles[1..-1].inject(roles[0].object_type){|subclass, role|
354
- next nil unless subclass and EntityType === role.object_type
355
- role.object_type.supertypes_transitive.include?(subclass) ? role.object_type : nil
356
- }
357
- end
358
-
359
- def dump_presence_constraint(c)
360
- # Loose binding in PresenceConstraints is limited to explicit role players (in an occurs list)
361
- # having no exact match, but having instead exactly one role of the same player in the readings.
362
-
363
- verbaliser = ActiveFacts::Metamodel::Verbaliser.new
364
- # For a mandatory constraint (min_frequency == 1, max == nil or 1) any subtyping step is over the proximate role player
365
- # For all other presence constraints any subtyping step is over the counterpart player
366
- role_proximity = c.min_frequency == 1 && [nil, 1].include?(c.max_frequency) ? :proximate : :counterpart
367
- if role_proximity == :proximate
368
- verbaliser.role_refs_have_subtype_steps(c.role_sequence)
369
- else
370
- join_over, joined_roles = ActiveFacts::Metamodel.plays_over(c.role_sequence.all_role_ref.map{|rr|rr.role}, role_proximity)
371
- verbaliser.roles_have_same_player(joined_roles) if join_over
372
- end
373
-
374
- verbaliser.prepare_role_sequence(c.role_sequence, join_over)
375
- # REVISIT: Need to discount role_adjuncts in here, since this constraint uses loose binding:
376
- verbaliser.create_subscripts :loose
377
-
378
- expanded_readings = verbaliser.verbalise_over_role_sequence(c.role_sequence, nil, role_proximity)
379
- if c.min_frequency == 1 && c.max_frequency == nil and c.role_sequence.all_role_ref.size == 2
380
- puts "either #{expanded_readings*' or '};"
381
- else
382
- roles = c.role_sequence.all_role_ref.map{|rr| rr.role }
383
- players = c.role_sequence.all_role_ref.map{|rr| verbaliser.subscripted_player(rr) }
384
- players.uniq! if role_proximity == :proximate
385
- min, max = c.min_frequency, c.max_frequency
386
- pl = (min&&min>1)||(max&&max>1) ? 's' : ''
387
- puts \
388
- "each #{players.size > 1 ? "combination " : ""}#{players*", "} occurs #{c.frequency} time#{pl} in\n\t"+
389
- "#{Array(expanded_readings)*",\n\t"};"
390
- end
391
- end
392
-
393
- def dump_set_comparison_constraint(c)
394
- scrs = c.all_set_comparison_roles.sort_by{|scr| scr.ordinal}
395
- role_sequences = scrs.map{|scr|scr.role_sequence}
396
- transposed_role_refs = scrs.map{|scr| scr.role_sequence.all_role_ref_in_order.to_a}.transpose
397
- verbaliser = ActiveFacts::Metamodel::Verbaliser.new
398
-
399
- # Tell the verbaliser all we know, so it can figure out which players to subscript:
400
- players = []
401
- trace :subscript, "Preparing query across projected roles in set comparison constraint" do
402
- transposed_role_refs.each do |role_refs|
403
- verbaliser.role_refs_have_subtype_steps role_refs
404
- join_over, = ActiveFacts::Metamodel.plays_over(role_refs.map{|rr| rr.role})
405
- players << join_over
406
- end
407
- end
408
- trace :subscript, "Preparing query between roles in set comparison constraint" do
409
- role_sequences.each do |role_sequence|
410
- trace :subscript, "role sequence is #{role_sequence.describe}" do
411
- verbaliser.prepare_role_sequence role_sequence
412
- end
413
- end
414
- end
415
- verbaliser.create_subscripts :normal
416
-
417
- if role_sequences.detect{|scr| scr.all_role_ref.detect{|rr| rr.play}}
418
- # This set constraint has an explicit query. Verbalise it.
419
-
420
- readings_list = role_sequences.
421
- map do |rs|
422
- verbaliser.verbalise_over_role_sequence(rs)
423
- end
424
- if c.is_a?(ActiveFacts::Metamodel::SetEqualityConstraint)
425
- puts readings_list.join("\n\tif and only if\n\t") + ';'
426
- return
427
- end
428
- if readings_list.size == 2 && c.is_mandatory # XOR constraint
429
- puts "either " + readings_list.join(" or ") + " but not both;"
430
- return
431
- end
432
-
433
- # Internal check: We must have located the players here
434
- if i = players.index(nil)
435
- rrs = transposed_role_refs[i]
436
- raise "Internal error detecting constrained object types in query involving #{rrs.map{|rr| rr.role.fact_type.default_reading}.uniq*', '}"
437
- end
438
-
439
- # Loose binding will apply only to the constrained roles, not to all roles. Not handled here.
440
- mode = c.is_mandatory ? "exactly one" : "at most one"
441
- puts "for each #{players.map{|p| p.name}*", "} #{mode} of these holds:\n\t" +
442
- readings_list.join(",\n\t") +
443
- ';'
444
- return
445
- end
446
-
447
- if c.is_a?(ActiveFacts::Metamodel::SetEqualityConstraint)
448
- puts \
449
- scrs.map{|scr|
450
- verbaliser.verbalise_over_role_sequence(scr.role_sequence)
451
- } * "\n\tif and only if\n\t" + ";"
452
- return
453
- end
454
-
455
- # A constrained role may involve a subtyping step. We substitute the name of the supertype for all occurrences.
456
- players = transposed_role_refs.map{|role_refs| common_supertype(role_refs.map{|rr| rr.role.object_type})}
457
- raise "Constraint must cover matching roles" if players.compact.size < players.size
458
-
459
- readings_expanded = scrs.
460
- map do |scr|
461
- # verbaliser.verbalise_over_role_sequence(scr.role_sequence)
462
- # REVISIT: verbalise_over_role_sequence cannot do what we need here, because of the
463
- # possibility of subtyping steps in the constrained roles across the different scr's
464
- # The following code uses "players" and "constrained_roles" to create substitutions.
465
- # These should instead be passed to the verbaliser (one variable per index, role_refs for each).
466
- fact_types_processed = {}
467
- constrained_roles = scr.role_sequence.all_role_ref_in_order.map{|rr| rr.role}
468
- join_over, joined_roles = *Metamodel.plays_over(constrained_roles)
469
- constrained_roles.map do |constrained_role|
470
- fact_type = constrained_role.fact_type
471
- next nil if fact_types_processed[fact_type] # Don't emit the same fact type twice (in case of objectification step)
472
- fact_types_processed[fact_type] = true
473
- reading = fact_type.reading_preferably_starting_with_role(constrained_role)
474
- expand_constrained(verbaliser, reading, constrained_roles, players)
475
- end.compact * " and "
476
- end
477
-
478
- if scrs.size == 2 && c.is_mandatory
479
- puts "either " + readings_expanded*" or " + " but not both;"
480
- else
481
- mode = c.is_mandatory ? "exactly one" : "at most one"
482
- puts "for each #{players.map{|p| p.name}*", "} #{mode} of these holds:\n\t" +
483
- readings_expanded*",\n\t" + ';'
484
- end
485
- end
486
-
487
- def dump_subset_constraint(c)
488
- # If the role players are identical and not duplicated, we can simply say "reading1 only if reading2"
489
- subset_roles, subset_fact_types =
490
- c.subset_role_sequence.all_role_ref_in_order.map{|rr| [rr.role, rr.role.fact_type]}.transpose
491
- superset_roles, superset_fact_types =
492
- c.superset_role_sequence.all_role_ref_in_order.map{|rr| [rr.role, rr.role.fact_type]}.transpose
493
- transposed_role_refs = [c.subset_role_sequence, c.superset_role_sequence].map{|rs| rs.all_role_ref_in_order.to_a}.transpose
494
-
495
- verbaliser = ActiveFacts::Metamodel::Verbaliser.new
496
- transposed_role_refs.each { |role_refs| verbaliser.role_refs_have_subtype_steps role_refs }
497
- verbaliser.prepare_role_sequence c.subset_role_sequence
498
- verbaliser.prepare_role_sequence c.superset_role_sequence
499
- verbaliser.create_subscripts :normal
500
-
501
- puts \
502
- verbaliser.verbalise_over_role_sequence(c.subset_role_sequence) +
503
- "\n\tonly if " +
504
- verbaliser.verbalise_over_role_sequence(c.superset_role_sequence) +
505
- ";"
506
- end
507
-
508
- def dump_ring_constraint(c)
509
- # At present, no ring constraint can be missed to be handled in this pass
510
- puts "// #{c.ring_type} ring over #{c.role.fact_type.default_reading}"
511
- end
512
-
513
- def constraint_dump(c)
514
- case c
515
- when ActiveFacts::Metamodel::PresenceConstraint
516
- dump_presence_constraint(c)
517
- when ActiveFacts::Metamodel::RingConstraint
518
- dump_ring_constraint(c)
519
- when ActiveFacts::Metamodel::SetComparisonConstraint # includes SetExclusionConstraint, SetEqualityConstraint
520
- dump_set_comparison_constraint(c)
521
- when ActiveFacts::Metamodel::SubsetConstraint
522
- dump_subset_constraint(c)
523
- else
524
- "#{c.class.basename} #{c.name}: unhandled constraint type"
525
- end
526
- end
527
-
528
- # Find the common supertype of these object_types.
529
- def common_supertype(object_types)
530
- common = object_types[0].supertypes_transitive
531
- object_types[1..-1].each do |object_type|
532
- common &= object_type.supertypes_transitive
533
- end
534
- common[0]
535
- end
536
-
537
- #============================================================
538
- # Verbalisation functions for fact type and entity type definitions
539
- #============================================================
540
-
541
- def fact_readings_with_constraints(verbaliser, fact_type)
542
- fact_constraints = @presence_constraints_by_fact[fact_type]
543
- readings = []
544
- define_role_names = true
545
- fact_type.all_reading_by_ordinal.each do |reading|
546
- readings << expanded_reading(verbaliser, reading, fact_constraints, define_role_names)
547
- define_role_names = false # No need to define role names in subsequent readings
548
- end
549
- readings
550
- end
551
-
552
- def expanded_reading(verbaliser, reading, fact_constraints, define_role_names)
553
- # Arrange the roles in order they occur in this reading:
554
- role_refs = reading.role_sequence.all_role_ref_in_order
555
- role_numbers = reading.text.scan(/\{(\d)\}/).flatten.map{|m| Integer(m) }
556
- roles = role_numbers.map{|m| role_refs[m].role }
557
-
558
- # Find the constraints that constrain frequency over each role we can verbalise:
559
- frequency_constraints = []
560
- value_constraints = []
561
- roles.each do |role|
562
- value_constraints <<
563
- if vc = role.role_value_constraint and !vc.ordered_dumped
564
- vc.ordered_dumped!
565
- vc.describe
566
- else
567
- nil
568
- end
569
-
570
- frequency_constraints <<
571
- if (role == roles.last) # On the last role of the reading, emit any presence constraint
572
- constraint = fact_constraints.
573
- detect do |c| # Find a UC that spans all other Roles
574
- c.is_a?(ActiveFacts::Metamodel::PresenceConstraint) &&
575
- !c.ordered_dumped && # Already verbalised
576
- roles-c.role_sequence.all_role_ref.map(&:role) == [role]
577
- end
578
- constraint.ordered_dumped! if constraint
579
- constraint && constraint.frequency
580
- else
581
- nil
582
- end
583
- end
584
-
585
- expanded = verbaliser.expand_reading(reading, frequency_constraints, define_role_names, value_constraints)
586
- expanded = "it is not the case that "+expanded if (reading.is_negative)
587
-
588
- if (ft_rings = @ring_constraints_by_fact[reading.fact_type]) &&
589
- (ring = ft_rings.detect{|rc| !rc.ordered_dumped})
590
- ring.ordered_dumped!
591
- append_ring_to_reading(expanded, ring)
592
- end
593
- expanded
594
- end
595
-
596
- # Expand this reading, substituting players[i].name for the each role in the i'th position in constrained_roles
597
- def expand_constrained(verbaliser, reading, constrained_roles, players)
598
- # Make sure that we refer to the constrained players by their common supertype (as passed in)
599
- frequency_constraints = reading.role_sequence.all_role_ref.
600
- map do |role_ref|
601
- player = role_ref.role.object_type
602
- i = constrained_roles.index(role_ref.role)
603
- player = players[i] if i
604
- [ nil, player.name ]
605
- end
606
- frequency_constraints = [] unless frequency_constraints.detect{|fc| fc[0] != "some" }
607
-
608
- expanded = verbaliser.expand_reading(reading, frequency_constraints)
609
- expanded = "it is not the case that "+expanded if (reading.is_negative)
610
- expanded
611
- end
612
-
613
- def build_indices
614
- @presence_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
615
- @ring_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
616
-
617
- @vocabulary.all_constraint.each { |c|
618
- case c
619
- when ActiveFacts::Metamodel::PresenceConstraint
620
- fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq # All fact types spanned by this constraint
621
- if fact_types.size == 1 # There's only one, save it:
622
- # trace "Single-fact constraint on #{fact_types[0].concept.guid}: #{c.name}"
623
- (@presence_constraints_by_fact[fact_types[0]] ||= []) << c
624
- end
625
- when ActiveFacts::Metamodel::RingConstraint
626
- (@ring_constraints_by_fact[c.role.fact_type] ||= []) << c
627
- else
628
- # trace "Found unhandled constraint #{c.class} #{c.name}"
629
- end
630
- }
631
- end
632
-
633
- end
634
- end
635
-
636
- module Metamodel
637
- class ValueType
638
- def as_cql
639
- parameters =
640
- [ length != 0 || scale != 0 ? length : nil,
641
- scale != 0 ? scale : nil
642
- ].compact
643
- parameters = parameters.length > 0 ? "("+parameters.join(",")+")" : ""
644
-
645
- "#{name
646
- } #{
647
- (is_independent ? '[independent] ' : '')
648
- }is written as #{
649
- (supertype || self).name
650
- }#{
651
- parameters
652
- }#{
653
- unit && " "+unit.name
654
- }#{
655
- transaction_phase && " auto-assigned at "+transaction_phase
656
- }#{
657
- concept.all_context_note_as_relevant_concept.map do |cn|
658
- cn.verbalise
659
- end.join("\n")
660
- }#{
661
- value_constraint && " "+value_constraint.describe
662
- };"
663
- end
664
- end
665
-
666
- class Unit
667
- def as_cql
668
- if !ephemera_url
669
- if coefficient
670
- # REVISIT: Use a smarter algorithm to switch to exponential form when there'd be lots of zeroes.
671
- coefficient.numerator.to_s('F') +
672
-
673
- if d = coefficient.denominator and d != 1
674
- "/#{d}"
675
- else
676
- ''
677
- end +
678
-
679
- ' '
680
- else
681
- '1 '
682
- end
683
- else
684
- ''
685
- end +
686
-
687
- all_derivation_as_derived_unit.
688
- sort_by{|d| d.base_unit.name}.
689
- # REVISIT: Sort base units
690
- # REVISIT: convert negative powers to division?
691
- map do |der|
692
- base = der.base_unit
693
- "#{base.name}#{der.exponent and der.exponent != 1 ? "^#{der.exponent}" : ''} "
694
- end*'' +
695
-
696
- if o = offset and o != 0
697
- "+ #{o.to_s('F')} "
698
- else
699
- ''
700
- end +
701
-
702
- "converts to #{name}#{plural_name ? '/'+plural_name : ''}" +
703
-
704
- (coefficient && !coefficient.is_precise ? ' approximately' : '') +
705
-
706
- (ephemera_url ? " ephemera #{ephemera_url}" : '') +
707
-
708
- ';'
709
- end
710
- end
711
- end
712
- end
713
-
714
- ActiveFacts::Registry.generator('cql', ActiveFacts::Generate::CQL)