<commit_before>require 'faker'

module Forgeable
  def forge(association, attributes={}, foreign_key=nil)
    foreign_key ||= self.class.name.downcase + '_id'
    attributes.merge!(foreign_key => self.id)
    eval(association.to_s.classify).forge(attributes)
  end
  
  def forge_photo(photo=true)
    if photo.is_a?(String)
      self.photo = File.open(photo)
    else
      self.photo = File.open(RAILS_ROOT + '/test/fixtures/files/image.jpg')
    end
  end
  
  def forge_file(file=true)
    if file.is_a?(String)
      self.file = File.open(file)
    else
      self.file = ActionController::TestUploadedFile.new(File.dirname(__FILE__) + '/fixtures/files/attachment.pdf', nil, false)
    end
  end
  
  def self.included(mod)
    mod.extend(ClassMethods)
    mod.class_eval <<-END
      @@forgery_defaults = {}
      
      def self.forgery_defaults=(defaults)
        class_eval do
          @@forgery_defaults = defaults
        end
      end

      def self.forgery_defaults
        defaults = {}
        @@forgery_defaults.each do |key, val|
          if val.respond_to? :call
            defaults[key] = val.call
          elsif val.is_a? Symbol
            defaults[key] = self.fake(val)
          else
            defaults[key] = val
          end
        end
        defaults
      end
    END
  end
  
  module ClassMethods
    
    def forge(attributes={})
      attributes.symbolize_keys!
      attributes = forgery_defaults.merge(attributes)
      photo = attributes.delete(:photo)
      file = attributes.delete(:file)
      fail_count = 0
      begin
        returning create!(attributes) do |obj|
          obj.forge_photo(photo) if photo
          obj.forge_file(file)   if file
        end
      rescue ActiveRecord::RecordInvalid => e
        if e.message =~ /already (been )?taken/ and fail_count < 10
          fail_count += 1
          retry
        end
      end
    end
    
    def fake(symbol)
      case symbol
      when :word
        Faker::Lorem.words(1).join
      when :sentence, :paragraph
        Faker::Lorem.send(symbol)
      when :email
        Faker::Internet.send(symbol)
      when :name
        "#{fake :first_name} #{fake :last_name}"
      when :first_name, :last_name
        Faker::Name.send(symbol)
      when :link
        "http://#{Faker::Internet.domain_name}"
      else
        raise 'Unrecognized faker symbol.'
      end
    end
    
  end
end

%w(Family Person Recipe Note Picture Verse Group Album Publication Tag NewsItem Comment PrayerRequest).each do |model|
  eval model<commit_msg>Be a little smarter about fixing a failed validation on uniqueness when forging data. Should fix those random broken tests.<commit_after>require 'faker'

module Forgeable
  def forge(association, attributes={}, foreign_key=nil)
    foreign_key ||= self.class.name.downcase + '_id'
    attributes.merge!(foreign_key => self.id)
    eval(association.to_s.classify).forge(attributes)
  end
  
  def forge_photo(photo=true)
    if photo.is_a?(String)
      self.photo = File.open(photo)
    else
      self.photo = File.open(RAILS_ROOT + '/test/fixtures/files/image.jpg')
    end
  end
  
  def forge_file(file=true)
    if file.is_a?(String)
      self.file = File.open(file)
    else
      self.file = ActionController::TestUploadedFile.new(File.dirname(__FILE__) + '/fixtures/files/attachment.pdf', nil, false)
    end
  end
  
  def self.included(mod)
    mod.extend(ClassMethods)
    mod.class_eval <<-END
      @@forgery_defaults = {}
      
      def self.forgery_defaults=(defaults)
        class_eval do
          @@forgery_defaults = defaults
        end
      end

      def self.forgery_defaults
        defaults = {}
        @@forgery_defaults.each do |key, val|
          if val.respond_to? :call
            defaults[key] = val.call
          elsif val.is_a? Symbol
            defaults[key] = self.fake(val)
          else
            defaults[key] = val
          end
        end
        defaults
      end
    END
  end
  
  module ClassMethods
    
    def forge(attributes={})
      attributes.symbolize_keys!
      attributes = forgery_defaults.merge(attributes)
      photo = attributes.delete(:photo)
      file = attributes.delete(:file)
      begin
        returning create!(attributes) do |obj|
          obj.forge_photo(photo) if photo
          obj.forge_file(file)   if file
        end
      rescue ActiveRecord::RecordInvalid => e
        if e.message =~ /^Validation failed: (.+) has already been taken/
          attributes[$1.downcase.to_sym] << 'a'
          retry
        else
          puts e.message
        end
      end
    end
    
    def fake(symbol)
      case symbol
      when :word
        Faker::Lorem.words(1).join
      when :sentence, :paragraph
        Faker::Lorem.send(symbol)
      when :email
        Faker::Internet.send(symbol)
      when :name
        "#{fake :first_name} #{fake :last_name}"
      when :first_name, :last_name
        Faker::Name.send(symbol)
      when :link
        "http://#{Faker::Internet.domain_name}"
      else
        raise 'Unrecognized faker symbol.'
      end
    end
    
  end
end

%w(Family Person Recipe Note Picture Verse Group Album Publication Tag NewsItem Comment PrayerRequest).each do |model|
  eval model
{'fraction_non_alphanumeric': 0.09857006673021926, 'fraction_numerical': 0.001334604385128694, 'mean_word_length': 2.198780487804878, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '610358', 'n_tokens_mistral': 1623, 'n_tokens_neox': 1596, 'n_words': 371}