dry-system 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +39 -0
- data/.rspec +3 -0
- data/.rubocop.yml +34 -0
- data/.rubocop_todo.yml +26 -0
- data/.travis.yml +26 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +158 -0
- data/Gemfile +9 -0
- data/LICENSE +20 -0
- data/README.md +23 -0
- data/Rakefile +12 -0
- data/dry-system.gemspec +30 -0
- data/examples/standalone/Gemfile +5 -0
- data/examples/standalone/lib/user_repo.rb +5 -0
- data/examples/standalone/run.rb +7 -0
- data/examples/standalone/system/boot/persistence.rb +13 -0
- data/examples/standalone/system/container.rb +9 -0
- data/examples/standalone/system/import.rb +3 -0
- data/lib/dry-system.rb +1 -0
- data/lib/dry/system.rb +4 -0
- data/lib/dry/system/auto_registrar.rb +80 -0
- data/lib/dry/system/booter.rb +101 -0
- data/lib/dry/system/component.rb +167 -0
- data/lib/dry/system/constants.rb +9 -0
- data/lib/dry/system/container.rb +500 -0
- data/lib/dry/system/errors.rb +62 -0
- data/lib/dry/system/importer.rb +53 -0
- data/lib/dry/system/injector.rb +68 -0
- data/lib/dry/system/lifecycle.rb +104 -0
- data/lib/dry/system/loader.rb +69 -0
- data/lib/dry/system/version.rb +5 -0
- data/spec/fixtures/components/bar.rb +5 -0
- data/spec/fixtures/components/bar/baz.rb +4 -0
- data/spec/fixtures/components/foo.rb +2 -0
- data/spec/fixtures/import_test/config/application.yml +2 -0
- data/spec/fixtures/import_test/lib/test/bar.rb +4 -0
- data/spec/fixtures/import_test/lib/test/foo.rb +5 -0
- data/spec/fixtures/import_test/system/boot/bar.rb +11 -0
- data/spec/fixtures/lazytest/config/application.yml +2 -0
- data/spec/fixtures/lazytest/lib/test/dep.rb +4 -0
- data/spec/fixtures/lazytest/lib/test/foo.rb +5 -0
- data/spec/fixtures/lazytest/lib/test/models.rb +4 -0
- data/spec/fixtures/lazytest/lib/test/models/book.rb +6 -0
- data/spec/fixtures/lazytest/lib/test/models/user.rb +6 -0
- data/spec/fixtures/lazytest/system/boot/bar.rb +15 -0
- data/spec/fixtures/namespaced_components/namespaced/bar.rb +5 -0
- data/spec/fixtures/namespaced_components/namespaced/foo.rb +4 -0
- data/spec/fixtures/other/config/boot/bar.rb +11 -0
- data/spec/fixtures/other/lib/test/dep.rb +4 -0
- data/spec/fixtures/other/lib/test/foo.rb +5 -0
- data/spec/fixtures/other/lib/test/models.rb +4 -0
- data/spec/fixtures/other/lib/test/models/book.rb +6 -0
- data/spec/fixtures/other/lib/test/models/user.rb +6 -0
- data/spec/fixtures/test/config/application.yml +2 -0
- data/spec/fixtures/test/config/subapp.yml +2 -0
- data/spec/fixtures/test/lib/test/dep.rb +4 -0
- data/spec/fixtures/test/lib/test/foo.rb +5 -0
- data/spec/fixtures/test/lib/test/models.rb +4 -0
- data/spec/fixtures/test/lib/test/models/book.rb +6 -0
- data/spec/fixtures/test/lib/test/models/user.rb +6 -0
- data/spec/fixtures/test/lib/test/singleton_dep.rb +7 -0
- data/spec/fixtures/test/log/.gitkeep +0 -0
- data/spec/fixtures/test/system/boot/bar.rb +11 -0
- data/spec/fixtures/test/system/boot/client.rb +7 -0
- data/spec/fixtures/test/system/boot/db.rb +1 -0
- data/spec/fixtures/test/system/boot/logger.rb +5 -0
- data/spec/fixtures/umbrella/system/boot/db.rb +10 -0
- data/spec/integration/boot_spec.rb +18 -0
- data/spec/integration/import_spec.rb +63 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/unit/component_spec.rb +116 -0
- data/spec/unit/container/auto_register_spec.rb +85 -0
- data/spec/unit/container/finalize_spec.rb +85 -0
- data/spec/unit/container/import_spec.rb +70 -0
- data/spec/unit/container/injector_spec.rb +29 -0
- data/spec/unit/container_spec.rb +165 -0
- data/spec/unit/injector_spec.rb +72 -0
- data/spec/unit/loader_spec.rb +64 -0
- metadata +295 -0
| @@ -0,0 +1,85 @@ | |
| 1 | 
            +
            RSpec.describe Dry::System::Container, '.finalize' do
         | 
