From 336ca2e7974d8d944b520f9c30932bbc221fa3e6 Mon Sep 17 00:00:00 2001 From: Thiago Araujo Date: Thu, 30 Apr 2026 21:33:51 -0600 Subject: [PATCH 1/2] fix: lazy loading This fix initializes lazy loading or eager loading after the first time a generator is called, which can be a bit surprising. But this guarantees that the `Faker::Config.lazy_loading` setting is respected. --- lib/faker.rb | 82 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/lib/faker.rb b/lib/faker.rb index a5d7d472b9..f88fd2685b 100644 --- a/lib/faker.rb +++ b/lib/faker.rb @@ -288,46 +288,62 @@ def disable_enforce_available_locales end end - if Faker::Config.lazy_loading? - def self.load_path(*constants) - constants.map do |class_name| - class_name - .to_s - .gsub('::', '/') - .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') - .gsub(/([a-z\d])([A-Z])/, '\1_\2') - .tr('-', '_') - .downcase - end.join('/') + def self.load_path(*constants) + constants.map do |class_name| + class_name + .to_s + .gsub('::', '/') + .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + .gsub(/([a-z\d])([A-Z])/, '\1_\2') + .tr('-', '_') + .downcase + end.join('/') + end + + # TODO: refactor this + + def self.resolve_const(context_name, class_name) + load_path = case class_name + when :DnD + load_path('faker/games/dnd') + else + load_path(context_name, class_name) + end + + begin + require(load_path) + rescue LoadError + require(load_path.gsub('faker/', 'faker/default/')) end + end - def self.lazy_load(klass) - def klass.const_missing(class_name) - load_path = case class_name - when :DnD - Faker.load_path('faker/games/dnd') - else - Faker.load_path(name, class_name) - end - - begin - require(load_path) - rescue LoadError - require(load_path.gsub('faker/', 'faker/default/')) - end + private_class_method :resolve_const - const_get(class_name) + EAGER_LOAD_MUTEX = Mutex.new + private_constant :EAGER_LOAD_MUTEX + + # initial usage determines lazy loading or eager loading + # TODO: this can be a bit surprising and error-prone + def self.const_missing(class_name) + EAGER_LOAD_MUTEX.synchronize do + if Config.lazy_loading? + resolve_const(name, class_name) + elsif !@eager_load + @eager_load = true + Dir.glob(["#{__dir__}/faker/*.rb", "#{__dir__}/faker/**/*.rb"]).each { |f| require f } end end - lazy_load(self) + const_get(class_name) end -end -unless Faker::Config.lazy_loading? - rb_files = [] - rb_files << File.join(mydir, 'faker', '*.rb') - rb_files << File.join(mydir, 'faker', '/**/*.rb') + def self.lazy_load(klass) + mutex = Mutex.new + + klass.define_singleton_method(:const_missing) do |class_name| + mutex.synchronize { Faker.resolve_const(name, class_name) } - Dir.glob(rb_files).each { |file| require file } + const_get(class_name) + end + end end From 471afd96294c2c78e442925a6cf4cf0c0021e29c Mon Sep 17 00:00:00 2001 From: Thiago Araujo Date: Thu, 30 Apr 2026 21:41:17 -0600 Subject: [PATCH 2/2] fix: private method call Fix this failure when lazy loading: https://github.com/faker-ruby/faker/actions/runs/25201119276/job/73892235147?pr=3256 --- lib/faker.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/faker.rb b/lib/faker.rb index f88fd2685b..a0a28f4251 100644 --- a/lib/faker.rb +++ b/lib/faker.rb @@ -317,8 +317,6 @@ def self.resolve_const(context_name, class_name) end end - private_class_method :resolve_const - EAGER_LOAD_MUTEX = Mutex.new private_constant :EAGER_LOAD_MUTEX