fix: Faker::Config.lazy_loading configuration must be respected (WIP) - #3256
fix: Faker::Config.lazy_loading configuration must be respected (WIP)#3256thdaraujo wants to merge 7 commits into
Faker::Config.lazy_loading configuration must be respected (WIP)#3256Conversation
|
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
endCall 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 |
f6c2113 to
471afd9
Compare
4003e8f to
8dda593
Compare
9014cb4 to
63fd229
Compare
| end | ||
|
|
||
| mutex.synchronize { loaded_files << f } | ||
| end |
There was a problem hiding this comment.
stub Kernel#require to spy on files being required/loaded
There was a problem hiding this comment.
I could pass require or Kernel via dependency injection to make it easier to test, but doesn't seem worth it.
dd9026d to
f1db978
Compare
|
I tested on a Ruby project, and some generators raise this error: |
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.
Fix this failure when lazy loading: https://github.com/faker-ruby/faker/actions/runs/25201119276/job/73892235147?pr=3256
1fd9439 to
6491270
Compare
| def load_const(context_name, class_name) | ||
| @mutex.synchronize do | ||
| if loading_strategy == :lazy | ||
| resolve_const(context_name, class_name) |
There was a problem hiding this comment.
this is currently broken on lazy loading
| class TestDeterminism < Test::Unit::TestCase | ||
| def setup | ||
| # TODO: can we expose loader? | ||
| Faker.instance_variable_get(:@loader).send(:eager_load!) |
6491270 to
31afb27
Compare
|
There are many problems with this implementation, and the complexity might not be worth it. I'm going to close this and rethink the approach. Maybe we could set up |
| end | ||
|
|
||
| def load_const(context_name, class_name) | ||
| @mutex.synchronize do |
There was a problem hiding this comment.
this might cause a deadlock? maybe a Monitor is a better fit?
https://ruby-doc.org/stdlib-2.5.3/libdoc/monitor/rdoc/Monitor.html
| # rubocop:disable Security/Eval,Style/EvalWithLocation | ||
| class TestDeterminism < Test::Unit::TestCase | ||
| def setup | ||
| # TODO: can we expose loader? |
There was a problem hiding this comment.
or maybe add a Faker::Config.eager_load! method
(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_loadingsetting is respected.We introduce a new
Faker::Loaderclass responsible for taking care of the loading process.The loader has a method
Loader#install_onthat adds lazy loading to a generator. It definesconst_missingon 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_missingcall. 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_loadingis 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:
lazy_loadingconfig is first set to true