activefacts-metamodel 1.9.6 → 1.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b1f0ae97a0a31369e5681e2310eb8deeb663390
4
- data.tar.gz: d5cbf6dc32862b3982eb8c2f26aa28fb033d2afe
3
+ metadata.gz: b7afe6a26853ed01f535f4d7f5790f79ec9be7f5
4
+ data.tar.gz: 746e2147513f5095bd03e1d16eaa3639ec7b7983
5
5
  SHA512:
6
- metadata.gz: 9031e41a724f5eb9c57aa7aa8f5ea2c8f22d0de1b6c9ea8808b6ebb062b31450cff6f08b8b19b744868fcee2b3f3db8d51cac187a0073292f2d044ee6bb78944
7
- data.tar.gz: d9922fc63374fb60f7d553e0251c6d91b0a6dfd1d0c784f17a0c5a4ce03fab7b1e9fa2cf9eb51adb19ba509aa5b9e73524aee4c0bad12f8725e20eb5ff545398
6
+ metadata.gz: f4d217b455a600eb0899906962bad4f8fff3c0da763526bfd6251df02873fb6582ccdac618d43dc7fb882d8326c9a92dc1f8d29fa70f95ce5d867e6515f01690
7
+ data.tar.gz: 71068e4a2c568f2f82c671412d37e11bf6eb9c0c35c58c26ec97508e64dc1065869197aae468ffd866f1273ec343bad98045af63f988ca9a4944cc31f4d43511
data/Gemfile CHANGED
@@ -9,4 +9,5 @@ if this_file =~ %r{\A#{ENV['HOME']}}i
9
9
  gem 'activefacts-cql', path: dir+'/cql'
10
10
  gem 'activefacts-compositions', path: dir+'/compositions'
11
11
  gem 'activefacts-api', path: dir+'/api'
12
+ gem 'activefacts-orm', path: dir+'/orm'
12
13
  end
@@ -20,7 +20,7 @@ This gem provides the core representations for the Fact Modeling tools of Active
20
20
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_development_dependency "bundler", ">= 1.10", "~> 1.10.6"
23
+ spec.add_development_dependency "bundler", ">= 1.10"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
25
  spec.add_development_dependency "rspec", "~> 3.3"
26
26
 
@@ -382,6 +382,7 @@ Domain Object Type is a kind of Object Type;
382
382
  Entity Type is a kind of Domain Object Type;
383
383
  Entity Type objectifies at most one Fact Type,
384
384
  Fact Type is objectified as at most one Entity Type;
385
+ Entity Type implicitly objectifies at most one implicitly- objectified Fact Type;
385
386
 
386
387
  Type Inheritance is a kind of Fact Type identified by Subtype and Supertype where
387
388
  Entity Type (as Subtype) is subtype of super-Entity Type (as Supertype) [acyclic, intransitive],
@@ -424,6 +425,8 @@ Composition is called one Name,
424
425
  Component is identified by Guid where
425
426
  Component has one Guid,
426
427
  Guid is of at most one Component;
428
+ Component (as Member) belongs to at most one Component (as Parent) [acyclic, stronglyintransitive],
429
+ Parent contains Member;
427
430
  Component projects at most one Name;
428
431
  Component has at most one Ordinal rank;
429
432
 
@@ -437,8 +440,6 @@ Discriminated Role is where
437
440
 
438
441
  Mapping is a kind of Component;
439
442
  Mapping represents one Object Type;
440
- Component (as Member) belongs to at most one Mapping (as Parent),
441
- Parent contains Member [acyclic, stronglyintransitive];
442
443
 
443
444
  Composite is identified by Mapping where
444
445
  Mapping projects at most one Composite,
@@ -446,6 +447,9 @@ Composite is identified by Mapping where
446
447
  Composition contains Composite,
447
448
  Composite belongs to one Composition;
448
449
 
450
+ Temporal Mapping is a kind of Mapping;
451
+ Temporal Mapping records time using one Value Type;
452
+
449
453
  Absorption is a kind of Mapping;
450
454
  Absorption traverses to one child-Role;
451
455
  Absorption traverses from one parent-Role;
@@ -453,8 +457,10 @@ forward-Absorption is matched by at most one reverse-Absorption,
453
457
  reverse-Absorption is reverse of at most one forward-Absorption;
454
458
  Absorption flattens;
455
459
 
460
+ /*
456
461
  some Absorption traverses from some parent- Role(1) and that Role(1) is played by some Object Type
457
- only if that Absorption is a kind of Mapping(1) that contains some Component that is a Mapping(2) that represents that Object Type;
462
+ only if that Absorption is a kind of Component(2) that contains some Component(3) that is a Mapping that represents that Object Type;
463
+ */
458
464
  some Absorption traverses to some child- Role(1) and that Role(1) is played by some Object Type
459
465
  only if that Absorption is a kind of Mapping that represents that Object Type;
460
466
 
@@ -487,6 +493,7 @@ Scoping is a kind of Mapping;
487
493
  Injection is a kind of Mapping;
488
494
  Value Field is a kind of Injection;
489
495
  Surrogate Key is a kind of Injection;
496
+ Valid From is a kind of Injection;
490
497
 
491
498
  /* Access Paths */
492
499
  Access Path is identified by Guid where
@@ -500,6 +507,9 @@ Access Path is to one Composite,
500
507
  Index is a kind of Access Path;
501
508
  Index is unique;
502
509
  Index derives from one Presence Constraint;
510
+ Composite has at most one natural-Index,
511
+ Index is natural for at most one Composite;
512
+ Composite has primary-Index; // Avoid ambiguity; this is a new fact type
503
513
  Composite has at most one primary-Index,
504
514
  Index is primary for at most one Composite;
505
515
  Index is primary for Composite
@@ -543,7 +553,7 @@ Absorption is nested under index Role in Ordinal position
543
553
  /*
544
554
  * Constraints:
545
555
  */
546
- either Component belongs to Mapping(1) or Component is a Mapping(2) that projects Composite but not both;
556
+ either Component(1) belongs to Component(2) or Component(1) is a Mapping that projects some Composite but not both;
547
557
  for each Component exactly one of these holds:
548
558
  Component is a Mapping,
549
559
  Component is an Indicator,
@@ -611,10 +621,10 @@ Variable is for Object Type that plays Role
611
621
  if and only if
612
622
  Variable is restricted by Role of Step;
613
623
  /*
614
- Absorption traverses from parent Role that is played by Object Type and Mapping(1) is a kind of Component(2) and Mapping(1) is an Absorption
615
- only if Member belongs to Mapping(2) that represents Object Type;
616
- Absorption traverses to child Role that is played by Object Type and Absorption is a kind of Mapping(2)
617
- only if Mapping(1) represents Object Type;
624
+ some Absorption traverses from some parent Role that is played by some Object Type
625
+ only if that Absorption contains some Component that is a Mapping(2) that represents that Object Type;
626
+ some Absorption traverses to some child Role that is played by some Object Type
627
+ only if that Absorption is a kind of Mapping that represents that Object Type;
618
628
  */
619
629
  Presence Constraint is preferred identifier
620
630
  only if Presence Constraint has max Frequency;
@@ -126,7 +126,7 @@ module ActiveFacts
126
126
  rr.role.fact_type
127
127
  end
128
128
  when ActiveFacts::Metamodel::ValueConstraint
129
- [ body.role ? body.role.fact_type : nil, body.value_type ] +
129
+ [ body.role_as_role_value_constraint ? body.role_as_role_value_constraint.fact_type : nil, body.value_type ] +
130
130
  body.all_allowed_range.map do |ar|
131
131
  [ ar.value_range.minimum_bound, ar.value_range.maximum_bound ].compact.map{|b| b.value.unit}
132
132
  end
@@ -163,8 +163,8 @@ module ActiveFacts
163
163
 
164
164
  class Topic
165
165
  def precursors
166
- # Precursors of a topic are the topics of all precursors of items in this topic
167
- all_concept.map{|c| c.precursors }.flatten.uniq.map{|c| c.topic}.uniq-[self]
166
+ # Precursors of a topic are the topics of all precursors of items in this topic
167
+ all_concept.map{|c| c.precursors }.flatten.uniq.map{|c| c.topic}.uniq-[self]
168
168
  end
169
169
  end
170
170
 
@@ -225,7 +225,7 @@ module ActiveFacts
225
225
  end
226
226
 
227
227
  def is_unary
228
- all_role.size == 1
228
+ all_role.size == 1
229
229
  end
230
230
 
231
231
  def internal_presence_constraints
@@ -265,7 +265,7 @@ module ActiveFacts
265
265
  # Mirror Role defines this, but it's more convenient not to have to type-check.
266
266
  # A Role that's not a Mirror Role is its own base role.
267
267
  def base_role
268
- self
268
+ self
269
269
  end
270
270
 
271
271
  def describe(highlight = nil)
@@ -273,7 +273,7 @@ module ActiveFacts
273
273
  end
274
274
 
275
275
  def is_mandatory
276
- return true if fact_type.is_a?(LinkFactType) # Handle objectification roles
276
+ return true if fact_type.is_a?(LinkFactType) # Handle objectification roles
277
277
  all_role_ref.detect{|rr|
278
278
  rs = rr.role_sequence
279
279
  rs.all_role_ref.size == 1 and
@@ -290,7 +290,7 @@ module ActiveFacts
290
290
  # Return true if this role is functional (has only one instance wrt its player)
291
291
  # A role in an objectified fact type is deemed to refer to the implicit role of the objectification.
292
292
  def is_functional
293
- return true if fact_type.is_a?(LinkFactType) # Handle objectification roles
293
+ return true if fact_type.is_a?(LinkFactType) # Handle objectification roles
294
294
 
295
295
  fact_type.entity_type or
296
296
  fact_type.all_role.size != 2 or
@@ -306,46 +306,46 @@ module ActiveFacts
306
306
  return pc if pc.max_frequency == 1 and !pc.enforcement # Alethic uniqueness constraint
307
307
  end
308
308
  }
309
- nil
309
+ nil
310
310
  end
311
311
 
312
312
  def is_identifying
313
- uc = uniqueness_constraint and uc.is_preferred_identifier
313
+ uc = uniqueness_constraint and uc.is_preferred_identifier
314
314
  end
315
315
 
316
316
  # Is there are internal uniqueness constraint on this role only?
317
317
  def is_unique
318
- return true if fact_type.is_a?(LinkFactType) or # Handle objectification roles
319
- fact_type.all_role.size == 1 # and unary roles
318
+ return true if fact_type.is_a?(LinkFactType) or # Handle objectification roles
319
+ fact_type.all_role.size == 1 # and unary roles
320
320
 
321
- uniqueness_constraint ? true : false
321
+ uniqueness_constraint ? true : false
322
322
  end
323
323
 
324
324
  def unique
325
- raise "REVISIT: unique is deprecated. Call is_unique instead"
325
+ raise "REVISIT: unique is deprecated. Call is_unique instead"
326
326
  end
327
327
 
328
328
  def name
329
329
  role_name or
330
- is_mirror_role && base_role.role_name or
331
- fact_type.is_unary && unary_name or
332
- String::Words.new(preferred_reference.role_name nil).capwords*' ' or
333
- object_type.name
330
+ is_mirror_role && base_role.role_name or
331
+ fact_type.is_unary && unary_name or
332
+ String::Words.new(preferred_reference.role_name nil).capwords*' ' or
333
+ object_type.name
334
334
  end
335
335
 
336
336
  def unary_name
337
- fact_type.
338
- preferred_reading.
339
- text.
340
- gsub(/(.*)\{[0-9]\}(.*)/) do
341
- if $1.empty? or $2.empty?
342
- "#{$1} #{$2}"
343
- else
344
- "#{$1} #{object_type.name} #{$2}"
345
- end
346
- end.
347
- words.
348
- titlewords*' '
337
+ fact_type.
338
+ preferred_reading.
339
+ text.
340
+ gsub(/(.*)\{[0-9]\}(.*)/) do
341
+ if $1.empty? or $2.empty?
342
+ "#{$1} #{$2}"
343
+ else
344
+ "#{$1} #{object_type.name} #{$2}"
345
+ end
346
+ end.
347
+ words.
348
+ titlewords*' '
349
349
  end
350
350
 
351
351
  def is_link_role
@@ -353,37 +353,37 @@ module ActiveFacts
353
353
  end
354
354
 
355
355
  def is_mirror_role
356
- is_a?(MirrorRole)
356
+ is_a?(MirrorRole)
357
357
  end
358
358
 
359
359
  def is_objectification_role
360
- is_link_role && !is_mirror_role
360
+ is_link_role && !is_mirror_role
361
361
  end
362
362
 
363
363
  def counterpart
364
- case fact_type.all_role.size
365
- when 1
366
- self
367
- when 2
368
- (fact_type.all_role.to_a-[self])[0]
369
- else
370
- nil # raise "counterpart roles are undefined in n-ary fact types"
371
- end
364
+ case fact_type.all_role.size
365
+ when 1
366
+ self
367
+ when 2
368
+ (fact_type.all_role.to_a-[self])[0]
369
+ else
370
+ nil # raise "counterpart roles are undefined in n-ary fact types"
371
+ end
372
372
  end
373
373
 
374
374
  # return an array of all the constraints on this role (not including ValueConstraint on a ValueType player)
375
375
  def all_constraint
376
- (
377
- Array(role_value_constraint) +
378
- all_role_ref.to_a.flat_map do |rr|
379
- rr.role_sequence.all_presence_constraint.to_a +
380
- rr.role_sequence.all_subset_constraint_as_superset_role_sequence +
381
- rr.role_sequence.all_subset_constraint_as_subset_role_sequence +
382
- rr.role_sequence.all_set_comparison_roles.map(&:set_comparison_constraint)
383
- end +
384
- all_ring_constraint.to_a +
385
- all_ring_constraint_as_other_role.to_a
386
- ).uniq
376
+ (
377
+ Array(role_value_constraint) +
378
+ all_role_ref.to_a.flat_map do |rr|
379
+ rr.role_sequence.all_presence_constraint.to_a +
380
+ rr.role_sequence.all_subset_constraint_as_superset_role_sequence +
381
+ rr.role_sequence.all_subset_constraint_as_subset_role_sequence +
382
+ rr.role_sequence.all_set_comparison_roles.map(&:set_comparison_constraint)
383
+ end +
384
+ all_ring_constraint.to_a +
385
+ all_ring_constraint_as_other_role.to_a
386
+ ).uniq
387
387
  end
388
388
  end
389
389
 
@@ -412,35 +412,35 @@ module ActiveFacts
412
412
  end
413
413
 
414
414
  def cql_leading_adjective
415
- if leading_adjective
416
- # 'foo' => "foo-"
417
- # 'foo bar' => "foo- bar "
418
- # 'foo-bar' => "foo-- bar "
419
- # 'foo-bar baz' => "foo-- bar baz "
420
- # 'bat foo-bar baz' => "bat- foo-bar baz "
421
- leading_adjective.strip.
422
- sub(/[- ]|$/, '-\0 ').sub(/ /, ' ').sub(/[^-]$/, '\0 ').sub(/- $/,'-')
423
- else
424
- ''
425
- end
415
+ if leading_adjective
416
+ # 'foo' => "foo-"
417
+ # 'foo bar' => "foo- bar "
418
+ # 'foo-bar' => "foo-- bar "
419
+ # 'foo-bar baz' => "foo-- bar baz "
420
+ # 'bat foo-bar baz' => "bat- foo-bar baz "
421
+ leading_adjective.strip.
422
+ sub(/[- ]|$/, '-\0 ').sub(/ /, ' ').sub(/[^-]$/, '\0 ').sub(/- $/,'-')
423
+ else
424
+ ''
425
+ end
426
426
  end
427
427
 
428
428
  def cql_trailing_adjective
429
- if trailing_adjective
430
- # 'foo' => "-foo"
431
- # 'foo bar' => " foo -bar"
432
- # 'foo-bar' => " foo --bar"
433
- # 'foo-bar baz' => " foo-bar -baz"
434
- # 'bat foo-bar baz' => " bat foo-bar -baz"
435
- trailing_adjective.
436
- strip.
437
- sub(/(?<a>.*) (?<b>[^- ]+$)|(?<a>.*)(?<b>-[^- ]*)$|(?<a>)(?<b>.*)/) {
438
- " #{$~[:a]} -#{$~[:b]}"
439
- }.
440
- sub(/^ *-/, '-') # A leading space is not needed if the hyphen is at the start
441
- else
442
- ''
443
- end
429
+ if trailing_adjective
430
+ # 'foo' => "-foo"
431
+ # 'foo bar' => " foo -bar"
432
+ # 'foo-bar' => " foo --bar"
433
+ # 'foo-bar baz' => " foo-bar -baz"
434
+ # 'bat foo-bar baz' => " bat foo-bar -baz"
435
+ trailing_adjective.
436
+ strip.
437
+ sub(/(?<a>.*) (?<b>[^- ]+$)|(?<a>.*)(?<b>-[^- ]*)$|(?<a>)(?<b>.*)/) {
438
+ " #{$~[:a]} -#{$~[:b]}"
439
+ }.
440
+ sub(/^ *-/, '-') # A leading space is not needed if the hyphen is at the start
441
+ else
442
+ ''
443
+ end
444
444
  end
445
445
 
446
446
  def cql_name
@@ -450,9 +450,9 @@ module ActiveFacts
450
450
  role.role_name
451
451
  else
452
452
  # Where an adjective has multiple words, the hyphen is inserted outside the outermost space, leaving the space
453
- cql_leading_adjective +
453
+ cql_leading_adjective +
454
454
  role.object_type.name+
455
- cql_trailing_adjective
455
+ cql_trailing_adjective
456
456
  end
457
457
  end
458
458
  end
@@ -461,8 +461,8 @@ module ActiveFacts
461
461
  def describe(highlighted_role_ref = nil)
462
462
  "("+
463
463
  all_role_ref_in_order.map{|rr| rr.role.name + (highlighted_role_ref == rr ? '*' : '') }*", " +
464
- " in " +
465
- all_role_ref.map(&:role).map(&:fact_type).uniq.map(&:default_reading).map(&:inspect)*', ' +
464
+ " in " +
465
+ all_role_ref.map(&:role).map(&:fact_type).uniq.map(&:default_reading).map(&:inspect)*', ' +
466
466
  ")"
467
467
  end
468
468
 
@@ -476,17 +476,21 @@ module ActiveFacts
476
476
  attr_reader :injected_surrogate_role
477
477
 
478
478
  def is_separate
479
- is_independent or concept.all_concept_annotation.detect{|ca| ca.mapping_annotation == 'separate'}
479
+ is_independent or concept.all_concept_annotation.detect{|ca| ca.mapping_annotation == 'separate'}
480
+ end
481
+
482
+ def is_static
483
+ concept.all_concept_annotation.detect{|ca| ca.mapping_annotation == 'static'}
480
484
  end
481
485
 
482
486
  def all_role_transitive
483
- supertypes_transitive.flat_map(&:all_role)
487
+ supertypes_transitive.flat_map(&:all_role)
484
488
  end
485
489
  end
486
490
 
487
491
  class ValueType
488
492
  def all_supertype
489
- Array(supertype)
493
+ Array(supertype)
490
494
  end
491
495
 
492
496
  def supertypes_transitive
@@ -527,20 +531,20 @@ module ActiveFacts
527
531
  end
528
532
 
529
533
  def assimilation
530
- ti = identifying_type_inheritance and ti.assimilation
534
+ ti = identifying_type_inheritance and ti.assimilation
531
535
  end
532
536
 
533
537
  def is_separate
534
- super || !['absorbed', nil].include?(assimilation)
538
+ super || !['absorbed', nil].include?(assimilation)
535
539
  end
536
540
 
537
541
  def preferred_identifier
538
542
  return @preferred_identifier if @preferred_identifier
539
543
  if fact_type
540
- # Objectified unaries are identified by the ID of the object that plays the role:
541
- if fact_type.all_role.size == 1
542
- return @preferred_identifier = fact_type.all_role.single.object_type.preferred_identifier
543
- end
544
+ # Objectified unaries are identified by the ID of the object that plays the role:
545
+ if fact_type.all_role.size == 1
546
+ return @preferred_identifier = fact_type.all_role.single.object_type.preferred_identifier
547
+ end
544
548
 
545
549
  # When compiling a fact instance, the delayed creation of a preferred identifier might be necessary
546
550
  if c = fact_type.check_and_add_spanning_uniqueness_constraint
@@ -601,7 +605,7 @@ module ActiveFacts
601
605
  ftroles = Array(role.fact_type.all_role)
602
606
 
603
607
  # Skip roles in ternary and higher fact types, they're objectified
604
- # REVISIT: This next line prevents a unary being used as a preferred_identifier:
608
+ # REVISIT: This next line prevents a unary being used as a preferred_identifier:
605
609
  next if ftroles.size != 2
606
610
 
607
611
  trace :pi, "Considering role in #{role.fact_type.describe(role)}"
@@ -696,11 +700,11 @@ module ActiveFacts
696
700
  end
697
701
 
698
702
  def preferred_identifier_roles
699
- preferred_identifier.role_sequence.all_role_ref_in_order.map(&:role)
703
+ preferred_identifier.role_sequence.all_role_ref_in_order.map(&:role)
700
704
  end
701
705
 
702
706
  def rank_in_preferred_identifier(role)
703
- preferred_identifier_roles.index(role)
707
+ preferred_identifier_roles.index(role)
704
708
  end
705
709
 
706
710
  # An array of all direct subtypes:
@@ -727,7 +731,7 @@ module ActiveFacts
727
731
  end
728
732
 
729
733
  def all_supertype
730
- supertypes
734
+ supertypes
731
735
  end
732
736
 
733
737
  # An array of all direct subtypes
@@ -744,13 +748,13 @@ module ActiveFacts
744
748
 
745
749
  def identifying_type_inheritance
746
750
  all_type_inheritance_as_subtype.detect do |ti|
747
- ti.provides_identification
748
- end
751
+ ti.provides_identification
752
+ end
749
753
  end
750
754
 
751
755
  # A subtype does not have a identifying_supertype if it defines its own identifier
752
756
  def identifying_supertype
753
- ti = identifying_type_inheritance and ti.supertype
757
+ ti = identifying_type_inheritance and ti.supertype
754
758
  end
755
759
 
756
760
  def common_supertype(other)
@@ -761,54 +765,54 @@ module ActiveFacts
761
765
  end
762
766
 
763
767
  def add_supertype(supertype, is_identifying_supertype, assimilation)
764
- inheritance_fact = constellation.TypeInheritance(self, supertype, :concept => :new)
765
-
766
- inheritance_fact.assimilation = assimilation
767
-
768
- # Create a reading:
769
- sub_role = constellation.Role(inheritance_fact, 0, :object_type => self, :concept => :new)
770
- super_role = constellation.Role(inheritance_fact, 1, :object_type => supertype, :concept => :new)
771
-
772
- rs = constellation.RoleSequence(:new)
773
- constellation.RoleRef(rs, 0, :role => sub_role)
774
- constellation.RoleRef(rs, 1, :role => super_role)
775
- constellation.Reading(inheritance_fact, 0, :role_sequence => rs, :text => "{0} is a kind of {1}", :is_negative => false)
776
-
777
- rs2 = constellation.RoleSequence(:new)
778
- constellation.RoleRef(rs2, 0, :role => super_role)
779
- constellation.RoleRef(rs2, 1, :role => sub_role)
780
- # Decide in which order to include is a/is an. Provide both, but in order.
781
- n = 'aeioh'.include?(sub_role.object_type.name.downcase[0]) ? 'n' : ''
782
- constellation.Reading(inheritance_fact, 2, :role_sequence => rs2, :text => "{0} is a#{n} {1}", :is_negative => false)
783
-
784
- if is_identifying_supertype
785
- inheritance_fact.provides_identification = true
786
- end
787
-
788
- # Create uniqueness constraints over the subtyping fact type.
789
- p1rs = constellation.RoleSequence(:new)
790
- constellation.RoleRef(p1rs, 0).role = sub_role
791
- pc1 = constellation.PresenceConstraint(:new, :vocabulary => vocabulary)
792
- pc1.name = "#{name}MustHaveSupertype#{supertype.name}"
793
- pc1.role_sequence = p1rs
794
- pc1.is_mandatory = true # A subtype instance must have a supertype instance
795
- pc1.min_frequency = 1
796
- pc1.max_frequency = 1
797
- pc1.is_preferred_identifier = false
798
- trace :constraint, "Made new subtype PC GUID=#{pc1.concept.guid} min=1 max=1 over #{p1rs.describe}"
799
-
800
- p2rs = constellation.RoleSequence(:new)
801
- constellation.RoleRef(p2rs, 0).role = super_role
802
- pc2 = constellation.PresenceConstraint(:new, :vocabulary => vocabulary)
803
- pc2.name = "#{supertype.name}MayBeA#{name}"
804
- pc2.role_sequence = p2rs
805
- pc2.is_mandatory = false
806
- pc2.min_frequency = 0
807
- pc2.max_frequency = 1
808
- # The supertype role often identifies the subtype:
809
- pc2.is_preferred_identifier = inheritance_fact.provides_identification
810
- trace :supertype, "identification of #{name} via supertype #{supertype.name} was #{inheritance_fact.provides_identification ? '' : 'not '}added"
811
- trace :constraint, "Made new supertype PC GUID=#{pc2.concept.guid} min=1 max=1 over #{p2rs.describe}"
768
+ inheritance_fact = constellation.TypeInheritance(self, supertype, :concept => :new)
769
+
770
+ inheritance_fact.assimilation = assimilation
771
+
772
+ # Create a reading:
773
+ sub_role = constellation.Role(inheritance_fact, 0, :object_type => self, :concept => :new)
774
+ super_role = constellation.Role(inheritance_fact, 1, :object_type => supertype, :concept => :new)
775
+
776
+ rs = constellation.RoleSequence(:new)
777
+ constellation.RoleRef(rs, 0, :role => sub_role)
778
+ constellation.RoleRef(rs, 1, :role => super_role)
779
+ constellation.Reading(inheritance_fact, 0, :role_sequence => rs, :text => "{0} is a kind of {1}", :is_negative => false)
780
+
781
+ rs2 = constellation.RoleSequence(:new)
782
+ constellation.RoleRef(rs2, 0, :role => super_role)
783
+ constellation.RoleRef(rs2, 1, :role => sub_role)
784
+ # Decide in which order to include is a/is an. Provide both, but in order.
785
+ n = 'aeioh'.include?(sub_role.object_type.name.downcase[0]) ? 'n' : ''
786
+ constellation.Reading(inheritance_fact, 2, :role_sequence => rs2, :text => "{0} is a#{n} {1}", :is_negative => false)
787
+
788
+ if is_identifying_supertype
789
+ inheritance_fact.provides_identification = true
790
+ end
791
+
792
+ # Create uniqueness constraints over the subtyping fact type.
793
+ p1rs = constellation.RoleSequence(:new)
794
+ constellation.RoleRef(p1rs, 0).role = sub_role
795
+ pc1 = constellation.PresenceConstraint(:new, :vocabulary => vocabulary)
796
+ pc1.name = "#{name}MustHaveSupertype#{supertype.name}"
797
+ pc1.role_sequence = p1rs
798
+ pc1.is_mandatory = true # A subtype instance must have a supertype instance
799
+ pc1.min_frequency = 1
800
+ pc1.max_frequency = 1
801
+ pc1.is_preferred_identifier = false
802
+ trace :constraint, "Made new subtype PC GUID=#{pc1.concept.guid} min=1 max=1 over #{p1rs.describe}"
803
+
804
+ p2rs = constellation.RoleSequence(:new)
805
+ constellation.RoleRef(p2rs, 0).role = super_role
806
+ pc2 = constellation.PresenceConstraint(:new, :vocabulary => vocabulary)
807
+ pc2.name = "#{supertype.name}MayBeA#{name}"
808
+ pc2.role_sequence = p2rs
809
+ pc2.is_mandatory = false
810
+ pc2.min_frequency = 0
811
+ pc2.max_frequency = 1
812
+ # The supertype role often identifies the subtype:
813
+ pc2.is_preferred_identifier = inheritance_fact.provides_identification
814
+ trace :supertype, "identification of #{name} via supertype #{supertype.name} was #{inheritance_fact.provides_identification ? '' : 'not '}added"
815
+ trace :constraint, "Made new supertype PC GUID=#{pc2.concept.guid} min=1 max=1 over #{p2rs.describe}"
812
816
  end
813
817
 
814
818
  # This entity type has just objectified a fact type.
@@ -818,7 +822,13 @@ module ActiveFacts
818
822
  next if role.mirror_role_as_base_role # Already exists
819
823
  link_fact_type = @constellation.LinkFactType(:new, :implying_role => role)
820
824
  objectification_role = @constellation.Role(link_fact_type, 0, :object_type => self, :concept => :new)
821
- mirror_role = @constellation.MirrorRole(link_fact_type, 1, :concept => :new, :object_type => role.object_type, :base_role => role)
825
+ mirror_role = @constellation.MirrorRole(
826
+ link_fact_type, 1,
827
+ :concept => :new,
828
+ :object_type => role.object_type,
829
+ :base_role => role,
830
+ :role_name => role.role_name
831
+ )
822
832
 
823
833
  link_fact_type.concept.implication_rule =
824
834
  objectification_role.concept.implication_rule =
@@ -973,7 +983,7 @@ module ActiveFacts
973
983
  end
974
984
 
975
985
  def all_constrained_role
976
- Array(role_as_role_value_constraint) # Empty unless it's a role value constraint
986
+ Array(role_as_role_value_constraint) # Empty unless it's a role value constraint
977
987
  end
978
988
  end
979
989
 
@@ -1047,11 +1057,11 @@ module ActiveFacts
1047
1057
  end
1048
1058
 
1049
1059
  def covers_role role
1050
- role_sequence.all_role_ref.map(&:role).include?(role)
1060
+ role_sequence.all_role_ref.map(&:role).include?(role)
1051
1061
  end
1052
1062
 
1053
1063
  def all_constrained_role
1054
- role_sequence.all_role_ref.map(&:role)
1064
+ role_sequence.all_role_ref.map(&:role)
1055
1065
  end
1056
1066
  end
1057
1067
 
@@ -1065,8 +1075,8 @@ module ActiveFacts
1065
1075
  end
1066
1076
 
1067
1077
  def all_constrained_role
1068
- subset_role_sequence.all_role_ref.map(&:role) +
1069
- superset_role_sequence.all_role_ref.map(&:role)
1078
+ subset_role_sequence.all_role_ref.map(&:role) +
1079
+ superset_role_sequence.all_role_ref.map(&:role)
1070
1080
  end
1071
1081
  end
1072
1082
 
@@ -1074,8 +1084,8 @@ module ActiveFacts
1074
1084
  def describe
1075
1085
  "("+
1076
1086
  role_sequence.all_role_ref_in_order.map{|rr| rr.role.name }*", " +
1077
- " in " +
1078
- role_sequence.all_role_ref.map(&:role).map(&:fact_type).uniq.map(&:default_reading).map(&:inspect)*', ' +
1087
+ " in " +
1088
+ role_sequence.all_role_ref.map(&:role).map(&:fact_type).uniq.map(&:default_reading).map(&:inspect)*', ' +
1079
1089
  ")"
1080
1090
  end
1081
1091
  end
@@ -1084,30 +1094,30 @@ module ActiveFacts
1084
1094
  def describe
1085
1095
  self.class.basename+'(' +
1086
1096
  all_set_comparison_roles.map do |scr|
1087
- '['+
1097
+ '['+
1088
1098
  scr.role_sequence.all_role_ref.map{|rr|
1089
- rr.role.fact_type.describe(rr.role)
1090
- }*',' +
1091
- ']'
1099
+ rr.role.fact_type.describe(rr.role)
1100
+ }*',' +
1101
+ ']'
1092
1102
  end*',' +
