lib/activefacts/vocabulary/extensions.rb in activefacts-0.8.8 vs lib/activefacts/vocabulary/extensions.rb in activefacts-0.8.9
- old
+ new
@@ -87,13 +87,17 @@
end
end
class RoleRef
def describe
- role_name + (join_node ? " JN#{join_node.ordinal}" : '')
+ role_name
end
+ def preferred_role_ref
+ role.fact_type.preferred_reading.role_sequence.all_role_ref.detect{|rr| rr.role == role}
+ end
+
def role_name(joiner = "-")
name_array =
if role.fact_type.all_role.size == 1
if role.fact_type.is_a?(ImplicitFactType)
"#{role.concept.name} phantom for #{role.fact_type.role.concept.name}"
@@ -484,108 +488,132 @@
class TypeInheritance
def describe(role = nil)
"#{subtype.name} is a kind of #{supertype.name}"
end
+
+ def supertype_role
+ (roles = all_role.to_a)[0].concept == supertype ? roles[0] : roles[1]
+ end
+
+ def subtype_role
+ (roles = all_role.to_a)[0].concept == subtype ? roles[0] : roles[1]
+ end
end
class JoinStep
def describe
- input_role_ref = input_join_node.all_role_ref.detect{|rr| rr.role.fact_type == fact_type}
- output_role_ref = output_join_node.all_role_ref.detect{|rr| rr.role.fact_type == fact_type}
- "from node #{input_join_node.ordinal} #{input_role_ref ? input_role_ref.role.concept.name : input_join_node.concept.name}"+
- " to node #{output_join_node.ordinal} #{output_role_ref ? output_role_ref.role.concept.name : output_join_node.concept.name}"+
- ": #{is_anti && 'not '}#{is_outer && 'maybe '}#{fact_type.default_reading}"
+ "JoinStep " +
+ "#{is_outer && 'maybe '}" +
+ (is_unary_step ? " (unary) " : "from #{input_join_role.describe} ") +
+ "#{is_anti && 'not '}" +
+ "to #{output_join_role.describe} " +
+ "over " + (is_objectification_step ? 'objectification ' : '') +
+ "'#{fact_type.default_reading}'"
end
def is_unary_step
# Preserve this in case we have to use a real join_node for the phantom
- # input_join_node.all_role_ref.detect{|rr| rr.role.fact_type.is_a?(ImplicitFactType) && rr.role.fact_type.role.fact_type.all_role.size == 1 }
- input_join_node == output_join_node
+ input_join_role == output_join_role
end
def is_objectification_step
fact_type.is_a?(ImplicitFactType)
end
+
+ def all_join_role
+ [input_join_role, output_join_role].uniq + all_incidental_join_role.to_a
+ end
+
+ def external_fact_type
+ fact_type.is_a?(ImplicitFactType) ? fact_type.role.fact_type : fact_type
+ end
end
class JoinNode
def describe
- concept.name
+ concept.name +
+ (subscript ? "(#{subscript})" : '') +
+ " JN#{ordinal}" +
+# (all_join_role.detect{|jr| jr.role_ref} ? " (projected)" : "") +
+ (value ? ' = '+value.describe : '')
end
+
+ def all_join_step
+ all_join_role.map do |jr|
+ jr.all_join_step_as_input_join_role.to_a +
+ jr.all_join_step_as_output_join_role.to_a
+ end.
+ flatten.
+ uniq
+ end
end
+ class JoinRole
+ def describe
+ "#{role.concept.name} JN#{join_node.ordinal}" +
+ (role_ref ? " (projected)" : "")
+ end
+
+ def all_join_step
+ (all_join_step_as_input_join_role.to_a +
+ all_join_step_as_output_join_role.to_a +
+ [join_step]).flatten.compact.uniq
+ end
+ end
+
class Join
def show
+ steps_shown = {}
debug :join, "Displaying full contents of Join #{join_id}" do
all_join_node.sort_by{|jn| jn.ordinal}.each do |join_node|
- debug :join, "Node #{join_node.ordinal} for #{join_node.concept.name}" do
- (join_node.all_join_step_as_input_join_node.to_a +
- join_node.all_join_step_as_output_join_node.to_a).
- uniq.
+ debug :join, "#{join_node.describe}" do
+ join_node.all_join_step.
each do |join_step|
- debug :join, "#{
- join_step.is_unary_step ? 'unary ' : ''
- }#{
- join_step.is_objectification_step ? 'objectification ' : ''
- }step #{join_step.describe}"
+ next if steps_shown[join_step]
+ steps_shown[join_step] = true
+ debug :join, "#{join_step.describe}"
end
- join_node.all_role_ref.each do |role_ref|
- debug :join, "reference #{role_ref.describe} in '#{role_ref.role.fact_type.default_reading}' over #{role_ref.role_sequence.describe}#{role_ref.role_sequence == role_sequence ? ' (projected)' : ''}"
+ join_node.all_join_role.each do |join_role|
+ debug :join, "role of #{join_role.describe} in '#{join_role.role.fact_type.default_reading}'"
end
end
end
end
end
+ def all_join_step
+ all_join_node.map{|jn| jn.all_join_step.to_a}.flatten.uniq
+ end
+
+ # Check all parts of this join for validity
def validate
show
return
- # Check all parts of this join for validity
- jns = all_join_node.sort_by{|jn| jn.ordinal}
- jns.each_with_index do |jn, i|
- raise "Join node #{i} should have ordinal #{jn.ordinal}" unless jn.ordinal == i
- end
-
# Check the join nodes:
- steps = []
- jns.each_with_index do |join_node, i|
+ join_steps = []
+ join_nodes = all_join_node.sort_by{|jn| jn.ordinal}
+ join_nodes.each_with_index do |join_node, i|
+ raise "Join node #{i} should have ordinal #{join_node.ordinal}" unless join_node.ordinal == i
raise "Join Node #{i} has missing concept" unless join_node.concept
- if join_node.all_role_ref.detect{|rr| rr.role.concept != join_node.concept }
- raise "All role references for join node #{join_node.ordinal} should be for #{
- join_node.concept.name
- } but we have #{
- (join_node.all_role_ref.map{|rr| rr.role.concept.name}-[join_node.concept.name]).uniq*', '
- }"
+ join_node.all_join_role do |join_role|
+ raise "Join Node for #{concept.name} includes role played by #{join_role.concept.name}" unless join_role.concept == concept
end
- steps += join_node.all_join_step_as_input_join_node.to_a
- steps += join_node.all_join_step_as_output_join_node.to_a
-
- # REVISIT: All Role References must be in a role sequence that covers one fact type exactly (why?)
- # REVISIT: All such role references must have a join node in this join. (why?)
+ join_steps += join_node.all_join_step
end
+ join_steps.uniq!
# Check the join steps:
- steps.uniq!
- steps.each_with_index do |join_step, i|
- raise "Join Step #{i} has missing fact type" unless join_step.fact_type
- raise "Join Step #{i} has missing input node" unless join_step.input_join_node
- raise "Join Step #{i} has missing output node" unless join_step.output_join_node
- debugger
- p join_step.fact_type.default_reading
- p join_step.input_join_node.all_role_ref.map(&:describe)
- p join_step.output_join_node.all_role_ref.map(&:describe)
-=begin
- unless join_step.input_join_node.all_role_ref.
- detect do |rr|
- rr.role.fact_type == join_step.fact_type
- or rr.role.fact_type.is_a?(ImplicitFactType) && rr.role.fact_type.role.fact_type == rr.join_step.concept
- end
- raise "Join Step #{join_step.describe} has nodes not matching its fact type"
+ join_steps.each do |join_step|
+ raise "Join Step has missing fact type" unless join_step.fact_type
+ raise "Join Step has missing input node" unless join_step.input_join_role
+ raise "Join Step has missing output node" unless join_step.output_join_role
+ if (role = input_join_role).role.fact_type != fact_type or
+ (role = output_join_role).role.fact_type != fact_type
+ raise "Join Step has role #{role.describe} which doesn't belong to the fact type '#{fact_type.default_reading}' it traverses"
end
-=end
end
# REVISIT: Do a connectivity check
end
end
@@ -617,10 +645,11 @@
def initialize(role, role_sequence)
@role = role
@role_sequence = role_sequence
end
def join_node; nil; end
+ def join_role; nil; end
def leading_adjective; nil; end
def trailing_adjective; nil; end
def describe
@role.concept.name
end
@@ -703,11 +732,11 @@
objectification_role_supertypes =
fact_type.entity_type.supertypes_transitive+concept.supertypes_transitive
objectification_role = role.implicit_fact_type.all_role.single # Find the phantom role here
else
objectification_role_supertypes = counterpart_role_supertypes
- objectification_role = nil
+ objectification_role = counterpart_role
end
if !d_c_o
d_c_o = [proximate_role_supertypes, counterpart_role_supertypes, objectification_role_supertypes, [counterpart_role], [objectification_role]]
#puts "role player supertypes starts #{d_c_o.map{|dco| dco.map(&:name).inspect}*' or '}"
@@ -731,15 +760,77 @@
counterpart_sups = []
end
end
# Choose the first entry in the first non-empty supertypes list:
- if options != :counterpart
+ if options != :counterpart && proximate_sups[0]
[ proximate_sups[0], roles ]
elsif !counterpart_sups.empty?
[ counterpart_sups[0], counterpart_roles ]
else
[ obj_sups[0], objectification_roles ]
+ end
+ end
+
+ class Fact
+ def verbalise(context = nil)
+ reading = fact_type.preferred_reading
+ reading_roles = reading.role_sequence.all_role_ref.sort_by{|rr| rr.ordinal}.map{|rr| rr.role }
+ role_values_in_reading_order = all_role_value.sort_by{|rv| reading_roles.index(rv.role) }
+ instance_verbalisations = role_values_in_reading_order.map do |rv|
+ if rv.instance.value
+ v = rv.instance.verbalise
+ else
+ if (c = rv.instance.concept).is_a?(EntityType)
+ if !c.preferred_identifier.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type == fact_type}
+ v = rv.instance.verbalise
+ end
+ end
+ end
+ next nil unless v
+ v.to_s.sub(/(#{rv.instance.concept.name}|\S*)\s/,'')
+ end
+ reading.expand([], false, instance_verbalisations)
+ end
+ end
+
+ class Instance
+ def verbalise(context = nil)
+ return "#{concept.name} #{value}" if concept.is_a?(ValueType)
+
+ return "#{concept.name} where #{fact.verbalise(context)}" if concept.fact_type
+
+ # It's an entity that's not an objectified fact type
+ # REVISIT: If it has a simple identifier, there's no need to fully verbalise the identifying facts
+ pi = concept.preferred_identifier
+ identifying_role_refs = pi.role_sequence.all_role_ref_in_order
+ "#{concept.name}" +
+ " is identified by " + # REVISIT: Where the single fact type is TypeInheritance, we can shrink this
+ if identifying_role_refs.size == 1 &&
+ (role = identifying_role_refs[0].role) &&
+ (my_role = (role.fact_type.all_role.to_a-[role])[0]) &&
+ (identifying_fact = my_role.all_role_value.detect{|rv| rv.instance == self}.fact) &&
+ (identifying_instance = identifying_fact.all_role_value.detect{|rv| rv.role == role}.instance)
+
+ "its #{identifying_instance.verbalise(context)}"
+ else
+ identifying_role_refs.map do |rr|
+ rr = rr.preferred_role_ref
+ [ (l = rr.leading_adjective) ? l+"-" : nil,
+ rr.role.role_name || rr.role.concept.name,
+ (t = rr.trailing_adjective) ? l+"-" : nil
+ ].compact*""
+ end * " and " +
+ " where " +
+ identifying_role_refs.map do |rr| # Go through the identifying roles and emit the facts that define them
+ instance_role = concept.all_role.detect{|r| r.fact_type == rr.role.fact_type}
+ identifying_fact = all_role_value.detect{|rv| rv.fact.fact_type == rr.role.fact_type}.fact
+ #counterpart_role = (rr.role.fact_type.all_role.to_a-[instance_role])[0]
+ #identifying_instance = counterpart_role.all_role_value.detect{|rv| rv.fact == identifying_fact}.instance
+ identifying_fact.verbalise(context)
+ end*", "
+ end
+
end
end
end
end