require 'faker' module Eco module Data module Random class Fake MAX_UNIQUE_ERRORS = 13 DEFAULT_LOCALE = 'en' DEFAULT_EMAIL_PATTERN = 'oscar+name@ecoportal.co.nz' LOCALES_MAPS = {'en' => 'en', 'nz' => 'en-NZ', 'ca' => 'en-CA', 'uk' => 'en-GB', 'usa' => 'en-USA'} TOPICS_MAPS = { 'general' => ['General', 'Vehicle', 'University', 'Address'], 'fantasy' => ['LordOfTheRings', 'Hobbit', 'HarryPotter', 'BackToTheFuture', 'FunnyName', 'GameOfThrones', 'PricesBride', 'StarWars', 'StarkTrek'], 'medieval-fantasy' => ['LordOfTheRings', 'Hobbit', 'GameOfThrones', 'PricesBride'], 'futuristic-fantasy' => ['BackToTheFuture', 'StarWars', 'StarTrek'], 'tolkien' => ['LordOfTheRings', 'Hobbit'], 'funny' => ['FunnyName', 'Simpsons', 'Superhero'], 'famous' => ['Book', 'GreekPhilosophers' ,'Scientists', 'SiliconValley', 'Space', 'WorldCup'], 'philosophers' => 'GreekPhilosophers' } @name = nil; @name_topics = nil @location = nil; @location_topics = nil attr_reader :local, :topic, :general_topic_on_fail attr_reader :today, :email_pattern, :unique_errors, :unique_resets, :force_unique def initialize(init = {}) @unique_resets = 0; @unique_errors = 0 init_topics self.topic = init.fetch('topic', TOPICS_MAPS.keys.sample) self.general_topic_on_fail = init.fetch('general_topic_on_fail', false) self.force_unique = init.fetch('force_unique', false) self.local = init.fetch('local', nil) self.today = init.fetch('today', Date.today) self.email_pattern = init.fetch('email_pattern', DEFAULT_EMAIL_PATTERN) @boolean = Faker::Boolean.method('boolean') @date_between = Faker::Date.method('between') @gender = Faker::Gender.method('binary_type') @name = get_topic_wrapper(@name_topics) @company = get_topic_wrapper(@company_topics) @location = get_topic_wrapper(@location_topics) @community = wrap_method { Faker::Address.community } @address = wrap_method { Faker::Address.unique.full_address } @country = wrap_method { Faker::Address.country } @city = wrap_method { Faker::Address.city } @postcode = wrap_method { Faker::Address.postcode } @timezone = Faker::Address.method('time_zone') @phone = wrap_method { Faker::PhoneNumber.unique.phone_number } @mobile = wrap_method { Faker::PhoneNumber.unique.cell_phone } @mobile_code = wrap_method { Faker::Code.unique.imei } end def topic=(value) @topic = TOPICS_MAPS.values.first # 'General' @topic = TOPICS_MAPS[value.downcase] if value && TOPICS_MAPS.keys.include?(value.downcase) init_topic_wrappers end def general_topic_on_fail=(value) @general_topic_on_fail = value end def today=(value) @today = nil @today = value if value.instance_of?(Date) @today = Date.today if !@today end def email_pattern=(value) @email_pattern = value @email_pattern = DEFAULT_EMAIL_PATTERN if !@mail_pattern&.include?('@ecoportal.co.nz') end def local=(value) @local = DEFAULT_LOCALE alias_locales = LOCALES_MAPS.keys; locales = LOCALES_MAPS.values permitted = value && (alias_locales.include?(value.downcase) || locales.include?(value)) @local = LOCALES_MAPS[value.downcase] if permitted ::Faker::Config.locale = @local end def force_unique=(value) @force_unique = !!value end def reset_unique @unique_errors = 0 @unique_resets += 1 ::Faker::UniqueGenerator.clear end def boolean @boolean.call end def past_date(years = 3) @date_between.call(previous_date(years), @today) end def future_date(years = 3) @date_between.call(@today, later_date(years)) end def birthday(min_age = 18, max_age = 65) @date_between.call(previous_date(min_age), previous_date(max_age)) end def name new_value = get_unique(@name, @name_topics) @name = get_topic_wrapper(@name_topics) return new_value end def company new_value = get_unique(@company, @company_topics) @company = get_topic_wrapper(@company_topics) return new_value end def community @community.call end def location new_value = get_unique(@location, @location_topics) @location = get_topic_wrapper(@location_topics) return new_value end def address @address.call end def contry @country.call end def city @city.call end def postcode @postcode.call end def timezone @timezone.call end def gender @geneder.call end def email(str_name = nil) str_name = self.name if !str_name&.strip @email_pattern.gsub('name', email_encode(str_name)) end def phone @phone.call end def mobile @mobile.call end def mobile_code @mobile_code.call end private def unique_error_count @unique_errors += 1 unique_overflow = @unique_errors > MAX_UNIQUE_ERRORS err_msg = "Error uniqueness broken" raise Faker::UniqueGenerator::RetryLimitExceeded.new(err_msg), err_msg if self.force_unique && unique_overflow self.reset_unique if unique_overflow end def previous_date(years = 3) @today - (years * 365) end def later_date(years = 3) @today + (years * 365) end def init_topics @name_topics = { 'General' => wrap_method { Faker::Name.unique.name }, 'LordOfTheRings' => wrap_method { Faker::LordOfTheRings.unique.character }, 'Hobbit' => wrap_method { Faker::Hobbit.unique.character }, 'BackToTheFuture' => wrap_method { Faker::BackToTheFuture.unique.character }, 'HarryPotter' => wrap_method { Faker::HarryPotter.unique.character }, 'GameOfThrones' => wrap_method { Faker::GameOfThrones.unique.character }, 'PrincesBride' => wrap_method { Faker::PrincesBride.unique.character }, 'StarWars' => wrap_method { Faker::StarWars.unique.character }, 'StarTrek' => wrap_method { Faker::StarTrek.unique.character }, 'Simpsons' => wrap_method { Faker::Simpsons.unique.character }, 'Superhero' => wrap_method { Faker::Superhero.unique.name }, 'FunnyName' => wrap_method { Faker::FunnyName.unique.name }, 'Book' => wrap_method { Faker::Book.unique.author }, 'GreekPhilosophers' => wrap_method { Faker::GreekPhilosophers.unique.name }, 'Scientists' => wrap_method { Faker::Science.unique.scientist }, 'SiliconValley' => wrap_method { Faker::SiliconValley.unique.character }, 'WorldCup' => wrap_method { Faker::WorldCup.unique.roster } } @location_topics = { 'General' => wrap_method { Faker::Nation.capital_city }, 'LordOfTheRings' => wrap_method { Faker::LordOfTheRings.location }, 'Hobbit' => wrap_method { Faker::Hobbit.location }, 'HarryPotter' => wrap_method { Faker::HarryPotter.location }, 'GameOfThrones' => wrap_method { Faker::GameOfThrones.city }, 'Simpsons' => wrap_method { Faker::Simpsons.location }, 'StarTrek' => wrap_method { Faker::StarTrek.location }, 'WorldCup' => wrap_method { Faker::WorldCup.city }, 'University' => wrap_method { Faker::University.name }, 'Address' => wrap_method { Faker::Address.city } } @company_topics = { 'General' => wrap_method { Faker::Company.name }, 'Vehicle' => wrap_method { Faker::Vehicle.manufacture }, 'SiliconValley' => wrap_method { Faker::SiliconValley.company }, 'Space' => wrap_method { Faker::Space.company } } @deparment_topics = { 'General' => wrap_method { Faker::Commerce.department } } end def init_topic_wrappers @name = get_topic_wrapper(@name_topics) @location = get_topic_wrapper(@location_topics) end def get_topic_wrapper(type_topics) all_topics = @topic.instance_of?(Array)? @topic : [@topic] topics = filter_by_key(type_topics, all_topics) failed_topic = !@topic || !topics || topics.values.length < 1 if !failed_topic topic = topics.values.sample #puts "\"Custom!!!!\"" else if @general_topic_on_fail topic = type_topics.fetch('General', nil) #puts "\"Genearal!!!!\"" else topic = type_topics.values.sample #puts "\"Force Random!!!!\"" end end return topic end def get_unique(wrapper, related_topics) begin new_value = wrapper.call rescue Faker::UniqueGenerator::RetryLimitExceeded unique_error_count wrapper = get_topic_wrapper(related_topics) new_value = get_unique(wrapper, related_topics) end return new_value end def filter_by_key (hash, keys) hash.select { |k,v| keys.include?(k) } end # should allow different topics def email_encode(str) return nil if !str.is_a?(String) return str.gsub(/\s+/,"_")&.gsub(/\W/,"")&.slice(0,25).downcase end def wrap_method(&block) block end def self.test(test_times = 500, fantasy: true, force_unique: false) pp "########## Testing Faker wrapper ###########" topic = if fantasy then 'fantasy' else nil end faker = self.new({ 'today' => Date.new(2018,1,1), 'locale' => 'nz', 'topic' => topic, 'general_topic_on_fail' => true, 'force_unique' => force_unique }) begin items = 0 test_times.times { pp "#{name=faker.name} - #{faker.birthday(20, 40).to_s} : #{faker.mobile} : #{faker.email(name)}" + \ " : #{faker.location} : #{faker.company} : #{faker.community}" items += 1 } rescue ::Faker::UniqueGenerator::RetryLimitExceeded => e puts "### Error: #{e.message} ###" end puts "total generated: #{items}" puts "locale: #{faker.local}; topic: #{topic}" puts "unique errors: #{faker.unique_errors} & #{faker.unique_resets} resets" end end end end end