1093
1103
  ')'
1094
1104
  end
1095
1105
 
1096
1106
  def all_constrained_role
1097
- all_set_comparison_roles.map(&:role_sequence).flat_map(&:all_role_ref).map(&:role).uniq
1107
+ all_set_comparison_roles.map(&:role_sequence).flat_map(&:all_role_ref).map(&:role).uniq
1098
1108
  end
1099
1109
  end
1100
1110
 
1101
1111
  class SetEqualityConstraint
1102
1112
  def describe
1103
- all_set_comparison_roles.map(&:describe) * " if and only if "
1113
+ all_set_comparison_roles.map(&:describe) * " if and only if "
1104
1114
  end
1105
1115
  end
1106
1116
 
1107
1117
  class SetExclusionConstraint
1108
1118
  def describe
1109
- (is_mandatory ? "exactly one of " : "at most one of ") +
1110
- all_set_comparison_roles.map(&:describe) * " or "
1119
+ (is_mandatory ? "exactly one of " : "at most one of ") +
1120
+ all_set_comparison_roles.map(&:describe) * " or "
1111
1121
  end
1112
1122
  end
1113
1123
 
@@ -1123,7 +1133,7 @@ module ActiveFacts
1123
1133
  end
1124
1134
 
1125
1135
  def all_constrained_role
