activefacts 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
 - data/Manifest.txt +83 -0
 - data/README.rdoc +81 -0
 - data/Rakefile +41 -0
 - data/bin/afgen +46 -0
 - data/bin/cql +52 -0
 - data/examples/CQL/Address.cql +46 -0
 - data/examples/CQL/Blog.cql +54 -0
 - data/examples/CQL/CompanyDirectorEmployee.cql +51 -0
 - data/examples/CQL/Death.cql +16 -0
 - data/examples/CQL/Genealogy.cql +95 -0
 - data/examples/CQL/Marriage.cql +18 -0
 - data/examples/CQL/Metamodel.cql +238 -0
 - data/examples/CQL/MultiInheritance.cql +19 -0
 - data/examples/CQL/OilSupply.cql +47 -0
 - data/examples/CQL/Orienteering.cql +108 -0
 - data/examples/CQL/PersonPlaysGame.cql +17 -0
 - data/examples/CQL/SchoolActivities.cql +31 -0
 - data/examples/CQL/SimplestUnary.cql +12 -0
 - data/examples/CQL/SubtypePI.cql +32 -0
 - data/examples/CQL/Warehousing.cql +99 -0
 - data/examples/CQL/WindowInRoomInBldg.cql +22 -0
 - data/lib/activefacts.rb +10 -0
 - data/lib/activefacts/api.rb +25 -0
 - data/lib/activefacts/api/concept.rb +384 -0
 - data/lib/activefacts/api/constellation.rb +106 -0
 - data/lib/activefacts/api/entity.rb +239 -0
 - data/lib/activefacts/api/instance.rb +54 -0
 - data/lib/activefacts/api/numeric.rb +158 -0
 - data/lib/activefacts/api/role.rb +94 -0
 - data/lib/activefacts/api/standard_types.rb +67 -0
 - data/lib/activefacts/api/support.rb +59 -0
 - data/lib/activefacts/api/value.rb +122 -0
 - data/lib/activefacts/api/vocabulary.rb +120 -0
 - data/lib/activefacts/cql.rb +31 -0
 - data/lib/activefacts/cql/CQLParser.treetop +104 -0
 - data/lib/activefacts/cql/Concepts.treetop +112 -0
 - data/lib/activefacts/cql/DataTypes.treetop +66 -0
 - data/lib/activefacts/cql/Expressions.treetop +113 -0
 - data/lib/activefacts/cql/FactTypes.treetop +185 -0
 - data/lib/activefacts/cql/Language/English.treetop +92 -0
 - data/lib/activefacts/cql/LexicalRules.treetop +169 -0
 - data/lib/activefacts/cql/Rakefile +6 -0
 - data/lib/activefacts/cql/parser.rb +88 -0
 - data/lib/activefacts/generate/absorption.rb +87 -0
 - data/lib/activefacts/generate/cql.rb +441 -0
 - data/lib/activefacts/generate/cql/html.rb +397 -0
 - data/lib/activefacts/generate/null.rb +19 -0
 - data/lib/activefacts/generate/ordered.rb +557 -0
 - data/lib/activefacts/generate/ruby.rb +326 -0
 - data/lib/activefacts/generate/sql/server.rb +164 -0
 - data/lib/activefacts/generate/text.rb +21 -0
 - data/lib/activefacts/input/cql.rb +1268 -0
 - data/lib/activefacts/input/orm.rb +926 -0
 - data/lib/activefacts/persistence.rb +1 -0
 - data/lib/activefacts/persistence/composition.rb +653 -0
 - data/lib/activefacts/support.rb +51 -0
 - data/lib/activefacts/version.rb +3 -0
 - data/lib/activefacts/vocabulary.rb +6 -0
 - data/lib/activefacts/vocabulary/extensions.rb +343 -0
 - data/lib/activefacts/vocabulary/metamodel.rb +303 -0
 - data/script/txt2html +71 -0
 - data/spec/absorption_spec.rb +95 -0
 - data/spec/api/autocounter.rb +82 -0
 - data/spec/api/constellation.rb +130 -0
 - data/spec/api/entity_type.rb +101 -0
 - data/spec/api/instance.rb +428 -0
 - data/spec/api/roles.rb +122 -0
 - data/spec/api/value_type.rb +112 -0
 - data/spec/api_spec.rb +14 -0
 - data/spec/cql_cql_spec.rb +58 -0
 - data/spec/cql_parse_spec.rb +31 -0
 - data/spec/cql_ruby_spec.rb +60 -0
 - data/spec/cql_sql_spec.rb +54 -0
 - data/spec/cql_symbol_tables_spec.rb +259 -0
 - data/spec/cql_unit_spec.rb +336 -0
 - data/spec/cqldump_spec.rb +169 -0
 - data/spec/norma_cql_spec.rb +48 -0
 - data/spec/norma_ruby_spec.rb +50 -0
 - data/spec/norma_sql_spec.rb +45 -0
 - data/spec/norma_tables_spec.rb +94 -0
 - data/spec/spec.opts +1 -0
 - data/spec/spec_helper.rb +10 -0
 - metadata +173 -0
 
| 
         @@ -0,0 +1,397 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Generate HTML-highlighted CQL from an ActiveFacts vocabulary.
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            # The text generated here is pre-formatted, and in spans haing the following styles:
         
     | 
| 
      
 6 
     | 
    
         
            +
            # keyword: ORM2 standard colour is #00C (blue)
         
     | 
| 
      
 7 
     | 
    
         
            +
            # concept: ORM2 standard concept is #808 (purple)
         
     | 
| 
      
 8 
     | 
    
         
            +
            # copula: ORM2 standard concept is #060 (green)
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'activefacts/vocabulary'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'activefacts/api'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'activefacts/generate/ordered'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require 'activefacts/generate/cql'
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            module ActiveFacts
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              module Generate
         
     | 
| 
      
 18 
     | 
    
         
            +
                class CQL
         
     | 
| 
      
 19 
     | 
    
         
            +
                class HTML < CQL
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def initialize(vocabulary, *options)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    super
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def puts s
         
     | 
| 
      
 26 
     | 
    
         
            +
                    super(s.gsub(/[,;]/) do |p| keyword p; end)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def keyword(str)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    "<span class='keyword'>#{str}</span>"
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def concept(str)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    "<span class='concept'>#{str}</span>"
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def copula(str)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    "<span class='copula'>#{str}</span>"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def vocabulary_start(vocabulary)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    puts %q{<head>
         
     | 
| 
      
 43 
     | 
    
         
            +
                      <link rel="stylesheet" href="css/orm2.css" type="text/css"/>
         
     | 
| 
      
 44 
     | 
    
         
            +
                      </head>
         
     | 
| 
      
 45 
     | 
    
         
            +
                      <pre class="copula">}
         
     | 
| 
      
 46 
     | 
    
         
            +
                    puts "#{keyword "vocabulary"} #{concept(vocabulary.name)};\n\n"
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def vocabulary_end
         
     | 
| 
      
 50 
     | 
    
         
            +
                    puts %q{</pre>}
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  def value_type_banner
         
     | 
| 
      
 54 
     | 
    
         
            +
                    puts "/*\n * Value Types\n */"
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def value_type_dump(o)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    return unless o.supertype    # An imported type
         
     | 
| 
      
 59 
     | 
    
         
            +
                    if o.name == o.supertype.name
         
     | 
| 
      
 60 
     | 
    
         
            +
                        # In ActiveFacts, parameterising a ValueType will create a new datatype
         
     | 
| 
      
 61 
     | 
    
         
            +
                        # throw Can't handle parameterized value type of same name as its datatype" if ...
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    parameters =
         
     | 
| 
      
 65 
     | 
    
         
            +
                      [ o.length != 0 || o.scale != 0 ? o.length : nil,
         
     | 
| 
      
 66 
     | 
    
         
            +
                        o.scale != 0 ? o.scale : nil
         
     | 
| 
      
 67 
     | 
    
         
            +
                      ].compact
         
     | 
| 
      
 68 
     | 
    
         
            +
                    parameters = parameters.length > 0 ? "("+parameters.join(",")+")" : "()"
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    puts "#{concept o.name} #{keyword "is defined as"} #{concept o.supertype.name + parameters }#{
         
     | 
| 
      
 71 
     | 
    
         
            +
                        if (o.value_restriction)
         
     | 
| 
      
 72 
     | 
    
         
            +
                          keyword("restricted to")+
         
     | 
| 
      
 73 
     | 
    
         
            +
                          o.value_restriction.all_allowed_range.map{|ar|
         
     | 
| 
      
 74 
     | 
    
         
            +
                              # REVISIT: Need to display as string or numeric according to type here...
         
     | 
| 
      
 75 
     | 
    
         
            +
                              min = ar.value_range.minimum_bound
         
     | 
| 
      
 76 
     | 
    
         
            +
                              max = ar.value_range.maximum_bound
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                              range = (min ? min.value : "") +
         
     | 
| 
      
 79 
     | 
    
         
            +
                                (min.value != (max&&max.value) ? (".." + (max ? max.value : "")) : "")
         
     | 
| 
      
 80 
     | 
    
         
            +
                              keyword range
         
     | 
| 
      
 81 
     | 
    
         
            +
                            }*", "
         
     | 
| 
      
 82 
     | 
    
         
            +
                        else
         
     | 
| 
      
 83 
     | 
    
         
            +
                          ""
         
     | 
| 
      
 84 
     | 
    
         
            +
                        end
         
     | 
| 
      
 85 
     | 
    
         
            +
                      };"
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  def append_ring_to_reading(reading, ring)
         
     | 
| 
      
 89 
     | 
    
         
            +
                    reading << keyword(" [#{(ring.ring_type.scan(/[A-Z][a-z]*/)*", ").downcase}]")
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  def identified_by_roles_and_facts(entity_type, identifying_roles, identifying_facts, preferred_readings)
         
     | 
