activefacts 0.7.0 → 0.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 (60) hide show
  1. data/README.rdoc +0 -3
  2. data/Rakefile +7 -5
  3. data/bin/afgen +5 -2
  4. data/bin/cql +3 -2
  5. data/examples/CQL/Genealogy.cql +3 -3
  6. data/examples/CQL/Metamodel.cql +10 -7
  7. data/examples/CQL/MultiInheritance.cql +2 -1
  8. data/examples/CQL/OilSupply.cql +4 -4
  9. data/examples/CQL/Orienteering.cql +2 -2
  10. data/lib/activefacts.rb +2 -1
  11. data/lib/activefacts/api.rb +21 -2
  12. data/lib/activefacts/api/concept.rb +52 -39
  13. data/lib/activefacts/api/constellation.rb +8 -6
  14. data/lib/activefacts/api/entity.rb +41 -37
  15. data/lib/activefacts/api/instance.rb +5 -3
  16. data/lib/activefacts/api/numeric.rb +28 -21
  17. data/lib/activefacts/api/role.rb +29 -43
  18. data/lib/activefacts/api/standard_types.rb +8 -3
  19. data/lib/activefacts/api/support.rb +4 -4
  20. data/lib/activefacts/api/value.rb +9 -3
  21. data/lib/activefacts/api/vocabulary.rb +17 -7
  22. data/lib/activefacts/cql.rb +10 -7
  23. data/lib/activefacts/cql/CQLParser.treetop +6 -0
  24. data/lib/activefacts/cql/Concepts.treetop +32 -26
  25. data/lib/activefacts/cql/DataTypes.treetop +6 -0
  26. data/lib/activefacts/cql/Expressions.treetop +6 -0
  27. data/lib/activefacts/cql/FactTypes.treetop +6 -0
  28. data/lib/activefacts/cql/Language/English.treetop +9 -3
  29. data/lib/activefacts/cql/LexicalRules.treetop +6 -0
  30. data/lib/activefacts/cql/Rakefile +8 -0
  31. data/lib/activefacts/cql/parser.rb +4 -2
  32. data/lib/activefacts/generate/absorption.rb +20 -28
  33. data/lib/activefacts/generate/cql.rb +28 -16
  34. data/lib/activefacts/generate/cql/html.rb +327 -321
  35. data/lib/activefacts/generate/null.rb +7 -3
  36. data/lib/activefacts/generate/oo.rb +19 -15
  37. data/lib/activefacts/generate/ordered.rb +457 -461
  38. data/lib/activefacts/generate/ruby.rb +12 -4
  39. data/lib/activefacts/generate/sql/server.rb +42 -10
  40. data/lib/activefacts/generate/text.rb +7 -3
  41. data/lib/activefacts/input/cql.rb +55 -28
  42. data/lib/activefacts/input/orm.rb +32 -22
  43. data/lib/activefacts/persistence.rb +5 -0
  44. data/lib/activefacts/persistence/columns.rb +66 -32
  45. data/lib/activefacts/persistence/foreignkey.rb +29 -5
  46. data/lib/activefacts/persistence/index.rb +57 -25
  47. data/lib/activefacts/persistence/reference.rb +65 -30
  48. data/lib/activefacts/persistence/tables.rb +28 -17
  49. data/lib/activefacts/support.rb +8 -0
  50. data/lib/activefacts/version.rb +7 -1
  51. data/lib/activefacts/vocabulary.rb +4 -2
  52. data/lib/activefacts/vocabulary/extensions.rb +12 -10
  53. data/lib/activefacts/vocabulary/metamodel.rb +24 -23
  54. data/spec/api/autocounter.rb +2 -2
  55. data/spec/api/entity_type.rb +2 -2
  56. data/spec/api/instance.rb +61 -30
  57. data/spec/api/roles.rb +9 -9
  58. data/spec/cql_parse_spec.rb +1 -0
  59. data/spec/norma_tables_spec.rb +3 -3
  60. metadata +8 -4
@@ -1,3 +1,8 @@
1
+ #
2
+ # ActiveFacts Relational mapping and persistence.
3
+ #
4
+ # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
5
+ #
1
6
  require 'activefacts/persistence/reference'
2
7
  require 'activefacts/persistence/tables'
3
8
  require 'activefacts/persistence/columns'