1126
- [role, other_role]
1136
+ [role, other_role]
1127
1137
  end
1128
1138
  end
1129
1139
 
@@ -1263,45 +1273,51 @@ module ActiveFacts
1263
1273
 
1264
1274
  class LinkFactType
1265
1275
  def all_reading
1266
- if super.size == 0
1267
- # REVISIT: Should we create reading orders independently?
1268
- # No user-defined readings have been defined, so it's time to stop being lazy:
1269
- objectification_role, mirror_role = *all_role_in_order
1270
- rs = constellation.RoleSequence(:new)
1271
- rr0 = constellation.RoleRef(rs, 0, :role => objectification_role)
1272
- rr1 = constellation.RoleRef(rs, 1, :role => mirror_role)
1273
- r0 = constellation.Reading(self, 0, :role_sequence => rs, :text => "{0} involves {1}", :is_negative => false) # REVISIT: This assumes English!
1274
- r1 = constellation.Reading(self, 1, :role_sequence => rs, :text => "{1} is involved in {0}", :is_negative => false)
1275
- end
1276
- @all_reading
1276
+ if super.size == 0
1277
+ # No user-defined readings have been defined, so it's time to stop being lazy:
1278
+ objectification_role, mirror_role = *all_role_in_order
1279
+
1280
+ preferred_role_ref = mirror_role.base_role.preferred_reference
1281
+
1282
+ rs = constellation.RoleSequence(:new)
1283
+ rr0 = constellation.RoleRef(rs, 0, :role => objectification_role)
1284
+ rr1 = constellation.RoleRef(rs, 1, :role => mirror_role)
1285
+
1286
+ rr1.leading_adjective = preferred_role_ref.leading_adjective
1287
+ rr1.trailing_adjective = preferred_role_ref.trailing_adjective
1288
+
1289
+ r0 = constellation.Reading(self, 0, :role_sequence => rs, :text => "{0} involves {1}", :is_negative => false) # REVISIT: This assumes English!
1290
+ r1 = constellation.Reading(self, 1, :role_sequence => rs, :text => "{1} is involved in {0}", :is_negative => false)
1291
+ end
1292
+ @all_reading
1277
1293
  end