| 2 | 
            +
              subject(:system) { Test::App }
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              let(:db) { spy(:db) }
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              before do
         | 
| 7 | 
            +
                Test.const_set(:DB, db)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                module Test
         | 
| 10 | 
            +
                  class App < Dry::System::Container
         | 
| 11 | 
            +
                    configure do |config|
         | 
| 12 | 
            +
                      config.root = SPEC_ROOT.join('fixtures/test')
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    finalize(:db) do
         | 
| 16 | 
            +
                      register(:db, Test::DB)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                      init do
         | 
| 19 | 
            +
                        db.establish_connection
         | 
| 20 | 
            +
                      end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      start do
         | 
| 23 | 
            +
                        db.load
         | 
| 24 | 
            +
                      end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                      stop do
         | 
| 27 | 
            +
                        db.close_connection
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              describe '#init' do
         | 
| 35 | 
            +
                it 'calls init function' do
         | 
| 36 | 
            +
                  system.booter.(:db).init
         | 
| 37 | 
            +
                  expect(db).to have_received(:establish_connection)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              describe '#start' do
         | 
| 42 | 
            +
                it 'calls start function' do
         | 
| 43 | 
            +
                  system.booter.(:db).start
         | 
| 44 | 
            +
                  expect(db).to have_received(:load)
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              describe '#stop' do
         | 
| 49 | 
            +
                it 'calls stop function' do
         | 
| 50 | 
            +
                  system.booter.(:db).stop
         | 
| 51 | 
            +
                  expect(db).to have_received(:close_connection)
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              specify 'boot triggers init' do
         | 
| 56 | 
            +
                system.booter.boot(:db)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                expect(db).to have_received(:establish_connection)
         | 
| 59 | 
            +
                expect(db).to_not have_received(:load)
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              specify 'boot! triggers init + start' do
         | 
| 63 | 
            +
                system.booter.boot!(:db)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                expect(db).to have_received(:establish_connection)
         | 
| 66 | 
            +
                expect(db).to have_received(:load)
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              specify 'booter returns cached lifecycle objects' do
         | 
| 70 | 
            +
                expect(system.booter.(:db)).to be(system.booter.(:db))
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              specify 'lifecycle triggers are called only once' do
         | 
| 74 | 
            +
                system.booter.boot!(:db)
         | 
| 75 | 
            +
                system.booter.boot!(:db)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                system.booter.boot(:db)
         | 
| 78 | 
            +
                system.booter.boot(:db)
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                expect(db).to have_received(:establish_connection).exactly(1)
         | 
| 81 | 
            +
                expect(db).to have_received(:load).exactly(1)
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                expect(system.booter.(:db).statuses).to eql(%i[init start])
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
            end
         | 
| @@ -0,0 +1,70 @@ | |
| 1 | 
            +
            require 'dry/system/container'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe Dry::System::Container, '.import' do
         | 
| 4 | 
            +
              subject(:app) { Class.new(Dry::System::Container) }
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              let(:db) do
         | 
| 7 | 
            +
                Class.new(Dry::System::Container) do
         | 
| 8 | 
            +
                  register(:users, %w(jane joe))
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              shared_examples_for 'an extended container' do
         | 
| 13 | 
            +
                it 'imports one container into another' do
         | 
| 14 | 
            +
                  expect(app.key?('persistence.users')).to be(false)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  app.finalize!
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  expect(app['persistence.users']).to eql(%w(jane joe))
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              context 'when a container has a name' do
         | 
| 23 | 
            +
                before do
         | 
| 24 | 
            +
                  db.configure { |c| c.name = :persistence }
         | 
| 25 | 
            +
                  app.import(db)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                it_behaves_like 'an extended container'
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              context 'when container does not have a name' do
         | 
| 32 | 
            +
                before do
         | 
| 33 | 
            +
                  app.import(persistence: db)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                it_behaves_like 'an extended container'
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              describe 'import module' do
         | 