| 
      
 93 
     | 
    
         
            +
                    identifying_role_names = identifying_roles.map{|role|
         
     | 
| 
      
 94 
     | 
    
         
            +
                        preferred_role_ref = preferred_readings[role.fact_type].role_sequence.all_role_ref.detect{|reading_rr|
         
     | 
| 
      
 95 
     | 
    
         
            +
                            reading_rr.role == role
         
     | 
| 
      
 96 
     | 
    
         
            +
                          }
         
     | 
| 
      
 97 
     | 
    
         
            +
                        role_words = []
         
     | 
| 
      
 98 
     | 
    
         
            +
                        # REVISIT: Consider whether NOT to use the adjective if it's a prefix of the role_name
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                        role_name = role.role_name
         
     | 
| 
      
 101 
     | 
    
         
            +
                        role_name = nil if role_name == ""
         
     | 
| 
      
 102 
     | 
    
         
            +
                        # debug "concept.name=#{preferred_role_ref.role.concept.name}, role_name=#{role_name.inspect}, preferred_role_name=#{preferred_role_ref.role.role_name.inspect}"
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                        if (role.fact_type.all_role.size == 1)
         
     | 
| 
      
 105 
     | 
    
         
            +
                          # REVISIT: Guard against unary reading containing the illegal words "and" and "where".
         
     | 
| 
      
 106 
     | 
    
         
            +
                          role.fact_type.default_reading    # Need whole reading for a unary.
         
     | 
| 
      
 107 
     | 
    
         
            +
                        elsif (role_name)
         
     | 
| 
      
 108 
     | 
    
         
            +
                          role_name
         
     | 
| 
      
 109 
     | 
    
         
            +
                        else
         
     | 
| 
      
 110 
     | 
    
         
            +
                          role_words << preferred_role_ref.leading_adjective if preferred_role_ref.leading_adjective != ""
         
     | 
| 
      
 111 
     | 
    
         
            +
                          role_words << preferred_role_ref.role.concept.name
         
     | 
| 
      
 112 
     | 
    
         
            +
                          role_words << preferred_role_ref.trailing_adjective if preferred_role_ref.trailing_adjective != ""
         
     | 
| 
      
 113 
     | 
    
         
            +
                          role_words.compact*"-"
         
     | 
| 
      
 114 
     | 
    
         
            +
                        end
         
     | 
| 
      
 115 
     | 
    
         
            +
                      }
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                    # REVISIT: Consider emitting extra fact types here, instead of in entity_type_dump?
         
     | 
| 
      
 118 
     | 
    
         
            +
                    # Just beware that readings having the same players will be considered to be of the same fact type, even if they're not.
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                    # Detect standard reference-mode scenarios
         
     | 
| 
      
 121 
     | 
    
         
            +
                    ft = identifying_facts[0]
         
     | 
| 
      
 122 
     | 
    
         
            +
                    fact_constraints = nil
         
     | 
| 
      
 123 
     | 
    
         
            +
                    if identifying_facts.size == 1 and
         
     | 
| 
      
 124 
     | 
    
         
            +
                      entity_role = ft.all_role[n = (ft.all_role[0].concept == entity_type ? 0 : 1)] and
         
     | 
| 
      
 125 
     | 
    
         
            +
                      value_role = ft.all_role[1-n] and
         
     | 
| 
      
 126 
     | 
    
         
            +
                      value_name = value_role.concept.name and
         
     | 
