smart_container 0.2.0 → 0.7.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 +4 -4
- data/.rubocop.yml +2 -2
- data/.travis.yml +7 -13
- data/CHANGELOG.md +30 -15
- data/Gemfile.lock +46 -31
- data/README.md +185 -6
- data/Rakefile +2 -1
- data/lib/smart_core/container.rb +84 -2
- data/lib/smart_core/container/definition_dsl.rb +6 -2
- data/lib/smart_core/container/definition_dsl/commands/definition/register.rb +1 -1
- data/lib/smart_core/container/dependency_resolver.rb +79 -8
- data/lib/smart_core/container/dependency_resolver/route.rb +5 -8
- data/lib/smart_core/container/errors.rb +2 -1
- data/lib/smart_core/container/registry.rb +98 -5
- data/lib/smart_core/container/version.rb +2 -2
- data/smart_container.gemspec +5 -5
- metadata +11 -11
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 3e536932a27a4bcf2ded83ea750978459e8dbf6a34ea35dfac8ef7008db3240d
         | 
| 4 | 
            +
              data.tar.gz: 2566b21ef936d31bab5ff8eb6d6d51cd6510db97acf62d9dc55992915094a962
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d1c443404d20ac8c6f61ea8bf6d37db0acd4e1131626ca00c75bf26f695262f275ee6814aab3ecd4b0a4c17b4d3f50ae449abb6932e658f0cc325e3e87cba8ea
         | 
| 7 | 
            +
              data.tar.gz: 587dac41ae390e811802ca6c5a6a4610d81d4b7cecd1d5de224a409b1724edf180c98d78acc1a81cd9bc06010343d5a42f769acd219d12d395bef06c4f9420c6
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/.travis.yml
    CHANGED
    
    | @@ -1,28 +1,22 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            language: ruby
         | 
| 3 3 | 
             
            cache: bundler
         | 
| 4 | 
            +
            os: linux
         | 
| 5 | 
            +
            dist: xenial
         | 
| 4 6 | 
             
            before_install:
         | 
| 5 | 
            -
            - gem install bundler | 
| 7 | 
            +
            - gem install bundler
         | 
| 6 8 | 
             
            script:
         | 
| 7 9 | 
             
            - bundle exec rake rubocop
         | 
| 8 10 | 
             
            - bundle exec rake rspec
         | 
| 9 11 | 
             
            jobs:
         | 
| 10 12 | 
             
              fast_finish: true
         | 
| 11 13 | 
             
              include:
         | 
| 12 | 
            -
              - rvm: 2.4. | 
| 13 | 
            -
             | 
| 14 | 
            -
              - rvm: 2. | 
| 15 | 
            -
             | 
| 16 | 
            -
              - rvm: 2.6.5
         | 
| 17 | 
            -
                os: [linux, osx]
         | 
| 18 | 
            -
              - rvm: 2.7.0
         | 
| 19 | 
            -
                os: [linux, osx]
         | 
| 14 | 
            +
              - rvm: 2.4.10
         | 
| 15 | 
            +
              - rvm: 2.5.8
         | 
| 16 | 
            +
              - rvm: 2.6.6
         | 
| 17 | 
            +
              - rvm: 2.7.1
         | 
| 20 18 | 
             
              - rvm: ruby-head
         | 
| 21 | 
            -
                os: [linux, osx]
         | 
| 22 19 | 
             
              - rvm: jruby-head
         | 
| 23 | 
            -
                os: [linux, osx]
         | 
| 24 20 | 
             
              allow_failures:
         | 
| 25 21 | 
             
              - rvm: ruby-head
         | 
| 26 | 
            -
                os: [linux, osx]
         | 
| 27 22 | 
             
              - rvm: jruby-head
         | 
| 28 | 
            -
                os: [linux, osx]
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,25 +1,40 @@ | |
| 1 1 | 
             
            # Changelog
         | 
| 2 2 | 
             
            All notable changes to this project will be documented in this file.
         | 
| 3 3 |  | 
| 4 | 
            -
            ## [0. | 
| 4 | 
            +
            ## [0.7.0] - 2020-06-20
         | 
| 5 | 
            +
            ### Added
         | 
| 6 | 
            +
            - `SmartCore::Container.define {}` - an ability to avoid explicit class definition that allows
         | 
| 7 | 
            +
              to create container instances from an anonymous container class imidietly
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## [0.6.0] - 2020-01-12
         | 
| 10 | 
            +
            ### Added
         | 
| 11 | 
            +
            - Missing memoization flag `:memoize` for runtime-based dependency registration:
         | 
| 12 | 
            +
              - `memoize: false` by default;
         | 
| 13 | 
            +
              - signature: `SmartCore::Container#register(dependency_name, memoize: false, &dependency)`
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ## [0.5.0] - 2020-01-07
         | 
| 16 | 
            +
            ### Added
         | 
| 17 | 
            +
            - Key predicates (`#key?(key)`, `#dependency?(path, memoized: nil/true/false)`, `#namespace?(path)`);
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ## [0.4.0] - 2020-01-06
         | 
| 20 | 
            +
            ### Added
         | 
| 21 | 
            +
            - `#keys(all_variants: false)` - return a list of dependency keys
         | 
| 22 | 
            +
              (`all_variants: true` is mean "including namespace kaeys");
         | 
| 23 | 
            +
            - `#each_dependency(yield_all: false) { |key, value| }` - iterate over conteiner's dependencies
         | 
| 24 | 
            +
              (`yield_all: true` will include nested containers to iteration process);
         | 
| 25 | 
            +
            ### Fixed
         | 
| 26 | 
            +
            - `SmartCore::Container::ResolvingError` class has incorrect message attribute name;
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            ## [0.3.0] - 2020-01-05
         | 
| 29 | 
            +
            ### Changed
         | 
| 30 | 
            +
            - Dependency resolving is not memoized by default (previously: totally memoized 😱);
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            ## [0.2.0] - 2020-01-05
         | 
| 5 33 | 
             
            ### Changed
         | 
| 6 34 | 
             
            - (Private API (`SmartCore::Container::RegistryBuilder`)) improved semantics:
         | 
| 7 35 | 
             
              - `build_state` is renamed to `initialise`;
         | 
| 8 36 | 
             
              - `build_definitions` is renamed to `define`;
         | 
| 9 | 
            -
            - (Public API) Support for memoized dependencies (all dependencies are memoized by default)
         | 
| 10 | 
            -
              ```ruby
         | 
| 11 | 
            -
              class MyContainer < SmartCore::Container
         | 
| 12 | 
            -
                namespace(:some_naespace) do
         | 
| 13 | 
            -
                  # memoized by default
         | 
| 14 | 
            -
                  register(:random_number) { rand(1000) }
         | 
| 15 | 
            -
                  # explicit memoization
         | 
| 16 | 
            -
                  register(:random_number, memoized: true) { rand(1000) }
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  # register non-memoizable dependency
         | 
| 19 | 
            -
                  register(:random_number, memoized: false) { rand(1000) }
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
              end
         | 
| 22 | 
            -
              ```
         | 
| 37 | 
            +
            - (Public API) Support for memoized dependencies (all dependencies are memoized by default);
         | 
| 23 38 |  | 
| 24 39 | 
             
            ## [0.1.0] - 2020-01-02
         | 
