Skip to content

Commit

Permalink
Attempt to lazy-load component when container is asked for key?
Browse files Browse the repository at this point in the history
This also adds `Container.registered?` which acts as `key?` used to.
Besides it, `Container.resove` not takes an optional block to make this interface constistent with dry-container
  • Loading branch information
flash-gordon committed Jul 8, 2019
1 parent 3326f16 commit fca4a64
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 22 deletions.
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

source 'https://rubygems.org'

git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
git_source(:github) { |repo_name| "https://github.com/dry-rb/#{repo_name}" }

gemspec

gem 'bootsnap'
gem 'dry-monitor'
gem 'dry-container', github: 'dry-container'

gem 'codeclimate-test-reporter', platforms: :mri

Expand Down
6 changes: 3 additions & 3 deletions lib/dry/system/auto_registrar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def components(dir)
files(dir)
.map { |file_name| [file_name, file_options(file_name)] }
.map { |(file_name, options)| component(relative_path(dir, file_name), **options) }
.reject { |component| key?(component.identifier) }
.reject { |component| registered?(component.identifier) }
end

# @api private
Expand Down Expand Up @@ -81,8 +81,8 @@ def root
end

# @api private
def key?(name)
container.key?(name)
def registered?(name)
container.registered?(name)
end

# @api private
Expand Down
2 changes: 1 addition & 1 deletion lib/dry/system/components/bootable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def container
# @api private
def finalize
lifecycle.container.each do |key, item|
container.register(key, item) unless container.key?(key)
container.register(key, item) unless container.registered?(key)
end
self
end
Expand Down
43 changes: 35 additions & 8 deletions lib/dry/system/container.rb
Original file line number Diff line number Diff line change
Expand Up @@ -518,12 +518,37 @@ def root
end

# @api public
def resolve(key)
load_component(key) unless finalized?
def resolve(key, &block)
load_component(key, &block) unless finalized?

super
end

alias_method :registered?, :key?
#
# @!method registered?(key)
# Whether a +key+ is registered (doesn't trigger loading)
# @param [String,Symbol] key Identifier
# @return [Boolean]
# @api public
#

# Check if identifier is registered.
# If not, try to load the component
#
# @param [String,Symbol] key Identifier
# @return [Boolean]
#
# @api public
def key?(key)
if finalized?
registered?(key)
else
registered?(key) || resolve(key) { return false }
true
end
end

# @api private
def load_paths
@load_paths ||= []
Expand Down Expand Up @@ -572,7 +597,7 @@ def component(identifier, **options)

# @api private
def require_component(component)
return if key?(component.identifier)
return if registered?(component.identifier)

raise FileNotFoundError, component unless component.file_exists?(load_paths)

Expand All @@ -593,8 +618,8 @@ def require_path(path)
end

# @api private
def load_component(key)
return self if key?(key)
def load_component(key, &block)
return self if registered?(key)

component(key).tap do |component|
if component.boot?
Expand All @@ -608,7 +633,7 @@ def load_component(key)
load_imported_component(component.namespaced(root_key))
end

load_local_component(component) unless key?(key)
load_local_component(component, &block) unless registered?(key)
end
end

Expand Down Expand Up @@ -641,17 +666,19 @@ def inherited(klass)
private

# @api private
def load_local_component(component, default_namespace_fallback = false)
def load_local_component(component, default_namespace_fallback = false, &block)
if booter.bootable?(component) || component.file_exists?(load_paths)
booter.boot_dependency(component) unless finalized?

require_component(component) do
register(component.identifier) { component.instance }
end
elsif !default_namespace_fallback
load_local_component(component.prepend(config.default_namespace), true)
load_local_component(component.prepend(config.default_namespace), true, &block)
elsif manual_registrar.file_exists?(component)
manual_registrar.(component)
elsif block_given?
yield
else
raise ComponentLoadError, component
end
Expand Down
2 changes: 1 addition & 1 deletion lib/dry/system/lifecycle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def trigger!(name, &block)

