activefacts-metamodel 1.9.6 → 1.9.8

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