@@ -1,4 +1,9 @@
1
1
  #
2
+ # ActiveFacts Relational mapping and persistence.
3
+ # Columns in a relational table; each is derived from a sequence of References.
4
+ #
5
+ # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
+ #
2
7
  # Each Reference from a Concept creates one or more Columns.
3
8
  # A reference to a simple valuetype creates a single column, as
4
9
  # does a reference to a table entity identified by a single value.
@@ -10,15 +15,18 @@
10
15
  # table, a reference to that entity creates multiple columns,
11
16
  # a multi-part foreign key.
12
17
  #
13
- # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
14
- #
15
18
 
16
19
  module ActiveFacts
17
- module Metamodel
20
+ module Persistence #:nodoc:
18
21
 
19
22
  class Column
20
- attr_reader :references
23
+ include Metamodel
24
+
25
+ def initialize(reference = nil) #:nodoc:
26
+ references << reference if reference
27
+ end
21
28
 
29
+ # A Column is created from a path through an array of References to a ValueType
22
30
  def references
23
31
  @references ||= []
24
32
  end
@@ -33,6 +41,7 @@ module ActiveFacts
33
41
  end
34
42
  end
35
43
 
44
+ # How many of the initial references are involved in full absorption of an EntityType into this column's table
36
45
  def absorption_level
37
46
  l = 0
38
47
  @references.detect do |ref|
@@ -42,15 +51,13 @@ module ActiveFacts
42
51
  l
43
52
  end
44
53
 
45
- def initialize(reference = nil)
46
- references << reference if reference
47
- end
48
-
49
- def prepend reference
54
+ def prepend reference #:nodoc:
50
55
  references.insert 0, reference
51
56
  self
52
57
  end
53
58
 
59
+ # A Column name is a sequence of names (derived from the to_roles of the References)
60
+ # joined by a joiner string (pass nil to get the original array of names)
54
61
  def name(joiner = "")
55
62
  last_name = ""
56
63
  names = @references.
@@ -61,7 +68,7 @@ module ActiveFacts
61
68
  ref.to and
62
69
  ref.to.is_a?(EntityType) and
63
70
  (role_refs = ref.to.preferred_identifier.role_sequence.all_role_ref).size == 1 and
64
- role_refs[0].role == ref.from_role
71
+ role_refs.only.role == ref.from_role
65
72
  end.
66
73
  inject([]) do |a, ref|
67
74
  names = ref.to_names
@@ -85,7 +92,7 @@ module ActiveFacts
85
92
  if names.size > 1 and
86
93
  (et = @references.last.from).is_a?(EntityType) and
87
94
  (role_refs = et.preferred_identifier.role_sequence.all_role_ref).size == 1 and
88
- role_refs[0].role == @references.last.to_role and
95
+ role_refs.only.role == @references.last.to_role and
89
96
  names.last[0...et.name.size].downcase == et.name.downcase
90
97
  names[-1] = names.last[et.name.size..-1]
91
98
  names.pop if names.last == ''
@@ -95,14 +102,17 @@ module ActiveFacts
95
102
  joiner ? name_array * joiner : name_array
96
103
  end
97
104
 
105
+ # Is this column mandatory or nullable?
98
106
  def is_mandatory
99
107
  !@references.detect{|ref| !ref.is_mandatory}
100
108
  end
101
109
 
110
+ # Is this column an auto-assigned value type?
102
111
  def is_auto_assigned
103
112
  (to = references[-1].to) && to.is_auto_assigned
104
113
  end
105
114
 
115
+ # What's the underlying SQL data type of this column?
106
116
  def type
107
117
  params = {}
108
118
  restrictions = []
@@ -126,6 +136,7 @@ module ActiveFacts
126
136
  return [vt.name, params, restrictions]
127
137
  end
128
138
 
139
+ # The comment is the readings from the References expressed as a join
129
140
  def comment
130
141
  @references.map do |ref|
131
142
  (ref.is_mandatory ? "" : "maybe ") +
@@ -134,13 +145,13 @@ module ActiveFacts
134
145
  end * " and "
135
146
  end
136
147
 
137
- def to_s
148
+ def to_s #:nodoc:
138
149
  "#{@references[0].from.name} column #{name('.')}"
139
150
  end
140
151
  end
141
152
 
