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