class ActiveFacts::Metamodel::ObjectType

Public Instance Methods

add_surrogate(type_name = 'Auto Counter', suffix = 'ID') click to toggle source
# File lib/activefacts/generators/transform/surrogate.rb, line 15
def add_surrogate type_name = 'Auto Counter', suffix = 'ID'
  # Find or assert the surrogate value type
  auto_counter = vocabulary.valid_value_type_name(type_name) ||
    constellation.ValueType(:vocabulary => vocabulary, :name => type_name, :concept => [:new, :implication_rule => 'Surrogate key transform'])

  # Create a subtype to identify this entity type:
  vt_name = self.name + ' '+suffix
  my_id = @vocabulary.valid_value_type_name(vt_name) ||
    constellation.ValueType(:vocabulary => vocabulary, :name => vt_name, :concept => :new, :supertype => auto_counter)

  # Create a fact type
  identifying_fact_type = constellation.FactType(:concept => :new)
  my_role = constellation.Role(:concept => :new, :fact_type => identifying_fact_type, :ordinal => 0, :object_type => self)
  @injected_surrogate_role = my_role
  id_role = constellation.Role(:concept => :new, :fact_type => identifying_fact_type, :ordinal => 1, :object_type => my_id)

  # Create a reading (which needs a RoleSequence)
  reading = constellation.Reading(
    :fact_type => identifying_fact_type,
    :ordinal => 0,
    :role_sequence => [:new],
    :text => "{0} has {1}"
  )
  constellation.RoleRef(:role_sequence => reading.role_sequence, :ordinal => 0, :role => my_role)
  constellation.RoleRef(:role_sequence => reading.role_sequence, :ordinal => 1, :role => id_role)

  # Create two uniqueness constraints for the one-to-one. Each needs a RoleSequence (two RoleRefs)
  one_id = constellation.PresenceConstraint(
      :concept => :new,
      :vocabulary => vocabulary,
      :name => self.name+'HasOne'+suffix,
      :role_sequence => [:new],
      :is_mandatory => true,
      :min_frequency => 1,
      :max_frequency => 1,
      :is_preferred_identifier => false
    )
  @constellation.RoleRef(:role_sequence => one_id.role_sequence, :ordinal => 0, :role => my_role)

  one_me = constellation.PresenceConstraint(
      :concept => :new,
      :vocabulary => vocabulary,
      :name => self.name+suffix+'IsOfOne'+self.name,
      :role_sequence => [:new],
      :is_mandatory => false,
      :min_frequency => 0,
      :max_frequency => 1,
      :is_preferred_identifier => true
    )
  @constellation.RoleRef(:role_sequence => one_me.role_sequence, :ordinal => 0, :role => id_role)