142
153
  class Reference
143
- def columns(excluded_supertypes)
154
+ def columns(excluded_supertypes) #:nodoc:
144
155
  kind = ""
145
156
  cols =
146
157
  if is_unary
@@ -167,16 +178,24 @@ module ActiveFacts
167
178
  end
168
179
  end
169
180
  end
181
+ end
170
182
 
183
+ module Metamodel #:nodoc:
184
+ # The Concept class is defined in the metamodel; full documentation is not generated.
185
+ # This section shows the features relevant to relational Persistence.
171
186
  class Concept
172
- attr_accessor :columns
187
+ # The array of columns for this Concept's table
188
+ def columns; @columns; end
173
189
 
174
- def populate_columns
190
+ def populate_columns #:nodoc:
175
191
  @columns = all_columns({})
176
192
  end
177
193
  end
178
194
 
179
- class ValueType
195
+ # The ValueType class is defined in the metamodel; full documentation is not generated.
196
+ # This section shows the features relevant to relational Persistence.
197
+ class ValueType < Concept
198
+ # The identifier_columns for a ValueType can only ever be the self-value role that was injected
180
199
  def identifier_columns
181
200
  debug :columns, "Identifier Columns for #{name}" do
182
201
  raise "Illegal call to identifier_columns for absorbed ValueType #{name}" unless is_table
@@ -184,23 +203,27 @@ module ActiveFacts
184
203
  end
185
204
  end
186
205
 
187
- def reference_columns(excluded_supertypes)
206
+ # When creating a foreign key to this ValueType, what columns must we include?
207
+ # This must be a fresh copy, because the columns will have References prepended
208
+ def reference_columns(excluded_supertypes) #:nodoc:
188
209
  debug :columns, "Reference Columns for #{name}" do
189
210
  if is_table
190
- [Column.new(self_value_reference)]
211
+ [ActiveFacts::Persistence::Column.new(self_value_reference)]
191
212
  else
192
- [Column.new]
213
+ [ActiveFacts::Persistence::Column.new]
193
214
  end
194
215
  end
195
216
  end
196
217
 
197
- def all_columns(excluded_supertypes)
218
+ # When absorbing this ValueType, what columns must be absorbed?
219
+ # This must be a fresh copy, because the columns will have References prepended.
220
+ def all_columns(excluded_supertypes) #:nodoc:
198
221
  columns = []
199
222
  debug :columns, "All Columns for #{name}" do
200
223
  if is_table
201
224
  self_value_reference
202
225
  else
203
- columns << Column.new
226
+ columns << ActiveFacts::Persistence::Column.new
204
227
  end
205
228
  references_from.each do |ref|
206
229
  debug :columns, "Columns absorbed via #{ref}" do
@@ -211,19 +234,23 @@ module ActiveFacts
211
234
  columns
212
235
  end
213
236
 
214
- def self_value_reference
237
+ # If someone asks for this, it's because it's needed, so create it.
238
+ def self_value_reference #:nodoc:
215
239
  # Make a reference for the self-value column
216
- @self_value_reference ||= Reference.new(self, nil).tabulate
240
+ @self_value_reference ||= ActiveFacts::Persistence::Reference.new(self, nil).tabulate
217
241
  end
218
242
  end
219
243
 
220
- class EntityType
244
+ # The EntityType class is defined in the metamodel; full documentation is not generated.
245
+ # This section shows the features relevant to relational Persistence.
246
+ class EntityType < Concept
247
+ # The identifier_columns for an EntityType are the columns that result from the identifying roles
221
248
  def identifier_columns
222
249
  debug :columns, "Identifier Columns for #{name}" do
223
250
  if absorbed_via and
224
251
  # If this is a subtype that has its own identification, use that.
