1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
# frozen_string_literal: true
module Faker
class UniqueGenerator
def initialize(generator, max_retries)
@generator = generator
@max_retries = max_retries
end
def method_missing(name, *arguments)
self.class.marked_unique.add(self)
@max_retries.times do
result = @generator.public_send(name, *arguments)
next if previous_results[[name, arguments]].include?(result)
previous_results[[name, arguments]] << result
return result
end
raise RetryLimitExceeded, "Retry limit exceeded for #{name}"
end
# Have method_missing use ruby 2.x keywords if the method exists.
# This is necessary because the syntax for passing arguments (`...`)
# is invalid on versions before Ruby 2.7, so it can't be used.
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
def respond_to_missing?(method_name, include_private = false)
method_name.to_s.start_with?('faker_') || super
end
class RetryLimitExceeded < StandardError; end
def previous_results
Thread.current[:faker_unique_generator_previous_results] ||= {}
Thread.current[:faker_unique_generator_previous_results][@generator] ||= Hash.new { |hash, key| hash[key] = Set.new }
end
def clear
previous_results.clear
end
def self.marked_unique
Thread.current[:faker_unique_generator_marked_unique] ||= Set.new
end
def self.clear
marked_unique.each(&:clear)
marked_unique.clear
end
def exclude(name, arguments, values)
values ||= []
values.each do |value|
previous_results[[name, arguments]] << value
end
end
end
end
|