lib/activefacts/generate/ordered.rb in activefacts-0.7.3 vs lib/activefacts/generate/ordered.rb in activefacts-0.8.5

- old
+ new

@@ -63,11 +63,11 @@ end def value_types_dump done_banner = false @value_type_dumped = {} - @vocabulary.all_feature.sort_by{|o| o.name}.each{|o| + @vocabulary.all_concept.sort_by{|o| o.name}.each{|o| next unless o.is_a?(ActiveFacts::Metamodel::ValueType) value_type_banner unless done_banner done_banner = true @@ -88,43 +88,48 @@ # 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 + @precursors, @followers = *build_entity_dependencies done_banner = false - sorted = @vocabulary.all_feature.select{|o| - o.is_a?(ActiveFacts::Metamodel::EntityType) and !o.fact_type + sorted = @vocabulary.all_concept.select{|o| + o.is_a?(ActiveFacts::Metamodel::EntityType) # 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 = @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 # We're going to emit o - remove it from precursors of others: - (followers[o]||[]).each{|f| - precursors[f] -= [o] + (@followers[o]||[]).each{|f| + @precursors[f] -= [o] } count_this_pass += 1 panic = nil - entity_type_dump(o) - released_fact_types_dump(o) + if (o.fact_type) + fact_type_dump_with_dependents(o.fact_type) + released_fact_types_dump(o) + else + entity_type_dump(o) + released_fact_types_dump(o) + end entity_type_group_end } # Check that we made progress if there's any to make: @@ -134,19 +139,19 @@ 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 + @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] || []; + f = @followers[o] || []; o.supertypes.detect{|s| !@concept_types_dumped[s] } ? 0 : -f.size }[0] # debug "Panic mode, selected #{panic.name} next" end end @@ -177,11 +182,11 @@ # 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 + identifying_facts = ([o.fact_type]+role_refs.map{|rr| rr.role.fact_type }).compact.uniq preferred_readings = identifying_facts.inject({}){|reading_hash, fact_type| pr = fact_type.preferred_reading reading_hash[fact_type] = pr reading_hash } @@ -209,24 +214,34 @@ 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) } + role_numbers = 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}" + # debug "Considering #{reading.text} having #{role_numbers.inspect}" # Find the constraints that constrain frequency over each role we can verbalise: frequency_constraints = [] + value_restrictions = [] 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 vr = role.role_value_restriction + if @constraints_used[vr] + vr = nil + else + @constraints_used[vr] = true + vr = vr.describe + end + end + value_restrictions << vr 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 @@ -243,11 +258,11 @@ 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, value_restrictions) 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) @@ -277,35 +292,50 @@ 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 o.is_a?(ActiveFacts::Metamodel::EntityType) && !o.fact_type + @vocabulary.all_concept.inject([{},{}]) { |a, o| + if o.is_a?(ActiveFacts::Metamodel::EntityType) 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 + # REVISIT: If we decide to emit value types on demand, need to remove this: next unless player.is_a?(ActiveFacts::Metamodel::EntityType) # player is a precursor of o (precursor[o] ||= []) << player if (player != o) (follower[player] ||= []) << o if (player != o) } end + if o.fact_type + o.fact_type.all_role.each do |role| + next unless role.concept.is_a?(ActiveFacts::Metamodel::EntityType) + (precursor[o] ||= []) << role.concept + (follower[role.concept] ||= []) << o + end + 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 } +# REVISIT: Need to use this to order ValueTypes after their supertypes +# else +# o.all_value_type_as_supertype.each { |s| +# (precursor[s] ||= []) << o +# (follower[o] ||= []) << s +# } end a } end @@ -315,11 +345,13 @@ 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] } + !fact_type.all_role.detect{|r| !@concept_types_dumped[r.concept] } && + !fact_type.entity_type +# !(fact_type.entity_type && (p = @precursors[fact_type.entity_type]) && p.size > 0) }.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 @@ -378,10 +410,10 @@ 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] + [pr.text] else fact_type.all_role.map{|role| role.concept.name } end (fact_type.entity_type ? [fact_type.entity_type.name] : [""]) + role_names