lib/activefacts/generate/ordered.rb in activefacts-0.8.9 vs lib/activefacts/generate/ordered.rb in activefacts-0.8.10

- old
+ new

@@ -30,11 +30,11 @@ def generate(out = $>) @out = out vocabulary_start(@vocabulary) build_indices - @concept_types_dumped = {} + @object_types_dumped = {} @fact_types_dumped = {} units_dump() value_types_dump() entity_types_dump() fact_types_dump() @@ -65,39 +65,50 @@ def units_dump done_banner = false units = @vocabulary.all_unit.to_a.sort_by{|u| u.name.gsub(/ /,'')} while units.size > 0 - if !done_banner - done_banner = true - units_banner - end i = 0 while i < units.size unit = units[i] i += 1 + # Skip this one if the precursors haven't yet been dumped: next if unit.all_derivation_as_derived_unit.detect{|d| units.include?(d.base_unit) } - unit_dump(unit) + # Even if we skip, we're done with this unit units.delete(unit) i -= 1 + + # Skip value-type derived units + next if unit.name =~ /\^/ + + # Don't dump fundamental units which have normal derived units, they are implied: + next if unit.is_fundamental && + unit.all_derivation_as_base_unit.detect{|d| d.derived_unit.name !~ /\^/} + + if !done_banner + done_banner = true + units_banner + end + unit_dump(unit) end end + units_end if done_banner end def value_types_dump done_banner = false @value_type_dumped = {} - @vocabulary.all_concept.sort_by{|o| o.name.gsub(/ /,'')}.each{|o| + @vocabulary.all_object_type.sort_by{|o| o.name.gsub(/ /,'')}.each{|o| next unless o.is_a?(ActiveFacts::Metamodel::ValueType) value_type_banner unless done_banner done_banner = true value_type_chain_dump(o) - @concept_types_dumped[o] = true + @object_types_dumped[o] = true } value_type_end if done_banner end # Ensure that supertype gets dumped first @@ -114,19 +125,19 @@ def entity_types_dump # Build hash tables of precursors and followers to use: @precursors, @followers = *build_entity_dependencies done_banner = false - sorted = @vocabulary.all_concept.select{|o| + sorted = @vocabulary.all_object_type.select{|o| o.is_a?(ActiveFacts::Metamodel::EntityType) # and !o.fact_type }.sort_by{|o| o.name.gsub(/ /,'')} panic = nil while true do count_this_pass = 0 skipped_this_pass = 0 sorted.each{|o| - next if @concept_types_dumped[o] # Already done + next if @object_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 @@ -158,24 +169,24 @@ # 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 + + (bad = sorted.select{|o| EntityType === o && !@object_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] }. + select{|o| !@object_types_dumped[o] }. sort_by{|o| f = @followers[o] || []; - o.supertypes.detect{|s| !@concept_types_dumped[s] } ? 0 : -f.size + o.supertypes.detect{|s| !@object_types_dumped[s] } ? 0 : -f.size }[0] # debug "Panic mode, selected #{panic.name} next" end end @@ -183,11 +194,11 @@ end end def entity_type_dump(o) - @concept_types_dumped[o] = true + @object_types_dumped[o] = true pi = o.preferred_identifier supers = o.supertypes if (supers.size > 0) # Ignore identification by a supertype: @@ -208,11 +219,10 @@ # We need to get the adjectives for the roles from the identifying fact's preferred readings: identifying_facts = ([o.fact_type]+identifying_role_refs.map{|rr| rr.role.fact_type }).compact.uniq identification = identified_by_roles_and_facts(o, identifying_role_refs, identifying_facts) - #identifying_facts.each{|f| @fact_types_dumped[f] = true } identification end def describe_fact_type(fact_type, highlight = nil) @@ -220,45 +230,45 @@ describe_roles(fact_type.all_role, highlight) end def describe_roles(roles, highlight = nil) "("+ - roles.map{|role| role.concept.name + (role == highlight ? "*" : "")}*", "+ + roles.map{|role| role.object_type.name + (role == highlight ? "*" : "")}*", "+ ")" end def describe_role_sequence(role_sequence) "("+ - role_sequence.all_role_ref.map{|role_ref| role_ref.role.concept.name }*", "+ + role_sequence.all_role_ref.map{|role_ref| role_ref.role.object_type.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_concept.inject([{},{}]) { |a, o| + @vocabulary.all_object_type.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 + player = role.object_type # 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 + next unless role.object_type.is_a?(ActiveFacts::Metamodel::EntityType) + (precursor[o] ||= []) << role.object_type + (follower[role.object_type] ||= []) << o end end # Supertypes are precursors too: subtyping = o.all_type_inheritance_as_supertype @@ -287,13 +297,14 @@ 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.is_a?(ActiveFacts::Metamodel::ImplicitFactType) && - !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) + !fact_type.all_role.detect{|r| !@object_types_dumped[r.object_type] } && + !fact_type.entity_type && + derivation_precursors_complete(fact_type) + # REVISIT: A derived fact type must not be dumped before its joined fact types have }.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 @@ -301,16 +312,26 @@ progress = true } end while progress end + def derivation_precursors_complete(fact_type) + pr = fact_type.preferred_reading + return true unless jr = pr.role_sequence.all_role_ref.to_a[0].join_role + join = jr.join_node.join + return false if join.all_join_step.detect{|js| !@fact_types_dumped[js.fact_type] } + return false if join.all_join_node.detect{|jn| !@object_types_dumped[jn.object_type] } + true + 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] - f.is_a?(ActiveFacts::Metamodel::TypeInheritance) || - (pcs && pcs.size > 0 && !pcs.detect{|c| !@constraints_used[c] }) + return true if f.is_a?(ActiveFacts::Metamodel::TypeInheritance) + return false if f.entity_type && !@object_types_dumped[f.entity_type] + pcs && pcs.size > 0 && !pcs.detect{|c| !@constraints_used[c] } 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) @@ -339,11 +360,11 @@ fact_type_dump(fact_type, name) # REVISIT: Go through the residual constraints and re-process appropriate readings to show them @fact_types_dumped[fact_type] = true - @concept_types_dumped[fact_type.entity_type] = true if fact_type.entity_type + @object_types_dumped[fact_type.entity_type] = true if fact_type.entity_type end # Dump fact types. def fact_types_dump # REVISIT: Uniqueness on the LHS of a binary can be coded using "distinct" @@ -358,11 +379,11 @@ fact_type = fact_collection[fact_id] and !fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) and !fact_type.is_a?(ActiveFacts::Metamodel::ImplicitFactType) and !@fact_types_dumped[fact_type] and !skip_fact_type(fact_type) and - !fact_type.all_role.detect{|r| r.concept.is_a?(ActiveFacts::Metamodel::EntityType) } + !fact_type.all_role.detect{|r| r.object_type.is_a?(ActiveFacts::Metamodel::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] @@ -378,11 +399,11 @@ !fact_type.is_a?(ActiveFacts::Metamodel::ImplicitFactType) }.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}*", "})" + # debug "Not dumped #{fact_type.verbalise}(#{fact_type.all_role.map{|r| r.object_type.name}*", "})" fact_type_banner unless done_banner done_banner = true fact_type_dump_with_dependents(fact_type) } @@ -410,32 +431,32 @@ 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*"-" } + + map{|role_ref| [ role_ref.leading_adjective, role_ref.role.object_type.name, role_ref.trailing_adjective ].compact*"-" } + [pr.text] else - fact_type.all_role.map{|role| role.concept.name } + fact_type.all_role.map{|role| role.object_type.name } end (fact_type.entity_type ? [fact_type.entity_type.name] : [""]) + role_names end def role_ref_key(role_ref) - [ role_ref.leading_adjective, role_ref.role.concept.name, role_ref.trailing_adjective ].compact*"-" + + [ role_ref.leading_adjective, role_ref.role.object_type.name, role_ref.trailing_adjective ].compact*"-" + " in " + role_ref.role.fact_type.preferred_reading.expand end def constraint_sort_key(c) case c when ActiveFacts::Metamodel::RingConstraint [ 1, c.ring_type, - c.role.concept.name, - c.other_role.concept.name, + c.role.object_type.name, + c.other_role.object_type.name, c.name||"" ] when ActiveFacts::Metamodel::SetExclusionConstraint [ 2+(c.is_mandatory ? 0 : 1), c.all_set_comparison_roles.map{|scrs| @@ -497,11 +518,11 @@ constraint_banner unless heading heading = true # Skip presence constraints on value types: # next if ActiveFacts::PresenceConstraint === c && - # ActiveFacts::ValueType === c.concept + # ActiveFacts::ValueType === c.object_type constraint_dump(c) end constraint_end if heading end @@ -512,9 +533,12 @@ def vocabulary_end debug "Should override vocabulary_end" end def units_banner + end + + def units_end end def unit_dump unit end