# @api private
def method_missing(meth, *args, &block)
if target.key?(meth)
if target.registered?(meth)
target[meth]
elsif container.key?(meth)
container[meth]
Expand Down
2 changes: 1 addition & 1 deletion lib/dry/system/plugins/logging.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def self.extended(system)
#
# @api private
def register_logger
if key?(:logger)
if registered?(:logger)
self
elsif config.logger
register(:logger, config.logger)
Expand Down
2 changes: 1 addition & 1 deletion lib/dry/system/plugins/notifications.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def self.dependencies

# @api private
def register_notifications
return self if key?(:notifications)
return self if registered?(:notifications)

register(:notifications, Monitor::Notifications.new(config.name))
end
Expand Down
2 changes: 1 addition & 1 deletion spec/integration/container/plugins/logging_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

context 'with default logger settings' do
subject(:system) do
Class.new(Dry::System::Container) do
class Test::Container < Dry::System::Container
use :env
use :logging
end
Expand Down
6 changes: 3 additions & 3 deletions spec/unit/container/auto_register_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Test::Container < Dry::System::Container
it { expect(Test::Container['bar.baz']).to be_an_instance_of(Bar::Baz) }

it "doesn't register files with inline option 'auto_register: false'" do
expect(Test::Container.key?('no_register')).to eql false
expect(Test::Container.registered?('no_register')).to eql false
end
end

Expand All @@ -46,8 +46,8 @@ class Test::Container < Dry::System::Container

expect(Test::Container['foo']).to eql('foo')

expect(Test::Container.key?('bar')).to eql false
expect(Test::Container.key?('bar.baz')).to eql false
expect(Test::Container.registered?('bar')).to eql false
expect(Test::Container.registered?('bar.baz')).to eql false
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/unit/container/import_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
it 'imports one container into another' do
app.import(persistence: db)

expect(app.key?('persistence.users')).to be(false)
expect(app.registered?('persistence.users')).to be(false)

app.finalize!

Expand Down
59 changes: 58 additions & 1 deletion spec/unit/container_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class Test::Container < Dry::System::Container
container.init(:bar)

expect(Test.const_defined?(:Bar)).to be(true)
expect(container.key?('test.bar')).to be(false)
expect(container.registered?('test.bar')).to be(false)
end
end

Expand Down Expand Up @@ -251,4 +251,61 @@ class Test::Container < Dry::System::Container
end
end
end

describe '.key?' do
before do
class Test::FalseyContainer < Dry::System::Container
register(:else) { :else }
register(:false) { false }
register(:nil) { nil }
end

class Test::Container < Dry::System::Container
config.root = SPEC_ROOT.join('fixtures/test').realpath
load_paths!('lib')

importer.registry.update(falses: Test::FalseyContainer)
end
end

it 'tries to load component' do
expect(container.key?('test.dep')).to be(true)
end

it 'returns false for non-existing component' do
expect(container.key?('test.missing')).to be(false)
end

it 'returns true if registered value is false or nil' do
expect(container.key?('falses.false')).to be(true)
expect(container.key?('falses.nil')).to be(true)
end
end

describe '.resolve' do
before do
class Test::Container < Dry::System::Container
config.root = SPEC_ROOT.join('fixtures/test').realpath
end
end

it 'runs a fallback block when a component cannot be resolved' do
expect(container.resolve('missing') { :fallback }).to be(:fallback)
end
end

describe '.registered?' do
before do
class Test::Container < Dry::System::Container
config.root = SPEC_ROOT.join('fixtures/test').realpath
load_paths!('lib')
end
end

it 'checks if a component is registered' do
expect(container.registered?('test.dep')).to be(false)
container.resolve('test.dep')
expect(container.registered?('test.dep')).to be(true)
end
end
end

0 comments on commit fca4a64

Please sign in to comment.