| 40 | 
            +
                it 'loads system when it was not loaded in the imported container yet' do
         | 
| 41 | 
            +
                  class Test::Other < Dry::System::Container
         | 
| 42 | 
            +
                    configure do |config|
         | 
| 43 | 
            +
                      config.root = SPEC_ROOT.join('fixtures/import_test').realpath
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    load_paths!('lib')
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  class Test::Container < Dry::System::Container
         | 
| 50 | 
            +
                    configure do |config|
         | 
| 51 | 
            +
                      config.root = SPEC_ROOT.join('fixtures/test').realpath
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    load_paths!('lib')
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    import other: Test::Other
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  module Test
         | 
| 60 | 
            +
                    Import = Container.injector
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  class Test::Foo
         | 
| 64 | 
            +
                    include Test::Import['other.test.bar']
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  expect(Test::Foo.new.bar).to be_instance_of(Test::Bar)
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            require "dry/system/container"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe Dry::System::Container, ".injector" do
         | 
| 4 | 
            +
              context "injector_options provided" do
         | 
| 5 | 
            +
                it "builds an injector with the provided options" do
         | 
| 6 | 
            +
                  Test::Foo = Class.new
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  Test::Container = Class.new(Dry::System::Container) do
         | 
| 9 | 
            +
                    register "foo", Test::Foo.new
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  Test::Inject = Test::Container.injector(strategies: {
         | 
| 13 | 
            +
                    default: Dry::AutoInject::Strategies::Args,
         | 
| 14 | 
            +
                    australian: Dry::AutoInject::Strategies::Args
         | 
| 15 | 
            +
                  })
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  injected_class = Class.new do
         | 
| 18 | 
            +
                    include Test::Inject.australian["foo"]
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  obj = injected_class.new
         | 
| 22 | 
            +
                  expect(obj.foo).to be_a Test::Foo
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  another = Object.new
         | 
| 25 | 
            +
                  obj = injected_class.new(another)
         | 
| 26 | 
            +
                  expect(obj.foo).to eq another
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,165 @@ | |
| 1 | 
            +
            require 'dry/system/container'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            RSpec.describe Dry::System::Container do
         | 
| 4 | 
            +
              subject(:container) { Test::Container }
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              context 'with default core dir' do
         | 
| 7 | 
            +
                before do
         | 
| 8 | 
            +
                  class Test::Container < Dry::System::Container
         | 
| 9 | 
            +
                    configure do |config|
         | 
| 10 | 
            +
                      config.root = SPEC_ROOT.join('fixtures/test').realpath
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    load_paths!('lib')
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  module Test
         | 
| 17 | 
            +
                    Import = Container.injector
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                describe '.require' do
         | 
| 22 | 
            +
                  it 'requires a single file' do
         | 
| 23 | 
            +
                    container.require(Pathname('lib/test/models'))
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    expect(Test.const_defined?(:Models)).to be(true)
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  it 'requires many files when glob pattern is passed' do
         | 
| 29 | 
            +
                    container.require(Pathname('lib/test/models/*.rb'))
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    expect(Test::Models.const_defined?(:User)).to be(true)
         | 
| 32 | 
            +
                    expect(Test::Models.const_defined?(:Book)).to be(true)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                describe '.require_component' do
         | 
| 37 | 
            +
                  it 'requires component file' do
         | 
| 38 | 
            +
                    component = container.component('test/foo')
         | 
| 39 | 
            +
                    required = false
         | 
| 40 | 
            +
                    container.require_component(component) do
         | 
| 41 | 
            +
                      required = true
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                    expect(required).to be(true)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  it 'raises when file does not exist' do
         | 
| 47 | 
            +
                    component = container.component('test/missing')
         | 
| 48 | 
            +
                    expect { container.require_component(component) }.to raise_error(
         | 
| 49 | 
            +
                      Dry::System::FileNotFoundError, /test\.missing/
         | 
| 50 | 
            +
                    )
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                describe '.load_component' do
         | 
| 55 | 
            +
                  it 'loads and registers systems from configured load paths' do
         | 
| 56 | 
            +
                    container.load_component('test.foo')
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    expect(Test.const_defined?(:Foo)).to be(true)
         | 
| 59 | 
            +
                    expect(Test.const_defined?(:Dep)).to be(true)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    expect(Test::Foo.new.dep).to be_instance_of(Test::Dep)
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  it "raises an error if a system's file can't be found" do
         | 
