Skip to content

Commit 8dda593

Browse files
committed
refactor: extract loading strategies to new class
1 parent a4d3547 commit 8dda593

2 files changed

Lines changed: 85 additions & 56 deletions

File tree

lib/faker.rb

Lines changed: 15 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require_relative 'faker/loader'
4+
35
mydir = __dir__
46

57
require 'psych'
@@ -14,9 +16,10 @@
1416
module Faker
1517
module Config
1618
@default_locale = nil
19+
@lazy_loading = false
1720

1821
class << self
19-
attr_writer :default_locale
22+
attr_writer :default_locale, :lazy_loading
2023

2124
def locale=(new_locale)
2225
Thread.current[:faker_config_locale] = new_locale
@@ -40,16 +43,12 @@ def random
4043
end
4144

4245
def lazy_loading?
43-
if ENV.key?('FAKER_LAZY_LOAD') && !ENV['FAKER_LAZY_LOAD'].nil?
44-
%w[true TRUE 1].include?(ENV.fetch('FAKER_LAZY_LOAD', nil))
46+
if ENV.key?('FAKER_LAZY_LOAD')
47+
%w[true TRUE 1].include?(ENV['FAKER_LAZY_LOAD'])
4548
else
46-
Thread.current[:faker_lazy_loading] == true
49+
@lazy_loading
4750
end
4851
end
49-
50-
def lazy_loading=(value)
51-
Thread.current[:faker_lazy_loading] = value
52-
end
5352
end
5453
end
5554

@@ -288,60 +287,20 @@ def disable_enforce_available_locales
288287
end
289288
end
290289

291-
def self.load_path(*constants)
292-
constants.map do |class_name|
293-
class_name
294-
.to_s
295-
.gsub('::', '/')
296-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
297-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
298-
.tr('-', '_')
299-
.downcase
300-
end.join('/')
301-
end
302-
303-
# TODO: refactor this
304-
305-
def self.resolve_const(context_name, class_name)
306-
load_path = case class_name
307-
when :DnD
308-
load_path('faker/games/dnd')
309-
else
310-
load_path(context_name, class_name)
311-
end
290+
@loader = Loader.new(__dir__, Config)
312291

313-
begin
314-
require(load_path)
315-
rescue LoadError
316-
require(load_path.gsub('faker/', 'faker/default/'))
317-
end
318-
end
319-
320-
EAGER_LOAD_MUTEX = Mutex.new
321-
private_constant :EAGER_LOAD_MUTEX
322-
323-
# initial usage determines lazy loading or eager loading
324-
# TODO: this can be a bit surprising and error-prone
292+
# Resolves missing constants by either lazy or eager loading generator files,
293+
# depending on +Config.lazy_loading?+ at the time of first use.
294+
#
295+
# The loading strategy is determined on the first access. Setting
296+
# +Config.lazy_loading+ after any generator has been referenced has no effect.
325297
def self.const_missing(class_name)
326-
EAGER_LOAD_MUTEX.synchronize do
327-
if Config.lazy_loading?
328-
resolve_const(name, class_name)
329-
elsif !@eager_load
330-
@eager_load = true
331-
Dir.glob(["#{__dir__}/faker/*.rb", "#{__dir__}/faker/**/*.rb"]).each { |f| require f }
332-
end
333-
end
298+
@loader.load_const(name, class_name)
334299

335300
const_get(class_name)
336301
end
337302

338303
def self.lazy_load(klass)
339-
mutex = Mutex.new
340-
341-
klass.define_singleton_method(:const_missing) do |class_name|
342-
mutex.synchronize { Faker.resolve_const(name, class_name) }
343-
344-
const_get(class_name)
345-
end
304+
@loader.install_on(klass)
346305
end
347306
end

lib/faker/loader.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
module Faker
4+
class Loader
5+
INFLECTIONS = { 'DnD' => 'dnd' }.freeze
6+
7+
def initialize(base_dir, config)
8+
@base_dir = base_dir
9+
@config = config
10+
@eager_loaded = false
11+
@mutex = Mutex.new
12+
end
13+
14+
def load_const(context_name, class_name)
15+
@mutex.synchronize do
16+
if lazy_loading?
17+
resolve_const(context_name, class_name)
18+
else
19+
eager_load!
20+
end
21+
end
22+
end
23+
24+
def install_on(klass)
25+
loader = self
26+
27+
klass.define_singleton_method(:const_missing) do |class_name|
28+
loader.resolve_const(name, class_name)
29+
30+
const_get(class_name)
31+
end
32+
end
33+
34+
def resolve_const(context_name, class_name)
35+
load_path = build_path(context_name, class_name)
36+
37+
require(load_path)
38+
rescue LoadError
39+
# try to load default generators
40+
require(load_path.gsub('faker/', 'faker/default/'))
41+
end
42+
43+
private
44+
45+
def eager_load!
46+
return if @eager_loaded
47+
48+
@eager_loaded = true
49+
50+
Dir.glob(["#{@base_dir}/faker/*.rb", "#{@base_dir}/faker/**/*.rb"])
51+
.each { |f| require f }
52+
end
53+
54+
def build_path(*constants)
55+
constants.map do |c|
56+
INFLECTIONS
57+
.reduce(c.to_s) { |s, (word, replacement)| s.gsub(word, replacement) }
58+
.gsub('::', '/')
59+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
60+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
61+
.tr('-', '_')
62+
.downcase
63+
end.join('/')
64+
end
65+
66+
def lazy_loading?
67+
@lazy_loading ||= @config.lazy_loading?
68+
end
69+
end
70+
end

0 commit comments

Comments
 (0)