<commit_before>class Taxon < ActiveRecord::Base
  # Sometimes you don't want to make a new taxon name with a taxon, like when
  # you're saving a new taxon name with a new associated taxon. Hence, this.
  attr_accessor :skip_new_taxon_name
  
  # If you want to shove some HTML in there before creating some JSON...
  attr_accessor :html
  
  acts_as_flaggable
  has_ancestry
  
  has_many :child_taxa, :class_name => Taxon.to_s, :foreign_key => :parent_id
  has_many :taxon_names, :dependent => :destroy
  has_many :observations, :dependent => :nullify
  has_many :listed_taxa, :dependent => :destroy
  has_many :lists, :through => :listed_taxa
  has_many :places, :through => :listed_taxa
  has_many :identifications, :dependent => :destroy
  has_many :taxon_links, :dependent => :destroy 
  belongs_to :source
  belongs_to :iconic_taxon, :class_name => 'Taxon', 
                            :foreign_key => 'iconic_taxon_id'
  belongs_to :creator, :class_name => 'User'
  belongs_to :updater, :class_name => 'User'
  has_many :taxon_photos, :dependent => :destroy
  has_many :photos, :through => :taxon_photos
  has_and_belongs_to_many :colors
  
  define_index do
    indexes :name
    indexes taxon_names.name, :as => :names
    indexes colors.value, :as => :color_values
    has iconic_taxon_id, :facet => true, :type => :integer
    has colors(:id), :as => :colors, :facet => true, :type => :multi
    has listed_taxa(:place_id), :as => :places, :facet => true, :type => :multi
    has listed_taxa(:list_id), :as => :lists, :type => :multi
    has created_at, ancestry
    has "REPLACE(ancestry, '/', ',')", :as => :ancestors, :type => :multi
    set_property :delta => :delayed
  end
  
  before_validation :normalize_rank, :set_rank_level, :remove_rank_from_name
  before_save :set_iconic_taxon, # if after, it would require an extra save
              :capitalize_name
  after_save :create_matching_taxon_name,
             :set_wikipedia_summary_later,
             :handle_after_move
  
  validates_presence_of :name, :rank
  validates_uniqueness_of :name, 
                          :scope => [:parent_id],
                          :unless => Proc.new { |taxon| taxon.parent_id.nil? },
                          :message => "already used as a child of this " + 
                                      "taxon's parent"
  
  NAME_PROVIDER_TITLES = {
    'ColNameProvider' => 'Catalogue of Life',
    'UBioNameProvider' => 'uBio'
  }
  
  RANK_LEVELS = {
    'root'         => 100,
    'kingdom'      => 70,
    'phylum'       => 60,
    'subphylum'    => 57,
    'superclass'   => 53,
    'class'        => 50,
    'subclass'     => 47,
    'superorder'   => 43,
    'order'        => 40,
    'suborder'     => 37,
    'superfamily'  => 33,
    'family'       => 30,
    'subfamily'    => 27,
    'supertribe'   => 26,
    'tribe'        => 25,
    'subtribe'     => 24,
    'genus'        => 20,
    'species'      => 10,
    'subspecies'   => 5,
    'variety'      => 5,
    'form'         => 5
  }
  
  RANKS = RANK_LEVELS.keys
  
  RANK_EQUIVALENTS = {
    'division'        => 'phylum',
    'sub-class'       => 'subclass',
    'super-order'     => 'superorder',
    'infraorder'      => 'suborder',
    'sub-order'       => 'suborder',
    'super-family'    => 'superfamily',
    'sub-family'      => 'subfamily',
    'gen'             => 'genus',
    'sp'              => 'species',
    'infraspecies'    => 'subspecies',
    'ssp'             => 'subspecies',
    'sub-species'     => 'subspecies',
    'subsp'           => 'subspecies',
    'trinomial'       => 'subspecies',
    'var'             => 'variety',
    'unranked'        => nil
  }
  
  PREFERRED_RANKS = [
    'kingdom',
    'phylum',
    'class',
    'order',
    'superfamily',
    'family',
    'genus',
    'species',
    'subspecies',
    'variety'
  ]
  
  # In case you don't feel like looking up TaxonNames
  ICONIC_TAXON_NAMES = {
    'Animalia' => 'Animals',
    'Actinopterygii' => 'Ray-finned Fishes',
    'Aves' => 'Birds',
    'Reptilia' => 'Reptiles',
    'Amphibia' => 'Amphibians',
    'Mammalia' => 'Mammals',
    'Arachnida' => 'Arachnids',
    'Insecta' => 'Insects',
    'Plantae' => 'Plants',
    'Fungi' => 'Fungi',
    'Protozoa' => 'Protozoans',
    'Mollusca' => 'Mollusks'
  }
  
  ICONIC_TAXON_DISPLAY_NAMES = ICONIC_TAXON_NAMES.merge(
    'Animalia' => 'Other Animals'
  )
  
  named_scope :observed_by, lambda {|user|
    { :joins => """
      JOIN (
        SELECT
          taxon_id
        FROM
          observations
        WHERE
          user_id=#{user.id}
        GROUP BY taxon_id
      ) o
      ON o.taxon_id=#{Taxon.table_name}.#{Taxon.primary_key}
      """ }}
  
  named_scope :iconic_taxa, :conditions => "is_iconic = true",
    :include => [:taxon_names]
  
  named_scope :of_rank, lambda {|rank|
    {:conditions => ["rank = ?", rank]}
  }
  
  ICONIC_TAXA = Taxon.sort_by_ancestry(self.iconic_taxa.arrange)
  ICONIC_TAXA_BY_ID = ICONIC_TAXA.index_by(&:id)
  
  
  # Callbacks ###############################################################
  
  def handle_after_move
    if ancestry_changed?
      update_listed_taxa
      handle_after_move
      update_life_lists
      update_obs_iconic_taxa
      set_iconic_taxon
    end
    true
  end
  
  def normalize_rank
    self.rank = Taxon.normalize_rank(self.rank)
    true
  end
  
  def set_rank_level
    self.rank_level = RANK_LEVELS[self.rank]<commit_msg>Fixed inf loop when moving taxa.<commit_after>class Taxon < ActiveRecord::Base
  # Sometimes you don't want to make a new taxon name with a taxon, like when
  # you're saving a new taxon name with a new associated taxon. Hence, this.
  attr_accessor :skip_new_taxon_name
  
  # If you want to shove some HTML in there before creating some JSON...
  attr_accessor :html
  
  acts_as_flaggable
  has_ancestry
  
  has_many :child_taxa, :class_name => Taxon.to_s, :foreign_key => :parent_id
  has_many :taxon_names, :dependent => :destroy
  has_many :observations, :dependent => :nullify
  has_many :listed_taxa, :dependent => :destroy
  has_many :lists, :through => :listed_taxa
  has_many :places, :through => :listed_taxa
  has_many :identifications, :dependent => :destroy
  has_many :taxon_links, :dependent => :destroy 
  belongs_to :source
  belongs_to :iconic_taxon, :class_name => 'Taxon', 
                            :foreign_key => 'iconic_taxon_id'
  belongs_to :creator, :class_name => 'User'
  belongs_to :updater, :class_name => 'User'
  has_many :taxon_photos, :dependent => :destroy
  has_many :photos, :through => :taxon_photos
  has_and_belongs_to_many :colors
  
  define_index do
    indexes :name
    indexes taxon_names.name, :as => :names
    indexes colors.value, :as => :color_values
    has iconic_taxon_id, :facet => true, :type => :integer
    has colors(:id), :as => :colors, :facet => true, :type => :multi
    has listed_taxa(:place_id), :as => :places, :facet => true, :type => :multi
    has listed_taxa(:list_id), :as => :lists, :type => :multi
    has created_at, ancestry
    has "REPLACE(ancestry, '/', ',')", :as => :ancestors, :type => :multi
    set_property :delta => :delayed
  end
  
  before_validation :normalize_rank, :set_rank_level, :remove_rank_from_name
  before_save :set_iconic_taxon, # if after, it would require an extra save
              :capitalize_name
  after_save :create_matching_taxon_name,
             :set_wikipedia_summary_later,
             :handle_after_move
  
  validates_presence_of :name, :rank
  validates_uniqueness_of :name, 
                          :scope => [:parent_id],
                          :unless => Proc.new { |taxon| taxon.parent_id.nil? },
                          :message => "already used as a child of this " + 
                                      "taxon's parent"
  
  NAME_PROVIDER_TITLES = {
    'ColNameProvider' => 'Catalogue of Life',
    'UBioNameProvider' => 'uBio'
  }
  
  RANK_LEVELS = {
    'root'         => 100,
    'kingdom'      => 70,
    'phylum'       => 60,
    'subphylum'    => 57,
    'superclass'   => 53,
    'class'        => 50,
    'subclass'     => 47,
    'superorder'   => 43,
    'order'        => 40,
    'suborder'     => 37,
    'superfamily'  => 33,
    'family'       => 30,
    'subfamily'    => 27,
    'supertribe'   => 26,
    'tribe'        => 25,
    'subtribe'     => 24,
    'genus'        => 20,
    'species'      => 10,
    'subspecies'   => 5,
    'variety'      => 5,
    'form'         => 5
  }
  
  RANKS = RANK_LEVELS.keys
  
  RANK_EQUIVALENTS = {
    'division'        => 'phylum',
    'sub-class'       => 'subclass',
    'super-order'     => 'superorder',
    'infraorder'      => 'suborder',
    'sub-order'       => 'suborder',
    'super-family'    => 'superfamily',
    'sub-family'      => 'subfamily',
    'gen'             => 'genus',
    'sp'              => 'species',
    'infraspecies'    => 'subspecies',
    'ssp'             => 'subspecies',
    'sub-species'     => 'subspecies',
    'subsp'           => 'subspecies',
    'trinomial'       => 'subspecies',
    'var'             => 'variety',
    'unranked'        => nil
  }
  
  PREFERRED_RANKS = [
    'kingdom',
    'phylum',
    'class',
    'order',
    'superfamily',
    'family',
    'genus',
    'species',
    'subspecies',
    'variety'
  ]
  
  # In case you don't feel like looking up TaxonNames
  ICONIC_TAXON_NAMES = {
    'Animalia' => 'Animals',
    'Actinopterygii' => 'Ray-finned Fishes',
    'Aves' => 'Birds',
    'Reptilia' => 'Reptiles',
    'Amphibia' => 'Amphibians',
    'Mammalia' => 'Mammals',
    'Arachnida' => 'Arachnids',
    'Insecta' => 'Insects',
    'Plantae' => 'Plants',
    'Fungi' => 'Fungi',
    'Protozoa' => 'Protozoans',
    'Mollusca' => 'Mollusks'
  }
  
  ICONIC_TAXON_DISPLAY_NAMES = ICONIC_TAXON_NAMES.merge(
    'Animalia' => 'Other Animals'
  )
  
  named_scope :observed_by, lambda {|user|
    { :joins => """
      JOIN (
        SELECT
          taxon_id
        FROM
          observations
        WHERE
          user_id=#{user.id}
        GROUP BY taxon_id
      ) o
      ON o.taxon_id=#{Taxon.table_name}.#{Taxon.primary_key}
      """ }}
  
  named_scope :iconic_taxa, :conditions => "is_iconic = true",
    :include => [:taxon_names]
  
  named_scope :of_rank, lambda {|rank|
    {:conditions => ["rank = ?", rank]}
  }
  
  ICONIC_TAXA = Taxon.sort_by_ancestry(self.iconic_taxa.arrange)
  ICONIC_TAXA_BY_ID = ICONIC_TAXA.index_by(&:id)
  
  
  # Callbacks ###############################################################
  
  def handle_after_move
    if ancestry_changed?
      update_listed_taxa
      update_life_lists
      update_obs_iconic_taxa
      set_iconic_taxon
    end
    true
  end
  
  def normalize_rank
    self.rank = Taxon.normalize_rank(self.rank)
    true
  end
  
  def set_rank_level
    self.rank_level = RANK_LEVELS[self.rank]
{'fraction_non_alphanumeric': 0.1450381679389313, 'fraction_numerical': 0.007357674974707992, 'mean_word_length': 2.432449494949495, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 181, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5141343', 'n_tokens_mistral': 4083, 'n_tokens_neox': 3895, 'n_words': 799}