| 65 | 
            +
                    expect { container.load_component('test.missing') }.to raise_error(
         | 
| 66 | 
            +
                      Dry::System::ComponentLoadError, /test\.missing/
         | 
| 67 | 
            +
                    )
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  it "is a no op if a matching system is already registered" do
         | 
| 71 | 
            +
                    container.register "test.no_matching_file", Object.new
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    expect { container.load_component("test.no_matching_file") }.not_to raise_error
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              describe '.boot' do
         | 
| 79 | 
            +
                before do
         | 
| 80 | 
            +
                  class Test::Container < Dry::System::Container
         | 
| 81 | 
            +
                    configure do |config|
         | 
| 82 | 
            +
                      config.root = SPEC_ROOT.join('fixtures/lazytest').realpath
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    load_paths!('lib')
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                it 'lazy-boot a given system' do
         | 
| 90 | 
            +
                  container.boot(:bar)
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  expect(Test.const_defined?(:Bar)).to be(true)
         | 
| 93 | 
            +
                  expect(container.key?('test.bar')).to be(false)
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              describe '.boot!' do
         | 
| 98 | 
            +
                shared_examples_for 'a booted system' do
         | 
| 99 | 
            +
                  it 'boots a given system and finalizes it' do
         | 
| 100 | 
            +
                    container.boot!(:bar)
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    expect(Test.const_defined?(:Bar)).to be(true)
         | 
| 103 | 
            +
                    expect(container['test.bar']).to eql('I was finalized')
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                  it 'expects a symbol identifier matching file name' do
         | 
| 107 | 
            +
                    expect {
         | 
| 108 | 
            +
                      container.boot!('bar')
         | 
| 109 | 
            +
                    }.to raise_error(ArgumentError, 'component identifier "bar" must be a symbol')
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  it 'expects identifier to point to an existing boot file' do
         | 
| 113 | 
            +
                    expect {
         | 
| 114 | 
            +
                      container.boot!(:foo)
         | 
| 115 | 
            +
                    }.to raise_error(
         | 
| 116 | 
            +
                      ArgumentError,
         | 
| 117 | 
            +
                      'component identifier +foo+ is invalid or boot file is missing'
         | 
| 118 | 
            +
                    )
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                context 'with the default core dir' do
         | 
| 123 | 
            +
                  it_behaves_like 'a booted system' do
         | 
| 124 | 
            +
                    before do
         | 
| 125 | 
            +
                      class Test::Container < Dry::System::Container
         | 
| 126 | 
            +
                        configure do |config|
         | 
| 127 | 
            +
                          config.root = SPEC_ROOT.join('fixtures/test').realpath
         | 
| 128 | 
            +
                        end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                        load_paths!('lib')
         | 
| 131 | 
            +
                      end
         | 
| 132 | 
            +
                    end
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                context 'with a custom core dir' do
         | 
| 137 | 
            +
                  it_behaves_like 'a booted system' do
         | 
| 138 | 
            +
                    before do
         | 
| 139 | 
            +
                      class Test::Container < Dry::System::Container
         | 
| 140 | 
            +
                        configure do |config|
         | 
| 141 | 
            +
                          config.root = SPEC_ROOT.join('fixtures/other').realpath
         | 
| 142 | 
            +
                          config.system_dir = 'config'
         | 
| 143 | 
            +
                        end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                        load_paths!('lib')
         | 
| 146 | 
            +
                      end
         | 
| 147 | 
            +
                    end
         | 
| 148 | 
            +
                  end
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                it 'passes container to the finalizer block' do
         | 
| 152 | 
            +
                  class Test::Container < Dry::System::Container
         | 
| 153 | 
            +
                    configure { |c| c.name = :awesome }
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                    finalize(:foo) do |container|
         | 
| 156 | 
            +
                      register(:w00t, container.config.name)
         | 
| 157 | 
            +
                    end
         | 
| 158 | 
            +
                  end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                  Test::Container.booter.(:foo)
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                  expect(Test::Container[:w00t]).to be(:awesome)
         | 
| 163 | 
            +
                end
         | 
| 164 | 
            +
              end
         | 
| 165 | 
            +
            end
         | 
| @@ -0,0 +1,72 @@ | |
| 1 | 
            +
            RSpec.describe Dry::System::Injector do
         | 
| 2 | 
            +
              before do
         | 
| 3 | 
            +
                class Test::Container < Dry::System::Container
         | 
| 4 | 
            +
                  configure do |config|
         | 