| 
      
 127 
     | 
    
         
            +
                      residual = value_name.gsub(%r{#{entity_role.concept.name}},'') and
         
     | 
| 
      
 128 
     | 
    
         
            +
                      residual != '' and
         
     | 
| 
      
 129 
     | 
    
         
            +
                      residual != value_name
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                      # The EntityType is identified by its association with a single ValueType
         
     | 
| 
      
 132 
     | 
    
         
            +
                      # whose name is an extension (the residual) of the EntityType's name.
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                      # Detect standard reference-mode readings:
         
     | 
| 
      
 135 
     | 
    
         
            +
                      forward_reading = reverse_reading = nil
         
     | 
| 
      
 136 
     | 
    
         
            +
                      ft.all_reading.each do |reading|
         
     | 
| 
      
 137 
     | 
    
         
            +
                        if reading.reading_text =~ /^\{(\d)\} has \{\d\}$/
         
     | 
| 
      
 138 
     | 
    
         
            +
                          if reading.role_sequence.all_role_ref[$1.to_i].role == entity_role
         
     | 
| 
      
 139 
     | 
    
         
            +
                            forward_reading = reading
         
     | 
| 
      
 140 
     | 
    
         
            +
                          else
         
     | 
| 
      
 141 
     | 
    
         
            +
                            reverse_reading = reading
         
     | 
| 
      
 142 
     | 
    
         
            +
                          end
         
     | 
| 
      
 143 
     | 
    
         
            +
                        elsif reading.reading_text =~ /^\{(\d)\} is of \{\d\}$/
         
     | 
| 
      
 144 
     | 
    
         
            +
                          if reading.role_sequence.all_role_ref[$1.to_i].role == value_role
         
     | 
| 
      
 145 
     | 
    
         
            +
                            reverse_reading = reading
         
     | 
| 
      
 146 
     | 
    
         
            +
                          else
         
     | 
| 
      
 147 
     | 
    
         
            +
                            forward_reading = reading
         
     | 
| 
      
 148 
     | 
    
         
            +
                          end
         
     | 
| 
      
 149 
     | 
    
         
            +
                        end
         
     | 
| 
      
 150 
     | 
    
         
            +
                      end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                      debug :mode, "------------------- Didn't find standard forward reading" unless forward_reading
         
     | 
| 
      
 153 
     | 
    
         
            +
                      debug :mode, "------------------- Didn't find standard reverse reading" unless reverse_reading
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                      # If we didn't find at least one of the standard readings, don't use a refmode:
         
     | 
| 
      
 156 
     | 
    
         
            +
                      if (forward_reading || reverse_reading)
         
     | 
| 
      
 157 
     | 
    
         
            +
                        # Elide the constraints that would have been emitted on those readings.
         
     | 
| 
      
 158 
     | 
    
         
            +
                        # If there is a UC that's not in the standard form for a reference mode,
         
     | 
| 
      
 159 
     | 
    
         
            +
                        # we have to emit the standard reading anyhow.
         
     | 
| 
      
 160 
     | 
    
         
            +
                        fact_constraints = @presence_constraints_by_fact[ft]
         
     | 
| 
      
 161 
     | 
    
         
            +
                        fact_constraints.each do |pc|
         
     | 
| 
      
 162 
     | 
    
         
            +
                          if (pc.role_sequence.all_role_ref.size == 1 and pc.max_frequency == 1)
         
     | 
| 
      
 163 
     | 
    
         
            +
                            # It's a uniqueness constraint, and will be regenerated
         
     | 
| 
      
 164 
     | 
    
         
            +
                            @constraints_used[pc] = true
         
     | 
| 
      
 165 
     | 
    
         
            +
                          end
         
     | 
| 
      
 166 
     | 
    
         
            +
                        end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                        @fact_types_dumped[ft] = true
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                        # Figure out whether any non-standard readings exist:
         
     | 
| 
      
 171 
     | 
    
         
            +
                        other_readings = ft.all_reading - [forward_reading] - [reverse_reading]
         
     | 
| 
      
 172 
     | 
    
         
            +
                        debug :mode, "--- other_readings.size now = #{other_readings.size}" if other_readings.size > 0
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                        fact_text = other_readings.map do |reading|
         
     | 
| 
      
 175 
     | 
    
         
            +
                          expanded_reading(reading, fact_constraints, true)
         
     | 
| 
      
 176 
     | 
    
         
            +
                        end*",\n\t"
         
     | 
| 
      
 177 
     | 
    
         
            +
                        return keyword(" identified by its ") +
         
     | 
| 
      
 178 
     | 
    
         
            +
                          concept(residual) +
         
     | 
| 
      
 179 
     | 
    
         
            +
                          (fact_text != "" ? keyword(" where\n\t") + fact_text : "")
         
     | 
| 
      
 180 
     | 
    
         
            +
                      end
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                    identifying_facts.each{|f| @fact_types_dumped[f] = true }
         
     | 
| 
      
 184 
     | 
    
         
            +
                    @identifying_fact_text = 
         
     | 
| 
      
 185 
     | 
    
         
            +
                        identifying_facts.map{|f|
         
     | 
| 
      
 186 
     | 
    
         
            +
                            fact_readings_with_constraints(f, fact_constraints)
         
     | 
| 
      
 187 
     | 
    
         
            +
                        }.flatten*",\n\t"
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                    keyword(" identified by ") +
         
     | 
| 
      
 190 
     | 
    
         
            +
                      identifying_role_names.map{|n| concept n} * keyword(" and ") +
         
     | 
| 
      
 191 
     | 
    
         
            +
                      keyword(" where\n\t") +
         
     | 
| 
      
 192 
     | 
    
         
            +
                      @identifying_fact_text
         
     | 
| 
      
 193 
     | 
    
         
            +
                  end
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
                  def show_frequency role, constraint
         
     | 
| 
      
 196 
     | 
    
         
            +
                    # REVISIT: Need to also colorize the adjectives here:
         
     | 
| 
      
 197 
     | 
    
         
            +
                    [ constraint ? keyword(constraint.frequency) : nil, concept(role.concept.name) ]
         
     | 
| 
      
 198 
     | 
    
         
            +
                  end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                  def entity_type_banner
         
     | 
| 
      
 201 
     | 
    
         
            +
                    puts(keyword("/*\n * Entity Types\n */"))
         
     | 
| 
      
 202 
     | 
    
         
            +
                  end
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
                  def fact_readings(fact_type)
         
     | 
| 
      
 205 
     | 
    
         
            +
                    constrained_fact_readings = fact_readings_with_constraints(fact_type)
         
     | 
| 
      
 206 
     | 
    
         
            +
                    constrained_fact_readings*",\n\t"
         
     | 
| 
      
 207 
     | 
    
         
            +
                  end
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                  def subtype_dump(o, supertypes, pi)
         
     | 
| 
      
 210 
     | 
    
         
            +
                    print "#{concept o.name} #{keyword "is a kind of"} #{ o.supertypes.map(&:name).map{|n| concept n}*keyword(", ") }"
         
     | 
| 
      
 211 
     | 
    
         
            +
                    if pi
         
     | 
| 
      
 212 
     | 
    
         
            +
                      print identified_by(o, pi)
         
     | 
| 
      
 213 
     | 
    
         
            +
                    end
         
     | 
| 
      
 214 
     | 
    
         
            +
                    # If there's a preferred_identifier for this subtype, identifying readings were emitted
         
     | 
| 
      
 215 
     | 
    
         
            +
                    if o.fact_type
         
     | 
| 
      
 216 
     | 
    
         
            +
                      print(
         
     | 
| 
      
 217 
     | 
    
         
            +
                        (pi ? "," : keyword(" where")) +
         
     | 
| 
      
 218 
     | 
    
         
            +
                        "\n\t" +
         
     | 
| 
      
 219 
     | 
    
         
            +
                        fact_readings(o.fact_type)
         
     | 
| 
      
 220 
     | 
    
         
            +
                      )
         
     | 
| 
      
 221 
     | 
    
         
            +
                    end
         
     | 
| 
      
 222 
     | 
    
         
            +
                    puts ";\n"
         
     | 
| 
      
 223 
     | 
    
         
            +
                  end
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
                  def non_subtype_dump(o, pi)
         
     | 
| 
      
 226 
     | 
    
         
            +
                    print "#{concept(o.name)} #{keyword "is"}" +
         
     | 
| 
      
 227 
     | 
    
         
            +
                      identified_by(o, pi)
         
     | 
| 
      
 228 
     | 
    
         
            +
                    print(keyword(" where\n\t") + fact_readings(o.fact_type)) if o.fact_type
         
     | 
| 
      
 229 
     | 
    
         
            +
                    puts ";\n"
         
     | 
| 
      
 230 
     | 
    
         
            +
                  end
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                  def fact_type_dump(fact_type, name)
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                    @identifying_fact_text = nil
         
     | 
| 
      
 235 
     | 
    
         
            +
                    if (o = fact_type.entity_type)
         
     | 
| 
      
 236 
     | 
    
         
            +
                      print "#{concept o.name} #{keyword "is"}"
         
     | 
| 
      
 237 
     | 
    
         
            +
                      if !o.all_type_inheritance_by_subtype.empty?
         
     | 
| 
      
 238 
     | 
    
         
            +
                        print(keyword(" a kind of ") + o.supertypes.map(&:name).map{|n| concept n}*", ")
         
     | 
| 
      
 239 
     | 
    
         
            +
                      end
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                      # Alternate identification of objectified fact type?
         
     | 
| 
      
 242 
     | 
    
         
            +
                      primary_supertype = o.supertypes[0]
         
     | 
| 
      
 243 
     | 
    
         
            +
                      pi = fact_type.entity_type.preferred_identifier
         
     | 
| 
      
 244 
     | 
    
         
            +
                      if pi && primary_supertype && primary_supertype.preferred_identifier != pi
         
     | 
| 
      
 245 
     | 
    
         
            +
                        print identified_by(o, pi)
         
     | 
| 
      
 246 
     | 
    
         
            +
                        print ";\n"
         
     | 
| 
      
 247 
     | 
    
         
            +
                      end
         
     | 
| 
      
 248 
     | 
    
         
            +
                    end
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
                    unless @identifying_fact_text
         
     | 
| 
      
 251 
     | 
    
         
            +
                      print(keyword(" where\n\t")) if o
         
     | 
| 
      
 252 
     | 
    
         
            +
                      puts(fact_readings(fact_type)+";")
         
     | 
| 
      
 253 
     | 
    
         
            +
                    end
         
     | 
| 
      
 254 
     | 
    
         
            +
                  end
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                  def fact_type_banner
         
     | 
| 
      
 257 
     | 
    
         
            +
                    puts keyword("/*\n * Fact Types\n */")
         
     | 
| 
      
 258 
     | 
    
         
            +
                  end
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
                  def constraint_banner
         
     | 
| 
      
 261 
     | 
    
         
            +
                    puts keyword("/*\n * Constraints:\n */")
         
     | 
| 
      
 262 
     | 
    
         
            +
                  end
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
                  def dump_presence_constraint(c)
         
     | 
| 
      
 265 
     | 
    
         
            +
                    roles = c.role_sequence.all_role_ref.map{|rr| rr.role }
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
                    # REVISIT: If only one role is covered and it's mandatory >=1 constraint, use SOME/THAT form:
         
     | 
| 
      
 268 
     | 
    
         
            +
                    # each Bug SOME Tester logged THAT Bug;
         
     | 
| 
      
 269 
     | 
    
         
            +
                    players = c.role_sequence.all_role_ref.map{|rr| rr.role.concept.name}.uniq
         
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
                    fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq
         
     | 
| 
      
 272 
     | 
    
         
            +
                    puts \
         
     | 
| 
      
 273 
     | 
    
         
            +
                      "#{keyword "each #{players.size > 1 ? "combination " : ""}"}"+
         
     | 
| 
      
 274 
     | 
    
         
            +
                      "#{players.map{|n| concept n}*", "} "+
         
     | 
| 
      
 275 
     | 
    
         
            +
                      "#{keyword "occurs #{c.frequency} time in"}\n\t"+
         
     | 
| 
      
 276 
     | 
    
         
            +
                      "#{fact_types.map{|ft| ft.default_reading([], nil)}*",\n\t"}" +
         
     | 
| 
      
 277 
     | 
    
         
            +
                        ";"
         
     | 
| 
      
 278 
     | 
    
         
            +
                  end
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                  def dump_set_constraint(c)
         
     | 
| 
      
 281 
     | 
    
         
            +
                    # REVISIT exclusion: every <player-list> must<?> either reading1, reading2, ...
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
                    # Each constraint involves two or more occurrences of one or more players.
         
     | 
| 
      
 284 
     | 
    
         
            +
                    # For each player, a subtype may be involved in the occurrences.
         
     | 
| 
      
 285 
     | 
    
         
            +
                    # Find the common supertype of each player.
         
     | 
| 
      
 286 
     | 
    
         
            +
                    scrs = c.all_set_comparison_roles
         
     | 
| 
      
 287 
     | 
    
         
            +
                    player_count = scrs[0].role_sequence.all_role_ref.size
         
     | 
| 
      
 288 
     | 
    
         
            +
                    role_seq_count = scrs.size
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
                    #raise "Can't verbalise constraint over many players and facts" if player_count > 1 and role_seq_count > 1
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
                    players_differ = []   # Record which players are also played by subclasses
         
     | 
| 
      
 293 
     | 
    
         
            +
                    players = (0...player_count).map do |pi|
         
     | 
| 
      
 294 
     | 
    
         
            +
                      # Find the common supertype of the players of the pi'th role in each sequence
         
     | 
| 
      
 295 
     | 
    
         
            +
                      concepts = scrs.map{|r| r.role_sequence.all_role_ref[pi].role.concept }
         
     | 
| 
      
 296 
     | 
    
         
            +
                      player, players_differ[pi] = common_supertype(concepts)
         
     | 
| 
      
 297 
     | 
    
         
            +
                      raise "Role sequences of #{c.class.basename} must have concepts matching #{c.name} in position #{pi}" unless player
         
     | 
| 
      
 298 
     | 
    
         
            +
                      player
         
     | 
| 
      
 299 
     | 
    
         
            +
                    end
         
     | 
| 
      
 300 
     | 
    
         
            +
                    #puts "#{c.class.basename} has players #{players.map{|p| p.name}*", "}"
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
                    if (SetEqualityConstraint === c)
         
     | 
| 
      
 303 
     | 
    
         
            +
                      # REVISIT: Need a proper approach to some/that and adjective disambiguation:
         
     | 
| 
      
 304 
     | 
    
         
            +
                      puts \
         
     | 
| 
      
 305 
     | 
    
         
            +
                        scrs.map{|scr|
         
     | 
| 
      
 306 
     | 
    
         
            +
                          scr.role_sequence.all_role_ref.map{|rr|
         
     | 
| 
      
 307 
     | 
    
         
            +
                            rr.role.fact_type.default_reading([], nil)
         
     | 
| 
      
 308 
     | 
    
         
            +
                          }*keyword(" and ")
         
     | 
| 
      
 309 
     | 
    
         
            +
                        } * keyword("\n\tif and only if\n\t") + ";"
         
     | 
| 
      
 310 
     | 
    
         
            +
                      return
         
     | 
| 
      
 311 
     | 
    
         
            +
                    end
         
     | 
| 
      
 312 
     | 
    
         
            +
             
     | 
| 
      
 313 
     | 
    
         
            +
                    mode = c.is_mandatory ? "exactly one" : "at most one"
         
     | 
| 
      
 314 
     | 
    
         
            +
                    puts "#{keyword "for each"} #{players.map{|p| concept p.name}*", "} #{keyword(mode + " of these holds")}:\n\t" +
         
     | 
| 
      
 315 
     | 
    
         
            +
                      (scrs.map do |scr|
         
     | 
| 
      
 316 
     | 
    
         
            +
                        constrained_roles = scr.role_sequence.all_role_ref.map{|rr| rr.role }
         
     | 
| 
      
 317 
     | 
    
         
            +
                        fact_types = constrained_roles.map{|r| r.fact_type }.uniq
         
     | 
| 
      
 318 
     | 
    
         
            +
             
     | 
| 
      
 319 
     | 
    
         
            +
                        fact_types.map do |fact_type|
         
     | 
| 
      
 320 
     | 
    
         
            +
                          # REVISIT: future: Use "THAT" and "SOME" only when:
         
     | 
| 
      
 321 
     | 
    
         
            +
                          # - the role player occurs twice in the reading, or
         
     | 
| 
      
 322 
     | 
    
         
            +
                          # - is a subclass of the constrained concept, or
         
     | 
| 
      
 323 
     | 
    
         
            +
                          reading = fact_type.preferred_reading
         
     | 
| 
      
 324 
     | 
    
         
            +
                          expand_constrained(reading, constrained_roles, players, players_differ)
         
     | 
| 
      
 325 
     | 
    
         
            +
                        end * keyword(" and ")
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
                      end*",\n\t"
         
     | 
| 
      
 328 
     | 
    
         
            +
                      )+';'
         
     | 
| 
      
 329 
     | 
    
         
            +
                  end
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
      
 331 
     | 
    
         
            +
                  # Expand this reading using (in)definite articles where needed
         
     | 
| 
      
 332 
     | 
    
         
            +
                  # Handle any roles in constrained_roles specially.
         
     | 
| 
      
 333 
     | 
    
         
            +
                  def expand_constrained(reading, constrained_roles, players, players_differ)
         
     | 
| 
      
 334 
     | 
    
         
            +
                    frequency_constraints = reading.role_sequence.all_role_ref.map {|role_ref|
         
     | 
| 
      
 335 
     | 
    
         
            +
                        i = constrained_roles.index(role_ref.role)
         
     | 
| 
      
 336 
     | 
    
         
            +
                        if !i
         
     | 
| 
      
 337 
     | 
    
         
            +
                          v = [ "some", role_ref.role.concept.name]
         
     | 
| 
      
 338 
     | 
    
         
            +
                        elsif players_differ[i]
         
     | 
| 
      
 339 
     | 
    
         
            +
                          v = [ "that", players[i].name ]   # Make sure to use the superclass name
         
     | 
| 
      
 340 
     | 
    
         
            +
                        else
         
     | 
| 
      
 341 
     | 
    
         
            +
                          if reading.fact_type.all_role.select{|r| r.concept == role_ref.role.concept }.size > 1
         
     | 
| 
      
 342 
     | 
    
         
            +
                            v = [ "that", role_ref.role.concept.name ]
         
     | 
| 
      
 343 
     | 
    
         
            +
                          else
         
     | 
| 
      
 344 
     | 
    
         
            +
                            v = [ "some", role_ref.role.concept.name ]
         
     | 
| 
      
 345 
     | 
    
         
            +
                          end
         
     | 
| 
      
 346 
     | 
    
         
            +
                        end
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
                        v[0] = keyword(v[0])
         
     | 
| 
      
 349 
     | 
    
         
            +
                        v[1] = concept(v[1])
         
     | 
| 
      
 350 
     | 
    
         
            +
                        v
         
     | 
| 
      
 351 
     | 
    
         
            +
                      }
         
     | 
| 
      
 352 
     | 
    
         
            +
                    frequency_constraints = [] unless frequency_constraints.detect{|fc| fc[0] =~ /some/ }
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
                    #$stderr.puts "fact_type roles (#{fact_type.all_role.map{|r| r.concept.name}*","}) default_reading '#{fact_type.preferred_reading.reading_text}' roles (#{fact_type.preferred_reading.role_sequence.all_role_ref.map{|rr| rr.role.concept.name}*","}) #{frequency_constraints.inspect}"
         
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
      
 356 
     | 
    
         
            +
                    # REVISIT: Make sure that we refer to the constrained players by their common supertype
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
                    reading.expand(frequency_constraints, nil)
         
     | 
| 
      
 359 
     | 
    
         
            +
                  end
         
     | 
| 
      
 360 
     | 
    
         
            +
             
     | 
| 
      
 361 
     | 
    
         
            +
                  def dump_subset_constraint(c)
         
     | 
| 
      
 362 
     | 
    
         
            +
                    # If the role players are identical and not duplicated, we can simply say "reading1 only if reading2"
         
     | 
| 
      
 363 
     | 
    
         
            +
                    subset_roles = c.subset_role_sequence.all_role_ref.map{|rr| rr.role}
         
     | 
| 
      
 364 
     | 
    
         
            +
                    superset_roles = c.superset_role_sequence.all_role_ref.map{|rr| rr.role}
         
     | 
| 
      
 365 
     | 
    
         
            +
             
     | 
| 
      
 366 
     | 
    
         
            +
                    subset_players = subset_roles.map(&:concept)
         
     | 
| 
      
 367 
     | 
    
         
            +
                    superset_players = superset_roles.map(&:concept)
         
     | 
| 
      
 368 
     | 
    
         
            +
             
     | 
| 
      
 369 
     | 
    
         
            +
                    subset_fact_types = c.subset_role_sequence.all_role_ref.map{|rr| rr.role.fact_type }.uniq
         
     | 
| 
      
 370 
     | 
    
         
            +
                    superset_fact_types = c.superset_role_sequence.all_role_ref.map{|rr| rr.role.fact_type }.uniq
         
     | 
| 
      
 371 
     | 
    
         
            +
             
     | 
| 
      
 372 
     | 
    
         
            +
                    # We need to ensure that if the player of any constrained role also exists
         
     | 
| 
      
 373 
     | 
    
         
            +
                    # as the player of a role that's not a constrained role, there are different
         
     | 
| 
      
 374 
     | 
    
         
            +
                    # adjectives or other qualifiers qualifier applied to distinguish that role.
         
     | 
| 
      
 375 
     | 
    
         
            +
                    fact_type_roles = (subset_fact_types+superset_fact_types).map{|ft| ft.all_role }.flatten
         
     | 
| 
      
 376 
     | 
    
         
            +
                    non_constrained_roles = fact_type_roles - subset_roles - superset_roles
         
     | 
| 
      
 377 
     | 
    
         
            +
                    if (r = non_constrained_roles.detect{|r| (subset_roles+superset_roles).include?(r) })
         
     | 
| 
      
 378 
     | 
    
         
            +
                      # REVISIT: Find a way to deal with this problem, should it arise.
         
     | 
| 
      
 379 
     | 
    
         
            +
             
     | 
| 
      
 380 
     | 
    
         
            +
                      # It would help, but not entirely fix it, to use SOME/THAT to identify the constrained roles.
         
     | 
| 
      
 381 
     | 
    
         
            +
                      # See ServiceDirector's DataStore<->Client fact types for example
         
     | 
| 
      
 382 
     | 
    
         
            +
                      # Use SOME on the subset, THAT on the superset.
         
     | 
| 
      
 383 
     | 
    
         
            +
                      raise "Critical ambiguity, #{r.concept.name} occurs both constrained and unconstrained in #{c.name}"
         
     | 
| 
      
 384 
     | 
    
         
            +
                    end
         
     | 
| 
      
 385 
     | 
    
         
            +
             
     | 
| 
      
 386 
     | 
    
         
            +
                    puts \
         
     | 
| 
      
 387 
     | 
    
         
            +
                      "#{subset_fact_types.map{|ft| ft.default_reading([], nil)}*" and "}" +
         
     | 
| 
      
 388 
     | 
    
         
            +
                      "\n\t#{keyword "only if"} " +
         
     | 
| 
      
 389 
     | 
    
         
            +
                      "#{superset_fact_types.map{|ft| ft.default_reading([], nil)}*" and "}" +
         
     | 
| 
      
 390 
     | 
    
         
            +
                      ";"
         
     | 
| 
      
 391 
     | 
    
         
            +
                  end
         
     | 
| 
      
 392 
     | 
    
         
            +
             
     | 
| 
      
 393 
     | 
    
         
            +
                end
         
     | 
| 
      
 394 
     | 
    
         
            +
                end
         
     | 
| 
      
 395 
     | 
    
         
            +
              end
         
     | 
| 
      
 396 
     | 
    
         
            +
            end
         
     | 
| 
      
 397 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Generate text output for ActiveFacts vocabularies.
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright (c) 2007 Clifford Heath. Read the LICENSE file.
         
     | 
| 
      
 5 
     | 
    
         
            +
            # Author: Clifford Heath.
         
     | 
| 
      
 6 
     | 
    
         
            +
            #
         
     | 
| 
      
 7 
     | 
    
         
            +
            module ActiveFacts
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Generate
         
     | 
| 
      
 9 
     | 
    
         
            +
                class NULL
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(vocabulary)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @vocabulary = vocabulary
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def generate(out = $>)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,557 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Generator superclass for ActiveFacts vocabularies that performs sequencing to avoid forward references.
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright (c) 2008 Clifford Heath. Read the LICENSE file.
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'activefacts/api'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module ActiveFacts
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              class OrderedDumper #:nodoc:
         
     | 
| 
      
 11 
     | 
    
         
            +
                include Metamodel
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize(vocabulary, *options)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @vocabulary = vocabulary
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @vocabulary = @vocabulary.Vocabulary.values[0] if ActiveFacts::API::Constellation === @vocabulary
         
     | 
| 
      
 16 
     | 
    
         
            +
                  options.each{|option| set_option(option) }
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def set_option(option)
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def puts(*a)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @out.puts *a
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def print(*a)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @out.print *a
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def generate(out = $>)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @out = out
         
     | 
| 
      
 32 
     | 
    
         
            +
                  vocabulary_start(@vocabulary)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  build_indices
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @concept_types_dumped = {}
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @fact_types_dumped = {}
         
     | 
| 
      
 37 
     | 
    
         
            +
                  value_types_dump()
         
     | 
| 
      
 38 
     | 
    
         
            +
                  entity_types_dump()
         
     | 
| 
      
 39 
     | 
    
         
            +
                  fact_types_dump()
         
     | 
| 
      
 40 
     | 
    
         
            +
                  constraints_dump(@constraints_used)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  vocabulary_end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def build_indices
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @presence_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @ring_constraints_by_fact = Hash.new{ |h, k| h[k] = [] }
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  @vocabulary.all_constraint.each { |c|
         
     | 
| 
      
 49 
     | 
    
         
            +
                      case c
         
     | 
| 
      
 50 
     | 
    
         
            +
                      when PresenceConstraint
         
     | 
| 
      
 51 
     | 
    
         
            +
                        fact_types = c.role_sequence.all_role_ref.map{|rr| rr.role.fact_type}.uniq  # All fact types spanned by this constraint
         
     | 
| 
      
 52 
     | 
    
         
            +
                        if fact_types.size == 1     # There's only one, save it:
         
     | 
| 
      
 53 
     | 
    
         
            +
                          # debug "Single-fact constraint on #{fact_types[0].fact_type_id}: #{c.name}"
         
     | 
| 
      
 54 
     | 
    
         
            +
                          (@presence_constraints_by_fact[fact_types[0]] ||= []) << c
         
     | 
| 
      
 55 
     | 
    
         
            +
                        end
         
     | 
| 
      
 56 
     | 
    
         
            +
                      when RingConstraint
         
     | 
| 
      
 57 
     | 
    
         
            +
                        (@ring_constraints_by_fact[c.role.fact_type] ||= []) << c
         
     | 
| 
      
 58 
     | 
    
         
            +
                      else
         
     | 
| 
      
 59 
     | 
    
         
            +
                        # debug "Found unhandled constraint #{c.class} #{c.name}"
         
     | 
| 
      
 60 
     | 
    
         
            +
                      end
         
     | 
| 
      
 61 
     | 
    
         
            +
                    }
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @constraints_used = {}
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def value_types_dump
         
     | 
| 
      
 66 
     | 
    
         
            +
                  done_banner = false
         
     | 
| 
      
 67 
     | 
    
         
            +
                  @vocabulary.all_feature.sort_by{|o| o.name}.each{|o|
         
     | 
| 
      
 68 
     | 
    
         
            +
                      next unless ValueType === o
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                      value_type_banner unless done_banner
         
     | 
| 
      
 71 
     | 
    
         
            +
                      done_banner = true
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                      value_type_dump(o)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      @concept_types_dumped[o] = true
         
     | 
| 
      
 75 
     | 
    
         
            +
                    }
         
     | 
| 
      
 76 
     | 
    
         
            +
                  value_type_end if done_banner
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                # Try to dump entity types in order of name, but we need
         
     | 
| 
      
 80 
     | 
    
         
            +
                # to dump ETs before they're referenced in preferred ids
         
     | 
| 
      
 81 
     | 
    
         
            +
                # if possible (it's not always, there may be loops!)
         
     | 
| 
      
 82 
     | 
    
         
            +
                def entity_types_dump
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # Build hash tables of precursors and followers to use:
         
     | 
| 
      
 84 
     | 
    
         
            +
                  precursors, followers = *build_entity_dependencies
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  done_banner = false
         
     | 
| 
      
 87 
     | 
    
         
            +
                  sorted = @vocabulary.all_feature.select{|o| EntityType === o and !o.fact_type }.sort_by{|o| o.name}
         
     | 
| 
      
 88 
     | 
    
         
            +
                  panic = nil
         
     | 
| 
      
 89 
     | 
    
         
            +
                  while true do
         
     | 
| 
      
 90 
     | 
    
         
            +
                    count_this_pass = 0
         
     | 
| 
      
 91 
     | 
    
         
            +
                    skipped_this_pass = 0
         
     | 
| 
      
 92 
     | 
    
         
            +
                    sorted.each{|o|
         
     | 
| 
      
 93 
     | 
    
         
            +
                        next if @concept_types_dumped[o]    # Already done
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                        # Can we do this yet?
         
     | 
| 
      
 96 
     | 
    
         
            +
                        if (o != panic and                  # We don't *have* to do it (panic mode)
         
     | 
| 
      
 97 
     | 
    
         
            +
                            (p = precursors[o]) and         # There might be...
         
     | 
| 
      
 98 
     | 
    
         
            +
                            p.size > 0)                     # precursors - still blocked
         
     | 
| 
      
 99 
     | 
    
         
            +
                          skipped_this_pass += 1
         
     | 
| 
      
 100 
     | 
    
         
            +
                          next
         
     | 
| 
      
 101 
     | 
    
         
            +
                        end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                        entity_type_banner unless done_banner
         
     | 
| 
      
 104 
     | 
    
         
            +
                        done_banner = true
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                        # We're going to emit o - remove it from precursors of others:
         
     | 
| 
      
 107 
     | 
    
         
            +
                        (followers[o]||[]).each{|f|
         
     | 
| 
      
 108 
     | 
    
         
            +
                            precursors[f] -= [o]
         
     | 
| 
      
 109 
     | 
    
         
            +
                          }
         
     | 
| 
      
 110 
     | 
    
         
            +
                        count_this_pass += 1
         
     | 
| 
      
 111 
     | 
    
         
            +
                        panic = nil
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                        entity_type_dump(o)
         
     | 
| 
      
 114 
     | 
    
         
            +
                        released_fact_types_dump(o)
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                        entity_type_group_end
         
     | 
| 
      
 117 
     | 
    
         
            +
                      }
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                      # Check that we made progress if there's any to make:
         
     | 
| 
      
 120 
     | 
    
         
            +
                      if count_this_pass == 0 && skipped_this_pass > 0
         
     | 
| 
      
 121 
     | 
    
         
            +
                        if panic        # We were already panicing... what to do now?
         
     | 
| 
      
 122 
     | 
    
         
            +
                          # This won't happen again unless the above code is changed to decide it can't dump "panic".
         
     | 
| 
      
 123 
     | 
    
         
            +
                          raise "Unresolvable cycle of forward references: " +
         
     | 
| 
      
 124 
     | 
    
         
            +
                            (bad = sorted.select{|o| EntityType === o && !@concept_types_dumped[o]}).map{|o| o.name }.inspect +
         
     | 
| 
      
 125 
     | 
    
         
            +
                            ":\n\t" + bad.map{|o|
         
     | 
| 
      
 126 
     | 
    
         
            +
                              o.name +
         
     | 
| 
      
 127 
     | 
    
         
            +
                              ": " +
         
     | 
| 
      
 128 
     | 
    
         
            +
                              precursors[o].map{|p| p.name}.uniq.inspect
         
     | 
| 
      
 129 
     | 
    
         
            +
                            } * "\n\t" + "\n"
         
     | 
| 
      
 130 
     | 
    
         
            +
                        else
         
     | 
| 
      
 131 
     | 
    
         
            +
                          # Find the object that has the most followers and no fwd-ref'd supertypes:
         
     | 
| 
      
 132 
     | 
    
         
            +
                          # This selection might be better if we allow PI roles to be fwd-ref'd...
         
     | 
| 
      
 133 
     | 
    
         
            +
                          panic = sorted.
         
     | 
| 
      
 134 
     | 
    
         
            +
                            select{|o| !@concept_types_dumped[o] }.
         
     | 
| 
      
 135 
     | 
    
         
            +
                            sort_by{|o|
         
     | 
| 
      
 136 
     | 
    
         
            +
                                f = followers[o] || []; 
         
     | 
| 
      
 137 
     | 
    
         
            +
                                o.supertypes.detect{|s| !@concept_types_dumped[s] } ? 0 : -f.size
         
     | 
| 
      
 138 
     | 
    
         
            +
                              }[0]
         
     | 
| 
      
 139 
     | 
    
         
            +
                          # debug "Panic mode, selected #{panic.name} next"
         
     | 
| 
      
 140 
     | 
    
         
            +
                        end
         
     | 
| 
      
 141 
     | 
    
         
            +
                      end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                      break if skipped_this_pass == 0       # All done.
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
                end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                def entity_type_dump(o)
         
     | 
| 
      
 149 
     | 
    
         
            +
                  @concept_types_dumped[o] = true
         
     | 
| 
      
 150 
     | 
    
         
            +
                  pi = o.preferred_identifier
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  supers = o.supertypes
         
     | 
| 
      
 153 
     | 
    
         
            +
                  if (supers.size > 0)
         
     | 
| 
      
 154 
     | 
    
         
            +
                    # Ignore identification by a supertype:
         
     | 
| 
      
 155 
     | 
    
         
            +
                    pi = nil if pi && pi.role_sequence.all_role_ref[0].role.fact_type.is_a?(TypeInheritance)
         
     | 
| 
      
 156 
     | 
    
         
            +
                    subtype_dump(o, supers, pi)
         
     | 
| 
      
 157 
     | 
    
         
            +
                  else
         
     | 
| 
      
 158 
     | 
    
         
            +
                    non_subtype_dump(o, pi)
         
     | 
| 
      
 159 
     | 
    
         
            +
                  end
         
     | 
| 
      
 160 
     | 
    
         
            +
                  @constraints_used[pi] = true
         
     | 
| 
      
 161 
     | 
    
         
            +
                end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                def identified_by(o, pi)
         
     | 
| 
      
 164 
     | 
    
         
            +
                  # Different adjectives might be used for different readings.
         
     | 
| 
      
 165 
     | 
    
         
            +
                  # Here, we must find the role_ref containing the adjectives that we need for each identifier,
         
     | 
| 
      
 166 
     | 
    
         
            +
                  # which will be attached to the uniqueness constraint on this object in the binary FT that
         
     | 
| 
      
 167 
     | 
    
         
            +
                  # attaches that identifying role.
         
     | 
| 
      
 168 
     | 
    
         
            +
                  role_refs = pi.role_sequence.all_role_ref.sort_by{|role_ref| role_ref.ordinal}
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                  # We need to get the adjectives for the roles from the identifying fact's preferred readings:
         
     | 
| 
      
 171 
     | 
    
         
            +
                  identifying_facts = role_refs.map{|rr| rr.role.fact_type }.uniq
         
     | 
| 
      
 172 
     | 
    
         
            +
                  preferred_readings = identifying_facts.inject({}){|reading_hash, fact_type|
         
     | 
| 
      
 173 
     | 
    
         
            +
                      pr = fact_type.preferred_reading
         
     | 
| 
      
 174 
     | 
    
         
            +
                      reading_hash[fact_type] = pr
         
     | 
| 
      
 175 
     | 
    
         
            +
                      reading_hash
         
     | 
| 
      
 176 
     | 
    
         
            +
                    }
         
     | 
| 
      
 177 
     | 
    
         
            +
                  #p identifying_facts.map{|f| f.preferred_reading }
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                  identifying_roles = role_refs.map(&:role)
         
     | 
| 
      
 180 
     | 
    
         
            +
                  identification = identified_by_roles_and_facts(o, identifying_roles, identifying_facts, preferred_readings)
         
     | 
| 
      
 181 
     | 
    
         
            +
                  #identifying_facts.each{|f| @fact_types_dumped[f] = true }
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                  identification
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                def fact_readings_with_constraints(fact_type, fact_constraints = nil)
         
     | 
| 
      
 187 
     | 
    
         
            +
                  define_role_names = true
         
     | 
| 
      
 188 
     | 
    
         
            +
                  fact_constraints ||= @presence_constraints_by_fact[fact_type]
         
     | 
| 
      
 189 
     | 
    
         
            +
                  readings = fact_type.all_reading_by_ordinal.inject([]) do |reading_array, reading|
         
     | 
| 
      
 190 
     | 
    
         
            +
                    reading_array << expanded_reading(reading, fact_constraints, define_role_names)
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                    define_role_names = false     # No need to define role names in subsequent readings
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                    reading_array
         
     | 
| 
      
 195 
     | 
    
         
            +
                  end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                  readings
         
     | 
| 
      
 198 
     | 
    
         
            +
                end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                def expanded_reading(reading, fact_constraints, define_role_names)
         
     | 
| 
      
 201 
     | 
    
         
            +
                  # Find all role numbers in order of occurrence in this reading:
         
     | 
| 
      
 202 
     | 
    
         
            +
                  role_refs = reading.role_sequence.all_role_ref.sort_by{|role_ref| role_ref.ordinal}
         
     | 
| 
      
 203 
     | 
    
         
            +
                  role_numbers = reading.reading_text.scan(/\{(\d)\}/).flatten.map{|m| Integer(m) }
         
     | 
| 
      
 204 
     | 
    
         
            +
                  roles = role_numbers.map{|m| role_refs[m].role }
         
     | 
| 
      
 205 
     | 
    
         
            +
                  # debug "Considering #{reading.reading_text} having #{role_numbers.inspect}"
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                  # Find the constraints that constrain frequency over each role we can verbalise:
         
     | 
| 
      
 208 
     | 
    
         
            +
                  frequency_constraints = []
         
     | 
| 
      
 209 
     | 
    
         
            +
                  roles.each do |role|
         
     | 
| 
      
 210 
     | 
    
         
            +
                    # Find a mandatory constraint that's *not* unique; this will need an extra reading
         
     | 
| 
      
 211 
     | 
    
         
            +
                    role_is_first_in = reading.fact_type.all_reading.detect{|r|
         
     | 
| 
      
 212 
     | 
    
         
            +
                        role == r.role_sequence.all_role_ref.sort_by{|role_ref|
         
     | 
| 
      
 213 
     | 
    
         
            +
                            role_ref.ordinal
         
     | 
| 
      
 214 
     | 
    
         
            +
                          }[0].role
         
     | 
| 
      
 215 
     | 
    
         
            +
                      }
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                    if (role == roles.last)   # First role of the reading?
         
     | 
| 
      
 218 
     | 
    
         
            +
                      # REVISIT: With a ternary, doing this on other than the last role can be ambiguous,
         
     | 
| 
      
 219 
     | 
    
         
            +
                      # in case both the 2nd and 3rd roles have frequencies. Think some more!
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                      constraint = fact_constraints.find{|c|  # Find a UC that spans all other Roles
         
     | 
| 
      
 222 
     | 
    
         
            +
                          # internal uniqueness constraints span all roles but one, the residual:
         
     | 
| 
      
 223 
     | 
    
         
            +
                          PresenceConstraint === c &&
         
     | 
| 
      
 224 
     | 
    
         
            +
                            !@constraints_used[c] &&  # Already verbalised
         
     | 
| 
      
 225 
     | 
    
         
            +
                            roles-c.role_sequence.all_role_ref.map(&:role) == [role]
         
     | 
| 
      
 226 
     | 
    
         
            +
                        }
         
     | 
| 
      
 227 
     | 
    
         
            +
                      # Index the frequency implied by the constraint under the role position in the reading
         
     | 
| 
      
 228 
     | 
    
         
            +
                      if constraint     # Mark this constraint as "verbalised" so we don't do it again:
         
     | 
| 
      
 229 
     | 
    
         
            +
                        @constraints_used[constraint] = true
         
     | 
| 
      
 230 
     | 
    
         
            +
                      end
         
     | 
| 
      
 231 
     | 
    
         
            +
                      frequency_constraints << show_frequency(role, constraint)
         
     | 
| 
      
 232 
     | 
    
         
            +
                    else
         
     | 
| 
      
 233 
     | 
    
         
            +
                      frequency_constraints << show_frequency(role, nil)
         
     | 
| 
      
 234 
     | 
    
         
            +
                    end
         
     | 
| 
      
 235 
     | 
    
         
            +
                  end
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                  expanded = reading.expand(frequency_constraints, define_role_names)
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                  if (ft_rings = @ring_constraints_by_fact[reading.fact_type]) &&
         
     | 
| 
      
 240 
     | 
    
         
            +
                     (ring = ft_rings.detect{|rc| !@constraints_used[rc]})
         
     | 
| 
      
 241 
     | 
    
         
            +
                    @constraints_used[ring] = true
         
     | 
| 
      
 242 
     | 
    
         
            +
                    append_ring_to_reading(expanded, ring)
         
     | 
| 
      
 243 
     | 
    
         
            +
                  end
         
     | 
| 
      
 244 
     | 
    
         
            +
                  expanded
         
     | 
| 
      
 245 
     | 
    
         
            +
                end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                def show_frequency role, constraint
         
     | 
| 
      
 248 
     | 
    
         
            +
                  constraint ? constraint.frequency : nil
         
     | 
| 
      
 249 
     | 
    
         
            +
                end
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                def describe_fact_type(fact_type, highlight = nil)
         
     | 
| 
      
 252 
     | 
    
         
            +
                  (fact_type.entity_type ? fact_type.entity_type.name : "")+
         
     | 
| 
      
 253 
     | 
    
         
            +
                  describe_roles(fact_type.all_role, highlight)
         
     | 
| 
      
 254 
     | 
    
         
            +
                end
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                def describe_roles(roles, highlight = nil)
         
     | 
| 
      
 257 
     | 
    
         
            +
                  "("+
         
     | 
| 
      
 258 
     | 
    
         
            +
                  roles.map{|role| role.concept.name + (role == highlight ? "*" : "")}*", "+
         
     | 
| 
      
 259 
     | 
    
         
            +
                  ")"
         
     | 
| 
      
 260 
     | 
    
         
            +
                end
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
                def describe_role_sequence(role_sequence)
         
     | 
| 
      
 263 
     | 
    
         
            +
                  "("+
         
     | 
| 
      
 264 
     | 
    
         
            +
                  role_sequence.all_role_ref.map{|role_ref| role_ref.role.concept.name }*", "+
         
     | 
| 
      
 265 
     | 
    
         
            +
                  ")"
         
     | 
| 
      
 266 
     | 
    
         
            +
                end
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                # This returns an array of two hash tables each keyed by an EntityType.
         
     | 
| 
      
 269 
     | 
    
         
            +
                # The values of each hash entry are the precursors and followers (respectively) of that entity.
         
     | 
| 
      
 270 
     | 
    
         
            +
                def build_entity_dependencies
         
     | 
| 
      
 271 
     | 
    
         
            +
                  @vocabulary.all_feature.inject([{},{}]) { |a, o|
         
     | 
| 
      
 272 
     | 
    
         
            +
                      if EntityType === o && !o.fact_type
         
     | 
| 
      
 273 
     | 
    
         
            +
                        precursor = a[0]
         
     | 
| 
      
 274 
     | 
    
         
            +
                        follower = a[1]
         
     | 
| 
      
 275 
     | 
    
         
            +
                        blocked = false
         
     | 
| 
      
 276 
     | 
    
         
            +
                        pi = o.preferred_identifier
         
     | 
| 
      
 277 
     | 
    
         
            +
                        if pi
         
     | 
| 
      
 278 
     | 
    
         
            +
                          pi.role_sequence.all_role_ref.each{|rr|
         
     | 
| 
      
 279 
     | 
    
         
            +
                              role = rr.role
         
     | 
| 
      
 280 
     | 
    
         
            +
                              player = role.concept
         
     | 
| 
      
 281 
     | 
    
         
            +
                              next unless EntityType === player
         
     | 
| 
      
 282 
     | 
    
         
            +
                              # player is a precursor of o
         
     | 
| 
      
 283 
     | 
    
         
            +
                              (precursor[o] ||= []) << player if (player != o)
         
     | 
| 
      
 284 
     | 
    
         
            +
                              (follower[player] ||= []) << o if (player != o)
         
     | 
| 
      
 285 
     | 
    
         
            +
                            }
         
     | 
| 
      
 286 
     | 
    
         
            +
                        end
         
     | 
| 
      
 287 
     | 
    
         
            +
                        # Supertypes are precursors too:
         
     | 
| 
      
 288 
     | 
    
         
            +
                        subtyping = o.all_type_inheritance_by_supertype
         
     | 
| 
      
 289 
     | 
    
         
            +
                        next a if subtyping.size == 0
         
     | 
| 
      
 290 
     | 
    
         
            +
                        subtyping.each{|ti|
         
     | 
| 
      
 291 
     | 
    
         
            +
                            # debug ti.class.roles.verbalise; debug "all_type_inheritance_by_supertype"; exit
         
     | 
| 
      
 292 
     | 
    
         
            +
                            s = ti.subtype
         
     | 
| 
      
 293 
     | 
    
         
            +
                            (precursor[s] ||= []) << o
         
     | 
| 
      
 294 
     | 
    
         
            +
                            (follower[o] ||= []) << s
         
     | 
| 
      
 295 
     | 
    
         
            +
                          }
         
     | 
| 
      
 296 
     | 
    
         
            +
                      end
         
     | 
| 
      
 297 
     | 
    
         
            +
                      a
         
     | 
| 
      
 298 
     | 
    
         
            +
                    }
         
     | 
| 
      
 299 
     | 
    
         
            +
                end
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
                # Dump all fact types for which all precursors (of which "o" is one) have been emitted:
         
     | 
| 
      
 302 
     | 
    
         
            +
                def released_fact_types_dump(o)
         
     | 
| 
      
 303 
     | 
    
         
            +
                  roles = o.all_role
         
     | 
| 
      
 304 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 305 
     | 
    
         
            +
                    progress = false
         
     | 
| 
      
 306 
     | 
    
         
            +
                    roles.map(&:fact_type).uniq.select{|fact_type|
         
     | 
| 
      
 307 
     | 
    
         
            +
                        # The fact type hasn't already been dumped but all its role players have
         
     | 
| 
      
 308 
     | 
    
         
            +
                        !@fact_types_dumped[fact_type] &&
         
     | 
| 
      
 309 
     | 
    
         
            +
                          !fact_type.all_role.detect{|r| !@concept_types_dumped[r.concept] }
         
     | 
| 
      
 310 
     | 
    
         
            +
                      }.sort_by{|fact_type|
         
     | 
| 
      
 311 
     | 
    
         
            +
                        fact_type_key(fact_type)
         
     | 
| 
      
 312 
     | 
    
         
            +
                      }.each{|fact_type|
         
     | 
| 
      
 313 
     | 
    
         
            +
                        fact_type_dump_with_dependents(fact_type)
         
     | 
| 
      
 314 
     | 
    
         
            +
                        # Objectified Fact Types may release additional fact types
         
     | 
| 
      
 315 
     | 
    
         
            +
                        roles += fact_type.entity_type.all_role if fact_type.entity_type
         
     | 
| 
      
 316 
     | 
    
         
            +
                        progress = true
         
     | 
| 
      
 317 
     | 
    
         
            +
                      }
         
     | 
| 
      
 318 
     | 
    
         
            +
                  end while progress
         
     | 
| 
      
 319 
     | 
    
         
            +
                end
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
                def skip_fact_type(f)
         
     | 
| 
      
 322 
     | 
    
         
            +
                  # REVISIT: There might be constraints we have to merge into the nested entity or subtype. 
         
     | 
| 
      
 323 
     | 
    
         
            +
                  # These will come up as un-handled constraints:
         
     | 
| 
      
 324 
     | 
    
         
            +
                  pcs = @presence_constraints_by_fact[f]
         
     | 
| 
      
 325 
     | 
    
         
            +
                  TypeInheritance === f ||
         
     | 
| 
      
 326 
     | 
    
         
            +
                    (pcs && pcs.size > 0 && !pcs.detect{|c| !@constraints_used[c] })
         
     | 
| 
      
 327 
     | 
    
         
            +
                end
         
     | 
| 
      
 328 
     | 
    
         
            +
             
     | 
| 
      
 329 
     | 
    
         
            +
                # Dump one fact type.
         
     | 
| 
      
 330 
     | 
    
         
            +
                # Include as many as possible internal constraints in the fact type readings.
         
     | 
| 
      
 331 
     | 
    
         
            +
                def fact_type_dump_with_dependents(fact_type)
         
     | 
| 
      
 332 
     | 
    
         
            +
                  @fact_types_dumped[fact_type] = true
         
     | 
| 
      
 333 
     | 
    
         
            +
                  # debug "Trying to dump FT again" if @fact_types_dumped[fact_type]
         
     | 
| 
      
 334 
     | 
    
         
            +
                  return if skip_fact_type(fact_type)
         
     | 
| 
      
 335 
     | 
    
         
            +
             
     | 
| 
      
 336 
     | 
    
         
            +
                  if (et = fact_type.entity_type) &&
         
     | 
| 
      
 337 
     | 
    
         
            +
                      (pi = et.preferred_identifier) &&
         
     | 
| 
      
 338 
     | 
    
         
            +
                      pi.role_sequence.all_role_ref[0].role.fact_type != fact_type
         
     | 
| 
      
 339 
     | 
    
         
            +
                    # debug "Dumping objectified FT #{et.name} as an entity, non-fact PI"
         
     | 
| 
      
 340 
     | 
    
         
            +
                    entity_type_dump(et)
         
     | 
| 
      
 341 
     | 
    
         
            +
                    released_fact_types_dump(et)
         
     | 
| 
      
 342 
     | 
    
         
            +
                    return
         
     | 
| 
      
 343 
     | 
    
         
            +
                  end
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
                  fact_constraints = @presence_constraints_by_fact[fact_type]
         
     | 
| 
      
 346 
     | 
    
         
            +
             
     | 
| 
      
 347 
     | 
    
         
            +
                  # debug "for fact type #{fact_type.to_s}, considering\n\t#{fact_constraints.map(&:to_s)*",\n\t"}"
         
     | 
| 
      
 348 
     | 
    
         
            +
                  # debug "#{fact_type.name} has readings:\n\t#{fact_type.readings.map(&:name)*"\n\t"}"
         
     | 
| 
      
 349 
     | 
    
         
            +
                  # debug "Dumping #{fact_type.fact_type_id} as a fact type"
         
     | 
| 
      
 350 
     | 
    
         
            +
             
     | 
| 
      
 351 
     | 
    
         
            +
                  # Fact types that aren't nested have no names
         
     | 
| 
      
 352 
     | 
    
         
            +
                  name = fact_type.entity_type && fact_type.entity_type.name
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
                  fact_type_dump(fact_type, name)
         
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
      
 356 
     | 
    
         
            +
                  # REVISIT: Go through the residual constraints and re-process appropriate readings to show them
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
                  @fact_types_dumped[fact_type] = true
         
     | 
| 
      
 359 
     | 
    
         
            +
                  @concept_types_dumped[fact_type.entity_type] = true if fact_type.entity_type
         
     | 
| 
      
 360 
     | 
    
         
            +
                end
         
     | 
| 
      
 361 
     | 
    
         
            +
             
     | 
| 
      
 362 
     | 
    
         
            +
                # Arrange for objectified fact types to appear in order of name, after other fact types.
         
     | 
| 
      
 363 
     | 
    
         
            +
                # Facts are ordered alphabetically by the names of their role players,
         
     | 
| 
      
 364 
     | 
    
         
            +
                # then by preferred_reading (subtyping fact types have no preferred_reading).
         
     | 
| 
      
 365 
     | 
    
         
            +
                def fact_type_key(fact_type)
         
     | 
| 
      
 366 
     | 
    
         
            +
                  role_names =
         
     | 
| 
      
 367 
     | 
    
         
            +
                    if (pr = fact_type.preferred_reading)
         
     | 
| 
      
 368 
     | 
    
         
            +
                      pr.role_sequence.
         
     | 
| 
      
 369 
     | 
    
         
            +
                        all_role_ref.
         
     | 
| 
      
 370 
     | 
    
         
            +
                        sort_by{|role_ref| role_ref.ordinal}.
         
     | 
| 
      
 371 
     | 
    
         
            +
                        map{|role_ref| [ role_ref.leading_adjective, role_ref.role.concept.name, role_ref.trailing_adjective ].compact*"-" } +
         
     | 
| 
      
 372 
     | 
    
         
            +
                        [pr.reading_text]
         
     | 
| 
      
 373 
     | 
    
         
            +
                    else
         
     | 
| 
      
 374 
     | 
    
         
            +
                      fact_type.all_role.map{|role| role.concept.name }
         
     | 
| 
      
 375 
     | 
    
         
            +
                    end
         
     | 
| 
      
 376 
     | 
    
         
            +
             
     | 
| 
      
 377 
     | 
    
         
            +
                  (fact_type.entity_type ? [fact_type.entity_type.name] : [""]) + role_names
         
     | 
| 
      
 378 
     | 
    
         
            +
                end
         
     | 
| 
      
 379 
     | 
    
         
            +
             
     | 
| 
      
 380 
     | 
    
         
            +
                def role_ref_key(role_ref)
         
     | 
| 
      
 381 
     | 
    
         
            +
                  [ role_ref.leading_adjective, role_ref.role.concept.name, role_ref.trailing_adjective ].compact*"-"
         
     | 
| 
      
 382 
     | 
    
         
            +
                end
         
     | 
| 
      
 383 
     | 
    
         
            +
             
     | 
| 
      
 384 
     | 
    
         
            +
                # Dump fact types.
         
     | 
| 
      
 385 
     | 
    
         
            +
                def fact_types_dump
         
     | 
| 
      
 386 
     | 
    
         
            +
                  # REVISIT: Uniqueness on the LHS of a binary can be coded using "distinct"
         
     | 
| 
      
 387 
     | 
    
         
            +
             
     | 
| 
      
 388 
     | 
    
         
            +
                  # The only fact types that can be remaining are those involving only value types,
         
     | 
| 
      
 389 
     | 
    
         
            +
                  # since we dumped every fact type as soon as all relevant entities were dumped.
         
     | 
| 
      
 390 
     | 
    
         
            +
                  # Iterate over all fact types of all value types, looking for these strays.
         
     | 
| 
      
 391 
     | 
    
         
            +
             
     | 
| 
      
 392 
     | 
    
         
            +
                  done_banner = false
         
     | 
| 
      
 393 
     | 
    
         
            +
                  fact_collection = @vocabulary.constellation.FactType
         
     | 
| 
      
 394 
     | 
    
         
            +
                  fact_collection.keys.select{|fact_id|
         
     | 
| 
      
 395 
     | 
    
         
            +
                          fact_type = fact_collection[fact_id]
         
     | 
| 
      
 396 
     | 
    
         
            +
                          !(TypeInheritance === fact_type) and
         
     | 
| 
      
 397 
     | 
    
         
            +
                          !@fact_types_dumped[fact_type] and
         
     | 
| 
      
 398 
     | 
    
         
            +
                          !skip_fact_type(fact_type) and
         
     | 
| 
      
 399 
     | 
    
         
            +
                          !fact_type.all_role.detect{|r| EntityType === r.concept }
         
     | 
| 
      
 400 
     | 
    
         
            +
                      }.sort_by{|fact_id|
         
     | 
| 
      
 401 
     | 
    
         
            +
                          fact_type = fact_collection[fact_id]
         
     | 
| 
      
 402 
     | 
    
         
            +
                          fact_type_key(fact_type)
         
     | 
| 
      
 403 
     | 
    
         
            +
                      }.each{|fact_id|
         
     | 
| 
      
 404 
     | 
    
         
            +
                          fact_type = fact_collection[fact_id]
         
     | 
| 
      
 405 
     | 
    
         
            +
             
     | 
| 
      
 406 
     | 
    
         
            +
                          fact_type_banner unless done_banner
         
     | 
| 
      
 407 
     | 
    
         
            +
                          done_banner = true
         
     | 
| 
      
 408 
     | 
    
         
            +
                          fact_type_dump_with_dependents(fact_type)
         
     | 
| 
      
 409 
     | 
    
         
            +
                    }
         
     | 
| 
      
 410 
     | 
    
         
            +
             
     | 
| 
      
 411 
     | 
    
         
            +
                  # REVISIT: Find out why some fact types are missed during entity dumping:
         
     | 
| 
      
 412 
     | 
    
         
            +
                  @vocabulary.constellation.FactType.values.select{|fact_type|
         
     | 
| 
      
 413 
     | 
    
         
            +
                      !(TypeInheritance === fact_type)
         
     | 
| 
      
 414 
     | 
    
         
            +
                    }.sort_by{|fact_type|
         
     | 
| 
      
 415 
     | 
    
         
            +
                      fact_type_key(fact_type)
         
     | 
| 
      
 416 
     | 
    
         
            +
                    }.each{|fact_type|
         
     | 
| 
      
 417 
     | 
    
         
            +
                      next if @fact_types_dumped[fact_type]
         
     | 
| 
      
 418 
     | 
    
         
            +
                      # debug "Not dumped #{fact_type.verbalise}(#{fact_type.all_role.map{|r| r.concept.name}*", "})"
         
     | 
| 
      
 419 
     | 
    
         
            +
                      fact_type_banner unless done_banner
         
     | 
| 
      
 420 
     | 
    
         
            +
                      done_banner = true
         
     | 
| 
      
 421 
     | 
    
         
            +
                      fact_type_dump_with_dependents(fact_type)
         
     | 
| 
      
 422 
     | 
    
         
            +
                    }
         
     | 
| 
      
 423 
     | 
    
         
            +
             
     | 
| 
      
 424 
     | 
    
         
            +
                  fact_type_end if done_banner
         
     | 
| 
      
 425 
     | 
    
         
            +
                  # unused = constraints - @constraints_used.keys
         
     | 
| 
      
 426 
     | 
    
         
            +
                  # debug "residual constraints are\n\t#{unused.map(&:to_s)*",\n\t"}"
         
     | 
| 
      
 427 
     | 
    
         
            +
             
     | 
| 
      
 428 
     | 
    
         
            +
                  @constraints_used
         
     | 
| 
      
 429 
     | 
    
         
            +
                end
         
     | 
| 
      
 430 
     | 
    
         
            +
             
     | 
| 
      
 431 
     | 
    
         
            +
                def fact_instances_dump
         
     | 
| 
      
 432 
     | 
    
         
            +
                  @vocabulary.fact_types.each{|f|
         
     | 
| 
      
 433 
     | 
    
         
            +
                      # Dump the instances:
         
     | 
| 
      
 434 
     | 
    
         
            +
                      f.facts.each{|i|
         
     | 
| 
      
 435 
     | 
    
         
            +
                        raise "REVISIT: Not dumping fact instances"
         
     | 
| 
      
 436 
     | 
    
         
            +
                        debug "\t\t"+i.to_s
         
     | 
| 
      
 437 
     | 
    
         
            +
                      }
         
     | 
| 
      
 438 
     | 
    
         
            +
                  }
         
     | 
| 
      
 439 
     | 
    
         
            +
                end
         
     | 
| 
      
 440 
     | 
    
         
            +
             
     | 
| 
      
 441 
     | 
    
         
            +
                def constraint_sort_key(c)
         
     | 
| 
      
 442 
     | 
    
         
            +
                  case c
         
     | 
| 
      
 443 
     | 
    
         
            +
                  when RingConstraint
         
     | 
| 
      
 444 
     | 
    
         
            +
                    [1, c.ring_type, c.role.concept.name, c.other_role.concept.name, c.name||""]
         
     | 
| 
      
 445 
     | 
    
         
            +
                  when SetComparisonConstraint
         
     | 
| 
      
 446 
     | 
    
         
            +
                    [2, c.all_set_comparison_roles.map{|scrs| scrs.role_sequence.all_role_ref.map{|rr| role_ref_key(rr)}}, c.name||""]
         
     | 
| 
      
 447 
     | 
    
         
            +
                  when SubsetConstraint
         
     | 
| 
      
 448 
     | 
    
         
            +
                    [3, [c.superset_role_sequence, c.subset_role_sequence].map{|rs| rs.all_role_ref.map{|rr| role_ref_key(rr)}}, c.name||""]
         
     | 
| 
      
 449 
     | 
    
         
            +
                  when PresenceConstraint
         
     | 
| 
      
 450 
     | 
    
         
            +
                    [4, c.role_sequence.all_role_ref.map{|rr| role_ref_key(rr)}, c.name||""]
         
     | 
| 
      
 451 
     | 
    
         
            +
                  end
         
     | 
| 
      
 452 
     | 
    
         
            +
                end
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
                def constraints_dump(except = {})
         
     | 
| 
      
 455 
     | 
    
         
            +
                  heading = false
         
     | 
| 
      
 456 
     | 
    
         
            +
                  @vocabulary.all_constraint.reject{|c| except[c]}.sort_by{ |c| constraint_sort_key(c) }.each do|c|
         
     | 
| 
      
 457 
     | 
    
         
            +
                    # Skip some PresenceConstraints:
         
     | 
| 
      
 458 
     | 
    
         
            +
                    if PresenceConstraint === c
         
     | 
| 
      
 459 
     | 
    
         
            +
                      # Skip uniqueness constraints that cover all roles of a fact type, they're implicit
         
     | 
| 
      
 460 
     | 
    
         
            +
                      role_refs = c.role_sequence.all_role_ref
         
     | 
| 
      
 461 
     | 
    
         
            +
                      if role_refs.size == 0
         
     | 
| 
      
 462 
     | 
    
         
            +
                        constraint_banner unless heading
         
     | 
| 
      
 463 
     | 
    
         
            +
                        heading = true
         
     | 
| 
      
 464 
     | 
    
         
            +
                        puts "PresenceConstraint without roles!" 
         
     | 
| 
      
 465 
     | 
    
         
            +
                        next
         
     | 
| 
      
 466 
     | 
    
         
            +
                      end
         
     | 
| 
      
 467 
     | 
    
         
            +
                      fact_type0 = role_refs[0].role.fact_type
         
     | 
| 
      
 468 
     | 
    
         
            +
                      next if c.max_frequency == 1 &&         # Uniqueness
         
     | 
| 
      
 469 
     | 
    
         
            +
                        role_refs.size == fact_type0.all_role.size &&     # Same number of roles
         
     | 
| 
      
 470 
     | 
    
         
            +
                        fact_type0.all_role.all?{|r| role_refs.map(&:role).include? r}    # All present
         
     | 
| 
      
 471 
     | 
    
         
            +
             
     | 
| 
      
 472 
     | 
    
         
            +
                      # Skip internal PresenceConstraints over TypeInheritances:
         
     | 
| 
      
 473 
     | 
    
         
            +
                      next if TypeInheritance === fact_type0 &&
         
     | 
| 
      
 474 
     | 
    
         
            +
                        !c.role_sequence.all_role_ref.detect{|rr| rr.role.fact_type != fact_type0 }
         
     | 
| 
      
 475 
     | 
    
         
            +
                    end
         
     | 
| 
      
 476 
     | 
    
         
            +
             
     | 
| 
      
 477 
     | 
    
         
            +
                    constraint_banner unless heading
         
     | 
| 
      
 478 
     | 
    
         
            +
                    heading = true
         
     | 
| 
      
 479 
     | 
    
         
            +
             
     | 
| 
      
 480 
     | 
    
         
            +
                    # Skip presence constraints on value types:
         
     | 
| 
      
 481 
     | 
    
         
            +
                    # next if ActiveFacts::PresenceConstraint === c &&
         
     | 
| 
      
 482 
     | 
    
         
            +
                    #     ActiveFacts::ValueType === c.concept
         
     | 
| 
      
 483 
     | 
    
         
            +
                    constraint_dump(c)
         
     | 
| 
      
 484 
     | 
    
         
            +
                  end
         
     | 
| 
      
 485 
     | 
    
         
            +
                  constraint_end if heading
         
     | 
| 
      
 486 
     | 
    
         
            +
                end
         
     | 
| 
      
 487 
     | 
    
         
            +
             
     | 
| 
      
 488 
     | 
    
         
            +
                def vocabulary_start(vocabulary)
         
     | 
| 
      
 489 
     | 
    
         
            +
                  debug "Should override vocabulary_start"
         
     | 
| 
      
 490 
     | 
    
         
            +
                end
         
     | 
| 
      
 491 
     | 
    
         
            +
             
     | 
| 
      
 492 
     | 
    
         
            +
                def vocabulary_end
         
     | 
| 
      
 493 
     | 
    
         
            +
                  debug "Should override vocabulary_end"
         
     | 
| 
      
 494 
     | 
    
         
            +
                end
         
     | 
| 
      
 495 
     | 
    
         
            +
             
     | 
| 
      
 496 
     | 
    
         
            +
                def value_type_banner
         
     | 
| 
      
 497 
     | 
    
         
            +
                  debug "Should override value_type_banner"
         
     | 
| 
      
 498 
     | 
    
         
            +
                end
         
     | 
| 
      
 499 
     | 
    
         
            +
             
     | 
| 
      
 500 
     | 
    
         
            +
                def value_type_end
         
     | 
| 
      
 501 
     | 
    
         
            +
                  debug "Should override value_type_end"
         
     | 
| 
      
 502 
     | 
    
         
            +
                end
         
     | 
| 
      
 503 
     | 
    
         
            +
             
     | 
| 
      
 504 
     | 
    
         
            +
                def value_type_dump(o)
         
     | 
| 
      
 505 
     | 
    
         
            +
                  debug "Should override value_type_dump"
         
     | 
| 
      
 506 
     | 
    
         
            +
                end
         
     | 
| 
      
 507 
     | 
    
         
            +
             
     | 
| 
      
 508 
     | 
    
         
            +
                def entity_type_banner
         
     | 
| 
      
 509 
     | 
    
         
            +
                  debug "Should override entity_type_banner"
         
     | 
| 
      
 510 
     | 
    
         
            +
                end
         
     | 
| 
      
 511 
     | 
    
         
            +
             
     | 
| 
      
 512 
     | 
    
         
            +
                def entity_type_group_end
         
     | 
| 
      
 513 
     | 
    
         
            +
                  debug "Should override entity_type_group_end"
         
     | 
| 
      
 514 
     | 
    
         
            +
                end
         
     | 
| 
      
 515 
     | 
    
         
            +
             
     | 
| 
      
 516 
     | 
    
         
            +
                def non_subtype_dump(o, pi)
         
     | 
| 
      
 517 
     | 
    
         
            +
                  debug "Should override non_subtype_dump"
         
     | 
| 
      
 518 
     | 
    
         
            +
                end
         
     | 
| 
      
 519 
     | 
    
         
            +
             
     | 
| 
      
 520 
     | 
    
         
            +
                def subtype_dump(o, supertypes, pi = nil)
         
     | 
| 
      
 521 
     | 
    
         
            +
                  debug "Should override subtype_dump"
         
     | 
| 
      
 522 
     | 
    
         
            +
                end
         
     | 
| 
      
 523 
     | 
    
         
            +
             
     | 
| 
      
 524 
     | 
    
         
            +
                def append_ring_to_reading(reading, ring)
         
     | 
| 
      
 525 
     | 
    
         
            +
                  debug "Should override append_ring_to_reading"
         
     | 
| 
      
 526 
     | 
    
         
            +
                end
         
     | 
| 
      
 527 
     | 
    
         
            +
             
     | 
| 
      
 528 
     | 
    
         
            +
                def fact_type_banner
         
     | 
| 
      
 529 
     | 
    
         
            +
                  debug "Should override fact_type_banner"
         
     | 
| 
      
 530 
     | 
    
         
            +
                end
         
     | 
| 
      
 531 
     | 
    
         
            +
             
     | 
| 
      
 532 
     | 
    
         
            +
                def fact_type_end
         
     | 
| 
      
 533 
     | 
    
         
            +
                  debug "Should override fact_type_end"
         
     | 
| 
      
 534 
     | 
    
         
            +
                end
         
     | 
| 
      
 535 
     | 
    
         
            +
             
     | 
| 
      
 536 
     | 
    
         
            +
                def fact_type_dump(fact_type, name)
         
     | 
| 
      
 537 
     | 
    
         
            +
                  debug "Should override fact_type_dump"
         
     | 
| 
      
 538 
     | 
    
         
            +
                end
         
     | 
| 
      
 539 
     | 
    
         
            +
             
     | 
| 
      
 540 
     | 
    
         
            +
                def constraint_banner
         
     | 
| 
      
 541 
     | 
    
         
            +
                  debug "Should override constraint_banner"
         
     | 
| 
      
 542 
     | 
    
         
            +
                end
         
     | 
| 
      
 543 
     | 
    
         
            +
             
     | 
| 
      
 544 
     | 
    
         
            +
                def constraint_end
         
     | 
| 
      
 545 
     | 
    
         
            +
                  debug "Should override constraint_end"
         
     | 
| 
      
 546 
     | 
    
         
            +
                end
         
     | 
| 
      
 547 
     | 
    
         
            +
             
     | 
| 
      
 548 
     | 
    
         
            +
                def constraint_dump(c)
         
     | 
| 
      
 549 
     | 
    
         
            +
                  debug "Should override constraint_dump"
         
     | 
| 
      
 550 
     | 
    
         
            +
                end
         
     | 
| 
      
 551 
     | 
    
         
            +
             
     | 
| 
      
 552 
     | 
    
         
            +
              end
         
     | 
| 
      
 553 
     | 
    
         
            +
             
     | 
| 
      
 554 
     | 
    
         
            +
              def dump(vocabulary, out = $>)
         
     | 
| 
      
 555 
     | 
    
         
            +
                OrderedDumper.new(vocabulary).dump(out)
         
     | 
| 
      
 556 
     | 
    
         
            +
              end
         
     | 
| 
      
 557 
     | 
    
         
            +
            end
         
     |