225
- (all_type_inheritance_by_subtype.size == 0 ||
226
- all_type_inheritance_by_subtype.detect{|ti| ti.provides_identification })
252
+ (all_type_inheritance_as_subtype.size == 0 ||
253
+ all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
227
254
  return absorbed_via.from.identifier_columns
228
255
  end
229
256
 
@@ -235,13 +262,15 @@ module ActiveFacts
235
262
  end
236
263
  end
237
264
 
238
- def reference_columns(excluded_supertypes)
265
+ # When creating a foreign key to this EntityType, what columns must we include (the identifier columns)?
266
+ # This must be a fresh copy, because the columns will have References prepended
267
+ def reference_columns(excluded_supertypes) #:nodoc:
239
268
  debug :columns, "Reference Columns for #{name}" do
240
269
 
241
270
  if absorbed_via and
242
271
  # If this is a subtype that has its own identification, use that.
243
- (all_type_inheritance_by_subtype.size == 0 ||
244
- all_type_inheritance_by_subtype.detect{|ti| ti.provides_identification })
272
+ (all_type_inheritance_as_subtype.size == 0 ||
273
+ all_type_inheritance_as_subtype.detect{|ti| ti.provides_identification })
245
274
  return absorbed_via.from.reference_columns(excluded_supertypes)
246
275
  end
247
276
 
@@ -257,7 +286,9 @@ module ActiveFacts
257
286
  end
258
287
  end
259
288
 
260
- def all_columns(excluded_supertypes)
289
+ # When absorbing this EntityType, what columns must be absorbed?
290
+ # This must be a fresh copy, because the columns will have References prepended.
291
+ def all_columns(excluded_supertypes) #:nodoc:
261
292
  debug :columns, "All Columns for #{name}" do
262
293
  columns = []
263
294
  sups = supertypes
@@ -287,15 +318,18 @@ module ActiveFacts
287
318
  end
288
319
  end
289
320
 
321
+ # The Vocabulary class is defined in the metamodel; full documentation is not generated.
322
+ # This section shows the features relevant to relational Persistence.
290
323
  class Vocabulary
291
- # Do things like adding ID fields and ValueType self-value columns
324
+ # Make schema transformations like adding ValueType self-value columns (and later, Rails-friendly ID fields).
325
+ # Override this method to change the transformations
292
326
  def finish_schema
293
327
  all_feature.each do |feature|
294
328
  feature.self_value_reference if feature.is_a?(ValueType) && feature.is_table
295
329
  end
296
330
  end
297
331
 
298
- def populate_all_columns
332
+ def populate_all_columns #:nodoc:
299
333
  # REVISIT: Is now a good time to apply schema transforms or should this be more explicit?
300
334
  finish_schema
301
335
 
@@ -1,15 +1,38 @@
1
+ #
2
+ # ActiveFacts Relational mapping and persistence.
3
+ # A ForeignKey exists for every Reference from a Concept to another Concept that's a table.
4
+ #
5
+ # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
6
+ #
1
7
  module ActiveFacts
2
- module Metamodel
3
-
8
+ module Persistence
4
9
  class ForeignKey
5
- attr_reader :from, :to, :reference, :from_columns, :to_columns
6
- def initialize(from, to, fk_ref, from_columns, to_columns)
10
+ # What table (Concept) is the FK from?
11
+ def from; @from; end
12
+
13
+ # What table (Concept) is the FK to?
14
+ def to; @to; end
15
+
16
+ # What reference created the FK?
17
+ def reference; @reference; end
18
+
19
+ # What columns in the *from* table form the FK
20
+ def from_columns; @from_columns; end
21
+
22
+ # What columns in the *to* table form the identifier
23
+ def to_columns; @to_columns; end
24
+
25
+ def initialize(from, to, fk_ref, from_columns, to_columns) #:nodoc:
7
26
  @from, @to, @fk_ref, @from_columns, @to_columns =
8
27
  from, to, fk_ref, from_columns, to_columns
9
28
  end
10
29
  end
30
+ end
11
31
 
32
+ module Metamodel #:nodoc:
12
33
  class Concept
34
+ # When an EntityType is fully absorbed, its foreign keys are too.
35
+ # Return an Array of Reference paths for such absorbed FKs
13
36
  def all_absorbed_foreign_key_reference_path
14
37
  references_from.inject([]) do |array, ref|
15
38
  if ref.is_simple_reference
@@ -23,6 +46,7 @@ module ActiveFacts
23
46
  end
24
47
  end
25
48
 
49
+ # Return an array of all the foreign keys from this table
26
50
  def foreign_keys
27
51
  fk_ref_paths = all_absorbed_foreign_key_reference_path
28
52
 
@@ -78,7 +102,7 @@ module ActiveFacts
78
102
  end
79
103
  debug :fk, "to_columns in #{to.name}: #{to_columns.map { |column| column ? column.name : "OOPS!" }*", "}"
80
104
 
81
- ForeignKey.new(self, to, fk_ref_path[-1], from_columns, to_columns)
105
+ ActiveFacts::Persistence::ForeignKey.new(self, to, fk_ref_path[-1], from_columns, to_columns)
82
106
  end
83
107
  end
84
108
  end
@@ -1,31 +1,49 @@
1
1
  #
2
- # An Index on a Concept is used to represent a unique constraint across roles absorbed
3
- # into that concept's table.
2
+ # ActiveFacts Relational mapping and persistence.
3
+ # An Index on a Concept is used to represent a unique constraint across roles absorbed
4
+ # into that concept's table.
4
5
  #
5
- # Reference objects update each concept's list of the references *to* and *from* that concept.
6
- #
7
- # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
6
+ # Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
8
7
  #
9
8
 
10
9
  module ActiveFacts
11
- module Metamodel
10
+ module Persistence
12
11
  class Index
13
- attr_reader :uniqueness_constraint, :on, :over, :columns, :is_primary, :is_unique
12
+ # The UniquenessConstraint that created this index
13
+ def uniqueness_constraint; @uniqueness_constraint; end
14
+
15
+ # The table that the index is on
16
+ def on; @on; end
17
+
18
+ # If a non-mandatory reference was absorbed, only the non-nil instances are unique.
19
+ # Return the Concept that was absorbed, which might differ from this Index's table.
20
+ def over; @over; end
21
+
22
+ # Return the array of columns in this index
23
+ def columns; @columns; end
24
+
25
+ # Is this index the primary key for this table?
26
+ def is_primary; @is_primary; end
27
+
28
+ # Is this index unique?
29
+ def is_unique; @is_unique; end
14
30
 
15
31
  # An Index arises from a uniqueness constraint and applies to a table,
16
32
  # but because the UC may actually be over an object absorbed into the table,
17
33
  # we must record that object also.
18
34
  # We record the columns it's over, whether it's primary (for 'over'),
19
35
  # and whether it's unique (always, at present)
20
- def initialize(uc, on, over, columns, is_primary, is_unique = true)
36
+ def initialize(uc, on, over, columns, is_primary, is_unique = true) #:nodoc:
21
37
  @uniqueness_constraint, @on, @over, @columns, @is_primary, @is_unique =
22
38
  uc, on, over, columns, is_primary, is_unique
23
39
  end
24
40
 
41
+ # The name that was assigned (perhaps implicitly by NORMA)
25
42
  def real_name
26
43
  @uniqueness_constraint.name && @uniqueness_constraint.name != '' ? @uniqueness_constraint.name : nil
27
44
  end
28
45
 
46
+ # This name is either the name explicitly assigned (if any) or is constructed to form a unique index name.
29
47
  def name
30
48
  uc = @uniqueness_constraint
31
49
  r = real_name
@@ -35,35 +53,41 @@ module ActiveFacts
35
53
  (uc.is_preferred_identifier ? "" : "By"+column_names*"")
36
54
  end
37
55
 
38
- def abbreviated_column_names
39
- columns.map{|column| column.name.sub(/^#{over.name}/,'')}
40
- end
41
-
56
+ # An array of the names of the columns this index covers
42
57
  def column_names
43
58
  columns.map{|column| column.name}
44
59
  end
45
60
 
61
+ # An array of the names of the columns this index covers, with some lexical truncations.
62
+ def abbreviated_column_names
63
+ columns.map{|column| column.name.sub(/^#{over.name}/,'')}
64
+ end
65
+
66
+ # The name of a view that can be created to enforce uniqueness over non-null key values
46
67
  def view_name
47
68
  "#{over.name}#{on == over ? "" : "In"+on.name}"
48
69
  end
49
70
 
50
- def to_s
71
+ def to_s #:nodoc:
51
72
  name = @uniqueness_constraint.name
52
73
  colnames = @columns.map(&:name)*", "
53
74
  preferred = @uniqueness_constraint.is_preferred_identifier ? " (preferred)" : ""
54
75
  "Index #{name} on #{@on.name} over #{@over.name}(#{colnames})#{preferred}"
55
76
  end
56
77
  end
78
+ end
57
79
 
80
+ module Metamodel #:nodoc:
58
81
  class Concept
59
- attr_reader :indices
82
+ # An array of each Index for this table
83
+ def indices; @indices; end
60
84
 
61
- def clear_indices
85
+ def clear_indices #:nodoc:
62
86
  # Clear any previous indices
63
87
  @indices = nil
64
88
  end
65
89
 
66
- def populate_indices
90
+ def populate_indices #:nodoc:
67
91
  # The absorption path of a column indicates how it came to be in this table.
68
92
  # It might be a direct many:one valuetype relationship, or it might be in such
69
93
  # a relationship to an entity that was absorbed into this table (and so on).
@@ -96,14 +120,20 @@ module ActiveFacts
96
120
  !pc.max_frequency or # No maximum freq; cannot be a uniqueness constraint
97
121
  pc.max_frequency != 1 or # maximum is not 1
98
122
  pc.role_sequence.all_role_ref.size == 1 && # UniquenessConstraint is over one role
99
- (pc.role_sequence.all_role_ref[0].role.fact_type.is_a?(TypeInheritance) || # Inheritance
100
- pc.role_sequence.all_role_ref[0].role.fact_type.all_role.size == 1) # Unary
123
+ ((fact_type = pc.role_sequence.all_role_ref.only.role.fact_type).is_a?(TypeInheritance) || # Inheritance
124
+ fact_type.all_role.size == 1) # Unary
101
125
  # The preceeeding two restrictions exclude the internal UCs created within NORMA.
102
126
  end
103
127
  next unless pcs.size > 0
104
128
  # The columns for this ref_path support the UCs in "pcs".
105
129
  pcs.each do |pc|
106
- (columns_by_unique_constraint[pc] ||= []).concat(all_column_by_ref_path[ref_path])
130
+ ref_columns = all_column_by_ref_path[ref_path]
131
+ ordinal = role_ref.ordinal # Position in priority order
132
+ ref_columns.each_with_index do |column, index|
133
+ #puts "Adding index column #{column.name} in rank[#{ordinal},#{index}]"
134
+ # REVISIT: the "index" here might be a duplicate in some cases: change sort_by below to just sort and run the SeparateSubtypes CQL model for example.
135
+ (columns_by_unique_constraint[pc] ||= []) << [ordinal, index, column]
136
+ end
107
137
  end
108
138
  hash[role_ref] = all_column_by_ref_path[ref_path]
109
139
  end
@@ -112,17 +142,19 @@ module ActiveFacts
112
142
  end
113
143
 
114
144
  debug :index, "All Indices in #{name}:" do
115
- @indices = columns_by_unique_constraint.map do |uc, columns|
145
+ @indices = columns_by_unique_constraint.map do |uc, columns_with_ordinal|
146
+ #puts "Index on #{name} over (#{columns_with_ordinal.sort.map{|ca| [ca[0], ca[1], ca[2].name].inspect}})"
147
+ columns = columns_with_ordinal.sort_by{|ca| [ca[0,2], ca[2].name]}.map{|ca| ca[2]}
116
148
  absorption_level = columns.map(&:absorption_level).min
117
149
  over = columns[0].references[absorption_level].from
118
150
 
119
151
  # Absorption through a one-to-one forms a UC that we don't need to enforce using an index:
120
- next if over != self and
152
+ next nil if over != self and
121
153
  over.absorbed_via == columns[0].references[absorption_level-1] and
122
154
  (rrs = uc.role_sequence.all_role_ref).size == 1 and
123
- over.absorbed_via.fact_type.all_role.include?(rrs[0].role)
155
+ over.absorbed_via.fact_type.all_role.include?(rrs.only.role)
124
156
 
125
- index = Index.new(
157
+ index = ActiveFacts::Persistence::Index.new(
126
158
  uc,
127
159
  self,
128
160
  over,
@@ -131,14 +163,14 @@ module ActiveFacts
131
163
  )
132
164
  debug :index, index
133
165
  index
134
- end
166
+ end.compact
135
167
  end
136
168
  end
137
169
 
138
170
  end
139
171
 
140
172
  class Vocabulary
141
- def populate_all_indices
173
+ def populate_all_indices #:nodoc:
142
174
  debug :index, "Populating all concept indices" do
143
175
  all_feature.each do |feature|
144
176
  next unless feature.is_a? Concept