1278
1294
  end
1279
1295
 
1280
1296
  class MirrorRole
1281
1297
  def is_mandatory
1282
- base_role.is_mandatory
1298
+ base_role.is_mandatory
1283
1299
  end
1284
1300
 
1285
1301
  def is_unique
1286
- base_role.is_unique
1302
+ base_role.is_unique
1287
1303
  end
1288
1304
 
1289
1305
  def is_functional
1290
- base_role.is_functional
1306
+ base_role.is_functional
1291
1307
  end
1292
1308
 
1293
1309
  def uniqueness_constraint
1294
- raise "A MirrorRole should not be asked for its uniqueness constraints"
1310
+ raise "A MirrorRole should not be asked for its uniqueness constraints"
1295
1311
  end
1296
1312
 
1297
1313
  %w{all_ring_constraint_as_other_role all_ring_constraint all_role_value role_value_constraint
1298
1314
  }.each do |accessor|
1299
- define_method(accessor.to_sym) do
1300
- base_role.send(accessor.to_sym)
1301
- end
1302
- define_method("#{accessor}=".to_sym) do |*a|
1303
- raise "REVISIT: It's a bad idea to try to set #{accessor} for a MirrorRole"
1304
- end
1315
+ define_method(accessor.to_sym) do
1316
+ base_role.send(accessor.to_sym)
1317
+ end
1318
+ define_method("#{accessor}=".to_sym) do |*a|
1319
+ raise "REVISIT: It's a bad idea to try to set #{accessor} for a MirrorRole"
1320
+ end
1305
1321
  end
1306
1322
  end
1307
1323
 
@@ -1351,7 +1367,8 @@ module ActiveFacts
1351
1367
  if fact_type.entity_type
1352
1368
  objectification_role_supertypes =
1353
1369
  fact_type.entity_type.supertypes_transitive+object_type.supertypes_transitive
1354
- # Find the objectification role here:
1370
+ # Find the objectification role here:
1371
+ return nil unless role.link_fact_type # REVISIT: Link Fact Types are missing; happens from half-baked surrogate transform
1355
1372
  objectification_role = role.link_fact_type.all_role.detect{|r| !r.is_a?(MirrorRole)}
