activefacts 1.6.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
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)