<commit_before># == Schema Information
# Schema version: 20090727140821
#
# Table name: package
#
#  id                  :integer         not null, primary key
#  name                :string(255)
#  description         :text
#  created_at          :datetime
#  latest_version_id   :integer
#  updated_at          :datetime
#  package_users_count :integer         default(0), not null
#

class Package < ActiveRecord::Base
  include NoFuzz
  fuzzy :name

  after_create :create_trigrams # Incrementally update the trigram index

  has_many :versions, :order => "id DESC", :dependent => :destroy
  has_many :package_ratings, :dependent => :destroy
  has_many :package_users, :dependent => :destroy
  has_many :reviews, :dependent => :destroy
  has_many :taggings, :dependent => :destroy
  has_many :tags, :through => :taggings, :uniq => true do
    # @param [String, Class] type E.g. Priority or TaskView
    def type(type)
      proxy_owner.tags.all(:conditions => ["type = ?", type.to_s])
    end
  end

  # We cache the latest version id
  belongs_to :latest_version, :class_name => "Version"
  alias :latest :latest_version

  fires :new_package, :on                => :create,
                      :subject           => :self,
                      :secondary_subject => :self # yes 2x package

  # Uncommented until Rails handles named scope order in a better way
  # default_scope :order => "LOWER(package.name)"

  named_scope :recent, :order => "#{self.table_name}.created_at DESC",
                       :include => :latest_version,
                       :conditions => "#{self.table_name}.created_at IS NOT NULL",
                       :limit => 50

  validates_presence_of :name
  validates_uniqueness_of :name
  validates_length_of :name, :in => 2..255

  # We can't validate the presence of a latest_version_id here, since we
  # create packages before versions are associated. In conclusion, we have
  # to be careful and ideally use transactions when creating packages to avoid
  # inconsistent data in the database.

  def self.find_by_param(id)
    self.find_by_name(id.gsub("-", ".")) or raise ActiveRecord::RecordNotFound
  end

  ## No. of packages to show per page.
  def self.per_page; 50; end

  ## Search On Name of Package.
  def self.paginating_search(q, search_results_page)
    q.strip.downcase!

    if q.ends_with? '~' # fuzzy search
      # TODO It's kinda bad to do two database hits here, I think it can be resolved
      # by using paginate's :finder argument and creating a new method that
      # calls out to fuzzy_find.
      ids = Package.fuzzy_find(q[0...-1], per_page).collect { |i| i.id }
      [paginate(ids,
               {:include => {:versions => :maintainer},
               :page => search_results_page}), "fuzzy"]
    else
      res = paginate({ :conditions => [ 'LOWER(package.name) LIKE ?', '%' + q + '%'],
                       :include => [{:latest_version => :maintainer}],
                       :order => 'LOWER(package.name)',
                       :page => search_results_page })
      res.empty? ? self.paginating_search(q + '~', search_results_page) : [res]
    end
  end

  def self.search(q, limit=self.per_page)
    extra = { :include => :latest_version }
    res = []
    if q.ends_with? '~' # fuzzy search
      res = [Package.fuzzy_find(q[0...-1], limit, extra), "fuzzy"]
    else
      qq = '%' + q + '%'
      res = [Package.all(:conditions =>
                         ['LOWER(package.name) LIKE ? OR LOWER(version.description) LIKE ?', qq, qq],
                         :order => "LOWER(package.name)",
                         :limit => limit, :include => :latest_version)]
      if res.first.empty?
        # Try a fuzzy search if no results were found
        res = [Package.fuzzy_find(q, limit, extra), "fuzzy"]
      end
    end
    res
  end

  def <=>(other)
    self.name.downcase <=> other.name.downcase
  end

  # If updated_at is nil (which is the case for some older records), return
  # created_at as the value for updated_at. This is required because e.g. the
  # sitemap relies on proper updated_at values.
  def updated_at
    super || self.created_at
  end

  def description
    self.latest_version.description # for convenience
  end

  # @return [Fixnum] Number of ratings for this package for the given aspect
  def rating_count(aspect="overall")
    PackageRating.count(:conditions => ["package_id = ? AND aspect = ?",
                                        self.id, aspect])
  end

  # Rounded average rating for this package
  def average_rating(aspect="overall")
    PackageRating.calculate_average(self, aspect)
  end

  def to_param
    name.gsub(".", "-")
  end

  def to_s
    name
  end

  def google_url
    "http://www.google.com/search?q=" + CGI.escape("#{name} cran OR r-project -inurl:contrib -inurl:doc/packages -inurl:CRAN")
  end

  def scholar_url
    "http://scholar.google.com/scholar?q=" + CGI.escape(name)
  end

  def rhelp_url
   "http://finzi.psych.upenn.edu/cgi-bin/namazu.cgi" +
     "?idxname=Rhelp02a&idxname=Rhelp01&query=" + CGI.escape(name)
  end

  def rdevel_url
   "http://finzi.psych.upenn.edu/cgi-bin/namazu.cgi" +
     "?idxname=R-devel&query=" + CGI.escape(name)
  end

end<commit_msg>Moved url generation into a single method<commit_after># == Schema Information
# Schema version: 20090727140821
#
# Table name: package
#
#  id                  :integer         not null, primary key
#  name                :string(255)
#  description         :text
#  created_at          :datetime
#  latest_version_id   :integer
#  updated_at          :datetime
#  package_users_count :integer         default(0), not null
#