1356
1373
  else
1357
1374
  objectification_role_supertypes = counterpart_role_supertypes
@@ -1504,64 +1521,64 @@ module ActiveFacts
1504
1521
 
1505
1522
  class Composition
1506
1523
  def all_composite_by_name
1507
- all_composite.keys.sort_by do |key|
1524
+ all_composite.keys.sort_by do |key|
1508
1525
  @constellation.Composite[key].mapping.name
1509
1526
  end.map do |key|
1510
1527
  composite = @constellation.Composite[key]
1511
- yield composite if block_given?
1512
- composite
1513
- end
1528
+ yield composite if block_given?
1529
+ composite
1530
+ end
1514
1531
  end
1515
1532
  end
1516
1533
 
1517
1534
  class Composite
1518
1535
  def inspect
1519
- "Composite #{mapping.inspect}"
1536
+ "Composite #{mapping.inspect}"
1520
1537
  end
1521
1538
 
1522
1539
  def all_index
1523
- all_access_path.
1524
- select{|ap| ap.is_a?(Index)}.
1525
- sort_by{|ap| [ap.composite_as_primary_index ? 0 : 1] + Array(ap.name)+ap.all_index_field.map(&:inspect) } # REVISIT: Fix hack for stable ordering
1540
+ all_access_path.
1541
+ select{|ap| ap.is_a?(Index)}.
1542
+ sort_by{|ap| [ap.composite_as_primary_index ? 0 : 1] + Array(ap.name)+ap.all_index_field.map(&:inspect) } # REVISIT: Fix hack for stable ordering
1526
1543
  end
1527
1544
 
1528
1545
  def show_trace
1529
- trace :composition, inspect do
1530
- trace :composition?, "Columns" do
1531
- mapping.show_trace
1532
- end
1533
-
1534
- indices = all_index
1535
- unless indices.empty?
1536
- trace :composition, "Indices" do
1537
- indices.each do |ap|
1538
- ap.show_trace
1539
- end
1540
- end
1541
- end
1542
-
1543
- inbound = all_access_path.
1544
- select{|ap| ap.is_a?(ForeignKey)}.
1545
- sort_by{|fk| [fk.source_composite.mapping.name, fk.absorption.inspect]+fk.all_foreign_key_field.map(&:inspect)+fk.all_index_field.map(&:inspect) }
1546
- unless inbound.empty?
1547
- trace :composition, "Foreign keys inbound" do
1548
- inbound.each do |fk|
1549
- fk.show_trace
1550
- end
1551
- end
1552
- end
1553
-
1554
- outbound =
1555
- all_foreign_key_as_source_composite.
1556
- sort_by{|fk| [fk.source_composite.mapping.name, fk.absorption.inspect]+fk.all_index_field.map(&:inspect)+fk.all_foreign_key_field.map(&:inspect) }
1557
- unless outbound.empty?
1558
- trace :composition, "Foreign keys outbound" do
1559
- outbound.each do |fk|
1560
- fk.show_trace
1561
- end
1562
- end
1563
- end
1564
- end
1546
+ trace :composition, inspect do
1547
+ trace :composition?, "Columns" do
1548
+ mapping.show_trace
1549
+ end
1550
+
1551
+ indices = all_index
1552
+ unless indices.empty?
1553
+ trace :composition, "Indices" do
1554
+ indices.each do |ap|
1555
+ ap.show_trace
1556
+ end
1557
+ end
1558
+ end
1559
+
1560
+ inbound = all_access_path.
1561
+ select{|ap| ap.is_a?(ForeignKey)}.
1562
+ sort_by{|fk| [fk.source_composite.mapping.name, fk.absorption.inspect]+fk.all_foreign_key_field.map(&:inspect)+fk.all_index_field.map(&:inspect) }
1563
+ unless inbound.empty?
1564
+ trace :composition, "Foreign keys inbound" do
1565
+ inbound.each do |fk|
1566
+ fk.show_trace
1567
+ end
1568
+ end
1569
+ end
1570
+
1571
+ outbound =
1572
+ all_foreign_key_as_source_composite.
1573
+ sort_by{|fk| [fk.source_composite.mapping.name, fk.absorption.inspect]+fk.all_index_field.map(&:inspect)+fk.all_foreign_key_field.map(&:inspect) }
1574
+ unless outbound.empty?
1575
+ trace :composition, "Foreign keys outbound" do
1576
+ outbound.each do |fk|
1577
+ fk.show_trace
1578
+ end
1579
+ end
1580
+ end
1581
+ end
1565
1582
  end
1566
1583
 
1567
1584
  # Provide a stable ordering for indices, based on the ordering of columns by rank:
@@ -1570,82 +1587,88 @@ module ActiveFacts
1570
1587
  reject{|ap| ap.is_a?(ActiveFacts::Metamodel::ForeignKey)}.
1571
1588
  sort_by{|ap| ap.all_index_field.to_a.flat_map{|ixf| ixf.component.rank_path}.compact }
1572
1589
  end
1590
+
1591
+ def all_foreign_key_as_target_composite
1592
+ all_access_path.
1593
+ select{|ap| ap.is_a?(ForeignKey)}.
1594
+ sort_by{|ap| ap.all_foreign_key_field.map(&:inspect) }
1595
+ end
1573
1596
  end
1574
1597
 
1575
1598
  class AccessPath
1576
1599
  def show_trace
1577
- trace :composition, inspect do
1578
- if is_a?(ForeignKey)
1579
- # First list any fields in a foreign key
1580
- all_foreign_key_field.sort_by(&:ordinal).each do |fk|
1581
- raise "Internal error: Foreign key not in foreign table!" if fk.component.root != source_composite
1582
- trace :composition, fk.inspect
1583
- end
1584
- end
1585
- # Now list the fields in the primary key
1586
- all_index_field.sort_by(&:ordinal).each do |ak|
1587
- trace :composition, ak.inspect
1588
- end
1589
- end
1600
+ trace :composition, inspect do
1601
+ if is_a?(ForeignKey)
1602
+ # First list any fields in a foreign key
1603
+ all_foreign_key_field.sort_by(&:ordinal).each do |fkf|
1604
+ $stderr.puts "Internal error: Foreign key field to #{fkf.component.column_name} is in #{fkf.component.root.mapping.name} not #{source_composite.mapping.name}!" if fkf.component.root != source_composite
1605
+ trace :composition, fkf.inspect
1606
+ end
1607
+ end
1608
+ # Now list the fields in the primary key
1609
+ all_index_field.sort_by(&:ordinal).each do |ak|
1610
+ trace :composition, ak.inspect
1611
+ end
1612
+ end
1590
1613
  end
1591
1614
 
1592
1615
  def position_in_index component
1593
- all_index_field.sort_by(&:ordinal).map(&:component).index(component)
1616
+ all_index_field.sort_by(&:ordinal).map(&:component).index(component)
1594
1617
  end
1595
1618
  end
1596
1619
 
1597
1620
  class Index
1598
1621
  def inspect
1599
- case
1600
- when !is_unique
1601
- 'Non-unique index'
1602
- when composite_as_primary_index
1603
- 'Primary index'
1604
- else
1605
- 'Unique index'
1606
- end +
1607
- (name ? " #{name.inspect}" : '') +
1608
- " to #{composite.mapping.name}" +
1609
- (presence_constraint ? " over #{presence_constraint.describe}" : '')
1622
+ case
1623
+ when !is_unique
1624
+ 'Non-unique index'
1625
+ when composite_as_primary_index
1626
+ 'Primary index'
1627
+ else
1628
+ 'Unique index'
1629
+ end +
1630
+ (name ? " #{name.inspect}" : '') +
1631
+ " to #{composite.mapping.name}" +
1632
+ (presence_constraint ? " over #{presence_constraint.describe}" : '')
1610
1633
  end
1611
1634
  end
1612
1635
 
1613
1636
  class ForeignKey
1614
1637
  def inspect
1615
- "Foreign Key" +
1616
- (name ? " #{name.inspect}" : '') +
1617
- " from #{source_composite.mapping.name} to #{composite.mapping.name}" +
1618
- (absorption ? " over #{absorption.inspect}" : '')
1638
+ "Foreign Key" +
1639
+ (name ? " #{name.inspect}" : '') +
1640
+ " from #{(sc = source_composite) ? sc.mapping.name : 'NO-SOURCE'} to #{composite.mapping.name}" +
1641
+ (absorption ? " over #{absorption.inspect}" : '')
1619
1642
  end
1620
1643
  end
1621
1644
 
1622
1645
  class IndexField
1623
1646
  def inspect
1624
- "IndexField part #{ordinal} in #{component.root.mapping.name} references #{component.inspect}" +
1625
- (value ? " discriminated by #{value.inspect}" : '')
1647
+ "IndexField part #{ordinal} in #{component.root.mapping.name} references #{component.inspect}" +
1648
+ (value ? " discriminated by #{value.inspect}" : '')
1626
1649
  end
1627
1650
  end
1628
1651
 
1629
1652
  class ForeignKeyField
1630
1653
  def inspect
1631
- operation = value ? "filters by value #{value} of" : "is"
1632
- "ForeignKeyField part #{ordinal} in #{component.root.mapping.name} #{operation} #{component.inspect}" +
1633
- (value ? " discriminated by #{value.inspect}" : '')
1654
+ operation = value ? "filters by value #{value} of" : "is"
1655
+ "ForeignKeyField part #{ordinal} in #{component.root.mapping.name} #{operation} #{component.inspect}" +
1656
+ (value ? " discriminated by #{value.inspect}" : '')
1634
1657
  end