| 5 | 
            +
                    config.root = SPEC_ROOT.join('fixtures/test').realpath
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  load_paths! 'lib'
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                Test::Inject = Test::Container.injector
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              it 'supports args injection by default' do
         | 
| 15 | 
            +
                obj = Class.new do
         | 
| 16 | 
            +
                  include Test::Inject['test.dep']
         | 
| 17 | 
            +
                end.new
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                expect(obj.dep).to be_a Test::Dep
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              it 'supports args injection with explicit method' do
         | 
| 23 | 
            +
                obj = Class.new do
         | 
| 24 | 
            +
                  include Test::Inject.args['test.dep']
         | 
| 25 | 
            +
                end.new
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                expect(obj.dep).to be_a Test::Dep
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              it 'supports hash injection' do
         | 
| 31 | 
            +
                obj = Class.new do
         | 
| 32 | 
            +
                  include Test::Inject.hash['test.dep']
         | 
| 33 | 
            +
                end.new
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                expect(obj.dep).to be_a Test::Dep
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              it 'support kwargs injection' do
         | 
| 39 | 
            +
                obj = Class.new do
         | 
| 40 | 
            +
                  include Test::Inject.kwargs['test.dep']
         | 
| 41 | 
            +
                end.new
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                expect(obj.dep).to be_a Test::Dep
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              it 'allows injection strategies to be swapped' do
         | 
| 47 | 
            +
                obj = Class.new do
         | 
| 48 | 
            +
                  include Test::Inject.kwargs.hash['test.dep']
         | 
| 49 | 
            +
                end.new
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                expect(obj.dep).to be_a Test::Dep
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              it 'supports aliases' do
         | 
| 55 | 
            +
                obj = Class.new do
         | 
| 56 | 
            +
                  include Test::Inject['test.dep', foo: 'test.dep']
         | 
| 57 | 
            +
                end.new
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                expect(obj.dep).to be_a Test::Dep
         | 
| 60 | 
            +
                expect(obj.foo).to be_a Test::Dep
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              context 'singleton' do
         | 
| 64 | 
            +
                it 'supports injection' do
         | 
| 65 | 
            +
                  obj = Class.new do
         | 
| 66 | 
            +
                    include Test::Inject[foo: 'test.singleton_dep']
         | 
| 67 | 
            +
                  end.new
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  expect(obj.foo).to be_a Test::SingletonDep
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
            end
         | 
| @@ -0,0 +1,64 @@ | |
| 1 | 
            +
            require 'dry/system/loader'
         | 
| 2 | 
            +
            require 'singleton'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            RSpec.describe Dry::System::Loader, '#call' do
         | 
| 5 | 
            +
              shared_examples_for 'object loader' do
         | 
| 6 | 
            +
                let(:instance) { loader.call }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                context 'not singleton' do
         | 
| 9 | 
            +
                  it 'returns a new instance of the constant' do
         | 
| 10 | 
            +
                    expect(instance).to be_instance_of(constant)
         | 
| 11 | 
            +
                    expect(instance).not_to be(loader.call)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                context 'singleton' do
         | 
| 16 | 
            +
                  before { constant.send(:include, Singleton) }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  it 'returns singleton instance' do
         | 
| 19 | 
            +
                    expect(instance).to be(constant.instance)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              context 'with a singular name' do
         | 
| 25 | 
            +
                subject(:loader) { Dry::System::Loader.new('test/bar') }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                let(:constant) { Test::Bar }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                before do
         | 
| 30 | 
            +
                  module Test;class Bar;end;end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                it_behaves_like 'object loader'
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              context 'with a plural name' do
         | 
| 37 | 
            +
                subject(:loader) { Dry::System::Loader.new('test/bars') }
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                let(:constant) { Test::Bars }
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                before do
         | 
| 42 | 
            +
                  module Test;class Bars;end;end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                it_behaves_like 'object loader'
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              context 'with a constructor accepting args' do
         | 
| 49 | 
            +
                subject(:loader) { Dry::System::Loader.new('test/bar') }
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                before do
         | 
| 52 | 
            +
                  module Test
         | 
| 53 | 
            +
                    Bar = Struct.new(:one, :two)
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                it 'passes args to the constructor' do
         | 
| 58 | 
            +
                  instance = loader.call(1, 2)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  expect(instance.one).to be(1)
         | 
| 61 | 
            +
                  expect(instance.two).to be(2)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         |