Skip to content

fix: Faker::Config.lazy_loading configuration must be respected (WIP)#3256

Open
thdaraujo wants to merge 5 commits into
mainfrom
ta/fix-lazy-loading-bug
Open

fix: Faker::Config.lazy_loading configuration must be respected (WIP)#3256
thdaraujo wants to merge 5 commits into
mainfrom
ta/fix-lazy-loading-bug

Conversation

@thdaraujo
Copy link
Copy Markdown
Contributor

@thdaraujo thdaraujo commented May 1, 2026

(fixes #3248 )

This fix initializes lazy loading or eager loading after the first constant access, which can be a bit surprising.

But this guarantees that the Faker::Config.lazy_loading setting is respected.

We introduce a new Faker::Loader class responsible for taking care of the loading process.

The loader has a method Loader#install_on that adds lazy loading to a generator. It defines const_missing on namespace classes (Faker::Games, Faker::Music etc.), delegating back to the Loader, which resolves the constant either by requiring the single corresponding file (lazy) or by loading all generator files at once (eager).

The loading strategy (lazy vs eager) is snapshotted on the first const_missing call. Changing config after first use has no effect.

The loader also has a list of inflections to handle cases such as DnD -> dnd.rb.

Config.lazy_loading is now process-wide rather than thread-local, so it cannot be confired per-thread anymore (which didn't seem very useful to begin with, so we're simplifying this).

--

The main source of the problem is due to Faker having configuration set directly, which makes it hard to defer evaluation of the configuration before requiring the Faker library.

Other possible alternative could be:

  • forcing eager loading when the lazy_loading config is first set to true
  • exposing a configuration block that only loads files after the block is executed.

@thdaraujo thdaraujo self-assigned this May 1, 2026
Comment thread lib/faker.rb Outdated
@thdaraujo
Copy link
Copy Markdown
Contributor Author

thdaraujo commented May 1, 2026

testing script

require_relative "../faker/lib/faker"

lazy_loading = if ENV.key?('FAKER_LAZY_LOAD')
                 puts 'set via env...'
                 ENV['FAKER_LAZY_LOAD'] == '1'
               else
                 puts 'set via config...'
                 Faker::Config.lazy_loading = true
               end

puts "Number of constants: #{Faker.constants.size}"
puts "Faker::Name #{Faker::Name.name}"
puts "Number of constants: #{Faker.constants.size}"

if lazy_loading
  puts "faker is lazy loading..."

  if Faker.constants.size > 10
    raise "must be lazy loaded!"
  else
    "lazy loading success!"
  end
else
  puts "faker is NOT lazy loading..."

  if Faker.constants.size < 10
    raise "must be eager loaded!"
  else
    "eager loading success!"
  end
end

Call with env or config:

FAKER_LAZY_LOAD=0 ruby script.rb 
FAKER_LAZY_LOAD=1 ruby script.rb

# change `lazy_loading` config on the file itself, then run
ruby script.rb 

@thdaraujo thdaraujo force-pushed the ta/fix-lazy-loading-bug branch 2 times, most recently from f6c2113 to 471afd9 Compare May 1, 2026 03:42
Comment thread lib/faker.rb Outdated
private_constant :EAGER_LOAD_MUTEX

# initial usage determines lazy loading or eager loading
# TODO: this can be a bit surprising and error-prone
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this sets up loading the first time a generator is called, which could be a bit surprising/unexpected.

maybe it's a good enough solution for letting folks test it?

in the future, we aim to make lazy loading default, so this wouldn't be a problem anymore, in my view.

@thdaraujo thdaraujo force-pushed the ta/fix-lazy-loading-bug branch from 4003e8f to 8dda593 Compare May 11, 2026 16:48
@thdaraujo thdaraujo force-pushed the ta/fix-lazy-loading-bug branch 3 times, most recently from e5c4aa3 to 9014cb4 Compare May 31, 2026 23:56
thdaraujo added 3 commits May 31, 2026 18:38
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.
@thdaraujo thdaraujo force-pushed the ta/fix-lazy-loading-bug branch from 9014cb4 to 63fd229 Compare June 1, 2026 00:38
@thdaraujo thdaraujo requested a review from stefannibrasil June 1, 2026 00:38
@thdaraujo thdaraujo marked this pull request as ready for review June 1, 2026 00:39
Comment thread test/faker/test_loader.rb
end

mutex.synchronize { loaded_files << f }
end
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stub Kernel#require to spy on files being required/loaded

Copy link
Copy Markdown
Contributor Author

@thdaraujo thdaraujo Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe I could pass require or Kernel via dependency injection to make it easier to test :/

It would also get rid of the warnings.

Could be a future improvement!

@thdaraujo thdaraujo force-pushed the ta/fix-lazy-loading-bug branch from 63fd229 to dd9026d Compare June 1, 2026 00:59
@thdaraujo thdaraujo force-pushed the ta/fix-lazy-loading-bug branch from dd9026d to f1db978 Compare June 1, 2026 01:12
@stefannibrasil
Copy link
Copy Markdown
Contributor

I tested on a Ruby project, and some generators raise this error:

Faker::Books::Dune.character =>

     NoMethodError:
       private method 'resolve_const' called for an instance of Faker::Loader

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The setting Faker::Config.lazy_loading = true does not work

2 participants