1635
1658
  end
1636
1659
 
1637
1660
  class Mapping
1638
1661
  def inspect
1639
- "#{self.class.basename} (#{rank_kind})#{parent ? " in #{parent.name}" :''} of #{name && name != '' ? name : '<anonymous>'}"
1662
+ "#{self.class.basename} (#{rank_kind})#{parent ? " in #{parent.name}" :''} of #{name && name != '' ? name : '<anonymous>'}"
1640
1663
  end
1641
1664
 
1642
1665
  def show_trace
1643
- trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}" do
1644
- yield if block_given?
1645
- all_member.sort_by{|member| [member.ordinal, member.name]}.each do |member|
1646
- member.show_trace
1647
- end
1648
- end
1666
+ trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}" do
1667
+ yield if block_given?
1668
+ all_member.sort_by{|member| [member.ordinal, member.name]}.each do |member|
1669
+ member.show_trace
1670
+ end
1671
+ end
1649
1672
  end
1650
1673
 
1651
1674
  # Recompute a contiguous member ranking fron zero, based on current membership:
@@ -1653,7 +1676,7 @@ module ActiveFacts
1653
1676
  all_member.each(&:uncache_rank_key)
1654
1677
  next_rank = 0
1655
1678
  all_member.
1656
- sort_by(&:rank_key).
1679
+ sort_by(&:rank_key).
1657
1680
  each do |member|
1658
1681
  member.ordinal = next_rank
1659
1682
  next_rank += 1
@@ -1661,14 +1684,14 @@ module ActiveFacts
1661
1684
  end
1662
1685
 
1663
1686
  def root
1664
- composite || parent && parent.root
1687
+ composite || parent && parent.root
1665
1688
  end
1666
1689
 
1667
- def leaves
1690
+ def all_leaf
1668
1691
  re_rank
1669
1692
  all_member.sort_by(&:ordinal).flat_map do |member|
1670
1693
  if member.is_a?(Mapping) && member.all_member.size > 0
1671
- member.leaves
1694
+ member.all_leaf
1672
1695
  else
1673
1696
  member
1674
1697
  end
@@ -1676,192 +1699,201 @@ module ActiveFacts
1676
1699
  end
1677
1700
 
1678
1701
  def is_mandatory
1679
- true
1702
+ true
1680
1703
  end
1681
1704
 
1682
1705
  def path_mandatory
1683
- true
1706
+ true
1684
1707
  end
1685
1708
  end
1686
1709
 
1687
1710
  class Nesting
1688
1711
  def show_trace
1689
- # The index role has a counterpart played by the parent object in the enclosing Absorption
1690
- reading = index_role.fact_type.default_reading
1691
- trace :composition, "#{ordinal}: Nesting under #{index_role.object_type.name}#{key_name ? " (as #{key_name.inspect})" : ''} in #{reading.inspect}}"
1712
+ # The index role has a counterpart played by the parent object in the enclosing Absorption
1713
+ reading = index_role.fact_type.default_reading
1714
+ trace :composition, "#{ordinal}: Nesting under #{index_role.object_type.name}#{key_name ? " (as #{key_name.inspect})" : ''} in #{reading.inspect}}"
1692
1715
  end
1693
1716
  end
1694
1717
 
1695
1718
  class Absorption
1696
1719
  def inspect_reading
1697
- parent_role.fact_type.reading_preferably_starting_with_role(parent_role).expand.inspect
1720
+ parent_role.fact_type.reading_preferably_starting_with_role(parent_role).expand.inspect
1698
1721
  end
1699
1722
 
1700
1723
  def inspect
1701
- "#{super}#{full_absorption ? ' (full)' : ''
1702
- } in #{inspect_reading}#{
1703
- # If we have a related forward absorption, we're by definition a reverse absorption
1704
- if forward_absorption
1705
- ' (reverse)'
1706
- else
1707
- # If we have a related reverse absorption, we're by definition a forward absorption
1708
- reverse_absorption ? ' (forward)' : ''
1709
- end
1710
- }"
1724
+ "#{super}#{full_absorption ? ' (full)' : ''
1725
+ } in #{inspect_reading}#{
1726
+ # If we have a related forward absorption, we're by definition a reverse absorption
1727
+ if forward_absorption
1728
+ ' (reverse)'
1729
+ else
1730
+ # If we have a related reverse absorption, we're by definition a forward absorption
1731
+ reverse_absorption ? ' (forward)' : ''
1732
+ end
1733
+ }"
1711
1734
  end
1712
1735
 
1713
1736
  def show_trace
1714
- super() do
1715
- if nesting_mode || all_nesting.size > 0
1716
- trace :composition, "Nested using #{nesting_mode || 'unspecified'} mode" do
1717
- all_nesting.sort_by(&:ordinal).each(&:show_trace)
1718
- end
1719
- end
1720
- end
1737
+ super() do
1738
+ if nesting_mode || all_nesting.size > 0
1739
+ trace :composition, "Nested using #{nesting_mode || 'unspecified'} mode" do
1740
+ all_nesting.sort_by(&:ordinal).each(&:show_trace)
1741
+ end
1742
+ end
1743
+ end
1721
1744
  end
1722
1745
 
1723
1746
  def is_type_inheritance
1724
- child_role.fact_type.is_a?(TypeInheritance) && child_role.fact_type
1747
+ child_role.fact_type.is_a?(TypeInheritance) && child_role.fact_type
1725
1748
  end
1726
1749
 
1727
1750
  def is_supertype_absorption
1728
- is_type_inheritance && child_role.fact_type.supertype == object_type
1751
+ is_type_inheritance && child_role.fact_type.supertype == object_type
1729
1752
  end
1730
1753
 
1731
1754
  def is_subtype_absorption
1732
- is_type_inheritance && parent_role.fact_type.supertype == object_type
1755
+ is_type_inheritance && parent_role.fact_type.supertype == object_type
1733
1756
  end
1734
1757
 
1735
1758
  def is_preferred_direction
1736
- return child_role.is_mirror_role if child_role.is_mirror_role != parent_role.is_mirror_role
1737
-
1738
- # Prefer to absorb the one into the many:
1739
- p_un = parent_role.is_unique
1740
- c_un = child_role.is_unique
1741
- return p_un if p_un != c_un
1742
-
1743
- # Prefer to absorb a subtype into the supertype (opposite if separate or partitioned)
1744
- if (ti = child_role.fact_type).is_a?(TypeInheritance)
1745
- is_subtype = child_role == ti.subtype_role # Supertype absorbing subtype
1746
- subtype = ti.subtype_role.object_type # Subtype doesn't want to be absorbed?
1747
- # REVISIT: We need fewer ways to say this:
1748
- child_separate = ["separate", "partitioned"].include?(ti.assimilation) ||
1749
- subtype.is_independent ||
1750
- subtype.concept.all_concept_annotation.detect{|ca| ca.mapping_annotation == 'separate'}
1751
- return !is_subtype != !child_separate
1752
- end
1753
-
1754
- if p_un && c_un
1755
- # Prefer to absorb a ValueType into an EntityType rather than the other way around:
1756
- pvt = parent_role.object_type.is_a?(ActiveFacts::Metamodel::ValueType)
1757
- cvt = child_role.object_type.is_a?(ActiveFacts::Metamodel::ValueType)
1758
- return cvt if pvt != cvt
1759
-
1760
- if !pvt
1761
- # Force the decision if one EntityType identifies another
1762
- return true if child_role.base_role.is_identifying # Parent is identified by child role, correct
1763
- return false if parent_role.base_role.is_identifying # Child is identified by parent role, incorrect
1764
- end
1765
-
1766
- # Primary absorption absorbs the object playing the mandatory role into the non-mandatory:
1767
- return child_role.is_mandatory if !parent_role.is_mandatory != !child_role.is_mandatory
1768
- end
1769
-
1770
- if parent_role.object_type.is_a?(ActiveFacts::Metamodel::EntityType) &&
1771
- child_role.object_type.is_a?(ActiveFacts::Metamodel::EntityType)
1772
- # Prefer to absorb an identifying element into the EntityType it identifies
1773
- return true if parent_role.object_type.preferred_identifier.
1774
- role_sequence.all_role_ref.map(&:role).detect{|r|
1775
- r.object_type == child_role.object_type
1776
- }
1777
- return false if child_role.object_type.preferred_identifier.
1778
- role_sequence.all_role_ref.map(&:role).detect{|r|
1779
- r.object_type == parent_role.object_type
1780
- }
1781
- end
1782
-
1783
- # For stability, absorb a later-named role into an earlier-named one:
1784
- return parent_role.name < child_role.name
1759
+ return child_role.is_mirror_role if child_role.is_mirror_role != parent_role.is_mirror_role
1760
+
1761
+ # Prefer to absorb the one into the many:
1762
+ p_un = parent_role.is_unique
1763
+ c_un = child_role.is_unique
1764
+ return p_un if p_un != c_un
1765
+
1766
+ # Prefer to absorb a subtype into the supertype (opposite if separate or partitioned)
1767
+ if (ti = child_role.fact_type).is_a?(TypeInheritance)
1768
+ is_subtype = child_role == ti.subtype_role # Supertype absorbing subtype
1769
+ subtype = ti.subtype_role.object_type # Subtype doesn't want to be absorbed?
1770
+ # REVISIT: We need fewer ways to say this:
1771
+ child_separate = ["separate", "partitioned"].include?(ti.assimilation) ||
1772
+ subtype.is_independent ||
1773
+ subtype.concept.all_concept_annotation.detect{|ca| ca.mapping_annotation == 'separate'}
1774
+ return !is_subtype != !child_separate
1775
+ end
1776
+
1777
+ if p_un && c_un
1778
+ # Prefer to absorb a ValueType into an EntityType rather than the other way around:
1779
+ pvt = parent_role.object_type.is_a?(ActiveFacts::Metamodel::ValueType)
1780
+ cvt = child_role.object_type.is_a?(ActiveFacts::Metamodel::ValueType)
1781
+ return cvt if pvt != cvt
1782
+
1783
+ if !pvt
1784
+ # Force the decision if one EntityType identifies another
1785
+ return true if child_role.base_role.is_identifying # Parent is identified by child role, correct
1786
+ return false if parent_role.base_role.is_identifying # Child is identified by parent role, incorrect
1787
+ end
1788
+
1789
+ # Primary absorption absorbs the object playing the mandatory role into the non-mandatory:
1790
+ return child_role.is_mandatory if !parent_role.is_mandatory != !child_role.is_mandatory
1791
+ end
1792
+
1793
+ if parent_role.object_type.is_a?(ActiveFacts::Metamodel::EntityType) &&
1794
+ child_role.object_type.is_a?(ActiveFacts::Metamodel::EntityType)
1795
+ # Prefer to absorb an identifying element into the EntityType it identifies
1796
+ return true if parent_role.object_type.preferred_identifier.
1797
+ role_sequence.all_role_ref.map(&:role).detect{|r|
1798
+ r.object_type == child_role.object_type
1799
+ }
1800
+ return false if child_role.object_type.preferred_identifier.
1801
+ role_sequence.all_role_ref.map(&:role).detect{|r|
1802
+ r.object_type == parent_role.object_type
1803
+ }
1804
+ end
1805
+
1806
+ # For stability, absorb a later-named role into an earlier-named one:
1807
+ return parent_role.name < child_role.name
1785
1808
  end