end
as_json_metadata() click to toggle source
# File lib/activefacts/generators/metadata/json.rb, line 55
def as_json_metadata
  # Using proc avoids polluting the object's namespace with these little methods
  verbalise_role = proc do |role, plural|
    fc = Array.new(role.fact_type.all_role.size, plural ? 'some' : 'one')
    reading = role.fact_type.reading_preferably_starting_with_role(role)
    fc.reverse! unless reading.role_sequence.all_role_ref.to_a[0].role == role
    fc[reading.role_sequence.all_role_ref_in_order.to_a.index{|rr| rr.role == role}] = 'this'
    reading.expand(fc, false)
  end

  titlize_words = proc do |phrase|
    phrase && phrase.split(/\s+/).map{|w| w.sub(/^[a-z]/) {|i| i.upcase}}*' '
  end

  role_name = proc do |role|
    if role.role_name
      role.role_name
    else
      ref = role.preferred_reference
      [ titlize_words.call(ref.leading_adjective), role.object_type.name, titlize_words.call(ref.trailing_adjective)].compact*' '
    end
  end

  return nil if name == '_ImplicitBooleanValueType'

  object_type = {}
  object_type["is_main"] = is_table
  object_type["id"] = concept.guid.to_s
  functions = object_type["functions"] = []

  if is_a?(ActiveFacts::Metamodel::EntityType)

    # Don't emit a binary objectified fact type that plays no roles (except in implicit fact types:
    if fact_type and fact_type.all_role.size == 2 and all_role.size == 2
      return nil
    end

    # Export the supertypes
    (supertypes_transitive-[self]).sort_by{|t| t.name}.each do |supertype|
      functions <<
        {
          "title" => "as #{supertype.name}",
          "type" => "#{supertype.name}"
        }
    end

    # Export the subtypes
    (subtypes_transitive-[self]).sort_by{|t| t.name}.each do |subtype|
      functions <<
        {
          "title" => "as #{subtype.name}",
          "type" => "#{subtype.name}"
        }
    end

    # If an objectified fact type, export the fact type's roles
    if fact_type
      fact_type.preferred_reading.role_sequence.all_role_ref_in_order.map(&:role).each do |role|
        functions <<
          {
            "title" => "involving #{role_name.call(role)}",
            "type" => "#{role.object_type.name}",
            "where" => verbalise_role.call(role, true)  # REVISIT: Need plural setting here!
          }
      end
    end
  end

  # Now export the ordinary roles. Get a sorted list first:
  roles = all_role.reject do |role|
      # supertype and subtype roles get handled separately
      role.fact_type.is_a?(ActiveFacts::Metamodel::TypeInheritance) ||
        role.fact_type.is_a?(ActiveFacts::Metamodel::LinkFactType)
    end.sort_by do |role|
      # Where this object type plays two roles in the same fact type,
      # we order them by the position of that role in the preferred reading:
      [role.fact_type.default_reading, role.fact_type.preferred_reading.role_sequence.all_role_ref_in_order.map(&:role).index(role)]
    end

  # For binary fact types, collect the count of the times the unadorned counterpart role name occurs, so we can adorn it
  plural_counterpart_counts = roles.inject(Hash.new{0}) do |h, role|
    next h unless role.fact_type.all_role.size == 2
    uc = role.all_role_ref.detect do |rr|
        rs = rr.role_sequence
        next false if rs.all_role_ref.size != 1   # Looking for a UC over just this one role
        rs.all_presence_constraint.detect do |pc|
            next false unless pc.max_frequency == 1   # It's a uniqueness constraint
            true
          end
      end
    next h if uc  # Not a plural role

    counterpart_role = (role.fact_type.all_role.to_a - [role])[0]
    h[role_name.call(counterpart_role)] += 1
    h
  end

  roles.each do |role|
    type_name = nil
    counterpart_name = nil

    if role.fact_type.entity_type and           # Role is in an objectified fact type
      # For binary objectified fact types, we traverse directly to the other role, not just to the objectification
      !(role.fact_type.entity_type.all_role.size == 2 and role.fact_type.all_role.size == 2)

      type_name = role.fact_type.entity_type.name
      counterpart_name = type_name          # If self plays more than one role in OFT, need to construct a role name
      plural = true
    elsif role.fact_type.all_role.size == 1
      # Handle unary roles
      type_name = 'boolean'
      counterpart_name = role.fact_type.default_reading
      plural = false
    else
      # Handle binary roles
      counterpart_role = (role.fact_type.all_role.to_a - [role])[0]
      type_name = counterpart_role.object_type.name
      counterpart_name = role_name.call(counterpart_role)
      # Figure out whether the counterpart is plural (say "all ..." if so)
      uc = role.all_role_ref.detect do |rr|
          rs = rr.role_sequence
          next false if rs.all_role_ref.size != 1   # Looking for a UC over just this one role
          rs.all_presence_constraint.detect do |pc|
              next false unless pc.max_frequency == 1   # It's a uniqueness constraint
              true
            end
        end
      plural = !uc
      if plural_counterpart_counts[counterpart_name] > 1
        counterpart_name += " as " + role_name.call(role)
      end
    end

    node = {
      "title" => "#{plural ? 'all ' : ''}#{counterpart_name}",
      "type" => "#{type_name}",
      "where" => verbalise_role.call(role, plural),
      "role_id" => role.concept.guid.to_s
    }
    node["is_list"] = true if plural
    functions << node 

  end
  functions.size > 0 ? object_type : nil
end
rails_class_name() click to toggle source
# File lib/activefacts/generators/traits/rails.rb, line 127
def rails_class_name
  ActiveSupport::Inflector.camelize(name.gsub(/\s+/, '_'))
end
rails_name() click to toggle source
# File lib/activefacts/generators/traits/rails.rb, line 119
def rails_name
  RMap::rails_plural_name(name)
end
rails_singular_name() click to toggle source
# File lib/activefacts/generators/traits/rails.rb, line 123
def rails_singular_name
  RMap::rails_singular_name(name)
end