Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy load autoloaded bucket components #678

Merged
merged 5 commits into from
Mar 16, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 34 additions & 23 deletions lib/phlex/bucket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,49 @@ def self.extended(mod)
warn "🚨 [WARNING] Phlex::Bucket is experimental and may be removed from future versions of Phlex."

# Eager load all constants in the module for apps that use Zeitwerk.
mod.constants.each { |c| mod.const_get(c) }
mod.constants.each { |c| mod.const_added(c) if mod.autoload?(c) }
end

def const_added(name)
# This can sometime be triggered by an autoload, which means it gets
# triggered a second time when we call `const_get` below and Ruby loads it.
return super if Fiber[:__phlex_adding_bucket_const__]

begin
Fiber[:__phlex_adding_bucket_const__] = true
constant = const_get(name)
ensure
Fiber[:__phlex_adding_bucket_const__] = false
end

if instance_methods.include?(name)
raise NameError, "The instance method `#{name}' is already defined on `#{inspect}`."
elsif methods.include?(name)
raise NameError, "The method `#{name}' is already defined on `#{inspect}`."
end

constant.include(self)

if Class === constant && constant < Phlex::SGML
if autoload?(name)
define_method(name) do |*args, **kwargs, &block|
render(constant.new(*args, **kwargs), &block)
this = method(name)
self.class.const_get(name) # load the constant (which should override this method)
joeldrapper marked this conversation as resolved.
Show resolved Hide resolved

if this == method(name)
# loading the constant didn't override this method
super
else
public_send(name, *args, **kwargs, &block) # call this method again
end
end

define_singleton_method(name) do |*args, **kwargs, &block|
Fiber[:__phlex_component__].instance_exec do
this = method(name)
const_get(name) # load the constant (which should override this method)

if this == method(name)
# loading the constant didn't override this method
super
else
public_send(name, *args, **kwargs, &block) # call this method again
end
end
else
constant = const_get(name)

constant.include(self)

if Class === constant && constant < Phlex::SGML
define_method(name) do |*args, **kwargs, &block|
render(constant.new(*args, **kwargs), &block)
end

define_singleton_method(name) do |*args, **kwargs, &block|
Fiber[:__phlex_component__].instance_exec do
render(constant.new(*args, **kwargs), &block)
end
end
end
end
end
Expand Down