1786
1809
 
1787
1810
  def flip!
1788
- raise "REVISIT: Need to flip FullAbsorption on #{inspect}" if full_absorption or reverse_absorption && reverse_absorption.full_absorption or forward_absorption && forward_absorption.full_absorption
1789
- if (other = forward_absorption)
1790
- # We point at them - make them point at us instead
1791
- self.forward_absorption = nil
1792
- self.reverse_absorption = other
1793
- elsif (other = reverse_absorption)
1794
- # They point at us - make us point at them instead
1795
- self.reverse_absorption = nil
1796
- self.forward_absorption = other
1797
- else
1798
- raise "Absorption cannot be flipped as it has no reverse"
1799
- end
1811
+ raise "REVISIT: Need to flip FullAbsorption on #{inspect}" if full_absorption or reverse_absorption && reverse_absorption.full_absorption or forward_absorption && forward_absorption.full_absorption
1812
+ if (other = forward_absorption)
1813
+ # We point at them - make them point at us instead
1814
+ self.forward_absorption = nil
1815
+ self.reverse_absorption = other
1816
+ elsif (other = reverse_absorption)
1817
+ # They point at us - make us point at them instead
1818
+ self.reverse_absorption = nil
1819
+ self.forward_absorption = other
1820
+ else
1821
+ raise "Absorption cannot be flipped as it has no reverse"
1822
+ end
1800
1823
  end
1801
1824
 
1802
1825
  def all_role
1803
- ([child_role, parent_role] + all_nesting.map(&:index_role)).flat_map{|role| [role, role.base_role]}.uniq
1826
+ ([child_role, parent_role] + all_nesting.map(&:index_role)).flat_map{|role| [role, role.base_role]}.uniq
1804
1827
  end
1805
1828
 
1806
1829
  def value_constraints
1807
- return [] unless object_type.is_a?(ValueType)
1808
- object_type.supertypes_transitive.flat_map{|vt| Array(vt.value_constraint)}
1830
+ return [] unless object_type.is_a?(ValueType)
1831
+ object_type.supertypes_transitive.flat_map{|vt| Array(vt.value_constraint)}
1809
1832
  end
1810
1833
 
1811
1834
  def is_mandatory
1812
- parent_role.is_mandatory
1835
+ parent_role.is_mandatory
1813
1836
  end
1814
1837
 
1815
1838
  def path_mandatory
1816
- is_mandatory && parent.path_mandatory
1839
+ is_mandatory && parent.path_mandatory
1817
1840
  end
1818
1841
  end
1819
1842
 
1820
1843
  class FullAbsorption
1821
1844
  def inspect
1822
- "Full #{absorption.inspect}"
1845
+ "Full #{absorption.inspect}"
1823
1846
  end
1824
1847
  end
1825
1848
 
1826
1849
  class Indicator
1827
1850
  def inspect
1828
- "#{self.class.basename} #{role.fact_type.default_reading.inspect}"
1851
+ "#{self.class.basename} #{role.fact_type.default_reading.inspect}"
1829
1852
  end
1830
1853
 
1831
1854
  def show_trace
1832
- trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect} #{name ? "(as #{name.inspect})" : ''}"
1855
+ trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect} #{name ? "(as #{name.inspect})" : ''}"
1833
1856
  end
1834
1857
 
1835
1858
  def all_role
1836
- [role, role.base_role].uniq
1859
+ [role, role.base_role].uniq
1837
1860
  end
1838
1861
 
1839
1862
  def is_mandatory
1840
- false
1863
+ false
1841
1864
  end
1842
1865
  end
1843
1866
 
1844
1867
  class Discriminator
1845
1868
  def inspect
1846
- "#{self.class.basename} between #{all_discriminated_role.map{|dr|dr.fact_type.default_reading.inspect}*', '}"
1869
+ "#{self.class.basename} between #{all_discriminated_role.map{|dr|dr.fact_type.default_reading.inspect}*', '}"
1847
1870
  end
1848
1871
 
1849
1872
  def show_trace
1850
- trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect} #{name ? " (as #{name.inspect})" : ''}"
1873
+ trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect} #{name ? " (as #{name.inspect})" : ''}"
1851
1874
  end
1852
1875
 
1853
1876
  def all_role
1854
- all_discriminated_role.map(&:role).flat_map{|role| [role, role.base_role]}.uniq
1877
+ all_discriminated_role.map(&:role).flat_map{|role| [role, role.base_role]}.uniq
1878
+ end
1879
+ end
1880
+
1881
+ class SurrogateKey
1882
+ def is_identifying
1883
+ if pk = root.primary_index
1884
+ return pk.all_index_field.detect{|ixf| ixf.component == self}
1885
+ end
1886
+ !parent.parent
1855
1887
  end
1856
1888
  end
1857
1889
 
1858
1890
  class ValueField
1859
1891
  def inspect
1860
- "#{self.class.basename} #{object_type.name.inspect}"
1892
+ "#{self.class.basename} #{object_type.name.inspect}"
1861
1893
  end
1862
1894
 
1863
1895
  def show_trace