class Package < ActiveRecord::Base
  include NoFuzz
  fuzzy :name

  after_create :create_trigrams # Incrementally update the trigram index

  has_many :versions, :order => "id DESC", :dependent => :destroy
  has_many :package_ratings, :dependent => :destroy
  has_many :package_users, :dependent => :destroy
  has_many :reviews, :dependent => :destroy
  has_many :taggings, :dependent => :destroy
  has_many :tags, :through => :taggings, :uniq => true do
    # @param [String, Class] type E.g. Priority or TaskView
    def type(type)
      proxy_owner.tags.all(:conditions => ["type = ?", type.to_s])
    end
  end

  # We cache the latest version id
  belongs_to :latest_version, :class_name => "Version"
  alias :latest :latest_version

  fires :new_package, :on                => :create,
                      :subject           => :self,
                      :secondary_subject => :self # yes 2x package

  # Uncommented until Rails handles named scope order in a better way
  # default_scope :order => "LOWER(package.name)"

  named_scope :recent, :order => "#{self.table_name}.created_at DESC",
                       :include => :latest_version,
                       :conditions => "#{self.table_name}.created_at IS NOT NULL",
                       :limit => 50

  validates_presence_of :name
  validates_uniqueness_of :name
  validates_length_of :name, :in => 2..255

  # We can't validate the presence of a latest_version_id here, since we
  # create packages before versions are associated. In conclusion, we have
  # to be careful and ideally use transactions when creating packages to avoid
  # inconsistent data in the database.

  def self.find_by_param(id)
    self.find_by_name(id.gsub("-", ".")) or raise ActiveRecord::RecordNotFound
  end

  ## No. of packages to show per page.
  def self.per_page; 50; end

  ## Search On Name of Package.
  def self.paginating_search(q, search_results_page)
    q.strip.downcase!

    if q.ends_with? '~' # fuzzy search
      # TODO It's kinda bad to do two database hits here, I think it can be resolved
      # by using paginate's :finder argument and creating a new method that
      # calls out to fuzzy_find.
      ids = Package.fuzzy_find(q[0...-1], per_page).collect { |i| i.id }
      [paginate(ids,
               {:include => {:versions => :maintainer},
               :page => search_results_page}), "fuzzy"]
    else
      res = paginate({ :conditions => [ 'LOWER(package.name) LIKE ?', '%' + q + '%'],
                       :include => [{:latest_version => :maintainer}],
                       :order => 'LOWER(package.name)',
                       :page => search_results_page })
      res.empty? ? self.paginating_search(q + '~', search_results_page) : [res]
    end
  end

  def self.search(q, limit=self.per_page)
    extra = { :include => :latest_version }
    res = []
    if q.ends_with? '~' # fuzzy search
      res = [Package.fuzzy_find(q[0...-1], limit, extra), "fuzzy"]
    else
      qq = '%' + q + '%'
      res = [Package.all(:conditions =>
                         ['LOWER(package.name) LIKE ? OR LOWER(version.description) LIKE ?', qq, qq],
                         :order => "LOWER(package.name)",
                         :limit => limit, :include => :latest_version)]
      if res.first.empty?
        # Try a fuzzy search if no results were found
        res = [Package.fuzzy_find(q, limit, extra), "fuzzy"]
      end
    end
    res
  end

  def <=>(other)
    self.name.downcase <=> other.name.downcase
  end

  # If updated_at is nil (which is the case for some older records), return
  # created_at as the value for updated_at. This is required because e.g. the
  # sitemap relies on proper updated_at values.
  def updated_at
    super || self.created_at
  end

  def description
    self.latest_version.description # for convenience
  end

  # @return [Fixnum] Number of ratings for this package for the given aspect
  def rating_count(aspect="overall")
    PackageRating.count(:conditions => ["package_id = ? AND aspect = ?",
                                        self.id, aspect])
  end

  # Rounded average rating for this package
  def average_rating(aspect="overall")
    PackageRating.calculate_average(self, aspect)
  end

  def to_param
    name.gsub(".", "-")
  end

  def to_s
    name
  end

  def url_for(site)
    case site
    when "google" then
      "http://www.google.com/search?q=" +
        CGI.escape("#{name} cran OR " +
                   "r-project -inurl:contrib -inurl:doc/packages -inurl:CRAN")
    when "scholar" then
      "http://scholar.google.com/scholar?q=" + CGI.escape(name)
    when "rhelp" then
      "http://finzi.psych.upenn.edu/cgi-bin/namazu.cgi" +
        "?idxname=Rhelp02a&idxname=Rhelp01&query=" + CGI.escape(name)
    when "rdevel" then
      "http://finzi.psych.upenn.edu/cgi-bin/namazu.cgi" +
        "?idxname=R-devel&query=" + CGI.escape(name)
    when "graphical_manual" then
       "http://bm2.genes.nig.ac.jp/RGM2/pkg.php?p=" + CGI.escape(name)
    end
  end

end
{'fraction_non_alphanumeric': 0.1187775382019312, 'fraction_numerical': 0.006749789069091591, 'mean_word_length': 2.537135278514589, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '619620', 'n_tokens_mistral': 3475, 'n_tokens_neox': 3261, 'n_words': 918}