lib/activefacts/generate/ordered.rb in activefacts-0.7.0 vs lib/activefacts/generate/ordered.rb in activefacts-0.7.1
- old
+ new
@@ -1,557 +1,553 @@
#
-# Generator superclass for ActiveFacts vocabularies that performs sequencing to avoid forward references.
+# ActiveFacts Generators.
+# Generation support superclass that sequences entity types to avoid forward references.
#
-# Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
+# Copyright (c) 2009 Clifford Heath. Read the LICENSE file.
#
require 'activefacts/api'
module ActiveFacts
+ module Generate #:nodoc:
+ class OrderedDumper #:nodoc:
+ # Base class for generators of object-oriented class libraries for an ActiveFacts vocabulary.
+ include Metamodel
- class OrderedDumper #:nodoc:
- include Metamodel
+ def initialize(vocabulary, *options)
+ @vocabulary = vocabulary
+ @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
+ options.each{|option| set_option(option) }
+ end
- def initialize(vocabulary, *options)
- @vocabulary = vocabulary
- @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
- options.each{|option| set_option(option) }
- end
+ def set_option(option)
+ end
- def set_option(option)
- end
+ def puts(*a)
+ @out.puts *a
+ end
- def puts(*a)
- @out.puts *a
- end
+ def print(*a)
+ @out.print *a
+ end
- def print(*a)
- @out.print *a
- end
+ def generate(out = $>)
+ @out = out
+ vocabulary_start(@vocabulary)
- def generate(out = $>)
- @out = out
- vocabulary_start(@vocabulary)
+ build_indices
+ @concept_types_dumped = {}
+ @fact_types_dumped = {}
+ value_types_dump()
+ entity_types_dump()
+ fact_types_dump()
+ constraints_dump(@constraints_used)
+ vocabulary_end
+ end
- build_indices
- @concept_types_dumped = {}
- @fact_types_dumped = {}
- value_types_dump()
- entity_types_dump()
- fact_types_dump()
- constraints_dump(@constraints_used)
- vocabulary_end
- end
+ def build_indices
+ @presence_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
+ @ring_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
- def build_indices
- @presence_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
- @ring_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
-
- @vocabulary.all_constraint.each { |c|
- case c
- when PresenceConstraint
- fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq # All fact types spanned by this constraint
- if fact_types.size == 1 # There's only one, save it:
- # debug "Single-fact constraint on #{fact_types[0].fact_type_id}: #{c.name}"
- (@presence_constraints_by_fact[fact_types[0]] ||= []) << c
+ @vocabulary.all_constraint.each { |c|
+ case c
+ when PresenceConstraint
+ fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq # All fact types spanned by this constraint
+ if fact_types.size == 1 # There's only one, save it:
+ # debug "Single-fact constraint on #{fact_types[0].fact_type_id}: #{c.name}"
+ (@presence_constraints_by_fact[fact_types[0]] ||= []) << c
+ end
+ when RingConstraint
+ (@ring_constraints_by_fact[c.role.fact_type] ||= []) << c
+ else
+ # debug "Found unhandled constraint #{c.class} #{c.name}"
end
- when RingConstraint
- (@ring_constraints_by_fact[c.role.fact_type] ||= []) << c
- else
- # debug "Found unhandled constraint #{c.class} #{c.name}"
- end
- }
- @constraints_used = {}
- end
+ }
+ @constraints_used = {}
+ end
- def value_types_dump
- done_banner = false
- @vocabulary.all_feature.sort_by{|o| o.name}.each{|o|
- next unless ValueType === o
+ def value_types_dump
+ done_banner = false
+ @vocabulary.all_feature.sort_by{|o| o.name}.each{|o|
+ next unless ValueType === o
- value_type_banner unless done_banner
- done_banner = true
+ value_type_banner unless done_banner
+ done_banner = true
- value_type_dump(o)
- @concept_types_dumped[o] = true
- }
- value_type_end if done_banner
- end
+ value_type_dump(o)
+ @concept_types_dumped[o] = true
+ }
+ value_type_end if done_banner
+ end
- # Try to dump entity types in order of name, but we need
- # to dump ETs before they're referenced in preferred ids
- # if possible (it's not always, there may be loops!)
- def entity_types_dump
- # Build hash tables of precursors and followers to use:
- precursors, followers = *build_entity_dependencies
+ # Try to dump entity types in order of name, but we need
+ # to dump ETs before they're referenced in preferred ids
+ # if possible (it's not always, there may be loops!)
+ def entity_types_dump
+ # Build hash tables of precursors and followers to use:
+ precursors, followers = *build_entity_dependencies
- done_banner = false
- sorted = @vocabulary.all_feature.select{|o| EntityType === o and !o.fact_type }.sort_by{|o| o.name}
- panic = nil
- while true do
- count_this_pass = 0
- skipped_this_pass = 0
- sorted.each{|o|
- next if @concept_types_dumped[o] # Already done
+ done_banner = false
+ sorted = @vocabulary.all_feature.select{|o| EntityType === o and !o.fact_type }.sort_by{|o| o.name}
+ panic = nil
+ while true do
+ count_this_pass = 0
+ skipped_this_pass = 0
+ sorted.each{|o|
+ next if @concept_types_dumped[o] # Already done
- # Can we do this yet?
- if (o != panic and # We don't *have* to do it (panic mode)
- (p = precursors[o]) and # There might be...
- p.size > 0) # precursors - still blocked
- skipped_this_pass += 1
- next
- end
+ # Can we do this yet?
+ if (o != panic and # We don't *have* to do it (panic mode)
+ (p = precursors[o]) and # There might be...
+ p.size > 0) # precursors - still blocked
+ skipped_this_pass += 1
+ next
+ end
- entity_type_banner unless done_banner
- done_banner = true
+ entity_type_banner unless done_banner
+ done_banner = true
- # We're going to emit o - remove it from precursors of others:
- (followers[o]||[]).each{|f|
- precursors[f] -= [o]
- }
- count_this_pass += 1
- panic = nil
+ # We're going to emit o - remove it from precursors of others:
+ (followers[o]||[]).each{|f|
+ precursors[f] -= [o]
+ }
+ count_this_pass += 1
+ panic = nil
- entity_type_dump(o)
- released_fact_types_dump(o)
+ entity_type_dump(o)
+ released_fact_types_dump(o)
- entity_type_group_end
- }
+ entity_type_group_end
+ }
- # Check that we made progress if there's any to make:
- if count_this_pass == 0 && skipped_this_pass > 0
- if panic # We were already panicing... what to do now?
- # This won't happen again unless the above code is changed to decide it can't dump "panic".
- raise "Unresolvable cycle of forward references: " +
- (bad = sorted.select{|o| EntityType === o && !@concept_types_dumped[o]}).map{|o| o.name }.inspect +
- ":\n\t" + bad.map{|o|
- o.name +
- ": " +
- precursors[o].map{|p| p.name}.uniq.inspect
- } * "\n\t" + "\n"
- else
- # Find the object that has the most followers and no fwd-ref'd supertypes:
- # This selection might be better if we allow PI roles to be fwd-ref'd...
- panic = sorted.
- select{|o| !@concept_types_dumped[o] }.
- sort_by{|o|
- f = followers[o] || [];
- o.supertypes.detect{|s| !@concept_types_dumped[s] } ? 0 : -f.size
- }[0]
- # debug "Panic mode, selected #{panic.name} next"
+ # Check that we made progress if there's any to make:
+ if count_this_pass == 0 && skipped_this_pass > 0
+ if panic # We were already panicing... what to do now?
+ # This won't happen again unless the above code is changed to decide it can't dump "panic".
+ raise "Unresolvable cycle of forward references: " +
+ (bad = sorted.select{|o| EntityType === o && !@concept_types_dumped[o]}).map{|o| o.name }.inspect +
+ ":\n\t" + bad.map{|o|
+ o.name +
+ ": " +
+ precursors[o].map{|p| p.name}.uniq.inspect
+ } * "\n\t" + "\n"
+ else
+ # Find the object that has the most followers and no fwd-ref'd supertypes:
+ # This selection might be better if we allow PI roles to be fwd-ref'd...
+ panic = sorted.
+ select{|o| !@concept_types_dumped[o] }.
+ sort_by{|o|
+ f = followers[o] || [];
+ o.supertypes.detect{|s| !@concept_types_dumped[s] } ? 0 : -f.size
+ }[0]
+ # debug "Panic mode, selected #{panic.name} next"
+ end
end
- end
- break if skipped_this_pass == 0 # All done.
+ break if skipped_this_pass == 0 # All done.
+ end
end
- end
- def entity_type_dump(o)
- @concept_types_dumped[o] = true
- pi = o.preferred_identifier
+ def entity_type_dump(o)
+ @concept_types_dumped[o] = true
+ pi = o.preferred_identifier
- supers = o.supertypes
- if (supers.size > 0)
- # Ignore identification by a supertype:
- pi = nil if pi && pi.role_sequence.all_role_ref[0].role.fact_type.is_a?(TypeInheritance)
- subtype_dump(o, supers, pi)
- else
- non_subtype_dump(o, pi)
+ supers = o.supertypes
+ if (supers.size > 0)
+ # Ignore identification by a supertype:
+ pi = nil if pi && pi.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type.is_a?(TypeInheritance) }
+ subtype_dump(o, supers, pi)
+ else
+ non_subtype_dump(o, pi)
+ end
+ @constraints_used[pi] = true
end
- @constraints_used[pi] = true
- end
- def identified_by(o, pi)
- # Different adjectives might be used for different readings.
- # Here, we must find the role_ref containing the adjectives that we need for each identifier,
- # which will be attached to the uniqueness constraint on this object in the binary FT that
- # attaches that identifying role.
- role_refs = pi.role_sequence.all_role_ref.sort_by{|role_ref| role_ref.ordinal}
+ def identified_by(o, pi)
+ # Different adjectives might be used for different readings.
+ # Here, we must find the role_ref containing the adjectives that we need for each identifier,
+ # which will be attached to the uniqueness constraint on this object in the binary FT that
+ # attaches that identifying role.
+ role_refs = pi.role_sequence.all_role_ref.sort_by{|role_ref| role_ref.ordinal}
- # We need to get the adjectives for the roles from the identifying fact's preferred readings:
- identifying_facts = role_refs.map{|rr| rr.role.fact_type }.uniq
- preferred_readings = identifying_facts.inject({}){|reading_hash, fact_type|
- pr = fact_type.preferred_reading
- reading_hash[fact_type] = pr
- reading_hash
- }
- #p identifying_facts.map{|f| f.preferred_reading }
+ # We need to get the adjectives for the roles from the identifying fact's preferred readings:
+ identifying_facts = role_refs.map{|rr| rr.role.fact_type }.uniq
+ preferred_readings = identifying_facts.inject({}){|reading_hash, fact_type|
+ pr = fact_type.preferred_reading
+ reading_hash[fact_type] = pr
+ reading_hash
+ }
+ #p identifying_facts.map{|f| f.preferred_reading }
- identifying_roles = role_refs.map(&:role)
- identification = identified_by_roles_and_facts(o, identifying_roles, identifying_facts, preferred_readings)
- #identifying_facts.each{|f| @fact_types_dumped[f] = true }
+ identifying_roles = role_refs.map(&:role)
+ identification = identified_by_roles_and_facts(o, identifying_roles, identifying_facts, preferred_readings)
+ #identifying_facts.each{|f| @fact_types_dumped[f] = true }
- identification
- end
+ identification
+ end
- def fact_readings_with_constraints(fact_type, fact_constraints = nil)
- define_role_names = true
- fact_constraints ||= @presence_constraints_by_fact[fact_type]
- readings = fact_type.all_reading_by_ordinal.inject([]) do |reading_array, reading|
- reading_array << expanded_reading(reading, fact_constraints, define_role_names)
+ def fact_readings_with_constraints(fact_type, fact_constraints = nil)
+ define_role_names = true
+ fact_constraints ||= @presence_constraints_by_fact[fact_type]
+ readings = fact_type.all_reading_by_ordinal.inject([]) do |reading_array, reading|
+ reading_array << expanded_reading(reading, fact_constraints, define_role_names)
- define_role_names = false # No need to define role names in subsequent readings
+ define_role_names = false # No need to define role names in subsequent readings
- reading_array
+ reading_array
+ end
+
+ readings
end
- readings
- end
+ def expanded_reading(reading, fact_constraints, define_role_names)
+ # Find all role numbers in order of occurrence in this reading:
+ role_refs = reading.role_sequence.all_role_ref.sort_by{|role_ref| role_ref.ordinal}
+ role_numbers = reading.reading_text.scan(/\{(\d)\}/).flatten.map{|m| Integer(m) }
+ roles = role_numbers.map{|m| role_refs[m].role }
+ # debug "Considering #{reading.reading_text} having #{role_numbers.inspect}"
- def expanded_reading(reading, fact_constraints, define_role_names)
- # Find all role numbers in order of occurrence in this reading:
- role_refs = reading.role_sequence.all_role_ref.sort_by{|role_ref| role_ref.ordinal}
- role_numbers = reading.reading_text.scan(/\{(\d)\}/).flatten.map{|m| Integer(m) }
- roles = role_numbers.map{|m| role_refs[m].role }
- # debug "Considering #{reading.reading_text} having #{role_numbers.inspect}"
+ # Find the constraints that constrain frequency over each role we can verbalise:
+ frequency_constraints = []
+ roles.each do |role|
+ # Find a mandatory constraint that's *not* unique; this will need an extra reading
+ role_is_first_in = reading.fact_type.all_reading.detect{|r|
+ role == r.role_sequence.all_role_ref.sort_by{|role_ref|
+ role_ref.ordinal
+ }[0].role
+ }
- # Find the constraints that constrain frequency over each role we can verbalise:
- frequency_constraints = []
- roles.each do |role|
- # Find a mandatory constraint that's *not* unique; this will need an extra reading
- role_is_first_in = reading.fact_type.all_reading.detect{|r|
- role == r.role_sequence.all_role_ref.sort_by{|role_ref|
- role_ref.ordinal
- }[0].role
- }
+ if (role == roles.last) # First role of the reading?
+ # REVISIT: With a ternary, doing this on other than the last role can be ambiguous,
+ # in case both the 2nd and 3rd roles have frequencies. Think some more!
- if (role == roles.last) # First role of the reading?
- # REVISIT: With a ternary, doing this on other than the last role can be ambiguous,
- # in case both the 2nd and 3rd roles have frequencies. Think some more!
-
- constraint = fact_constraints.find{|c| # Find a UC that spans all other Roles
- # internal uniqueness constraints span all roles but one, the residual:
- PresenceConstraint === c &&
- !@constraints_used[c] && # Already verbalised
- roles-c.role_sequence.all_role_ref.map(&:role) == [role]
- }
- # Index the frequency implied by the constraint under the role position in the reading
- if constraint # Mark this constraint as "verbalised" so we don't do it again:
- @constraints_used[constraint] = true
+ constraint = fact_constraints.find{|c| # Find a UC that spans all other Roles
+ # internal uniqueness constraints span all roles but one, the residual:
+ PresenceConstraint === c &&
+ !@constraints_used[c] && # Already verbalised
+ roles-c.role_sequence.all_role_ref.map(&:role) == [role]
+ }
+ # Index the frequency implied by the constraint under the role position in the reading
+ if constraint # Mark this constraint as "verbalised" so we don't do it again:
+ @constraints_used[constraint] = true
+ end
+ frequency_constraints << show_frequency(role, constraint)
+ else
+ frequency_constraints << show_frequency(role, nil)
end
- frequency_constraints << show_frequency(role, constraint)
- else
- frequency_constraints << show_frequency(role, nil)
end
- end
- expanded = reading.expand(frequency_constraints, define_role_names)
+ expanded = reading.expand(frequency_constraints, define_role_names)
- if (ft_rings = @ring_constraints_by_fact[reading.fact_type]) &&
- (ring = ft_rings.detect{|rc| !@constraints_used[rc]})
- @constraints_used[ring] = true
- append_ring_to_reading(expanded, ring)
+ if (ft_rings = @ring_constraints_by_fact[reading.fact_type]) &&
+ (ring = ft_rings.detect{|rc| !@constraints_used[rc]})
+ @constraints_used[ring] = true
+ append_ring_to_reading(expanded, ring)
+ end
+ expanded
end
- expanded
- end
- def show_frequency role, constraint
- constraint ? constraint.frequency : nil
- end
+ def show_frequency role, constraint
+ constraint ? constraint.frequency : nil
+ end
- def describe_fact_type(fact_type, highlight = nil)
- (fact_type.entity_type ? fact_type.entity_type.name : "")+
- describe_roles(fact_type.all_role, highlight)
- end
+ def describe_fact_type(fact_type, highlight = nil)
+ (fact_type.entity_type ? fact_type.entity_type.name : "")+
+ describe_roles(fact_type.all_role, highlight)
+ end
- def describe_roles(roles, highlight = nil)
- "("+
- roles.map{|role| role.concept.name + (role == highlight ? "*" : "")}*", "+
- ")"
- end
+ def describe_roles(roles, highlight = nil)
+ "("+
+ roles.map{|role| role.concept.name + (role == highlight ? "*" : "")}*", "+
+ ")"
+ end
- def describe_role_sequence(role_sequence)
- "("+
- role_sequence.all_role_ref.map{|role_ref| role_ref.role.concept.name }*", "+
- ")"
- end
+ def describe_role_sequence(role_sequence)
+ "("+
+ role_sequence.all_role_ref.map{|role_ref| role_ref.role.concept.name }*", "+
+ ")"
+ end
- # This returns an array of two hash tables each keyed by an EntityType.
- # The values of each hash entry are the precursors and followers (respectively) of that entity.
- def build_entity_dependencies
- @vocabulary.all_feature.inject([{},{}]) { |a, o|
- if EntityType === o && !o.fact_type
- precursor = a[0]
- follower = a[1]
- blocked = false
- pi = o.preferred_identifier
- if pi
- pi.role_sequence.all_role_ref.each{|rr|
- role = rr.role
- player = role.concept
- next unless EntityType === player
- # player is a precursor of o
- (precursor[o] ||= []) << player if (player != o)
- (follower[player] ||= []) << o if (player != o)
+ # This returns an array of two hash tables each keyed by an EntityType.
+ # The values of each hash entry are the precursors and followers (respectively) of that entity.
+ def build_entity_dependencies
+ @vocabulary.all_feature.inject([{},{}]) { |a, o|
+ if EntityType === o && !o.fact_type
+ precursor = a[0]
+ follower = a[1]
+ blocked = false
+ pi = o.preferred_identifier
+ if pi
+ pi.role_sequence.all_role_ref.each{|rr|
+ role = rr.role
+ player = role.concept
+ next unless EntityType === player
+ # player is a precursor of o
+ (precursor[o] ||= []) << player if (player != o)
+ (follower[player] ||= []) << o if (player != o)
+ }
+ end
+ # Supertypes are precursors too:
+ subtyping = o.all_type_inheritance_as_supertype
+ next a if subtyping.size == 0
+ subtyping.each{|ti|
+ # debug ti.class.roles.verbalise; debug "all_type_inheritance_as_supertype"; exit
+ s = ti.subtype
+ (precursor[s] ||= []) << o
+ (follower[o] ||= []) << s
}
end
- # Supertypes are precursors too:
- subtyping = o.all_type_inheritance_by_supertype
- next a if subtyping.size == 0
- subtyping.each{|ti|
- # debug ti.class.roles.verbalise; debug "all_type_inheritance_by_supertype"; exit
- s = ti.subtype
- (precursor[s] ||= []) << o
- (follower[o] ||= []) << s
- }
- end
- a
- }
- end
-
- # Dump all fact types for which all precursors (of which "o" is one) have been emitted:
- def released_fact_types_dump(o)
- roles = o.all_role
- begin
- progress = false
- roles.map(&:fact_type).uniq.select{|fact_type|
- # The fact type hasn't already been dumped but all its role players have
- !@fact_types_dumped[fact_type] &&
- !fact_type.all_role.detect{|r| !@concept_types_dumped[r.concept] }
- }.sort_by{|fact_type|
- fact_type_key(fact_type)
- }.each{|fact_type|
- fact_type_dump_with_dependents(fact_type)
- # Objectified Fact Types may release additional fact types
- roles += fact_type.entity_type.all_role if fact_type.entity_type
- progress = true
+ a
}
- end while progress
- end
+ end
- def skip_fact_type(f)
- # REVISIT: There might be constraints we have to merge into the nested entity or subtype.
- # These will come up as un-handled constraints:
- pcs = @presence_constraints_by_fact[f]
- TypeInheritance === f ||
- (pcs && pcs.size > 0 && !pcs.detect{|c| !@constraints_used[c] })
- end
+ # Dump all fact types for which all precursors (of which "o" is one) have been emitted:
+ def released_fact_types_dump(o)
+ roles = o.all_role
+ begin
+ progress = false
+ roles.map(&:fact_type).uniq.select{|fact_type|
+ # The fact type hasn't already been dumped but all its role players have
+ !@fact_types_dumped[fact_type] &&
+ !fact_type.all_role.detect{|r| !@concept_types_dumped[r.concept] }
+ }.sort_by{|fact_type|
+ fact_type_key(fact_type)
+ }.each{|fact_type|
+ fact_type_dump_with_dependents(fact_type)
+ # Objectified Fact Types may release additional fact types
+ roles += fact_type.entity_type.all_role.sort_by{|role| role.ordinal} if fact_type.entity_type
+ progress = true
+ }
+ end while progress
+ end
- # Dump one fact type.
- # Include as many as possible internal constraints in the fact type readings.
- def fact_type_dump_with_dependents(fact_type)
- @fact_types_dumped[fact_type] = true
- # debug "Trying to dump FT again" if @fact_types_dumped[fact_type]
- return if skip_fact_type(fact_type)
-
- if (et = fact_type.entity_type) &&
- (pi = et.preferred_identifier) &&
- pi.role_sequence.all_role_ref[0].role.fact_type != fact_type
- # debug "Dumping objectified FT #{et.name} as an entity, non-fact PI"
- entity_type_dump(et)
- released_fact_types_dump(et)
- return
+ def skip_fact_type(f)
+ # REVISIT: There might be constraints we have to merge into the nested entity or subtype.
+ # These will come up as un-handled constraints:
+ pcs = @presence_constraints_by_fact[f]
+ TypeInheritance === f ||
+ (pcs && pcs.size > 0 && !pcs.detect{|c| !@constraints_used[c] })
end
- fact_constraints = @presence_constraints_by_fact[fact_type]
+ # Dump one fact type.
+ # Include as many as possible internal constraints in the fact type readings.
+ def fact_type_dump_with_dependents(fact_type)
+ @fact_types_dumped[fact_type] = true
+ # debug "Trying to dump FT again" if @fact_types_dumped[fact_type]
+ return if skip_fact_type(fact_type)
- # debug "for fact type #{fact_type.to_s}, considering\n\t#{fact_constraints.map(&:to_s)*",\n\t"}"
- # debug "#{fact_type.name} has readings:\n\t#{fact_type.readings.map(&:name)*"\n\t"}"
- # debug "Dumping #{fact_type.fact_type_id} as a fact type"
+ if (et = fact_type.entity_type) &&
+ (pi = et.preferred_identifier) &&
+ pi.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type != fact_type }
+ # debug "Dumping objectified FT #{et.name} as an entity, non-fact PI"
+ entity_type_dump(et)
+ released_fact_types_dump(et)
+ return
+ end
- # Fact types that aren't nested have no names
- name = fact_type.entity_type && fact_type.entity_type.name
+ fact_constraints = @presence_constraints_by_fact[fact_type]
- fact_type_dump(fact_type, name)
+ # debug "for fact type #{fact_type.to_s}, considering\n\t#{fact_constraints.map(&:to_s)*",\n\t"}"
+ # debug "#{fact_type.name} has readings:\n\t#{fact_type.readings.map(&:name)*"\n\t"}"
+ # debug "Dumping #{fact_type.fact_type_id} as a fact type"
- # REVISIT: Go through the residual constraints and re-process appropriate readings to show them
+ # Fact types that aren't nested have no names
+ name = fact_type.entity_type && fact_type.entity_type.name
- @fact_types_dumped[fact_type] = true
- @concept_types_dumped[fact_type.entity_type] = true if fact_type.entity_type
- end
+ fact_type_dump(fact_type, name)
- # Arrange for objectified fact types to appear in order of name, after other fact types.
- # Facts are ordered alphabetically by the names of their role players,
- # then by preferred_reading (subtyping fact types have no preferred_reading).
- def fact_type_key(fact_type)
- role_names =
- if (pr = fact_type.preferred_reading)
- pr.role_sequence.
- all_role_ref.
- sort_by{|role_ref| role_ref.ordinal}.
- map{|role_ref| [ role_ref.leading_adjective, role_ref.role.concept.name, role_ref.trailing_adjective ].compact*"-" } +
- [pr.reading_text]
- else
- fact_type.all_role.map{|role| role.concept.name }
- end
+ # REVISIT: Go through the residual constraints and re-process appropriate readings to show them
- (fact_type.entity_type ? [fact_type.entity_type.name] : [""]) + role_names
- end
+ @fact_types_dumped[fact_type] = true
+ @concept_types_dumped[fact_type.entity_type] = true if fact_type.entity_type
+ end
- def role_ref_key(role_ref)
- [ role_ref.leading_adjective, role_ref.role.concept.name, role_ref.trailing_adjective ].compact*"-"
- end
+ # Arrange for objectified fact types to appear in order of name, after other fact types.
+ # Facts are ordered alphabetically by the names of their role players,
+ # then by preferred_reading (subtyping fact types have no preferred_reading).
+ def fact_type_key(fact_type)
+ role_names =
+ if (pr = fact_type.preferred_reading)
+ pr.role_sequence.
+ all_role_ref.
+ sort_by{|role_ref| role_ref.ordinal}.
+ map{|role_ref| [ role_ref.leading_adjective, role_ref.role.concept.name, role_ref.trailing_adjective ].compact*"-" } +
+ [pr.reading_text]
+ else
+ fact_type.all_role.map{|role| role.concept.name }
+ end
- # Dump fact types.
- def fact_types_dump
- # REVISIT: Uniqueness on the LHS of a binary can be coded using "distinct"
+ (fact_type.entity_type ? [fact_type.entity_type.name] : [""]) + role_names
+ end
- # The only fact types that can be remaining are those involving only value types,
- # since we dumped every fact type as soon as all relevant entities were dumped.
- # Iterate over all fact types of all value types, looking for these strays.
+ def role_ref_key(role_ref)
+ [ role_ref.leading_adjective, role_ref.role.concept.name, role_ref.trailing_adjective ].compact*"-"
+ end
- done_banner = false
- fact_collection = @vocabulary.constellation.FactType
- fact_collection.keys.select{|fact_id|
- fact_type = fact_collection[fact_id]
- !(TypeInheritance === fact_type) and
- !@fact_types_dumped[fact_type] and
- !skip_fact_type(fact_type) and
- !fact_type.all_role.detect{|r| EntityType === r.concept }
- }.sort_by{|fact_id|
- fact_type = fact_collection[fact_id]
- fact_type_key(fact_type)
- }.each{|fact_id|
- fact_type = fact_collection[fact_id]
+ # Dump fact types.
+ def fact_types_dump
+ # REVISIT: Uniqueness on the LHS of a binary can be coded using "distinct"
- fact_type_banner unless done_banner
- done_banner = true
- fact_type_dump_with_dependents(fact_type)
- }
+ # The only fact types that can be remaining are those involving only value types,
+ # since we dumped every fact type as soon as all relevant entities were dumped.
+ # Iterate over all fact types of all value types, looking for these strays.
- # REVISIT: Find out why some fact types are missed during entity dumping:
- @vocabulary.constellation.FactType.values.select{|fact_type|
- !(TypeInheritance === fact_type)
- }.sort_by{|fact_type|
- fact_type_key(fact_type)
- }.each{|fact_type|
- next if @fact_types_dumped[fact_type]
- # debug "Not dumped #{fact_type.verbalise}(#{fact_type.all_role.map{|r| r.concept.name}*", "})"
- fact_type_banner unless done_banner
- done_banner = true
- fact_type_dump_with_dependents(fact_type)
- }
+ done_banner = false
+ fact_collection = @vocabulary.constellation.FactType
+ fact_collection.keys.select{|fact_id|
+ fact_type = fact_collection[fact_id] and
+ !(TypeInheritance === fact_type) and
+ !@fact_types_dumped[fact_type] and
+ !skip_fact_type(fact_type) and
+ !fact_type.all_role.detect{|r| r.concept.is_a?(EntityType) }
+ }.sort_by{|fact_id|
+ fact_type = fact_collection[fact_id]
+ fact_type_key(fact_type)
+ }.each{|fact_id|
+ fact_type = fact_collection[fact_id]
- fact_type_end if done_banner
- # unused = constraints - @constraints_used.keys
- # debug "residual constraints are\n\t#{unused.map(&:to_s)*",\n\t"}"
+ fact_type_banner unless done_banner
+ done_banner = true
+ fact_type_dump_with_dependents(fact_type)
+ }
- @constraints_used
- end
-
- def fact_instances_dump
- @vocabulary.fact_types.each{|f|
- # Dump the instances:
- f.facts.each{|i|
- raise "REVISIT: Not dumping fact instances"
- debug "\t\t"+i.to_s
+ # REVISIT: Find out why some fact types are missed during entity dumping:
+ @vocabulary.constellation.FactType.values.select{|fact_type|
+ !(TypeInheritance === fact_type)
+ }.sort_by{|fact_type|
+ fact_type_key(fact_type)
+ }.each{|fact_type|
+ next if @fact_types_dumped[fact_type]
+ # debug "Not dumped #{fact_type.verbalise}(#{fact_type.all_role.map{|r| r.concept.name}*", "})"
+ fact_type_banner unless done_banner
+ done_banner = true
+ fact_type_dump_with_dependents(fact_type)
}
- }
- end
- def constraint_sort_key(c)
- case c
- when RingConstraint
- [1, c.ring_type, c.role.concept.name, c.other_role.concept.name, c.name||""]
- when SetComparisonConstraint
- [2, c.all_set_comparison_roles.map{|scrs| scrs.role_sequence.all_role_ref.map{|rr| role_ref_key(rr)}}, c.name||""]
- when SubsetConstraint
- [3, [c.superset_role_sequence, c.subset_role_sequence].map{|rs| rs.all_role_ref.map{|rr| role_ref_key(rr)}}, c.name||""]
- when PresenceConstraint
- [4, c.role_sequence.all_role_ref.map{|rr| role_ref_key(rr)}, c.name||""]
+ fact_type_end if done_banner
+ # unused = constraints - @constraints_used.keys
+ # debug "residual constraints are\n\t#{unused.map(&:to_s)*",\n\t"}"
+
+ @constraints_used
end
- end
- def constraints_dump(except = {})
- heading = false
- @vocabulary.all_constraint.reject{|c| except[c]}.sort_by{ |c| constraint_sort_key(c) }.each do|c|
- # Skip some PresenceConstraints:
- if PresenceConstraint === c
- # Skip uniqueness constraints that cover all roles of a fact type, they're implicit
- role_refs = c.role_sequence.all_role_ref
- if role_refs.size == 0
- constraint_banner unless heading
- heading = true
- puts "PresenceConstraint without roles!"
- next
+ def fact_instances_dump
+ @vocabulary.fact_types.each{|f|
+ # Dump the instances:
+ f.facts.each{|i|
+ raise "REVISIT: Not dumping fact instances"
+ debug "\t\t"+i.to_s
+ }
+ }
+ end
+
+ def constraint_sort_key(c)
+ case c
+ when RingConstraint
+ [1, c.ring_type, c.role.concept.name, c.other_role.concept.name, c.name||""]
+ when SetComparisonConstraint
+ [2, c.all_set_comparison_roles.map{|scrs| scrs.role_sequence.all_role_ref.map{|rr| role_ref_key(rr)}}, c.name||""]
+ when SubsetConstraint
+ [3, [c.superset_role_sequence, c.subset_role_sequence].map{|rs| rs.all_role_ref.map{|rr| role_ref_key(rr)}}, c.name||""]
+ when PresenceConstraint
+ [4, c.role_sequence.all_role_ref.map{|rr| role_ref_key(rr)}, c.name||""]
+ end
+ end
+
+ def constraints_dump(except = {})
+ heading = false
+ @vocabulary.all_constraint.reject{|c| except[c]}.sort_by{ |c| constraint_sort_key(c) }.each do|c|
+ # Skip some PresenceConstraints:
+ if PresenceConstraint === c
+ # Skip uniqueness constraints that cover all roles of a fact type, they're implicit
+ fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq
+ next if fact_types.size == 1 &&
+ c.max_frequency == 1 && # Uniqueness
+ fact_types[0].all_role.size == c.role_sequence.all_role_ref.size
+
+ # Skip internal PresenceConstraints over TypeInheritances:
+ next if c.role_sequence.all_role_ref.size == 1 &&
+ TypeInheritance === fact_types[0]
end
- fact_type0 = role_refs[0].role.fact_type
- next if c.max_frequency == 1 && # Uniqueness
- role_refs.size == fact_type0.all_role.size && # Same number of roles
- fact_type0.all_role.all?{|r| role_refs.map(&:role).include? r} # All present
- # Skip internal PresenceConstraints over TypeInheritances:
- next if TypeInheritance === fact_type0 &&
- !c.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type != fact_type0 }
+ constraint_banner unless heading
+ heading = true
+
+ # Skip presence constraints on value types:
+ # next if ActiveFacts::PresenceConstraint === c &&
+ # ActiveFacts::ValueType === c.concept
+ constraint_dump(c)
end
+ constraint_end if heading
+ end
- constraint_banner unless heading
- heading = true
+ def vocabulary_start(vocabulary)
+ debug "Should override vocabulary_start"
+ end
- # Skip presence constraints on value types:
- # next if ActiveFacts::PresenceConstraint === c &&
- # ActiveFacts::ValueType === c.concept
- constraint_dump(c)
+ def vocabulary_end
+ debug "Should override vocabulary_end"
end
- constraint_end if heading
- end
- def vocabulary_start(vocabulary)
- debug "Should override vocabulary_start"
- end
+ def value_type_banner
+ debug "Should override value_type_banner"
+ end
- def vocabulary_end
- debug "Should override vocabulary_end"
- end
+ def value_type_end
+ debug "Should override value_type_end"
+ end
- def value_type_banner
- debug "Should override value_type_banner"
- end
+ def value_type_dump(o)
+ debug "Should override value_type_dump"
+ end
- def value_type_end
- debug "Should override value_type_end"
- end
+ def entity_type_banner
+ debug "Should override entity_type_banner"
+ end
- def value_type_dump(o)
- debug "Should override value_type_dump"
- end
+ def entity_type_group_end
+ debug "Should override entity_type_group_end"
+ end
- def entity_type_banner
- debug "Should override entity_type_banner"
- end
+ def non_subtype_dump(o, pi)
+ debug "Should override non_subtype_dump"
+ end
- def entity_type_group_end
- debug "Should override entity_type_group_end"
- end
+ def subtype_dump(o, supertypes, pi = nil)
+ debug "Should override subtype_dump"
+ end
- def non_subtype_dump(o, pi)
- debug "Should override non_subtype_dump"
- end
+ def append_ring_to_reading(reading, ring)
+ debug "Should override append_ring_to_reading"
+ end
- def subtype_dump(o, supertypes, pi = nil)
- debug "Should override subtype_dump"
- end
+ def fact_type_banner
+ debug "Should override fact_type_banner"
+ end
- def append_ring_to_reading(reading, ring)
- debug "Should override append_ring_to_reading"
- end
+ def fact_type_end
+ debug "Should override fact_type_end"
+ end
- def fact_type_banner
- debug "Should override fact_type_banner"
- end
+ def fact_type_dump(fact_type, name)
+ debug "Should override fact_type_dump"
+ end
- def fact_type_end
- debug "Should override fact_type_end"
- end
+ def constraint_banner
+ debug "Should override constraint_banner"
+ end
- def fact_type_dump(fact_type, name)
- debug "Should override fact_type_dump"
- end
+ def constraint_end
+ debug "Should override constraint_end"
+ end
- def constraint_banner
- debug "Should override constraint_banner"
- end
+ def constraint_dump(c)
+ debug "Should override constraint_dump"
+ end
- def constraint_end
- debug "Should override constraint_end"
end
- def constraint_dump(c)
- debug "Should override constraint_dump"
+ def dump(vocabulary, out = $>)
+ OrderedDumper.new(vocabulary).dump(out)
end
-
- end
-
- def dump(vocabulary, out = $>)
- OrderedDumper.new(vocabulary).dump(out)
end
end