1864
- trace :composition, "#{ordinal}: #{inspect}#{name ? " (as #{name.inspect})" : ''}"
1896
+ trace :composition, "#{ordinal}: #{inspect}#{name ? " (as #{name.inspect})" : ''}"
1865
1897
  end
1866
1898
  end
1867
1899
 
@@ -1869,128 +1901,130 @@ module ActiveFacts
1869
1901
  # The ranking key of a component indicates its importance to its parent:
1870
1902
  # Ranking assigns a total order, but is computed in groups:
1871
1903
  RANK_SURROGATE = 0
1872
- RANK_SUPER = 1 # Supertypes, with the identifying supertype first, others alphabetical
1873
- RANK_IDENT = 2 # Identifying components (absorptions, indicator), in order of the identifier
1874
- RANK_VALUE = 3 # A ValueField
1875
- RANK_INJECTION = 4 # Injections, in alphabetical order
1876
- RANK_DISCRIMINATOR = 5 # Discriminator components, in alphabetical order
1877
- RANK_FOREIGN = 6 # REVISIT: Foreign key components
1878
- RANK_INDICATOR = 7 # Indicators in alphabetical order
1879
- RANK_MANDATORY = 8 # Absorption: unique mandatory
1880
- RANK_NON_MANDATORY = 9 # Absorption: unique optional
1881
- RANK_MULTIPLE = 10 # Absorption: manifold
1882
- RANK_SUBTYPE = 11 # Subtypes in alphabetical order
1883
- RANK_SCOPING = 12 # Scoping in alphabetical order
1904
+ RANK_SUPER = 1 # Supertypes, with the identifying supertype first, others alphabetical
1905
+ RANK_IDENT = 2 # Identifying components (absorptions, indicator), in order of the identifier
1906
+ RANK_VALUE = 3 # A ValueField
1907
+ RANK_INJECTION = 4 # Injections, in alphabetical order
1908
+ RANK_DISCRIMINATOR = 5 # Discriminator components, in alphabetical order
1909
+ RANK_FOREIGN = 6 # REVISIT: Foreign key components
1910
+ RANK_INDICATOR = 7 # Indicators in alphabetical order
1911
+ RANK_MANDATORY = 8 # Absorption: unique mandatory
1912
+ RANK_NON_MANDATORY = 9 # Absorption: unique optional
1913
+ RANK_MULTIPLE = 10 # Absorption: manifold
1914
+ RANK_SUBTYPE = 11 # Subtypes in alphabetical order
1915
+ RANK_SCOPING = 12 # Scoping in alphabetical order
1884
1916
 
1885
1917
  def uncache_rank_key
1886
- @rank_key = nil
1918
+ @rank_key = nil
1887
1919
  end
1888
1920
 
1889
1921
  def rank_key
1890
- @rank_key ||=
1891
- case self
1892
- when SurrogateKey
1893
- if !parent.parent
1894
- [RANK_SURROGATE] # an injected PK
1895
- else
1896
- [RANK_MANDATORY, name] # an FK
1897
- end
1898
-
1899
- when Indicator
1900
- if (p = parent_entity_type) and (position = p.rank_in_preferred_identifier(role.base_role))
1901
- [RANK_IDENT, position] # An identifying unary
1902
- else
1903
- [RANK_INDICATOR, name || role.name] # A non-identifying unary
1904
- end
1905
-
1906
- when Discriminator
1907
- [RANK_DISCRIMINATOR, name || child_role.name]
1908
-
1909
- when ValueField
1910
- [RANK_IDENT]
1911
-
1912
- when Injection
1913
- [RANK_INJECTION, name] # REVISIT: Injection not fully elaborated. A different sub-key for ranking may be needed
1914
-
1915
- when Absorption
1916
- if is_type_inheritance
1917
- # We are traversing a type inheritance fact type. Is this object_type the subtype or supertype?
1918
- if is_supertype_absorption
1919
- # What's the rank of this supertype?
1920
- tis = parent_role.object_type.all_type_inheritance_as_subtype.sort_by{|ti| ti.provides_identification ? '' : ti.supertype.name }
1921
- [RANK_SUPER, child_role.fact_type.provides_identification ? 0 : 1+tis.index(parent_role.fact_type)]
1922
- else
1923
- # What's the rank of this subtype?
1924
- tis = parent_role.object_type.all_type_inheritance_as_supertype.sort_by{|ti| ti.subtype.name }
1925
- [RANK_SUBTYPE, tis.index(parent_role.fact_type)]
1926
- end
1927
- elsif (p = parent_entity_type) and (position = p.rank_in_preferred_identifier(child_role.base_role))
1928
- [RANK_IDENT, position]
1929
- else
1930
- if parent_role.is_unique
1931
- [parent_role.is_mandatory ? RANK_MANDATORY : RANK_NON_MANDATORY, name || child_role.name]
1932
- else
1933
- [RANK_MULTIPLE, name || child_role.name, parent_role.name]
1934
- end
1935
- end
1936
-
1937
- when Scoping
1938
- [RANK_SCOPING, name || object_type.name]
1939
-
1940
- else
1941
- raise "unexpected #{self.class.basename} in Component#rank_key"
1942
- end
1922
+ @rank_key ||=
1923
+ case self
1924
+ when SurrogateKey
1925
+ if is_identifying
1926
+ [RANK_SURROGATE] # an injected PK
1927
+ else
1928
+ [RANK_MANDATORY, name] # an FK
1929
+ end
1930
+
1931
+ when Indicator
1932
+ if (p = parent_entity_type) and
1933
+ p.preferred_identifier and
1934
+ (position = p.rank_in_preferred_identifier(role.base_role))
1935
+ [RANK_IDENT, position] # An identifying unary
1936
+ else
1937
+ [RANK_INDICATOR, name || role.name] # A non-identifying unary
1938
+ end
1939
+
1940
+ when Discriminator
1941
+ [RANK_DISCRIMINATOR, name || child_role.name]
1942
+
1943
+ when ValueField
1944
+ [RANK_IDENT]
1945
+
1946
+ when Injection
1947
+ [RANK_INJECTION, name] # REVISIT: Injection not fully elaborated. A different sub-key for ranking may be needed
1948
+
1949
+ when Absorption
1950
+ if is_type_inheritance
1951
+ # We are traversing a type inheritance fact type. Is this object_type the subtype or supertype?
1952
+ if is_supertype_absorption
1953
+ # What's the rank of this supertype?
1954
+ tis = parent_role.object_type.all_type_inheritance_as_subtype.sort_by{|ti| ti.provides_identification ? '' : ti.supertype.name }
1955
+ [RANK_SUPER, child_role.fact_type.provides_identification ? 0 : 1+tis.index(parent_role.fact_type)]
1956
+ else
1957
+ # What's the rank of this subtype?
1958
+ tis = parent_role.object_type.all_type_inheritance_as_supertype.sort_by{|ti| ti.subtype.name }
1959
+ [RANK_SUBTYPE, tis.index(parent_role.fact_type)]
1960
+ end
1961
+ elsif (p = parent_entity_type) and (position = p.rank_in_preferred_identifier(child_role.base_role))
1962
+ [RANK_IDENT, position]
1963
+ else
1964
+ if parent_role.is_unique
1965
+ [parent_role.is_mandatory ? RANK_MANDATORY : RANK_NON_MANDATORY, name || child_role.name]
1966
+ else
1967
+ [RANK_MULTIPLE, name || child_role.name, parent_role.name]
1968
+ end
1969
+ end
1970
+
1971
+ when Scoping
1972
+ [RANK_SCOPING, name || object_type.name]
1973
+
1974
+ else
1975
+ raise "unexpected #{self.class.basename} in Component#rank_key"
1976
+ end
1943
1977
  end
1944
1978
 
1945
1979
  def primary_index_components
1946
- root and
1947
- ix = root.primary_index and # Primary index has been decided
1948
- root.primary_index.all_index_field.size > 0 and # has been populated and
1949
- ix = root.primary_index and
1950
- ixfs = ix.all_index_field.sort_by(&:ordinal) and
1951
- ixfs.map(&:component)
1980
+ root and
1981
+ ix = root.primary_index and # Primary index has been decided
1982
+ root.primary_index.all_index_field.size > 0 and # has been populated and
1983
+ ix = root.primary_index and
1984
+ ixfs = ix.all_index_field.sort_by(&:ordinal) and
1985
+ ixfs.map(&:component)
1952
1986
  end
1953
1987
 
1954
1988
  def parent_entity_type
1955
- parent &&
1956
- parent.object_type.is_a?(EntityType) &&
1957
- parent.object_type
1989
+ parent &&
1990
+ parent.object_type.is_a?(EntityType) &&
1991
+ parent.object_type
1958
1992
  end
1959
1993
 
1960
1994
  def rank_kind
1961
- return "top" unless parent # E.g. a Mapping that is a Composite
1962
- case rank_key[0]
1963
- when RANK_SURROGATE; "surrogate"
1964
- when RANK_SUPER; "supertype"
1965
- when RANK_IDENT; "existential"
1966
- when RANK_VALUE; "self-value"
1967
- when RANK_INJECTION; "injection"
1968
- when RANK_DISCRIMINATOR;"discriminator"
1969
- when RANK_FOREIGN; "foreignkey"
1970
- when RANK_INDICATOR; "indicator"
1971
- when RANK_MANDATORY; "mandatory"
1972
- when RANK_NON_MANDATORY;"optional"
1973
- when RANK_MULTIPLE; "multiple"
1974
- when RANK_SUBTYPE; "subtype"
1975
- when RANK_SCOPING; "scoping"
1976
- end
1995
+ return "top" unless parent # E.g. a Mapping that is a Composite
1996
+ case rank_key[0]
1997
+ when RANK_SURROGATE; "surrogate"
1998
+ when RANK_SUPER; "supertype"
1999
+ when RANK_IDENT; "existential"
2000
+ when RANK_VALUE; "self-value"
2001
+ when RANK_INJECTION; "injection"
2002
+ when RANK_DISCRIMINATOR;"discriminator"
2003
+ when RANK_FOREIGN; "foreignkey"
2004
+ when RANK_INDICATOR; "indicator"
2005
+ when RANK_MANDATORY; "mandatory"
2006
+ when RANK_NON_MANDATORY;"optional"
2007
+ when RANK_MULTIPLE; "multiple"
2008
+ when RANK_SUBTYPE; "subtype"
2009
+ when RANK_SCOPING; "scoping"
2010
+ end
1977
2011
  end
1978
2012
 
1979
2013
  def root
1980
- parent.root
2014
+ parent.root
1981
2015
  end
1982
2016
 
1983
2017
  def depth
1984
- parent ? 1+parent.depth : 0
2018
+ parent ? 1+parent.depth : 0
1985
2019
  end
1986
2020
 
1987
2021
  def inspect
1988
- "#{self.class.basename}"
2022
+ "#{self.class.basename}"
1989
2023
  end
1990
2024
 
1991
2025
  def show_trace
1992
- raise "Implemented in subclasses"
1993
- # trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}#{name ? " (as #{name.inspect})" : ''}"
2026
+ raise "Implemented in subclasses"
2027
+ # trace :composition, "#{ordinal ? "#{ordinal}: " : ''}#{inspect}#{name ? " (as #{name.inspect})" : ''}"
1994
2028
  end
1995
2029
 
1996
2030
  def leaves
@@ -2002,15 +2036,15 @@ module ActiveFacts
2002
2036
  end
2003
2037
 
2004
2038
  def is_mandatory
2005
- parent.is_mandatory
2039
+ parent.is_mandatory
2006
2040
  end
2007
2041
 
2008
2042
  def path_mandatory
2009
- parent.path_mandatory
2043
+ parent.path_mandatory
2010
2044
  end
2011
2045
 
2012
2046
  def all_role
2013
- []
2047
+ []
2014
2048
  end
2015
2049
 
2016
2050
  def rank_path