| 25 40 |  | 
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,83 +1,98 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                smart_container (0. | 
| 5 | 
            -
                  smart_engine (~> 0. | 
| 4 | 
            +
                smart_container (0.6.0)
         | 
| 5 | 
            +
                  smart_engine (~> 0.5)
         | 
| 6 6 |  | 
| 7 7 | 
             
            GEM
         | 
| 8 8 | 
             
              remote: https://rubygems.org/
         | 
| 9 9 | 
             
              specs:
         | 
| 10 | 
            -
                 | 
| 11 | 
            -
                   | 
| 10 | 
            +
                activesupport (6.0.2.2)
         | 
| 11 | 
            +
                  concurrent-ruby (~> 1.0, >= 1.0.2)
         | 
| 12 | 
            +
                  i18n (>= 0.7, < 2)
         | 
| 13 | 
            +
                  minitest (~> 5.1)
         | 
| 14 | 
            +
                  tzinfo (~> 1.1)
         | 
| 15 | 
            +
                  zeitwerk (~> 2.2)
         | 
| 16 | 
            +
                armitage-rubocop (0.81.0)
         | 
| 17 | 
            +
                  rubocop (= 0.81.0)
         | 
| 12 18 | 
             
                  rubocop-performance (= 1.5.2)
         | 
| 13 | 
            -
                  rubocop-rails (= 2. | 
| 14 | 
            -
                  rubocop-rake (= 0.5. | 
| 15 | 
            -
                  rubocop-rspec (= 1. | 
| 19 | 
            +
                  rubocop-rails (= 2.5.2)
         | 
| 20 | 
            +
                  rubocop-rake (= 0.5.1)
         | 
| 21 | 
            +
                  rubocop-rspec (= 1.38.1)
         | 
| 16 22 | 
             
                ast (2.4.0)
         | 
| 17 23 | 
             
                coderay (1.1.2)
         | 
| 24 | 
            +
                concurrent-ruby (1.1.6)
         | 
| 18 25 | 
             
                diff-lcs (1.3)
         | 
| 19 26 | 
             
                docile (1.3.2)
         | 
| 27 | 
            +
                i18n (1.8.2)
         | 
| 28 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 20 29 | 
             
                jaro_winkler (1.5.4)
         | 
| 21 | 
            -
                 | 
| 22 | 
            -
                 | 
| 30 | 
            +
                method_source (1.0.0)
         | 
| 31 | 
            +
                minitest (5.14.0)
         | 
| 23 32 | 
             
                parallel (1.19.1)
         | 
| 24 | 
            -
                parser (2.7.0 | 
| 33 | 
            +
                parser (2.7.1.0)
         | 
| 25 34 | 
             
                  ast (~> 2.4.0)
         | 
| 26 | 
            -
                pry (0. | 
| 27 | 
            -
                  coderay (~> 1.1 | 
| 28 | 
            -
                  method_source (~>  | 
| 29 | 
            -
                rack (2. | 
| 35 | 
            +
                pry (0.13.1)
         | 
| 36 | 
            +
                  coderay (~> 1.1)
         | 
| 37 | 
            +
                  method_source (~> 1.0)
         | 
| 38 | 
            +
                rack (2.2.2)
         | 
| 30 39 | 
             
                rainbow (3.0.0)
         | 
| 31 40 | 
             
                rake (13.0.1)
         | 
| 41 | 
            +
                rexml (3.2.4)
         | 
| 32 42 | 
             
                rspec (3.9.0)
         | 
| 33 43 | 
             
                  rspec-core (~> 3.9.0)
         | 
| 34 44 | 
             
                  rspec-expectations (~> 3.9.0)
         | 
| 35 45 | 
             
                  rspec-mocks (~> 3.9.0)
         | 
| 36 46 | 
             
                rspec-core (3.9.1)
         | 
| 37 47 | 
             
                  rspec-support (~> 3.9.1)
         | 
| 38 | 
            -
                rspec-expectations (3.9. | 
| 48 | 
            +
                rspec-expectations (3.9.1)
         | 
| 39 49 | 
             
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 40 50 | 
             
                  rspec-support (~> 3.9.0)
         | 
| 41 51 | 
             
                rspec-mocks (3.9.1)
         | 
| 42 52 | 
             
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 43 53 | 
             
                  rspec-support (~> 3.9.0)
         | 
| 44 54 | 
             
                rspec-support (3.9.2)
         | 
| 45 | 
            -
                rubocop (0. | 
| 55 | 
            +
                rubocop (0.81.0)
         | 
| 46 56 | 
             
                  jaro_winkler (~> 1.5.1)
         | 
| 47 57 | 
             
                  parallel (~> 1.10)
         | 
| 48 | 
            -
                  parser (>= 2. | 
| 58 | 
            +
                  parser (>= 2.7.0.1)
         | 
| 49 59 | 
             
                  rainbow (>= 2.2.2, < 4.0)
         | 
| 60 | 
            +
                  rexml
         | 
| 50 61 | 
             
                  ruby-progressbar (~> 1.7)
         | 
| 51 | 
            -
                  unicode-display_width (>= 1.4.0, <  | 
| 62 | 
            +
                  unicode-display_width (>= 1.4.0, < 2.0)
         | 
| 52 63 | 
             
                rubocop-performance (1.5.2)
         | 
| 53 64 | 
             
                  rubocop (>= 0.71.0)
         | 
| 54 | 
            -
                rubocop-rails (2. | 
| 65 | 
            +
                rubocop-rails (2.5.2)
         | 
| 66 | 
            +
                  activesupport
         | 
| 55 67 | 
             
                  rack (>= 1.1)
         | 
| 56 68 | 
             
                  rubocop (>= 0.72.0)
         | 
| 57 | 
            -
                rubocop-rake (0.5. | 
| 69 | 
            +
                rubocop-rake (0.5.1)
         | 
| 58 70 | 
             
                  rubocop
         | 
| 59 | 
            -
                rubocop-rspec (1. | 
| 71 | 
            +
                rubocop-rspec (1.38.1)
         | 
| 60 72 | 
             
                  rubocop (>= 0.68.1)
         | 
| 61 73 | 
             
                ruby-progressbar (1.10.1)
         | 
| 62 | 
            -
                simplecov (0. | 
| 74 | 
            +
                simplecov (0.18.5)
         | 
| 63 75 | 
             
                  docile (~> 1.1)
         | 
| 64 | 
            -
                   | 
| 65 | 
            -
             | 
| 66 | 
            -
                 | 
| 67 | 
            -
                 | 
| 68 | 
            -
                 | 
| 76 | 
            +
                  simplecov-html (~> 0.11)
         | 
| 77 | 
            +
                simplecov-html (0.12.2)
         | 
| 78 | 
            +
                smart_engine (0.5.0)
         | 
| 79 | 
            +
                thread_safe (0.3.6)
         | 
| 80 | 
            +
                tzinfo (1.2.7)
         | 
| 81 | 
            +
                  thread_safe (~> 0.1)
         | 
| 82 | 
            +
                unicode-display_width (1.7.0)
         | 
| 83 | 
            +
                zeitwerk (2.3.0)
         | 
| 69 84 |  | 
| 70 85 | 
             
            PLATFORMS
         | 
| 71 86 | 
             
              ruby
         | 
| 72 87 |  | 
| 73 88 | 
             
            DEPENDENCIES
         | 
| 74 | 
            -
              armitage-rubocop (~> 0. | 
| 89 | 
            +
              armitage-rubocop (~> 0.81)
         | 
| 75 90 | 
             
              bundler (~> 2.1)
         | 
| 76 | 
            -
              pry (~> 0. | 
| 91 | 
            +
              pry (~> 0.13)
         | 
| 77 92 | 
             
              rake (~> 13.0)
         | 
| 78 93 | 
             
              rspec (~> 3.9)
         | 
| 79 | 
            -
              simplecov (~> 0. | 
| 94 | 
            +
              simplecov (~> 0.18)
         | 
| 80 95 | 
             
              smart_container!
         | 
| 81 96 |  | 
| 82 97 | 
             
            BUNDLED WITH
         | 
| 83 | 
            -
               2.1. | 
| 98 | 
            +
               2.1.4
         | 
    
        data/README.md
    CHANGED
    
    | @@ -24,35 +24,214 @@ require 'smart_core/container' | |
| 24 24 |  | 
| 25 25 | 
             
            ## Synopsis (demo)
         | 
| 26 26 |  | 
| 27 | 
            +
            - container class creation:
         | 
| 28 | 
            +
             | 
| 27 29 | 
             
            ```ruby
         | 
| 28 30 | 
             
            class Container < SmartCore::Container
         | 
| 29 31 | 
             
              namespace(:database) do # support for namespaces
         | 
| 30 | 
            -
                register(:resolver) { SomeDatabaseResolver.new } # dependency registration
         | 
| 32 | 
            +
                register(:resolver, memoize: true) { SomeDatabaseResolver.new } # dependency registration
         | 
| 31 33 |  | 
| 32 34 | 
             
                namespace(:cache) do # support for nested naespaces
         | 
| 33 | 
            -
                  register(:memcached) { MemcachedClient.new }
         | 
| 34 | 
            -
                  register(:redis) { RedisClient.new }
         | 
| 35 | 
            +
                  register(:memcached, memoize: true) { MemcachedClient.new }
         | 
| 36 | 
            +
                  register(:redis, memoize: true) { RedisClient.new }
         | 
| 35 37 | 
             
                end
         | 
| 36 38 | 
             
              end
         | 
| 37 39 |  | 
| 38 40 | 
             
              # root dependencies
         | 
| 39 | 
            -
              register(:logger) { Logger.new(STDOUT) }
         | 
| 41 | 
            +
              register(:logger, memoize: true) { Logger.new(STDOUT) }
         | 
| 40 42 |  | 
| 41 | 
            -
              #  | 
| 42 | 
            -
              register(:random | 
| 43 | 
            +
              # dependencies are not memoized by default (memoize: false)
         | 
| 44 | 
            +
              register(:random) { rand(1000) }
         | 
| 43 45 | 
             
            end
         | 
| 46 | 
            +
            ```
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            - mixin:
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            ```ruby
         | 
| 51 | 
            +
            # full documentaiton is coming;
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            class Application
         | 
| 54 | 
            +
              include SmartCore::Container::Mixin
         | 
| 44 55 |  | 
| 56 | 
            +
              dependencies do
         | 
| 57 | 
            +
                namespace(:database) do
         | 
| 58 | 
            +
                  register(:cache) { MemcachedClient.new }
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            # access:
         | 
| 64 | 
            +
            Application.container
         | 
| 65 | 
            +
            Application.new.container # NOTE: the same instance as Application.container
         | 
| 66 | 
            +
            ```
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            - container instantiation and dependency resolving:
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            ```ruby
         | 
| 45 71 | 
             
            container = Container.new # create container instance
         | 
| 72 | 
            +
            ```
         | 
| 46 73 |  | 
| 74 | 
            +
            ```ruby
         | 
| 47 75 | 
             
            container['database.resolver'] # => #<SomeDatabaseResolver:0x00007f0f0f1d6332>
         | 
| 48 76 | 
             
            container['database.cache.redis'] # => #<RedisClient:0x00007f0f0f1d0158>
         | 
| 49 77 | 
             
            container['logger'] # => #<Logger:0x00007f5f0f2f0158>
         | 
| 50 78 |  | 
| 79 | 
            +
            container.resolve('logger') # #resolve(path) is an alias for #[](path)
         | 
| 80 | 
            +
             | 
| 51 81 | 
             
            # non-memoized dependency
         | 
| 52 82 | 
             
            container['random'] # => 352
         | 
| 53 83 | 
             
            container['random'] # => 57
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            # trying to resolve a namespace as dependency
         | 
| 86 | 
            +
            container['database'] # => SmartCore::Container::ResolvingError
         | 
| 87 | 
            +
             | 
| 88 | 
            +
            # but you can fetch any depenendency type (internal containers and values) via #fetch
         | 
| 89 | 
            +
            container.fetch('database') # => SmartCore::Container (nested container)
         | 
| 90 | 
            +
            container.fetch('database.resolver') # => #<SomeDatabaseResolver:0x00007f0f0f1d6332>
         | 
| 91 | 
            +
            ```
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            - runtime-level dependency/namespace registration:
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            ```ruby
         | 
| 96 | 
            +
            container.namespace(:api) do
         | 
| 97 | 
            +
              register(:provider) { GoogleProvider } # without memoization
         | 
| 98 | 
            +
            end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            container.register('game_api', memoize: true) { 'overwatch' } # with memoization
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            container['api.provider'] # => GoogleProvider
         | 
| 103 | 
            +
            container['game_api'] # => 'overwatch'
         | 
| 104 | 
            +
            ```
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            - container keys (dependency names):
         | 
| 107 | 
            +
             | 
| 108 | 
            +
            ```ruby
         | 
| 109 | 
            +
            # get dependnecy keys (only dependencies)
         | 
| 110 | 
            +
            container.keys
         | 
| 111 | 
            +
            # => result:
         | 
| 112 | 
            +
            [
         | 
| 113 | 
            +
              'database.resolver',
         | 
| 114 | 
            +
              'database.cache.memcached',
         | 
| 115 | 
            +
              'database.cache.redis',
         | 
| 116 | 
            +
              'logger',
         | 
| 117 | 
            +
              'random'
         | 
| 118 | 
            +
            ]
         | 
| 119 | 
            +
            ```
         | 
| 120 | 
            +
            ```ruby
         | 
| 121 | 
            +
            # get all keys (namespaces and dependencies)
         | 
| 122 | 
            +
            container.keys(all_variants: true)
         | 
| 123 | 
            +
            # => result:
         | 
| 124 | 
            +
            [
         | 
| 125 | 
            +
              'database', # namespace
         | 
| 126 | 
            +
              'database.resolver',
         | 
| 127 | 
            +
              'database.cache', # namespace
         | 
| 128 | 
            +
              'database.cache.memcached',
         | 
| 129 | 
            +
              'database.cache.redis',
         | 
| 130 | 
            +
              'logger',
         | 
| 131 | 
            +
              'random'
         | 
| 132 | 
            +
            ]
         | 
| 54 133 | 
             
            ```
         | 
| 55 134 |  | 
| 135 | 
            +
            - key predicates:
         | 
| 136 | 
            +
              - `key?(key)` - has dependency or namespace?
         | 
| 137 | 
            +
              - `namespace?(path)` - has namespace?
         | 
| 138 | 
            +
              - `dependency?(path)` - has dependency?
         | 
| 139 | 
            +
              - `dependency?(path, memoized: true)` - has memoized dependency?
         | 
| 140 | 
            +
              - `dependency?(path, memoized: false)` - has non-memoized dependency?
         | 
| 141 | 
            +
             | 
| 142 | 
            +
            ```ruby
         | 
| 143 | 
            +
            container.key?('database') # => true
         | 
| 144 | 
            +
            container.key?('database.cache.memcached') # => true
         | 
| 145 | 
            +
             | 
| 146 | 
            +
            container.dependency?('database') # => false
         | 
| 147 | 
            +
            container.dependency?('database.resolver') # => true
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            container.namespace?('database') # => true
         | 
| 150 | 
            +
            container.namespace?('database.resolver') # => false
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            container.dependency?('database.resolver', memoized: true) # => true
         | 
| 153 | 
            +
            container.dependency?('database.resolver', memoized: false) # => false
         | 
| 154 | 
            +
             | 
| 155 | 
            +
            container.dependency?('random', memoized: true) # => false
         | 
| 156 | 
            +
            container.dependency?('random', memoized: false) # => true
         | 
| 157 | 
            +
            ```
         | 
| 158 | 
            +
             | 
| 159 | 
            +
            - state freeze (`#freeze!`, `.#frozen?`):
         | 
| 160 | 
            +
             | 
| 161 | 
            +
            ```ruby
         | 
| 162 | 
            +
            # documentation is coming;
         | 
| 163 | 
            +
            ```
         | 
| 164 | 
            +
             | 
| 165 | 
            +
            - reloading (`#reload!):
         | 
| 166 | 
            +
             | 
| 167 | 
            +
            ```ruby
         | 
| 168 | 
            +
            # documentation is coming;
         | 
| 169 | 
            +
            ```
         | 
| 170 | 
            +
             | 
| 171 | 
            +
            - hash tree (`#hash_tree`, `#hash_tree(resolve_dependencies: true)`):
         | 
| 172 | 
            +
             | 
| 173 | 
            +
            ```ruby
         | 
| 174 | 
            +
            # documentation is coming`;
         | 
| 175 | 
            +
            ```
         | 
| 176 | 
            +
             | 
| 177 | 
            +
            - `SmartCore::Container.define` - avoid explicit class definition (allows to create container instance from an anonymous container class immidietly):
         | 
| 178 | 
            +
             | 
| 179 | 
            +
            ```ruby
         | 
| 180 | 
            +
            # - create from empty container class -
         | 
| 181 | 
            +
             | 
| 182 | 
            +
            AppContainer = SmartCore::Container.define do
         | 
| 183 | 
            +
              namespace :database do
         | 
| 184 | 
            +
                register(:logger) { Logger.new }
         | 
| 185 | 
            +
              end
         | 
| 186 | 
            +
            end # => an instance of Class<SmartCore::Container>
         | 
| 187 | 
            +
             | 
| 188 | 
            +
            AppContainer.resolve('database.logger') # => #<Logger:0x00007f5f0f2f0158>
         | 
| 189 | 
            +
            AppContainer['database.logger'] # => #<Logger:0x00007f5f0f2f0158>
         | 
| 190 | 
            +
            ```
         | 
| 191 | 
            +
             | 
| 192 | 
            +
            ```ruby
         | 
| 193 | 
            +
            # - create from another container class with a custom sub-definitions -
         | 
| 194 | 
            +
             | 
| 195 | 
            +
            class BasicContainer < SmartCore::Container
         | 
| 196 | 
            +
              namespace(:api) do
         | 
| 197 | 
            +
                register(:client) { Kickbox.new }
         | 
| 198 | 
            +
              end
         | 
| 199 | 
            +
            end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
            AppContainer = BasicContainer.define do
         | 
| 202 | 
            +
              register(:db_driver) { Sequel }
         | 
| 203 | 
            +
            end
         | 
| 204 | 
            +
            # --- or ---
         | 
| 205 | 
            +
            AppContainer = SmartCore::Container.define(BasicContainer) do
         | 
| 206 | 
            +
              register(:db_driver) { Sequel }
         | 
| 207 | 
            +
            end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
            AppContainer['api.client'] # => #<Kickbox:0x00007f5f0f2f0158> (BasicContainer dependency)
         | 
| 210 | 
            +
            AppContainer['db_driver'] # => Sequel (AppContainer dependency)
         | 
| 211 | 
            +
            ```
         | 
| 212 | 
            +
             | 
| 213 | 
            +
            ---
         | 
| 214 | 
            +
             | 
| 215 | 
            +
            ## Roadmap
         | 
| 216 | 
            +
             | 
| 217 | 
            +
            - support for instant dependency registration:
         | 
| 218 | 
            +
             | 
| 219 | 
            +
            ```ruby
         | 
| 220 | 
            +
            # common (dynamic) way:
         | 
| 221 | 
            +
            register('dependency_name') { dependency_value }
         | 
| 222 | 
            +
             | 
| 223 | 
            +
            # instant way:
         | 
| 224 | 
            +
            register('dependency_name', dependency_value)
         | 
| 225 | 
            +
            ```
         | 
| 226 | 
            +
             | 
| 227 | 
            +
            - support for memoization ignorance during dependency resolving:
         | 
| 228 | 
            +
             | 
| 229 | 
            +
            ```ruby
         | 
| 230 | 
            +
            resolve('logger', :allocate) # Draft
         | 
| 231 | 
            +
            ```
         | 
| 232 | 
            +
             | 
| 233 | 
            +
            - container composition;
         | 
| 234 | 
            +
             | 
| 56 235 | 
             
            ---
         | 
| 57 236 |  | 
| 58 237 | 
             
            ## Contributing
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -4,6 +4,7 @@ require 'bundler/gem_tasks' | |
| 4 4 | 
             
            require 'rspec/core/rake_task'
         | 
| 5 5 | 
             
            require 'rubocop'
         | 
| 6 6 | 
             
            require 'rubocop/rake_task'
         | 
| 7 | 
            +
            require 'rubocop-rails'
         | 
| 7 8 | 
             
            require 'rubocop-performance'
         | 
| 8 9 | 
             
            require 'rubocop-rspec'
         | 
| 9 10 | 
             
            require 'rubocop-rake'
         | 
| @@ -11,8 +12,8 @@ require 'rubocop-rake' | |
| 11 12 | 
             
            RuboCop::RakeTask.new(:rubocop) do |t|
         | 
| 12 13 | 
             
              config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
         | 
| 13 14 | 
             
              t.options = ['--config', config_path]
         | 
| 14 | 
            -
              t.requires << 'rubocop-performance'
         | 
| 15 15 | 
             
              t.requires << 'rubocop-rspec'
         | 
| 16 | 
            +
              t.requires << 'rubocop-performance'
         | 
| 16 17 | 
             
              t.requires << 'rubocop-rake'
         | 
| 17 18 | 
             
            end
         | 
| 18 19 |  | 
    
        data/lib/smart_core/container.rb
    CHANGED
    
    | @@ -20,6 +20,27 @@ module SmartCore | |
| 20 20 | 
             
                require_relative 'container/dependency_resolver'
         | 
| 21 21 | 
             
                require_relative 'container/mixin'
         | 
| 22 22 |  | 
| 23 | 
            +
                class << self
         | 
| 24 | 
            +
                  # @param initial_container_klass [Class<SmartCore::Container>]
         | 
| 25 | 
            +
                  # @param container_definitions [Block]
         | 
| 26 | 
            +
                  # @return [SmartCore::Container]
         | 
| 27 | 
            +
                  #
         | 
| 28 | 
            +
                  # @api public
         | 
| 29 | 
            +
                  # @since 0.7.0
         | 
| 30 | 
            +
                  def define(initial_container_klass = self, &container_definitions)
         | 
| 31 | 
            +
                    unless initial_container_klass <= SmartCore::Container
         | 
| 32 | 
            +
                      raise(SmartCore::Container::ArgumentError, <<~ERROR_MESSAGE)
         | 
| 33 | 
            +
                        Base class should be a type of SmartCore::Container
         | 
| 34 | 
            +
                      ERROR_MESSAGE
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    Class.new(initial_container_klass, &container_definitions).new
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                # @since 0.4.0
         | 
| 42 | 
            +
                include ::Enumerable
         | 
| 43 | 
            +
             | 
| 23 44 | 
             
                # @since 0.1.0
         | 
| 24 45 | 
             
                include DefinitionDSL
         | 
| 25 46 |  | 
| @@ -44,8 +65,14 @@ module SmartCore | |
| 44 65 | 
             
                #
         | 
| 45 66 | 
             
                # @api public
         | 
| 46 67 | 
             
                # @sicne 0.1.0
         | 
| 47 | 
            -
                def register( | 
| 48 | 
            -
                   | 
| 68 | 
            +
                def register(
         | 
| 69 | 
            +
                  dependency_name,
         | 
| 70 | 
            +
                  memoize: SmartCore::Container::Registry::DEFAULT_MEMOIZATION_BEHAVIOR,
         | 
| 71 | 
            +
                  &dependency_definition
         | 
| 72 | 
            +
                )
         | 
| 73 | 
            +
                  thread_safe do
         | 
| 74 | 
            +
                    registry.register_dependency(dependency_name, memoize: memoize, &dependency_definition)
         | 
| 75 | 
            +
                  end
         | 
| 49 76 | 
             
                end
         | 
| 50 77 |  | 
| 51 78 | 
             
                # @param namespace_name [String, Symbol]
         | 
| @@ -102,6 +129,61 @@ module SmartCore | |
| 102 129 | 
             
                  thread_safe { build_registry! }
         | 
| 103 130 | 
             
                end
         | 
| 104 131 |  | 
| 132 | 
            +
                # @option all_variants [Boolean]
         | 
| 133 | 
            +
                # @return [Array<String>]
         | 
| 134 | 
            +
                #
         | 
| 135 | 
            +
                # @api public
         | 
| 136 | 
            +
                # @since 0.4.0
         | 
| 137 | 
            +
                def keys(all_variants: SmartCore::Container::Registry::DEFAULT_KEY_EXTRACTION_BEHAVIOUR)
         | 
| 138 | 
            +
                  thread_safe { registry.keys(all_variants: all_variants) }
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                # @param key [String, Symbol]
         | 
| 142 | 
            +
                # @return [Boolean]
         | 
| 143 | 
            +
                #
         | 
| 144 | 
            +
                # @api public
         | 
| 145 | 
            +
                # @since 0.5.0
         | 
| 146 | 
            +
                def key?(key)
         | 
| 147 | 
            +
                  thread_safe { DependencyResolver.key?(self, key) }
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                # @param namespace_path [String, Symbol]
         | 
| 151 | 
            +
                # @return [Boolean]
         | 
| 152 | 
            +
                #
         | 
| 153 | 
            +
                # @api public
         | 
| 154 | 
            +
                # @since 0.5.0
         | 
| 155 | 
            +
                def namespace?(namespace_path)
         | 
| 156 | 
            +
                  thread_safe { DependencyResolver.namespace?(self, namespace_path) }
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                # @param dependency_path [String, Symbol]
         | 
| 160 | 
            +
                # @option memoized [NilClass, Boolean]
         | 
| 161 | 
            +
                # @return [Boolean]
         | 
| 162 | 
            +
                #
         | 
| 163 | 
            +
                # @api public
         | 
| 164 | 
            +
                # @since 0.5.0
         | 
| 165 | 
            +
                def dependency?(dependency_path, memoized: nil)
         | 
| 166 | 
            +
                  thread_safe { DependencyResolver.dependency?(self, dependency_path, memoized: memoized) }
         | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                # @option yield_all [Boolean]
         | 
| 170 | 
            +
                # @param block [Block]
         | 
| 171 | 
            +
                # @yield [dependency_name, dependency_value]
         | 
| 172 | 
            +
                # @yield_param dependency_name [String]
         | 
| 173 | 
            +
                # @yield_param dependency_value [Any, SmartCore::Container]
         | 
| 174 | 
            +
                # @return [Enumerable]
         | 
| 175 | 
            +
                #
         | 
| 176 | 
            +
                # @api public
         | 
| 177 | 
            +
                # @since 0.4.0
         | 
| 178 | 
            +
                def each_dependency(
         | 
| 179 | 
            +
                  yield_all: SmartCore::Container::Registry::DEFAULT_ITERATION_YIELD_BEHAVIOUR,
         | 
| 180 | 
            +
                  &block
         | 
| 181 | 
            +
                )
         | 
| 182 | 
            +
                  thread_safe { registry.each_dependency(yield_all: yield_all, &block) }
         | 
| 183 | 
            +
                end
         | 
| 184 | 
            +
                alias_method :each, :each_dependency
         | 
| 185 | 
            +
                alias_method :each_pair, :each_dependency
         | 
| 186 | 
            +
             | 
| 105 187 | 
             
                # @option resolve_dependencies [Boolean]
         | 
| 106 188 | 
             
                # @return [Hash<String|Symbol,SmartCore::Container::Entities::Base|Any>]
         | 
| 107 189 | 
             
                #
         | 
| @@ -69,8 +69,12 @@ class SmartCore::Container | |
| 69 69 | 
             
                  #
         | 
| 70 70 | 
             
                  # @api public
         | 
| 71 71 | 
             
                  # @since 0.1.0
         | 
| 72 | 
            -
                  # @version 0. | 
| 73 | 
            -
                  def register( | 
| 72 | 
            +
                  # @version 0.3.0
         | 
| 73 | 
            +
                  def register(
         | 
| 74 | 
            +
                    dependency_name,
         | 
| 75 | 
            +
                    memoize: SmartCore::Container::Registry::DEFAULT_MEMOIZATION_BEHAVIOR,
         | 
| 76 | 
            +
                    &dependency_definition
         | 
| 77 | 
            +
                  )
         | 
| 74 78 | 
             
                    @__container_definition_lock__.thread_safe do
         | 
| 75 79 | 
             
                      DependencyCompatability::Definition.prevent_namespace_overlap!(self, dependency_name)
         | 
| 76 80 |  | 
| @@ -36,7 +36,7 @@ module SmartCore::Container::DefinitionDSL::Commands::Definition | |
| 36 36 | 
             
                # @since 0.1.0
         | 
| 37 37 | 
             
                # @version 0.2.0
         | 
| 38 38 | 
             
                def call(registry)
         | 
| 39 | 
            -
                  registry.register_dependency(dependency_name, memoize, &dependency_definition)
         | 
| 39 | 
            +
                  registry.register_dependency(dependency_name, memoize: memoize, &dependency_definition)
         | 
| 40 40 | 
             
                end
         | 
| 41 41 |  | 
| 42 42 | 
             
                # @return [SmartCore::Container::DefinitionDSL::Commands::Definition::Register]
         | 
| @@ -5,6 +5,12 @@ | |
| 5 5 | 
             
            module SmartCore::Container::DependencyResolver
         | 
| 6 6 | 
             
              require_relative 'dependency_resolver/route'
         | 
| 7 7 |  | 
| 8 | 
            +
              # @return [String]
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              # @api private
         | 
| 11 | 
            +
              # @since 0.4.0
         | 
| 12 | 
            +
              PATH_PART_SEPARATOR = '.'
         | 
| 13 | 
            +
             | 
| 8 14 | 
             
              class << self
         | 
| 9 15 | 
             
                # @param container [SmartCore::Container]
         | 
| 10 16 | 
             
                # @param dependency_path [String, Symbol]
         | 
| @@ -20,6 +26,54 @@ module SmartCore::Container::DependencyResolver | |
| 20 26 | 
             
                  container.registry.resolve(dependency_path).reveal
         | 
| 21 27 | 
             
                end
         | 
| 22 28 |  | 
| 29 | 
            +
                # @param container [SmartCore::Container]
         | 
| 30 | 
            +
                # @param key [String, Symbol]
         | 
| 31 | 
            +
                # @return [Boolean]
         | 
| 32 | 
            +
                #
         | 
| 33 | 
            +
                # @api private
         | 
| 34 | 
            +
                # @since 0.5.0
         | 
| 35 | 
            +
                def key?(container, key)
         | 
| 36 | 
            +
                  extract(container, key)
         | 
| 37 | 
            +
                  true
         | 
| 38 | 
            +
                rescue SmartCore::Container::ResolvingError
         | 
| 39 | 
            +
                  false
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                # @param container [SmartCore::Container]
         | 
| 43 | 
            +
                # @param namespace_path [String, Symbol]
         | 
| 44 | 
            +
                # @return [Boolean]
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                # @api private
         | 
| 47 | 
            +
                # @since 0.5.0
         | 
| 48 | 
            +
                def namespace?(container, namespace_path)
         | 
| 49 | 
            +
                  extract(container, namespace_path).is_a?(SmartCore::Container::Entities::Namespace)
         | 
| 50 | 
            +
                rescue SmartCore::Container::ResolvingError
         | 
| 51 | 
            +
                  false
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                # @param container [SmartCore::Container]
         | 
| 55 | 
            +
                # @param dependency_path [String, Symbol]
         | 
| 56 | 
            +
                # @option memoized [NilClass, Boolean]
         | 
| 57 | 
            +
                # @return [Boolean]
         | 
| 58 | 
            +
                #
         | 
| 59 | 
            +
                # @api private
         | 
| 60 | 
            +
                # @since 0.5.0
         | 
| 61 | 
            +
                def dependency?(container, dependency_path, memoized: nil)
         | 
| 62 | 
            +
                  entity = extract(container, dependency_path)
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  case
         | 
| 65 | 
            +
                  when memoized.nil?
         | 
| 66 | 
            +
                    entity.is_a?(SmartCore::Container::Entities::Dependency)
         | 
| 67 | 
            +
                  when !!memoized == true
         | 
| 68 | 
            +
                    entity.is_a?(SmartCore::Container::Entities::MemoizedDependency)
         | 
| 69 | 
            +
                  when !!memoized == false
         | 
| 70 | 
            +
                    entity.is_a?(SmartCore::Container::Entities::Dependency) &&
         | 
| 71 | 
            +
                      !entity.is_a?(SmartCore::Container::Entities::MemoizedDependency)
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                rescue SmartCore::Container::ResolvingError
         | 
| 74 | 
            +
                  false
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 23 77 | 
             
                # @param container [SmartCore::Container]
         | 
| 24 78 | 
             
                # @param dependency_path [String, Symbol]
         | 
| 25 79 | 
             
                # @return [SmartCore::Container, Any]
         | 
| @@ -32,12 +86,11 @@ module SmartCore::Container::DependencyResolver | |
| 32 86 | 
             
                #
         | 
| 33 87 | 
             
                # @api private
         | 
| 34 88 | 
             
                # @since 0.1.0
         | 
| 35 | 
            -
                # @version 0.1.0
         | 
| 36 89 | 
             
                def resolve(container, dependency_path)
         | 
| 37 90 | 
             
                  entity = container
         | 
| 38 91 | 
             
                  Route.build(dependency_path).each do |cursor|
         | 
| 39 92 | 
             
                    entity = entity.registry.resolve(cursor.current_path)
         | 
| 40 | 
            -
                     | 
| 93 | 
            +
                    prevent_ambiguous_resolving!(cursor, entity)
         | 
| 41 94 | 
             
                    entity = entity.reveal
         | 
| 42 95 | 
             
                  end
         | 
| 43 96 | 
             
                  entity
         | 
| @@ -47,6 +100,25 @@ module SmartCore::Container::DependencyResolver | |
| 47 100 |  | 
| 48 101 | 
             
                private
         | 
| 49 102 |  | 
| 103 | 
            +
                # @param container [SmartCore::Container]
         | 
| 104 | 
            +
                # @param entity_path [String, Symbol]
         | 
| 105 | 
            +
                # @return [SmartCore::Container::Entities::Base]
         | 
| 106 | 
            +
                #
         | 
| 107 | 
            +
                # @api private
         | 
| 108 | 
            +
                # @since 0.5.0
         | 
| 109 | 
            +
                def extract(container, entity_path)
         | 
| 110 | 
            +
                  resolved_entity = container
         | 
| 111 | 
            +
                  extracted_entity = container
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  Route.build(entity_path).each do |cursor|
         | 
| 114 | 
            +
                    resolved_entity = resolved_entity.registry.resolve(cursor.current_path)
         | 
| 115 | 
            +
                    extracted_entity = resolved_entity
         | 
| 116 | 
            +
                    resolved_entity = resolved_entity.reveal
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  extracted_entity
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 50 122 | 
             
                # @param cursor [SmartCore::Container::DependencyResolver::Route::Cursor]
         | 
| 51 123 | 
             
                # @param entity [SmartCore::Container::Entities::Base]
         | 
| 52 124 | 
             
                # @return [void]
         | 
| @@ -54,8 +126,8 @@ module SmartCore::Container::DependencyResolver | |
| 54 126 | 
             
                # @raise [SmartCore::Container::ResolvingError]
         | 
| 55 127 | 
             
                #
         | 
| 56 128 | 
             
                # @api private
         | 
| 57 | 
            -
                # @since 0. | 
| 58 | 
            -
                def  | 
| 129 | 
            +
                # @since 0.5.0
         | 
| 130 | 
            +
                def prevent_ambiguous_resolving!(cursor, entity)
         | 
| 59 131 | 
             
                  if cursor.last? && entity.is_a?(SmartCore::Container::Entities::Namespace)
         | 
| 60 132 | 
             
                    raise(
         | 
| 61 133 | 
             
                      SmartCore::Container::ResolvingError.new(
         | 
| @@ -84,10 +156,9 @@ module SmartCore::Container::DependencyResolver | |
| 84 156 | 
             
                # @api private
         | 
| 85 157 | 
             
                # @since 0.1.0
         | 
| 86 158 | 
             
                def process_resolving_error(dependency_path, error)
         | 
| 87 | 
            -
                  full_dependency_path = Route.build_path( | 
| 88 | 
            -
                   | 
| 89 | 
            -
             | 
| 90 | 
            -
                  MESSAGE
         | 
| 159 | 
            +
                  full_dependency_path = Route.build_path(error.path_part)
         | 
| 160 | 
            +
                  message = "#{error.message} (incorrect path: \"#{full_dependency_path}\")"
         | 
| 161 | 
            +
                  raise(SmartCore::Container::ResolvingError.new(message, path_part: full_dependency_path))
         | 
| 91 162 | 
             
                end
         | 
| 92 163 | 
             
              end
         | 
| 93 164 | 
             
            end
         | 
| @@ -2,18 +2,13 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.4.0
         | 
| 5 6 | 
             
            class SmartCore::Container::DependencyResolver::Route
         | 
| 6 7 | 
             
              require_relative 'route/cursor'
         | 
| 7 8 |  | 
| 8 9 | 
             
              # @since 0.1.0
         | 
| 9 10 | 
             
              include Enumerable
         | 
| 10 11 |  | 
| 11 | 
            -
              # @return [String]
         | 
| 12 | 
            -
              #
         | 
| 13 | 
            -
              # @api private
         | 
| 14 | 
            -
              # @since 0.1.0
         | 
| 15 | 
            -
              PATH_PART_SEPARATOR = '.'
         | 
| 16 | 
            -
             | 
| 17 12 | 
             
              class << self
         | 
| 18 13 | 
             
                # @param path [String, Symbol]
         | 
| 19 14 | 
             
                # @return [SmartCore::Container::DependencyResolver::Route]
         | 
| @@ -28,8 +23,9 @@ class SmartCore::Container::DependencyResolver::Route | |
| 28 23 | 
             
                #
         | 
| 29 24 | 
             
                # @api private
         | 
| 30 25 | 
             
                # @since 0.1.0
         | 
| 26 | 
            +
                # @version 0.4.0
         | 
| 31 27 | 
             
                def build_path(*path_parts)
         | 
| 32 | 
            -
                  path_parts.join(PATH_PART_SEPARATOR)
         | 
| 28 | 
            +
                  path_parts.join(SmartCore::Container::DependencyResolver::PATH_PART_SEPARATOR)
         | 
| 33 29 | 
             
                end
         | 
| 34 30 | 
             
              end
         | 
| 35 31 |  | 
| @@ -50,9 +46,10 @@ class SmartCore::Container::DependencyResolver::Route | |
| 50 46 | 
             
              #
         | 
| 51 47 | 
             
              # @api private
         | 
| 52 48 | 
             
              # @since 0.1.0
         | 
| 49 | 
            +
              # @version 0.4.0
         | 
| 53 50 | 
             
              def initialize(path)
         | 
| 54 51 | 
             
                @path = path
         | 
| 55 | 
            -
                @path_parts = path.split(PATH_PART_SEPARATOR).freeze
         | 
| 52 | 
            +
                @path_parts = path.split(SmartCore::Container::DependencyResolver::PATH_PART_SEPARATOR).freeze
         | 
| 56 53 | 
             
                @size = @path_parts.size
         | 
| 57 54 | 
             
              end
         | 
| 58 55 |  | 
| @@ -7,6 +7,24 @@ class SmartCore::Container::Registry | |
| 7 7 | 
             
              # @since 0.1.0
         | 
| 8 8 | 
             
              include Enumerable
         | 
| 9 9 |  | 
| 10 | 
            +
              # @return [Boolean]
         | 
| 11 | 
            +
              #
         | 
| 12 | 
            +
              # @api private
         | 
| 13 | 
            +
              # @since 0.3.0
         | 
| 14 | 
            +
              DEFAULT_MEMOIZATION_BEHAVIOR = false
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              # @return [Boolean]
         | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              # @api private
         | 
| 19 | 
            +
              # @since 0.4.0
         | 
| 20 | 
            +
              DEFAULT_ITERATION_YIELD_BEHAVIOUR = false
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              # @return [Boolean]
         | 
| 23 | 
            +
              #
         | 
| 24 | 
            +
              # @api private
         | 
| 25 | 
            +
              # @since 0.4.0
         | 
| 26 | 
            +
              DEFAULT_KEY_EXTRACTION_BEHAVIOUR = false
         | 
| 27 | 
            +
             | 
| 10 28 | 
             
              # @return [Hash<Symbol,SmartCore::Container::Entity>]
         | 
| 11 29 | 
             
              #
         | 
| 12 30 | 
             
              # @api private
         | 
| @@ -38,8 +56,8 @@ class SmartCore::Container::Registry | |
| 38 56 | 
             
              #
         | 
| 39 57 | 
             
              # @api private
         | 
| 40 58 | 
             
              # @since 0.1.0
         | 
| 41 | 
            -
              # @version 0. | 
| 42 | 
            -
              def register_dependency(name, memoize  | 
| 59 | 
            +
              # @version 0.3.0
         | 
| 60 | 
            +
              def register_dependency(name, memoize: DEFAULT_MEMOIZATION_BEHAVIOR, &dependency_definition)
         | 
| 43 61 | 
             
                thread_safe { add_dependency(name, dependency_definition, memoize) }
         | 
| 44 62 | 
             
              end
         | 
| 45 63 |  | 
| @@ -78,6 +96,30 @@ class SmartCore::Container::Registry | |
| 78 96 | 
             
                thread_safe { enumerate(&block) }
         | 
| 79 97 | 
             
              end
         | 
| 80 98 |  | 
| 99 | 
            +
              # @param root_dependency_name [NilClass, String]
         | 
| 100 | 
            +
              # @option yield_all [Boolean]
         | 
| 101 | 
            +
              # @param block [Block]
         | 
| 102 | 
            +
              # @return [Enumerable]
         | 
| 103 | 
            +
              #
         | 
| 104 | 
            +
              # @api private
         | 
| 105 | 
            +
              # @since 0.4.0
         | 
| 106 | 
            +
              def each_dependency(
         | 
| 107 | 
            +
                root_dependency_name = nil,
         | 
| 108 | 
            +
                yield_all: DEFAULT_ITERATION_YIELD_BEHAVIOUR,
         | 
| 109 | 
            +
                &block
         | 
| 110 | 
            +
              )
         | 
| 111 | 
            +
                thread_safe { iterate(root_dependency_name, yield_all: yield_all, &block) }
         | 
| 112 | 
            +
              end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              # @option all_variants [Boolean]
         | 
| 115 | 
            +
              # @return [Array<String>]
         | 
| 116 | 
            +
              #
         | 
| 117 | 
            +
              # @api private
         | 
| 118 | 
            +
              # @since 0.4.0
         | 
| 119 | 
            +
              def keys(all_variants: DEFAULT_KEY_EXTRACTION_BEHAVIOUR)
         | 
| 120 | 
            +
                thread_safe { extract_keys(all_variants: all_variants) }
         | 
| 121 | 
            +
              end
         | 
| 122 | 
            +
             | 
| 81 123 | 
             
              # @return [Hash<String|Symbol,SmartCore::Container::Entities::Base|Any>]
         | 
| 82 124 | 
             
              #
         | 
| 83 125 | 
             
              # @api private
         | 
| @@ -152,9 +194,8 @@ class SmartCore::Container::Registry | |
| 152 194 | 
             
                dependency_name = indifferently_accessable_name(entity_path)
         | 
| 153 195 | 
             
                registry.fetch(dependency_name)
         | 
| 154 196 | 
             
              rescue KeyError
         | 
| 155 | 
            -
                 | 
| 156 | 
            -
             | 
| 157 | 
            -
                MESSAGE
         | 
| 197 | 
            +
                error_message = "Entity with \"#{dependency_name}\" name does not exist"
         | 
| 198 | 
            +
                raise(SmartCore::Container::ResolvingError.new(error_message, path_part: dependency_name))
         | 
| 158 199 | 
             
              end
         | 
| 159 200 |  | 
| 160 201 | 
             
              # @param dependency_name [String, Symbol]
         | 
| @@ -209,6 +250,58 @@ class SmartCore::Container::Registry | |
| 209 250 | 
             
                namespace_entity.tap { namespace_entity.append_definitions(dependencies_definition) }
         | 
| 210 251 | 
             
              end
         | 
| 211 252 |  | 
| 253 | 
            +
              # @param root_dependency_name [String, NilClass]
         | 
| 254 | 
            +
              # @param block [Block]
         | 
| 255 | 
            +
              # @option yield_all [Boolean]
         | 
| 256 | 
            +
              # @yield [dependency_name, dependency]
         | 
| 257 | 
            +
              # @yield_param dependency_name [String]
         | 
| 258 | 
            +
              # @yield_param dependency [Any]
         | 
| 259 | 
            +
              # @return [Enumerable]
         | 
| 260 | 
            +
              #
         | 
| 261 | 
            +
              # @api private
         | 
| 262 | 
            +
              # @since 0.4.0
         | 
| 263 | 
            +
              def iterate(root_dependency_name = nil, yield_all: DEFAULT_ITERATION_YIELD_BEHAVIOUR, &block)
         | 
| 264 | 
            +
                enumerator = Enumerator.new do |yielder|
         | 
| 265 | 
            +
                  registry.each_pair do |dependency_name, dependency|
         | 
| 266 | 
            +
                    final_dependency_name =
         | 
| 267 | 
            +
                      if root_dependency_name
         | 
| 268 | 
            +
                        "#{root_dependency_name}" \
         | 
| 269 | 
            +
                        "#{SmartCore::Container::DependencyResolver::PATH_PART_SEPARATOR}" \
         | 
| 270 | 
            +
                        "#{dependency_name}"
         | 
| 271 | 
            +
                      else
         | 
| 272 | 
            +
                        dependency_name
         | 
| 273 | 
            +
                      end
         | 
| 274 | 
            +
             | 
| 275 | 
            +
                    case dependency
         | 
| 276 | 
            +
                    when SmartCore::Container::Entities::Dependency
         | 
| 277 | 
            +
                      yielder.yield(final_dependency_name, dependency.reveal)
         | 
| 278 | 
            +
                    when SmartCore::Container::Entities::Namespace
         | 
| 279 | 
            +
                      yielder.yield(final_dependency_name, dependency.reveal) if yield_all
         | 
| 280 | 
            +
                      dependency.reveal.registry.each_dependency(
         | 
| 281 | 
            +
                        final_dependency_name,
         | 
| 282 | 
            +
                        yield_all: yield_all,
         | 
| 283 | 
            +
                        &block
         | 
| 284 | 
            +
                      )
         | 
| 285 | 
            +
                    end
         | 
| 286 | 
            +
                  end
         | 
| 287 | 
            +
                end
         | 
| 288 | 
            +
             | 
| 289 | 
            +
                block_given? ? enumerator.each(&block) : enumerator.each
         | 
| 290 | 
            +
              end
         | 
| 291 | 
            +
             | 
| 292 | 
            +
              # @option all_variants [Boolean]
         | 
| 293 | 
            +
              # @return [Array<String>]
         | 
| 294 | 
            +
              #
         | 
| 295 | 
            +
              # @api private
         | 
| 296 | 
            +
              # @since 0.4.0
         | 
| 297 | 
            +
              def extract_keys(all_variants: DEFAULT_KEY_EXTRACTION_BEHAVIOUR)
         | 
| 298 | 
            +
                Set.new.tap do |dependency_names|
         | 
| 299 | 
            +
                  iterate(yield_all: all_variants) do |dependency_name, _dependency|
         | 
| 300 | 
            +
                    dependency_names << dependency_name
         | 
| 301 | 
            +
                  end
         | 
| 302 | 
            +
                end.to_a
         | 
| 303 | 
            +
              end
         | 
| 304 | 
            +
             | 
| 212 305 | 
             
              # @param name [String, Symbol]
         | 
| 213 306 | 
             
              # @return [void]
         | 
| 214 307 | 
             
              #
         | 
    
        data/smart_container.gemspec
    CHANGED
    
    | @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            require_relative 'lib/smart_core/container/version'
         | 
| 4 4 |  | 
| 5 5 | 
             
            Gem::Specification.new do |spec|
         | 
| 6 | 
            -
              spec.required_ruby_version = Gem::Requirement.new('>= 2.4. | 
| 6 | 
            +
              spec.required_ruby_version = Gem::Requirement.new('>= 2.4.10')
         | 
| 7 7 |  | 
| 8 8 | 
             
              spec.name    = 'smart_container'
         | 
| 9 9 | 
             
              spec.version = SmartCore::Container::VERSION
         | 
| @@ -27,12 +27,12 @@ Gem::Specification.new do |spec| | |
| 27 27 | 
             
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 28 28 | 
             
              spec.require_paths = ['lib']
         | 
| 29 29 |  | 
| 30 | 
            -
              spec.add_dependency 'smart_engine', '~> 0. | 
| 30 | 
            +
              spec.add_dependency 'smart_engine', '~> 0.5'
         | 
| 31 31 |  | 
| 32 32 | 
             
              spec.add_development_dependency 'bundler',          '~> 2.1'
         | 
| 33 33 | 
             
              spec.add_development_dependency 'rake',             '~> 13.0'
         | 
| 34 34 | 
             
              spec.add_development_dependency 'rspec',            '~> 3.9'
         | 
| 35 | 
            -
              spec.add_development_dependency 'armitage-rubocop', '~> 0. | 
| 36 | 
            -
              spec.add_development_dependency 'simplecov',        '~> 0. | 
| 37 | 
            -
              spec.add_development_dependency 'pry',              '~> 0. | 
| 35 | 
            +
              spec.add_development_dependency 'armitage-rubocop', '~> 0.81'
         | 
| 36 | 
            +
              spec.add_development_dependency 'simplecov',        '~> 0.18'
         | 
| 37 | 
            +
              spec.add_development_dependency 'pry',              '~> 0.13'
         | 
| 38 38 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: smart_container
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.7.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Rustam Ibragimov
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020- | 
| 11 | 
            +
            date: 2020-06-20 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: smart_engine
         | 
| @@ -16,14 +16,14 @@ dependencies: | |
| 16 16 | 
             
                requirements:
         | 
| 17 17 | 
             
                - - "~>"
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: '0. | 
| 19 | 
            +
                    version: '0.5'
         | 
| 20 20 | 
             
              type: :runtime
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 24 | 
             
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version: '0. | 
| 26 | 
            +
                    version: '0.5'
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: bundler
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -72,42 +72,42 @@ dependencies: | |
| 72 72 | 
             
                requirements:
         | 
| 73 73 | 
             
                - - "~>"
         | 
| 74 74 | 
             
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            -
                    version: '0. | 
| 75 | 
            +
                    version: '0.81'
         | 
| 76 76 | 
             
              type: :development
         | 
| 77 77 | 
             
              prerelease: false
         | 
| 78 78 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 79 | 
             
                requirements:
         | 
| 80 80 | 
             
                - - "~>"
         | 
| 81 81 | 
             
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            -
                    version: '0. | 
| 82 | 
            +
                    version: '0.81'
         | 
| 83 83 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 84 84 | 
             
              name: simplecov
         | 
| 85 85 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 86 | 
             
                requirements:
         | 
| 87 87 | 
             
                - - "~>"
         | 
| 88 88 | 
             
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            -
                    version: '0. | 
| 89 | 
            +
                    version: '0.18'
         | 
| 90 90 | 
             
              type: :development
         | 
| 91 91 | 
             
              prerelease: false
         | 
| 92 92 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 93 | 
             
                requirements:
         | 
| 94 94 | 
             
                - - "~>"
         | 
| 95 95 | 
             
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            -
                    version: '0. | 
| 96 | 
            +
                    version: '0.18'
         | 
| 97 97 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 98 98 | 
             
              name: pry
         | 
| 99 99 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 100 100 | 
             
                requirements:
         | 
| 101 101 | 
             
                - - "~>"
         | 
| 102 102 | 
             
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            -
                    version: '0. | 
| 103 | 
            +
                    version: '0.13'
         | 
| 104 104 | 
             
              type: :development
         | 
| 105 105 | 
             
              prerelease: false
         | 
| 106 106 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 107 | 
             
                requirements:
         | 
| 108 108 | 
             
                - - "~>"
         | 
| 109 109 | 
             
                  - !ruby/object:Gem::Version
         | 
| 110 | 
            -
                    version: '0. | 
| 110 | 
            +
                    version: '0.13'
         | 
| 111 111 | 
             
            description: Thread-safe semanticaly-defined IoC/DI Container
         | 
| 112 112 | 
             
            email:
         | 
| 113 113 | 
             
            - iamdaiver@gmail.com
         | 
| @@ -178,7 +178,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 178 178 | 
             
              requirements:
         | 
| 179 179 | 
             
              - - ">="
         | 
| 180 180 | 
             
                - !ruby/object:Gem::Version
         | 
| 181 | 
            -
                  version: 2.4. | 
| 181 | 
            +
                  version: 2.4.10
         | 
| 182 182 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 183 183 | 
             
              requirements:
         | 
| 184 184 | 
             
              - - ">="
         |