[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: hanami\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "content": "---\nname: \"\\U0001F41B Bug report\"\nabout: See CONTRIBUTING.md for more information\ntitle: ''\nlabels: bug, help wanted\nassignees: ''\n\n---\n\n## Describe the bug\n\nA clear and concise description of what the bug is.\n\n## To Reproduce\n\nProvide detailed steps to reproduce, **an executable script would be best**.\n\n## Expected behavior\n\nA clear and concise description of what you expected to happen.\n\n## My environment\n\n- Ruby version: ...\n- OS: ...\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Community support\n    url: https://discourse.hanamirb.org\n    about: Please ask and answer questions here.\n"
  },
  {
    "path": ".github/SUPPORT.md",
    "content": "## Support\n\nIf you need help with any of the Hanami, Dry or Rom libraries, feel free to ask questions on our [discussion forum](https://discourse.hanamirb.org/). This is the best place to seek help. Make sure to search for a potential solution in past threads before posting your question. Thanks! :heart:\n"
  },
  {
    "path": ".github/workflows/ci-lint.yml",
    "content": "name: CI lint\n\non:\n  push:\n    branches: [\"main\", \"release-*\", \"ci/*\"]\n    tags: [\"v*\"]\n    paths:\n      - \".github/**\"\n  pull_request:\n    branches: [\"main\", \"release-*\"]\n    paths:\n      - \".github/**\"\n  schedule:\n    - cron: \"0 0 * * 0\" # every Sunday at midnight\n\npermissions: {}\n\njobs:\n  zizmor:\n    name: Run zizmor\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd\n        with:\n          persist-credentials: false\n\n      - name: Run zizmor\n        uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d\n        with:\n          advanced-security: false\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "# This file is synced from hanakai-rb/repo-sync\n\nname: CI\nrun-name: ${{ github.ref_type == 'tag' && format('Release {0}', github.ref_name) || 'CI' }}\n\non:\n  push:\n    branches: [\"main\", \"release-*\", \"ci/*\"]\n    tags: [\"v*\"]\n  pull_request:\n    branches: [\"main\", \"release-*\"]\n  schedule:\n    - cron: \"30 4 * * *\"\n\npermissions:\n  contents: read\n\njobs:\n  tests:\n    name: Tests (Ruby ${{ matrix.ruby }})\n    runs-on: ubuntu-latest\n    continue-on-error: ${{ matrix.optional || false }}\n    strategy:\n      fail-fast: false\n      matrix:\n        ruby:\n          - \"4.0\"\n          - \"3.4\"\n          - \"3.3\"\n          - \"3.2\"\n          - \"3.3.0\"\n          - \"jruby\"\n        include:\n          - ruby: \"4.0\"\n            coverage: \"true\"\n    env:\n      COVERAGE: ${{ matrix.coverage }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n        with:\n          persist-credentials: false\n      - name: Install package dependencies\n        run: \"[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS\"\n      - name: Set up Ruby\n        uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # zizmor: ignore[cache-poisoning]\n        with:\n          ruby-version: ${{ matrix.ruby }}\n          bundler-cache: true\n      - name: Run all tests\n        id: test\n        run: |\n          status=0\n          bundle exec rake || status=$?\n          if [ ${status} -ne 0 ] && [ \"${{ matrix.optional }}\" == \"true\" ]; then\n            echo \"::warning::Optional matrix job failed.\"\n            echo \"optional_fail=true\" >> \"${GITHUB_OUTPUT}\"\n            echo \"optional_fail_status=${status}\" >> \"${GITHUB_OUTPUT}\"\n            exit 0  # Ignore error here to keep the green checkmark\n          fi\n          exit ${status}\n      - name: Create optional failure comment\n        if: ${{ matrix.optional && github.event.pull_request }}\n        uses: hanakai-rb/repo-sync/pr-comment-artifact@main\n        with:\n          name: ci-ruby-${{ matrix.ruby }}\n          pr-number: ${{ github.event.pull_request.number }}\n          comment-tag: ruby-${{ matrix.ruby }}-optional-failure\n          message: \"ℹ️ Optional job failed: Ruby ${{ matrix.ruby }}\"\n          mode: ${{ steps.test.outputs.optional_fail == 'true' && 'upsert' || 'delete' }}\n\n  workflow-keepalive:\n    if: github.event_name == 'schedule'\n    runs-on: ubuntu-latest\n    permissions:\n      actions: write\n    steps:\n      - uses: liskin/gh-workflow-keepalive@7a9194bad497f0b993708eeaf10fc0a2d726eb71\n\n  release:\n    runs-on: ubuntu-latest\n    if: github.ref_type == 'tag'\n    needs: tests\n    steps:\n      - name: Trigger release workflow\n        uses: actions/github-script@450193c5abd4cdb17ba9f3ffcfe8f635c4bb6c2a\n        with:\n          github-token: ${{ secrets.RELEASE_MACHINE_DISPATCH_TOKEN }}\n          script: |\n            const tag = context.ref.replace(\"refs/tags/\", \"\");\n            const repo = context.repo.owner + \"/\" + context.repo.repo;\n\n            const tagMessage = await github.rest.git.getTag({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              tag_sha: context.sha\n            }).then(res => res.data.message).catch(() => \"\");\n            const announce = /(skip-announce|no-announce)/i.test(tagMessage) ? \"false\" : \"true\";\n\n            await github.rest.actions.createWorkflowDispatch({\n              owner: \"hanakai-rb\",\n              repo: \"release-machine\",\n              workflow_id: \"release.yml\",\n              ref: \"main\",\n              inputs: { repo, tag, announce }\n            });\n\n            const workflowUrl = \"https://github.com/hanakai-rb/release-machine/actions/workflows/release.yml\";\n            await core.summary\n              .addHeading(\"Release Triggered\")\n              .addRaw(`Triggered release workflow for <code>${tag}</code>`)\n              .addLink(\"View release workflow\", workflowUrl)\n              .write();\n  \n\n"
  },
  {
    "path": ".github/workflows/pr-comments.yml",
    "content": "# This file is synced from hanakai-rb/repo-sync\n\n# Downloads comment artifacts from completed workflows and posts them to PRs. This allows source\n# workflows to run with read-only permissions on fork PRs while still posting comments via this\n# privileged workflow that runs in the base repo context.\n#\n# Comment artifacts should be generated using the `hanakai-rb/repo-sync/pr-comment-artifact@main`\n# action.\n\nname: PR comments\n\non: # zizmor: ignore[dangerous-triggers]\n  workflow_run:\n    workflows: [\"CI\"]\n    types:\n      - completed\n\npermissions:\n  pull-requests: write\n\njobs:\n  post-comments:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    if: github.event.workflow_run.event == 'pull_request'\n\n    steps:\n      - name: Post comments\n        uses: hanakai-rb/repo-sync/pr-comments-from-artifacts@main\n        with:\n          workflow-run-id: ${{ github.event.workflow_run.id }}\n"
  },
  {
    "path": ".github/workflows/repo-sync-preview.yml",
    "content": "name: Repo-sync preview\n\non: # zizmor: ignore[dangerous-triggers]\n  workflow_run:\n    workflows: [\"CI\", \"RuboCop\", \"CI lint\"]\n    types: [completed]\n    branches:\n      - \"ci/repo-sync-preview-*\"\n\njobs:\n  report:\n    runs-on: ubuntu-latest\n    permissions: {}\n    if: >\n      github.event.workflow_run.event == 'push' &&\n      github.event.workflow_run.head_repository.fork == false\n    steps:\n      - name: Dispatch status to repo-sync\n        uses: actions/github-script@450193c5abd4cdb17ba9f3ffcfe8f635c4bb6c2a\n        with:\n          github-token: ${{ secrets.REPO_SYNC_DISPATCH_TOKEN }}\n          script: |\n            const { BRANCH, REPO, WORKFLOW, STATUS, RUN_URL } = process.env;\n            await github.rest.actions.createWorkflowDispatch({\n              owner: \"hanakai-rb\",\n              repo: \"repo-sync\",\n              workflow_id: \"aggregate-preview-status.yml\",\n              ref: \"main\",\n              inputs: {\n                pr_number: BRANCH.replace(\"ci/repo-sync-preview-\", \"\"),\n                repo_name: REPO,\n                workflow_name: WORKFLOW,\n                status: STATUS,\n                run_url: RUN_URL\n              }\n            });\n        env:\n          BRANCH: ${{ github.event.workflow_run.head_branch }}\n          REPO: ${{ github.repository }}\n          WORKFLOW: ${{ github.event.workflow_run.name }}\n          STATUS: ${{ github.event.workflow_run.conclusion }}\n          RUN_URL: ${{ github.event.workflow_run.html_url }}\n"
  },
  {
    "path": ".github/workflows/rubocop.yml",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nname: RuboCop\n\non:\n  push:\n    branches: [\"main\", \"release-*\", \"ci/*\"]\n    tags: [\"v*\"]\n  pull_request:\n    branches: [\"main\", \"release-*\"]\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    env:\n      BUNDLE_ONLY: tools\n\n    steps:\n      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n        with:\n          persist-credentials: false\n\n      - name: Set up Ruby 4.0\n        uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # zizmor: ignore[cache-poisoning]\n        with:\n          ruby-version: 4.0\n          bundler-cache: true\n\n      - name: Run RuboCop\n        run: bundle exec rubocop --parallel\n"
  },
  {
    "path": ".gitignore",
    "content": "*.gem\n*.rbc\n*.log\n/.rubocop*\n/.config\n/coverage/\n/InstalledFiles\n/pkg/\n/spec/reports/\n/test/tmp/\n/test/version_tmp/\n/tmp/\n\n## Specific to RubyMotion:\n.dat*\n.repl_history\nbuild/\n\n## Documentation cache and generated files:\n/.yardoc/\n/_yardoc/\n/doc/\n/rdoc/\n\n## Environment normalisation:\n/.bundle/\n/vendor/bundle\n/lib/bundler/man/\n\n# for a library or gem, you might want to ignore these files since the code is\n# intended to run in multiple environments; otherwise, check them in:\n# Gemfile.lock\n# .ruby-version\n# .ruby-gemset\n\n# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:\n.rvmrc\nGemfile.lock\n\n## Specific to RubyMine\n.idea\n\n## Tests\n/spec/examples.txt\n/spec/fixtures/test/tmp/cache\n"
  },
  {
    "path": ".rspec",
    "content": "--color\n--require spec_helper\n--order random\n--warnings\n"
  },
  {
    "path": ".yardopts",
    "content": "--no-private\n--hide-void-return\n\n--markup-provider=redcarpet\n--markup=markdown\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).\n\n## [Unreleased]\n\n[Unreleased]: https://github.com/dry-rb/dry-system/compare/v1.2.5...main\n\n## [1.2.5] - 2025-12-01\n\n### Fixed\n\n- Pass through keyword arguments to monitored objects in `monitoring` plugin. (@yuszuv in #290)\n\n[1.2.5]: https://github.com/dry-rb/dry-system/compare/v1.2.4...v1.2.5\n\n## [1.2.4] - 2025-08-14\n\n\n### Fixed\n\n- Allow imported components to be lazy loaded when both strings and symbols are given as the\nnamespace to `Container.import` (@timriley in #287)\n\n\n[Compare v1.2.3...v1.2.4](https://github.com/dry-rb/dry-system/compare/v1.2.3...v1.2.4)\n\n## [1.2.3] - 2025-07-29\n\n\n### Added\n\n- Add :register after-hook to detect container key registration dynamically. (via #274, @alassek)\n\n### Fixed\n\n- Re-register components from manifest registrars in apps that reload the container (e.g. when\nusing dry-rails and Rails development mode) (via #286, @alassek)\n\n### Changed\n\n- :finalize after-hook now executes before container freeze to allow mutation. (via #274, @alassek)\n\n[Compare v1.2.2...v1.2.3](https://github.com/dry-rb/dry-system/compare/v1.2.2...v1.2.3)\n\n## [1.2.2] - 2025-01-31\n\n\n### Fixed\n\n- Syntax errors on 3.3.0 (@flash-gordon, see #284)\n\n\n[Compare v1.2.1...v1.2.2](https://github.com/dry-rb/dry-system/compare/v1.2.1...v1.2.2)\n\n## [1.2.1] - 2025-01-08\n\n\n### Fixed\n\n- `eager_load` was removed from `finalize!`. It was introduced with `true` by default that\nwasn't the intention #281 (via #282) (@flash-gordon)\n\n\n[Compare v1.2.0...v1.2.1](https://github.com/dry-rb/dry-system/compare/v1.2.0...v1.2.1)\n\n## [1.2.0] - 2025-01-07\n\n\n### Added\n\n- Option to skip eager loading during finalize with `eager_load: false` (via #276) (@cllns)\n\n### Changed\n\n- Update required Ruby version to 3.1 (@flash-gordon)\n\n[Compare v1.1.1...v1.2.0](https://github.com/dry-rb/dry-system/compare/v1.1.1...v1.2.0)\n\n## [1.1.1] - 2024-11-03\n\n\n### Fixed\n\n- Restore `ProviderRegistrar#find_and_load_provider` as an alias of `#[]`\n\n\n[Compare v1.1.0...v1.1.1](https://github.com/dry-rb/dry-system/compare/v1.1.0...v1.1.1)\n\n## [1.1.0] - 2024-10-31\n\n\n\n[Compare v1.1.0.beta2...v1.1.0](https://github.com/dry-rb/dry-system/compare/v1.1.0.beta2...v1.1.0)\n\n## [1.1.0.beta2] - 2024-09-25\n\n\n### Changed\n\n- Allow provider sources to use a custom superclass. This requires a custom provider registrar\nto be configured, with its own implementations of `#provider_source_class` (the superclass to\nuse) and `#provider_source_options` (custom initialization args to pass to the provider\nsource). (via #275) (@alassek, @timriley)\n\n[Compare v1.1.0.beta1...v1.1.0.beta2](https://github.com/dry-rb/dry-system/compare/v1.1.0.beta1...v1.1.0.beta2)\n\n## [1.1.0.beta1] - 2024-07-03\n\n\n### Added\n\n- Add `Dry::System::ProviderRegistrar#target_container`, to be passed when initializing\nproviders. By default this is an alias of `#container`. This allows for custom provider\nregistrars to override `#target_container` to provide a custom `#target` within providers.\nAn overridden value **MUST** still wrap the original `#target_container` to ensure components\nare registered in the right place. (via #270) (@timriley)\n\n### Changed\n\n- Make `Dry::System::ProviderRegistrar` public API (via #270) (@timriley)\n- When registering a provider source, you can now provide a `provider_options:` hash of default\noptions for providers to be registered using that source. The one provider option currently\nsupported is `namespace:`. (via #271) (@timriley)\n- Load providers when accessing them via `Dry::System::ProviderRegistrar#[]`. The previous,\nbehavior of `#[]` returning `nil` if a provider had not been explicitly loaded was a\npotential source of confusion. Now `#[]` can serve as the one and only interface for fetching\na provider. (via #273) (@timriley)\n\n[Compare v1.0.1...v1.1.0.beta1](https://github.com/dry-rb/dry-system/compare/v1.0.1...v1.1.0.beta1)\n\n## [1.0.1] - 2022-11-18\n\n\n### Changed\n\n- Bumped dry-auto_inject dependency to its 1.0.0 final release (@solnic)\n\n[Compare v1.0.0...v1.0.1](https://github.com/dry-rb/dry-system/compare/v1.0.0...v1.0.1)\n\n## [1.0.0] - 2022-11-18\n\n\n### Fixed\n\n- Only use DidYouMean-integrated Error for Component loading failure (via #261) (@cllns + @solnic)\n\n### Changed\n\n- This version uses dry-core 1.0 and dry-configurable 1.0 (@solnic + @flash-gordon)\n- Raise error on import after finalize (via #254) (@timriley + @tak1n)\n- Validate settings even if loader does not set value (via #246) (@oeoeaio)\n- Remove all deprecated functionality and deprecation messages (via #255) (@timriley)\n- Use main dry/monitor entrypoint for autoloading (via #257) (@timriley)\n- Use dry-configurable 1.0 (via 43c79095ccf54c6251e825ae20c97a9415e78209) (@flash-gordon)\n- Use dry-core 1.0 (via 3d0cf95aef120601e67f3e8fbbf16d004017d376) (@flash-gordon)\n- Remove dry-container dependency and update to use `Dry::Core::Container` (via 2b76554e5925fc92614627d5c1e0a9177cecf12f) (@solnic)\n\n[Compare v0.27.2...v1.0.0](https://github.com/dry-rb/dry-system/compare/v0.27.2...v1.0.0)\n\n## [0.27.2] - 2022-10-17\n\n\n### Fixed\n\n- Removed remaining manual require left-overs (@solnic)\n\n\n[Compare v0.27.1...v0.27.2](https://github.com/dry-rb/dry-system/compare/v0.27.1...v0.27.2)\n\n## [0.27.1] - 2022-10-15\n\n\n### Fixed\n\n- Tweak for zeitwerk loader (@flash-gordon)\n\n\n[Compare v0.27.0...v0.27.1](https://github.com/dry-rb/dry-system/compare/v0.27.0...v0.27.1)\n\n## [0.27.0] - 2022-10-15\n\n\n### Changed\n\n- [BREAKING] Use zeitwerk for auto-loading dry-system (@flash-gordon + @solnic)\n\nFrom now on you need to do `require \"dry/system\"` as it sets up its Zeitwerk loader and from\nthere, everything else will be auto-loaded.\n\n[Compare v0.26.0...v0.27.0](https://github.com/dry-rb/dry-system/compare/v0.26.0...v0.27.0)\n\n## [0.26.0] - 2022-10-08\n\n\n### Changed\n\n- Update dry-configurable dependency to 0.16.0 and make internal adjustments to suit (@timriley in #249)\n- Remove now-unused concurrent-ruby gem dependency (@timriley in #250)\n\n[Compare v0.25.0...v0.26.0](https://github.com/dry-rb/dry-system/compare/v0.25.0...v0.26.0)\n\n## [0.25.0] - 2022-07-10\n\n\n### Fixed\n\n- Fix incorrect type in `ManifestRegistrar#finalize!` (@alassek)\n\n### Changed\n\n- Import root components via `nil` import namespace (via #236) (@timriley)\n- Allow deeper `Provider::Source` hierarchies (via #240) (@timriley + @solnic)\n- Prefer local components when importing (via #241) (@timriley  + @solnic)\n\n[Compare v0.24.0...v0.25.0](https://github.com/dry-rb/dry-system/compare/v0.24.0...v0.25.0)\n\n## [0.24.0] - \n\n\n### Changed\n\n- dry-struct depedency was removed (@flash-gordon)\n\n[Compare v0.23.0...master](https://github.com/dry-rb/dry-system/compare/v0.23.0...master)\n\n## [0.23.0] - 2022-02-08\n\nThis is a major overhaul of bootable components (now known as “Providers”), and brings major advancements to other areas, including container imports and exports.\n\nDeprecations are in place for otherwise breaking changes to commonly used parts of dry-system, though some breaking changes remain.\n\nThis prepares the way for dry-system 1.0, which will be released in the coming months.\n\n\n### Added\n\n- Containers can configure specific components for export using `config.exports` (@timriley in #209).\n\n  ```ruby\n  class MyContainer < Dry::System::Container\n    configure do |config|\n      config.exports = %w[component_a component_b]\n    end\n  end\n  ```\n\n  Containers importing another container with configured exports will import only those components.\n\n  When importing a specific set of components (see the note in the “Changed” section below), only those components whose keys intersect with the configured exports will be imported.\n- A `:zeitwerk` plugin, to set up [Zeitwerk](https://github.com/fxn/zeitwerk) and integrate it with your container configuration (@ianks and @timriley in #197, #222, 13f8c87, #223)\n\n  This makes it possible to enable Zeitwerk with a one-liner:\n\n  ```ruby\n  class MyContainer < Dry::System::Container\n    use :zeitwerk\n\n    configure do |config|\n      config.component_dirs.add \"lib\"\n      # ...\n    end\n  end\n  ```\n\n  The plugin makes a `Zeitwerk::Loader` instance available at `config.autoloader`, and then in an after-`:configure` hook, the plugin will set up the loader to work with all of your configured component dirs and their namespaces. It will also enable the `Dry::System::Loader::Autoloading` loader for all component dirs, plus disable those dirs from being added to the `$LOAD_PATH`.\n\n  The plugin accepts the following options:\n\n  - `loader:` - (optional) to use a pre-initialized loader, if required.\n  - `run_setup:` - (optional) a bool to determine whether to run `Zeitwerk::Loader#setup` as part of the after-`:configure` hook. This may be useful to disable in advanced cases when integrating with an externally managed loader.\n  - `eager_load:` - (optional) a bool to determine whether to run `Zeitwerk::Loader#eager_load` as part of an after-`:finalize` hook. When not provided, it will default to true if the `:env` plugin is enabled and the env is set to `:production`.\n  - `debug:` - (optional) a bool to set whether Zeitwerk should log to `$stdout`.\n- New `Identifier#end_with?` and `Identifier#include?` predicates (@timriley in #219)\n\n  These are key segment-aware predicates that can be useful when checking components as part of container configuration.\n\n  ```ruby\n  identifier.key # => \"articles.operations.create\"\n\n  identifier.end_with?(\"create\") # => true\n  identifier.end_with?(\"operations.create\") # => true\n  identifier.end_with?(\"ate\") # => false, not a whole segment\n  identifier.end_with?(\"nope\") # => false, not part of the key at all\n\n  identifier.include?(\"operations\") # => true\n  identifier.include?(\"articles.operations\") # => true\n  identifier.include?(\"operations.create\") # => true\n  identifier.include?(\"article\") # false, not a whole segment\n  identifier.include?(\"update\") # => false, not part of the key at all\n  ```\n- An `instance` setting for component dirs allows simpler per-dir control over component instantiation (@timriley in #215)\n\n  This optional setting should be provided a proc that receives a single `Dry::System::Component` instance as an argument, and should return the instance for the given component.\n\n  ```ruby\n  configure do |config|\n    config.component_dirs.add \"lib\" do |dir|\n      dir.instance = proc do |component|\n        if component.identifier.include?(\"workers\")\n          # Register classes for jobs\n          component.loader.constant(component)\n        else\n          # Otherwise register regular instances per default loader\n          component.loader.call(component)\n        end\n      end\n    end\n  end\n  ```\n\n  For complete control of component loading, you should continue to configure the component dir’s `loader` instead.\n- A new `ComponentNotLoadableError` error and helpful message is raised when resolving a component and an unexpected class is defined in the component’s source file (@cllns in #217).\n\n  The error shows expected and found class names, and inflector configuration that may be required in the case of class names containing acronyms.\n\n### Fixed\n\n- Registrations made in providers (by calling `register` inside a provider step) have all their registration options preserved (such as a block-based registration, or the `memoize:` option) when having their registration merged into the target container after the provider lifecycle steps complete (@timriley in #212).\n- Providers can no longer implicitly re-start themselves while in the process of starting and cause an infinite loop (@timriley #213).\n\n  This was possible before when a provider resolved a component from the target container that auto-injected dependencies with container keys sharing the same base key as the provider name.\n\n### Changed\n\n- “Bootable components” (also referred to in some places simply as “components”) have been renamed to “Providers” (@timriley in #200).\n\n  Register a provider with `Dry::System::Container.register_provider` (`Dry::System::Container.boot` has been deprecated):\n\n  ```ruby\n  MyContainer.register_provider(:mailer) do\n    # ...\n  end\n  ```\n- Provider `init` lifecycle step has been deprecated and renamed to `prepare` (@timriley in #200).\n\n  ```ruby\n  MyContainer.reigster_provider(:mailer) do\n    # Rename `init` to `prepare`\n    prepare do\n      require \"some/third_party/mailer\"\n    end\n  end\n  ```\n- Provider behavior is now backed by a class per provider, known as the “Provider source” (@timriley in #202).\n\n  The provider source class is created for each provider as a subclass of `Dry::System::Provider::Source`.\n\n  You can still register simple providers using the block-based DSL, but the class backing means you can share state between provider steps using regular instance variables:\n\n  ```ruby\n  MyContainer.reigster_provider(:mailer) do\n    prepare do\n      require \"some/third_party/mailer\"\n      @some_config = ThirdParty::Mailer::Config.new\n    end\n\n    start do\n      # Since the `prepare` step will always run before start, we can access\n      # @some_config here\n      register \"mailer\", ThirdParty::Mailer.new(@some_config)\n    end\n  end\n  ```\n\n  Inside this `register_provider` block, `self` is the source subclass itself, and inside each of the step blocks (i.e. `prepare do`), `self` will be the _instance_ of that provider source.\n\n  For more complex providers, you can define your own source subclass and register it directly with the `source:` option for `register_provider`. This allows you to more readily use standard arrangements for factoring your logic within a class, such as extraction to another method:\n\n  ```ruby\n  MyContainer.register_provider(:mailer, source: Class.new(Dry::System::Provider::Source) {\n    # The provider lifecycle steps are ordinary methods\n    def prepare\n    end\n\n    def start\n      mailer = some_complex_logic_to_build_the_mailer(some: \"config\")\n      register(:mailer, mailer)\n    end\n\n    private\n\n    def some_complex_logic_to_build_the_mailer(**options)\n      # ...\n    end\n  })\n  ```\n- The block argument to `Dry::System::Container.register_provider` (previously `.boot`) has been deprecated. (@timriley in #202).\n\n  This argument was used to give you access to the provider's target container (i.e. the container on which you were registering the provider).\n\n  To access the target container, you can use `#target_container` (or `#target` as a convenience alias) instead.\n\n  You can also access the provider's own container (which is where the provider's components are registered when you call `register` directly inside a provider step) as `#provider_container` (or `#container` as a convenience alias).\n- `use(provider_name)` inside a provider step has been deprecated. Use `target_container.start(provider_name)` instead (@timriley in #211 and #224)\n\n  Now that you can access `target_container` consistently within all provider steps, you can use it to also start any other providers as you require without any special additional method. This also allows you to invoke other provider lifecycle steps, like `target_container.prepare(provider_name)`.\n- `method_missing`-based delegation within providers to target container registrations has been removed (**BREAKING**) (@timriley in #202)\n\n  Delegation to registrations with the provider's own container has been kept, since it can be a convenient way to access registrations made in a prior lifecycle step:\n\n  ```ruby\n  MyContainer.register_provider(:mailer, namespace: true) do\n    prepare do\n      register :config, \"mailer config here\"\n    end\n\n    start do\n      config # => \"mailer config here\"\n    end\n  end\n  ```\n- The previous \"external component\" and \"provider\" concepts have been renamed to \"external provider sources\", in keeping with the new provider terminology outlined above (@timriley in #200 and #202).\n\n  You can register a collection of external provider sources defined in their own source files via `Dry::System.register_provider_sources` (`Dry::System.register_provider` has been deprecated):\n\n  ```ruby\n  require \"dry/system\"\n\n  Dry::System.register_provider_sources(path)\n  ```\n\n  You can register an individual external provider source via `Dry::System.register_provider_source` (`Dry::System.register_component` has been deprecated):\n\n  ```ruby\n  Dry::System.register_provider_source(:something, group: :my_gem) do\n    start do\n      # ...\n    end\n  end\n  ```\n\n  Just like providers, you can also register a class as an external provider source:\n\n  ```ruby\n  module MyGem\n    class MySource < Dry::System::Provider::Source\n      def start\n        # ...\n      end\n    end\n  end\n\n  Dry::System.register_provider_source(:something, group: :my_gem, source: MyGem::MySource)\n  ```\n\n  The `group:` argument when registering an external provider sources is for preventing name clashes between provider sources. You should use an underscored version of your gem name or namespace when registering your own provider sources.\n- Registering a provider using an explicitly named external provider source via `key:` argument is deprecated, use the `source:` argument instead (@timriley in #202).\n\n  You can register a provider using the same name as an external provider source by specifying the `from:` argument only, as before:\n\n  ```ruby\n  # Elsewhere\n  Dry::System.register_provider_source(:something, group: :my_gem) { ... }\n\n  # In your app:\n  MyContainer.register_provider(:something, from: :my_gem)\n  ```\n\n  When you wish the name your provider differently, this is when you need to use the `source:` argument:\n\n  ```ruby\n  MyContainer.register_provider(:differently_named, from: :my_gem, source: :something)\n  ```\n\n  When you're registering a provider using an external provider source, you cannot provie your own `Dry::System::Provider::Source` subclass as the `source:`, since that source class is being provided by the external provider source.\n- Provider source settings are now defined using dry-configurable’s `setting` API at the top-level scope (@timriley in #202).\n\n  Use the top-level `setting` method to define your settings (the `settings` block and settings defined inside the block using `key` is deprecated). Inside the provider steps, the configured settings can be accessed as `config`:\n\n  ```ruby\n  # In the external provider source\n  Dry::System.register_provider_source(:something, group: :my_gem) do\n    setting :my_option\n\n    start do\n      # Do something with `config.my_option` here\n    end\n  end\n  ```\n\n  When using an external provider source, configure the source via the `#configure`:\n\n  ```ruby\n  # In your application's provider using the external source\n  MyContainer.register_provider(:something, from: :my_gem) do\n    configure do |config|\n      config.my_option = \"some value\"\n    end\n  end\n  ```\n\n  To provide default values and type checking or constraints for your settings, use the dry-configurable’s `default:` and `constructor:` arguments:\n\n  ```ruby\n  # Constructor can take any proc being passed the provided value\n  setting :my_option, default: \"hello\", constructor: -> (v) { v.to_s.upcase }\n\n  # Constructor will also work with dry-types objects\n  setting :my_option, default: \"hello\", constructor: Types::String.constrained(min_size: 3)\n  ```\n- External provider sources can define their own methods for use by the providers alongside lifecycle steps (@timriley in #202).\n\n  Now that provider sources are class-backed, external provider sources can define their own methods to be made available when that provider source is used. This makes it possible to define your own extended API for interacting with the provider source:\n\n  ```ruby\n  # In the external provider source\n\n  module MyGem\n    class MySource < Dry::System::Provider::Source\n      # Standard lifecycle steps\n      def start\n        # Do something with @on_start here\n      end\n\n      # Custom behavior available when this provider source is used in a provider\n      def on_start(&block)\n        @on_start = block\n      end\n    end\n  end\n\n  Dry::System.register_provider_source(:something, group: :my_gem, source: MyGem::MySource)\n\n  # In your application's provider using the external source\n\n  MyContainer.register_provider(:something, from: :my_gem) do\n    # Use the custom method!\n    on_start do\n      # ...\n    end\n  end\n  ```\n- Providers can be registered conditionally using the `if:` option (@timriley in #218).\n\n  You should provide a simple truthy or falsey value to `if:`, and in the case of falsey value, the provider will not be registered.\n\n  This is useful in cases where you have providers that are loaded explicitly for specific runtime configurations of your app (e.g. when they are needed for specific tasks or processes only), but you do not need them for your primaary app process, for which you may finalize your container.\n- `bootable_dirs` container setting has been deprecated and replaced by `provider_dirs` (@timriley in #200).\n\n  The default value for `provider_dirs` is now `\"system/providers`\".\n- Removed the unused `system_dir` container setting (**BREAKING**) (@timriley in #200)\n\n  If you’ve configured this inside your container, you can remove it.\n- dry-system’s first-party external provider sources now available via `require \"dry/system/provider_sources\"`, with the previous `require \"dry/system/components\"` deprecated (@timriley in #202).\n- When using registering a provider using a first-party dry-system provider source, `from: :dry_system` instead of `from: :system` (which is now deprecated) (@timriley in #202).\n\n  ```ruby\n  MyContainer.register_provider(:settings, from: :dry_system) do\n    # ...\n  end\n- When registering a provider using the `:settings` provider source, settings are now defined using `setting` inside a `settings` block, rather than `key`, which is deprecated (@timriley in #202).\n\n  This `setting` method uses the dry-configurable setting API:\n\n  ```ruby\n  MyContainer.register_provider(:settings, from: :dry_system) do\n    settings do\n      # Previously:\n      # key :my_int_setting, MyTypes::Coercible::Integer\n\n      # Now:\n      setting :my_setting, default: 0, constructor: MyTypes::Coercible::Integer\n    end\n  end\n  ```\n- The `:settings` provider source now requires the dotenv gem to load settings from `.env*` files (**BREAKING**) (@timriley in #204)\n\n  To ensure you can load your settings from these `.env*` files, add `gem \"dotenv\"` to your `Gemfile`.\n- `Dry::System::Container` can be now be configured direclty using the setting writer methods on the class-level `.config` object, without going the `.configure(&block)` API (@timriley in #207).\n\n   If configuring via the class-level `.config` object, you should call `.configured!` after you're completed your configuration, which will finalize (freeze) the `config` object and then run any after-`:configure` hooks.\n- `Dry::System::Container.configure(&block)` will now finalize (freeze) the `config` object by default, before returning (@timriley in #207).\n\n  You can opt out of this behavior by passing the `finalize_config: false` option:\n\n  ```ruby\n  class MyContainer < Dry::System::Container\n    configure(finalize_config: false) do |config|\n      # ...\n    end\n\n    # `config` is still non-finalized here\n  end\n  ```\n- `Dry::System::Container.finalize!` will call `.configured!` (if it has not yet been called) before doing its work (@timriley in #207)\n\n  This ensures config finalization is an intrinsic part of the overall container finalization process.\n- The `Dry::System::Container` `before(:configure)` hook has been removed (**BREAKING**) (@timriley in #207).\n\n  This was previously used for plugins to register their own settings, but this was not necessary given that plugins are modules, and can use their ordinary `.extended(container_class)` hook to register their settings. Essentially, any time after container subclass definition is \"before configure\" in nature.\n- Container plugins should define their settings on the container using their module `.extended` hook, no longer in a `before(:configure)` hook (as above) (**BREAKING**) (@timriley in #207).\n\n  This ensures the plugin settings are available immediately after you’ve enabled the plugin via `Dry::System::Container.use`.\n- The `Dry::System::Container` key `namespace_separator` setting is no longer expected to be user-configured. A key namespace separator of \".\" is hard-coded and expected to remain the separator string. (@timriley in #206)\n- Containers can import a specific subset of another container’s components via changes to `.import`, which is now `.import(keys: nil, from:, as:)` (with prior API deprecated) (@timriley in #209)\n\n  To import specific components:\n\n  ```ruby\n  class MyContainer < Dry::System::Container\n    # config, etc.\n\n    # Will import components with keys \"other.component_a\", \"other.component_b\"\n    import(\n      keys: %w[component_a component_b],\n      from: OtherContainer,\n      as: :other\n    )\n  ```\n\n  Omitting `keys:` will import all the components available from the other container.\n- Components imported into a container from another will be protected from subsequent export unless explicitly configured in `config.exports` (@timriley in #209)\n\n  Imported components are considered “private” by default because they did not originate in container that imported them.\n\n  This ensures there are no redundant imports in arrangements where multiple all containers import a common “base” container, and then some of those containers then import each other.\n- Container imports are now made without finalizing the exporting container in most cases, ensuring more efficient imports (@timriley in #209)\n\n  Now, the only time the exporting container will be finalized is when a container is importing all components, and the exporting container has not declared any components in `config.exports`.\n- [Internal] The `manual_registrar` container setting and associated `ManualRegistrar` class have been renamed to `manifest_registrar` and `ManifestRegistrar` respectively (**BREAKING**) (@timriley in #208).\n- The default value for the container `registrations_dir` setting has been changed from `\"container\"` to `\"system/registrations\"` (**BREAKING**) (@timriley in #208)\n- The `:dependency_graph` plugin now supports all dry-auto_inject injector strategies (@davydovanton and @timriley in #214)\n\n[Compare v0.22.0...v0.23.0](https://github.com/dry-rb/dry-system/compare/v0.22.0...v0.23.0)\n\n## [0.22.0] - 2022-01-06\n\n\n### Added\n\n- Expanded public interfaces for `Dry::System::Config::ComponentDirs` and `Dry::System::Config::Namespaces` to better support programmatic construction and inspection of these configs (@timriley in #195)\n\n### Changed\n\n- Deprecated `Dry::System::Config::Namespaces#root` as the way to add and configure a root namespace. Use `#add_root` instead (@timriley in #195)\n- Allow bootsnap plugin to use bootsnap on Ruby versions up to 3.0 (pusewicz in #196)\n\n[Compare v0.21.0...v0.22.0](https://github.com/dry-rb/dry-system/compare/v0.21.0...v0.22.0)\n\n## [0.21.0] - 2021-11-01\n\n\n### Added\n\n- Added **component dir namespaces** as a way to specify multiple, ordered, independent namespace rules within a given component dir. This replaces and expands upon the namespace support we previously provided via the singular `default_namespace` component dir setting (@timriley in #181)\n\n### Changed\n\n- `default_namespace` setting on component dirs has been deprecated. Add a component dir namespace instead, e.g. instead of:\n\n  ```ruby\n  # Inside Dry::System::Container.configure\n  config.component_dirs.add \"lib\" do |dir|\n    dir.default_namespace = \"admin\"\n  end\n  ```\n\n  Add this:\n\n  ```ruby\n  config.component_dirs.add \"lib\" do |dir|\n    dir.namespaces.add \"admin\", key: nil\n  end\n  ```\n\n  (@timriley in #181)\n- `Dry::System::Component#path` has been removed and replaced by `Component#require_path` and `Component#const_path` (@timriley in #181)\n- Unused `Dry::System::FileNotFoundError` and `Dry::System::InvalidComponentIdentifierTypeError` errors have been removed (@timriley in #194)\n- Allow bootsnap for Rubies up to 3.0.x (via #196) (@pusewicz)\n\n[Compare v0.20.0...v0.21.0](https://github.com/dry-rb/dry-system/compare/v0.20.0...v0.21.0)\n\n## [0.20.0] - 2021-09-12\n\n\n### Fixed\n\n- Fixed dependency graph plugin to work with internal changes introduced in 0.19.0 (@wuarmin in #173)\n- Fixed behavior of `Dry::System::Identifier#start_with?` for components identified by a single segment, or if all matching segments are provided (@wuarmin in #177)\n- Fixed compatibility of `finalize!` signature provided in `Container::Stubs` (@mpokrywka in #178)\n\n### Changed\n\n- [internal] Upgraded to new `setting` API provided in dry-configurable 0.13.0 (@timriley in #179)\n\n[Compare v0.19.2...v0.20.0](https://github.com/dry-rb/dry-system/compare/v0.19.2...v0.20.0)\n\n## [0.19.2] - 2021-08-30\n\n\n### Changed\n\n- [internal] Improved compatibility with upcoming dry-configurable 0.13.0 release (@timriley in #186)\n\n[Compare v0.18.2...v0.19.2](https://github.com/dry-rb/dry-system/compare/v0.18.2...v0.19.2)\n\n## [0.18.2] - 2021-08-30\n\n\n### Changed\n\n- [internal] Improved compatibility with upcoming dry-configurable 0.13.0 release (@timriley in #187)\n\n[Compare v0.19.1...v0.18.2](https://github.com/dry-rb/dry-system/compare/v0.19.1...v0.18.2)\n\n## [0.19.1] - 2021-07-11\n\n\n### Fixed\n\n- Check for registered components (@timriley in #175)\n\n\n[Compare v0.19.0...v0.19.1](https://github.com/dry-rb/dry-system/compare/v0.19.0...v0.19.1)\n\n## [0.19.0] - 2021-04-22\n\nThis release marks a huge step forward for dry-system, bringing support for Zeitwerk and other autoloaders, plus clearer configuration and improved consistency around component resolution for both finalized and lazy loading containers. [Read the announcement post](https://dry-rb.org/news/2021/04/22/dry-system-0-19-released-with-zeitwerk-support-and-more-leading-the-way-for-hanami-2-0/) for a high-level tour of the new features.\n\n### Added\n\n- New `component_dirs` setting on `Dry::System::Container`, which must be used for specifying the directories which dry-system will search for component source files.\n\n  Each added component dir is relative to the container's `root`, and can have its own set of settings configured:\n\n  ```ruby\n  class MyApp::Container < Dry::System::Container\n    configure do |config|\n      config.root = __dir__\n\n      # Defaults for all component dirs can be configured separately\n      config.component_dirs.auto_register = true # default is already true\n\n      # Component dirs can be added and configured independently\n      config.component_dirs.add \"lib\" do |dir|\n        dir.add_to_load_path = true # defaults to true\n        dir.default_namespace = \"my_app\"\n      end\n\n      # All component dir settings are optional. Component dirs relying on default\n      # settings can be added like so:\n      config.component_dirs.add \"custom_components\"\n    end\n  end\n  ```\n\n  The following settings are available for configuring added `component_dirs`:\n\n  - `auto_register`, a boolean, or a proc accepting a `Dry::System::Component` instance and returning a truthy or falsey value. Providing a proc allows an auto-registration policy to apply on a per-component basis\n  - `add_to_load_path`, a boolean\n  - `default_namespace`, a string representing the leading namespace segments to be stripped from the component's identifier (given the identifier is derived from the component's fully qualified class name)\n  - `loader`, a custom replacement for the default `Dry::System::Loader` to be used for the component dir\n  - `memoize`, a boolean, to enable/disable memoizing all components in the directory, or a proc accepting a `Dry::System::Component` instance and returning a truthy or falsey value. Providing a proc allows a memoization policy to apply on a per-component basis\n\n  _All component dir settings are optional._\n\n  (@timriley in #155, #157, and #162)\n- A new autoloading-friendly `Dry::System::Loader::Autoloading` is available, which is tested to work with [Zeitwerk](https://github.com/fxn/zeitwerk) 🎉\n\n  Configure this on the container (via a component dir `loader` setting), and the loader will no longer `require` any components, instead allowing missing constant resolution to trigger the loading of the required file.\n\n  This loader presumes an autoloading system like Zeitwerk has already been enabled and appropriately configured.\n\n  A recommended setup is as follows:\n\n  ```ruby\n  require \"dry/system/container\"\n  require \"dry/system/loader/autoloading\"\n  require \"zeitwerk\"\n\n  class MyApp::Container < Dry::System::Container\n    configure do |config|\n      config.root = __dir__\n\n      config.component_dirs.loader = Dry::System::Loader::Autoloading\n      config.component_dirs.add_to_load_path = false\n\n      config.component_dirs.add \"lib\" do |dir|\n        # ...\n      end\n    end\n  end\n\n  loader = Zeitwerk::Loader.new\n  loader.push_dir MyApp::Container.config.root.join(\"lib\").realpath\n  loader.setup\n  ```\n\n  (@timriley in #153)\n- [BREAKING] `Dry::System::Component` instances (which users of dry-system will interact with via custom loaders, as well as via the `auto_register` and `memoize` component dir settings described above) now return a `Dry::System::Identifier` from their `#identifier` method. The raw identifier string may be accessed via the identifier's own `#key` or `#to_s` methods. `Identifier` also provides a helpful namespace-aware `#start_with?` method for returning whether the identifier begins with the provided namespace(s) (@timriley in #158)\n\n### Changed\n\n- Components with `# auto_register: false` magic comments in their source files are now properly ignored when lazy loading (@timriley in #155)\n- `# memoize: true` and `# memoize: false` magic comments at top of component files are now respected (@timriley in #155)\n- [BREAKING] `Dry::System::Container.load_paths!` has been renamed to `.add_to_load_path!`. This method now exists as a mere convenience only. Calling this method is no longer required for any configured `component_dirs`; these are now added to the load path automatically (@timriley in #153 and #155)\n- [BREAKING] `auto_register` container setting has been removed. Configured directories to be auto-registered by adding `component_dirs` instead (@timriley in #155)\n- [BREAKING] `default_namespace` container setting has been removed. Set it when adding `component_dirs` instead (@timriley in #155)\n- [BREAKING] `loader` container setting has been nested under `component_dirs`, now available as `component_dirs.loader` to configure a default loader for all component dirs, as well as on individual component dirs when being added (@timriley in #162)\n- [BREAKING] `Dry::System::ComponentLoadError` is no longer raised when a component could not be lazy loaded; this was only raised in a single specific failure condition. Instead, a `Dry::Container::Error` is raised in all cases of components failing to load (@timriley in #155)\n- [BREAKING] `Dry::System::Container.auto_register!` has been removed. Configure `component_dirs` instead. (@timriley in #157)\n- [BREAKING] The `Dry::System::Loader` interface has changed. It is now a static interface, no longer initialized with a component. The component is instead passed to each method as an argument: `.require!(component)`, `.call(component, *args)`, `.constant(component)` (@timriley in #157)\n- [BREAKING] `Dry::System::Container.require_path` has been removed. Provide custom require behavior by configuring your own `loader` (@timriley in #153)\n\n[Compare v0.18.1...v0.19.0](https://github.com/dry-rb/dry-system/compare/v0.18.1...v0.19.0)\n\n## [0.18.1] - 2020-08-26\n\n\n### Fixed\n\n- Made `Booter#boot_files` a public method again, since it was required by dry-rails (@timriley)\n\n\n[Compare v0.18.0...v0.18.1](https://github.com/dry-rb/dry-system/compare/v0.18.0...v0.18.1)\n\n## [0.18.0] - 2020-08-24\n\n\n### Added\n\n- New `bootable_dirs` setting on `Dry::System::Container`, which accepts paths to multiple directories for looking up bootable component files. (@timriley in PR #151)\n\n  For each entry in the `bootable_dirs` array, relative directories will be appended to the container's `root`, and absolute directories will be left unchanged.\n\n  When searching for bootable files, the first match will win, and any subsequent same-named files will not be loaded. In this way, the `bootable_dirs` act similarly to the `$PATH` in a shell environment.\n\n\n[Compare v0.17.0...v0.18.0](https://github.com/dry-rb/dry-system/compare/v0.17.0...v0.18.0)\n\n## [0.17.0] - 2020-02-19\n\n\n### Fixed\n\n- Works with the latest dry-configurable version (issue #141) (@solnic)\n\n### Changed\n\n- Depends on dry-configurable `=> 0.11.1` now (@solnic)\n\n[Compare v0.16.0...v0.17.0](https://github.com/dry-rb/dry-system/compare/v0.16.0...v0.17.0)\n\n## [0.16.0] - 2020-02-15\n\n\n### Changed\n\n- Plugins can now define their own settings which are available in the `before(:configure)` hook (@solnic)\n- Dependency on dry-configurable was bumped to `~> 0.11` (@solnic)\n\n[Compare v0.15.0...v0.16.0](https://github.com/dry-rb/dry-system/compare/v0.15.0...v0.16.0)\n\n## [0.15.0] - 2020-01-30\n\n\n### Added\n\n- New hook - `before(:configure)` which a plugin should use if it needs to declare new settings (@solnic)\n\n```ruby\n# in your plugin code\nbefore(:configure) { setting :my_new_setting }\n\nafter(:configure) { config.my_new_setting = \"awesome\" }\n```\n\n\n### Changed\n\n- Centralize error definitions in `lib/dry/system/errors.rb` (@cgeorgii)\n- All built-in plugins use `before(:configure)` now to declare their settings (@solnic)\n\n[Compare v0.14.1...v0.15.0](https://github.com/dry-rb/dry-system/compare/v0.14.1...v0.15.0)\n\n## [0.14.1] - 2020-01-22\n\n\n### Changed\n\n- Use `Kernel.require` explicitly to avoid issues with monkey-patched `require` from ActiveSupport (@solnic)\n\n[Compare v0.14.0...v0.14.1](https://github.com/dry-rb/dry-system/compare/v0.14.0...v0.14.1)\n\n## [0.14.0] - 2020-01-21\n\n\n### Fixed\n\n- Misspelled plugin name raises meaningful error (issue #132) (@cgeorgii)\n- Fail fast if auto_registrar config contains incorrect path (@cutalion)\n\n\n[Compare v0.13.2...v0.14.0](https://github.com/dry-rb/dry-system/compare/v0.13.2...v0.14.0)\n\n## [0.13.2] - 2019-12-28\n\n\n### Fixed\n\n- More keyword warnings (flash-gordon)\n\n\n[Compare v0.13.1...v0.13.2](https://github.com/dry-rb/dry-system/compare/v0.13.1...v0.13.2)\n\n## [0.13.1] - 2019-11-07\n\n\n### Fixed\n\n- Fixed keyword warnings reported by Ruby 2.7 (flash-gordon)\n- Duplicates in `Dry::System::Plugins.loaded_dependencies` (AMHOL)\n\n\n[Compare v0.13.0...v0.13.1](https://github.com/dry-rb/dry-system/compare/v0.13.0...v0.13.1)\n\n## [0.13.0] - 2019-10-13\n\n\n### Added\n\n- `Container.resolve` accepts and optional block parameter which will be called if component cannot be found. This makes dry-system consistent with dry-container 0.7.2 (flash-gordon)\n  ```ruby\n  App.resolve('missing.dep') { :fallback } # => :fallback\n  ```\n\n### Changed\n\n- [BREAKING] `Container.key?` triggers lazy-loading for not finalized containers. If component wasn't found it returns `false` without raising an error. This is a breaking change, if you seek the previous behavior, use `Container.registered?` (flash-gordon)\n\n[Compare v0.12.0...v0.13.0](https://github.com/dry-rb/dry-system/compare/v0.12.0...v0.13.0)\n\n## [0.12.0] - 2019-04-24\n\n\n### Changed\n\n- Compatibility with dry-struct 1.0 and dry-types 1.0 (flash-gordon)\n\n[Compare v0.11.0...v0.12.0](https://github.com/dry-rb/dry-system/compare/v0.11.0...v0.12.0)\n\n## [0.11.0] - 2019-03-22\n\n\n### Changed\n\n- [BREAKING] `:decorate` plugin was moved from dry-system to dry-container (available in 0.7.0+). To upgrade remove `use :decorate` and change `decorate` calls from `decorate(key, decorator: something)` to `decorate(key, with: something)` (flash-gordon)\n- [internal] Compatibility with dry-struct 0.7.0 and dry-types 0.15.0\n\n[Compare v0.10.1...v0.11.0](https://github.com/dry-rb/dry-system/compare/v0.10.1...v0.11.0)\n\n## [0.10.1] - 2018-07-05\n\n\n### Added\n\n- Support for stopping bootable components with `Container.stop(component_name)` (GustavoCaso)\n\n### Fixed\n\n- When using a non-finalized container, you can now resolve multiple different container objects registered using the same root key as a bootable component (timriley)\n\n\n[Compare v0.10.0...v0.10.1](https://github.com/dry-rb/dry-system/compare/v0.10.0...v0.10.1)\n\n## [0.10.0] - 2018-06-07\n\n\n### Added\n\n- You can now set a custom inflector on the container level. As a result, the `Loader`'s constructor accepts two arguments: `path` and `inflector`, update your custom loaders accordingly (flash-gordon)\n\n  ```ruby\n  class MyContainer < Dry::System::Container\n    configure do |config|\n      config.inflector = Dry::Inflector.new do |inflections|\n        inflections.acronym('API')\n      end\n    end\n  end\n  ```\n\n### Changed\n\n- A helpful error will be raised if an invalid setting value is provided (GustavoCaso)\n- When using setting plugin, will use default values from types (GustavoCaso)\n- Minimal supported ruby version was bumped to `2.3` (flash-gordon)\n- `dry-struct` was updated to `~> 0.5` (flash-gordon)\n\n[Compare v0.9.2...v0.10.0](https://github.com/dry-rb/dry-system/compare/v0.9.2...v0.10.0)\n\n## [0.9.2] - 2018-02-08\n\n\n### Fixed\n\n- Default namespace no longer breaks resolving dependencies with identifier that includes part of the namespace (ie `mail.mailer`) (GustavoCaso)\n\n\n[Compare v0.9.1...v0.9.2](https://github.com/dry-rb/dry-system/compare/v0.9.1...v0.9.2)\n\n## [0.9.1] - 2018-01-03\n\n\n### Fixed\n\n- Plugin dependencies are now auto-required and a meaningful error is raised when a dep failed to load (solnic)\n\n\n[Compare v0.9.0...v0.9.1](https://github.com/dry-rb/dry-system/compare/v0.9.0...v0.9.1)\n\n## [0.9.0] - 2018-01-02\n\n\n### Added\n\n- Plugin API (solnic)\n- `:env` plugin which adds support for setting `env` config value (solnic)\n- `:logging` plugin which adds a default logger (solnic)\n- `:decorate` plugin for decorating registered objects (solnic)\n- `:notifications` plugin adding pub/sub bus to containers (solnic)\n- `:monitoring` plugin which adds `monitor` method for monitoring object method calls (solnic)\n- `:bootsnap` plugin which adds support for bootsnap (solnic)\n\n### Changed\n\n- [BREAKING] renamed `Container.{require=>require_from_root}` (GustavoCaso)\n\n[Compare v0.8.1...v0.9.0](https://github.com/dry-rb/dry-system/compare/v0.8.1...v0.9.0)\n\n## [0.8.1] - 2017-10-17\n\n\n### Fixed\n\n- Aliasing an external component works correctly (solnic)\n- Manually calling `:init` will also finalize a component (solnic)\n\n\n[Compare v0.8.0...v0.8.1](https://github.com/dry-rb/dry-system/compare/v0.8.0...v0.8.1)\n\n## [0.8.0] - 2017-10-16\n\n\n### Added\n\n- Support for external bootable components (solnic)\n- Built-in `:system` components including `:settings` component (solnic)\n\n### Fixed\n\n- Lazy-loading components work when a container has `default_namespace` configured (GustavoCaso)\n\n### Changed\n\n- [BREAKING] Improved boot DSL with support for namespacing and lifecycle before/after callbacks (solnic)\n\n[Compare v0.7.3...v0.8.0](https://github.com/dry-rb/dry-system/compare/v0.7.3...v0.8.0)\n\n## [0.7.3] - 2017-08-02\n\n\n### Fixed\n\n- `Container.enable_stubs!` calls super too, which actually adds `stub` API (solnic)\n- Issues with lazy-loading and import in stub mode are gone (solnic)\n\n\n[Compare v0.7.2...v0.7.3](https://github.com/dry-rb/dry-system/compare/v0.7.2...v0.7.3)\n\n## [0.7.2] - 2017-08-02\n\n\n### Added\n\n- `Container.enable_stubs!` for test environments which enables stubbing components (GustavoCaso)\n\n### Changed\n\n- Component identifiers can now include same name more than once ie `foo.stuff.foo` (GustavoCaso)\n- `Container#boot!` was renamed to `Container#start` (davydovanton)\n- `Container#boot` was renamed to `Container#init` (davydovanton)\n\n[Compare v0.7.1...v0.7.2](https://github.com/dry-rb/dry-system/compare/v0.7.1...v0.7.2)\n\n## [0.7.1] - 2017-06-16\n\n\n### Changed\n\n- Accept string values for Container's `root` config (timriley)\n\n[Compare v0.7.0...v0.7.1](https://github.com/dry-rb/dry-system/compare/v0.7.0...v0.7.1)\n\n## [0.7.0] - 2017-06-15\n\n\n### Added\n\n- Added `manual_registrar` container setting (along with default `ManualRegistrar` implementation), and `registrations_dir` setting. These provide support for a well-established place for keeping files with manual container registrations (timriley)\n- AutoRegistrar parses initial lines of Ruby source files for \"magic comments\" when auto-registering components. An `# auto_register: false` magic comment will prevent a Ruby file from being auto-registered (timriley)\n- `Container.auto_register!`, when called with a block, yields a configuration object to control the auto-registration behavior for that path, with support for configuring 2 different aspects of auto-registration behavior (both optional):\n\n  ```ruby\n  class MyContainer < Dry::System::Container\n    auto_register!('lib') do |config|\n      config.instance do |component|\n        # custom logic for initializing a component\n      end\n\n      config.exclude do |component|\n        # return true to skip auto-registration of the component, e.g.\n        # component.path =~ /entities/\n      end\n    end\n  end\n  ```\n- A helpful error will be raised if a bootable component's finalize block name doesn't match its boot file name (GustavoCaso)\n\n### Changed\n\n- The `default_namespace` container setting now supports multi-level namespaces (GustavoCaso)\n- `Container.auto_register!` yields a configuration block instead of a block for returning a custom instance (see above) (GustavoCaso)\n- `Container.import` now requires an explicit local name for the imported container (e.g. `import(local_name: AnotherContainer)`) (timriley)\n\n[Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-system/compare/v0.6.0...v0.7.0)\n\n## [0.6.0] - 2016-02-02\n\n\n### Changed\n\n- Lazy load components as they are resolved, rather than on injection (timriley)\n- Perform registration even though component already required (blelump)\n\n[Compare v0.5.1...v0.6.0](https://github.com/dry-rb/dry-system/compare/v0.5.1...v0.6.0)\n\n## [0.5.1] - 2016-08-23\n\n\n### Fixed\n\n- Undefined locals or method calls will raise proper exceptions in Lifecycle DSL (aradunovic)\n\n\n[Compare v0.5.0...v0.5.1](https://github.com/dry-rb/dry-system/compare/v0.5.0...v0.5.1)\n\n## [0.5.0] - 2016-08-15\n\nfor multi-container setups. As part of this release `dry-system` has been renamed to `dry-system`.\n\n### Added\n\n- Boot DSL with:\n  - Lifecycle triggers: `init`, `start` and `stop` (solnic)\n  - `use` method which auto-boots a dependency and makes it available in the booting context (solnic)\n- When a component relies on a bootable component, and is being loaded in isolation, the component will be booted automatically (solnic)\n\n### Changed\n\n- [BREAKING] `Dry::Component::Container` is now `Dry::System::Container` (solnic)\n- [BREAKING] Configurable `loader` is now a class that accepts container's config and responds to `#constant` and `#instance` (solnic)\n- [BREAKING] `core_dir` renameda to `system_dir` and defaults to `system` (solnic)\n- [BREAKING] `auto_register!` yields `Component` objects (solnic)\n\n[Compare v0.4.3...v0.5.0](https://github.com/dry-rb/dry-system/compare/v0.4.3...v0.5.0)\n\n## [0.4.3] - 2016-08-01\n\n\n### Fixed\n\n- Return immediately from `Container.load_component` if the requested component key already exists in the container. This fixes a crash when requesting to load a manually registered component with a name that doesn't map to a filename (timriley in [#24](https://github.com/dry-rb/dry-system/pull/24))\n\n\n[Compare v0.4.2...v0.4.3](https://github.com/dry-rb/dry-system/compare/v0.4.2...v0.4.3)\n\n## [0.4.2] - 2016-07-26\n\n\n### Fixed\n\n- Ensure file components can be loaded when they're requested for the first time using their shorthand container identifier (i.e. with the container's default namespace removed) (timriley)\n\n\n[Compare v0.4.1...v0.4.2](https://github.com/dry-rb/dry-system/compare/v0.4.1...v0.4.2)\n\n## [0.4.1] - 2016-07-26\n\n\n### Fixed\n\n- Require the 0.4.0 release of dry-auto_inject for the features below (in 0.4.0) to work properly (timriley)\n\n\n[Compare v0.4.0...v0.4.1](https://github.com/dry-rb/dry-system/compare/v0.4.0...v0.4.1)\n\n## [0.4.0] - 2016-07-26\n\n\n### Added\n\n- Support for supplying a default namespace to a container, which is passed to the container's injector to allow for convenient shorthand access to registered objects in the same namespace (timriley in [#20](https://github.com/dry-rb/dry-system/pull/20))\n\n  ```ruby\n  # Set up container with default namespace\n  module Admin\n    class Container < Dry::Component::Container\n      configure do |config|\n        config.root = Pathname.new(__dir__).join(\"../..\")\n        config.default_namespace = \"admin\"\n      end\n    end\n\n    Import = Container.injector\n  end\n\n  module Admin\n    class CreateUser\n      # \"users.repository\" will resolve an Admin::Users::Repository instance,\n      # where previously you had to identify it as \"admin.users.repository\"\n      include Admin::Import[\"users.repository\"]\n    end\n  end\n  ```\n- Support for supplying to options directly to dry-auto_inject's `Builder` via `Dry::Component::Container#injector(options)`. This allows you to provide dry-auto_inject customizations like your own container of injection strategies (timriley in [#20](https://github.com/dry-rb/dry-system/pull/20))\n- Support for accessing all available injector strategies, not just the defaults (e.g. `MyContainer.injector.some_custom_strategy`) (timriley in [#19](https://github.com/dry-rb/dry-system/pull/19))\n\n### Changed\n\n- Subclasses of `Dry::Component::Container` no longer have an `Injector` constant automatically defined within them. The recommended approach is to save your own injector object to a constant, which allows you to pass options to it at the same time, e.g. `MyApp::Import = MyApp::Container.injector(my_options)` (timriley in [#19](https://github.com/dry-rb/dry-system/pull/19))\n\n[Compare v0.3.0...v0.4.0](https://github.com/dry-rb/dry-system/compare/v0.3.0...v0.4.0)\n\n## [0.3.0] - 2016-06-18\n\nRemoved two pieces that are moving to dry-web:\n\n### Changed\n\n- Removed two pieces that are moving to dry-web:\n- Removed `env` setting from `Container` (timriley)\n- Removed `Dry::Component::Config` and `options` setting from `Container` (timriley)\n- Changed `Component#configure` behavior so it can be run multiple times for configuration to be applied in multiple passes (timriley)\n\n[Compare v0.2.0...v0.3.0](https://github.com/dry-rb/dry-system/compare/v0.2.0...v0.3.0)\n\n## [0.2.0] - 2016-06-13\n\n\n### Fixed\n\n- Fixed bug where specified auto-inject strategies were not respected (timriley)\n\n### Changed\n\n- Component core directory is now `component/` by default (timriley)\n- Injector default stragegy is now whatever dry-auto_inject's default is (rather than hard-coding a particular default strategy for dry-system) (timriley)\n\n[Compare v0.1.0...v0.2.0](https://github.com/dry-rb/dry-system/compare/v0.1.0...v0.2.0)\n\n## [0.1.0] - 2016-06-07\n\n\n### Added\n\n- Provide a dependency injector as an `Inject` constant inside any subclass of `Dry::Component::Container`. This injector supports all of `dry-auto_inject`'s default injection strategies, and will lazily load any dependencies as they are injected. It also supports arbitrarily switching strategies, so they can be used in different classes as required (e.g. `include MyComponent::Inject.args[\"dep\"]`) (timriley)\n- Support aliased dependency names when calling the injector object (e.g. `MyComponent::Inject[foo: \"my_app.foo\", bar: \"another.thing\"]`) (timriley)\n- Allow a custom dependency loader to be set on a container via its config (AMHOL)\n\n  ```ruby\n  class MyContainer < Dry::Component::Container\n    configure do |config|\n      # other config\n      config.loader = MyLoader\n    end\n  end\n  ```\n\n### Changed\n\n- `Container.boot` now only makes a simple `require` for the boot file (solnic)\n- Container object is passed to `Container.finalize` blocks (solnic)\n- Allow `Pathname` objects passed to `Container.require` (solnic)\n- Support lazily loading missing dependencies from imported containers (solnic)\n- `Container.import_module` renamed to `.injector` (timriley)\n- Default injection strategy is now `kwargs`, courtesy of the new dry-auto_inject default (timriley)\n\n[Compare v0.0.2...v0.1.0](https://github.com/dry-rb/dry-system/compare/v0.0.2...v0.1.0)\n\n## [0.0.2] - 2015-12-24\n\n\n### Added\n\n- Containers have a `name` setting (solnic)\n- Containers can be imported into one another (solnic)\n\n### Changed\n\n- Container name is used to determine the name of its config file (solnic)\n\n[Compare v0.0.1...v0.0.2](https://github.com/dry-rb/dry-system/compare/v0.0.1...v0.0.2)\n\n## [0.0.1] - 2015-12-24\n\nFirst public release, extracted from rodakase project\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe pledge to make our community welcoming, safe, and equitable for all.\n\nWe are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant.\n\n## Encouraged Behaviors\n\nWhile acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language.\n\nWith these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including:\n\n1. Respecting the **purpose of our community**, our activities, and our ways of gathering.\n2. Engaging **kindly and honestly** with others.\n3. Respecting **different viewpoints** and experiences.\n4. **Taking responsibility** for our actions and contributions.\n5. Gracefully giving and accepting **constructive feedback**.\n6. Committing to **repairing harm** when it occurs.\n7. Behaving in other ways that promote and sustain the **well-being of our community**.\n\n## Restricted Behaviors\n\nWe agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct.\n\n1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop.\n2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people.\n3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits.\n4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community.\n5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission.\n6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.\n7. Behaving in other ways that **threaten the well-being** of our community.\n\n### Other Restrictions\n\n1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions.\n2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.\n3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community.\n4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors.\n\n## Reporting an Issue\n\nTensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm.\n\nWhen an incident does occur, it is important to report it promptly. To report a possible violation, email conduct@hanakai.org.\n\nCommunity Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution.\n\n## Addressing and Repairing Harm\n\nIf an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped.\n\n1) Warning\n   1) Event: A violation involving a single incident or series of incidents.\n   2) Consequence: A private, written warning from the Community Moderators.\n   3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations.\n2) Temporarily Limited Activities\n   1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation.\n   2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members.\n   3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over.\n3) Temporary Suspension\n   1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation.\n   2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions.\n   3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted.\n4) Permanent Ban\n   1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member.\n   2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior.\n   3) Repair: There is no possible repair in cases of this severity.\n\nThis enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.\n\n## Attribution\n\nThis Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/).\n\nContributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/)\n\nFor answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion).\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Issue guidelines\n\n## Reporting bugs\n\nIf you’ve found a bug, please report an issue and describe the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.\n\n## Reporting feature requests\n\nReport a feature request **only after discussing it first on [our forum](https://discourse.hanamirb.org)** and having it accepted. Please provide a concise description of the feature.\n\n## Reporting questions, support requests, ideas, concerns etc.\n\n**Please don’t.** Use [our forum](https://discourse.hanamirb.org) instead.\n\n# Pull request guidelines\n\nA pull request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.\n\nOther requirements:\n\n1. Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.\n2. Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.\n3. Add API documentation if it's a new feature.\n4. Update API documentation if it changes an existing feature.\n5. Bonus points for sending a PR which updates user documentation in our [site repository](https://github.com/hanakai-rb/site).\n\n# Asking for help\n\nIf these guidelines aren't helpful, and you're stuck, please post a message on [our forum](https://discourse.dry-rb.org) or [find us in chat](https://discord.gg/KFCxDmk3JQ).\n"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\neval_gemfile \"Gemfile.devtools\"\n\ngemspec\n\n# Remove verson constraint once latter versions release their -java packages\ngem \"bootsnap\"\ngem \"dotenv\"\ngem \"dry-events\"\ngem \"dry-monitor\"\ngem \"dry-types\"\n\ngem \"zeitwerk\"\n\ngroup :test do\n  gem \"ostruct\"\nend\n"
  },
  {
    "path": "Gemfile.devtools",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\ngem \"rake\", \">= 12.3.3\"\n\ngroup :test do\n  gem \"simplecov\", require: false, platforms: :ruby\n  gem \"simplecov-cobertura\", require: false, platforms: :ruby\n  gem \"rexml\", require: false\n\n  gem \"warning\"\nend\n\ngroup :tools do\n  gem \"rubocop\"\nend\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015-2026 Hanakai team\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<!--- This file is synced from hanakai-rb/repo-sync -->\n\n[actions]: https://github.com/dry-rb/dry-system/actions\n[chat]: https://discord.gg/naQApPAsZB\n[forum]: https://discourse.hanamirb.org\n[rubygem]: https://rubygems.org/gems/dry-system\n\n# dry-system [![Gem Version](https://badge.fury.io/rb/dry-system.svg)][rubygem] [![CI Status](https://github.com/dry-rb/dry-system/workflows/CI/badge.svg)][actions]\n\n[![Forum](https://img.shields.io/badge/Forum-dc360f?logo=discourse&logoColor=white)][forum]\n[![Chat](https://img.shields.io/badge/Chat-717cf8?logo=discord&logoColor=white)][chat]\n\n## Links\n\n- [User documentation](https://dry-rb.org/gems/dry-system)\n- [API documentation](http://rubydoc.info/gems/dry-system)\n- [Forum](https://discourse.dry-rb.org)\n\n## License\n\nSee `LICENSE` file.\n\n"
  },
  {
    "path": "Rakefile",
    "content": "#!/usr/bin/env rake\n# frozen_string_literal: true\n\nrequire \"bundler/gem_tasks\"\n\n$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), \"lib\"))\n\nrequire \"rspec/core\"\nrequire \"rspec/core/rake_task\"\n\ntask default: :spec\n\ndesc \"Run all specs in spec directory\"\nRSpec::Core::RakeTask.new(:spec)\n"
  },
  {
    "path": "bin/.gitkeep",
    "content": ""
  },
  {
    "path": "bin/console",
    "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nrequire \"bundler/setup\"\n\nbegin\n  require \"pry-byebug\"\n  Pry.start\nrescue LoadError\n  require \"irb\"\n  IRB.start\nend\n"
  },
  {
    "path": "docsite/source/component-dirs.html.md",
    "content": "---\ntitle: Component dirs\nlayout: gem-single\nname: dry-system\n---\n\nThe container auto-registers its components from one or more component dirs, the directories holding the Ruby source files for your classes.\n\nYou can configure one or more component dirs:\n\n```ruby\nclass Application < Dry::System::Container\n  configure do |config|\n    config.root = __dir__\n\n    config.component_dirs.add \"lib\"\n    config.component_dirs.add \"app\"\n  end\nend\n```\n\nComponent dirs will be searched in the order you add them. A component found in the first added dir will be registered in preference to a component with the same name in a later dir.\n\n### Component dir configuration\n\nYou can configure many aspects of component auto-registration via component dirs.\n\n#### auto_register\n\n`auto_register` sets the auto-registration policy for the component dir.\n\nThis may be a simple boolean to enable or disable auto-registration for all components, or a proc accepting a `Dry::Sytem::Component` and returning a boolean to configure auto-registration on a per-component basis.\n\n`auto_register` defaults to `true`.\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.auto_register = false\nend\n```\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.auto_register = proc do |component|\n    !component.identifier.start_with?(\"entities\")\n  end\nend\n```\n\n#### memoize\n\n`memoize` sets whether to memoize components from the dir when registered in the container (ordinarily, components are initialized every time they are resolved).\n\nThis may be a simple boolean to enable or disable memoization for all components, or a proc accepting a `Dry::Sytem::Component` and returning a boolean to configure memoization on a per-component basis.\n\n`memoize` defaults to `false`.\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.memoize = true\nend\n```\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.memoize = proc do |component|\n    component.identifier.start_with?(\"providers\")\n  end\nend\n```\n\n#### namespaces\n\n`namespaces` allows one or more namespaces to be added for paths within the component dir. For the given path, the namespace determines:\n\n1. The leading segments of its components' registered identifiers, and\n2. The expected constant namespace of their class constants.\n\nWhen adding a namespace, you can specify:\n\n- A `key:` namespace, which determines the leading part of the key used to register each component in the container. It can be:\n  - Omitted, in which case it defaults to the value of `path`\n  - A string, which will become the leading part of the registered keys\n  - `nil`, which will make the registered keys top-level, with no additional leading parts\n- A `const:` namespace, which is the Ruby namespace expected to contain the class constants defined within each component's source file.\n\n  This value is provided as an \"underscored\" string, and will be run through the container inflector's `#constantize`, to be converted in to a real constant (e.g. `\"foo_bar/baz\"` will become `FooBar::Baz`). Accordingly, `const:` can be:\n  - Omitted, in which case it defaults to the value of `path`\n  - A string, which will be constantized to the expected constant namespace per the rules above\n  - `nil`, to indicate the class constants will be in the top-level constant namespace\n\nOnly a single namespace can be added for any distinct path.\n\nTo illustrate these options:\n\n**Top-level key namespace**\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.namespaces.add \"admin\", key: nil\nend\n```\n\n- `admin/foo.rb` is expected to define `Admin::Foo`, will be registered as `\"foo\"`\n- `admin/bar/baz.rb` is expected to define `Admin::Bar::Baz`, will be registered as `\"bar.baz\"`\n\n**Top-level const namespace**\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.namespaces.add \"admin/top\", const: nil\nend\n```\n\n- `admin/top/foo.rb` is expected to define `Foo`, will be registered as `\"admin.top.foo\"`\n- `admin/top/bar/baz.rb` is expected to define `Bar::Baz`, will be registered as `\"admin.top.bar.baz\"`\n\n**Distinct const namespace**\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.namespaces.add \"admin\", key: nil, const: \"super/admin\"\nend\n```\n\n- `admin/foo.rb` is expected to define `Super::Admin::Foo`, will be registered as `\"foo\"`\n- `admin/bar/baz.rb` is expected to define `Super::Admin::Bar::Baz`, will be registered as `\"bar.baz\"`\n\n**Omitted key namespace, with keys keeping their natural prefix**\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.namespaces.add \"admin\", const: \"super/admin\"\nend\n```\n\n- `admin/foo.rb` is expected to define `Super::Admin::Foo`, will be registered as `\"admin.foo\"`\n- `admin/bar/baz.rb` is expected to define `Super::Admin::Bar::Baz`, will be registered as `\"admin.bar.baz\"`\n\n##### Each component dir may have multiple namespaces\n\nThe examples above show a component dir with a single configured namespace, but component dir may have any number of namespaces:\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.namespaces.add \"admin/system_adapters\", key: nil, const: nil\n  dir.namespaces.add \"admin\", key: nil\n  dir.namespaces.add \"elsewhere\", key: \"stuff.and.things\"\nend\n```\n\nWhen the container loads its components, namespaces are searched and evaluated in order of definition. So for the example above:\n\n- Files within `lib/admin/system_adapters/` will have the `key: nil, const: nil` namespace rules applied\n- All other files in `lib/admin/` will have the `key: nil` namespace rules applied\n- Files in `lib/elsewhere/` will have the `key: \"stuff.and.things\"` namespace rules applied\n\n##### A root namespace is implicitly appended to a component dir's configured namespaces\n\nTo ensure that all the the files within a component dir remain loadable, a \"root namespace\" is implicitly appended to the list of configured namespaces on a component dir.\n\nA root namespace, as the name implies, encompasses all files in the component dir. In the example above, the root namespace would be used when loading files _not_ in the `admin/` or `elsewhere/` paths.\n\nThe default root namespace is effectively the following:\n\n```ruby\nnamespaces.add nil, key: nil, const: nil\n```\n\nIt has `nil` path (the root of the component dir), a `nil` leading key namespace (all keys will be determined based on the full file path from the root of the dir), and a `nil` const namespace (implying that the root of the component dir will hold top-level constants).\n\nThese assumptions tend to hold true for typically organised projects, and they ensure that the component dirs can load code usefully even when no namespaces are configured at all.\n\n##### The root namespace may be explicitly configured\n\nThere may be cases where you want different namespace rules to apply when loading components from the root of the component dir. To support this, you can configure the root namespace explicitly via `namespaces.root`.\n\nIn this example, files in `lib/` are all expected to provide class constants in the `Admin` namespace:\n\n```ruby\nconfig.component_dirs.add \"lib\" do |dir|\n  dir.namespaces.root const: \"admin\"\nend\n```\n\nRoot namespaces can be configured alongside other namespaces. The same namespace ordering preferences apply to root namespaces as to all others.\n\n#### add_to_load_path\n\n`add_to_load_path` sets whether the component dir should be added to the `$LOAD_PATH` after the container is configured.\n\nSet this to false if you’re using dry-container with an autoloader.\n\n`add_to_load_path` defaults to `true`.\n\n#### loader\n\n`loader` sets the loader to use when registering components from the dir in the container.\n\n`loader` defaults to `Dry::System::Loader`.\n\nWhen using a class autoloader, consider setting this to `Dry::System::Loader::Autoloading`:\n\n```ruby\nrequire \"dry/system\"\n\nclass Application < Dry::System::Container\n  configure do |config|\n    config.root = __dir__\n\n    config.component_dirs.add \"lib\" do |dir|\n      dir.loader = Dry::System::Loader::Autoloading\n    end\n  end\nend\n```\n\nTo provide a custom loader, you must implement the same interface as `Dry::System::Loader`.\n\n### Component dir defaults configuration\n\nIf you are adding multiple component dirs to your container, and would like common configuration to be applied to all of them, you can configure the `component_dirs` collection directly.\n\nConfiguration set on `component_dirs` will be applied to all added component dirs. Any configuration applied directly to an individual component dir will override the defaults.\n\n```ruby\nclass MyApp::Container < Dry::System::Container\n  configure do |config|\n    config.root = __dir__\n\n    # Configure defaults for all component dirs\n    config.component_dirs.auto_register = proc do |component|\n      !component.identifier.start_with?(\"entities\")\n    end\n    config.component_dirs.namespaces.add \"admin\", key: nil\n\n    config.component_dirs.add \"lib\"\n    config.component_dirs.add \"app\"\n  end\nend\n```\n\n### Inline component configuration with magic comments\n\nYou can override certain aspects of the component dir configuration on a per-component basis by adding “magic comments” to the top of your source files.\n\nThe following settings can be configured by magic comments:\n\n- `auto_register`\n- `memoize`\n\nIn the magic comments, you can set `true` or `false` values only.\n\nFor example, to disable auto-registration of a particular component:\n\n```ruby\n# auto_register: false\n# frozen_string_literal: true\n\nclass MyClass\nend\n```\n\nOr to enable memoization of a particular component:\n\n```ruby\n# memoize: true\n# frozen_string_literal: true\n\nclass MyClass\nend\n```\n"
  },
  {
    "path": "docsite/source/container/hooks.html.md",
    "content": "---\ntitle: Hooks\nlayout: gem-single\nname: dry-system\n---\n\nThere are a few lifecycle events that you can hook into if you need to ensure things happen in a particular order.\n\nHooks are executed within the context of the container instance.\n\n### `configure` Event\n\nYou can register a callback to fire after the container is configured, which happens one of three ways:\n\n1. The `configure` method is called on the container\n2. The `configured!` method is called\n3. The `finalize!` method is called when neither of the other two have been\n\n```ruby\nclass MyApp::Container < Dry::System::Container\n  after(:configure) do\n    # do something here\n  end\nend\n```\n\n### `register` Event\n\nMost of the time, you will know what keys you are working with ahead of time. But for certain cases you may want to\nreact to keys dynamically.\n\n```ruby\nclass MyApp::Container < Dry::System::Container\n  use :monitoring\n\n  after(:register) do |key|\n    next unless key.end_with?(\".gateway\")\n\n    monitor(key) do |event|\n      resolve(:logger).debug(key:, method: event[:method], time: event[:time])\n    end\n  end\nend\n```\n\nNow let's say you register `api_client.gateway` into your container. Your API methods will be automatically monitored\nand their timing measured and logged.\n\n### `finalize` Event\n\nFinalization is the point at which the container is made ready, such as booting a web application.\n\nThe following keys are loaded in sequence:\n\n1. Providers\n2. Auto-registered components\n3. Manually-registered components\n4. Container imports\n\nAt the conclusion of this process, the container is frozen thus preventing any further changes. This makes the\n`finalize` event quite important: it's the last call before your container will disallow mutation.\n\nUnlike the previous events, you can register before hooks in addition to after hooks.\n\nThe after hooks will run immediately prior to the container freeze. This allows you to enumerate the container keys\nwhile they can still be mutated, such as with `decorate` or `monitor`.\n\n```ruby\nclass MyApp::Container < Dry::System::Container\n  before(:finalize) do\n    # Before system boot, no keys registered yet\n  end\n\n  after(:finalize) do\n    # After system boot, all keys registered\n  end\nend\n```\n"
  },
  {
    "path": "docsite/source/container.html.md",
    "content": "---\ntitle: Container\nlayout: gem-single\nname: dry-system\nsections:\n  - hooks\n---\n\nThe main API of dry-system is the abstract container that you inherit from. It allows you to configure basic settings and exposes APIs for requiring files easily. Container is the entry point to your application, and it encapsulates application's state.\n\nLet's say you want to define an application container that will provide a logger:\n\n``` ruby\nrequire 'dry/system'\n\nclass Application < Dry::System::Container\n  configure do |config|\n    config.root = Pathname('./my/app')\n  end\nend\n\n# now you can register a logger\nrequire 'logger'\nApplication.register('utils.logger', Logger.new($stdout))\n\n# and access it\nApplication['utils.logger']\n```\n\n### Auto-Registration\n\nBy using simple naming conventions we can automatically register objects within our container.\n\nLet's provide a custom logger object and put it under a custom load-path that we will configure:\n\n``` ruby\nrequire \"dry/system\"\n\nclass Application < Dry::System::Container\n  configure do |config|\n    config.root = Pathname(\"./my/app\")\n\n    # Add a 'lib' component dir (relative to `root`), containing class definitions\n    # that can be auto-registered\n    config.component_dirs.add \"lib\"\n  end\nend\n\n# under /my/app/lib/logger.rb we put\nclass Logger\n  # some neat logger implementation\nend\n\n# we can finalize the container which triggers auto-registration\nApplication.finalize!\n\n# the logger becomes available\nApplication[\"logger\"]\n```\n"
  },
  {
    "path": "docsite/source/dependency-auto-injection.html.md",
    "content": "---\ntitle: Dependency auto-injection\nlayout: gem-single\nname: dry-system\n---\n\nAfter defining your container, you can use its auto-injector as a mixin to declare a component's dependencies using their container keys.\n\nFor example, if you have an `Application` container and an object that will need a logger:\n\n``` ruby\n# system/import.rb\nrequire \"system/container\"\nImport = Application.injector\n\n# In a class definition you simply specify what it needs\n# lib/post_publisher.rb\nrequire \"import\"\nclass PostPublisher\n  include Import[\"logger\"]\n\n  def call(post)\n    # some stuff\n    logger.debug(\"post published: #{post}\")\n  end\nend\n```\n\n### Auto-registered component keys\n\nWhen components are auto-registered, their default keys are based on their file paths and your [component dir](docs::component-dirs) configuration. For example, `lib/api/client.rb` will have the key `\"api.client\"` and will resolve an instance of `API::Client`.\n\nResolving a component will also start a registered [provider](docs::providers) if it shares the same name as the root segment of its container key. This is useful in cases where a group of components require an additional dependency to be always made available.\n\nFor example, if you have a group of repository objects that need a `persistence` provider to be started, all you need to do is to follow this naming convention:\n\n- `system/providers/persistence.rb` - where you register your `:persistence` provider\n- `lib/persistence/user_repo` - where you can define any components that need the components or setup established by the `persistence` provider\n\nHere's a sample setup for this scenario:\n\n``` ruby\n# system/container.rb\nrequire \"dry/system\"\n\nclass Application < Dry::System::Container\n  configure do |config|\n    config.root = Pathname(\"/my/app\")\n    config.component_dirs.add \"lib\"\n  end\nend\n\n# system/import.rb\nrequire_relative \"container\"\n\nImport = Application.injector\n\n# system/providers/persistence.rb\nApplication.register_provider(:persistence) do\n  start do\n    require \"sequel\"\n    container.register(\"persistence.db\", Sequel.connect(ENV['DB_URL']))\n  end\n\n  stop do\n    container[\"persistence.db\"].disconnect\n  end\nend\n\n# lib/persistence/user_repo.rb\nrequire \"import\"\n\nmodule Persistence\n  class UserRepo\n    include Import[\"persistence.db\"]\n\n    def find(conditions)\n      db[:users].where(conditions)\n    end\n  end\nend\n```\n"
  },
  {
    "path": "docsite/source/external-provider-sources.html.md",
    "content": "---\ntitle: External provider sources\nlayout: gem-single\nname: dry-system\n---\n\nYou can distribute your own components to other dry-system users via external provider sources, which can be used as the basis for providers within any dry-system container.\n\nProvider sources look and work the same as regular providers, which means allowing you to use their full lifecycle for creating, configuring, and registering your components.\n\nTo distribute a group of provider sources (defined in their own files), register them with `Dry::System`:\n\n``` ruby\n# my_gem\n#  |- lib/my_gem/provider_sources.rb\n\nDry::System.register_provider_sources(:common, boot_path: File.join(__dir__, \"provider_sources\"))\n```\n\nThen, define your provider source:\n\n``` ruby\n# my_gem\n#  |- lib/my_gem/provider_sources/exception_notifier.rb\n\nDry::System.register_provider_source(:exception_notifier, group: :my_gem) do\n  prepare do\n    require \"some_exception_notifier\"\n  end\n\n  start do\n    register(:exception_notifier, SomeExceptionNotifier.new)\n  end\nend\n```\n\nThen you can use this provider source when you register a provider in a dry-system container:\n\n``` ruby\n# system/app/container.rb\n\nrequire \"dry/system\"\nrequire \"my_gem/provider_sources\"\n\nmodule App\n  class Container < Dry::System::Container\n    register_provider(:exception_notifier, from: :my_gem)\n  end\nend\n\nApp::Container[:exception_notifier]\n```\n\n### Customizing provider sources\n\nYou can customize a provider source for your application via `before` and `after` callbacks for its lifecycle steps.\n\nFor example, you can register additional components based on the provider source's own registrations via an `after(:start)` callback:\n\n``` ruby\nmodule App\n  class Container < Dry::System::Container\n    register_provider(:exception_notifier, from: :my_gem) do\n      after(:start)\n        register(:my_notifier, container[:exception_notifier])\n      end\n    end\n  end\nend\n```\n\nThe following callbacks are supported:\n\n- `before(:prepare)`\n- `after(:prepare)`\n- `before(:start)`\n- `after(:start)`\n\n### Providing component configuration\n\nProvider sources can define their own settings using [dry-configurable’s](/gems/dry-configurable) `setting` API. These will be configured when the provider source is used by a provider. The other lifecycle steps in the provider souce can access the configured settings as `config`.\n\nFor example, here’s an extended `:exception_notifier` provider source with settings:\n\n``` ruby\n# my_gem\n#  |- lib/my_gem/provider_sources/exception_notifier.rb\n\nDry::System.register_component(:exception_notifier, provider: :common) do\n  setting :environments, default: :production, constructor: Types::Strict::Array.of(Types::Strict::Symbol)\n  setting :logger\n\n  prepare do\n    require \"some_exception_notifier\"\n  end\n\n  start do\n    # Now we have access to `config`\n    register(:exception_notifier, SomeExceptionNotifier.new(config.to_h))\n  end\nend\n```\n\nThis defines two settings:\n\n- `:environments`, which is a list of environment identifiers with default value set to `[:production]`\n- `:logger`, an object that should be used as the logger, which must be configured\n\nTo configure this provider source, you can use a `configure` block when defining your provider using the source:\n\n``` ruby\nmodule App\n  class Container < Dry::System::Container\n    register_provider(:exception_notifier, from: :my_gem) do\n      require \"logger\"\n\n      configure do |config|\n        config.logger = Logger.new($stdout)\n      end\n    end\n  end\nend\n```\n"
  },
  {
    "path": "docsite/source/index.html.md",
    "content": "---\ntitle: Introduction\nlayout: gem-single\nname: dry-system\ntype: gem\nsections:\n  - container\n  - component-dirs\n  - providers\n  - dependency-auto-injection\n  - plugins\n  - external-provider-sources\n  - settings\n  - test-mode\n---\n\nObject dependency management system based on [dry-container](/gems/dry-container) and [dry-auto_inject](/gems/dry-auto_inject) allowing you to configure reusable components in any environment, set up their load-paths, require needed files and instantiate objects automatically with the ability to have them injected as dependencies.\n\nThis library relies on very basic mechanisms provided by Ruby, specifically `require` and managing `$LOAD_PATH`. It doesn't use magic like automatic const resolution, it's pretty much the opposite and forces you to be explicit about dependencies in your applications.\n\nIt does a couple of things for you:\n\n* Provides an abstract dependency container implementation\n* Integrates with an autoloader, or handles `$LOAD_PATH` for you and loads needed files using `require`\n* Resolves object dependencies automatically\n* Supports auto-registration of dependencies via file/dir naming conventions\n* Supports multi-system setups (ie your application is split into multiple sub-systems)\n* Supports configuring component providers, which can be used to share common components between many systems\n* Supports test-mode with convenient stubbing API\n\nTo put it all together, this allows you to configure your system in a way where you have full control over dependencies and it's very easy to draw the boundaries between individual components.\n\nThis comes with a bunch of nice benefits:\n\n* Your system relies on abstractions rather than concrete classes and modules\n* It helps in decoupling your code from 3rd party code\n* It makes it possible to load components in complete isolation. In example you can run a single test for a single component and only required files will be loaded, or you can run a rake task and it will only load the things it needs.\n* It opens up doors to better instrumentation and debugging tools\n\nYou can use dry-system in a new application or add it to an existing application. It should Just Work™ but if it doesn't please [report an issue](https://github.com/dry-rb/dry-system/issues).\n\n### Rails support\n\nIf you want to use dry-system with Rails, it's recommended to use [dry-rails](/gems/dry-rails) which sets up application container for you and provides additional features on top of it.\n\n### Credits\n\n* dry-system has been extracted from an experimental project called Rodakase created by [solnic](https://github.com/solnic). Later on Rodakase was renamed to [dry-web](https://github.com/dry-rb/dry-web).\n* System/Component and lifecycle triggers are inspired by Clojure's [component](https://github.com/stuartsierra/component) library by [Stuart Sierra](https://github.com/stuartsierra)\n\n"
  },
  {
    "path": "docsite/source/plugins.html.md",
    "content": "---\ntitle: Plugins\nlayout: gem-single\nname: dry-system\n---\n\ndry-system has already built-in plugins that you can enable, and it’s very easy to write your own.\n\n## Zeitwerk\n\nWith the `:zeitwerk` plugin you can easily use [Zeitwerk](https://github.com/fxn/zeitwerk) as your applications's code loader:\n\n> Given a conventional file structure, Zeitwerk is able to load your project's classes and modules on demand (autoloading), or upfront (eager loading). You don't need to write require calls for your own files, rather, you can streamline your programming knowing that your classes and modules are available everywhere. This feature is efficient, thread-safe, and matches Ruby's semantics for constants. (Zeitwerk docs)\n\n### Example\n\nHere is an example of using Zeitwerk plugin:\n\n```ruby\nclass App < Dry::System::Container\n  use :env, inferrer: -> { ENV.fetch(\"RACK_ENV\", :development).to_sym }\n  use :zeitwerk\n\n  configure do |config|\n    config.component_dirs.add \"lib\"\n  end\nend\n```\n\nFor a more in depth and runnable example, [see here](https://github.com/dry-rb/dry-system/tree/master/examples/zeitwerk).\n\n### Inflections\n\nThe plugin passes the container's inflector to the Zeitwerk loader for resolving constants from file names. If Zeitwerk has trouble resolving some constants, you can update the container's inflector like so:\n\n```ruby\nclass App < Dry::System::Container\n  use :zeitwerk\n\n  configure do |config|\n    config.inflector = Dry::Inflector.new do |inflections|\n      inflections.acronym('REST')\n    end\n\n    # ...\n  end\nend\n```\n\n### Eager Loading\n\nBy default, the plugin will have Zeitwerk eager load when using the `:env` plugin sets the environment to `:production`. However, you can change this behavior by passing `:eager_load` option to the plugin:\n\n```ruby\nclass App < Dry::System::Container\n  use :zeitwerk, eager_load: true\nend\n```\n\n### Debugging\n\nWhen you are developing your application, you can enable the plugin's debugging mode by passing `debug: true` option to the plugin, which will print Zeitwerk's logs to the standard output.\n\n```ruby\nclass App < Dry::System::Container\n  use :zeitwerk, debug: true\nend\n```\n\n### Advanced Configuration\n\nIf you need to adjust the Zeitwerk configuration, you can do so by accessing the `Zeitwerk::Loader` instance directly on the container, as `.autoloader`:\n\n```ruby\n# After you have configured the container but before you have finalized it\n\nMyContainer.autoloader.ignore(\"./some_path.rb)\n```\n\n## Application environment\n\nYou can use the `:env` plugin to set and configure an `env` setting for your application.\n\n```ruby\nclass App < Dry::System::Container\n  use :env\n\n  configure do |config|\n    config.env = :staging\n  end\nend\n```\n\nYou can provide environment inferrer, which is probably something you want to do, here’s how dry-web sets up its environment:\n\n```ruby\nmodule Dry\n  module Web\n    class Container < Dry::System::Container\n      use :env, inferrer: -> { ENV.fetch(\"RACK_ENV\", :development).to_sym }\n    end\n  end\nend\n```\n\n## Logging\n\nYou can now enable a default system logger by simply enabling `:logging` plugin, you can also configure log dir, level and provide your own logger class.\n\n```ruby\nclass App < Dry::System::Container\n  use :logging\nend\n\n# default logger is registered as a standard object, so you can inject it via auto-injection\nApp[:logger]\n\n# short-cut method is provided too, which is convenient in some cases\nApp.logger\n```\n\n## Monitoring\n\nAnother plugin is called `:monitoring` which allows you to enable object monitoring, which is built on top of dry-monitor’s instrumentation API. Let’s say you have an object registered under `\"users.operations.create\",` and you’d like to add additional logging:\n\n```ruby\nclass App < Dry::System::Container\n  use :logging\n  use :monitoring\nend\n\nApp.monitor(\"users.operations.create\") do |event|\n  App.logger.debug \"user created: #{event.payload} in #{event[:time]}ms\"\nend\n```\n\nYou can also provide specific methods that should be monitored, let’s say we’re only interested in `#call` method:\n\n```ruby\nApp.monitor(\"users.operations.create\", methods: %i[call]) do |event|\n  App.logger.debug \"user created: #{event.payload} in #{event[:time]}ms\"\nend\n```\n\n## Experimental bootsnap support\n\ndry-system is already pretty fast, but in a really big apps, it can take some seconds to boot. You can now speed it up significantly by using `:bootsnap` plugin, which simply configures bootsnap for you:\n\n```ruby\nclass App < Dry::System::Container\n  use :bootsnap # that's it\nend\n```\n\nWe’ve noticed a ~30% speed boost during booting the entire app, unfortunately there are some problems with bootsnap + byebug, so it is now recommended to turn it off if you’re debugging something.\n"
  },
  {
    "path": "docsite/source/providers.html.md",
    "content": "---\ntitle: Providers\nlayout: gem-single\nname: dry-system\n---\n\nSome components can be large, stateful, or requiring specific configuration as part of their setup (such as when dealing with third party code). You can use providers to manage and register these components across several distinct lifecycle steps.\n\nYou can define your providers as individual source files in `system/providers/`, for example:\n\n``` ruby\n# system/providers/persistence.rb\n\nApplication.register_provider(:database) do\n  prepare do\n    require \"third_party/db\"\n  end\n\n  start do\n    register(:database, ThirdParty::DB.new)\n  end\nend\n```\n\nThe provider’s lifecycle steps will not run until the provider is required by another component, is started directly, or when the container finalizes.\n\nThis means you can require your container and ask it to start just that one provider:\n\n``` ruby\n# system/application/container.rb\nclass Application < Dry::System::Container\n  configure do |config|\n    config.root = Pathname(\"/my/app\")\n  end\nend\n\nApplication.start(:database)\n\n# and now `database` becomes available\nApplication[\"database\"]\n```\n\n### Provider lifecycle\n\nThe provider lifecycle consists of three steps, each with a distinct purpose:\n\n* `prepare` - basic setup code, here you can require third party code and perform basic configuration\n* `start` - code that needs to run for a component to be usable at application's runtime\n* `stop` - code that needs to run to stop a component, ie close a database connection, clear some artifacts etc.\n\nHere's a simple example:\n\n``` ruby\n# system/providers/db.rb\n\nApplication.register_provider(:database) do\n  prepare do\n    require 'third_party/db'\n\n    register(:database, ThirdParty::DB.configure(ENV['DB_URL']))\n  end\n\n  start do\n    container[:database].establish_connection\n  end\n\n  stop do\n    container[:database].close_connection\n  end\nend\n```\n\n### Using other providers\n\nYou can start one provider as a dependency of another by invoking the provider’s lifecycle directly on the `target` container (i.e. your application container):\n\n``` ruby\n# system/providers/logger.rb\nApplication.register_provider(:logger) do\n  prepare do\n    require \"logger\"\n  end\n\n  start do\n    register(:logger, Logger.new($stdout))\n  end\nend\n\n# system/providers/db.rb\nApplication.register_provider(:db) do\n  start do\n    target.start :logger\n\n    register(DB.new(ENV['DB_URL'], logger: target[:logger]))\n  end\nend\n```\n"
  },
  {
    "path": "docsite/source/settings.html.md",
    "content": "---\ntitle: Settings\nlayout: gem-single\nname: dry-system\n---\n\n## Basic usage\n\ndry-system provides a `:settings` provider source that you can use to load settings and share them throughout your application. To use this provider source, create your own `:settings` provider using the provider source from `:dry_system`, then declare your settings inside `settings` block (using [dry-configurable’s](/gems/dry-configurable) `setting` API):\n\n```ruby\n# system/providers/settings.rb:\n\nrequire \"dry/system\"\n\nApplication.register_provider(:settings, from: :dry_system) do\n  before :prepare do\n    # Change this to load your own `Types` module if you want type-checked settings\n    require \"your/types/module\"\n  end\n\n  settings do\n    setting :database_url, constructor: Types::String.constrained(filled: true)\n\n    setting :logger_level, default: :info, constructor: Types::Symbol\n      .constructor { |value| value.to_s.downcase.to_sym }\n      .enum(:trace, :unknown, :error, :fatal, :warn, :info, :debug)\n  end\nend\n```\n\nYour provider will then map `ENV` variables to a struct object giving access to your settings as their own methods, which you can use throughout your application:\n\n```ruby\nApplication[:settings].database_url # => \"postgres://...\"\nApplication[:settings].logger_level # => :info\n```\n\nYou can use this settings object in other providers:\n\n```ruby\nApplication.register_provider(:redis) do\n  start do\n    use :settings\n\n    uri = URI.parse(target[:settings].redis_url)\n    redis = Redis.new(host: uri.host, port: uri.port, password: uri.password)\n\n    register('persistance.redis', redis)\n  end\nend\n```\n\nOr as an injected dependency in your classes:\n\n```ruby\n  module Operations\n    class CreateUser\n      include Import[:settings]\n\n      def call(params)\n        settings # => your settings struct\n      end\n    end\n  end\nend\n```\n"
  },
  {
    "path": "docsite/source/test-mode.html.md",
    "content": "---\ntitle: Test Mode\nlayout: gem-single\nname: dry-system\n---\n\nIn some cases it is useful to stub a component in your tests. To enable this, dry-system provides a test mode,\nin which a container will not be frozen during finalization. This allows you to use `stub` API to stub a given component.\n\n``` ruby\nrequire 'dry/system'\n\nclass Application < Dry::System::Container\n  configure do |config|\n    config.root = Pathname('./my/app')\n  end\nend\n\nrequire 'dry/system/stubs'\n\nApplication.enable_stubs!\n\nApplication.stub('persistence.db', stubbed_db)\n```\n\nTypically, you want to use `enable_stubs!` in a test helper file, before booting your system.\n"
  },
  {
    "path": "dry-system.gemspec",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.\n\nlib = File.expand_path(\"lib\", __dir__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire \"dry/system/version\"\n\nGem::Specification.new do |spec|\n  spec.name          = \"dry-system\"\n  spec.authors       = [\"Hanakai team\"]\n  spec.email         = [\"info@hanakai.org\"]\n  spec.license       = \"MIT\"\n  spec.version       = Dry::System::VERSION.dup\n\n  spec.summary       = \"Organize your code into reusable components\"\n  spec.description   = spec.summary\n  spec.homepage      = \"https://dry-rb.org/gems/dry-system\"\n  spec.files         = Dir[\"CHANGELOG.md\", \"LICENSE\", \"README.md\", \"dry-system.gemspec\", \"lib/**/*\"]\n  spec.bindir        = \"exe\"\n  spec.executables   = Dir[\"exe/*\"].map { |f| File.basename(f) }\n  spec.require_paths = [\"lib\"]\n\n  spec.extra_rdoc_files = [\"README.md\", \"CHANGELOG.md\", \"LICENSE\"]\n\n  spec.metadata[\"changelog_uri\"]     = \"https://github.com/dry-rb/dry-system/blob/main/CHANGELOG.md\"\n  spec.metadata[\"source_code_uri\"]   = \"https://github.com/dry-rb/dry-system\"\n  spec.metadata[\"bug_tracker_uri\"]   = \"https://github.com/dry-rb/dry-system/issues\"\n  spec.metadata[\"funding_uri\"]       = \"https://github.com/sponsors/hanami\"\n\n  spec.required_ruby_version = \">= 3.1.0\"\n\n  spec.add_runtime_dependency \"dry-auto_inject\", \"~> 1.1\"\n  spec.add_runtime_dependency \"dry-configurable\", \"~> 1.3\"\n  spec.add_runtime_dependency \"dry-core\", \"~> 1.1\"\n  spec.add_runtime_dependency \"dry-inflector\", \"~> 1.1\"\n  spec.add_development_dependency \"bundler\"\n  spec.add_development_dependency \"rake\"\n  spec.add_development_dependency \"rspec\"\nend\n\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/Gemfile",
    "content": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngem \"dry-system\", path: \"../..\"\ngem \"sequel\"\ngem \"sqlite3\"\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/lib/entities/user.rb",
    "content": "# frozen_string_literal: true\n\nmodule Entities\n  class User\n    include Import[\"persistence.db\"]\n  end\nend\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/lib/user_repo.rb",
    "content": "# frozen_string_literal: true\n\nclass UserRepo\n  include Import[\"persistence.db\"]\nend\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/run.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire_relative \"system/container\"\nrequire_relative \"system/import\"\n\nApp.finalize!\n\nuser_repo1 = App[\"user_repo\"]\nuser_repo2 = App[\"user_repo\"]\nputs \"User has not been loaded\" unless App.key?(\"entities.user\")\nputs user_repo1.db.inspect\nputs user_repo2.db.inspect\nputs \"user_repo1 and user_repo2 reference the same instance\" if user_repo1.equal?(user_repo2)\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/system/boot/persistence.rb",
    "content": "# frozen_string_literal: true\n\nApp.boot(:persistence) do |persistence|\n  init do\n    require \"sequel\"\n  end\n\n  start do\n    persistence.register(\"persistence.db\", Sequel.connect(\"sqlite::memory\"))\n  end\n\n  stop do\n    db.close_connection\n  end\nend\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/system/container.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nclass App < Dry::System::Container\n  configure do |config|\n    config.component_dirs.add \"lib\" do |dir|\n      dir.memoize = true\n\n      dir.auto_register = lambda do |component|\n        !component.identifier.start_with?(\"entities\")\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/system/import.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative \"container\"\n\nImport = App.injector\n"
  },
  {
    "path": "examples/standalone/Gemfile",
    "content": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngem \"dry-events\"\ngem \"dry-monitor\"\ngem \"dry-system\", path: \"../..\"\ngem \"sequel\"\ngem \"sqlite3\"\n"
  },
  {
    "path": "examples/standalone/lib/empty_service.rb",
    "content": "# frozen_string_literal: true\n\nclass EmptyService\nend\n"
  },
  {
    "path": "examples/standalone/lib/not_registered.rb",
    "content": "# frozen_string_literal: true\n\nclass NotRegistered\nend\n"
  },
  {
    "path": "examples/standalone/lib/service_with_dependency.rb",
    "content": "# frozen_string_literal: true\n\nclass ServiceWithDependency\n  include Import[\"user_repo\"]\nend\n"
  },
  {
    "path": "examples/standalone/lib/user_repo.rb",
    "content": "# frozen_string_literal: true\n\nclass UserRepo\n  include Import[\"persistence.db\"]\nend\n"
  },
  {
    "path": "examples/standalone/run.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire_relative \"system/container\"\nrequire_relative \"system/import\"\nrequire \"dry/events\"\nrequire \"dry/monitor/notifications\"\n\nApp[:notifications].subscribe(:resolved_dependency) do |event|\n  puts \"Event #{event.id}, payload: #{event.to_h}\"\nend\n\nApp[:notifications].subscribe(:registered_dependency) do |event|\n  puts \"Event #{event.id}, payload: #{event.to_h}\"\nend\n\nApp.finalize!\np App.keys\n\nApp[\"service_with_dependency\"]\nuser_repo = App[\"user_repo\"]\n\nputs user_repo.db.inspect\n"
  },
  {
    "path": "examples/standalone/system/container.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/events\"\nrequire \"dry/monitor/notifications\"\nrequire \"dry/system\"\n\nclass App < Dry::System::Container\n  use :dependency_graph\n\n  configure do |config|\n    config.component_dirs.add \"lib\" do |dir|\n      dir.add_to_load_path = true # defaults to true\n      dir.auto_register = lambda do |component|\n        !component.identifier.start_with?(\"not_registered\")\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "examples/standalone/system/import.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative \"container\"\n\nImport = App.injector\n"
  },
  {
    "path": "examples/standalone/system/providers/persistence.rb",
    "content": "# frozen_string_literal: true\n\nApp.boot(:persistence) do |persistence|\n  init do\n    require \"sequel\"\n  end\n\n  start do\n    persistence.register(\"persistence.db\", Sequel.connect(\"sqlite::memory\"))\n  end\n\n  stop do\n    db.close_connection\n  end\nend\n"
  },
  {
    "path": "examples/zeitwerk/Gemfile",
    "content": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngem \"dry-events\"\ngem \"dry-monitor\"\ngem \"dry-system\", path: \"../..\"\ngem \"zeitwerk\"\n"
  },
  {
    "path": "examples/zeitwerk/lib/service_with_dependency.rb",
    "content": "# frozen_string_literal: true\n\nclass ServiceWithDependency\n  include Import[\"user_repo\"]\nend\n"
  },
  {
    "path": "examples/zeitwerk/lib/user_repo.rb",
    "content": "# frozen_string_literal: true\n\nclass UserRepo\nend\n"
  },
  {
    "path": "examples/zeitwerk/run.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire_relative \"system/container\"\nrequire_relative \"system/import\"\n\nApp.finalize!\n\nservice = App[\"service_with_dependency\"]\n\nputs \"Container keys: #{App.keys}\"\nputs \"User repo:      #{service.user_repo.inspect}\"\nputs \"Loader:         #{App.autoloader}\"\n"
  },
  {
    "path": "examples/zeitwerk/system/container.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nclass App < Dry::System::Container\n  use :env, inferrer: -> { ENV.fetch(\"RACK_ENV\", :development).to_sym }\n  use :zeitwerk, debug: true\n\n  configure do |config|\n    config.component_dirs.add \"lib\"\n  end\nend\n"
  },
  {
    "path": "examples/zeitwerk/system/import.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative \"container\"\n\nImport = App.injector\n"
  },
  {
    "path": "lib/dry/system/auto_registrar.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Default auto-registration implementation\n    #\n    # This is currently configured by default for every System::Container.\n    # Auto-registrar objects are responsible for loading files from configured\n    # auto-register paths and registering components automatically within the\n    # container.\n    #\n    # @api private\n    class AutoRegistrar\n      attr_reader :container\n\n      def initialize(container)\n        @container = container\n      end\n\n      # @api private\n      def finalize!\n        container.component_dirs.each do |component_dir|\n          call(component_dir) if component_dir.auto_register?\n        end\n      end\n\n      # @api private\n      def call(component_dir)\n        component_dir.each_component do |component|\n          next unless register_component?(component)\n\n          container.register(component.key, memoize: component.memoize?) { component.instance }\n        end\n      end\n\n      private\n\n      def register_component?(component)\n        !container.registered?(component.key) && component.auto_register?\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/component.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"pathname\"\nrequire \"dry/inflector\"\nrequire \"dry/system/errors\"\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Components are objects providing information about auto-registered files.\n    # They expose an API to query this information and use a configurable\n    # loader object to initialize class instances.\n    #\n    # @api public\n    class Component\n      include Dry::Equalizer(:identifier, :file_path, :namespace, :options)\n\n      DEFAULT_OPTIONS = {\n        inflector: Dry::Inflector.new,\n        loader: Loader\n      }.freeze\n\n      # @!attribute [r] identifier\n      #   @return [String] the component's unique identifier\n      attr_reader :identifier\n\n      # @!attribute [r] file_path\n      #   @return [Pathname] the component's source file path\n      attr_reader :file_path\n\n      # @!attribute [r] namespace\n      #   @return [Dry::System::Config::Namespace] the component's namespace\n      attr_reader :namespace\n\n      # @!attribute [r] options\n      #   @return [Hash] the component's options\n      attr_reader :options\n\n      # @api private\n      def initialize(identifier, file_path:, namespace:, **options)\n        @identifier = identifier\n        @file_path = Pathname(file_path)\n        @namespace = namespace\n        @options = DEFAULT_OPTIONS.merge(options)\n      end\n\n      # Returns true, indicating that the component is directly loadable from the files\n      # managed by the container\n      #\n      # This is the inverse of {IndirectComponent#loadable?}\n      #\n      # @return [TrueClass]\n      #\n      # @api private\n      def loadable?\n        true\n      end\n\n      # Returns the component's instance\n      #\n      # @return [Object] component's class instance\n      # @api public\n      def instance(*args, **kwargs)\n        options[:instance]&.call(self, *args, **kwargs) || loader.call(self, *args, **kwargs)\n      end\n\n      # Returns the component's unique key\n      #\n      # @return [String] the key\n      #\n      # @see Identifier#key\n      #\n      # @api public\n      def key\n        identifier.key\n      end\n\n      # Returns the root namespace segment of the component's key, as a symbol\n      #\n      # @see Identifier#root_key\n      #\n      # @return [Symbol] the root key\n      #\n      # @api public\n      def root_key\n        identifier.root_key\n      end\n\n      # Returns a path-delimited representation of the compnent, appropriate for passing\n      # to `Kernel#require` to require its source file\n      #\n      # The path takes into account the rules of the namespace used to load the component.\n      #\n      # @example Component from a root namespace\n      #   component.key # => \"articles.create\"\n      #   component.require_path # => \"articles/create\"\n      #\n      # @example Component from an \"admin/\" path namespace (with `key: nil`)\n      #   component.key # => \"articles.create\"\n      #   component.require_path # => \"admin/articles/create\"\n      #\n      # @see Config::Namespaces#add\n      # @see Config::Namespace\n      #\n      # @return [String] the require path\n      #\n      # @api public\n      def require_path\n        if namespace.path\n          \"#{namespace.path}#{PATH_SEPARATOR}#{path_in_namespace}\"\n        else\n          path_in_namespace\n        end\n      end\n\n      # Returns an \"underscored\", path-delimited representation of the component,\n      # appropriate for passing to the inflector for constantizing\n      #\n      # The const path takes into account the rules of the namespace used to load the\n      # component.\n      #\n      # @example Component from a namespace with `const: nil`\n      #   component.key # => \"articles.create_article\"\n      #   component.const_path # => \"articles/create_article\"\n      #   component.inflector.constantize(component.const_path) # => Articles::CreateArticle\n      #\n      # @example Component from a namespace with `const: \"admin\"`\n      #   component.key # => \"articles.create_article\"\n      #   component.const_path # => \"admin/articles/create_article\"\n      #   component.inflector.constantize(component.const_path) # => Admin::Articles::CreateArticle\n      #\n      # @see Config::Namespaces#add\n      # @see Config::Namespace\n      #\n      # @return [String] the const path\n      #\n      # @api public\n      def const_path\n        namespace_const_path = namespace.const&.gsub(KEY_SEPARATOR, PATH_SEPARATOR)\n\n        if namespace_const_path\n          \"#{namespace_const_path}#{PATH_SEPARATOR}#{path_in_namespace}\"\n        else\n          path_in_namespace\n        end\n      end\n\n      # @api private\n      def loader\n        options.fetch(:loader)\n      end\n\n      # @api private\n      def inflector\n        options.fetch(:inflector)\n      end\n\n      # @api private\n      def auto_register?\n        callable_option?(options[:auto_register])\n      end\n\n      # @api private\n      def memoize?\n        callable_option?(options[:memoize])\n      end\n\n      private\n\n      def path_in_namespace\n        identifier_in_namespace =\n          if namespace.key\n            identifier.namespaced(from: namespace.key, to: nil)\n          else\n            identifier\n          end\n\n        identifier_in_namespace.key_with_separator(PATH_SEPARATOR)\n      end\n\n      def callable_option?(value)\n        if value.respond_to?(:call)\n          !!value.call(self)\n        else\n          !!value\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/component_dir.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"pathname\"\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # A configured component directory within the container's root. Provides access to the\n    # component directory's configuration, as well as methods for locating component files\n    # within the directory\n    #\n    # @see Dry::System::Config::ComponentDir\n    # @api private\n    class ComponentDir\n      # @!attribute [r] config\n      #   @return [Dry::System::Config::ComponentDir] the component directory configuration\n      #   @api private\n      attr_reader :config\n\n      # @!attribute [r] container\n      #   @return [Dry::System::Container] the container managing the component directory\n      #   @api private\n      attr_reader :container\n\n      # @api private\n      def initialize(config:, container:)\n        @config = config\n        @container = container\n      end\n\n      # Returns a component for the given key if a matching source file is found within\n      # the component dir\n      #\n      # This searches according to the component dir's configured namespaces, in order of\n      # definition, with the first match returned as the component.\n      #\n      # @param key [String] the component's key\n      # @return [Dry::System::Component, nil] the component, if found\n      #\n      # @api private\n      def component_for_key(key)\n        config.namespaces.each do |namespace|\n          identifier = Identifier.new(key)\n\n          next unless identifier.start_with?(namespace.key)\n\n          if (file_path = find_component_file(identifier, namespace))\n            return build_component(identifier, namespace, file_path)\n          end\n        end\n\n        nil\n      end\n\n      def each_component\n        return enum_for(:each_component) unless block_given?\n\n        each_file do |file_path, namespace|\n          yield component_for_path(file_path, namespace)\n        end\n      end\n\n      private\n\n      def each_file\n        return enum_for(:each_file) unless block_given?\n\n        raise ComponentDirNotFoundError, full_path unless Dir.exist?(full_path)\n\n        config.namespaces.each do |namespace|\n          files(namespace).each do |file|\n            yield file, namespace\n          end\n        end\n      end\n\n      def files(namespace)\n        if namespace.path?\n          ::Dir[::File.join(full_path, namespace.path, \"**\", RB_GLOB)]\n        else\n          non_root_paths = config.namespaces.to_a.reject(&:root?).map(&:path)\n\n          ::Dir[::File.join(full_path, \"**\", RB_GLOB)].reject { |file_path|\n            Pathname(file_path).relative_path_from(full_path).to_s.start_with?(*non_root_paths)\n          }\n        end\n      end\n\n      # Returns the full path of the component directory\n      #\n      # @return [Pathname]\n      def full_path\n        container.root.join(path)\n      end\n\n      # Returns a component for a full path to a Ruby source file within the component dir\n      #\n      # @param path [String] the full path to the file\n      # @return [Dry::System::Component] the component\n      def component_for_path(path, namespace)\n        key = Pathname(path).relative_path_from(full_path).to_s\n          .sub(RB_EXT, EMPTY_STRING)\n          .scan(WORD_REGEX)\n          .join(KEY_SEPARATOR)\n\n        identifier = Identifier.new(key)\n          .namespaced(\n            from: namespace.path&.gsub(PATH_SEPARATOR, KEY_SEPARATOR),\n            to: namespace.key\n          )\n\n        build_component(identifier, namespace, path)\n      end\n\n      def find_component_file(identifier, namespace)\n        # To properly find the file within a namespace with a key, we should strip the key\n        # from beginning of our given identifier\n        if namespace.key\n          identifier = identifier.namespaced(from: namespace.key, to: nil)\n        end\n\n        file_name = \"#{identifier.key_with_separator(PATH_SEPARATOR)}#{RB_EXT}\"\n\n        component_file =\n          if namespace.path?\n            full_path.join(namespace.path, file_name)\n          else\n            full_path.join(file_name)\n          end\n\n        component_file if component_file.exist?\n      end\n\n      def build_component(identifier, namespace, file_path)\n        options = {\n          inflector: container.config.inflector,\n          **component_options,\n          **MagicCommentsParser.(file_path)\n        }\n\n        Component.new(\n          identifier,\n          namespace: namespace,\n          file_path: file_path,\n          **options\n        )\n      end\n\n      def component_options\n        {\n          auto_register: auto_register,\n          loader: loader,\n          instance: instance,\n          memoize: memoize\n        }\n      end\n\n      def method_missing(name, ...)\n        if config.respond_to?(name)\n          config.public_send(name, ...)\n        else\n          super\n        end\n      end\n\n      def respond_to_missing?(name, include_all = false)\n        config.respond_to?(name) || super\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/config/component_dir.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    module Config\n      # @api public\n      class ComponentDir\n        include ::Dry::Configurable\n\n        # @!group Settings\n\n        # @!method auto_register=(policy)\n        #\n        #   Sets the auto-registration policy for the component dir.\n        #\n        #   This may be a simple boolean to enable or disable auto-registration for all\n        #   components, or a proc accepting a {Dry::System::Component} and returning a\n        #   boolean to configure auto-registration on a per-component basis\n        #\n        #   Defaults to `true`.\n        #\n        #   @param policy [Boolean, Proc]\n        #   @return [Boolean, Proc]\n        #\n        #   @example\n        #     dir.auto_register = false\n        #\n        #   @example\n        #     dir.auto_register = proc do |component|\n        #       !component.identifier.start_with?(\"entities\")\n        #     end\n        #\n        #   @see auto_register\n        #   @see Component\n        #   @api public\n        #\n        # @!method auto_register\n        #\n        #   Returns the configured auto-registration policy.\n        #\n        #   @return [Boolean, Proc] the configured policy\n        #\n        #   @see auto_register=\n        #   @api public\n        setting :auto_register, default: true\n\n        # @!method instance=(instance_proc)\n        #\n        #   Sets a proc used to return the instance of any component within the component\n        #   dir.\n        #\n        #   This proc should accept a {Dry::System::Component} and return the object to\n        #   serve as the component's instance.\n        #\n        #   When you provide an instance proc, it will be used in preference to the\n        #   {loader} (either the default loader or an explicitly configured one). Provide\n        #   an instance proc when you want a simple way to customize the instance for\n        #   certain components. For complete control, provide a replacement loader via\n        #   {loader=}.\n        #\n        #   Defaults to `nil`.\n        #\n        #   @param instance_proc [Proc, nil]\n        #   @return [Proc]\n        #\n        #   @example\n        #     dir.instance = proc do |component|\n        #       if component.key.match?(/workers\\./)\n        #         # Register classes for jobs\n        #         component.loader.constant(component)\n        #       else\n        #         # Otherwise register regular instances per default loader\n        #         component.loader.call(component)\n        #       end\n        #     end\n        #\n        #   @see Component, Loader\n        #   @api public\n        #\n        # @!method instance\n        #\n        #   Returns the configured instance proc.\n        #\n        #   @return [Proc, nil]\n        #\n        #   @see instance=\n        #   @api public\n        setting :instance\n\n        # @!method loader=(loader)\n        #\n        #   Sets the loader to use when registering components from the dir in the\n        #   container.\n        #\n        #   Defaults to `Dry::System::Loader`.\n        #\n        #   When using an autoloader like Zeitwerk, consider using\n        #   `Dry::System::Loader::Autoloading`\n        #\n        #   @param loader [#call] the loader\n        #   @return [#call] the configured loader\n        #\n        #   @see loader\n        #   @see Loader\n        #   @see Loader::Autoloading\n        #   @api public\n        #\n        # @!method loader\n        #\n        #   Returns the configured loader.\n        #\n        #   @return [#call]\n        #\n        #   @see loader=\n        #   @api public\n        setting :loader, default: Dry::System::Loader\n\n        # @!method memoize=(policy)\n        #\n        #   Sets whether to memoize components from the dir when registered in the\n        #   container.\n        #\n        #   This may be a simple boolean to enable or disable memoization for all\n        #   components, or a proc accepting a `Dry::Sytem::Component` and returning a\n        #   boolean to configure memoization on a per-component basis\n        #\n        #   Defaults to `false`.\n        #\n        #   @param policy [Boolean, Proc]\n        #   @return [Boolean, Proc] the configured memoization policy\n        #\n        #   @example\n        #     dir.memoize = true\n        #\n        #   @example\n        #     dir.memoize = proc do |component|\n        #       !component.identifier.start_with?(\"providers\")\n        #     end\n        #\n        #   @see memoize\n        #   @see Component\n        #   @api public\n        #\n        # @!method memoize\n        #\n        #   Returns the configured memoization policy.\n        #\n        #   @return [Boolean, Proc] the configured memoization policy\n        #\n        #   @see memoize=\n        #   @api public\n        setting :memoize, default: false\n\n        # @!method namespaces\n        #\n        #   Returns the configured namespaces for the component dir.\n        #\n        #   Allows namespaces to added on the returned object via {Namespaces#add}.\n        #\n        #   @return [Namespaces] the namespaces\n        #\n        #   @see Namespaces#add\n        #   @api public\n        setting :namespaces, default: Namespaces.new, cloneable: true\n\n        # @!method add_to_load_path=(policy)\n        #\n        #   Sets whether the dir should be added to the `$LOAD_PATH` after the container\n        #   is configured.\n        #\n        #   Defaults to `true`. This may need to be set to `false` when using a class\n        #   autoloading system.\n        #\n        #   @param policy [Boolean]\n        #   @return [Boolean]\n        #\n        #   @see add_to_load_path\n        #   @see Container.configure\n        #   @api public\n        #\n        # @!method add_to_load_path\n        #\n        #   Returns the configured value.\n        #\n        #   @return [Boolean]\n        #\n        #   @see add_to_load_path=\n        #   @api public\n        setting :add_to_load_path, default: true\n\n        # @!endgroup\n\n        # Returns the component dir path, relative to the configured container root\n        #\n        # @return [String] the path\n        attr_reader :path\n\n        # @api public\n        def initialize(path)\n          super()\n          @path = path\n          yield self if block_given?\n        end\n\n        # @api private\n        def auto_register?\n          !!config.auto_register\n        end\n\n        private\n\n        def method_missing(name, ...)\n          if config.respond_to?(name)\n            config.public_send(name, ...)\n          else\n            super\n          end\n        end\n\n        def respond_to_missing?(name, include_all = false)\n          config.respond_to?(name) || super\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/config/component_dirs.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\nrequire \"dry/system/errors\"\n\nmodule Dry\n  module System\n    module Config\n      # The configured component dirs for a container\n      #\n      # @api public\n      class ComponentDirs\n        # @!group Settings\n\n        # @!method auto_register=(value)\n        #\n        #   Sets a default `auto_register` for all added component dirs\n        #\n        #   @see ComponentDir.auto_register=\n        #   @see auto_register\n        #\n        # @!method auto_register\n        #\n        #   Returns the configured default `auto_register`\n        #\n        #   @see auto_register=\n\n        # @!method instance=(value)\n        #\n        #   Sets a default `instance` for all added component dirs\n        #\n        #   @see ComponentDir.instance=\n        #   @see auto_register\n        #\n        # @!method auto_register\n        #\n        #   Returns the configured default `instance`\n        #\n        #   @see instance=\n\n        # @!method loader=(value)\n        #\n        #   Sets a default `loader` value for all added component dirs\n        #\n        #   @see ComponentDir.loader=\n        #   @see loader\n        #\n        # @!method loader\n        #\n        #   Returns the configured default `loader`\n        #\n        #   @see loader=\n\n        # @!method memoize=(value)\n        #\n        #   Sets a default `memoize` value for all added component dirs\n        #\n        #   @see ComponentDir.memoize=\n        #   @see memoize\n        #\n        # @!method memoize\n        #\n        #   Returns the configured default `memoize`\n        #\n        #   @see memoize=\n\n        # @!method namespaces\n        #\n        #   Returns the default configured namespaces for all added component dirs\n        #\n        #   Allows namespaces to added on the returned object via {Dry::System::Config::Namespaces#add}.\n        #\n        #   @see Dry::System::Config::Namespaces#add\n        #\n        #   @return [Namespaces] the namespaces\n\n        # @!method add_to_load_path=(value)\n        #\n        #   Sets a default `add_to_load_path` value for all added component dirs\n        #\n        #   @see ComponentDir.add_to_load_path=\n        #   @see add_to_load_path\n        #\n        # @!method add_to_load_path\n        #\n        #   Returns the configured default `add_to_load_path`\n        #\n        #   @see add_to_load_path=\n\n        # @!endgroup\n\n        # A ComponentDir for configuring the default values to apply to all added\n        # component dirs\n        #\n        # @see #method_missing\n        # @api private\n        attr_reader :defaults\n\n        # Creates a new component dirs\n        #\n        # @api private\n        def initialize\n          @dirs = {}\n          @defaults = ComponentDir.new(nil)\n        end\n\n        # @api private\n        def initialize_copy(source)\n          @dirs = source.dirs.transform_values(&:dup)\n          @defaults = source.defaults.dup\n        end\n\n        # Returns and optionally yields a previously added component dir\n        #\n        # @param path [String] the path for the component dir\n        # @yieldparam dir [ComponentDir] the component dir\n        #\n        # @return [ComponentDir] the component dir\n        #\n        # @api public\n        def dir(path)\n          dirs[path].tap do |dir|\n            # Defaults can be (re-)applied first, since the dir has already been added\n            apply_defaults_to_dir(dir) if dir\n            yield dir if block_given?\n          end\n        end\n        alias_method :[], :dir\n\n        # @overload add(path)\n        #   Adds and configures a component dir for the given path\n        #\n        #   @param path [String] the path for the component dir, relative to the configured\n        #     container root\n        #   @yieldparam dir [ComponentDir] the component dir to configure\n        #\n        #   @return [ComponentDir] the added component dir\n        #\n        #   @example\n        #     component_dirs.add \"lib\" do |dir|\n        #       dir.default_namespace = \"my_app\"\n        #     end\n        #\n        #   @see ComponentDir\n        #   @api public\n        #\n        # @overload add(dir)\n        #   Adds a configured component dir\n        #\n        #   @param dir [ComponentDir] the configured component dir\n        #\n        #   @return [ComponentDir] the added component dir\n        #\n        #   @example\n        #     dir = Dry::System::ComponentDir.new(\"lib\")\n        #     component_dirs.add dir\n        #\n        #   @see ComponentDir\n        #   @api public\n        def add(path_or_dir)\n          path, dir_to_add = path_and_dir(path_or_dir)\n\n          raise ComponentDirAlreadyAddedError, path if dirs.key?(path)\n\n          dirs[path] = dir_to_add.tap do |dir|\n            # Defaults must be applied after yielding, since the dir is being newly added,\n            # and must have its configuration fully in place before we can know which\n            # defaults to apply\n            yield dir if path_or_dir == path && block_given?\n            apply_defaults_to_dir(dir)\n          end\n        end\n\n        # Deletes and returns a previously added component dir\n        #\n        # @param path [String] the path for the component dir\n        #\n        # @return [ComponentDir] the removed component dir\n        #\n        # @api public\n        def delete(path)\n          dirs.delete(path)\n        end\n\n        # Returns the paths of the component dirs\n        #\n        # @return [Array<String>] the component dir paths\n        #\n        # @api public\n        def paths\n          dirs.keys\n        end\n\n        # Returns the count of component dirs\n        #\n        # @return [Integer]\n        #\n        # @api public\n        def length\n          dirs.length\n        end\n        alias_method :size, :length\n\n        # Returns the added component dirs, with default settings applied\n        #\n        # @return [Array<ComponentDir>]\n        #\n        # @api public\n        def to_a\n          dirs.each { |_, dir| apply_defaults_to_dir(dir) }\n          dirs.values\n        end\n\n        # Calls the given block once for each added component dir, passing the dir as an\n        # argument.\n        #\n        # @yieldparam dir [ComponentDir] the yielded component dir\n        #\n        # @api public\n        def each(&)\n          to_a.each(&)\n        end\n\n        protected\n\n        # Returns the hash of component dirs, keyed by their paths\n        #\n        # Recently changed default configuration may not be applied to these dirs. Use\n        # #to_a or #each to access dirs with default configuration fully applied.\n        #\n        # This method exists to encapsulate the instance variable and to serve the needs\n        # of #initialize_copy\n        #\n        # @return [Hash{String => ComponentDir}]\n        #\n        # @api private\n        attr_reader :dirs\n\n        private\n\n        # Converts a path string or pre-built component dir into a path and dir tuple\n        #\n        # @param path_or_dir [String,ComponentDir]\n        #\n        # @return [Array<(String, ComponentDir)>]\n        #\n        # @see #add\n        def path_and_dir(path_or_dir)\n          if path_or_dir.is_a?(ComponentDir)\n            dir = path_or_dir\n            [dir.path, dir]\n          else\n            path = path_or_dir\n            [path, ComponentDir.new(path)]\n          end\n        end\n\n        # Applies default settings to a component dir. This is run every time the dirs are\n        # accessed to ensure defaults are applied regardless of when new component dirs\n        # are added. This method must be idempotent.\n        #\n        # @return [void]\n        def apply_defaults_to_dir(dir)\n          defaults.config.values.each do |key, _|\n            if defaults.configured?(key) && !dir.configured?(key)\n              dir.public_send(:\"#{key}=\", defaults.public_send(key).dup)\n            end\n          end\n        end\n\n        def method_missing(name, ...)\n          if defaults.respond_to?(name)\n            defaults.public_send(name, ...)\n          else\n            super\n          end\n        end\n\n        def respond_to_missing?(name, include_all = false)\n          defaults.respond_to?(name) || super\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/config/namespace.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    module Config\n      # A configured namespace for a component dir\n      #\n      # Namespaces consist of three elements:\n      #\n      # - The `path` within the component dir to which its namespace rules should apply.\n      # - A `key`, which determines the leading part of the key used to register\n      #   each component in the container.\n      # - A `const`, which is the Ruby namespace expected to contain the class constants\n      #   defined within each component's source file. This value is expected to be an\n      #   \"underscored\" string, intended to be run through the configured inflector to be\n      #   converted into a real constant (e.g. `\"foo_bar/baz\"` will become `FooBar::Baz`)\n      #\n      # Namespaces are added and configured for a component dir via {Namespaces#add}.\n      #\n      # @see Namespaces#add\n      #\n      # @api public\n      class Namespace\n        ROOT_PATH = nil\n\n        include Dry::Equalizer(:path, :key, :const)\n\n        # @api public\n        attr_reader :path\n\n        # @api public\n        attr_reader :key\n\n        # @api public\n        attr_reader :const\n\n        # Returns a namespace configured to serve as the default root namespace for a\n        # component dir, ensuring that all code within the dir can be loaded, regardless\n        # of any other explictly configured namespaces\n        #\n        # @return [Namespace] the root namespace\n        #\n        # @api private\n        def self.default_root\n          new(\n            path: ROOT_PATH,\n            key: nil,\n            const: nil\n          )\n        end\n\n        # @api private\n        def initialize(path:, key:, const:)\n          @path = path\n          # Default keys (i.e. when the user does not explicitly provide one) for non-root\n          # paths will include path separators, which we must convert into key separators\n          @key = key && key == path ? key.gsub(PATH_SEPARATOR, KEY_SEPARATOR) : key\n          @const = const\n        end\n\n        # @api public\n        def root?\n          path == ROOT_PATH\n        end\n\n        # @api public\n        def path?\n          !root?\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/config/namespaces.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/errors\"\n\nmodule Dry\n  module System\n    module Config\n      # The configured namespaces for a ComponentDir\n      #\n      # @see Config::ComponentDir#namespaces\n      #\n      # @api private\n      class Namespaces\n        include Dry::Equalizer(:namespaces)\n\n        # @api private\n        attr_reader :namespaces\n\n        # @api private\n        def initialize\n          @namespaces = {}\n        end\n\n        # @api private\n        def initialize_copy(source)\n          super\n          @namespaces = source.namespaces.dup\n        end\n\n        # Returns the namespace configured for the path, or nil if no such namespace has\n        # been configured\n        #\n        # @return [Namespace, nil] the namespace, if configured\n        #\n        # @api public\n        def namespace(path)\n          namespaces[path]\n        end\n        alias_method :[], :namespace\n\n        # Returns the namespace configured for the root path, or nil if the root namespace\n        # has not been configured\n        #\n        # @return [Namespace, nil] the root namespace, if configured\n        #\n        # @api public\n        def root\n          namespaces[Namespace::ROOT_PATH]\n        end\n\n        # Adds a component dir namespace\n        #\n        # A namespace encompasses a given sub-directory of the component dir, and\n        # determines (1) the leading segments of its components' registered identifiers,\n        # and (2) the expected constant namespace of their class constants.\n        #\n        # A namespace for a path can only be added once.\n        #\n        # @example Adding a namespace with top-level identifiers\n        #   # Components defined within admin/ (e.g. admin/my_component.rb) will be:\n        #   #\n        #   # - Registered with top-level identifiers (\"my_component\")\n        #   # - Expected to have constants in `Admin`, matching the namespace's path (Admin::MyComponent)\n        #\n        #   namespaces.add \"admin\", key: nil\n        #\n        # @example Adding a namespace with top-level class constants\n        #   # Components defined within adapters/ (e.g. adapters/my_adapter.rb) will be:\n        #   #\n        #   # - Registered with leading identifiers matching the namespace's path (\"adapters.my_adapter\")\n        #   # - Expected to have top-level constants (::MyAdapter)\n        #\n        #   namespaces.add \"adapters\", const: nil\n        #\n        # @example Adding a namespace with distinct identifiers and class constants\n        #   # Components defined within `bananas/` (e.g. bananas/banana_split.rb) will be:\n        #   #\n        #   # - Registered with the given leading identifier (\"desserts.banana_split\")\n        #   # - Expected to have constants within the given namespace (EatMe::Now::BananaSplit)\n        #\n        #   namespaces.add \"bananas\", key: \"desserts\", const: \"eat_me/now\"\n        #\n        # @param path [String] the path to the sub-directory of source files to which this\n        #   namespace should apply, relative to the component dir\n        # @param key [String, nil] the leading namespace to apply to the container keys\n        #   for the components. Set `nil` for the keys to be top-level.\n        # @param const [String, nil] the Ruby constant namespace to expect for constants\n        #   defined within the components. This should be provided in underscored string\n        #   form, e.g. \"hello_there/world\" for a Ruby constant of `HelloThere::World`. Set\n        #   `nil` for the constants to be top-level.\n        #\n        # @return [Namespace] the added namespace\n        #\n        # @see Namespace\n        #\n        # @api public\n        def add(path, key: path, const: path)\n          raise NamespaceAlreadyAddedError, path if namespaces.key?(path)\n\n          namespaces[path] = Namespace.new(path: path, key: key, const: const)\n        end\n\n        # Adds a root component dir namespace\n        #\n        # @see #add\n        #\n        # @api public\n        def add_root(key: nil, const: nil)\n          add(Namespace::ROOT_PATH, key: key, const: const)\n        end\n\n        # Deletes the configured namespace for the given path and returns the namespace\n        #\n        # If no namespace was previously configured for the given path, returns nil\n        #\n        # @param path [String] the path for the namespace\n        #\n        # @return [Namespace, nil]\n        #\n        # @api public\n        def delete(path)\n          namespaces.delete(path)\n        end\n\n        # Deletes the configured root namespace and returns the namespace\n        #\n        # If no root namespace was previously configured, returns nil\n        #\n        # @return [Namespace, nil]\n        #\n        # @api public\n        def delete_root\n          delete(Namespace::ROOT_PATH)\n        end\n\n        # Returns the paths of the configured namespaces\n        #\n        # @return [Array<String,nil>] the namespace paths, with nil representing the root\n        #   namespace\n        #\n        # @api public\n        def paths\n          namespaces.keys\n        end\n\n        # Returns the count of configured namespaces\n        #\n        # @return [Integer]\n        #\n        # @api public\n        def length\n          namespaces.length\n        end\n        alias_method :size, :length\n\n        # Returns true if there are no configured namespaces\n        #\n        # @return [Boolean]\n        #\n        # @api public\n        def empty?\n          namespaces.empty?\n        end\n\n        # Returns the configured namespaces as an array\n        #\n        # Adds a default root namespace to the end of the array if one was not added\n        # explicitly. This fallback ensures that all components in the component dir can\n        # be loaded.\n        #\n        # @return [Array<Namespace>] the namespaces\n        #\n        # @api public\n        def to_a\n          namespaces.values.tap do |arr|\n            arr << Namespace.default_root unless arr.any?(&:root?)\n          end\n        end\n\n        # Calls the given block once for each configured namespace, passing the namespace\n        # as an argument.\n        #\n        # @yieldparam namespace [Namespace] the yielded namespace\n        #\n        # @api public\n        def each(&)\n          to_a.each(&)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/constants.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    include Dry::Core::Constants\n\n    RB_EXT = \".rb\"\n    RB_GLOB = \"*.rb\"\n    PATH_SEPARATOR = File::SEPARATOR\n    KEY_SEPARATOR = \".\"\n    WORD_REGEX = /\\w+/\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/container.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"pathname\"\n\nrequire \"dry/configurable\"\nrequire \"dry/auto_inject\"\nrequire \"dry/inflector\"\n\nmodule Dry\n  module System\n    # Abstract container class to inherit from\n    #\n    # Container class is treated as a global registry with all system components.\n    # Container can also import dependencies from other containers, which is\n    # useful in complex systems that are split into sub-systems.\n    #\n    # Container can be finalized, which triggers loading of all the defined\n    # components within a system, after finalization it becomes frozen. This\n    # typically happens in cases like booting a web application.\n    #\n    # Before finalization, Container can lazy-load components on demand. A\n    # component can be a simple class defined in a single file, or a complex\n    # component which has init/start/stop lifecycle, and it's defined in a boot\n    # file. Components which specify their dependencies using Import module can\n    # be safely required in complete isolation, and Container will resolve and\n    # load these dependencies automatically.\n    #\n    # Furthermore, Container supports auto-registering components based on\n    # dir/file naming conventions. This reduces a lot of boilerplate code as all\n    # you have to do is to put your classes under configured directories and\n    # their instances will be automatically registered within a container.\n    #\n    # Every container needs to be configured with following settings:\n    #\n    # * `:name` - a unique container name\n    # * `:root` - a system root directory (defaults to `pwd`)\n    #\n    # @example\n    #   class MyApp < Dry::System::Container\n    #     configure do |config|\n    #       config.name = :my_app\n    #\n    #       # this will auto-register classes from 'lib/components'. ie if you add\n    #       # `lib/components/repo.rb` which defines `Repo` class, then it's\n    #       # instance will be automatically available as `MyApp['repo']`\n    #       config.auto_register = %w(lib/components)\n    #     end\n    #\n    #     # this will configure $LOAD_PATH to include your `lib` dir\n    #     add_dirs_to_load_paths!('lib')\n    #   end\n    #\n    # @api public\n    class Container\n      extend Dry::Core::Container::Mixin\n      extend Dry::System::Plugins\n\n      setting :name\n      setting :root, default: Pathname.pwd.freeze, constructor: ->(path) { Pathname(path) }\n      setting :provider_dirs, default: [\"system/providers\"]\n      setting :registrations_dir, default: \"system/registrations\"\n      setting :component_dirs, default: Config::ComponentDirs.new, cloneable: true\n      setting :exports, reader: true\n      setting :inflector, default: Dry::Inflector.new\n      setting :auto_registrar, default: Dry::System::AutoRegistrar\n      setting :manifest_registrar, default: Dry::System::ManifestRegistrar\n      setting :provider_registrar, default: Dry::System::ProviderRegistrar\n      setting :importer, default: Dry::System::Importer\n\n      # Expect \".\" as key namespace separator. This is not intended to be user-configurable.\n      config.namespace_separator = KEY_SEPARATOR\n\n      class << self\n        # @!method config\n        #   Returns the configuration for the container\n        #\n        #   @example\n        #     container.config.root = \"/path/to/app\"\n        #     container.config.root # => #<Pathname:/path/to/app>\n        #\n        #   @return [Dry::Configurable::Config]\n        #\n        #   @api public\n\n        # Yields a configuration object for the container, which you can use to modify the\n        # configuration, then runs the after-`configured` hooks and finalizes (freezes)\n        # the {config}.\n        #\n        # Does not finalize the config when given `finalize_config: false`\n        #\n        # @example\n        #   class MyApp < Dry::System::Container\n        #     configure do |config|\n        #       config.root = Pathname(\"/path/to/app\")\n        #       config.name = :my_app\n        #     end\n        #   end\n        #\n        # @param finalize_config [Boolean]\n        #\n        # @return [self]\n        #\n        # @see after\n        #\n        # @api public\n        def configure(finalize_config: true, &)\n          super(&)\n          configured!(finalize_config: finalize_config)\n        end\n\n        # Marks the container as configured, runs the after-`configured` hooks, then\n        # finalizes (freezes) the {config}.\n        #\n        # This method is useful to call if you're modifying the container's {config}\n        # directly, rather than via the config object yielded when calling {configure}.\n        #\n        # Does not finalize the config if given `finalize_config: false`.\n        #\n        # @param finalize_config [Boolean]\n        #\n        # @return [self]\n        #\n        # @see after\n        #\n        # @api public\n        def configured!(finalize_config: true)\n          return self if configured?\n\n          hooks[:after_configure].each { |hook| instance_eval(&hook) }\n\n          _configurable_finalize! if finalize_config\n\n          @__configured__ = true\n\n          self\n        end\n\n        # Finalizes the config for this container\n        #\n        # @api private\n        alias_method :_configurable_finalize!, :finalize!\n\n        def configured?\n          @__configured__.equal?(true)\n        end\n\n        # Registers another container for import\n        #\n        # @example\n        #   # system/container.rb\n        #   require \"dry/system\"\n        #   require \"logger\"\n        #\n        #   class Core < Dry::System::Container\n        #     register(\"logger\", Logger.new($stdout))\n        #   end\n        #\n        #   # apps/my_app/system/container.rb\n        #   require 'system/container'\n        #\n        #   class MyApp < Dry::System::Container\n        #     import(from: Core, as: :core)\n        #   end\n        #\n        #   MyApp.import(keys: [\"logger\"], from: Core, as: :core2)\n        #\n        #   MyApp[\"core.logger\"].info(\"Test\")\n        #   MyApp[\"core2.logger\"].info(\"Test2\")\n        #\n        # @param keys [Array<String>] Keys for the components to import\n        # @param from [Class] The container to import from\n        # @param as [Symbol] Namespace to use for the components of the imported container\n        #\n        # @raise [Dry::System::ContainerAlreadyFinalizedError] if the container has already\n        #  been finalized\n        #\n        # @api public\n        def import(from:, as:, keys: nil)\n          raise Dry::System::ContainerAlreadyFinalizedError if finalized?\n\n          importer.register(container: from, namespace: as, keys: keys)\n\n          self\n        end\n\n        # @overload register_provider(name, namespace: nil, from: nil, source: nil, if: true, &block)\n        #   Registers a provider and its lifecycle hooks\n        #\n        #   By convention, you should place a file for each provider in one of the\n        #   configured `provider_dirs`, and they will be loaded on demand when components\n        #   are loaded in isolation, or during container finalization.\n        #\n        #   @example\n        #     # system/container.rb\n        #     class MyApp < Dry::System::Container\n        #       configure do |config|\n        #         config.root = Pathname(\"/path/to/app\")\n        #       end\n        #     end\n        #\n        #     # system/providers/db.rb\n        #     #\n        #     # Simple provider registration\n        #     MyApp.register_provider(:db) do\n        #       start do\n        #         require \"db\"\n        #         register(\"db\", DB.new)\n        #       end\n        #     end\n        #\n        #     # system/providers/db.rb\n        #     #\n        #     # Provider registration with lifecycle triggers\n        #     MyApp.register_provider(:db) do |container|\n        #       init do\n        #         require \"db\"\n        #         DB.configure(ENV[\"DB_URL\"])\n        #         container.register(\"db\", DB.new)\n        #       end\n        #\n        #       start do\n        #         container[\"db\"].establish_connection\n        #       end\n        #\n        #       stop do\n        #         container[\"db\"].close_connection\n        #       end\n        #     end\n        #\n        #     # system/providers/db.rb\n        #     #\n        #     # Provider registration which uses another provider\n        #     MyApp.register_provider(:db) do |container|\n        #       start do\n        #         use :logger\n        #\n        #         require \"db\"\n        #         DB.configure(ENV['DB_URL'], logger: logger)\n        #         container.register(\"db\", DB.new)\n        #       end\n        #     end\n        #\n        #     # system/providers/db.rb\n        #     #\n        #     # Provider registration under a namespace. This will register the\n        #     # db object with the \"persistence.db\" key\n        #     MyApp.register_provider(:persistence, namespace: \"db\") do\n        #       start do\n        #         require \"db\"\n        #         DB.configure(ENV[\"DB_URL\"])\n        #         register(\"db\", DB.new)\n        #       end\n        #     end\n        #\n        #   @param name [Symbol] a unique name for the provider\n        #   @param namespace [String, nil] the key namespace to use for any registrations\n        #     made during the provider's lifecycle\n        #   @param from [Symbol, nil] the group for the external provider source (with the\n        #     provider source name inferred from `name` or passsed explicitly as\n        #     `source:`)\n        #   @param source [Symbol, nil] the name of the external provider source to use\n        #     (if different from the value provided as `name`)\n        #   @param if [Boolean] a boolean to determine whether to register the provider\n        #\n        #   @see Provider\n        #   @see Provider::Source\n        #\n        #   @return [self]\n        #\n        #   @api public\n        def register_provider(...)\n          providers.register_provider(...)\n        end\n\n        # Return if a container was finalized\n        #\n        # @return [TrueClass, FalseClass]\n        #\n        # @api public\n        def finalized?\n          @__finalized__.equal?(true)\n        end\n\n        # Finalizes the container\n        #\n        # This triggers importing components from other containers, booting\n        # registered components and auto-registering components. It should be\n        # called only in places where you want to finalize your system as a\n        # whole, ie when booting a web application\n        #\n        # @example\n        #   # system/container.rb\n        #   class MyApp < Dry::System::Container\n        #     configure do |config|\n        #       config.root = Pathname(\"/path/to/app\")\n        #       config.name = :my_app\n        #       config.auto_register = %w(lib/apis lib/core)\n        #     end\n        #   end\n        #\n        #   # You can put finalization file anywhere you want, ie system/boot.rb\n        #   MyApp.finalize!\n        #\n        #   # If you need last-moment adjustments just before the finalization\n        #   # you can pass a block and do it there\n        #   MyApp.finalize! do |container|\n        #     # stuff that only needs to happen for finalization\n        #   end\n        #\n        # @return [self] frozen container\n        #\n        # @api public\n        def finalize!(freeze: true, &)\n          return self if finalized?\n\n          configured!\n\n          run_hooks(:finalize) do\n            yield(self) if block_given?\n\n            [providers, auto_registrar, manifest_registrar, importer].each(&:finalize!)\n\n            @__finalized__ = true\n          end\n\n          self.freeze if freeze\n\n          self\n        end\n\n        # Starts a provider\n        #\n        # As a result, the provider's `prepare` and `start` lifecycle triggers are called\n        #\n        # @example\n        #   MyApp.start(:persistence)\n        #\n        # @param name [Symbol] the name of a registered provider to start\n        #\n        # @return [self]\n        #\n        # @api public\n        def start(name)\n          providers.start(name)\n          self\n        end\n\n        # Prepares a provider using its `prepare` lifecycle trigger\n        #\n        # Preparing (as opposed to starting) a provider is useful in places where some\n        # aspects of a heavier dependency are needed, but its fully started environment\n        #\n        # @example\n        #   MyApp.prepare(:persistence)\n        #\n        # @param name [Symbol] The name of the registered provider to prepare\n        #\n        # @return [self]\n        #\n        # @api public\n        def prepare(name)\n          providers.prepare(name)\n          self\n        end\n\n        # Stop a specific component but calls only `stop` lifecycle trigger\n        #\n        # @example\n        #   MyApp.stop(:persistence)\n        #\n        # @param name [Symbol] The name of a registered bootable component\n        #\n        # @return [self]\n        #\n        # @api public\n        def stop(name)\n          providers.stop(name)\n          self\n        end\n\n        # @api public\n        def shutdown!\n          providers.shutdown\n          self\n        end\n\n        # Adds the directories (relative to the container's root) to the Ruby load path\n        #\n        # @example\n        #   class MyApp < Dry::System::Container\n        #     configure do |config|\n        #       # ...\n        #     end\n        #\n        #     add_to_load_path!('lib')\n        #   end\n        #\n        # @param dirs [Array<String>]\n        #\n        # @return [self]\n        #\n        # @api public\n        def add_to_load_path!(*dirs)\n          dirs.reverse.map(&root.method(:join)).each do |path|\n            $LOAD_PATH.prepend(path.to_s) unless $LOAD_PATH.include?(path.to_s)\n          end\n          self\n        end\n\n        # @api public\n        def load_registrations!(name)\n          manifest_registrar.(name)\n          self\n        end\n\n        # Builds injector for this container\n        #\n        # An injector is a useful mixin which injects dependencies into\n        # automatically defined constructor.\n        #\n        # @example\n        #   # Define an injection mixin\n        #   #\n        #   # system/import.rb\n        #   Import = MyApp.injector\n        #\n        #   # Use it in your auto-registered classes\n        #   #\n        #   # lib/user_repo.rb\n        #   require 'import'\n        #\n        #   class UserRepo\n        #     include Import['persistence.db']\n        #   end\n        #\n        #   MyApp['user_repo].db # instance under 'persistence.db' key\n        #\n        # @param options [Hash] injector options\n        #\n        # @api public\n        def injector(**options)\n          Dry::AutoInject(self, **options)\n        end\n\n        # Requires one or more files relative to the container's root\n        #\n        # @example\n        #   # single file\n        #   MyApp.require_from_root('lib/core')\n        #\n        #   # glob\n        #   MyApp.require_from_root('lib/**/*')\n        #\n        # @param paths [Array<String>] one or more paths, supports globs too\n        #\n        # @api public\n        def require_from_root(*paths)\n          paths.flat_map { |path|\n            path.to_s.include?(\"*\") ? ::Dir[root.join(path)] : root.join(path)\n          }.each { |path|\n            Kernel.require path.to_s\n          }\n        end\n\n        # Returns container's root path\n        #\n        # @example\n        #   class MyApp < Dry::System::Container\n        #     configure do |config|\n        #       config.root = Pathname('/my/app')\n        #     end\n        #   end\n        #\n        #   MyApp.root # returns '/my/app' pathname\n        #\n        # @return [Pathname]\n        #\n        # @api public\n        def root\n          config.root\n        end\n\n        # @api public\n        def register(key, *)\n          super\n\n          hooks[:after_register].each { |hook| instance_exec(key, &hook) }\n\n          self\n        end\n\n        # @api public\n        def resolve(key)\n          load_component(key) unless finalized?\n\n          super\n        end\n\n        alias_method :registered?, :key?\n        #\n        # @!method registered?(key)\n        #   Whether a +key+ is registered (doesn't trigger loading)\n        #   @param key [String,Symbol] The key\n        #   @return [Boolean]\n        #   @api public\n        #\n\n        # Check if identifier is registered.\n        # If not, try to load the component\n        #\n        # @param key [String,Symbol] Identifier\n        # @return [Boolean]\n        #\n        # @api public\n        def key?(key)\n          if finalized?\n            registered?(key)\n          else\n            registered?(key) || resolve(key) { return false }\n            true\n          end\n        end\n\n        # @api private\n        def component_dirs\n          config.component_dirs.to_a.map { |dir| ComponentDir.new(config: dir, container: self) }\n        end\n\n        # @api private\n        def providers\n          @providers ||= config.provider_registrar.new(self)\n        end\n\n        # @api private\n        def auto_registrar\n          @auto_registrar ||= config.auto_registrar.new(self)\n        end\n\n        # @api private\n        def manifest_registrar\n          @manifest_registrar ||= config.manifest_registrar.new(self)\n        end\n\n        # @api private\n        def importer\n          @importer ||= config.importer.new(self)\n        end\n\n        # Registers a callback hook to run before container lifecycle events.\n        #\n        # Currently, the only supported event is `:finalized`. This hook is called when\n        # you run `{finalize!}`.\n        #\n        # When the given block is called, `self` is the container class, and no block\n        # arguments are given.\n        #\n        # @param event [Symbol] the event name\n        # @param block [Proc] the callback hook to run\n        #\n        # @return [self]\n        #\n        # @api public\n        def before(event, &block)\n          hooks[:\"before_#{event}\"] << block\n          self\n        end\n\n        # Registers a callback hook to run after container lifecycle events.\n        #\n        # The supported events are:\n        #\n        # - `:configured`, called when you run {configure} or {configured!}, or when\n        #   running {finalize!} and neither of the prior two methods have been called.\n        # - `:finalized`, called when you run {finalize!}.\n        #\n        # When the given block is called, `self` is the container class, and no block\n        # arguments are given.\n        #\n        # @param event [Symbol] the event name\n        # @param block [Proc] the callback hook to run\n        #\n        # @return [self]\n        #\n        # @api public\n        def after(event, &block)\n          hooks[:\"after_#{event}\"] << block\n          self\n        end\n\n        # @api private\n        def hooks\n          @hooks ||= Hash.new { |h, k| h[k] = [] }\n        end\n\n        # @api private\n        def inherited(klass)\n          hooks.each do |event, blocks|\n            klass.hooks[event].concat blocks.dup\n          end\n\n          klass.instance_variable_set(:@__configured__, false)\n          klass.instance_variable_set(:@__finalized__, false)\n\n          super\n        end\n\n        protected\n\n        # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity\n        # @api private\n        def load_component(key)\n          return self if registered?(key)\n\n          if (provider = providers[key])\n            provider.start\n            return self\n          end\n\n          component = find_component(key)\n\n          providers[component.root_key]&.start\n          return self if registered?(key)\n\n          if component.loadable?\n            load_local_component(component)\n          elsif manifest_registrar.file_exists?(component)\n            manifest_registrar.(component)\n          elsif importer.namespace?(component.root_key)\n            load_imported_component(component.identifier, namespace: component.root_key)\n          elsif importer.namespace?(nil)\n            load_imported_component(component.identifier, namespace: nil)\n          end\n\n          self\n        end\n        # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity\n\n        private\n\n        def load_local_component(component)\n          if component.auto_register?\n            register(component.identifier, memoize: component.memoize?) { component.instance }\n          end\n        end\n\n        def load_imported_component(identifier, namespace:)\n          return unless importer.namespace?(namespace)\n\n          import_key = identifier.namespaced(from: namespace, to: nil).key\n\n          importer.import(namespace, keys: [import_key])\n        end\n\n        def find_component(key)\n          # Find the first matching component from within the configured component dirs.\n          # If no matching component is found, return a null component; this fallback is\n          # important because the component may still be loadable via the manifest\n          # registrar or an imported container.\n          component_dirs.detect { |dir|\n            if (component = dir.component_for_key(key))\n              break component\n            end\n          } || IndirectComponent.new(Identifier.new(key))\n        end\n\n        def run_hooks(event)\n          hooks[:\"before_#{event}\"].each { instance_eval(&_1) }\n          yield\n          hooks[:\"after_#{event}\"].each { instance_eval(&_1) }\n        end\n      end\n\n      # Default hooks\n      after :configure do\n        # Add appropriately configured component dirs to the load path\n        #\n        # Do this in a single pass to preserve ordering (i.e. earliest dirs win)\n        paths = config.component_dirs.to_a.each_with_object([]) { |dir, arr|\n          arr << dir.path if dir.add_to_load_path\n        }\n        add_to_load_path!(*paths)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/errors.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    # Error raised when import is called on an already finalized container\n    #\n    # @api public\n    ContainerAlreadyFinalizedError = Class.new(StandardError)\n\n    # Error raised when a component dir is added to configuration more than once\n    #\n    # @api public\n    ComponentDirAlreadyAddedError = Class.new(StandardError) do\n      def initialize(dir)\n        super(\"Component directory #{dir.inspect} already added\")\n      end\n    end\n\n    # Error raised when a configured component directory could not be found\n    #\n    # @api public\n    ComponentDirNotFoundError = Class.new(StandardError) do\n      def initialize(dir)\n        super(\"Component dir '#{dir}' not found\")\n      end\n    end\n\n    # Error raised when a namespace for a component dir is added to configuration more\n    # than once\n    #\n    # @api public\n    NamespaceAlreadyAddedError = Class.new(StandardError) do\n      def initialize(path)\n        path_label = path ? \"path #{path.inspect}\" : \"root path\"\n\n        super(\"Namespace for #{path_label} already added\")\n      end\n    end\n\n    # Error raised when attempting to register provider using a name that has already been\n    # registered\n    #\n    # @api public\n    ProviderAlreadyRegisteredError = Class.new(ArgumentError) do\n      def initialize(provider_name)\n        super(\"Provider #{provider_name.inspect} has already been registered\")\n      end\n    end\n\n    # Error raised when a named provider could not be found\n    #\n    # @api public\n    ProviderNotFoundError = Class.new(ArgumentError) do\n      def initialize(name)\n        super(\"Provider #{name.inspect} not found\")\n      end\n    end\n\n    # Error raised when a named provider source could not be found\n    #\n    # @api public\n    ProviderSourceNotFoundError = Class.new(StandardError) do\n      def initialize(name:, group:, keys:)\n        msg = \"Provider source not found: #{name.inspect}, group: #{group.inspect}\"\n\n        key_list = keys.map { |key| \"- #{key[:name].inspect}, group: #{key[:group].inspect}\" }\n        msg += \"Available provider sources:\\n\\n#{key_list}\"\n\n        super(msg)\n      end\n    end\n\n    # Error raised when trying to use a plugin that does not exist.\n    #\n    # @api public\n    PluginNotFoundError = Class.new(StandardError) do\n      def initialize(plugin_name)\n        super(\"Plugin #{plugin_name.inspect} does not exist\")\n      end\n    end\n\n    # Exception raise when a plugin dependency failed to load\n    #\n    # @api public\n    PluginDependencyMissing = Class.new(StandardError) do\n      # @api private\n      def initialize(plugin, message, gem = nil)\n        details = gem ? \"#{message} - add #{gem} to your Gemfile\" : message\n        super(\"dry-system plugin #{plugin.inspect} failed to load its dependencies: #{details}\")\n      end\n    end\n\n    # Exception raised when auto-registerable component is not loadable\n    #\n    # @api public\n    ComponentNotLoadableError = Class.new(NameError) do\n      # @api private\n      def initialize(component, error,\n                     corrections: DidYouMean::ClassNameChecker.new(error).corrections)\n        full_class_name = [error.receiver, error.name].join(\"::\")\n\n        message = [\n          \"Component '#{component.key}' is not loadable.\",\n          \"Looking for #{full_class_name}.\"\n        ]\n\n        if corrections.any?\n          case_correction = corrections.find { |correction| correction.casecmp?(full_class_name) }\n          if case_correction\n            acronyms_needed = case_correction.split(\"::\").difference(full_class_name.split(\"::\"))\n            stringified_acronyms_needed = acronyms_needed.map { |acronym|\n              \"'#{acronym}'\"\n            } .join(\", \")\n            message <<\n              <<~ERROR_MESSAGE\n\n                You likely need to add:\n\n                    acronym(#{stringified_acronyms_needed})\n\n                to your container's inflector, since we found a #{case_correction} class.\n              ERROR_MESSAGE\n          else\n            message << DidYouMean.formatter.message_for(corrections)\n          end\n        end\n\n        super(message.join(\"\\n\"))\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/identifier.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # An identifier representing a component to be registered.\n    #\n    # Components are eventually registered in the container using plain string\n    # identifiers, available as the `identifier` or `key` attribute here. Additional\n    # methods are provided to make it easier to evaluate or manipulate these identifiers.\n    #\n    # @api public\n    class Identifier\n      include Dry::Equalizer(:key)\n\n      # @return [String] the identifier's string key\n      # @api public\n      attr_reader :key\n\n      # @api private\n      def initialize(key)\n        @key = key.to_s\n      end\n\n      # @!method to_s\n      #   Returns the identifier string key\n      #\n      #   @return [String]\n      #   @see #key\n      #   @api public\n      alias_method :to_s, :key\n\n      # Returns the root namespace segment of the identifier string, as a symbol\n      #\n      # @example\n      #   identifier.key # => \"articles.operations.create\"\n      #   identifier.root_key # => :articles\n      #\n      # @return [Symbol] the root key\n      # @api public\n      def root_key\n        segments.first.to_sym\n      end\n\n      # Returns true if the given leading segments string is a leading part of the {key}.\n      #\n      # Also returns true if nil or an empty string is given.\n      #\n      # @example\n      #   identifier.key # => \"articles.operations.create\"\n      #\n      #   identifier.start_with?(\"articles.operations\") # => true\n      #   identifier.start_with?(\"articles\") # => true\n      #   identifier.start_with?(\"article\") # => false\n      #   identifier.start_with?(nil) # => true\n      #\n      # @param leading_segments [String] the one or more leading segments to check\n      # @return [Boolean]\n      # @api public\n      def start_with?(leading_segments)\n        leading_segments.to_s.empty? ||\n          key.start_with?(\"#{leading_segments}#{KEY_SEPARATOR}\") ||\n          key.eql?(leading_segments)\n      end\n\n      # Returns true if the given trailing segments string is the end part of the {key}.\n      #\n      # Also returns true if nil or an empty string is given.\n      #\n      # @example\n      #   identifier.key # => \"articles.operations.create\"\n      #\n      #   identifier.end_with?(\"create\") # => true\n      #   identifier.end_with?(\"operations.create\") # => true\n      #   identifier.end_with?(\"ate\") # => false, not a whole segment\n      #   identifier.end_with?(\"nup\") # => false, not in key at all\n      #\n      # @param trailing_segments [String] the one or more trailing key segments to check\n      # @return [Boolean]\n      # @api public\n      def end_with?(trailing_segments)\n        trailing_segments.to_s.empty? ||\n          key.end_with?(\"#{KEY_SEPARATOR}#{trailing_segments}\") ||\n          key.eql?(trailing_segments)\n      end\n\n      # Returns true if the given segments string matches whole segments within the {key}.\n      #\n      # @example\n      #   identifier.key # => \"articles.operations.create\"\n      #\n      #   identifier.include?(\"operations\") # => true\n      #   identifier.include?(\"articles.operations\") # => true\n      #   identifier.include?(\"operations.create\") # => true\n      #\n      #   identifier.include?(\"article\") # => false, not a whole segment\n      #   identifier.include?(\"update\") # => false, not in key at all\n      #\n      # @param segments [String] the one of more key segments to check\n      # @return [Boolean]\n      # @api public\n      def include?(segments)\n        return false if segments.to_s.empty?\n\n        sep_re = Regexp.escape(KEY_SEPARATOR)\n        key.match?(\n          /\n            (\\A|#{sep_re})\n            #{Regexp.escape(segments)}\n            (\\Z|#{sep_re})\n          /x\n        )\n      end\n\n      # Returns the key with its segments separated by the given separator\n      #\n      # @example\n      #   identifier.key # => \"articles.operations.create\"\n      #   identifier.key_with_separator(\"/\") # => \"articles/operations/create\"\n      #\n      # @return [String] the key using the separator\n      # @api private\n      def key_with_separator(separator)\n        segments.join(separator)\n      end\n\n      # Returns a copy of the identifier with the key's leading namespace(s) replaced\n      #\n      # @example Changing a namespace\n      #   identifier.key # => \"articles.operations.create\"\n      #   identifier.namespaced(from: \"articles\", to: \"posts\").key # => \"posts.commands.create\"\n      #\n      # @example Removing a namespace\n      #   identifier.key # => \"articles.operations.create\"\n      #   identifier.namespaced(from: \"articles\", to: nil).key # => \"operations.create\"\n      #\n      # @example Adding a namespace\n      #   identifier.key # => \"articles.operations.create\"\n      #   identifier.namespaced(from: nil, to: \"admin\").key # => \"admin.articles.operations.create\"\n      #\n      # @param from [String, nil] the leading namespace(s) to replace\n      # @param to [String, nil] the replacement for the leading namespace\n      #\n      # @return [Dry::System::Identifier] the copy of the identifier\n      #\n      # @see #initialize\n      # @api private\n      def namespaced(from:, to:)\n        return self if from == to\n\n        separated_to = \"#{to}#{KEY_SEPARATOR}\" if to\n\n        new_key =\n          if from.nil?\n            \"#{separated_to}#{key}\"\n          else\n            key.sub(\n              /^#{Regexp.escape(from.to_s)}#{Regexp.escape(KEY_SEPARATOR)}/,\n              separated_to || EMPTY_STRING\n            )\n          end\n\n        return self if new_key == key\n\n        self.class.new(new_key)\n      end\n\n      private\n\n      def segments\n        @segments ||= key.split(KEY_SEPARATOR)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/importer.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Default importer implementation\n    #\n    # This is currently configured by default for every System::Container.\n    # Importer objects are responsible for importing components from one\n    # container to another. This is used in cases where an application is split\n    # into multiple sub-systems.\n    #\n    # @api private\n    class Importer\n      # @api private\n      class Item\n        attr_reader :namespace, :container, :import_keys\n\n        def initialize(namespace:, container:, import_keys:)\n          @namespace = namespace\n          @container = container\n          @import_keys = import_keys\n        end\n      end\n\n      attr_reader :container\n\n      attr_reader :registry\n\n      # @api private\n      def initialize(container)\n        @container = container\n        @registry = {}\n      end\n\n      # @api private\n      def register(namespace:, container:, keys: nil)\n        registry[namespace_key(namespace)] = Item.new(\n          namespace: namespace,\n          container: container,\n          import_keys: keys\n        )\n      end\n\n      # @api private\n      def [](name)\n        registry.fetch(namespace_key(name))\n      end\n\n      # @api private\n      def key?(name)\n        registry.key?(namespace_key(name))\n      end\n      alias_method :namespace?, :key?\n\n      # @api private\n      def finalize!\n        registry.each_key { import(_1) }\n        self\n      end\n\n      # @api private\n      def import(namespace, keys: Undefined)\n        item = self[namespace]\n        keys = Undefined.default(keys, item.import_keys)\n\n        if keys\n          import_keys(item.container, namespace, keys_to_import(keys, item))\n        else\n          import_all(item.container, namespace)\n        end\n\n        self\n      end\n\n      private\n\n      # Returns nil if given a nil (i.e. root) namespace. Otherwise, converts the namespace to a\n      # string.\n      #\n      # This ensures imported components are found when either symbols or strings to given as the\n      # namespace in {Container.import}.\n      def namespace_key(namespace)\n        return nil if namespace.nil?\n\n        namespace.to_s\n      end\n\n      def keys_to_import(keys, item)\n        keys\n          .then { (arr = item.import_keys) ? _1 & arr : _1 }\n          .then { (arr = item.container.exports) ? _1 & arr : _1 }\n      end\n\n      def import_keys(other, namespace, keys)\n        merge(container, build_merge_container(other, keys), namespace: namespace)\n      end\n\n      def import_all(other, namespace)\n        merge_container =\n          if other.exports\n            build_merge_container(other, other.exports)\n          else\n            build_merge_container(other.finalize!, other.keys)\n          end\n\n        merge(container, merge_container, namespace: namespace)\n      end\n\n      # Merges `other` into `container`, favoring the container's existing registrations\n      def merge(container, other, namespace:)\n        container.merge(other, namespace: namespace) { |_key, old_item, new_item|\n          old_item || new_item\n        }\n      end\n\n      def build_merge_container(other, keys)\n        keys.each_with_object(Core::Container.new) { |key, ic|\n          next unless other.key?(key)\n\n          # Access the other container's items directly so that we can preserve all their\n          # options when we merge them with the target container (e.g. if a component in\n          # the provider container was registered with a block, we want block registration\n          # behavior to be exhibited when later resolving that component from the target\n          # container). TODO: Make this part of dry-system's public API.\n          item = other._container[key]\n\n          # By default, we \"protect\" components that were themselves imported into the\n          # other container from being implicitly exported; imported components are\n          # considered \"private\" and must be explicitly included in `exports` to be\n          # exported.\n          next if item.options[:imported] && !other.exports\n\n          if item.callable?\n            ic.register(key, **item.options, imported: true, &item.item)\n          else\n            ic.register(key, item.item, **item.options, imported: true)\n          end\n        }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/indirect_component.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    # An indirect component is a component that cannot be directly from a source file\n    # directly managed by the container. It may be component that needs to be loaded\n    # indirectly, either via a registration manifest file or an imported container\n    #\n    # Indirect components are an internal abstraction and, unlike ordinary components, are\n    # not exposed to users via component dir configuration hooks.\n    #\n    # @see Container#load_component\n    # @see Container#find_component\n    #\n    # @api private\n    class IndirectComponent\n      include Dry::Equalizer(:identifier)\n\n      # @!attribute [r] identifier\n      #   @return [String] the component's unique identifier\n      attr_reader :identifier\n\n      # @api private\n      def initialize(identifier)\n        @identifier = identifier\n      end\n\n      # Returns false, indicating that the component is not directly loadable from the\n      # files managed by the container\n      #\n      # This is the inverse of {Component#loadable?}\n      #\n      # @return [FalseClass]\n      #\n      # @api private\n      def loadable?\n        false\n      end\n\n      # Returns the component's unique key\n      #\n      # @return [String] the key\n      #\n      # @see Identifier#key\n      #\n      # @api private\n      def key\n        identifier.to_s\n      end\n\n      # Returns the root namespace segment of the component's key, as a symbol\n      #\n      # @see Identifier#root_key\n      #\n      # @return [Symbol] the root key\n      #\n      # @api private\n      def root_key\n        identifier.root_key\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/loader/autoloading.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    class Loader\n      # Component loader for autoloading-enabled applications\n      #\n      # This behaves like the default loader, except instead of requiring the given path,\n      # it loads the respective constant, allowing the autoloader to load the\n      # corresponding file per its own configuration.\n      #\n      # @see Loader\n      # @api public\n      class Autoloading < Loader\n        class << self\n          def require!(component)\n            constant(component)\n            self\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/loader.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/errors\"\n\nmodule Dry\n  module System\n    # Default component loader implementation\n    #\n    # This class is configured by default for every System::Container. You can\n    # provide your own and use it in your containers too.\n    #\n    # @example\n    #   class MyLoader < Dry::System::Loader\n    #     def call(*args)\n    #       constant.build(*args)\n    #     end\n    #   end\n    #\n    #   class MyApp < Dry::System::Container\n    #     configure do |config|\n    #       # ...\n    #       config.component_dirs.loader = MyLoader\n    #     end\n    #   end\n    #\n    # @api public\n    class Loader\n      class << self\n        # Requires the component's source file\n        #\n        # @api public\n        def require!(component)\n          require(component.require_path)\n          self\n        end\n\n        # Returns an instance of the component\n        #\n        # Provided optional args are passed to object's constructor\n        #\n        # @param [Array] args Optional constructor args\n        #\n        # @return [Object]\n        #\n        # @api public\n        def call(component, *args, **kwargs)\n          require!(component)\n\n          constant = self.constant(component)\n\n          if singleton?(constant)\n            constant.instance(*args, **kwargs)\n          else\n            constant.new(*args, **kwargs)\n          end\n        end\n\n        # Returns the component's class constant\n        #\n        # @return [Class]\n        #\n        # @api public\n        def constant(component)\n          inflector = component.inflector\n          const_name = inflector.camelize(component.const_path)\n          inflector.constantize(const_name)\n        rescue NameError => exception\n          # Ensure it's this component's constant, not any other NameError within the component\n          if exception.message =~ /#{const_name}( |\\n|$)/\n            raise ComponentNotLoadableError.new(component, exception)\n          else\n            raise exception\n          end\n        end\n\n        private\n\n        def singleton?(constant)\n          constant.respond_to?(:instance) && !constant.respond_to?(:new)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/magic_comments_parser.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    class MagicCommentsParser\n      VALID_LINE_RE = /^(#.*)?$/\n      COMMENT_RE = /^#\\s+(?<name>[A-Za-z]{1}[A-Za-z0-9_]+):\\s+(?<value>.+?)$/\n\n      COERCIONS = {\n        \"true\" => true,\n        \"false\" => false\n      }.freeze\n\n      def self.call(file_name)\n        {}.tap do |options|\n          File.foreach(file_name) do |line|\n            break unless line =~ VALID_LINE_RE\n\n            if (comment = line.match(COMMENT_RE))\n              options[comment[:name].to_sym] = coerce(comment[:value])\n            end\n          end\n        end\n      end\n\n      def self.coerce(value)\n        COERCIONS.fetch(value) { value }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/manifest_registrar.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Default manifest registration implementation\n    #\n    # This is configured by default for every System::Container. The manifest registrar is\n    # responsible for loading manifest files that contain code to manually register\n    # certain objects with the container.\n    #\n    # @api private\n    class ManifestRegistrar\n      # @api private\n      attr_reader :container\n\n      # @api private\n      attr_reader :config\n\n      # @api private\n      def initialize(container)\n        @container = container\n        @config = container.config\n      end\n\n      # @api private\n      def finalize!\n        ::Dir[registrations_dir.join(RB_GLOB)].each do |file|\n          call(Identifier.new(File.basename(file, RB_EXT)))\n        end\n      end\n\n      # @api private\n      def call(component)\n        load(root.join(config.registrations_dir, \"#{component.root_key}#{RB_EXT}\"))\n      end\n\n      # @api private\n      def file_exists?(component)\n        ::File.exist?(::File.join(registrations_dir, \"#{component.root_key}#{RB_EXT}\"))\n      end\n\n      private\n\n      # @api private\n      def registrations_dir\n        root.join(config.registrations_dir)\n      end\n\n      # @api private\n      def root\n        container.root\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/bootsnap.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      module Bootsnap\n        DEFAULT_OPTIONS = {\n          load_path_cache: true,\n          compile_cache_iseq: true,\n          compile_cache_yaml: true\n        }.freeze\n\n        # @api private\n        def self.extended(system)\n          super\n\n          system.use(:env)\n          system.setting :bootsnap, default: DEFAULT_OPTIONS\n          system.after(:configure, &:setup_bootsnap)\n        end\n\n        # @api private\n        def self.dependencies\n          {bootsnap: \"bootsnap\"}\n        end\n\n        # Set up bootsnap for faster booting\n        #\n        # @api public\n        def setup_bootsnap\n          return unless bootsnap_available?\n\n          ::Bootsnap.setup(**config.bootsnap, cache_dir: root.join(\"tmp/cache\").to_s)\n        end\n\n        # @api private\n        def bootsnap_available?\n          spec = Gem.loaded_specs[\"bootsnap\"] or return false\n\n          RUBY_ENGINE == \"ruby\" &&\n            spec.match_platform(RUBY_PLATFORM) &&\n            spec.required_ruby_version.satisfied_by?(Gem::Version.new(RUBY_VERSION))\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/dependency_graph/strategies.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      module DependencyGraph\n        # @api private\n        class Strategies\n          extend Core::Container::Mixin\n\n          # @api private\n          class Kwargs < Dry::AutoInject::Strategies::Kwargs\n            private\n\n            # @api private\n            def define_initialize(klass)\n              @container[\"notifications\"].instrument(\n                :resolved_dependency,\n                dependency_map: dependency_map.to_h,\n                target_class: klass\n              )\n\n              super\n            end\n          end\n\n          # @api private\n          class Args < Dry::AutoInject::Strategies::Args\n            private\n\n            # @api private\n            def define_initialize(klass)\n              @container[\"notifications\"].instrument(\n                :resolved_dependency,\n                dependency_map: dependency_map.to_h,\n                target_class: klass\n              )\n\n              super\n            end\n          end\n\n          class Hash < Dry::AutoInject::Strategies::Hash\n            private\n\n            # @api private\n            def define_initialize(klass)\n              @container[\"notifications\"].instrument(\n                :resolved_dependency,\n                dependency_map: dependency_map.to_h,\n                target_class: klass\n              )\n\n              super\n            end\n          end\n\n          register :kwargs, Kwargs\n          register :args, Args\n          register :hash, Hash\n          register :default, Kwargs\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/dependency_graph.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # @api public\n      module DependencyGraph\n        # @api private\n        def self.extended(system)\n          super\n\n          system.instance_eval do\n            use(:notifications)\n\n            setting :dependency_graph do\n              setting :ignored_dependencies, default: []\n            end\n\n            after(:configure) do\n              self[:notifications].register_event(:resolved_dependency)\n              self[:notifications].register_event(:registered_dependency)\n            end\n          end\n        end\n\n        # @api private\n        def self.dependencies\n          {\"dry-events\" => \"dry/events/publisher\"}\n        end\n\n        # @api private\n        def injector(**options)\n          super(**options, strategies: DependencyGraph::Strategies)\n        end\n\n        # @api private\n        def register(key, contents = nil, options = {}, &)\n          super.tap do\n            key = key.to_s\n\n            unless config.dependency_graph.ignored_dependencies.include?(key)\n              self[:notifications].instrument(\n                :registered_dependency,\n                key: key,\n                class: self[key].class\n              )\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/env.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # @api public\n      class Env < Module\n        DEFAULT_INFERRER = -> { :development }\n\n        attr_reader :options\n\n        # @api private\n        def initialize(**options)\n          @options = options\n          super()\n        end\n\n        def inferrer\n          options.fetch(:inferrer, DEFAULT_INFERRER)\n        end\n\n        # @api private\n        def extended(system)\n          system.setting :env, default: inferrer.(), reader: true\n          super\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/logging.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"logger\"\n\nmodule Dry\n  module System\n    module Plugins\n      module Logging\n        # @api private\n        def self.extended(system)\n          system.instance_eval do\n            setting :logger, reader: true\n\n            setting :log_dir, default: \"log\"\n\n            setting :log_levels, default: {\n              development: Logger::DEBUG,\n              test: Logger::DEBUG,\n              production: Logger::ERROR\n            }\n\n            setting :logger_class, default: ::Logger, reader: true\n          end\n\n          system.after(:configure, &:register_logger)\n\n          super\n        end\n\n        # Set a logger\n        #\n        # This is invoked automatically when a container is being configured\n        #\n        # @return [self]\n        #\n        # @api private\n        def register_logger\n          if registered?(:logger)\n            self\n          elsif config.logger\n            register(:logger, config.logger)\n          else\n            config.logger = config.logger_class.new(log_file_path)\n            config.logger.level = log_level\n\n            register(:logger, config.logger)\n            self\n          end\n        end\n\n        # @api private\n        def log_level\n          config.log_levels.fetch(config.env, Logger::ERROR)\n        end\n\n        # @api private\n        def log_dir_path\n          root.join(config.log_dir).realpath\n        end\n\n        # @api private\n        def log_file_path\n          log_dir_path.join(log_file_name)\n        end\n\n        # @api private\n        def log_file_name\n          \"#{config.env}.log\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/monitoring/proxy.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"delegate\"\n\nmodule Dry\n  module System\n    module Plugins\n      module Monitoring\n        # @api private\n        class Proxy < SimpleDelegator\n          # @api private\n          def self.for(target, key:, methods: [])\n            monitored_methods =\n              if methods.empty?\n                target.public_methods - Object.public_instance_methods\n              else\n                methods\n              end\n\n            Class.new(self) do\n              extend Dry::Core::ClassAttributes\n              include Dry::Events::Publisher[target.class.name]\n\n              defines :monitored_methods\n\n              attr_reader :__notifications__\n\n              monitored_methods(monitored_methods)\n\n              monitored_methods.each do |meth|\n                define_method(meth) do |*args, **kwargs, &block|\n                  object = __getobj__\n                  opts = {target: key, object: object, method: meth, args: args, kwargs: kwargs}\n\n                  __notifications__.instrument(:monitoring, opts) do\n                    object.public_send(meth, *args, **kwargs, &block)\n                  end\n                end\n              end\n            end\n          end\n\n          def initialize(target, notifications)\n            super(target)\n            @__notifications__ = notifications\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/monitoring.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    module Plugins\n      # @api public\n      module Monitoring\n        # @api private\n        def self.extended(system)\n          super\n\n          system.use(:notifications)\n\n          system.after(:configure) do\n            self[:notifications].register_event(:monitoring)\n          end\n        end\n\n        # @api private\n        def self.dependencies\n          {\"dry-events\": \"dry/events/publisher\"}\n        end\n\n        # @api private\n        def monitor(key, **options, &block)\n          notifications = self[:notifications]\n\n          resolve(key).tap do |target|\n            proxy = Proxy.for(target, **options, key: key)\n\n            if block_given?\n              proxy.monitored_methods.each do |meth|\n                notifications.subscribe(:monitoring, target: key, method: meth, &block)\n              end\n            end\n\n            decorate(key, with: -> tgt { proxy.new(tgt, notifications) })\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/notifications.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # @api public\n      module Notifications\n        # @api private\n        def self.extended(system)\n          system.after(:configure, &:register_notifications)\n        end\n\n        # @api private\n        def self.dependencies\n          {\"dry-monitor\": \"dry/monitor\"}\n        end\n\n        # @api private\n        def register_notifications\n          return self if registered?(:notifications)\n\n          register(:notifications, Monitor::Notifications.new(config.name))\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/plugin.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # @api private\n      class Plugin\n        attr_reader :name\n\n        attr_reader :mod\n\n        attr_reader :block\n\n        # @api private\n        def initialize(name, mod, &block)\n          @name = name\n          @mod = mod\n          @block = block\n        end\n\n        # @api private\n        def apply_to(system, **options)\n          system.extend(stateful? ? mod.new(**options) : mod)\n          system.instance_eval(&block) if block\n          system\n        end\n\n        # @api private\n        def load_dependencies(dependencies = mod_dependencies, gem = nil)\n          Array(dependencies).each do |dependency|\n            if dependency.is_a?(Array) || dependency.is_a?(Hash)\n              dependency.each { |value| load_dependencies(*Array(value).reverse) }\n            elsif !Plugins.loaded_dependencies.include?(dependency.to_s)\n              load_dependency(dependency, gem)\n            end\n          end\n        end\n\n        # @api private\n        def load_dependency(dependency, gem)\n          Kernel.require dependency\n          Plugins.loaded_dependencies << dependency.to_s\n        rescue LoadError => exception\n          raise PluginDependencyMissing.new(name, exception.message, gem)\n        end\n\n        # @api private\n        def stateful?\n          mod < Module\n        end\n\n        # @api private\n        def mod_dependencies\n          return EMPTY_ARRAY unless mod.respond_to?(:dependencies)\n\n          mod.dependencies.is_a?(Array) ? mod.dependencies : [mod.dependencies]\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/zeitwerk/compat_inflector.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      class Zeitwerk < Module\n        # @api private\n        class CompatInflector\n          attr_reader :config\n\n          def initialize(config)\n            @config = config\n          end\n\n          def camelize(string, _)\n            config.inflector.camelize(string)\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins/zeitwerk.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    module Plugins\n      # @api private\n      class Zeitwerk < Module\n        # @api private\n        def self.dependencies\n          [\n            \"dry/system/loader/autoloading\",\n            \"dry/system/plugins/zeitwerk/compat_inflector\",\n            {\"zeitwerk\" => \"zeitwerk\"}\n          ]\n        end\n\n        # @api private\n        attr_reader :loader, :run_setup, :eager_load, :debug\n\n        # @api private\n        def initialize(loader: nil, run_setup: true, eager_load: nil, debug: false)\n          @loader = loader || ::Zeitwerk::Loader.new\n          @run_setup = run_setup\n          @eager_load = eager_load\n          @debug = debug\n          super()\n        end\n\n        # @api private\n        def extended(system)\n          system.setting :autoloader, reader: true\n\n          system.config.autoloader = loader\n          system.config.component_dirs.loader = Dry::System::Loader::Autoloading\n          system.config.component_dirs.add_to_load_path = false\n\n          system.after(:configure, &method(:setup_autoloader))\n\n          super\n        end\n\n        private\n\n        def setup_autoloader(system)\n          configure_loader(system.autoloader, system)\n\n          push_component_dirs_to_loader(system, system.autoloader)\n\n          system.autoloader.setup if run_setup\n\n          system.after(:finalize) { system.autoloader.eager_load } if eager_load?(system)\n\n          system\n        end\n\n        # Build a zeitwerk loader with the configured component directories\n        #\n        # @return [Zeitwerk::Loader]\n        def configure_loader(loader, system)\n          loader.tag = system.config.name || system.name unless loader.tag\n          loader.inflector = CompatInflector.new(system.config)\n          loader.logger = method(:puts) if debug\n        end\n\n        # Add component dirs to the zeitwerk loader\n        #\n        # @return [Zeitwerk::Loader]\n        def push_component_dirs_to_loader(system, loader)\n          system.config.component_dirs.each do |dir|\n            dir.namespaces.each do |ns|\n              loader.push_dir(\n                system.root.join(dir.path, ns.path.to_s),\n                namespace: module_for_namespace(ns, system.config.inflector)\n              )\n            end\n          end\n\n          loader\n        end\n\n        def module_for_namespace(namespace, inflector)\n          return Object unless namespace.const\n\n          begin\n            inflector.constantize(inflector.camelize(namespace.const))\n          rescue NameError\n            namespace.const.split(PATH_SEPARATOR).reduce(Object) { |parent_mod, mod_path|\n              get_or_define_module(parent_mod, inflector.camelize(mod_path))\n            }\n          end\n        end\n\n        def get_or_define_module(parent_mod, name)\n          parent_mod.const_get(name)\n        rescue NameError\n          parent_mod.const_set(name, Module.new)\n        end\n\n        def eager_load?(system)\n          return eager_load unless eager_load.nil?\n\n          system.config.respond_to?(:env) && system.config.env == :production\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/plugins.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # Register a plugin\n      #\n      # @param [Symbol] name The name of a plugin\n      # @param [Class] plugin Plugin module\n      #\n      # @return [Plugins]\n      #\n      # @api public\n      def self.register(name, plugin, &)\n        registry[name] = Plugin.new(name, plugin, &)\n      end\n\n      # @api private\n      def self.registry\n        @registry ||= {}\n      end\n\n      # @api private\n      def self.loaded_dependencies\n        @loaded_dependencies ||= []\n      end\n\n      # Enables a plugin if not already enabled.\n      # Raises error if plugin cannot be found in the plugin registry.\n      #\n      # @param [Symbol] name The plugin name\n      # @param [Hash] options Plugin options\n      #\n      # @return [self]\n      #\n      # @api public\n      def use(name, **options)\n        return self if enabled_plugins.include?(name)\n\n        raise PluginNotFoundError, name unless (plugin = Dry::System::Plugins.registry[name])\n\n        plugin.load_dependencies\n        plugin.apply_to(self, **options)\n\n        enabled_plugins << name\n\n        self\n      end\n\n      # @api private\n      def inherited(klass)\n        klass.instance_variable_set(:@enabled_plugins, enabled_plugins.dup)\n        super\n      end\n\n      # @api private\n      def enabled_plugins\n        @enabled_plugins ||= []\n      end\n\n      register(:bootsnap, Plugins::Bootsnap)\n      register(:logging, Plugins::Logging)\n      register(:env, Plugins::Env)\n      register(:notifications, Plugins::Notifications)\n      register(:monitoring, Plugins::Monitoring)\n      register(:dependency_graph, Plugins::DependencyGraph)\n      register(:zeitwerk, Plugins::Zeitwerk)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/provider/source.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    class Provider\n      # A provider's source provides the specific behavior for a given provider to serve\n      # its purpose.\n      #\n      # Sources should be subclasses of `Dry::System::Source::Provider`, with instance\n      # methods for each lifecycle step providing their behavior: {#prepare}, {#start},\n      # and {#stop}.\n      #\n      # Inside each of these methods, you should create and configure your provider's\n      # objects as required, and then {#register} them with the {#provider_container}.\n      # When the provider's lifecycle steps are run (via {Dry::System::Provider}), these\n      # registered components will be merged into the target container.\n      #\n      # You can prepare a provider's source in two ways:\n      #\n      # 1. Passing a bock when registering the provider, which is then evaluated via\n      #    {Dry::System::Provider::SourceDSL} to prepare the provider subclass. This\n      #    approach is easiest for simple providers.\n      # 2. Manually creare your own subclass of {Dry::System::Provider} and implement your\n      #    own instance methods for the lifecycle steps (you should not implement your own\n      #    `#initialize`). This approach may be useful for more complex providers.\n      #\n      # @see Dry::System::Container.register_provider\n      # @see Dry::System.register_provider_source\n      # @see Dry::System::Source::ProviderDSL\n      #\n      # @api public\n      class Source\n        class << self\n          # Returns a new Dry::System::Provider::Source subclass with its behavior supplied by the\n          # given block, which is evaluated using Dry::System::Provider::SourceDSL.\n          #\n          # @see Dry::System::Provider::SourceDSL\n          #\n          # @api private\n          def for(name:, group: nil, superclass: nil, &block)\n            superclass ||= self\n\n            ::Class.new(superclass) { |klass|\n              klass.source_name name\n              klass.source_group group\n\n              name_with_group = group ? \"#{group}->#{name}\" : name\n              klass.instance_eval(<<~RUBY, __FILE__, __LINE__ + 1)\n                def name                                   # def name\n                  \"#{superclass.name}[#{name_with_group}]\" #   \"CustomSource[custom]\"\n                end                                        # end\n              RUBY\n\n              SourceDSL.evaluate(klass, &block) if block_given?\n            }\n          end\n\n          def inherited(subclass)\n            super\n\n            # Include Dry::Configurable only when first subclassing to ensure that\n            # distinct Source subclasses do not share settings.\n            #\n            # The superclass check here allows deeper Source class hierarchies to be\n            # created without running into a Dry::Configurable::AlreadyIncluded error.\n            if subclass.superclass == Source\n              subclass.include Dry::Configurable\n            end\n          end\n\n          # @api private\n          def to_s\n            \"#<#{name}>\"\n          end\n\n          # @api private\n          def inspect\n            to_s\n          end\n        end\n\n        CALLBACK_MAP = Hash.new { |h, k| h[k] = [] }.freeze\n\n        extend Dry::Core::ClassAttributes\n\n        defines :source_name, :source_group\n\n        # @api private\n        attr_reader :callbacks\n\n        # Returns the provider's own container for the provider.\n        #\n        # This container is namespaced based on the provider's `namespace:` configuration.\n        #\n        # Registered components in this container will be merged into the target container\n        # after the `prepare` and `start` lifecycle steps.\n        #\n        # @return [Dry::Container]\n        #\n        # @see #target_container\n        # @see Dry::System::Provider\n        #\n        # @api public\n        attr_reader :provider_container\n        alias_method :container, :provider_container\n\n        # Returns the target container for the provider.\n        #\n        # This is the container with which the provider is registered (via\n        # {Dry::System::Container.register_provider}).\n        #\n        # Registered components from the provider's container will be merged into this\n        # container after the `prepare` and `start` lifecycle steps.\n        #\n        # @return [Dry::System::Container]\n        #\n        # @see #provider_container\n        # @see Dry::System::Provider\n        #\n        # @api public\n        attr_reader :target_container\n\n        # @see #target_container\n        # @api public\n        def target = target_container\n\n        # @api private\n        def initialize(provider_container:, target_container:, &)\n          super()\n          @callbacks = {before: CALLBACK_MAP.dup, after: CALLBACK_MAP.dup}\n          @provider_container = provider_container\n          @target_container = target_container\n          instance_exec(&) if block_given?\n        end\n\n        # Returns a string containing a human-readable representation of the provider.\n        #\n        # @return [String]\n        #\n        # @api private\n        def inspect\n          ivars = instance_variables.map { |ivar|\n            \"#{ivar}=#{instance_variable_get(ivar).inspect}\"\n          }.join(\" \")\n\n          \"#<#{self.class.name} #{ivars}>\"\n        end\n\n        # Runs the behavior for the \"prepare\" lifecycle step.\n        #\n        # This should be implemented by your source subclass or specified by\n        # `SourceDSL#prepare` when registering a provider using a block.\n        #\n        # @return [void]\n        #\n        # @see SourceDSL#prepare\n        #\n        # @api public\n        def prepare; end\n\n        # Runs the behavior for the \"start\" lifecycle step.\n        #\n        # This should be implemented by your source subclass or specified by\n        # `SourceDSL#start` when registering a provider using a block.\n        #\n        # You can presume that {#prepare} has already run by the time this method is\n        # called.\n        #\n        # @return [void]\n        #\n        # @see SourceDSL#start\n        #\n        # @api public\n        def start; end\n\n        # Runs the behavior for the \"stop\" lifecycle step.\n        #\n        # This should be implemented by your source subclass or specified by\n        # `SourceDSL#stop` when registering a provider using a block.\n        #\n        # You can presume that {#prepare} and {#start} have already run by the time this\n        # method is called.\n        #\n        # @return [void]\n        #\n        # @see SourceDSL#stop\n        #\n        # @api public\n        def stop; end\n\n        # Registers a \"before\" callback for the given lifecycle step.\n        #\n        # The given block will be run before the lifecycle step method is run. The block\n        # will be evaluated in the context of the instance of this source.\n        #\n        # @param step_name [Symbol]\n        # @param block [Proc] the callback block\n        #\n        # @return [self]\n        #\n        # @see #after\n        #\n        # @api public\n        def before(step_name, &block)\n          callbacks[:before][step_name] << block\n          self\n        end\n\n        # Registers an \"after\" callback for the given lifecycle step.\n        #\n        # The given block will be run after the lifecycle step method is run. The block\n        # will be evaluated in the context of the instance of this source.\n        #\n        # @param step_name [Symbol]\n        # @param block [Proc] the callback block\n        #\n        # @return [self]\n        #\n        # @see #before\n        #\n        # @api public\n        def after(step_name, &block)\n          callbacks[:after][step_name] << block\n          self\n        end\n\n        # @api private\n        def run_callback(hook, step)\n          callbacks[hook][step].each do |callback|\n            instance_eval(&callback)\n          end\n        end\n\n        private\n\n        # Registers a component in the provider container.\n        #\n        # When the provider's lifecycle steps are run (via {Dry::System::Provider}), these\n        # registered components will be merged into the target container.\n        #\n        # @return [Dry::Container] the provider container\n        #\n        # @api public\n        def register(...)\n          provider_container.register(...)\n        end\n\n        # Resolves a previously registered component from the provider container.\n        #\n        # @param key [String] the key for the component to resolve\n        #\n        # @return [Object] the previously registered component\n        #\n        # @api public\n        def resolve(key)\n          provider_container.resolve(key)\n        end\n\n        # @api private\n        def run_step_block(step_name)\n          step_block = self.class.step_blocks[step_name]\n          instance_eval(&step_block) if step_block\n        end\n\n        # @api private\n        def method_missing(name, *args, &)\n          if container.key?(name)\n            container[name]\n          else\n            super\n          end\n        end\n\n        # @api private\n        def respond_to_missing?(name, include_all = false)\n          container.key?(name) || super\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/provider/source_dsl.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    class Provider\n      # Configures a Dry::System::Provider::Source subclass using a DSL that makes it\n      # nicer to define source behaviour via a single block.\n      #\n      # @see Dry::System::Container.register_provider\n      #\n      # @api private\n      class SourceDSL\n        def self.evaluate(source_class, &)\n          new(source_class).instance_eval(&)\n        end\n\n        attr_reader :source_class\n\n        def initialize(source_class)\n          @source_class = source_class\n        end\n\n        def setting(...)\n          source_class.setting(...)\n        end\n\n        def prepare(&)\n          source_class.define_method(:prepare, &)\n        end\n\n        def start(&)\n          source_class.define_method(:start, &)\n        end\n\n        def stop(&)\n          source_class.define_method(:stop, &)\n        end\n\n        private\n\n        def method_missing(name, ...)\n          if source_class.respond_to?(name)\n            source_class.public_send(name, ...)\n          else\n            super\n          end\n        end\n\n        def respond_to_missing?(name, include_all = false)\n          source_class.respond_to?(name, include_all) || super\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/provider.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Providers can prepare and register one or more objects and typically work with third\n    # party code. A typical provider might be for a database library, or an API client.\n    #\n    # The particular behavior for any provider is defined in a {Provider::Source}, which\n    # is a subclass created when you run {Container.register_provider} or\n    # {Dry::System.register_provider_source}. The Source provides this behavior through\n    # methods for each of the steps in the provider lifecycle: `prepare`, `start`, and\n    # `run`. These methods typically create and configure various objects, then register\n    # them with the {#provider_container}.\n    #\n    # The Provider manages this lifecycle by implementing common behavior around the\n    # lifecycle steps, such as running step callbacks, and only running steps when\n    # appropriate for the current status of the lifecycle.\n    #\n    # Providers can be registered via {Container.register_provider}.\n    #\n    # @example Simple provider\n    #   class App < Dry::System::Container\n    #     register_provider(:logger) do\n    #       prepare do\n    #         require \"logger\"\n    #       end\n    #\n    #       start do\n    #         register(:logger, Logger.new($stdout))\n    #       end\n    #     end\n    #   end\n    #\n    #   App[:logger] # returns configured logger\n    #\n    # @example Using an external Provider Source\n    #   class App < Dry::System::Container\n    #     register_provider(:logger, from: :some_external_provider_source) do\n    #       configure do |config|\n    #         config.log_level = :debug\n    #       end\n    #\n    #       after :start do\n    #         register(:my_extra_logger, resolve(:logger))\n    #       end\n    #     end\n    #   end\n    #\n    #   App[:my_extra_logger] # returns the extra logger registered in the callback\n    #\n    # @api public\n    class Provider\n      # Returns the provider's unique name.\n      #\n      # @return [Symbol]\n      #\n      # @api public\n      attr_reader :name\n\n      # Returns the default namespace for the provider's container keys.\n      #\n      # @return [Symbol,String]\n      #\n      # @api public\n      attr_reader :namespace\n\n      # Returns an array of lifecycle steps that have been run.\n      #\n      # @return [Array<Symbol>]\n      #\n      # @example\n      #   provider.statuses # => [:prepare, :start]\n      #\n      # @api public\n      attr_reader :statuses\n\n      # Returns the name of the currently running step, if any.\n      #\n      # @return [Symbol, nil]\n      #\n      # @api private\n      attr_reader :step_running\n      private :step_running\n\n      # Returns the container for the provider.\n      #\n      # This is where the provider's source will register its components, which are then\n      # later marged into the target container after the `prepare` and `start` lifecycle\n      # steps.\n      #\n      # @return [Dry::Core::Container]\n      #\n      # @api public\n      attr_reader :provider_container\n      alias_method :container, :provider_container\n\n      # Returns the target container for the provider.\n      #\n      # This is the container with which the provider is registered (via\n      # {Dry::System::Container.register_provider}).\n      #\n      # Registered components from the provider's container will be merged into this\n      # container after the `prepare` and `start` lifecycle steps.\n      #\n      # @return [Dry::System::Container]\n      #\n      # @api public\n      attr_reader :target_container\n      alias_method :target, :target_container\n\n      # Returns the provider's source\n      #\n      # The source provides the specific behavior for the provider via methods\n      # implementing the lifecycle steps.\n      #\n      # The provider's source is defined when registering a provider with the container,\n      # or an external provider source.\n      #\n      # @see Dry::System::Container.register_provider\n      # @see Dry::System.register_provider_source\n      #\n      # @return [Dry::System::Provider::Source]\n      #\n      # @api private\n      attr_reader :source\n\n      # @api private\n      # rubocop:disable Style/KeywordParametersOrder\n      def initialize(name:, namespace: nil, target_container:, source_class:, source_options: {}, &)\n        @name = name\n        @namespace = namespace\n        @target_container = target_container\n\n        @provider_container = build_provider_container\n        @statuses = []\n        @step_running = nil\n\n        @source = source_class.new(\n          **source_options,\n          provider_container: provider_container,\n          target_container: target_container,\n          &\n        )\n      end\n      # rubocop:enable Style/KeywordParametersOrder\n\n      # Runs the `prepare` lifecycle step.\n      #\n      # Also runs any callbacks for the step, and then merges any registered components\n      # from the provider container into the target container.\n      #\n      # @return [self]\n      #\n      # @api public\n      def prepare\n        run_step(:prepare)\n      end\n\n      # Runs the `start` lifecycle step.\n      #\n      # Also runs any callbacks for the step, and then merges any registered components\n      # from the provider container into the target container.\n      #\n      # @return [self]\n      #\n      # @api public\n      def start\n        run_step(:prepare)\n        run_step(:start)\n      end\n\n      # Runs the `stop` lifecycle step.\n      #\n      # Also runs any callbacks for the step.\n      #\n      # @return [self]\n      #\n      # @api public\n      def stop\n        return self unless started?\n\n        run_step(:stop)\n      end\n\n      # Returns true if the provider's `prepare` lifecycle step has run\n      #\n      # @api public\n      def prepared?\n        statuses.include?(:prepare)\n      end\n\n      # Returns true if the provider's `start` lifecycle step has run\n      #\n      # @api public\n      def started?\n        statuses.include?(:start)\n      end\n\n      # Returns true if the provider's `stop` lifecycle step has run\n      #\n      # @api public\n      def stopped?\n        statuses.include?(:stop)\n      end\n\n      private\n\n      # @api private\n      def build_provider_container\n        container = Core::Container.new\n\n        case namespace\n        when String, Symbol\n          container.namespace(namespace) { |c| return c }\n        when true\n          container.namespace(name) { |c| return c }\n        when nil\n          container\n        else\n          raise ArgumentError,\n                \"+namespace:+ must be true, string or symbol: #{namespace.inspect} given.\"\n        end\n      end\n\n      # @api private\n      def run_step(step_name)\n        return self if step_running? || statuses.include?(step_name)\n\n        @step_running = step_name\n\n        source.run_callback(:before, step_name)\n        source.public_send(step_name)\n        source.run_callback(:after, step_name)\n\n        statuses << step_name\n\n        apply\n\n        @step_running = nil\n\n        self\n      end\n\n      # Returns true if a step is currenly running.\n      #\n      # This is important for short-circuiting the invocation of {#run_step} and avoiding\n      # infinite loops if a provider step happens to result in resolution of a component\n      # with the same root key as the provider's own name (which ordinarily results in\n      # that provider being started).\n      #\n      # @return [Boolean]\n      #\n      # @see {#run_step}\n      #\n      # @api private\n      def step_running?\n        !!step_running\n      end\n\n      # Registers any components from the provider's container in the main container.\n      #\n      # Called after each lifecycle step runs.\n      #\n      # @return [self]\n      #\n      # @api private\n      def apply\n        provider_container.each_key do |key|\n          next if target_container.registered?(key)\n\n          # Access the provider's container items directly so that we can preserve all\n          # their options when we merge them with the target container (e.g. if a\n          # component in the provider container was registered with a block, we want block\n          # registration behavior to be exhibited when later resolving that component from\n          # the target container). TODO: Make this part of dry-system's public API.\n          item = provider_container._container[key]\n\n          if item.callable?\n            target_container.register(key, **item.options, &item.item)\n          else\n            target_container.register(key, item.item, **item.options)\n          end\n        end\n\n        self\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/provider_registrar.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"pathname\"\n\nrequire \"dry/system/errors\"\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Default provider registrar implementation\n    #\n    # This is currently configured by default for every Dry::System::Container. The\n    # provider registrar is responsible for loading provider files and exposing an API for\n    # running the provider lifecycle steps.\n    #\n    # @api public\n    # @since 1.1.0\n    class ProviderRegistrar\n      # @api private\n      attr_reader :providers\n\n      # @api private\n      attr_reader :container\n\n      # Returns the container exposed to providers as `target_container`.\n      #\n      # @return [Dry::System::Container]\n      #\n      # @api public\n      # @since 1.1.0\n      alias_method :target_container, :container\n\n      # @api private\n      def initialize(container)\n        @providers = {}\n        @container = container\n      end\n\n      # @api private\n      def freeze\n        providers.freeze\n        super\n      end\n\n      # rubocop:disable Metrics/PerceivedComplexity\n\n      # @see Container.register_provider\n      # @api private\n      def register_provider(name, from: nil, source: nil, if: true, **provider_options, &)\n        raise ProviderAlreadyRegisteredError, name if providers.key?(name)\n\n        if from && source.is_a?(Class)\n          raise ArgumentError, \"You must supply a block when using a provider source\"\n        end\n\n        if block_given? && source.is_a?(Class)\n          raise ArgumentError, \"You must supply only a `source:` option or a block, not both\"\n        end\n\n        return self unless binding.local_variable_get(:if)\n\n        provider =\n          if from\n            build_provider_from_source(\n              name,\n              source: source || name,\n              group: from,\n              options: provider_options,\n              &\n            )\n          else\n            build_provider(\n              name,\n              source: source,\n              options: provider_options,\n              &\n            )\n          end\n\n        providers[provider.name] = provider\n\n        self\n      end\n\n      # rubocop:enable Metrics/PerceivedComplexity\n\n      # Returns a provider if it can be found or loaded, otherwise nil\n      #\n      # @return [Dry::System::Provider, nil]\n      #\n      # @api public\n      def [](provider_name)\n        provider_name = provider_name.to_sym\n\n        if (provider = providers[provider_name])\n          return provider\n        end\n\n        return if finalized?\n\n        require_provider_file(provider_name)\n\n        providers[provider_name]\n      end\n\n      # @api public\n      alias_method :find_and_load_provider, :[]\n\n      # @api private\n      def key?(provider_name)\n        providers.key?(provider_name)\n      end\n\n      # Returns all provider files within the configured provider_paths.\n      #\n      # Searches for files in the order of the configured provider_paths. In the case of multiple\n      # identically-named boot files within different provider_paths, the file found first will be\n      # returned, and other matching files will be discarded.\n      #\n      # This method is public to allow other tools extending dry-system (like dry-rails)\n      # to access a canonical list of real, in-use provider files.\n      #\n      # @see Container.provider_paths\n      #\n      # @return [Array<Pathname>]\n      # @api public\n      def provider_files\n        @provider_files ||= provider_paths.each_with_object([[], []]) { |path, (provider_files, loaded)|\n          files = ::Dir[\"#{path}/#{RB_GLOB}\"]\n\n          files.each do |file|\n            basename = ::File.basename(file)\n\n            unless loaded.include?(basename)\n              provider_files << Pathname(file)\n              loaded << basename\n            end\n          end\n        }.first\n      end\n\n      # Extension point for subclasses to customize their\n      # provider source superclass. Expected to be a subclass\n      # of Dry::System::Provider::Source\n      #\n      # @api public\n      # @since 1.1.0\n      def provider_source_class = Dry::System::Provider::Source\n\n      # Extension point for subclasses to customize initialization\n      # params for provider_source_class\n      #\n      # @api public\n      # @since 1.1.0\n      def provider_source_options = {}\n\n      # @api private\n      def finalize!\n        provider_files.each do |path|\n          load_provider(path)\n        end\n\n        providers.each_value(&:start)\n\n        freeze\n      end\n\n      # @!method finalized?\n      #   Returns true if the booter has been finalized\n      #\n      #   @return [Boolean]\n      #   @api private\n      alias_method :finalized?, :frozen?\n\n      # @api private\n      def shutdown\n        providers.each_value(&:stop)\n        self\n      end\n\n      # @api private\n      def prepare(provider_name)\n        with_provider(provider_name, &:prepare)\n        self\n      end\n\n      # @api private\n      def start(provider_name)\n        with_provider(provider_name, &:start)\n        self\n      end\n\n      # @api private\n      def stop(provider_name)\n        with_provider(provider_name, &:stop)\n        self\n      end\n\n      private\n\n      # @api private\n      def provider_paths\n        provider_dirs = container.config.provider_dirs\n\n        provider_dirs.map { |dir|\n          dir = Pathname(dir)\n\n          if dir.relative?\n            container.root.join(dir)\n          else\n            dir\n          end\n        }\n      end\n\n      def build_provider(name, options:, source: nil, &)\n        source_class = source || Provider::Source.for(\n          name: name,\n          superclass: provider_source_class,\n          &\n        )\n\n        source_options =\n          if source_class < provider_source_class\n            provider_source_options\n          else\n            {}\n          end\n\n        Provider.new(\n          **options,\n          name: name,\n          target_container: target_container,\n          source_class: source_class,\n          source_options: source_options\n        )\n      end\n\n      def build_provider_from_source(name, source:, group:, options:, &)\n        provider_source = System.provider_sources.resolve(name: source, group: group)\n\n        source_options =\n          if provider_source.source <= provider_source_class\n            provider_source_options\n          else\n            {}\n          end\n\n        Provider.new(\n          **provider_source.provider_options,\n          **options,\n          name: name,\n          target_container: target_container,\n          source_class: provider_source.source,\n          source_options: source_options,\n          &\n        )\n      end\n\n      def with_provider(provider_name)\n        require_provider_file(provider_name) unless providers.key?(provider_name)\n\n        provider = providers[provider_name]\n\n        raise ProviderNotFoundError, provider_name unless provider\n\n        yield(provider)\n      end\n\n      def load_provider(path)\n        name = Pathname(path).basename(RB_EXT).to_s.to_sym\n\n        Kernel.require path unless providers.key?(name)\n\n        self\n      end\n\n      def require_provider_file(name)\n        provider_file = find_provider_file(name)\n\n        Kernel.require provider_file if provider_file\n      end\n\n      def find_provider_file(name)\n        provider_files.detect { |file| File.basename(file, RB_EXT) == name.to_s }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/provider_source_registry.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # @api private\n    class ProviderSourceRegistry\n      # @api private\n      class Registration\n        attr_reader :source\n        attr_reader :provider_options\n\n        def initialize(source:, provider_options:)\n          @source = source\n          @provider_options = provider_options\n        end\n      end\n\n      attr_reader :sources\n\n      def initialize\n        @sources = {}\n      end\n\n      def load_sources(path)\n        ::Dir[::File.join(path, \"**/#{RB_GLOB}\")].each do |file|\n          require file\n        end\n      end\n\n      def register(name:, group:, source:, provider_options:)\n        sources[key(name, group)] = Registration.new(\n          source: source,\n          provider_options: provider_options\n        )\n      end\n\n      def register_from_block(name:, group:, provider_options:, &)\n        register(\n          name: name,\n          group: group,\n          source: Provider::Source.for(name: name, group: group, &),\n          provider_options: provider_options\n        )\n      end\n\n      def resolve(name:, group:)\n        sources[key(name, group)].tap { |source|\n          unless source\n            raise ProviderSourceNotFoundError.new(\n              name: name,\n              group: group,\n              keys: sources.keys\n            )\n          end\n        }\n      end\n\n      private\n\n      def key(name, group)\n        {group: group, name: name}\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/provider_sources/settings/config.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module ProviderSources\n      # @api private\n      module Settings\n        InvalidSettingsError = Class.new(ArgumentError) do\n          # @api private\n          def initialize(errors)\n            message = <<~STR\n              Could not load settings. The following settings were invalid:\n\n              #{setting_errors(errors).join(\"\\n\")}\n            STR\n\n            super(message)\n          end\n\n          private\n\n          def setting_errors(errors)\n            errors.sort_by { |k, _| k }.map { |key, error| \"#{key}: #{error}\" }\n          end\n        end\n\n        # @api private\n        class Config\n          # @api private\n          def self.load(root:, env:, loader: Loader)\n            loader = loader.new(root: root, env: env)\n\n            new.tap do |settings_obj|\n              errors = {}\n\n              settings.to_a.each do |setting|\n                value = loader[setting.name.to_s.upcase]\n\n                begin\n                  if value\n                    settings_obj.config.public_send(:\"#{setting.name}=\", value)\n                  else\n                    settings_obj.config[setting.name]\n                  end\n                rescue => exception # rubocop:disable Style/RescueStandardError\n                  errors[setting.name] = exception\n                end\n              end\n\n              raise InvalidSettingsError, errors unless errors.empty?\n            end\n          end\n\n          include Dry::Configurable\n\n          private\n\n          def method_missing(name, ...)\n            if config.respond_to?(name)\n              config.public_send(name, ...)\n            else\n              super\n            end\n          end\n\n          def respond_to_missing?(name, include_all = false)\n            config.respond_to?(name, include_all) || super\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/provider_sources/settings/loader.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module ProviderSources\n      module Settings\n        # @api private\n        class Loader\n          # @api private\n          attr_reader :store\n\n          # @api private\n          def initialize(root:, env:, store: ENV)\n            @store = store\n            load_dotenv(root, env.to_sym)\n          end\n\n          # @api private\n          def [](key)\n            store[key]\n          end\n\n          private\n\n          def load_dotenv(root, env)\n            require \"dotenv\"\n            Dotenv.load(*dotenv_files(root, env)) if defined?(Dotenv)\n          rescue LoadError\n            # Do nothing if dotenv is unavailable\n          end\n\n          def dotenv_files(root, env)\n            [\n              File.join(root, \".env.#{env}.local\"),\n              (File.join(root, \".env.local\") unless env == :test),\n              File.join(root, \".env.#{env}\"),\n              File.join(root, \".env\")\n            ].compact\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/provider_sources/settings.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module ProviderSources\n      module Settings\n        class Source < Dry::System::Provider::Source\n          setting :store\n\n          def prepare\n            require \"dry/system/provider_sources/settings/config\"\n          end\n\n          def start\n            register(:settings, settings.load(root: target.root, env: target.config.env))\n          end\n\n          def settings(&block)\n            # Save the block and evaluate it lazily to allow a provider with this source\n            # to `require` any necessary files for the block to evaluate correctly (e.g.\n            # requiring an app-specific types module for setting constructors)\n            if block\n              @settings_block = block\n            elsif defined? @settings_class\n              @settings_class\n            elsif @settings_block\n              @settings_class = Class.new(Settings::Config, &@settings_block)\n            end\n          end\n        end\n      end\n    end\n  end\nend\n\nDry::System.register_provider_source(\n  :settings,\n  group: :dry_system,\n  source: Dry::System::ProviderSources::Settings::Source\n)\n"
  },
  {
    "path": "lib/dry/system/provider_sources.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"pathname\"\nrequire \"dry/system\"\n\nDry::System.register_provider_sources Pathname(__dir__).join(\"provider_sources\").realpath\n"
  },
  {
    "path": "lib/dry/system/stubs.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/core/container/stub\"\n\nmodule Dry\n  module System\n    class Container\n      # @api private\n      module Stubs\n        # This overrides default finalize! just to disable automatic freezing\n        # of the container\n        #\n        # @api private\n        def finalize!(**, &)\n          super(freeze: false, &)\n        end\n      end\n\n      # Enables stubbing container's components\n      #\n      # @example\n      #   require 'dry/system/stubs'\n      #\n      #   MyContainer.enable_stubs!\n      #   MyContainer.finalize!\n      #\n      #   MyContainer.stub('some.component', some_stub_object)\n      #\n      # @return Container\n      #\n      # @api public\n      def self.enable_stubs!\n        super\n        extend ::Dry::System::Container::Stubs\n        self\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/dry/system/version.rb",
    "content": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    VERSION = \"1.2.5\"\n  end\nend\n"
  },
  {
    "path": "lib/dry/system.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"zeitwerk\"\nrequire \"dry/core\"\n\nmodule Dry\n  module System\n    # @api private\n    def self.loader\n      @loader ||= Zeitwerk::Loader.new.tap do |loader|\n        root = File.expand_path(\"..\", __dir__)\n        loader.tag = \"dry-system\"\n        loader.inflector = Zeitwerk::GemInflector.new(\"#{root}/dry-system.rb\")\n        loader.push_dir(root)\n        loader.ignore(\n          \"#{root}/dry-system.rb\",\n          \"#{root}/dry/system/{components,constants,errors,stubs,version}.rb\"\n        )\n        loader.inflector.inflect(\"source_dsl\" => \"SourceDSL\")\n      end\n    end\n\n    # Registers the provider sources in the files under the given path\n    #\n    # @api public\n    def self.register_provider_sources(path)\n      provider_sources.load_sources(path)\n    end\n\n    # Registers a provider source, which can be used as the basis for other providers\n    #\n    # @api public\n    def self.register_provider_source(name, group:, source: nil, provider_options: {}, &)\n      if source && block_given?\n        raise ArgumentError, \"You must supply only a `source:` option or a block, not both\"\n      end\n\n      if source\n        provider_sources.register(\n          name: name,\n          group: group,\n          source: source,\n          provider_options: provider_options\n        )\n      else\n        provider_sources.register_from_block(\n          name: name,\n          group: group,\n          provider_options: provider_options,\n          &\n        )\n      end\n    end\n\n    # @api private\n    def self.provider_sources\n      @provider_sources ||= ProviderSourceRegistry.new\n    end\n\n    loader.setup\n  end\nend\n"
  },
  {
    "path": "lib/dry-system.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n"
  },
  {
    "path": "repo-sync.yml",
    "content": "name:\n  gem: dry-system\n  constant: Dry::System\ngithub_org: dry-rb\nci:\n  rubies: [\"3.3.0\"]\ngemspec:\n  authors: [\"Hanakai team\"]\n  email: [\"info@hanakai.org\"]\n  summary: \"Organize your code into reusable components\"\n  homepage: \"https://dry-rb.org/gems/dry-system\"\n  required_ruby_version: \">= 3.1.0\"\n  development_dependencies:\n    - bundler\n    - rake\n    - rspec\n  runtime_dependencies:\n    - [dry-auto_inject, \"~> 1.1\"]\n    - [dry-configurable, \"~> 1.3\"]\n    - [dry-core, \"~> 1.1\"]\n    - [dry-inflector, \"~> 1.1\"]\n"
  },
  {
    "path": "spec/fixtures/app/lib/ignored_spec_service.rb",
    "content": "# frozen_string_literal: true\n\nclass IgnoredSpecService\nend\n"
  },
  {
    "path": "spec/fixtures/app/lib/spec_service.rb",
    "content": "# frozen_string_literal: true\n\nclass SpecService\nend\n"
  },
  {
    "path": "spec/fixtures/app/system/providers/client.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:client) do\n  module Test\n    class Client\n    end\n  end\n\n  start do\n    register(:client, Test::Client.new)\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/autoloading/lib/test/entities/foo_entity.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Entities\n    class FooEntity\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/autoloading/lib/test/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n    def call\n      Entities::FooEntity.new\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/components/test/bar/abc.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Bar\n    class ABC\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/components/test/bar/baz.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Bar\n    class Baz\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/components/test/bar.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Bar\n    def self.call\n      \"Welcome to my Moe's Tavern!\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/components/test/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/components/test/no_register.rb",
    "content": "# auto_register: false\n# frozen_string_literal: true\n\nmodule Test\n  class NoRegister\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/components_with_errors/test/constant_error.rb",
    "content": "# frozen_string_literal: true\n\nclass ConstantError\n  const_get(:NotHere)\nend\n"
  },
  {
    "path": "spec/fixtures/deprecations/bootable_dirs_config/system/boot/logger.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider :logger do\n  start do\n    register \"logger\", \"my logger\"\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/deprecations/bootable_dirs_config/system/custom_boot/logger.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider :logger do\n  start do\n    register \"logger\", \"my logger\"\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/external_components/alt-components/db.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:db, group: :alt) do\n  prepare do\n    module AltComponents\n      class DbConn\n      end\n    end\n  end\n\n  start do\n    register(:db_conn, AltComponents::DbConn.new)\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/external_components/alt-components/logger.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:logger, group: :alt) do\n  prepare do\n    module AltComponents\n      class Logger\n      end\n    end\n  end\n\n  start do\n    register(:logger, AltComponents::Logger.new)\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/external_components/components/logger.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:logger, group: :external_components) do\n  setting :log_level, default: :scream, constructor: Types::Symbol\n\n  prepare do\n    unless defined?(ExternalComponents)\n      module ExternalComponents\n        class Logger\n          class << self\n            attr_accessor :default_level\n          end\n\n          self.default_level = :scream\n\n          attr_reader :log_level\n\n          def initialize(log_level = Logger.default_level)\n            @log_level = log_level\n          end\n        end\n      end\n    end\n  end\n\n  start do\n    logger =\n      if config.log_level\n        ExternalComponents::Logger.new(config.log_level)\n      else\n        ExternalComponents::Logger.new\n      end\n\n    register(:logger, logger)\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/external_components/components/mailer.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:mailer, group: :external_components) do\n  prepare do\n    module ExternalComponents\n      class Mailer\n        attr_reader :client\n\n        def initialize(client)\n          @client = client\n        end\n      end\n    end\n  end\n\n  start do\n    target.start :client\n\n    register(:mailer, ExternalComponents::Mailer.new(target_container[\"client\"]))\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/external_components/components/notifier.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:notifier, group: :external_components) do\n  prepare do\n    module ExternalComponents\n      class Notifier\n        attr_reader :monitor\n\n        def initialize(monitor)\n          @monitor = monitor\n        end\n      end\n    end\n  end\n\n  start do\n    register(:notifier, ExternalComponents::Notifier.new(target_container[\"monitor\"]))\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/external_components/lib/external_components.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_sources Pathname(__dir__).join(\"../components\").realpath\nDry::System.register_provider_sources Pathname(__dir__).join(\"../alt-components\").realpath\n"
  },
  {
    "path": "spec/fixtures/external_components_deprecated/components/logger.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_component(:logger, provider: :external_components) do\n  setting :log_level, default: :scream, constructor: Types::Symbol\n\n  prepare do\n    unless defined?(ExternalComponents)\n      module ExternalComponents\n        class Logger\n          class << self\n            attr_accessor :default_level\n          end\n\n          self.default_level = :scream\n\n          attr_reader :log_level\n\n          def initialize(log_level = Logger.default_level)\n            @log_level = log_level\n          end\n        end\n      end\n    end\n  end\n\n  start do\n    logger =\n      if config\n        ExternalComponents::Logger.new(config.log_level)\n      else\n        ExternalComponents::Logger.new\n      end\n\n    register(:logger, logger)\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/external_components_deprecated/lib/external_components.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider(\n  :external_components,\n  path: Pathname(__dir__).join(\"../components\").realpath\n)\n"
  },
  {
    "path": "spec/fixtures/import_test/config/application.yml",
    "content": "test:\n  foo: 'bar'\n"
  },
  {
    "path": "spec/fixtures/import_test/lib/test/bar.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Bar\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/import_test/lib/test/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n    include Import[\"test.bar\"]\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazy_loading/auto_registration_disabled/lib/entities/kitten.rb",
    "content": "# auto_register: false\n# frozen_string_literal: true\n\nmodule Entities\n  class Kitten\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazy_loading/auto_registration_disabled/lib/fetch_kitten.rb",
    "content": "# frozen_string_literal: true\n\nclass FetchKitten\nend\n"
  },
  {
    "path": "spec/fixtures/lazy_loading/shared_root_keys/lib/kitten_service/fetch_kitten.rb",
    "content": "# frozen_string_literal: true\n\nmodule KittenService\n  class FetchKitten\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazy_loading/shared_root_keys/lib/kitten_service/submit_kitten.rb",
    "content": "# frozen_string_literal: true\n\nmodule KittenService\n  class SubmitKitten\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazy_loading/shared_root_keys/system/providers/kitten_service.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:kitten_service, namespace: true) do\n  prepare do\n    module KittenService\n      class Client\n      end\n    end\n  end\n\n  start do\n    register \"client\", KittenService::Client.new\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazytest/config/application.yml",
    "content": "test:\n  foo: 'bar'\n"
  },
  {
    "path": "spec/fixtures/lazytest/lib/test/dep.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Dep\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazytest/lib/test/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n    include Import[\"test.dep\"]\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazytest/lib/test/models/book.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n    class Book\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazytest/lib/test/models/user.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n    class User\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazytest/lib/test/models.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazytest/system/providers/bar.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.namespace(:test) do |container|\n  container.register_provider(:bar) do\n    prepare do\n      module Test\n        module Bar\n          # I shall be booted\n        end\n      end\n    end\n\n    start do\n      container.register(:bar, \"I was finalized\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/magic_comments/comments.rb",
    "content": "#!/usr/bin/env ruby\n# rubocop:disable Layout/CommentIndentation\n# frozen_string_literal: true\n\n# This is a file with a mix of valid and invalid magic comments\n\n# valid_comment: hello\n# true_comment: true\n# false_comment: false\n# comment_123: alpha-numeric and underscores allowed\n# 123_will_not_match: will not match\n# not-using-underscores: value for comment using dashes\n\n  # not_at_start_of_line: will not match\n\nmodule Test\nend\n\n# after_code: will not match\n# rubocop:enable Layout/CommentIndentation\n"
  },
  {
    "path": "spec/fixtures/manifest_registration/lib/test/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n    attr_reader :name\n\n    def initialize(name)\n      @name = name\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/manifest_registration/system/registrations/foo.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.namespace(:foo) do |container|\n  container.register(\"special\") do\n    require \"test/foo\"\n    Test::Foo.new(\"special\")\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/memoize_magic_comments/test/memoize_false_comment.rb",
    "content": "# memoize: false\n# frozen_string_literal: true\n\nmodule Test\n  class MemoizeFalseComment\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/memoize_magic_comments/test/memoize_no_comment.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class MemoizeNoComment\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/memoize_magic_comments/test/memoize_true_comment.rb",
    "content": "# memoize: true\n# frozen_string_literal: true\n\nmodule Test\n  class MemoizeTrueComment\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/mixed_namespaces/lib/test/external/external_component.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module External\n    class ExternalComponent\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/mixed_namespaces/lib/test/my_app/app_component.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module MyApp\n    class AppComponent\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/multiple_namespaced_components/multiple/level/baz.rb",
    "content": "# frozen_string_literal: true\n\nmodule Multiple\n  module Level\n    class Baz\n      include Test::Container.injector[\"foz\"]\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/multiple_namespaced_components/multiple/level/foz.rb",
    "content": "# frozen_string_literal: true\n\nmodule Multiple\n  module Level\n    class Foz\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/multiple_provider_dirs/custom_bootables/logger.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:logger) do\n  start do\n    register(:logger, \"custom_logger\")\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/multiple_provider_dirs/default_bootables/inflector.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:inflector) do\n  start do\n    register(:inflector, \"default_inflector\")\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/multiple_provider_dirs/default_bootables/logger.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:logger) do\n  start do\n    register(:logger, \"default_logger\")\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/namespaced_components/namespaced/bar.rb",
    "content": "# frozen_string_literal: true\n\nmodule Namespaced\n  class Bar\n    include Test::Container.injector[\"foo\"]\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/namespaced_components/namespaced/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Namespaced\n  class Foo\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/config/providers/bar.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:bar, namespace: \"test\") do |_container|\n  prepare do\n    module Test\n      module Bar\n        # I shall be booted\n      end\n    end\n  end\n\n  start do\n    register(:bar, \"I was finalized\")\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/config/providers/hell.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:heaven) do\n  start do\n    register(\"heaven\", \"string\")\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/lib/test/dep.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Dep\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/lib/test/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n    include Import[\"test.dep\"]\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/lib/test/models/book.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n    class Book\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/lib/test/models/user.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n    class User\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/lib/test/models.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/require_path/lib/test/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/settings_test/types.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/types\"\n\nmodule SettingsTest\n  module Types\n    include Dry::Types()\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/standard_container_with_default_namespace/lib/test/dep.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Dep\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/standard_container_with_default_namespace/lib/test/example_with_dep.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class ExampleWithDep\n    include Import[\"dep\"]\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/standard_container_without_default_namespace/lib/test/dep.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Dep\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/standard_container_without_default_namespace/lib/test/example_with_dep.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class ExampleWithDep\n    include Import[\"test.dep\"]\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/stubbing/lib/test/car.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Car\n    def wheels_count\n      4\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/stubbing/system/providers/db.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:db) do\n  module Test\n    class DB\n    end\n  end\n\n  start do\n    register(:db, Test::DB.new)\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/config/application.yml",
    "content": "test:\n  foo: 'bar'\n"
  },
  {
    "path": "spec/fixtures/test/config/subapp.yml",
    "content": "test:\n  bar: 'baz'\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/dep.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Dep\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/foo.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n    include Import[\"test.dep\"]\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/models/book.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n    class Book\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/models/user.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n    class User\n    end\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/models.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/singleton_dep.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"singleton\"\n\nmodule Test\n  class SingletonDep\n    include Singleton\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/log/.gitkeep",
    "content": ""
  },
  {
    "path": "spec/fixtures/test/system/providers/bar.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:bar, namespace: \"test\") do\n  prepare do\n    module Test\n      module Bar\n        # I shall be booted\n      end\n    end\n  end\n\n  start do\n    register(:bar, \"I was finalized\")\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/system/providers/client.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:client) do\n  start do\n    target.start :logger\n\n    Test::Client = Struct.new(:logger)\n\n    register(:client, Test::Client.new(target_container[\"logger\"]))\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/system/providers/db.rb",
    "content": "# frozen_string_literal: true\n\n# this is just for Container.finalize spec, actual finalization code is in the test\n"
  },
  {
    "path": "spec/fixtures/test/system/providers/hell.rb",
    "content": "# frozen_string_literal: true\n\nTest::Container.register_provider(:heaven) do\n  start do\n    register(\"heaven\", \"string\")\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/system/providers/logger.rb",
    "content": "# frozen_string_literal: true\n\nmodule Test\n  class LoggerProvider < Dry::System::Provider::Source\n    def prepare\n      require \"logger\"\n    end\n\n    def start\n      register(:logger, Logger.new(target_container.root.join(\"log/test.log\")))\n    end\n  end\nend\n\nTest::Container.register_provider(:logger, source: Test::LoggerProvider)\n"
  },
  {
    "path": "spec/fixtures/umbrella/system/providers/db.rb",
    "content": "# frozen_string_literal: true\n\nTest::Umbrella.register_provider(:db, namespace: \"db\") do\n  prepare do\n    module Db\n      class Repo\n      end\n    end\n  end\n\n  start do\n    register(:repo, Db::Repo.new)\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/unit/component/component_dir_1/namespace/nested/component_file.rb",
    "content": "# frozen_string_literal: true\n"
  },
  {
    "path": "spec/fixtures/unit/component/component_dir_1/namespace/nested/component_file_with_auto_register_false.rb",
    "content": "# auto_register: false\n# frozen_string_literal: true\n"
  },
  {
    "path": "spec/fixtures/unit/component/component_dir_1/outside_namespace/component_file.rb",
    "content": "# frozen_string_literal: true\n"
  },
  {
    "path": "spec/fixtures/unit/component/component_dir_2/namespace/nested/component_file.rb",
    "content": ""
  },
  {
    "path": "spec/fixtures/unit/component_dir/component_file.rb",
    "content": ""
  },
  {
    "path": "spec/integration/boot_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"ostruct\"\n\nRSpec.describe Dry::System::Container, \".register_provider\" do\n  subject(:system) { Test::Container }\n  let(:setup_db) do\n    system.register_provider(:db) do\n      prepare do\n        module Test\n          class Db < OpenStruct\n          end\n        end\n      end\n\n      start do\n        register(\"db.conn\", Test::Db.new(established: true))\n      end\n\n      stop do\n        container[\"db.conn\"].established = false\n      end\n    end\n  end\n\n  let(:setup_client) do\n    system.register_provider(:client) do\n      prepare do\n        module Test\n          class Client < OpenStruct\n          end\n        end\n      end\n\n      start do\n        register(\"client.conn\", Test::Client.new(connected: true))\n      end\n\n      stop do\n        container[\"client.conn\"].connected = false\n      end\n    end\n  end\n\n  context \"with a boot file\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/test\").realpath\n        end\n      end\n    end\n\n    it \"auto-boots dependency of a bootable component\" do\n      system.start(:client)\n\n      expect(system[:client]).to be_a(Test::Client)\n      expect(system[:client].logger).to be_a(Logger)\n    end\n  end\n\n  context \"using predefined settings for configuration\" do\n    before do\n      class Test::Container < Dry::System::Container\n      end\n    end\n\n    it \"uses defaults\" do\n      system.register_provider(:api) do\n        setting :token, default: \"xxx\"\n\n        start do\n          register(:client, OpenStruct.new(config.to_h))\n        end\n      end\n\n      system.start(:api)\n\n      client = system[:client]\n\n      expect(client.token).to eql(\"xxx\")\n    end\n  end\n\n  context \"inline booting\" do\n    before do\n      class Test::Container < Dry::System::Container\n      end\n    end\n\n    it \"allows lazy-booting\" do\n      system.register_provider(:db) do\n        prepare do\n          module Test\n            class Db < OpenStruct\n            end\n          end\n        end\n\n        start do\n          register(\"db.conn\", Test::Db.new(established?: true))\n        end\n\n        stop do\n          db.conn.established = false\n        end\n      end\n      conn = system[\"db.conn\"]\n\n      expect(conn).to be_established\n    end\n\n    it \"allows component to be stopped\" do\n      setup_db\n      system.start(:db)\n\n      conn = system[\"db.conn\"]\n      system.stop(:db)\n\n      expect(conn.established).to eq false\n    end\n\n    xit \"raises an error when trying to stop a component that has not been started\" do\n      setup_db\n\n      expect {\n        system.stop(:db)\n      }.to raise_error(Dry::System::ProviderNotStartedError)\n    end\n\n    describe \"#shutdown!\" do\n      it \"allows container to stop all started components\" do\n        setup_db\n        setup_client\n\n        db = system[\"db.conn\"]\n        client = system[\"client.conn\"]\n        system.shutdown!\n\n        expect(db.established).to eq false\n        expect(client.connected).to eq false\n      end\n\n      it \"skips components that has not been started\" do\n        setup_db\n        setup_client\n\n        db = system[\"db.conn\"]\n        system.shutdown!\n\n        expect {\n          system.shutdown!\n        }.to_not raise_error\n\n        expect(db.established).to eq false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/autoloading_loader_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/loader/autoloading\"\nrequire \"zeitwerk\"\n\nRSpec.describe \"Component dir namespaces / Autoloading loader\" do\n  let(:container) {\n    root = @dir\n    dir_config = defined?(component_dir_config) ? component_dir_config : -> * {}\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n        config.component_dirs.add \"lib\" do |dir|\n          dir.loader = Dry::System::Loader::Autoloading\n          dir_config.(dir)\n        end\n      end\n    }\n  }\n\n  let(:loader) { Zeitwerk::Loader.new }\n\n  before do\n    allow(Zeitwerk::Loader).to receive(:new).and_return(ZeitwerkLoaderRegistry.new_loader)\n  end\n\n  after { ZeitwerkLoaderRegistry.clear }\n\n  context \"top-level constant namespace\" do\n    let(:component_dir_config) {\n      -> dir {\n        dir.namespaces.add \"ns\", const: nil\n      }\n    }\n\n    before :context do\n      @dir = make_tmp_directory\n\n      with_directory(@dir) do\n        write \"lib/ns/component.rb\", <<~RUBY\n          class Component\n          end\n        RUBY\n\n        write \"lib/ns/nested/component.rb\", <<~RUBY\n          module Nested\n            class Component\n            end\n          end\n        RUBY\n      end\n    end\n\n    before do\n      loader.push_dir @dir.join(\"lib/ns\").realpath\n      loader.setup\n    end\n\n    let(:cleanable_constants) { %i[Component] }\n\n    context \"lazy loading\" do\n      it \"resolves the component as an instance of a top-level class\" do\n        expect(container[\"ns.component\"]).to be_an_instance_of Component\n        expect(container[\"ns.nested.component\"]).to be_an_instance_of Nested::Component\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        container.finalize!\n      end\n\n      it \"resolves the component as an instance of a top-level class\" do\n        expect(container[\"ns.component\"]).to be_an_instance_of Component\n        expect(container[\"ns.nested.component\"]).to be_an_instance_of Nested::Component\n      end\n    end\n  end\n\n  context \"distinct constant namespace\" do\n    let(:component_dir_config) {\n      -> dir {\n        dir.namespaces.add \"ns\", const: \"my_namespace\"\n      }\n    }\n\n    before :context do\n      @dir = make_tmp_directory\n\n      with_directory(@dir) do\n        write \"lib/ns/component.rb\", <<~RUBY\n          module MyNamespace\n            class Component\n            end\n          end\n        RUBY\n\n        write \"lib/ns/nested/component.rb\", <<~RUBY\n          module MyNamespace\n            module Nested\n              class Component\n              end\n            end\n          end\n        RUBY\n      end\n    end\n\n    before do\n      module MyNamespace; end\n\n      loader.push_dir @dir.join(\"lib\", \"ns\").realpath, namespace: MyNamespace\n      loader.setup\n    end\n\n    let(:cleanable_modules) { super() + %i[MyNamespace] }\n\n    context \"lazy loading\" do\n      it \"resolves the component as an instance of a class in the given constant namespace\" do\n        expect(container[\"ns.component\"]).to be_an_instance_of MyNamespace::Component\n        expect(container[\"ns.nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        container.finalize!\n      end\n\n      it \"resolves the component as an instance of a class in the given constant namespace\" do\n        expect(container[\"ns.component\"]).to be_an_instance_of MyNamespace::Component\n        expect(container[\"ns.nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n      end\n    end\n  end\n\n  context \"distinct constant namespace for root\" do\n    let(:component_dir_config) {\n      -> dir {\n        dir.namespaces.add_root const: \"my_namespace\"\n      }\n    }\n\n    before :context do\n      @dir = make_tmp_directory\n\n      with_directory(@dir) do\n        write \"lib/component.rb\", <<~RUBY\n          module MyNamespace\n            class Component\n            end\n          end\n        RUBY\n\n        write \"lib/nested/component.rb\", <<~RUBY\n          module MyNamespace\n            module Nested\n              class Component\n              end\n            end\n          end\n        RUBY\n      end\n    end\n\n    before do\n      module MyNamespace; end\n\n      loader.push_dir @dir.join(\"lib\").realpath, namespace: MyNamespace\n      loader.setup\n    end\n\n    let(:cleanable_modules) { super() + %i[MyNamespace] }\n\n    context \"lazy loading\" do\n      it \"resolves the component as an instance of a class in the given constant namespace\" do\n        expect(container[\"component\"]).to be_an_instance_of MyNamespace::Component\n        expect(container[\"nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        container.finalize!\n      end\n\n      it \"resolves the component as an instance of a class in the given constant namespace\" do\n        expect(container[\"component\"]).to be_an_instance_of MyNamespace::Component\n        expect(container[\"nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/deep_namespace_paths_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Component dir namespaces / Deep namespace paths\" do\n  let(:container) {\n    root = @dir\n    dir_config = defined?(component_dir_config) ? component_dir_config : -> * {}\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n        config.component_dirs.add(\"lib\", &dir_config)\n      end\n    }\n  }\n\n  context \"key namespace not given\" do\n    let(:component_dir_config) {\n      -> dir {\n        dir.namespaces.add \"ns/nested\", const: nil\n      }\n    }\n\n    before :context do\n      @dir = make_tmp_directory\n\n      with_directory(@dir) do\n        write \"lib/ns/nested/component.rb\", <<~RUBY\n          class Component\n          end\n        RUBY\n      end\n    end\n\n    context \"lazy loading\" do\n      it \"registers components using the key namespace separator ('.'), not the path separator used for the namespace path\" do\n        expect(container[\"ns.nested.component\"]).to be_an_instance_of Component\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        container.finalize!\n      end\n\n      it \"registers components using the key namespace separator ('.'), not the path separator used for the namespace path\" do\n        expect(container[\"ns.nested.component\"]).to be_an_instance_of Component\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/default_loader_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Component dir namespaces / Default loader\" do\n  let(:container) {\n    root = @dir\n    dir_config = defined?(component_dir_config) ? component_dir_config : -> * {}\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n        config.component_dirs.add(\"lib\", &dir_config)\n      end\n    }\n  }\n\n  describe \"constant namespaces\" do\n    context \"top-level constant namespace\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add \"ns\", const: nil\n        }\n      }\n\n      before :context do\n        @dir = make_tmp_directory\n\n        with_directory(@dir) do\n          write \"lib/ns/component.rb\", <<~RUBY\n            class Component\n            end\n          RUBY\n        end\n      end\n\n      let(:cleanable_constants) { %i[Component] }\n\n      context \"lazy loading\" do\n        it \"resolves the component as an instance of a top-level class\" do\n          expect(container[\"ns.component\"]).to be_an_instance_of Component\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"resolves the component as an instance of a top-level class\" do\n          expect(container[\"ns.component\"]).to be_an_instance_of Component\n        end\n      end\n    end\n\n    context \"distinct constant namespace\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add \"ns\", const: \"my_namespace\"\n        }\n      }\n\n      before :context do\n        @dir = make_tmp_directory\n\n        with_directory(@dir) do\n          write \"lib/ns/component.rb\", <<~RUBY\n            module MyNamespace\n              class Component\n              end\n            end\n          RUBY\n\n          write \"lib/ns/nested/component.rb\", <<~RUBY\n            module MyNamespace\n              module Nested\n                class Component\n                end\n              end\n            end\n          RUBY\n        end\n      end\n\n      let(:cleanable_modules) { super() + %i[MyNamespace] }\n\n      context \"lazy loading\" do\n        it \"resolves the component as an instance of a class in the given constant namespace\" do\n          expect(container[\"ns.component\"]).to be_an_instance_of MyNamespace::Component\n          expect(container[\"ns.nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"resolves the component as an instance of a class in the given constant namespace\" do\n          expect(container[\"ns.component\"]).to be_an_instance_of MyNamespace::Component\n          expect(container[\"ns.nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n        end\n      end\n    end\n\n    context \"distinct constant namespace for root\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add_root const: \"my_namespace\"\n        }\n      }\n\n      before :context do\n        @dir = make_tmp_directory\n\n        with_directory(@dir) do\n          write \"lib/component.rb\", <<~RUBY\n            module MyNamespace\n              class Component\n              end\n            end\n          RUBY\n\n          write \"lib/nested/component.rb\", <<~RUBY\n            module MyNamespace\n              module Nested\n                class Component\n                end\n              end\n            end\n          RUBY\n        end\n      end\n\n      let(:cleanable_modules) { super() + %i[MyNamespace] }\n\n      context \"lazy loading\" do\n        it \"resolves the component as an instance of a class in the given constant namespace\" do\n          expect(container[\"component\"]).to be_an_instance_of MyNamespace::Component\n          expect(container[\"nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"resolves the component as an instance of a class in the given constant namespace\" do\n          expect(container[\"component\"]).to be_an_instance_of MyNamespace::Component\n          expect(container[\"nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n        end\n      end\n    end\n  end\n\n  describe \"key namespaces\" do\n    describe \"top-level key namespace\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add \"ns\", key: nil\n        }\n      }\n\n      before :context do\n        @dir = make_tmp_directory\n\n        with_directory(@dir) do\n          write \"lib/ns/component.rb\", <<~RUBY\n            module Ns\n              class Component\n              end\n            end\n          RUBY\n        end\n      end\n\n      let(:cleanable_modules) { super() + %i[Ns] }\n\n      context \"lazy loading\" do\n        it \"resolves the component via a top-level key\" do\n          expect(container[\"component\"]).to be_an_instance_of Ns::Component\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"resolves the component as an instance of a top-level class\" do\n          expect(container[\"component\"]).to be_an_instance_of Ns::Component\n        end\n      end\n    end\n\n    describe \"distinct key namespace\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add \"ns\", key: \"my_ns\"\n        }\n      }\n\n      before :context do\n        @dir = make_tmp_directory\n\n        with_directory(@dir) do\n          write \"lib/ns/component.rb\", <<~RUBY\n            module Ns\n              class Component\n              end\n            end\n          RUBY\n\n          write \"lib/ns/nested/component.rb\", <<~RUBY\n            module Ns\n              module Nested\n                class Component\n                end\n              end\n            end\n          RUBY\n        end\n      end\n\n      let(:cleanable_modules) { super() + %i[Ns] }\n\n      context \"lazy loading\" do\n        it \"resolves the component via the given key namespace\" do\n          expect(container[\"my_ns.component\"]).to be_an_instance_of Ns::Component\n          expect(container[\"my_ns.nested.component\"]).to be_an_instance_of Ns::Nested::Component\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"resolves the component via the given key namespace\" do\n          expect(container[\"my_ns.component\"]).to be_an_instance_of Ns::Component\n          expect(container[\"my_ns.nested.component\"]).to be_an_instance_of Ns::Nested::Component\n        end\n      end\n    end\n\n    describe \"distinct key namespace for root\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add_root key: \"my_ns\"\n        }\n      }\n\n      before :context do\n        @dir = make_tmp_directory\n\n        with_directory(@dir) do\n          write \"lib/component.rb\", <<~RUBY\n            class Component\n            end\n          RUBY\n\n          write \"lib/nested/component.rb\", <<~RUBY\n            module Nested\n              class Component\n              end\n            end\n          RUBY\n        end\n      end\n\n      let(:cleanable_modules) { super() + %i[Nested] }\n      let(:cleanable_constants) { %i[Component] }\n\n      context \"lazy loading\" do\n        it \"resolves the component via the given key namespace\" do\n          expect(container[\"my_ns.component\"]).to be_an_instance_of Component\n          expect(container[\"my_ns.nested.component\"]).to be_an_instance_of Nested::Component\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"resolves the component via the given key namespace\" do\n          expect(container[\"my_ns.component\"]).to be_an_instance_of Component\n          expect(container[\"my_ns.nested.component\"]).to be_an_instance_of Nested::Component\n        end\n      end\n    end\n  end\n\n  describe \"mixed constant and key namespaces\" do\n    let(:component_dir_config) {\n      -> dir {\n        dir.namespaces.add \"ns\", key: \"my_ns\", const: \"my_namespace\"\n      }\n    }\n\n    before :context do\n      @dir = make_tmp_directory\n\n      with_directory(@dir) do\n        write \"lib/ns/component.rb\", <<~RUBY\n          module MyNamespace\n            class Component\n            end\n          end\n        RUBY\n\n        write \"lib/ns/nested/component.rb\", <<~RUBY\n          module MyNamespace\n            module Nested\n              class Component\n              end\n            end\n          end\n        RUBY\n      end\n    end\n\n    let(:cleanable_modules) { super() + %i[MyNamespace] }\n\n    context \"lazy loading\" do\n      it \"resolves the component via the given key namespace and returns an instance of a class in the given constant namespace\" do\n        expect(container[\"my_ns.component\"]).to be_an_instance_of MyNamespace::Component\n        expect(container[\"my_ns.nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        container.finalize!\n      end\n\n      it \"resolves the component via the given key namespace and returns an instance of a class in the given constant namespace\" do\n        expect(container[\"my_ns.component\"]).to be_an_instance_of MyNamespace::Component\n        expect(container[\"my_ns.nested.component\"]).to be_an_instance_of MyNamespace::Nested::Component\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/multiple_namespaces_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Component dir namespaces / Multiple namespaces\" do\n  let(:cleanable_constants) { %i[Component RootComponent] }\n  let(:cleanable_modules) { %i[Admin Test] }\n\n  let(:container) {\n    root = @dir\n    dir_config = defined?(component_dir_config) ? component_dir_config : -> * {}\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n        config.component_dirs.add(\"lib\", &dir_config)\n      end\n    }\n  }\n\n  context \"single configured path namespace\" do\n    let(:component_dir_config) {\n      -> dir {\n        dir.namespaces.add \"test\", key: nil\n      }\n    }\n\n    before :context do\n      @dir = make_tmp_directory\n\n      with_directory(@dir) do\n        write \"lib/test/component.rb\", <<~RUBY\n          module Test\n            class Component\n            end\n          end\n        RUBY\n      end\n    end\n\n    context \"lazy loading\" do\n      it \"resolves the compoment via the namespace\" do\n        expect(container[\"component\"]).to be_an_instance_of Test::Component\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        container.finalize!\n      end\n\n      it \"resolves the compoment via the namespace\" do\n        expect(container[\"component\"]).to be_an_instance_of Test::Component\n      end\n    end\n  end\n\n  context \"mixed path and root namespace\" do\n    before :context do\n      @dir = make_tmp_directory\n\n      with_directory(@dir) do\n        write \"lib/test/component.rb\", <<~RUBY\n          module Test\n            class Component\n            end\n          end\n        RUBY\n\n        write \"lib/component.rb\", <<~RUBY\n          class Component\n          end\n        RUBY\n\n        write \"lib/root_component.rb\", <<~RUBY\n          class RootComponent\n          end\n        RUBY\n      end\n    end\n\n    context \"configured path namespace before implicit trailing root namespace\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add \"test\", key: nil\n        }\n      }\n\n      context \"lazy loading\" do\n        it \"prefers the configured namespace when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Test::Component\n          expect(container[\"root_component\"]).to be_an_instance_of RootComponent\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"prefers the configured namespace when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Test::Component\n          expect(container[\"root_component\"]).to be_an_instance_of RootComponent\n        end\n      end\n    end\n\n    context \"leading root namespace before configured path namespace\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add_root\n          dir.namespaces.add \"test\", key: nil\n        }\n      }\n\n      context \"lazy loading\" do\n        it \"prefers the root namespace when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Component\n          expect(container[\"root_component\"]).to be_an_instance_of RootComponent\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"prefers the root namespace when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Component\n          expect(container[\"root_component\"]).to be_an_instance_of RootComponent\n        end\n      end\n    end\n  end\n\n  context \"multiple configured path namespaces\" do\n    before :context do\n      @dir = make_tmp_directory\n\n      with_directory(@dir) do\n        write \"lib/admin/admin_component.rb\", <<~RUBY\n          module Admin\n            class AdminComponent\n            end\n          end\n        RUBY\n\n        write \"lib/admin/component.rb\", <<~RUBY\n          module Admin\n            class Component\n            end\n          end\n        RUBY\n\n        write \"lib/test/test_component.rb\", <<~RUBY\n          module Test\n            class TestComponent\n            end\n          end\n        RUBY\n\n        write \"lib/test/component.rb\", <<~RUBY\n          module Test\n            class Component\n            end\n          end\n        RUBY\n\n        write \"lib/component.rb\", <<~RUBY\n          class Component\n          end\n        RUBY\n\n        write \"lib/root_component.rb\", <<~RUBY\n          class RootComponent\n          end\n        RUBY\n      end\n    end\n\n    context \"ordered one way\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add \"admin\", key: nil\n          dir.namespaces.add \"test\", key: nil\n        }\n      }\n\n      context \"lazy loading\" do\n        it \"prefers the earlier configured namespaces when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Admin::Component\n          expect(container[\"admin_component\"]).to be_an_instance_of Admin::AdminComponent\n          expect(container[\"test_component\"]).to be_an_instance_of Test::TestComponent\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"prefers the earlier configured namespaces when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Admin::Component\n          expect(container[\"admin_component\"]).to be_an_instance_of Admin::AdminComponent\n          expect(container[\"test_component\"]).to be_an_instance_of Test::TestComponent\n        end\n      end\n    end\n\n    context \"ordered the other way\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add \"test\", key: nil\n          dir.namespaces.add \"admin\", key: nil\n        }\n      }\n\n      context \"lazy loading\" do\n        it \"prefers the earlier configured namespaces when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Test::Component\n          expect(container[\"admin_component\"]).to be_an_instance_of Admin::AdminComponent\n          expect(container[\"test_component\"]).to be_an_instance_of Test::TestComponent\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"prefers the earlier configured namespaces when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Test::Component\n          expect(container[\"admin_component\"]).to be_an_instance_of Admin::AdminComponent\n          expect(container[\"test_component\"]).to be_an_instance_of Test::TestComponent\n        end\n      end\n    end\n\n    context \"leading root namespace\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add_root\n          dir.namespaces.add \"admin\", key: nil\n          dir.namespaces.add \"test\", key: nil\n        }\n      }\n\n      context \"lazy loading\" do\n        it \"prefers the earlier configured namespaces when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Component\n          expect(container[\"admin_component\"]).to be_an_instance_of Admin::AdminComponent\n          expect(container[\"test_component\"]).to be_an_instance_of Test::TestComponent\n          expect(container[\"root_component\"]).to be_an_instance_of RootComponent\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"prefers the earlier configured namespaces when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Component\n          expect(container[\"admin_component\"]).to be_an_instance_of Admin::AdminComponent\n          expect(container[\"test_component\"]).to be_an_instance_of Test::TestComponent\n          expect(container[\"root_component\"]).to be_an_instance_of RootComponent\n        end\n      end\n    end\n\n    context \"root namespace between path namespaces\" do\n      let(:component_dir_config) {\n        -> dir {\n          dir.namespaces.add \"admin\", key: nil\n          dir.namespaces.add_root\n          dir.namespaces.add \"test\", key: nil\n        }\n      }\n\n      context \"lazy loading\" do\n        it \"prefers the earlier configured namespaces when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Admin::Component\n          expect(container[\"admin_component\"]).to be_an_instance_of Admin::AdminComponent\n          expect(container[\"test_component\"]).to be_an_instance_of Test::TestComponent\n          expect(container[\"root_component\"]).to be_an_instance_of RootComponent\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          container.finalize!\n        end\n\n        it \"prefers the earlier configured namespaces when resolving components\" do\n          expect(container[\"component\"]).to be_an_instance_of Admin::Component\n          expect(container[\"admin_component\"]).to be_an_instance_of Admin::AdminComponent\n          expect(container[\"test_component\"]).to be_an_instance_of Test::TestComponent\n          expect(container[\"root_component\"]).to be_an_instance_of RootComponent\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/namespaces_as_defaults_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Component dir namespaces / Namespaces as component dir defaults\" do\n  let(:container) {\n    root = @dir\n    cont_config = defined?(container_config) ? container_config : -> * {}\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n\n        cont_config.(config)\n      end\n    }\n  }\n\n  let(:container_config) {\n    -> config {\n      config.component_dirs.add \"lib\"\n\n      config.component_dirs.namespaces.add \"top_level_const\", const: nil\n      config.component_dirs.namespaces.add \"top_level_key\", key: nil\n\n      config.component_dirs.add \"xyz\"\n    }\n  }\n\n  before :context do\n    @dir = make_tmp_directory\n\n    with_directory(@dir) do\n      write \"lib/top_level_const/top_level_lib_component.rb\", <<~RUBY\n        class TopLevelLibComponent\n        end\n      RUBY\n\n      write \"xyz/top_level_const/top_level_xyz_component.rb\", <<~RUBY\n        class TopLevelXyzComponent\n        end\n      RUBY\n\n      write \"lib/top_level_key/nested/lib_component.rb\", <<~RUBY\n        module TopLevelKey\n          module Nested\n            class LibComponent\n            end\n          end\n        end\n      RUBY\n\n      write \"xyz/top_level_key/nested/xyz_component.rb\", <<~RUBY\n        module TopLevelKey\n          module Nested\n            class XyzComponent\n            end\n          end\n        end\n      RUBY\n    end\n  end\n\n  context \"lazy loading\" do\n    it \"resolves the components from multiple component dirs according to the default namespaces\" do\n      expect(container[\"top_level_const.top_level_lib_component\"]).to be_an_instance_of TopLevelLibComponent\n      expect(container[\"top_level_const.top_level_xyz_component\"]).to be_an_instance_of TopLevelXyzComponent\n\n      expect(container[\"nested.lib_component\"]).to be_an_instance_of TopLevelKey::Nested::LibComponent\n      expect(container[\"nested.xyz_component\"]).to be_an_instance_of TopLevelKey::Nested::XyzComponent\n    end\n  end\n\n  context \"finalized\" do\n    before do\n      container.finalize!\n    end\n\n    it \"resolves the components from multiple component dirs according to the default namespaces\" do\n      expect(container[\"top_level_const.top_level_lib_component\"]).to be_an_instance_of TopLevelLibComponent\n      expect(container[\"top_level_const.top_level_xyz_component\"]).to be_an_instance_of TopLevelXyzComponent\n\n      expect(container[\"nested.lib_component\"]).to be_an_instance_of TopLevelKey::Nested::LibComponent\n      expect(container[\"nested.xyz_component\"]).to be_an_instance_of TopLevelKey::Nested::XyzComponent\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/custom_auto_register_proc_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Auto-registration / Custom auto_register proc\" do\n  before do\n    class Test::Container < Dry::System::Container\n      configure do |config|\n        config.root = SPEC_ROOT.join(\"fixtures\").realpath\n\n        config.component_dirs.add \"components\" do |dir|\n          dir.namespaces.add \"test\", key: nil\n          dir.auto_register = proc do |component|\n            !component.key.match?(/bar/)\n          end\n        end\n      end\n    end\n  end\n\n  shared_examples \"custom auto_register proc\" do\n    it \"registers components according to the custom auto_register proc\" do\n      expect(Test::Container.key?(\"foo\")).to be true\n      expect(Test::Container.key?(\"bar\")).to be false\n      expect(Test::Container.key?(\"bar.baz\")).to be false\n    end\n  end\n\n  context \"Finalized container\" do\n    before do\n      Test::Container.finalize!\n    end\n\n    include_examples \"custom auto_register proc\"\n  end\n\n  context \"Non-finalized container\" do\n    include_examples \"custom auto_register proc\"\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/custom_instance_proc_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Auto-registration / Custom instance proc\" do\n  before :context do\n    with_directory(@dir = make_tmp_directory) do\n      write \"lib/foo.rb\", <<~RUBY\n        module Test\n          class Foo; end\n        end\n      RUBY\n    end\n  end\n\n  let(:container) {\n    root = @dir\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n\n        config.component_dirs.add \"lib\" do |dir|\n          dir.namespaces.add_root const: \"test\"\n          dir.instance = proc do |component, *args|\n            # Return the component's string key as its instance\n            component.key\n          end\n        end\n      end\n    }\n  }\n\n  shared_examples \"custom instance proc\" do\n    it \"registers the component using the custom loader\" do\n      expect(container[\"foo\"]).to eq \"foo\"\n    end\n  end\n\n  context \"Non-finalized container\" do\n    include_examples \"custom instance proc\"\n  end\n\n  context \"Finalized container\" do\n    before do\n      container.finalize!\n    end\n\n    include_examples \"custom instance proc\"\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/custom_loader_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Auto-registration / Custom loader\" do\n  before do\n    # A loader that simply returns the component's identifier string as its instance\n    class Test::IdentifierLoader\n      def self.call(component, *_args)\n        component.identifier.to_s\n      end\n    end\n\n    class Test::Container < Dry::System::Container\n      configure do |config|\n        config.root = SPEC_ROOT.join(\"fixtures\").realpath\n\n        config.component_dirs.add \"components\" do |dir|\n          dir.namespaces.add \"test\", key: nil\n          dir.loader = Test::IdentifierLoader\n        end\n      end\n    end\n  end\n\n  shared_examples \"custom loader\" do\n    it \"registers the component using the custom loader\" do\n      expect(Test::Container[\"foo\"]).to eq \"foo\"\n    end\n  end\n\n  context \"Finalized container\" do\n    before do\n      Test::Container.finalize!\n    end\n\n    include_examples \"custom loader\"\n  end\n\n  context \"Non-finalized container\" do\n    include_examples \"custom loader\"\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/memoize_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec::Matchers.define :have_memoized_component do |key|\n  match do |container|\n    container[key].eql?(container[key])\n  end\nend\n\nRSpec.describe \"Auto-registration / Memoizing components\" do\n  describe \"Memoizing all components in a component directory\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").realpath\n\n          config.component_dirs.add \"components\" do |dir|\n            dir.namespaces.add \"test\", key: nil\n            dir.memoize = true\n          end\n        end\n      end\n    end\n\n    shared_examples \"memoizing components\" do\n      it \"memoizes the components\" do\n        expect(Test::Container[\"foo\"]).to be Test::Container[\"foo\"]\n      end\n    end\n\n    context \"Finalized container\" do\n      before do\n        Test::Container.finalize!\n      end\n\n      include_examples \"memoizing components\"\n    end\n\n    context \"Non-finalized container\" do\n      include_examples \"memoizing components\"\n    end\n  end\n\n  describe \"Memoizing specific components in a component directory with a memoize proc\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").realpath\n\n          config.component_dirs.add \"components\" do |dir|\n            dir.namespaces.add \"test\", key: nil\n            dir.memoize = proc do |component|\n              !component.key.match?(/bar/)\n            end\n          end\n        end\n      end\n    end\n\n    shared_examples \"memoizing components\" do\n      it \"memoizes the components matching the memoize proc\" do\n        expect(Test::Container[\"foo\"]).to be Test::Container[\"foo\"]\n        expect(Test::Container[\"bar\"]).not_to be Test::Container[\"bar\"]\n        expect(Test::Container[\"bar.baz\"]).not_to be Test::Container[\"bar.baz\"]\n      end\n    end\n\n    context \"Finalized container\" do\n      before do\n        Test::Container.finalize!\n      end\n\n      include_examples \"memoizing components\"\n    end\n\n    context \"Non-finalized container\" do\n      include_examples \"memoizing components\"\n    end\n  end\n\n  describe \"Memoizing specific components via magic comments\" do\n    shared_examples \"memoizing components based on magic comments\" do\n      it \"memoizes components with memoize: true\" do\n        expect(Test::Container).to have_memoized_component \"memoize_true_comment\"\n      end\n\n      it \"does not memoize components with memoize: false\" do\n        expect(Test::Container).not_to have_memoized_component \"memoize_false_comment\"\n      end\n    end\n\n    context \"No memoizing config for component_dir\" do\n      before do\n        class Test::Container < Dry::System::Container\n          configure do |config|\n            config.root = SPEC_ROOT.join(\"fixtures\").realpath\n            config.component_dirs.add \"memoize_magic_comments\" do |dir|\n              dir.namespaces.add \"test\", key: nil\n            end\n          end\n        end\n      end\n\n      include_examples \"memoizing components based on magic comments\"\n\n      it \"does not memoize components without magic comments\" do\n        expect(Test::Container).not_to have_memoized_component \"memoize_no_comment\"\n      end\n    end\n\n    context \"Memoize config 'false' for component_dir\" do\n      before do\n        class Test::Container < Dry::System::Container\n          configure do |config|\n            config.root = SPEC_ROOT.join(\"fixtures\").realpath\n            config.component_dirs.add \"memoize_magic_comments\" do |dir|\n              dir.namespaces.add \"test\", key: nil\n              dir.memoize = false\n            end\n          end\n        end\n      end\n\n      include_examples \"memoizing components based on magic comments\"\n\n      it \"does not memoize components without magic comments\" do\n        expect(Test::Container).not_to have_memoized_component \"memoize_no_comment\"\n      end\n    end\n\n    context \"Memoize config 'true' for component_dir\" do\n      before do\n        class Test::Container < Dry::System::Container\n          configure do |config|\n            config.root = SPEC_ROOT.join(\"fixtures\").realpath\n            config.component_dirs.add \"memoize_magic_comments\" do |dir|\n              dir.namespaces.add \"test\", key: nil\n              dir.memoize = true\n            end\n          end\n        end\n      end\n\n      include_examples \"memoizing components based on magic comments\"\n\n      it \"memoizes components without magic comments\" do\n        expect(Test::Container).to have_memoized_component \"memoize_no_comment\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration/mixed_namespaces_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Auto-registration / Components with mixed namespaces\" do\n  before do\n    class Test::Container < Dry::System::Container\n      configure do |config|\n        config.root = SPEC_ROOT.join(\"fixtures/mixed_namespaces\").realpath\n\n        config.component_dirs.add \"lib\" do |dir|\n          dir.namespaces.add \"test/my_app\", key: nil\n        end\n      end\n    end\n  end\n\n  it \"loads components with and without the default namespace (lazy loading)\" do\n    aggregate_failures do\n      expect(Test::Container[\"app_component\"]).to be_an_instance_of Test::MyApp::AppComponent\n      expect(Test::Container[\"test.external.external_component\"]).to be_an_instance_of Test::External::ExternalComponent\n    end\n  end\n\n  it \"loads components with and without the default namespace (finalizing)\" do\n    Test::Container.finalize!\n\n    aggregate_failures do\n      expect(Test::Container[\"app_component\"]).to be_an_instance_of Test::MyApp::AppComponent\n      expect(Test::Container[\"test.external.external_component\"]).to be_an_instance_of Test::External::ExternalComponent\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/auto_registration_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\nrequire \"zeitwerk\"\n\nRSpec.describe \"Auto-registration\" do\n  specify \"Resolving components from a non-finalized container, without a default namespace\" do\n    module Test\n      class Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/standard_container_without_default_namespace\").realpath\n          config.component_dirs.add \"lib\"\n        end\n      end\n\n      Import = Container.injector\n    end\n\n    example_with_dep = Test::Container[\"test.example_with_dep\"]\n\n    expect(example_with_dep).to be_a Test::ExampleWithDep\n    expect(example_with_dep.dep).to be_a Test::Dep\n  end\n\n  specify \"Resolving components from a non-finalized container, with a default namespace\" do\n    module Test\n      class Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/standard_container_with_default_namespace\").realpath\n          config.component_dirs.add \"lib\" do |dir|\n            dir.namespaces.add \"test\", key: nil\n          end\n        end\n      end\n\n      Import = Container.injector\n    end\n\n    example_with_dep = Test::Container[\"example_with_dep\"]\n\n    expect(example_with_dep).to be_a Test::ExampleWithDep\n    expect(example_with_dep.dep).to be_a Test::Dep\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/autoloading_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\nrequire \"dry/system/loader/autoloading\"\nrequire \"zeitwerk\"\n\nRSpec.describe \"Autoloading loader\" do\n  specify \"Resolving components using Zeitwerk\" do\n    module Test\n      class Container < Dry::System::Container\n        config.root = SPEC_ROOT.join(\"fixtures/autoloading\").realpath\n        config.component_dirs.loader = Dry::System::Loader::Autoloading\n        config.component_dirs.add \"lib\" do |dir|\n          dir.add_to_load_path = false\n          dir.namespaces.add \"test\", key: nil\n        end\n      end\n    end\n\n    loader = ZeitwerkLoaderRegistry.new_loader\n    loader.push_dir Test::Container.config.root.join(\"lib\").realpath\n    loader.setup\n\n    foo = Test::Container[\"foo\"]\n    entity = foo.call\n\n    expect(foo).to be_a Test::Foo\n    expect(entity).to be_a Test::Entities::FooEntity\n\n    ZeitwerkLoaderRegistry.clear\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/importing/container_registration_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Container / Imports / Container registration\" do\n  let(:exporting_container) do\n    Class.new(Dry::System::Container) {\n      register \"block_component\" do\n        Object.new\n      end\n\n      register \"direct_component\", Object.new\n\n      register \"memoized_component\", memoize: true do\n        Object.new\n      end\n\n      register \"existing_component\", \"from exporting container\"\n    }\n  end\n\n  let(:importing_container) do\n    Class.new(Dry::System::Container) {\n      register \"existing_component\", \"from importing container\"\n    }\n  end\n\n  before do\n    importing_container.import(from: exporting_container, as: :other).finalize!\n  end\n\n  it \"imports components with the same options as their original registration\" do\n    block_component_a = importing_container[\"other.block_component\"]\n    block_component_b = importing_container[\"other.block_component\"]\n\n    expect(block_component_a).to be_an_instance_of(block_component_b.class)\n    expect(block_component_a).not_to be block_component_b\n\n    direct_component_a = importing_container[\"other.direct_component\"]\n    direct_component_b = importing_container[\"other.direct_component\"]\n\n    expect(direct_component_a).to be direct_component_b\n\n    memoized_component_a = importing_container[\"other.memoized_component\"]\n    memoized_component_b = importing_container[\"other.memoized_component\"]\n\n    expect(memoized_component_a).to be memoized_component_b\n\n    expect(importing_container[\"existing_component\"]).to eql(\"from importing container\")\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/importing/exports_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Container / Imports / Exports\" do\n  before :context do\n    @dir = make_tmp_directory\n\n    with_directory @dir do\n      write \"lib/private_component.rb\", <<~RUBY\n        module Test\n          class PrivateComponent; end\n        end\n      RUBY\n\n      write \"lib/exportable_component_a.rb\", <<~RUBY\n        module Test\n          class ExportableComponentA; end\n        end\n      RUBY\n\n      write \"lib/nested/exportable_component_b.rb\", <<~RUBY\n        module Test\n          module Nested\n            class ExportableComponentB; end\n          end\n        end\n      RUBY\n    end\n  end\n\n  let(:exporting_container) {\n    root = @dir\n    exports = self.exports if respond_to?(:exports)\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n        config.component_dirs.add \"lib\" do |dir|\n          dir.namespaces.add_root const: \"test\"\n        end\n        config.exports = exports if exports\n      end\n    }\n  }\n\n  let(:importing_container) {\n    exporting_container = self.exporting_container\n\n    Class.new(Dry::System::Container) {\n      import from: exporting_container, as: :other\n    }\n  }\n\n  context \"exports configured as a list of keys\" do\n    let(:exports) {\n      %w[\n        exportable_component_a\n        nested.exportable_component_b\n      ]\n    }\n\n    context \"importing container is lazy loading\" do\n      it \"can import only the components marked as exports\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.nested.exportable_component_b\")).to be true\n        expect(importing_container.key?(\"other.private_component\")).to be false\n      end\n\n      it \"only loads imported components as required (in both containers)\" do\n        importing_container[\"other.exportable_component_a\"]\n\n        expect(importing_container.keys).to eq [\"other.exportable_component_a\"]\n        expect(exporting_container.keys).to eq [\"exportable_component_a\"]\n      end\n\n      it \"does not finalize either container\" do\n        importing_container[\"other.exportable_component_a\"]\n\n        expect(importing_container).not_to be_finalized\n        expect(exporting_container).not_to be_finalized\n      end\n    end\n\n    context \"importing container is finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"can import only the components explicitly marked as exports\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.nested.exportable_component_b\")).to be true\n        expect(importing_container.key?(\"other.private_component\")).to be false\n      end\n\n      it \"does not finalize the exporting container\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(exporting_container).not_to be_finalized\n      end\n\n      it \"does not load components not marked for export\" do\n        expect(exporting_container.keys).to eq [\n          \"exportable_component_a\",\n          \"nested.exportable_component_b\"\n        ]\n      end\n    end\n  end\n\n  context \"exports configured with non-existent components included\" do\n    let(:exports) {\n      %w[\n        exportable_component_a\n        non_existent_component\n      ]\n    }\n\n    context \"importing container is lazy loading\" do\n      it \"ignores the non-existent keys\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.non_existent_component\")).to be false\n      end\n    end\n\n    context \"importing container is finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"ignores the non-existent keys\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.non_existent_component\")).to be false\n      end\n    end\n  end\n\n  context \"exports configured as an empty array\" do\n    let(:exports) { [] }\n\n    context \"importing container is lazy loading\" do\n      it \"cannot import anything\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be false\n        expect(importing_container.key?(\"other.nested.exportable_component_b\")).to be false\n        expect(importing_container.key?(\"other.private_component\")).to be false\n      end\n\n      it \"does not finalize the exporting container\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be false\n        expect(exporting_container).not_to be_finalized\n      end\n\n      it \"does not load any components in the exporting container\" do\n        expect(exporting_container.keys).to be_empty\n      end\n    end\n\n    context \"importing container is finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"cannot import anything\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be false\n        expect(importing_container.key?(\"other.nested.exportable_component_b\")).to be false\n        expect(importing_container.key?(\"other.private_component\")).to be false\n      end\n\n      it \"does not finalize the exporting container\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be false\n        expect(exporting_container).not_to be_finalized\n      end\n\n      it \"does not load any components in the exporting container\" do\n        expect(exporting_container.keys).to be_empty\n      end\n    end\n  end\n\n  context \"exports not configured (defaulting to nil)\" do\n    context \"importing container is lazy loading\" do\n      it \"can import all components\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.nested.exportable_component_b\")).to be true\n        expect(importing_container.key?(\"other.private_component\")).to be true\n      end\n\n      it \"only loads imported components as required (in both containers)\" do\n        importing_container[\"other.exportable_component_a\"]\n\n        expect(importing_container.keys).to eq [\"other.exportable_component_a\"]\n        expect(exporting_container.keys).to eq [\"exportable_component_a\"]\n      end\n\n      it \"does not finalize either container\" do\n        importing_container[\"other.exportable_component_a\"]\n\n        expect(importing_container).not_to be_finalized\n        expect(exporting_container).not_to be_finalized\n      end\n    end\n\n    context \"importing container is finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"imports all components\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.nested.exportable_component_b\")).to be true\n        expect(importing_container.key?(\"other.private_component\")).to be true\n      end\n\n      it \"finalizes the exporting container\" do\n        expect(exporting_container).to be_finalized\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/importing/import_namespaces_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Container / Imports / Import namespaces\" do\n  before :context do\n    @dir = make_tmp_directory\n\n    with_directory @dir do\n      write \"lib/exportable_component_a.rb\", <<~RUBY\n        module Test\n          class ExportableComponentA; end\n        end\n      RUBY\n\n      write \"lib/nested/exportable_component_b.rb\", <<~RUBY\n        module Test\n          module Nested\n            class ExportableComponentB; end\n          end\n        end\n      RUBY\n    end\n  end\n\n  let(:exporting_container) {\n    root = @dir\n    exports = self.exports if respond_to?(:exports)\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n        config.component_dirs.add \"lib\" do |dir|\n          dir.namespaces.add_root const: \"test\"\n        end\n        config.exports = exports if exports\n      end\n    }\n  }\n\n  context \"nil namespace\" do\n    context \"no keys specified\" do\n      let(:importing_container) {\n        exporting_container = self.exporting_container\n\n        Class.new(Dry::System::Container) {\n          import from: exporting_container, as: nil\n        }\n      }\n\n      context \"importing container is lazy loading\" do\n        it \"imports all the components\" do\n          expect(importing_container.key?(\"exportable_component_a\")).to be true\n          expect(importing_container.key?(\"nested.exportable_component_b\")).to be true\n          expect(importing_container.key?(\"non_existent\")).to be false\n        end\n      end\n\n      context \"importing container is finalized\" do\n        before do\n          importing_container.finalize!\n        end\n\n        it \"imports all the components\" do\n          expect(importing_container.key?(\"exportable_component_a\")).to be true\n          expect(importing_container.key?(\"nested.exportable_component_b\")).to be true\n          expect(importing_container.key?(\"non_existent\")).to be false\n        end\n      end\n    end\n\n    context \"keys specified\" do\n      let(:importing_container) {\n        exporting_container = self.exporting_container\n\n        Class.new(Dry::System::Container) {\n          import keys: [\"exportable_component_a\"], from: exporting_container, as: nil\n        }\n      }\n\n      context \"importing container is lazy loading\" do\n        it \"imports the specified components only\" do\n          expect(importing_container.key?(\"exportable_component_a\")).to be true\n          expect(importing_container.key?(\"nested.exportable_component_b\")).to be false\n        end\n      end\n\n      context \"importing container is finalized\" do\n        before do\n          importing_container.finalize!\n        end\n\n        it \"imports the specified components only\" do\n          expect(importing_container.key?(\"exportable_component_a\")).to be true\n          expect(importing_container.key?(\"nested.exportable_component_b\")).to be false\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/importing/imported_component_protection_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Container / Imports / Protection of imported components from export\" do\n  let(:source_container_1) {\n    Class.new(Dry::System::Container) {\n      register(\"component\", Object.new)\n    }\n  }\n\n  let(:source_container_2) {\n    container_1 = source_container_1\n\n    Class.new(Dry::System::Container) {\n      register(\"component\", Object.new)\n\n      import from: container_1, as: :container_1\n    }\n  }\n\n  let(:importing_container) {\n    container_2 = source_container_2\n\n    Class.new(Dry::System::Container) {\n      import from: container_2, as: :container_2\n    }\n  }\n\n  describe \"no exports configured\" do\n    context \"importing container lazy loading\" do\n      it \"does not import components that were themselves imported\" do\n        expect(importing_container.key?(\"container_2.component\")).to be true\n        expect(importing_container.key?(\"container_2.container_1.component\")).to be false\n      end\n    end\n\n    context \"importing container finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"does not import components that were themselves imported\" do\n        expect(importing_container.keys).to eq [\"container_2.component\"]\n      end\n    end\n  end\n\n  describe \"exports configured with imported components included\" do\n    let(:source_container_2) {\n      container_1 = source_container_1\n\n      Class.new(Dry::System::Container) {\n        configure do |config|\n          config.exports = %w[component container_1.component]\n        end\n\n        register(\"component\", Object.new)\n\n        import from: container_1, as: :container_1\n      }\n    }\n\n    context \"importing container lazy loading\" do\n      it \"imports the previously-imported component\" do\n        expect(importing_container.key?(\"container_2.component\")).to be true\n        expect(importing_container.key?(\"container_2.container_1.component\")).to be true\n      end\n    end\n\n    context \"importing container finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"imports the previously-imported component\" do\n        expect(importing_container.keys).to eq %w[container_2.component container_2.container_1.component]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/importing/partial_imports_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Container / Imports / Partial imports\" do\n  before :context do\n    @dir = make_tmp_directory\n\n    with_directory @dir do\n      write \"lib/exportable_component_a.rb\", <<~RUBY\n        module Test\n          class ExportableComponentA; end\n        end\n      RUBY\n\n      write \"lib/exportable_component_b.rb\", <<~RUBY\n        module Test\n          module Nested\n            class ExportableComponentB; end\n          end\n        end\n      RUBY\n    end\n  end\n\n  let(:exporting_container) {\n    root = @dir\n    exports = self.exports if respond_to?(:exports)\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = root\n        config.component_dirs.add \"lib\" do |dir|\n          dir.namespaces.add_root const: \"test\"\n        end\n        config.exports = exports if exports\n      end\n    }\n  }\n\n  let(:importing_container) {\n    exporting_container = self.exporting_container\n    import_keys = self.import_keys\n\n    Class.new(Dry::System::Container) {\n      import keys: import_keys, from: exporting_container, as: :other\n    }\n  }\n\n  let(:import_keys) { %w[exportable_component_a] }\n\n  context \"no exports configured (whole container export)\" do\n    context \"lazy loading\" do\n      it \"imports the specified components only\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.exportable_component_b\")).to be false\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"imports the specified components only\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.exportable_component_b\")).to be false\n      end\n    end\n  end\n\n  context \"exports configured (with import keys included)\" do\n    let(:exports) { %w[exportable_component_a exportable_component_b] }\n\n    context \"lazy loading\" do\n      it \"imports the specified components only\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.exportable_component_b\")).to be false\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"imports the specified components only\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.exportable_component_b\")).to be false\n      end\n    end\n  end\n\n  context \"exports configured (with import keys not included)\" do\n    let(:exports) { %w[exportable_component_b] }\n\n    context \"lazy loading\" do\n      it \"does not import any components\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be false\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"does not import any components\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be false\n      end\n    end\n  end\n\n  context \"import keys specified that do not exist in exporting container\" do\n    let(:import_keys) { %w[exportable_component_a non_existent_key] }\n\n    context \"lazy loading\" do\n      it \"imports the existent components only\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.non_existent_key\")).to be false\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        importing_container.finalize!\n      end\n\n      it \"imports the existent components only\" do\n        expect(importing_container.key?(\"other.exportable_component_a\")).to be true\n        expect(importing_container.key?(\"other.non_existent_key\")).to be false\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/lazy_loading/auto_registration_disabled_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Lazy loading components with auto-registration disabled\" do\n  before do\n    module Test\n      class Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/lazy_loading/auto_registration_disabled\").realpath\n          config.component_dirs.add \"lib\"\n        end\n      end\n    end\n  end\n\n  it \"reports the component as absent\" do\n    expect(Test::Container.key?(\"entities.kitten\")).to be false\n  end\n\n  it \"does not load the component\" do\n    expect { Test::Container[\"entities.kitten\"] }.to raise_error(Dry::Core::Container::KeyError)\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/lazy_loading/bootable_components_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Lazy loading bootable components\" do\n  describe \"Booting component when resolving another components with bootable component as root key\" do\n    before do\n      module Test\n        class Container < Dry::System::Container\n          configure do |config|\n            config.root = SPEC_ROOT.join(\"fixtures/lazy_loading/shared_root_keys\").realpath\n            config.component_dirs.add \"lib\"\n          end\n        end\n      end\n    end\n\n    context \"Single container\" do\n      it \"boots the component and can resolve multiple other components registered using the same root key\" do\n        expect(Test::Container[\"kitten_service.fetch_kitten\"]).to be\n        expect(Test::Container.keys).to include(\"kitten_service.client\", \"kitten_service.fetch_kitten\")\n        expect(Test::Container[\"kitten_service.submit_kitten\"]).to be\n        expect(Test::Container.keys).to include(\"kitten_service.client\", \"kitten_service.fetch_kitten\", \"kitten_service.submit_kitten\")\n      end\n    end\n\n    context \"Bootable component in imported container\" do\n      before do\n        module Test\n          class AnotherContainer < Dry::System::Container\n            import from: Container, as: :core\n          end\n        end\n      end\n\n      context \"lazy loading\" do\n        it \"boots the component and can resolve multiple other components registered using the same root key\" do\n          expect(Test::AnotherContainer[\"core.kitten_service.fetch_kitten\"]).to be\n          expect(Test::AnotherContainer.keys).to include(\"core.kitten_service.fetch_kitten\")\n\n          expect(Test::AnotherContainer[\"core.kitten_service.submit_kitten\"]).to be\n          expect(Test::AnotherContainer.keys).to include(\"core.kitten_service.submit_kitten\")\n\n          expect(Test::AnotherContainer[\"core.kitten_service.client\"]).to be\n          expect(Test::AnotherContainer.keys).to include(\"core.kitten_service.client\")\n        end\n      end\n\n      context \"finalized\" do\n        before do\n          Test::AnotherContainer.finalize!\n        end\n\n        it \"boots the component in the imported container and imports the bootable component's registered components\" do\n          expect(Test::AnotherContainer.keys).to include(\"core.kitten_service.fetch_kitten\", \"core.kitten_service.submit_kitten\", \"core.kitten_service.client\")\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/lazy_loading/manifest_registration_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Lazy-loading registration manifest files\" do\n  module Test; end\n\n  def build_container\n    Class.new(Dry::System::Container) do\n      configure do |config|\n        config.root = SPEC_ROOT.join(\"fixtures/manifest_registration\").realpath\n      end\n    end\n  end\n\n  shared_examples \"manifest component\" do\n    before do\n      Test::Container = build_container\n      Test::Container.add_to_load_path!(\"lib\")\n    end\n\n    it \"loads a registration manifest file if the component could not be found\" do\n      expect(Test::Container[\"foo.special\"]).to be_a(Test::Foo)\n      expect(Test::Container[\"foo.special\"].name).to eq \"special\"\n    end\n  end\n\n  context \"Non-finalized container\" do\n    include_examples \"manifest component\"\n  end\n\n  context \"Finalized container\" do\n    include_examples \"manifest component\"\n    before { Test::Container.finalize! }\n  end\n\n  context \"Autoloaded container\" do\n    let :autoloader do\n      Zeitwerk::Loader.new.tap do |loader|\n        loader.enable_reloading\n\n        # This is a simulacrum of the Dry::Rails container reset\n        # that happens on every reload\n        loader.on_setup do\n          if Test.const_defined?(:Container)\n            Test.__send__(:remove_const, :Container)\n          end\n\n          Test.const_set :Container, build_container\n          Test::Container.finalize!\n\n          loader.push_dir(Test::Container.root)\n        end\n      end\n    end\n\n    it \"reloads manifest keys\" do\n      autoloader.setup\n      expect(Test::Container.keys).to include(\"foo.special\")\n\n      autoloader.reload\n      expect(Test::Container.keys).to include(\"foo.special\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/plugins/bootsnap_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Plugins / Bootsnap\" do\n  subject(:system) do\n    Class.new(Dry::System::Container) do\n      use :bootsnap\n\n      configure do |config|\n        config.root = SPEC_ROOT.join(\"fixtures/test\")\n        config.env = :development\n        config.bootsnap = {\n          load_path_cache: false,\n          compile_cache_iseq: true,\n          compile_cache_yaml: true\n        }\n      end\n    end\n  end\n\n  let(:cache_dir) do\n    system.root.join(\"tmp/cache\")\n  end\n\n  let(:bootsnap_cache_file) do\n    cache_dir.join(\"bootsnap\")\n  end\n\n  before do\n    FileUtils.rm_rf(cache_dir)\n    FileUtils.mkdir_p(cache_dir)\n  end\n\n  after do\n    FileUtils.rm_rf(cache_dir)\n  end\n\n  describe \".require_from_root\" do\n    if Gem::Version.new(RUBY_VERSION) < Gem::Version.new(\"3.4.0\")\n      it \"loads file\" do\n        system.require_from_root(\"lib/test/models\")\n\n        expect(Object.const_defined?(\"Test::Models\")).to be(true)\n\n        expect(bootsnap_cache_file.exist?).to be(true)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/plugins/dependency_graph_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Plugins / Dependency Graph\" do\n  let(:container) { Test::Container }\n  subject(:events) { [] }\n\n  before :context do\n    with_directory(@dir = make_tmp_directory) do\n      write \"system/providers/mailer.rb\", <<~RUBY\n        Test::Container.register_provider :mailer do\n          start do\n            register \"mailer\", Object.new\n          end\n\n        end\n      RUBY\n\n      write \"lib/foo.rb\", <<~RUBY\n        module Test\n          class Foo\n            include Deps[\"mailer\"]\n          end\n        end\n      RUBY\n\n      write \"lib/bar.rb\", <<~RUBY\n        module Test\n          class Bar\n            include Deps[\"foo\"]\n          end\n        end\n      RUBY\n    end\n  end\n\n  before do\n    root = @dir\n    Test::Container = Class.new(Dry::System::Container) {\n      use :dependency_graph\n\n      configure do |config|\n        config.root = root\n        config.component_dirs.add \"lib\" do |dir|\n          dir.namespaces.add_root const: \"test\"\n        end\n      end\n    }\n  end\n\n  before do\n    container[:notifications].subscribe(:resolved_dependency) { events << _1 }\n    container[:notifications].subscribe(:registered_dependency) { events << _1 }\n  end\n\n  shared_examples \"dependency graph notifications\" do\n    context \"lazy loading\" do\n      it \"emits dependency notifications for the resolved component\" do\n        container[\"foo\"]\n\n        expect(events.map { [_1.id, _1.payload] }).to eq [\n          [:resolved_dependency, {dependency_map: {mailer: \"mailer\"}, target_class: Test::Foo}],\n          [:registered_dependency, {class: Object, key: \"mailer\"}],\n          [:registered_dependency, {class: Test::Foo, key: \"foo\"}]\n        ]\n      end\n    end\n\n    context \"finalized\" do\n      before do\n        container.finalize!\n      end\n\n      it \"emits dependency notifications for all components\" do\n        expect(events.map { [_1.id, _1.payload] }).to eq [\n          [:registered_dependency, {key: \"mailer\", class: Object}],\n          [:resolved_dependency, {dependency_map: {foo: \"foo\"}, target_class: Test::Bar}],\n          [:resolved_dependency, {dependency_map: {mailer: \"mailer\"}, target_class: Test::Foo}],\n          [:registered_dependency, {key: \"foo\", class: Test::Foo}],\n          [:registered_dependency, {key: \"bar\", class: Test::Bar}]\n        ]\n      end\n    end\n  end\n\n  describe \"default (kwargs) injector\" do\n    before do\n      Test::Deps = Test::Container.injector\n    end\n\n    specify \"objects receive dependencies via keyword arguments\" do\n      expect(container[\"bar\"].method(:initialize).parameters).to eq(\n        [[:keyrest, :kwargs], [:block, :block]]\n      )\n    end\n\n    it_behaves_like \"dependency graph notifications\"\n  end\n\n  describe \"hash injector\" do\n    before do\n      Test::Deps = Test::Container.injector.hash\n    end\n\n    specify \"objects receive dependencies via a single options hash argument\" do\n      expect(container[\"bar\"].method(:initialize).parameters).to eq [[:req, :options]]\n    end\n\n    it_behaves_like \"dependency graph notifications\"\n  end\n\n  describe \"args injector\" do\n    before do\n      Test::Deps = Test::Container.injector.args\n    end\n\n    specify \"objects receive dependencies via positional arguments\" do\n      expect(container[\"bar\"].method(:initialize).parameters).to eq [[:req, :foo]]\n    end\n\n    it_behaves_like \"dependency graph notifications\"\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/plugins/env_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Plugins / Env\" do\n  context \"with default settings\" do\n    subject(:system) do\n      Class.new(Dry::System::Container) do\n        use :env\n      end\n    end\n\n    describe \".env\" do\n      it \"returns :development\" do\n        expect(system.env).to be(:development)\n      end\n    end\n  end\n\n  context \"with a custom inferrer\" do\n    subject(:system) do\n      Class.new(Dry::System::Container) do\n        use :env, inferrer: -> { :test }\n      end\n    end\n\n    describe \".env\" do\n      it \"returns :test\" do\n        expect(system.env).to be(:test)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/plugins/logging_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Plugins / Logging\" do\n  before do\n    system.configure do |config|\n      config.root = SPEC_ROOT.join(\"fixtures/test\")\n    end\n  end\n\n  let(:logger) do\n    system.logger\n  end\n\n  let(:log_file_content) do\n    File.read(system.log_file_path)\n  end\n\n  context \"with default logger settings\" do\n    subject(:system) do\n      class Test::Container < Dry::System::Container\n        use :env\n        use :logging\n      end\n    end\n\n    it \"logs to development.log\" do\n      logger.info \"info message\"\n\n      expect(log_file_content).to include(\"info message\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/plugins/zeitwerk/eager_loading_spec.rb",
    "content": "# frozen_string_literal: true\n\n# rubocop:disable Style/GlobalVars\n\nRSpec.describe \"Zeitwerk plugin / Eager loading\" do\n  before do\n    $eager_loaded = false\n    allow(Zeitwerk::Loader).to receive(:new).and_return(ZeitwerkLoaderRegistry.new_loader)\n  end\n\n  after { ZeitwerkLoaderRegistry.clear }\n\n  it \"Eager loads after finalization\" do\n    with_tmp_directory do |tmp_dir|\n      write \"lib/zeitwerk_eager.rb\", <<~RUBY\n        $eager_loaded = true\n\n        module Test\n          class ZeitwerkEager; end\n        end\n      RUBY\n\n      container = Class.new(Dry::System::Container) do\n        use :zeitwerk, eager_load: true\n\n        configure do |config|\n          config.root = tmp_dir\n          config.component_dirs.add \"lib\" do |dir|\n            dir.namespaces.add_root const: \"test\"\n          end\n        end\n      end\n\n      expect { container.finalize! }.to change { $eager_loaded }.to true\n    end\n  end\n\n  it \"Eager loads in production by default\" do\n    with_tmp_directory do |tmp_dir|\n      write \"lib/zeitwerk_eager.rb\", <<~RUBY\n        $eager_loaded = true\n\n        module Test\n          class ZeitwerkEager; end\n        end\n      RUBY\n\n      container = Class.new(Dry::System::Container) do\n        use :env, inferrer: -> { :production }\n        use :zeitwerk\n\n        configure do |config|\n          config.root = tmp_dir\n          config.component_dirs.add \"lib\" do |dir|\n            dir.namespaces.add_root const: \"test\"\n          end\n        end\n      end\n\n      expect { container.finalize! }.to change { $eager_loaded }.to true\n    end\n  end\nend\n\n# rubocop:enable Style/GlobalVars\n"
  },
  {
    "path": "spec/integration/container/plugins/zeitwerk/namespaces_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Zeitwerk plugin / Namespaces\" do\n  before do\n    allow(Zeitwerk::Loader).to receive(:new).and_return(ZeitwerkLoaderRegistry.new_loader)\n  end\n\n  after { ZeitwerkLoaderRegistry.clear }\n\n  it \"loads components from a root namespace with a const namespace\" do\n    with_tmp_directory do |tmp_dir|\n      write \"lib/foo.rb\", <<~RUBY\n        module Test\n          class Foo; end\n        end\n      RUBY\n\n      container = Class.new(Dry::System::Container) do\n        use :zeitwerk\n\n        configure do |config|\n          config.root = tmp_dir\n\n          config.component_dirs.add \"lib\" do |dir|\n            dir.namespaces.add_root const: \"test\"\n          end\n        end\n      end\n\n      expect(container[\"foo\"]).to be_an_instance_of Test::Foo\n    end\n  end\n\n  it \"loads components from multiple namespace with distinct const namespaces\" do\n    with_tmp_directory do |tmp_dir|\n      write \"lib/foo.rb\", <<~RUBY\n        module Test\n          class Foo; end\n        end\n      RUBY\n\n      write \"lib/nested/foo.rb\", <<~RUBY\n        module Test\n          module Nested\n            class Foo; end\n          end\n        end\n      RUBY\n\n      write \"lib/adapters/bar.rb\", <<~RUBY\n        module My\n          module Adapters\n            class Bar; end\n          end\n        end\n      RUBY\n\n      container = Class.new(Dry::System::Container) do\n        use :zeitwerk\n\n        configure do |config|\n          config.root = tmp_dir\n\n          config.component_dirs.add \"lib\" do |dir|\n            dir.namespaces.add \"adapters\", const: \"my/adapters\"\n            dir.namespaces.add_root const: \"test\"\n          end\n        end\n      end\n\n      expect(container[\"foo\"]).to be_an_instance_of Test::Foo\n      expect(container[\"nested.foo\"]).to be_an_instance_of Test::Nested::Foo\n      expect(container[\"adapters.bar\"]).to be_an_instance_of My::Adapters::Bar\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/plugins/zeitwerk/resolving_components_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Zeitwerk plugin / Resolving components\" do\n  before do\n    allow(Zeitwerk::Loader).to receive(:new).and_return(ZeitwerkLoaderRegistry.new_loader)\n  end\n\n  after { ZeitwerkLoaderRegistry.clear }\n\n  specify \"Resolving components using Zeitwerk\" do\n    with_tmp_directory do |tmp_dir|\n      write \"lib/foo.rb\", <<~RUBY\n        module Test\n          class Foo\n            def call\n              Entities::FooEntity.new\n            end\n          end\n        end\n      RUBY\n\n      write \"lib/entities/foo_entity.rb\", <<~RUBY\n        module Test\n          module Entities\n            class FooEntity; end\n          end\n        end\n      RUBY\n\n      container = Class.new(Dry::System::Container) do\n        use :zeitwerk\n\n        configure do |config|\n          config.root = tmp_dir\n          config.component_dirs.add \"lib\" do |dir|\n            dir.namespaces.add_root const: \"test\"\n          end\n        end\n      end\n\n      foo = container[\"foo\"]\n      entity = foo.call\n\n      expect(foo).to be_a Test::Foo\n      expect(entity).to be_a Test::Entities::FooEntity\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/plugins/zeitwerk/user_configured_loader_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Zeitwerk plugin / User-configured loader\" do\n  before do\n    allow(Zeitwerk::Loader).to receive(:new).and_return(ZeitwerkLoaderRegistry.new_loader)\n  end\n\n  after { ZeitwerkLoaderRegistry.clear }\n\n  it \"uses the user-configured loader and pushes component dirs to it\" do\n    with_tmp_directory do |tmp_dir|\n      write \"lib/foo.rb\", <<~RUBY\n        module Test\n          class Foo;end\n        end\n      RUBY\n\n      require \"zeitwerk\"\n\n      logs = []\n\n      container = Class.new(Dry::System::Container) do\n        use :zeitwerk\n\n        configure do |config|\n          config.root = tmp_dir\n          config.component_dirs.add \"lib\" do |dir|\n            dir.namespaces.add_root const: \"test\"\n          end\n\n          config.autoloader = Zeitwerk::Loader.new.tap do |loader|\n            loader.tag = \"custom_loader\"\n            loader.logger = -> str { logs << str }\n          end\n        end\n      end\n\n      expect(container[\"foo\"]).to be_a Test::Foo\n      expect(logs).not_to be_empty\n      expect(logs[0]).to include \"custom_loader\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/plugins_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::System::Container, \".use\" do\n  subject(:system) do\n    Class.new(Dry::System::Container)\n  end\n\n  before do\n    # Store globals\n    Test::PluginRegistry = Dry::System::Plugins.registry.dup\n    Test::LoadedDependencies = Dry::System::Plugins.loaded_dependencies.dup\n  end\n\n  after do\n    # Restore globals\n    Dry::System::Plugins.instance_eval do\n      @registry = Test::PluginRegistry\n      @loaded_dependencies = Test::LoadedDependencies\n    end\n  end\n\n  context \"with a plugin which has dependencies\" do\n    let(:plugin) do\n      Module.new do\n        def self.dependencies\n          SPEC_ROOT.join(\"fixtures/test/lib/test/dep\")\n        end\n      end\n    end\n\n    before do\n      Dry::System::Plugins.register(:test_plugin, plugin)\n    end\n\n    context \"when another plugin has the same dependency\" do\n      context \"and dependencies are defined with the same type\" do\n        before do\n          Dry::System::Plugins.register(:test_plugin_2, plugin)\n        end\n\n        it \"loads plugin and does not duplicate loaded_dependencies\" do\n          system.use(:test_plugin)\n          system.use(:test_plugin_2)\n\n          expect(Object.const_defined?(\"Test::Dep\")).to be(true)\n\n          expect(\n            Dry::System::Plugins.loaded_dependencies.count { |dep|\n              dep == SPEC_ROOT.join(\"fixtures/test/lib/test/dep\").to_s\n            }\n          ).to be(1)\n        end\n      end\n\n      context \"and dependencies are not defined with the same type\" do\n        let(:plugin_2) do\n          Module.new do\n            def self.dependencies\n              SPEC_ROOT.join(\"fixtures/test/lib/test/dep\").to_s\n            end\n          end\n        end\n\n        before do\n          Dry::System::Plugins.register(:test_plugin_2, plugin_2)\n        end\n\n        it \"loads plugin and does not duplicate loaded_dependencies\" do\n          system.use(:test_plugin)\n          system.use(:test_plugin_2)\n\n          expect(Object.const_defined?(\"Test::Dep\")).to be(true)\n\n          expect(\n            Dry::System::Plugins.loaded_dependencies.count { |dep|\n              dep == SPEC_ROOT.join(\"fixtures/test/lib/test/dep\").to_s\n            }\n          ).to be(1)\n        end\n      end\n    end\n\n    context \"when dependency is available\" do\n      it \"auto-requires dependency\" do\n        system.use(:test_plugin)\n\n        expect(Object.const_defined?(\"Test::Dep\")).to be(true)\n      end\n    end\n\n    context \"when dependency gem is not available\" do\n      let(:plugin) do\n        Module.new do\n          def self.dependencies\n            {gem_name: \"this-does-not-exist\"}\n          end\n        end\n      end\n\n      it \"raises exception\" do\n        msg =\n          \"dry-system plugin :test_plugin failed to load its dependencies: \" \\\n            \"cannot load such file -- this-does-not-exist - add gem_name to your Gemfile\"\n\n        expect { system.use(:test_plugin) }\n          .to raise_error(Dry::System::PluginDependencyMissing, msg)\n      end\n    end\n\n    context \"when dependency is not available\" do\n      let(:plugin) do\n        Module.new do\n          def self.dependencies\n            \"this-does-not-exist\"\n          end\n        end\n      end\n\n      it \"raises exception\" do\n        msg =\n          \"dry-system plugin :test_plugin failed to load its dependencies: \" \\\n            \"cannot load such file -- this-does-not-exist\"\n\n        expect { system.use(:test_plugin) }\n          .to raise_error(Dry::System::PluginDependencyMissing, msg)\n      end\n    end\n  end\n\n  context \"with a stateless plugin\" do\n    let(:plugin) do\n      Module.new do\n        def plugin_enabled?\n          true\n        end\n      end\n    end\n\n    context \"plugin without a block\" do\n      before do\n        Dry::System::Plugins.register(:test_plugin, plugin)\n      end\n\n      it \"enables a plugin\" do\n        system.use(:test_plugin)\n        expect(system).to be_plugin_enabled\n      end\n    end\n\n    context \"plugin with a block\" do\n      before do\n        Dry::System::Plugins.register(:test_plugin, plugin) do\n          setting :foo, default: \"bar\"\n        end\n      end\n\n      it \"enables a plugin which evaluates its block\" do\n        system.use(:test_plugin)\n        expect(system).to be_plugin_enabled\n        expect(system.config.foo).to eql(\"bar\")\n      end\n    end\n\n    context \"inheritance\" do\n      before do\n        Dry::System::Plugins.register(:test_plugin, plugin) do\n          setting :trace, default: []\n\n          after(:configure) do\n            config.trace << :test_plugin_configured\n          end\n        end\n      end\n\n      it \"enables plugin for a class and its descendant\" do\n        system.use(:test_plugin)\n\n        descendant = Class.new(system)\n\n        system.configure {}\n        descendant.configure {}\n\n        expect(system.config.trace).to eql([:test_plugin_configured])\n        expect(descendant.config.trace).to eql([:test_plugin_configured])\n      end\n    end\n\n    context \"calling multiple times\" do\n      before do\n        Dry::System::Plugins.register(:test_plugin, plugin) do\n          setting :trace, default: []\n\n          after(:configure) do\n            config.trace << :test_plugin_configured\n          end\n        end\n      end\n\n      it \"enables the plugin only once\" do\n        system.use(:test_plugin).use(:test_plugin).configure {}\n\n        expect(system.config.trace).to eql([:test_plugin_configured])\n      end\n    end\n  end\n\n  context \"with a stateful plugin\" do\n    let(:plugin) do\n      Class.new(Module) do\n        def initialize(options)\n          super()\n          @options = options\n\n          define_method(:plugin_test) do\n            options[:value]\n          end\n        end\n      end\n    end\n\n    before do\n      Dry::System::Plugins.register(:test_plugin, plugin)\n    end\n\n    it \"enables a plugin\" do\n      system.use(:test_plugin, value: \"bar\")\n      expect(system.plugin_test).to eql(\"bar\")\n    end\n  end\n\n  context \"misspeled plugin name\" do\n    it \"raises meaningful error\" do\n      expect { system.use :wrong_name }\n        .to raise_error(Dry::System::PluginNotFoundError, \"Plugin :wrong_name does not exist\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/providers/conditional_providers_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Providers / Conditional providers\" do\n  let(:container) {\n    provider_if = self.provider_if\n    Class.new(Dry::System::Container) {\n      register_provider :provided, if: provider_if do\n        start do\n          register \"provided\", Object.new\n        end\n      end\n    }\n  }\n\n  shared_examples \"loads the provider\" do\n    it \"runs the provider when a related component is resolved\" do\n      expect(container[\"provided\"]).to be\n      expect(container.providers.key?(:provided)).to be true\n    end\n  end\n\n  shared_examples \"does not load the provider\" do\n    it \"does not run the provider when a related component is resolved\" do\n      expect { container[\"provided\"] }.to raise_error(Dry::Core::Container::KeyError, /key not found: \"provided\"/)\n      expect(container.providers.key?(:provided)).to be false\n    end\n  end\n\n  describe \"true\" do\n    let(:provider_if) { true }\n\n    context \"lazy loading\" do\n      include_examples \"loads the provider\"\n    end\n\n    context \"finalized\" do\n      before { container.finalize! }\n      include_examples \"loads the provider\"\n    end\n  end\n\n  describe \"false\" do\n    let(:provider_if) { false }\n\n    context \"lazy loading\" do\n      include_examples \"does not load the provider\"\n    end\n\n    context \"finalized\" do\n      before { container.finalize! }\n      include_examples \"does not load the provider\"\n    end\n  end\n\n  describe \"provider file in provider dir\" do\n    let(:container) {\n      root = @dir\n      Test::Container = Class.new(Dry::System::Container) {\n        configure do |config|\n          config.root = root\n        end\n      }\n    }\n\n    describe \"true\" do\n      before :context do\n        with_directory(@dir = make_tmp_directory) do\n          write \"system/providers/provided.rb\", <<~RUBY\n            Test::Container.register_provider :provided, if: true do\n              start do\n                register \"provided\", Object.new\n              end\n            end\n          RUBY\n        end\n      end\n\n      context \"lazy loading\" do\n        include_examples \"loads the provider\"\n      end\n\n      context \"finalized\" do\n        before { container.finalize! }\n        include_examples \"loads the provider\"\n      end\n    end\n\n    describe \"true\" do\n      before :context do\n        with_directory(@dir = make_tmp_directory) do\n          write \"system/providers/provided.rb\", <<~RUBY\n            Test::Container.register_provider :provided, if: false do\n              start do\n                register \"provided\", Object.new\n              end\n            end\n          RUBY\n        end\n      end\n\n      context \"lazy loading\" do\n        include_examples \"does not load the provider\"\n      end\n\n      context \"finalized\" do\n        before { container.finalize! }\n        include_examples \"does not load the provider\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/providers/custom_provider_registrar_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Providers / Custom provider registrar\" do\n  specify \"Customizing the target_container for providers\" do\n    # Create a provider registrar that exposes a container _wrapper_ (i.e. something resembling a\n    # Hanami slice) as the target_container.\n    provider_registrar = Class.new(Dry::System::ProviderRegistrar) do\n      def self.for_wrapper(wrapper)\n        Class.new(self) do\n          define_singleton_method(:new) do |container|\n            super(container, wrapper)\n          end\n        end\n      end\n\n      attr_reader :wrapper\n\n      def initialize(container, wrapper)\n        super(container)\n        @wrapper = wrapper\n      end\n\n      def target_container\n        wrapper\n      end\n    end\n\n    # Create the wrapper, which has an internal Dry::System::Container (configured with our custom\n    # provider_registrar) that it then delegates to.\n    container_wrapper = Class.new do\n      define_singleton_method(:container) do\n        @container ||= Class.new(Dry::System::Container).tap do |container|\n          container.config.provider_registrar = provider_registrar.for_wrapper(self)\n        end\n      end\n\n      def self.register_provider(...)\n        container.register_provider(...)\n      end\n\n      def self.start(...)\n        container.start(...)\n      end\n    end\n\n    # Create a provider to expose its given `target` so we can make expecations about it\n    exposed_target = nil\n    container_wrapper.register_provider(:my_provider) do\n      start do\n        exposed_target = target\n      end\n    end\n    container_wrapper.start(:my_provider)\n\n    expect(exposed_target).to be container_wrapper\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/providers/custom_provider_superclass_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Providers / Custom provider superclass\" do\n  let!(:custom_superclass) do\n    module Test\n      class CustomSource < Dry::System::Provider::Source\n        attr_reader :custom_setting\n\n        def initialize(custom_setting:, **options, &)\n          super(**options, &)\n          @custom_setting = custom_setting\n        end\n      end\n    end\n\n    Test::CustomSource\n  end\n\n  let!(:custom_registrar) do\n    module Test\n      class CustomRegistrar < Dry::System::ProviderRegistrar\n        def provider_source_class = Test::CustomSource\n        def provider_source_options = {custom_setting: \"hello\"}\n      end\n    end\n\n    Test::CustomRegistrar\n  end\n\n  subject(:system) do\n    module Test\n      class Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/app\").realpath\n          config.provider_registrar = Test::CustomRegistrar\n        end\n      end\n    end\n\n    Test::Container\n  end\n\n  it \"overrides the default Provider Source base class\" do\n    system.register_provider(:test) {}\n\n    provider_source = system.providers[:test].source\n\n    expect(provider_source.class).to be < custom_superclass\n    expect(provider_source.class.name).to eq \"Test::CustomSource[test]\"\n    expect(provider_source.custom_setting).to eq \"hello\"\n  end\n\n  context \"Source class != provider_source_class\" do\n    let!(:custom_source) do\n      module Test\n        class OtherSource < Dry::System::Provider::Source\n          attr_reader :options\n\n          def initialize(**options, &block)\n            @options = options.except(:provider_container, :target_container)\n            super(**options.slice(:provider_container, :target_container), &block)\n          end\n        end\n      end\n\n      Test::OtherSource\n    end\n\n    specify \"External source doesn't use provider_source_options\" do\n      Dry::System.register_provider_source(:test, group: :custom, source: custom_source)\n      system.register_provider(:test, from: :custom) {}\n\n      expect {\n        provider_source = system.providers[:test].source\n        expect(provider_source.class).to be < Dry::System::Provider::Source\n        expect(provider_source.options).to be_empty\n      }.to_not raise_error\n    end\n\n    specify \"Class-based source doesn't use provider_source_options\" do\n      system.register_provider(:test, source: custom_source)\n\n      expect {\n        provider_source = system.providers[:test].source\n        expect(provider_source.class).to be < Dry::System::Provider::Source\n        expect(provider_source.options).to be_empty\n      }.to_not raise_error\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/providers/multiple_provider_dirs_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Providers / Multiple provider dirs\" do\n  specify \"Resolving provider files from multiple provider dirs\" do\n    module Test\n      class Container < Dry::System::Container\n        config.root = SPEC_ROOT.join(\"fixtures/multiple_provider_dirs\").realpath\n\n        config.provider_dirs = [\n          \"custom_bootables\", # Relative paths are appended to the container root\n          SPEC_ROOT.join(\"fixtures/multiple_provider_dirs/default_bootables\")\n        ]\n      end\n    end\n\n    expect(Test::Container[:inflector]).to eq \"default_inflector\"\n    expect(Test::Container[:logger]).to eq \"custom_logger\"\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/providers/provider_sources/provider_options_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Providers / Provider sources / Provider options\" do\n  let(:container) { Class.new(Dry::System::Container) }\n\n  specify \"provider_options registered with provider sources are used when creating corresponding providers\" do\n    Dry::System.register_provider_source(:db, group: :my_framework, provider_options: {namespace: true}) do\n      start do\n        register \"config\", \"db_config_here\"\n      end\n    end\n\n    # Note no `namespace:` option when registering provider\n    container.register_provider :db, from: :my_framework\n\n    # Also works when using a different name for the provider\n    container.register_provider :my_db, from: :my_framework, source: :db\n\n    container.start :db\n    container.start :my_db\n\n    expect(container[\"db.config\"]).to eq \"db_config_here\"\n    expect(container[\"my_db.config\"]).to eq \"db_config_here\"\n  end\n\n  specify \"provider source provider_options can be overridden\" do\n    Dry::System.register_provider_source(:db, group: :my_framework, provider_options: {namespace: true}) do\n      start do\n        register \"config\", \"db_config_here\"\n      end\n    end\n\n    container.register_provider :db, from: :my_framework, namespace: \"custom_db\"\n\n    container.start :db\n\n    expect(container[\"custom_db.config\"]).to eq \"db_config_here\"\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/providers/registering_components_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Providers / Registering components\" do\n  specify \"Components registered with blocks in a provider are resolved as new objects each time in the target container\" do\n    module Test\n      class Thing; end\n    end\n\n    container = Class.new(Dry::System::Container) do\n      register_provider :thing, namespace: true do\n        start do\n          register :via_block do\n            Test::Thing.new\n          end\n\n          register :direct, Test::Thing.new\n        end\n      end\n    end\n\n    container.start :thing\n\n    thing_via_block_1 = container[\"thing.via_block\"]\n    thing_via_block_2 = container[\"thing.via_block\"]\n\n    thing_direct_1 = container[\"thing.direct\"]\n    thing_direct_2 = container[\"thing.direct\"]\n\n    expect(thing_via_block_1).to be_an_instance_of(thing_via_block_2.class)\n    expect(thing_via_block_1).not_to be thing_via_block_2\n\n    expect(thing_direct_1).to be thing_direct_2\n  end\n\n  specify \"Components registered with options in a provider have those options set on the target container\" do\n    container = Class.new(Dry::System::Container) do\n      register_provider :thing do\n        start do\n          register :thing, memoize: true do\n            Object.new\n          end\n        end\n      end\n    end\n\n    container.start :thing\n\n    thing_1 = container[\"thing\"]\n    thing_2 = container[\"thing\"]\n\n    expect(thing_2).to be thing_1\n  end\n\n  specify \"Components registered with keys that are already used on the target container are not applied\" do\n    container = Class.new(Dry::System::Container) do\n      register_provider :thing, namespace: true do\n        start do\n          register :first, Object.new\n          register :second, Object.new\n        end\n      end\n    end\n\n    already_registered = Object.new\n    container.register \"thing.second\", already_registered\n\n    container.start :thing\n\n    expect(container[\"thing.first\"]).to be\n    expect(container[\"thing.second\"]).to be already_registered\n  end\nend\n"
  },
  {
    "path": "spec/integration/container/providers/resolving_root_key_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"Providers / Resolving components with same root key as a running provider\" do\n  before :context do\n    @dir = make_tmp_directory\n\n    with_directory(@dir) do\n      write \"lib/animals/cat.rb\", <<~RUBY\n        module Test\n          module Animals\n            class Cat\n              include Deps[\"animals.collar\"]\n            end\n          end\n        end\n      RUBY\n\n      write \"lib/animals/collar.rb\", <<~RUBY\n        module Test\n          module Animals\n            class Collar; end\n          end\n        end\n      RUBY\n\n      write \"system/providers/animals.rb\", <<~RUBY\n        Test::Container.register_provider :animals, namespace: true do\n          start do\n            require \"animals/cat\"\n            register :cat, Test::Animals::Cat.new\n          end\n        end\n      RUBY\n    end\n  end\n\n  before do\n    root = @dir\n    Test::Container = Class.new(Dry::System::Container) do\n      configure do |config|\n        config.root = root\n        config.component_dirs.add \"lib\" do |dir|\n          dir.namespaces.add_root const: \"test\"\n        end\n      end\n    end\n\n    Test::Deps = Test::Container.injector\n  end\n\n  context \"lazy loading\" do\n    it \"resolves the component without attempting to re-run provider steps\" do\n      expect(Test::Container[\"animals.cat\"]).to be\n    end\n  end\n\n  context \"finalized\" do\n    before do\n      Test::Container.finalize!\n    end\n\n    it \"resolves the component without attempting to re-run provider steps\" do\n      expect(Test::Container[\"animals.cat\"]).to be\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/did_you_mean_integration_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"ostruct\"\n\nRSpec.describe \"DidYouMean integration\" do\n  subject(:system) { Test::Container }\n\n  context \"with a file with a syntax error in it\" do\n    before do\n      class Test::Container < Dry::System::Container\n        use :zeitwerk\n\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").join(\"components_with_errors\").realpath\n          config.component_dirs.add \"test\"\n        end\n      end\n    end\n\n    it \"auto-boots dependency of a bootable component\" do\n      expect { system[\"constant_error\"] }\n        .to raise_error(NameError, \"uninitialized constant ConstantError::NotHere\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/external_components_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe \"External Components\" do\n  before do\n    Object.send(:remove_const, :ExternalComponents) if defined? ExternalComponents\n  end\n  subject(:container) do\n    module Test\n      class Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/app\").realpath\n        end\n\n        register_provider(:logger, from: :external_components)\n\n        register_provider(:my_logger, from: :external_components, source: :logger) do\n          configure do |config|\n            config.log_level = :debug\n          end\n\n          after(:start) do\n            register(:my_logger, container[:logger])\n          end\n        end\n\n        register_provider(:notifier, from: :external_components)\n\n        register_provider(:mailer, from: :external_components)\n\n        register(:monitor, \"a monitor\")\n      end\n    end\n\n    Test::Container\n  end\n\n  before do\n    require SPEC_ROOT.join(\"fixtures/external_components/lib/external_components\")\n  end\n\n  context \"with default behavior\" do\n    it \"boots external logger component\" do\n      container.finalize!\n\n      expect(container[:logger]).to be_instance_of(ExternalComponents::Logger)\n    end\n\n    it \"boots external logger component with customized booting process\" do\n      container.finalize!\n\n      my_logger = container[:my_logger]\n\n      expect(my_logger).to be_instance_of(ExternalComponents::Logger)\n      expect(my_logger.log_level).to eq(:debug)\n    end\n\n    it \"boots external notifier component which needs a local component\" do\n      container.finalize!\n\n      notifier = container[:notifier]\n\n      expect(notifier.monitor).to be(container[:monitor])\n    end\n\n    it \"boots external mailer component which needs a local bootable component\" do\n      container.finalize!\n\n      mailer = container[:mailer]\n\n      expect(mailer.client).to be(container[:client])\n    end\n  end\n\n  context \"with customized booting\" do\n    it \"allows aliasing external components\" do\n      container.register_provider(:error_logger, from: :external_components, source: :logger) do\n        after(:start) do\n          register(:error_logger, container[:logger])\n        end\n      end\n\n      container.finalize!\n\n      expect(container[:error_logger]).to be_instance_of(ExternalComponents::Logger)\n    end\n\n    it \"allows calling :prepare manually\" do\n      container.register_provider(:error_logger, from: :external_components, source: :logger) do\n        after(:prepare) do\n          ExternalComponents::Logger.default_level = :error\n        end\n\n        after(:start) do\n          register(:error_logger, container[:logger])\n        end\n      end\n\n      container.prepare(:error_logger)\n\n      expect(container[:error_logger]).to be_instance_of(ExternalComponents::Logger)\n      expect(container[:error_logger].class.default_level).to be(:error)\n    end\n  end\n\n  context \"customized registration from an alternative provider\" do\n    subject(:container) do\n      Class.new(Dry::System::Container) do\n        register_provider(:logger, from: :external_components)\n\n        register_provider(:conn, from: :alt, source: :db) do\n          after(:start) do\n            register(:conn, container[:db_conn])\n          end\n        end\n      end\n    end\n\n    before do\n      require SPEC_ROOT.join(\"fixtures/external_components/lib/external_components\")\n    end\n\n    context \"with default behavior\" do\n      it \"boots external logger component from the specified provider\" do\n        container.finalize!\n\n        expect(container[:logger]).to be_instance_of(ExternalComponents::Logger)\n        expect(container[:conn]).to be_instance_of(AltComponents::DbConn)\n      end\n\n      it \"lazy-boots external logger components\" do\n        expect(container[:logger]).to be_instance_of(ExternalComponents::Logger)\n      end\n    end\n  end\n\n  it \"raises an error when specifying an unknown provider sourse\" do\n    msgs = [\n      \"Provider source not found: :logger, group: :not_found_components\",\n      \"Available provider sources:\",\n      \"- :logger, group: :external_components\"\n    ]\n    error_re = /#{msgs.join(\".*\")}/m\n\n    expect {\n      Class.new(Dry::System::Container) {\n        register_provider(:logger, from: :not_found_components)\n      }\n    }.to raise_error Dry::System::ProviderSourceNotFoundError, error_re\n  end\nend\n"
  },
  {
    "path": "spec/integration/import_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/stubs\"\n\nRSpec.describe \"Lazy-booting external deps\" do\n  before do\n    module Test\n      class Umbrella < Dry::System::Container\n        configure do |config|\n          config.name = :core\n          config.root = SPEC_ROOT.join(\"fixtures/umbrella\").realpath\n        end\n      end\n\n      class App < Dry::System::Container\n        configure do |config|\n          config.name = :main\n        end\n      end\n    end\n  end\n\n  shared_examples_for \"lazy booted dependency\" do\n    it \"lazy boots an external dep provided by top-level container\" do\n      expect(user_repo.repo).to be_instance_of(Db::Repo)\n    end\n\n    it \"loads an external dep during finalization\" do\n      system.finalize!\n      expect(user_repo.repo).to be_instance_of(Db::Repo)\n    end\n  end\n\n  context \"when top-level container provides the dependency\" do\n    let(:user_repo) do\n      Class.new { include Test::Import[\"db.repo\"] }.new\n    end\n\n    let(:system) { Test::Umbrella }\n\n    before do\n      module Test\n        Umbrella.import(from: App, as: :main)\n        Import = Umbrella.injector\n      end\n    end\n\n    it_behaves_like \"lazy booted dependency\"\n\n    context \"when stubs are enabled\" do\n      before do\n        system.enable_stubs!\n      end\n\n      it_behaves_like \"lazy booted dependency\"\n    end\n  end\n\n  context \"when top-level container provides the dependency through import\" do\n    let(:user_repo) do\n      Class.new { include Test::Import[\"core.db.repo\"] }.new\n    end\n\n    let(:system) { Test::App }\n\n    before do\n      module Test\n        App.import(from: Umbrella, as: :core)\n        Import = App.injector\n      end\n    end\n\n    it_behaves_like \"lazy booted dependency\"\n\n    context \"when stubs are enabled\" do\n      before do\n        system.enable_stubs!\n      end\n\n      it_behaves_like \"lazy booted dependency\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/settings_component_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/provider_sources\"\n\nRSpec.describe \"Settings component\" do\n  subject(:system) do\n    Class.new(Dry::System::Container) do\n      setting :env\n\n      configure do |config|\n        config.root = SPEC_ROOT.join(\"fixtures\").join(\"settings_test\")\n        config.env = :test\n      end\n\n      register_provider(:settings, from: :dry_system) do\n        before(:prepare) do\n          target_container.require_from_root \"types\"\n        end\n\n        settings do\n          setting :database_url, constructor: SettingsTest::Types::String.constrained(filled: true)\n          setting :session_secret, constructor: SettingsTest::Types::String.constrained(filled: true)\n        end\n      end\n    end\n  end\n\n  let(:settings) do\n    system[:settings]\n  end\n\n  before do\n    ENV[\"DATABASE_URL\"] = \"sqlite::memory\"\n  end\n\n  after do\n    ENV.delete(\"DATABASE_URL\")\n  end\n\n  it \"sets up system settings component via ENV and .env\" do\n    expect(settings.database_url).to eql(\"sqlite::memory\")\n    expect(settings.session_secret).to eql(\"super-secret\")\n  end\n\n  context \"Invalid setting value\" do\n    subject(:system) do\n      Class.new(Dry::System::Container) do\n        setting :env\n\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").join(\"settings_test\")\n          config.env = :test\n        end\n\n        register_provider(:settings, from: :dry_system) do\n          before(:prepare) do\n            target_container.require_from_root \"types\"\n          end\n\n          settings do\n            setting :integer_value, constructor: SettingsTest::Types::Integer\n            setting :coercible_value, constructor: SettingsTest::Types::Coercible::Integer\n          end\n        end\n      end\n    end\n\n    before do\n      ENV[\"INTEGER_VALUE\"] = \"foo\"\n      ENV[\"COERCIBLE_VALUE\"] = \"foo\"\n    end\n\n    after do\n      ENV.delete(\"INTEGER_VALUE\")\n      ENV.delete(\"COERCIBLE_VALUE\")\n    end\n\n    it \"raises InvalidSettingsError with meaningful message\" do\n      expect {\n        settings.integer_value\n      }.to raise_error(\n        Dry::System::ProviderSources::Settings::InvalidSettingsError,\n        <<~TEXT\n          Could not load settings. The following settings were invalid:\n\n          coercible_value: invalid value for Integer(): \"foo\"\n          integer_value: \"foo\" violates constraints (type?(Integer, \"foo\") failed)\n        TEXT\n      )\n    end\n  end\n\n  context \"Missing setting value\" do\n    subject(:system) do\n      Class.new(Dry::System::Container) do\n        setting :env\n\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").join(\"settings_test\")\n          config.env = :test\n        end\n\n        register_provider(:settings, from: :dry_system) do\n          before(:prepare) do\n            target_container.require_from_root \"types\"\n          end\n\n          settings do\n            setting :missing_value_designated_optional, constructor: SettingsTest::Types::String.optional\n            setting :missing_value_with_default, constructor: SettingsTest::Types::String, default: \"blah\"\n            setting :missing_value_without_default, constructor: SettingsTest::Types::String\n          end\n        end\n      end\n    end\n\n    it \"raises InvalidSettingsError with meaningful message for settings where the constructor cannot accept nil\" do\n      expect {\n        settings.to_h\n      }.to raise_error(\n        Dry::System::ProviderSources::Settings::InvalidSettingsError,\n        <<~TEXT\n          Could not load settings. The following settings were invalid:\n\n          missing_value_without_default: nil violates constraints (type?(String, nil) failed)\n        TEXT\n      )\n    end\n  end\n\n  context \"With default values\" do\n    subject(:system) do\n      Class.new(Dry::System::Container) do\n        setting :env\n\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").join(\"settings_test\")\n          config.env = :test\n        end\n\n        register_provider(:settings, from: :dry_system) do\n          after(:prepare) do\n            target_container.require_from_root \"types\"\n          end\n\n          settings do\n            setting :number_of_workers, default: 14, constructor: SettingsTest::Types::Coercible::Integer\n          end\n        end\n      end\n    end\n\n    it \"uses the default value\" do\n      expect(settings.number_of_workers).to eql(14)\n    end\n\n    context \"ENV variables take precedence before defaults\" do\n      before do\n        ENV[\"NUMBER_OF_WORKERS\"] = \"4\"\n      end\n\n      after do\n        ENV.delete(\"NUMBER_OF_WORKERS\")\n      end\n\n      it \"uses the ENV value\" do\n        expect(settings.number_of_workers).to eql(4)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"bundler/setup\"\n\nrequire \"pathname\"\nrequire \"warning\"\n\nbegin\n  require \"byebug\"\n  require \"pry-byebug\"\nrescue LoadError;\nend\n\nSPEC_ROOT = Pathname(__dir__)\n\nDir[SPEC_ROOT.join(\"support\", \"**\", \"*.rb\")].each { |f| require f }\nDir[SPEC_ROOT.join(\"shared\", \"**\", \"*.rb\")].each { |f| require f }\n\nrequire \"dry/system\"\nrequire \"dry/system/stubs\"\nrequire \"dry/events\"\nrequire \"dry/types\"\n\n# For specs that rely on `settings` DSL\nmodule Types\n  include Dry::Types()\nend\n\nRSpec.configure do |config|\n  config.after do\n    Dry::System.provider_sources.sources.delete_if { |k, _| k[:group] != :dry_system }\n  end\nend\n"
  },
  {
    "path": "spec/support/coverage.rb",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nif ENV[\"COVERAGE\"] == \"true\"\n  require \"simplecov\"\n  require \"simplecov-cobertura\"\n\n  SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter\n\n  SimpleCov.start do\n    add_filter \"/spec/\"\n    enable_coverage :branch\n  end\nend\n"
  },
  {
    "path": "spec/support/loaded_constants_cleaning.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"tmpdir\"\n\nmodule TestCleanableNamespace\n  def remove_constants\n    constants.each do |name|\n      remove_const(name)\n    end\n  end\nend\n\nRSpec.shared_context \"Loaded constants cleaning\" do\n  let(:cleanable_modules) { %i[Test] }\n  let(:cleanable_constants) { [] }\nend\n\nRSpec.configure do |config|\n  config.include_context \"Loaded constants cleaning\"\n\n  config.before do\n    @load_path = $LOAD_PATH.dup\n    @loaded_features = $LOADED_FEATURES.dup\n\n    cleanable_modules.each do |mod|\n      if Object.const_defined?(mod)\n        Object.const_get(mod).extend(TestCleanableNamespace)\n      else\n        Object.const_set(mod, Module.new { |m| m.extend(TestCleanableNamespace) })\n      end\n    end\n  end\n\n  config.after do\n    $LOAD_PATH.replace(@load_path)\n\n    # We want to delete only newly loaded features within spec/, otherwise we're removing\n    # files that may have been additionally loaded for rspec et al\n    new_features_to_keep = ($LOADED_FEATURES - @loaded_features).tap do |feats|\n      feats.delete_if { |path| path.include?(SPEC_ROOT.to_s) || path.include?(Dir.tmpdir) }\n    end\n    $LOADED_FEATURES.replace(@loaded_features + new_features_to_keep)\n\n    cleanable_modules.each do |mod|\n      next unless Object.const_defined?(mod)\n\n      Object.const_get(mod).remove_constants\n      Object.send :remove_const, mod\n    end\n\n    cleanable_constants.each do |const|\n      Object.send :remove_const, const if Object.const_defined?(const)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/support/rspec.rb",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nRSpec.configure do |config|\n  # When no filter given, search and run focused tests\n  config.filter_run_when_matching :focus\n\n  # Disables rspec monkey patches (no reason for their existence tbh)\n  config.disable_monkey_patching!\n\n  # Run ruby in verbose mode\n  config.warnings = true\n\n  # Collect all failing expectations automatically,\n  # without calling aggregate_failures everywhere\n  config.define_derived_metadata do |meta|\n    meta[:aggregate_failures] = true\n  end\n\n  if ENV[\"CI\"]\n    # No focused specs should be committed. This ensures\n    # builds fail when this happens.\n    config.before(:each, :focus) do\n      raise StandardError, \"You've committed a focused spec!\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/support/tmp_directory.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"fileutils\"\nrequire \"pathname\"\nrequire \"tmpdir\"\n\nmodule RSpec\n  module Support\n    module TmpDirectory\n      private\n\n      def with_tmp_directory(&)\n        with_directory(make_tmp_directory, &)\n      end\n\n      def with_directory(dir, &)\n        Dir.chdir(dir, &)\n      end\n\n      def make_tmp_directory\n        Pathname(::Dir.mktmpdir).tap do |dir|\n          (@made_tmp_dirs ||= []) << dir\n        end\n      end\n\n      def write(path, *content)\n        ::Pathname.new(path).dirname.mkpath\n\n        File.open(path, ::File::CREAT | ::File::WRONLY) do |file|\n          file.write(Array(content).flatten.join)\n        end\n      end\n    end\n  end\nend\n\nRSpec.configure do |config|\n  config.include RSpec::Support::TmpDirectory\n\n  config.after :all do\n    if instance_variable_defined?(:@made_tmp_dirs)\n      Array(@made_tmp_dirs).each do |dir|\n        FileUtils.remove_entry dir\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/support/warnings.rb",
    "content": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nrequire \"warning\"\n\n# Ignore warnings for experimental features\nWarning[:experimental] = false if Warning.respond_to?(:[])\n\n# Ignore all warnings coming from gem dependencies\nGem.path.each do |path|\n  Warning.ignore(//, path)\nend\n"
  },
  {
    "path": "spec/support/zeitwerk_loader_registry.rb",
    "content": "# frozen_string_literal: true\n\nmodule ZeitwerkLoaderRegistry\n  class << self\n    def new_loader\n      Zeitwerk::Loader.new.tap do |loader|\n        loaders << loader\n      end\n    end\n\n    def clear\n      loaders.each do |loader|\n        loader.unregister\n      end\n    end\n\n    private\n\n    def loaders\n      @loaders ||= []\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/auto_registrar_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/auto_registrar\"\nrequire \"dry/system/errors\"\n\nRSpec.describe Dry::System::AutoRegistrar, \"#finalize!\" do\n  let(:auto_registrar) { described_class.new(container) }\n\n  let(:container) {\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = SPEC_ROOT.join(\"fixtures\").realpath\n        config.component_dirs.add \"components\" do |dir|\n          dir.namespaces.add \"test\", key: nil\n        end\n      end\n    }\n  }\n\n  it \"registers components in the configured component dirs\" do\n    auto_registrar.finalize!\n\n    expect(container[\"foo\"]).to be_an_instance_of(Test::Foo)\n    expect(container[\"bar\"]).to be_an_instance_of(Test::Bar)\n    expect(container[\"bar.baz\"]).to be_an_instance_of(Test::Bar::Baz)\n\n    expect { container[\"bar.abc\"] }.to raise_error(\n      Dry::System::ComponentNotLoadableError\n    ).with_message(\n      <<~ERROR_MESSAGE\n        Component 'bar.abc' is not loadable.\n        Looking for Test::Bar::Abc.\n\n        You likely need to add:\n\n            acronym('ABC')\n\n        to your container's inflector, since we found a Test::Bar::ABC class.\n      ERROR_MESSAGE\n    )\n  end\n\n  it \"doesn't re-register components previously registered via lazy loading\" do\n    expect(container[\"foo\"]).to be_an_instance_of(Test::Foo)\n\n    expect { auto_registrar.finalize! }.not_to raise_error\n\n    expect(container[\"bar\"]).to be_an_instance_of(Test::Bar)\n    expect(container[\"bar.baz\"]).to be_an_instance_of(Test::Bar::Baz)\n  end\nend\n"
  },
  {
    "path": "spec/unit/component_dir/component_for_identifier_key.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/component_dir\"\nrequire \"dry/system/config/component_dir\"\nrequire \"dry/system/container\"\n\nRSpec.describe Dry::System::ComponentDir, \"#component_for_key\" do\n  subject(:component) { component_dir.component_for_key(key) }\n\n  let(:component_dir) {\n    Dry::System::ComponentDir.new(\n      config: Dry::System::Config::ComponentDir.new(\"component_dir_1\") { |config|\n        config.namespaces.add \"namespace\", key: nil\n        component_dir_options.each do |key, val|\n          config.send :\"#{key}=\", val\n        end\n      },\n      container: container\n    )\n  }\n  let(:component_dir_options) { {} }\n  let(:container) {\n    container_root = root\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = container_root\n      end\n    }\n  }\n  let(:root) { SPEC_ROOT.join(\"fixtures/unit/component\").realpath }\n\n  context \"component file located\" do\n    let(:key) { \"nested.component_file\" }\n\n    it \"returns a component\" do\n      expect(component).to be_a Dry::System::Component\n    end\n\n    it \"has a matching key\" do\n      expect(component.key).to eq key\n    end\n\n    it \"has the component dir's namespace\" do\n      expect(component.namespace.path).to eq \"namespace\"\n    end\n\n    context \"options given as component dir config\" do\n      let(:component_dir_options) { {memoize: true} }\n\n      it \"has the component dir's options\" do\n        expect(component.memoize?).to be true\n      end\n    end\n\n    context \"options given as magic comments in file\" do\n      let(:key) { \"nested.component_file_with_auto_register_false\" }\n\n      it \"loads options specified within the file's magic comments\" do\n        expect(component.options).to include(auto_register: false)\n      end\n    end\n\n    context \"options given as both component dir config and as magic comments in file\" do\n      let(:component_dir_options) { {auto_register: true} }\n      let(:key) { \"nested.component_file_with_auto_register_false\" }\n\n      it \"prefers the options specified as magic comments\" do\n        expect(component.options).to include(auto_register: false)\n      end\n    end\n  end\n\n  context \"component file not located\" do\n    let(:key) { \"nested.missing_component\" }\n\n    it \"returns nil\" do\n      expect(component).to be_nil\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/component_dir/each_component_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/component_dir\"\nrequire \"dry/system/config/component_dir\"\nrequire \"dry/system/container\"\n\nRSpec.describe Dry::System::ComponentDir, \"#each_component\" do\n  subject(:components) { component_dir.each_component.to_a }\n\n  let(:component_dir) {\n    described_class.new(\n      config: Dry::System::Config::ComponentDir.new(@dir.join(\"lib\")) { |config|\n        component_dir_config.(config) if defined?(component_dir_config)\n      },\n      container: container\n    )\n  }\n\n  let(:container) {\n    container_root = @dir\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = container_root\n      end\n    }\n  }\n\n  before :all do\n    @dir = make_tmp_directory\n\n    with_directory(@dir) do\n      write \"lib/test/component_file.rb\"\n\n      write \"lib/test/component_file_with_auto_register_true.rb\", <<~RUBY\n        # auto_register: false\n      RUBY\n\n      write \"lib/outside_namespace/component_file.rb\"\n    end\n  end\n\n  it \"finds the components\" do\n    expect(components.length).to eq 3\n  end\n\n  it \"returns components as Dry::System::Component\" do\n    expect(components).to all be_a Dry::System::Component\n  end\n\n  it \"yields the components when called with a block\" do\n    expect { |b| component_dir.each_component(&b) }.to yield_successive_args(\n      an_object_satisfying { |c| c.is_a?(Dry::System::Component) },\n      an_object_satisfying { |c| c.is_a?(Dry::System::Component) },\n      an_object_satisfying { |c| c.is_a?(Dry::System::Component) }\n    )\n  end\n\n  it \"prepares a matching key for each component\" do\n    expect(components.map(&:key)).to eq %w[\n      outside_namespace.component_file\n      test.component_file\n      test.component_file_with_auto_register_true\n    ]\n  end\n\n  context \"component options given as component dir config\" do\n    let(:component_dir_config) {\n      -> config {\n        config.memoize = true\n      }\n    }\n\n    it \"includes the options with all components\" do\n      expect(components).to all satisfy(&:memoize?)\n    end\n  end\n\n  context \"component options given as magic comments\" do\n    let(:component) {\n      components.detect { |c| c.key == \"test.component_file_with_auto_register_true\" }\n    }\n\n    it \"loads the options specified within the magic comments\" do\n      expect(component.options).to include(auto_register: false)\n    end\n  end\n\n  context \"component options given as both component dir config and magic comments\" do\n    let(:component_dir_config) {\n      -> config {\n        config.auto_register = true\n      }\n    }\n\n    let(:component) {\n      components.detect { |c| c.key == \"test.component_file_with_auto_register_true\" }\n    }\n\n    it \"prefers the options given as magic comments\" do\n      expect(component.options).to include(auto_register: false)\n    end\n  end\n\n  context \"namespaces configured\" do\n    let(:component_dir_config) {\n      -> config {\n        config.namespaces.add \"test\", key: nil\n      }\n    }\n\n    it \"loads the components in the order of the configured namespaces\" do\n      expect(components.map(&:key)).to eq %w[\n        component_file\n        component_file_with_auto_register_true\n        outside_namespace.component_file\n      ]\n    end\n\n    it \"provides the namespace to each component\" do\n      expect(components[0].namespace.path).to eq \"test\"\n      expect(components[1].namespace.path).to eq \"test\"\n      expect(components[2].namespace.path).to be nil\n    end\n  end\n\n  context \"clashing component names in multiple namespaces\" do\n    before :all do\n      @dir = make_tmp_directory\n    end\n\n    before :all do\n      with_directory(@dir) do\n        write \"lib/ns1/component_file.rb\"\n        write \"lib/ns2/component_file.rb\"\n      end\n    end\n\n    let(:component_dir_config) {\n      -> config {\n        config.namespaces.add \"ns1\", key: nil\n        config.namespaces.add \"ns2\", key: nil\n      }\n    }\n\n    it \"returns all components, in order of configured namespaces, even with clashing keys\" do\n      expect(components.map(&:key)).to eq %w[\n        component_file\n        component_file\n      ]\n\n      expect(components[0].namespace.path).to eq \"ns1\"\n      expect(components[1].namespace.path).to eq \"ns2\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/component_dir_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/component_dir\"\n\nrequire \"dry/system/container\"\nrequire \"dry/system/config/component_dir\"\n\nRSpec.describe Dry::System::ComponentDir do\n  subject(:component_dir) { described_class.new(config: config, container: container) }\n\n  let(:config) { Dry::System::Config::ComponentDir.new(dir_path) }\n  let(:dir_path) { \"component_dir\" }\n  let(:container) {\n    container_root = root\n\n    Class.new(Dry::System::Container) {\n      configure do |config|\n        config.root = container_root\n      end\n    }\n  }\n  let(:root) { SPEC_ROOT.join(\"fixtures/unit\").realpath }\n\n  describe \"config\" do\n    it \"delegates config methods to the config\" do\n      expect(component_dir.path).to eql config.path\n      expect(component_dir.auto_register).to eql config.auto_register\n      expect(component_dir.add_to_load_path).to eql config.add_to_load_path\n    end\n\n    # TODO\n    xit \"provides a default root namespace if none is specified\"\n  end\nend\n"
  },
  {
    "path": "spec/unit/component_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/component\"\nrequire \"dry/system/identifier\"\nrequire \"dry/system/loader\"\nrequire \"dry/system/config/namespace\"\n\nRSpec.describe Dry::System::Component do\n  subject(:component) {\n    described_class.new(\n      identifier,\n      file_path: file_path,\n      namespace: namespace,\n      loader: loader\n    )\n  }\n\n  let(:identifier) { Dry::System::Identifier.new(\"test.foo\") }\n  let(:file_path) { \"/path/to/test/foo.rb\" }\n  let(:namespace) { Dry::System::Config::Namespace.default_root }\n  let(:loader) { class_spy(Dry::System::Loader) }\n\n  it \"is loadable\" do\n    expect(component).to be_loadable\n  end\n\n  describe \"#identifier\" do\n    it \"is the given identifier\" do\n      expect(component.identifier).to be identifier\n    end\n  end\n\n  describe \"#key\" do\n    it \"returns the identifier's key\" do\n      expect(component.key).to eq \"test.foo\"\n    end\n  end\n\n  describe \"#root_key\" do\n    it \"returns the identifier's root_key\" do\n      expect(component.root_key).to eq :test\n    end\n  end\n\n  describe \"#instance\" do\n    it \"builds and returns an instance via the loader\" do\n      loaded_instance = double(:instance)\n      allow(loader).to receive(:call).with(component) { loaded_instance }\n\n      expect(component.instance).to eql loaded_instance\n    end\n\n    it \"forwards additional arguments to the loader\" do\n      loaded_instance = double(:instance)\n      allow(loader).to receive(:call).with(component, \"extra\", \"args\") { loaded_instance }\n\n      expect(component.instance(\"extra\", \"args\")).to eql loaded_instance\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/config/component_dirs_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/config/component_dirs\"\nrequire \"dry/system/config/component_dir\"\n\nRSpec.describe Dry::System::Config::ComponentDirs do\n  subject(:component_dirs) { described_class.new }\n\n  describe \"#dir\" do\n    it \"returns the added dir for the given path\" do\n      dir = component_dirs.add(\"test/path\")\n      expect(component_dirs.dir(\"test/path\")).to be dir\n    end\n\n    it \"yields the dir\" do\n      dir = component_dirs.add(\"test/path\")\n      expect { |b| component_dirs.dir(\"test/path\", &b) }.to yield_with_args dir\n    end\n\n    it \"applies global default values configured before retrieval\" do\n      component_dirs.add(\"test/path\")\n      component_dirs.namespaces.add \"global_default\"\n      expect(component_dirs.dir(\"test/path\").namespaces.paths).to eq [\"global_default\"]\n    end\n\n    it \"returns nil when no dir was added for the given path\" do\n      expect(component_dirs.dir(\"test/path\")).to be nil\n    end\n  end\n\n  describe \"#[]\" do\n    it \"returns the added dir for the given path\" do\n      dir = component_dirs.add(\"test/path\")\n      expect(component_dirs[\"test/path\"]).to be dir\n    end\n\n    it \"yields the dir\" do\n      dir = component_dirs.add(\"test/path\")\n      expect { |b| component_dirs[\"test/path\", &b] }.to yield_with_args dir\n    end\n\n    it \"applies global default values configured before retrieval\" do\n      component_dirs.add(\"test/path\")\n      component_dirs.namespaces.add \"global_default\"\n      expect(component_dirs[\"test/path\"].namespaces.paths).to eq [\"global_default\"]\n    end\n\n    it \"returns nil when no dir was added for the given path\" do\n      expect(component_dirs[\"test/path\"]).to be nil\n    end\n  end\n\n  describe \"#add\" do\n    it \"adds a component dir by path, with config set on a yielded dir\" do\n      expect {\n        component_dirs.add \"test/path\" do |dir|\n          dir.auto_register = false\n          dir.add_to_load_path = false\n        end\n      }\n        .to change { component_dirs.length }\n        .from(0).to(1)\n\n      dir = component_dirs[\"test/path\"]\n\n      expect(dir.path).to eq \"test/path\"\n      expect(dir.auto_register).to eq false\n      expect(dir.add_to_load_path).to eq false\n    end\n\n    it \"adds a pre-built component dir\" do\n      dir = Dry::System::Config::ComponentDir.new(\"test/path\").tap do |d|\n        d.auto_register = false\n        d.add_to_load_path = false\n      end\n\n      expect { component_dirs.add(dir) }\n        .to change { component_dirs.length }\n        .from(0).to(1)\n\n      expect(component_dirs[\"test/path\"]).to be dir\n    end\n\n    it \"raises an error when a component dir has already been added for the given path\" do\n      component_dirs.add \"test/path\"\n      expect { component_dirs.add \"test/path\" }.to raise_error(Dry::System::ComponentDirAlreadyAddedError, %r{test/path})\n    end\n\n    it \"raises an error when a component dir has already been added for the given dir's path\" do\n      component_dirs.add \"test/path\"\n      expect {\n        component_dirs.add Dry::System::Config::ComponentDir.new(\"test/path\")\n      }\n        .to raise_error(Dry::System::ComponentDirAlreadyAddedError, %r{test/path})\n    end\n\n    it \"applies default values configured before adding\" do\n      component_dirs.namespaces.add \"global_default\"\n\n      component_dirs.add \"test/path\"\n\n      dir = component_dirs[\"test/path\"]\n      expect(dir.namespaces.to_a.map(&:path)).to eq [\"global_default\", nil]\n    end\n\n    it \"does not apply default values over the component dir's own config\" do\n      component_dirs.namespaces.add \"global_default\"\n      component_dirs.memoize = true\n\n      component_dirs.add \"test/path\" do |dir|\n        dir.namespaces.add_root # force the default value\n        dir.memoize = false\n      end\n\n      dir = component_dirs[\"test/path\"]\n\n      expect(dir.namespaces.to_a.map(&:path)).to eq [nil]\n      expect(dir.memoize).to be false\n    end\n  end\n\n  describe \"#delete\" do\n    it \"deletes and returns the component dir for the given path\" do\n      added_dir = component_dirs.add(\"test/path\")\n\n      deleted_dir = nil\n      expect { deleted_dir = component_dirs.delete(\"test/path\") }\n        .to change { component_dirs.length }\n        .from(1).to(0)\n\n      expect(deleted_dir).to be added_dir\n    end\n\n    it \"returns nil when no component dir has been added for the given path\" do\n      expect(component_dirs.delete(\"test/path\")).to be nil\n      expect(component_dirs.length).to eq 0\n    end\n  end\n\n  describe \"#length\" do\n    it \"returns the count of component dirs\" do\n      component_dirs.add \"test/path_1\"\n      component_dirs.add \"test/path_2\"\n      expect(component_dirs.length).to eq 2\n    end\n\n    it \"returns 0 when there are no configured component dirs\" do\n      expect(component_dirs.length).to eq 0\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/config/namespaces_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/config/namespaces\"\nrequire \"dry/system/config/namespace\"\n\nRSpec.describe Dry::System::Config::Namespaces do\n  subject(:namespaces) { described_class.new }\n\n  describe \"#namespace\" do\n    it \"returns the previously configured namespace for the given path\" do\n      added_namespace = namespaces.add \"test/path\", key: \"key_ns\", const: \"const_ns\"\n\n      expect(namespaces.namespace(\"test/path\")).to be added_namespace\n    end\n\n    it \"returns nil when no namepace was previously configured for the given path\" do\n      expect(namespaces.namespace(\"test/path\")).to be nil\n    end\n  end\n\n  describe \"#[]\" do\n    it \"returns the previously configured namespace for the given path\" do\n      added_namespace = namespaces.add \"test/path\", key: \"key_ns\", const: \"const_ns\"\n\n      expect(namespaces[\"test/path\"]).to be added_namespace\n    end\n\n    it \"returns nil when no namepace was previously configured for the given path\" do\n      expect(namespaces[\"test/path\"]).to be nil\n    end\n  end\n\n  describe \"#root\" do\n    it \"returns the previously configured root namespace\" do\n      added_root_namespace = namespaces.add_root\n\n      expect(namespaces.root).to be added_root_namespace\n    end\n\n    it \"returns nil when no root namespace was previously configured\" do\n      expect(namespaces.root).to be nil\n    end\n  end\n\n  describe \"#add\" do\n    it \"adds the namespace with the given configuration\" do\n      expect {\n        namespaces.add \"test/path\", key: \"key_ns\", const: \"const_ns\"\n      }\n        .to change { namespaces.length }\n        .from(0).to(1)\n\n      ns = namespaces.namespaces[\"test/path\"]\n\n      expect(ns.path).to eq \"test/path\"\n      expect(ns.key).to eq \"key_ns\"\n      expect(ns.const).to eq \"const_ns\"\n    end\n\n    it \"raises an exception when a namespace is already added\" do\n      namespaces.add \"test/path\"\n\n      expect { namespaces.add \"test/path\" }.to raise_error(Dry::System::NamespaceAlreadyAddedError, %r{test/path})\n    end\n  end\n\n  describe \"#add_root\" do\n    it \"adds a root namespace with the given configuration\" do\n      expect {\n        namespaces.add_root key: \"key_ns\", const: \"const_ns\"\n      }\n        .to change { namespaces.length }\n        .from(0).to(1)\n\n      ns = namespaces.namespaces[nil]\n\n      expect(ns).to be_root\n      expect(ns.path).to be_nil\n      expect(ns.key).to eq \"key_ns\"\n      expect(ns.const).to eq \"const_ns\"\n    end\n\n    it \"raises an exception when a root namespace is already added\" do\n      namespaces.add_root\n\n      expect { namespaces.add_root }.to raise_error(Dry::System::NamespaceAlreadyAddedError, /root path/)\n    end\n  end\n\n  describe \"#delete\" do\n    it \"deletes and returns the configured namespace for the given path\" do\n      added_namespace = namespaces.add \"test/path\"\n\n      deleted_namespace = nil\n      expect {\n        deleted_namespace = namespaces.delete(\"test/path\")\n      }\n        .to change { namespaces.length }\n        .from(1).to(0)\n\n      expect(deleted_namespace).to be added_namespace\n    end\n\n    it \"returns nil when no namespace has been configured for the given path\" do\n      expect(namespaces.delete(\"test/path\")).to be nil\n      expect(namespaces).to be_empty\n    end\n  end\n\n  describe \"#delete_root\" do\n    it \"deletes and returns the configured root namespace\" do\n      added_namespace = namespaces.add_root\n\n      deleted_namespace = nil\n      expect {\n        deleted_namespace = namespaces.delete_root\n      }\n        .to change { namespaces.length }\n        .from(1).to(0)\n\n      expect(deleted_namespace).to be added_namespace\n    end\n\n    it \"returns nil when no root namespace has been configured\" do\n      expect(namespaces.delete_root).to be nil\n      expect(namespaces).to be_empty\n    end\n  end\n\n  describe \"#length\" do\n    it \"returns the count of configured namespaces\" do\n      namespaces.add \"test/path_1\"\n      namespaces.add \"test/path_2\"\n      expect(namespaces.length).to eq 2\n    end\n\n    it \"returns 0 when there are no configured namespaces\" do\n      expect(namespaces.length).to eq 0\n    end\n  end\n\n  describe \"#empty?\" do\n    it \"returns true if there are no configured namespaces\" do\n      expect(namespaces).to be_empty\n    end\n\n    it \"returns false if a namespace has been added\" do\n      expect { namespaces.add \"test/path\" }\n        .to change { namespaces.empty? }\n        .from(true).to(false)\n    end\n  end\n\n  describe \"#to_a\" do\n    it \"returns an array of the configured namespaces, in order of definition\" do\n      namespaces.add \"test/path\", key: \"test_key_ns\"\n      namespaces.add_root key: \"root_key_ns\"\n\n      arr = namespaces.to_a\n\n      expect(arr.length).to eq 2\n\n      expect(arr[0].path).to eq \"test/path\"\n      expect(arr[0].key).to eq \"test_key_ns\"\n\n      expect(arr[1].path).to eq nil\n      expect(arr[1].key).to eq \"root_key_ns\"\n    end\n\n    it \"appends a default root namespace if not explicitly configured\" do\n      namespaces.add \"test/path\", key: \"test_key_ns\"\n\n      arr = namespaces.to_a\n\n      expect(arr.length).to eq 2\n\n      expect(arr[0].path).to eq \"test/path\"\n      expect(arr[0].key).to eq \"test_key_ns\"\n\n      expect(arr[1].path).to be nil\n      expect(arr[1].key).to be nil\n      expect(arr[1].const).to be nil\n    end\n\n    it \"includes a default root namespace if no namespaces configured\" do\n      arr = namespaces.to_a\n\n      expect(arr.length).to eq 1\n\n      expect(arr[0].path).to be nil\n      expect(arr[0].key).to be nil\n      expect(arr[0].const).to be nil\n    end\n  end\n\n  describe \"#each\" do\n    it \"yields each configured namespace\" do\n      namespaces.add \"test/path\", key: \"test_key_ns\"\n      namespaces.add_root key: \"root_key_ns\"\n\n      expect { |b|\n        namespaces.each(&b)\n      }.to yield_successive_args(\n        an_object_satisfying { |ns| ns.path == \"test/path\" },\n        an_object_satisfying(&:root?)\n      )\n    end\n  end\n\n  describe \"#dup\" do\n    it \"dups the registry of namespaces\" do\n      namespaces.add \"test/path\", key: \"test_key_ns\"\n\n      new_namespaces = namespaces.dup\n\n      expect(new_namespaces.to_a).to eq(namespaces.to_a)\n      expect(new_namespaces.namespaces).not_to be(namespaces.namespaces)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/auto_register_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\n\nRSpec.describe Dry::System::Container, \".auto_register!\" do\n  context \"standard loader\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").realpath\n          config.component_dirs.add \"components\" do |dir|\n            dir.namespaces.add \"test\", key: nil\n          end\n        end\n      end\n    end\n\n    it { expect(Test::Container[\"foo\"]).to be_an_instance_of(Test::Foo) }\n    it { expect(Test::Container[\"bar\"]).to be_an_instance_of(Test::Bar) }\n    it { expect(Test::Container[\"bar.baz\"]).to be_an_instance_of(Test::Bar::Baz) }\n\n    it \"doesn't register files with inline option 'auto_register: false'\" do\n      expect(Test::Container.registered?(\"no_register\")).to eql false\n    end\n  end\n\n  context \"standard loader with a default namespace configured\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").realpath\n          config.component_dirs.add \"namespaced_components\" do |dir|\n            dir.namespaces.add \"namespaced\", key: nil\n          end\n        end\n      end\n    end\n\n    specify { expect(Test::Container[\"bar\"]).to be_a(Namespaced::Bar) }\n    specify { expect(Test::Container[\"bar\"].foo).to be_a(Namespaced::Foo) }\n    specify { expect(Test::Container[\"foo\"]).to be_a(Namespaced::Foo) }\n  end\n\n  context \"standard loader with default namespace but boot files without\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").realpath\n\n          config.component_dirs.add \"components\" do |dir|\n            dir.namespaces.add \"test\", key: nil\n          end\n        end\n      end\n    end\n\n    specify { expect(Test::Container[\"foo\"]).to be_an_instance_of(Test::Foo) }\n    specify { expect(Test::Container[\"bar\"]).to be_an_instance_of(Test::Bar) }\n    specify { expect(Test::Container[\"bar.baz\"]).to be_an_instance_of(Test::Bar::Baz) }\n  end\n\n  context \"standard loader with a default namespace with multiple level\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").realpath\n          config.component_dirs.add \"multiple_namespaced_components\" do |dir|\n            dir.namespaces.add \"multiple/level\", key: nil\n          end\n        end\n      end\n    end\n\n    specify { expect(Test::Container[\"baz\"]).to be_a(Multiple::Level::Baz) }\n    specify { expect(Test::Container[\"foz\"]).to be_a(Multiple::Level::Foz) }\n  end\n\n  context \"with a custom loader\" do\n    before do\n      class Test::Loader < Dry::System::Loader\n        def self.call(component, *args)\n          require!(component)\n\n          constant = self.constant(component)\n\n          constant.respond_to?(:call) ? constant : constant.new(*args)\n        end\n      end\n\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").realpath\n          config.component_dirs.loader = Test::Loader\n          config.component_dirs.add \"components\" do |dir|\n            dir.namespaces.add \"test\", key: nil\n          end\n        end\n      end\n    end\n\n    it { expect(Test::Container[\"foo\"]).to be_an_instance_of(Test::Foo) }\n    it { expect(Test::Container[\"bar\"]).to eq(Test::Bar) }\n    it { expect(Test::Container[\"bar\"].call).to eq(\"Welcome to my Moe's Tavern!\") }\n    it { expect(Test::Container[\"bar.baz\"]).to be_an_instance_of(Test::Bar::Baz) }\n  end\n\n  context \"when component directory is missing\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures\").realpath\n          config.component_dirs.add \"components\" do |dir|\n            dir.namespaces.add \"test\", key: nil\n          end\n          config.component_dirs.add \"unknown_dir\"\n        end\n      end\n    end\n\n    it \"warns about it\" do\n      expect {\n        Test::Container.finalize!\n      }.to raise_error Dry::System::ComponentDirNotFoundError, %r{fixtures/unknown_dir}\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/boot_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::System::Container, \".register_provider\" do\n  subject(:system) { Test::App }\n\n  let(:db) { spy(:db) }\n  let(:client) { spy(:client) }\n\n  before do\n    Test.const_set(:DB, db)\n    Test.const_set(:Client, client)\n\n    module Test\n      class App < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/test\")\n        end\n\n        register_provider(:db) do\n          prepare do\n            register(:db, Test::DB)\n            db.establish_connection\n          end\n\n          start do\n            db.load\n          end\n\n          stop do\n            db.close_connection\n          end\n        end\n\n        register_provider(:client) do\n          prepare do\n            register(:client, Test::Client)\n            client.establish_connection\n          end\n\n          start do\n            client.load\n          end\n\n          stop do\n            client.close_connection\n          end\n        end\n      end\n    end\n  end\n\n  describe \"#init\" do\n    it \"calls init function\" do\n      system.providers.prepare(:db)\n      expect(db).to have_received(:establish_connection)\n    end\n  end\n\n  describe \"#start\" do\n    it \"calls start function\" do\n      system.providers.start(:db)\n      expect(db).to have_received(:load)\n    end\n\n    xit \"store booted component\" do\n      system.providers.start(:db)\n      expect(system.providers.booted.map(&:name)).to include(:db)\n    end\n  end\n\n  describe \"#stop\" do\n    context \"provider has started\" do\n      it \"calls stop function\" do\n        system.providers.start(:db)\n        system.providers.stop(:db)\n        expect(db).to have_received(:close_connection)\n      end\n\n      it \"marks the provider as stopped\" do\n        expect {\n          system.providers.start(:db)\n          system.providers.stop(:db)\n        }\n          .to change { system.providers[:db].stopped? }\n          .from(false). to true\n      end\n    end\n\n    context \"provider has not started\" do\n      it \"does not call stop function\" do\n        system.providers.stop(:db)\n        expect(db).not_to have_received(:close_connection)\n      end\n\n      it \"does not mark the provider as stopped\" do\n        expect { system.providers.stop(:db) }.not_to change { system.providers[:db].stopped? }\n        expect(system.providers[:db]).not_to be_stopped\n      end\n    end\n  end\n\n  describe \"#shutdown\" do\n    it \"calls stop function for every component\" do\n      system.providers.start(:db)\n      system.providers.start(:client)\n      system.providers.shutdown\n\n      expect(db).to have_received(:close_connection)\n      expect(client).to have_received(:close_connection)\n    end\n  end\n\n  specify \"boot triggers prepare\" do\n    system.providers.prepare(:db)\n\n    expect(db).to have_received(:establish_connection)\n    expect(db).to_not have_received(:load)\n  end\n\n  specify \"start triggers init + start\" do\n    system.providers.start(:db)\n\n    expect(db).to have_received(:establish_connection)\n    expect(db).to have_received(:load)\n  end\n\n  specify \"start raises error on undefined method or variable\" do\n    expect {\n      system.register_provider(:broken_1) { oops(\"arg\") }\n      system.providers.start(:broken_1)\n    }.to raise_error(NoMethodError, /oops/)\n\n    expect {\n      system.register_provider(:broken_2) { oops }\n      system.providers.start(:broken_2)\n    }.to raise_error(NameError, /oops/)\n  end\n\n  specify \"lifecycle triggers are called only once\" do\n    system.providers.start(:db)\n    system.providers.start(:db)\n\n    system.providers.prepare(:db)\n    system.providers.prepare(:db)\n\n    expect(db).to have_received(:establish_connection).exactly(1)\n    expect(db).to have_received(:load).exactly(1)\n\n    expect(system.providers[:db].statuses).to eql(%i[prepare start])\n  end\n\n  it \"raises when a duplicated identifier was used\" do\n    system.register_provider(:logger) {}\n\n    expect {\n      system.register_provider(:logger) {}\n    }.to raise_error(Dry::System::ProviderAlreadyRegisteredError, /logger/)\n  end\n\n  it \"allow setting namespace to true\" do\n    system.register_provider(:api, namespace: true) do\n      start do\n        register(:client, \"connected\")\n      end\n    end\n\n    expect(system[\"api.client\"]).to eql(\"connected\")\n  end\n\n  it \"raises when namespace value is not valid\" do\n    expect { system.register_provider(:api, namespace: 312) {} }\n      .to raise_error(ArgumentError, /\\+namespace:\\+ must be true, string or symbol/)\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/config/root_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\n\nRSpec.describe Dry::System::Container, \".config\" do\n  subject(:config) { Test::Container.config }\n  let(:configuration) { proc {} }\n\n  before do\n    class Test::Container < Dry::System::Container\n    end\n    Test::Container.configure(&configuration)\n  end\n\n  describe \"#root\" do\n    subject(:root) { config.root }\n\n    context \"no value\" do\n      it \"defaults to pwd\" do\n        expect(root).to eq Pathname.pwd\n      end\n    end\n\n    context \"string provided\" do\n      let(:configuration) { proc { |config| config.root = \"/tmp\" } }\n\n      it \"coerces string paths to pathname\" do\n        expect(root).to eq Pathname(\"/tmp\")\n      end\n    end\n\n    context \"pathname provided\" do\n      let(:configuration) { proc { |config| config.root = Pathname(\"/tmp\") } }\n\n      it \"accepts the pathname\" do\n        expect(root).to eq Pathname(\"/tmp\")\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/configuration_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\n\nRSpec.describe Dry::System::Container, \"configuration phase\" do\n  subject(:container) { Class.new(described_class) }\n\n  describe \"#configure\" do\n    it \"configures the container\" do\n      expect {\n        container.configure do |config|\n          config.root = \"/root\"\n        end\n      }.to change { container.config.root }.to Pathname(\"/root\")\n    end\n\n    it \"marks the container as configured\" do\n      expect { container.configure {} }\n        .to change { container.configured? }\n        .from(false).to true\n    end\n\n    it \"runs after configure hooks\" do\n      container.instance_eval do\n        def hooks_trace\n          @hooks_trace ||= []\n        end\n\n        after :configure do\n          hooks_trace << :after_configure\n        end\n      end\n\n      expect { container.configure {} }\n        .to change { container.hooks_trace }\n        .from([])\n        .to [:after_configure]\n    end\n\n    it \"does not run after configure hooks when called a second time\" do\n      container.instance_eval do\n        def hooks_trace\n          @hooks_trace ||= []\n        end\n\n        after :configure do\n          hooks_trace << :after_configure\n        end\n      end\n\n      expect {\n        container.configure(finalize_config: false) {}\n        container.configure(finalize_config: false) {}\n      }\n        .to change { container.hooks_trace }\n        .from([])\n        .to [:after_configure]\n    end\n\n    it \"finalizes (freezes) the config\" do\n      expect { container.configure {} }\n        .to change { container.config.frozen? }\n        .from(false).to true\n\n      expect { container.configure { |c| c.root = \"/root\" } }\n        .to raise_error Dry::Configurable::FrozenConfigError\n    end\n\n    it \"does not finalize the config with `finalize_config: false`\" do\n      expect { container.configure(finalize_config: false) {} }\n        .not_to change { container.config.frozen? }\n\n      expect(container.config).not_to be_frozen\n\n      expect { container.configure { |c| c.root = \"/root\" } }\n        .not_to raise_error\n    end\n  end\n\n  describe \"#configured!\" do\n    it \"marks the container as configured\" do\n      expect { container.configured! }\n        .to change { container.configured? }\n        .from(false).to true\n    end\n\n    it \"runs after configure hooks\" do\n      container.instance_eval do\n        def hooks_trace\n          @hooks_trace ||= []\n        end\n\n        after :configure do\n          hooks_trace << :after_configure\n        end\n      end\n\n      expect { container.configured! }\n        .to change { container.hooks_trace }\n        .from([])\n        .to [:after_configure]\n    end\n\n    it \"does not run after configure hooks when run a second time\" do\n      container.instance_eval do\n        def hooks_trace\n          @hooks_trace ||= []\n        end\n\n        after :configure do\n          hooks_trace << :after_configure\n        end\n      end\n\n      expect { container.configured!; container.configured! }\n        .to change { container.hooks_trace }\n        .from([])\n        .to [:after_configure]\n    end\n\n    it \"finalizes (freezes) the config\" do\n      expect { container.configured! }\n        .to change { container.config.frozen? }\n        .from(false).to true\n\n      expect { container.config.root = \"/root\" }.to raise_error Dry::Configurable::FrozenConfigError\n    end\n\n    it \"does not finalize the config with `finalize_config: false`\" do\n      expect { container.configured!(finalize_config: false) }\n        .not_to change { container.config.frozen? }\n\n      expect(container.config).not_to be_frozen\n\n      expect { container.config.root = \"/root\" }.not_to raise_error\n    end\n  end\n\n  describe \"#finalize!\" do\n    it \"marks the container as configured if not configured prior\" do\n      expect { container.finalize! }\n        .to change { container.configured? }.from(false).to true\n    end\n\n    it \"runs after configure hooks if not run prior\" do\n      container.instance_eval do\n        def hooks_trace\n          @hooks_trace ||= []\n        end\n\n        after :configure do\n          hooks_trace << :after_configure\n        end\n      end\n\n      expect { container.finalize! }\n        .to change { container.hooks_trace }\n        .from([])\n        .to [:after_configure]\n    end\n\n    it \"does not run after configure hooks when run a second time\" do\n      container.instance_eval do\n        def hooks_trace\n          @hooks_trace ||= []\n        end\n\n        after :configure do\n          hooks_trace << :after_configure\n        end\n      end\n\n      expect { container.finalize!; container.finalize! }\n        .to change { container.hooks_trace }\n        .from([])\n        .to [:after_configure]\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/decorate_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"delegate\"\n\nRSpec.describe Dry::System::Container do\n  subject(:system) do\n    Class.new(Dry::System::Container)\n  end\n\n  describe \".decorate\" do\n    it \"decorates registered singleton object with provided decorator API\" do\n      system.register(:foo, \"foo\")\n\n      system.decorate(:foo, with: SimpleDelegator)\n\n      expect(system[:foo]).to be_instance_of(SimpleDelegator)\n    end\n\n    it \"decorates registered object with provided decorator API\" do\n      system.register(:foo) { \"foo\" }\n\n      system.decorate(:foo, with: SimpleDelegator)\n\n      expect(system[:foo]).to be_instance_of(SimpleDelegator)\n      expect(system[:foo].__getobj__).to eql(\"foo\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/hooks/after_hooks_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::System::Container do\n  subject(:system) do\n    Class.new(described_class)\n  end\n\n  describe \"after_register hook\" do\n    it \"executes after a new key is registered\" do\n      expect { |hook|\n        system.after(:register, &hook)\n        system.register(:foo) { \"bar\" }\n      }.to yield_with_args(:foo)\n    end\n\n    it \"provides the fully-qualified key\" do\n      expect { |hook|\n        system.after(:register, &hook)\n        system.namespace :foo do\n          register(:bar) { \"baz\" }\n        end\n      }.to yield_with_args(\"foo.bar\")\n    end\n  end\n\n  describe \"after_finalize hook\" do\n    it \"executes after finalization\" do\n      expect { |hook|\n        system.after(:finalize, &hook)\n        system.finalize!\n      }.to yield_control\n    end\n\n    it \"executes before the container is frozen\" do\n      is_frozen = nil\n\n      system.after(:finalize) { is_frozen = frozen? }\n      system.finalize!\n\n      expect(is_frozen).to eq false\n      expect(system).to be_frozen\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/hooks/load_path_hook_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::System::Container, \"Default hooks / Load path\" do\n  let(:container) {\n    Class.new(Dry::System::Container) {\n      config.root = SPEC_ROOT.join(\"fixtures/test\")\n    }\n  }\n\n  before do\n    @load_path_before = $LOAD_PATH\n  end\n\n  after do\n    $LOAD_PATH.replace(@load_path_before)\n  end\n\n  context \"component_dirs configured with add_to_load_path = true\" do\n    before do\n      container.config.component_dirs.add \"lib\" do |dir|\n        dir.add_to_load_path = true\n      end\n    end\n\n    it \"adds the component dirs to the load path\" do\n      expect {\n        container.configure do\n        end\n      }.to change { $LOAD_PATH.include?(SPEC_ROOT.join(\"fixtures/test/lib\").to_s) }\n        .from(false).to(true)\n    end\n  end\n\n  context \"component_dirs configured with add_to_load_path = false\" do\n    before do\n      container.config.component_dirs.add \"lib\" do |dir|\n        dir.add_to_load_path = false\n      end\n    end\n\n    it \"does not change the load path\" do\n      expect {\n        container.configure do\n        end\n      }.not_to(change { $LOAD_PATH })\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/hooks_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::System::Container do\n  subject(:system) do\n    Class.new(Dry::System::Container)\n  end\n\n  describe \".after\" do\n    it \"registers an after hook\" do\n      system.after(:configure) do\n        register(:test, true)\n      end\n\n      system.configure {}\n\n      expect(system[:test]).to be(true)\n    end\n\n    it \"inherits hooks from superclass\" do\n      system.after(:configure) do\n        register(:test_1, true)\n      end\n\n      descendant = Class.new(system) do\n        after(:configure) do\n          register(:test_2, true)\n        end\n      end\n\n      descendant.configure {}\n\n      expect(descendant[:test_1]).to be(true)\n      expect(descendant[:test_2]).to be(true)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/import_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\n\nRSpec.describe Dry::System::Container, \".import\" do\n  subject(:app) { Class.new(Dry::System::Container) }\n\n  let(:db) do\n    Class.new(Dry::System::Container) do\n      register(:users, %w[jane joe])\n    end\n  end\n\n  it \"imports one container into another\" do\n    app.import(from: db, as: :persistence)\n\n    expect(app.registered?(\"persistence.users\")).to be(false)\n\n    app.finalize!\n\n    expect(app[\"persistence.users\"]).to eql(%w[jane joe])\n  end\n\n  context \"when container has been finalized\" do\n    it \"raises an error\" do\n      app.finalize!\n\n      expect do\n        app.import(from: db, as: :persistence)\n      end.to raise_error(Dry::System::ContainerAlreadyFinalizedError)\n    end\n  end\n\n  describe \"import module\" do\n    it \"loads system when it was not loaded in the imported container yet\" do\n      class Test::Other < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/import_test\").realpath\n          config.component_dirs.add \"lib\"\n        end\n      end\n\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/test\").realpath\n          config.component_dirs.add \"lib\"\n        end\n\n        import from: Test::Other, as: :other\n      end\n\n      module Test\n        Import = Container.injector\n      end\n\n      class Test::Foo\n        include Test::Import[\"other.test.bar\"]\n      end\n\n      expect(Test::Foo.new.bar).to be_instance_of(Test::Bar)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/injector_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\n\nRSpec.describe Dry::System::Container, \".injector\" do\n  context \"default injector\" do\n    it \"works correct\" do\n      Test::Foo = Class.new\n\n      Test::Container = Class.new(Dry::System::Container) do\n        register \"foo\", Test::Foo.new\n      end\n\n      Test::Inject = Test::Container.injector\n\n      injected_class = Class.new do\n        include Test::Inject[\"foo\"]\n      end\n\n      obj = injected_class.new\n      expect(obj.foo).to be_a Test::Foo\n\n      another = Object.new\n      obj = injected_class.new(foo: another)\n      expect(obj.foo).to eq another\n    end\n  end\n\n  context \"injector_options provided\" do\n    it \"builds an injector with the provided options\" do\n      Test::Foo = Class.new\n\n      Test::Container = Class.new(Dry::System::Container) do\n        register \"foo\", Test::Foo.new\n      end\n\n      Test::Inject = Test::Container.injector(strategies: {\n                                                default: Dry::AutoInject::Strategies::Args,\n                                                australian: Dry::AutoInject::Strategies::Args\n                                              })\n\n      injected_class = Class.new do\n        include Test::Inject.australian[\"foo\"]\n      end\n\n      obj = injected_class.new\n      expect(obj.foo).to be_a Test::Foo\n\n      another = Object.new\n      obj = injected_class.new(another)\n      expect(obj.foo).to eq another\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/load_path_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\n\nRSpec.describe Dry::System::Container, \"Load path handling\" do\n  let(:container) {\n    class Test::Container < Dry::System::Container\n      config.root = SPEC_ROOT.join(\"fixtures/test\")\n      config.component_dirs.add \"lib\"\n    end\n\n    Test::Container\n  }\n\n  before do\n    @load_path_before = $LOAD_PATH\n  end\n\n  after do\n    $LOAD_PATH.replace(@load_path_before)\n  end\n\n  describe \".add_to_load_path!\" do\n    it \"adds the given directories, relative to the container's root, to the beginning of the $LOAD_PATH\" do\n      expect { container.add_to_load_path!(\"lib\", \"system\") }\n        .to change { $LOAD_PATH.include?(SPEC_ROOT.join(\"fixtures/test/lib\").to_s) }\n        .from(false).to(true)\n        .and change { $LOAD_PATH.include?(SPEC_ROOT.join(\"fixtures/test/system\").to_s) }\n        .from(false).to(true)\n\n      expect($LOAD_PATH[0..1]).to eq [\n        SPEC_ROOT.join(\"fixtures/test/lib\").to_s,\n        SPEC_ROOT.join(\"fixtures/test/system\").to_s\n      ]\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/monitor_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::System::Container do\n  subject(:system) do\n    Class.new(Dry::System::Container) do\n      use :monitoring\n    end\n  end\n\n  describe \".monitor\" do\n    let(:klass) do\n      Class.new do\n        def self.name\n          \"Test::Class_#{__id__}\"\n        end\n\n        def say(word, lang: nil, &block)\n          block&.call\n          word\n        end\n\n        def other; end\n      end\n    end\n\n    let(:object) do\n      klass.new\n    end\n\n    before do\n      system.configure {}\n      system.register(:object, klass.new)\n    end\n\n    it \"monitors object public method calls\" do\n      captured = []\n\n      system.monitor(:object) do |event|\n        captured << [event.id, event[:target], event[:method], event[:args], event[:kwargs]]\n      end\n\n      object = system[:object]\n      block_result = []\n      block = proc { block_result << true }\n\n      result = object.say(\"hi\", lang: \"en\", &block)\n\n      expect(block_result).to eql([true])\n      expect(result).to eql(\"hi\")\n\n      expect(captured).to eql([[:monitoring, :object, :say, [\"hi\"], {lang: \"en\"}]])\n    end\n\n    it \"monitors specified object method calls\" do\n      captured = []\n\n      system.monitor(:object, methods: [:say]) do |event|\n        captured << [event.id, event[:target], event[:method], event[:args], event[:kwargs]]\n      end\n\n      object = system[:object]\n\n      object.say(\"hi\")\n      object.other\n\n      expect(captured).to eql([[:monitoring, :object, :say, [\"hi\"], {}]])\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container/notifications_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::System::Container do\n  subject(:system) do\n    Class.new(Dry::System::Container) do\n      use :notifications\n    end\n  end\n\n  describe \".notifications\" do\n    it \"returns configured notifications\" do\n      system.configure {}\n\n      expect(system[:notifications]).to be_instance_of(Dry::Monitor::Notifications)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/container_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\nrequire \"dry/system/stubs\"\n\nRSpec.describe Dry::System::Container do\n  subject(:container) { Test::Container }\n\n  context \"with default core dir\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/test\").realpath\n          config.component_dirs.add \"lib\"\n        end\n      end\n\n      module Test\n        Import = Container.injector\n      end\n    end\n\n    describe \".require_from_root\" do\n      it \"requires a single file\" do\n        container.require_from_root(Pathname(\"lib/test/models\"))\n\n        expect(Test.const_defined?(:Models)).to be(true)\n      end\n\n      it \"requires many files when glob pattern is passed\" do\n        container.require_from_root(Pathname(\"lib/test/models/*.rb\"))\n\n        expect(Test::Models.const_defined?(:User)).to be(true)\n        expect(Test::Models.const_defined?(:Book)).to be(true)\n      end\n    end\n  end\n\n  describe \".init\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/lazytest\").realpath\n        end\n\n        add_to_load_path!(\"lib\")\n      end\n    end\n\n    it \"lazy-boot a given system\" do\n      container.prepare(:bar)\n\n      expect(Test.const_defined?(:Bar)).to be(true)\n      expect(container.registered?(\"test.bar\")).to be(false)\n    end\n  end\n\n  describe \".start\" do\n    shared_examples_for \"a booted system\" do\n      it \"boots a given system and finalizes it\" do\n        container.start(:bar)\n\n        expect(Test.const_defined?(:Bar)).to be(true)\n        expect(container[\"test.bar\"]).to eql(\"I was finalized\")\n      end\n\n      it \"expects name to point to an existing boot file\" do\n        expect {\n          container.start(:foo)\n        }.to raise_error(Dry::System::ProviderNotFoundError, \"Provider :foo not found\")\n      end\n\n      describe \"mismatch between finalize name and registered component\" do\n        it \"raises a meaningful error\" do\n          expect {\n            container.start(:hell)\n          }.to raise_error(Dry::System::ProviderNotFoundError, \"Provider :hell not found\")\n        end\n      end\n    end\n\n    context \"with the default core dir\" do\n      it_behaves_like \"a booted system\" do\n        before do\n          class Test::Container < Dry::System::Container\n            configure do |config|\n              config.root = SPEC_ROOT.join(\"fixtures/test\").realpath\n            end\n\n            add_to_load_path!(\"lib\")\n          end\n        end\n      end\n    end\n\n    context \"with a custom provider dir specified\" do\n      it_behaves_like \"a booted system\" do\n        before do\n          class Test::Container < Dry::System::Container\n            configure do |config|\n              config.root = SPEC_ROOT.join(\"fixtures/other\").realpath\n              config.provider_dirs = [\"config/providers\"]\n            end\n\n            add_to_load_path!(\"lib\")\n          end\n        end\n      end\n    end\n  end\n\n  describe \".stub\" do\n    let(:stubbed_car) do\n      double(:car, wheels_count: 5)\n    end\n\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/stubbing\").realpath\n          config.component_dirs.add \"lib\"\n        end\n      end\n    end\n\n    describe \"with stubs disabled\" do\n      it \"raises error when trying to stub frozen container\" do\n        expect { container.stub(\"test.car\", stubbed_car) }.to raise_error(NoMethodError, /stub/)\n      end\n    end\n\n    describe \"with stubs enabled\" do\n      before do\n        container.enable_stubs!\n      end\n\n      it \"lazy-loads a component\" do\n        # This test doens't really make sense\n        # why do we test it again afterwards? It's also nothing to do with stubbing really...\n\n        expect(container[:db]).to be_instance_of(Test::DB)\n\n        # byebug\n        container.finalize!\n        expect(container[:db]).to be_instance_of(Test::DB)\n      end\n\n      it \"allows to stub components\" do\n        container.finalize!\n\n        expect(container[\"test.car\"].wheels_count).to be(4)\n\n        container.stub(\"test.car\", stubbed_car)\n\n        expect(container[\"test.car\"].wheels_count).to be(5)\n      end\n    end\n  end\n\n  describe \".key?\" do\n    before do\n      class Test::FalseyContainer < Dry::System::Container\n        register(:else) { :else }\n        register(:false) { false }\n        register(:nil) { nil }\n      end\n\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/test\").realpath\n          config.component_dirs.add \"lib\"\n        end\n\n        import from: Test::FalseyContainer, as: :falses\n      end\n    end\n\n    it \"tries to load component\" do\n      expect(container.key?(\"test.dep\")).to be(true)\n    end\n\n    it \"returns false for non-existing component\" do\n      expect(container.key?(\"test.missing\")).to be(false)\n    end\n\n    it \"returns true if registered value is false or nil\" do\n      expect(container.key?(\"falses.false\")).to be(true)\n      expect(container.key?(\"falses.nil\")).to be(true)\n    end\n  end\n\n  describe \".resolve\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/test\").realpath\n          config.component_dirs.add \"lib\"\n        end\n      end\n    end\n\n    it \"runs a fallback block when a component cannot be resolved\" do\n      expect(container.resolve(\"missing\") { :fallback }).to be(:fallback)\n    end\n  end\n\n  describe \".registered?\" do\n    before do\n      class Test::Container < Dry::System::Container\n        configure do |config|\n          config.root = SPEC_ROOT.join(\"fixtures/test\").realpath\n          config.component_dirs.add \"lib\"\n        end\n      end\n    end\n\n    it \"checks if a component is registered\" do\n      expect(container.registered?(\"test.dep\")).to be(false)\n      container.resolve(\"test.dep\")\n      expect(container.registered?(\"test.dep\")).to be(true)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/errors_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/errors\"\n\nmodule Dry\n  module System\n    RSpec.describe \"Errors\" do\n      describe ComponentNotLoadableError do\n        let(:component) { instance_double(Dry::System::Component, key: key) }\n        let(:error) { instance_double(NameError, name: \"Foo\", receiver: \"Test\") }\n        subject { described_class.new(component, error, corrections: corrections) }\n\n        describe \"without corrections\" do\n          let(:corrections) { [] }\n          let(:key) { \"test.foo\" }\n\n          it do\n            expect(subject.message).to eq(\n              \"Component 'test.foo' is not loadable.\\n\" \\\n              \"Looking for Test::Foo.\"\n            )\n          end\n        end\n\n        describe \"with corrections\" do\n          describe \"acronym\" do\n            describe \"single class name correction\" do\n              let(:corrections) { [\"Test::FOO\"] }\n              let(:key) { \"test.foo\" }\n\n              it do\n                expect(subject.message).to eq(\n                  <<~ERROR_MESSAGE\n                    Component 'test.foo' is not loadable.\n                    Looking for Test::Foo.\n\n                    You likely need to add:\n\n                        acronym('FOO')\n\n                    to your container's inflector, since we found a Test::FOO class.\n                  ERROR_MESSAGE\n                )\n              end\n            end\n\n            describe \"module and class name correction\" do\n              let(:error) { instance_double(NameError, name: \"Foo\", receiver: \"Test::Api\") }\n              let(:corrections) { [\"Test::API::FOO\"] }\n              let(:key) { \"test.api.foo\" }\n\n              it do\n                expect(subject.message).to eq(\n                  <<~ERROR_MESSAGE\n                    Component 'test.api.foo' is not loadable.\n                    Looking for Test::Api::Foo.\n\n                    You likely need to add:\n\n                        acronym('API', 'FOO')\n\n                    to your container's inflector, since we found a Test::API::FOO class.\n                  ERROR_MESSAGE\n                )\n              end\n            end\n          end\n\n          describe \"typo\" do\n            let(:corrections) { [\"Test::Fon\", \"Test::Flo\"] }\n            let(:key) { \"test.foo\" }\n\n            it do\n              expect(subject.message).to eq(\n                <<~ERROR_MESSAGE.chomp\n                  Component 'test.foo' is not loadable.\n                  Looking for Test::Foo.\n\n                  Did you mean?  Test::Fon\n                                 Test::Flo\n                ERROR_MESSAGE\n              )\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/identifier_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/identifier\"\n\nRSpec.describe Dry::System::Identifier do\n  subject(:identifier) { described_class.new(key) }\n\n  let(:key) { \"kittens.operations.belly_rub\" }\n\n  describe \"#key\" do\n    it \"returns the identifier's key\" do\n      expect(identifier.key).to eql \"kittens.operations.belly_rub\"\n    end\n\n    context \"non-string key given\" do\n      let(:key) { :db }\n\n      it \"converts to a string\" do\n        expect(identifier.key).to eq \"db\"\n      end\n    end\n  end\n\n  describe \"#to_s\" do\n    it \"returns the key\" do\n      expect(identifier.to_s).to eq \"kittens.operations.belly_rub\"\n    end\n  end\n\n  describe \"#root_key\" do\n    it \"returns the base segment of the key, as a symbol\" do\n      expect(identifier.root_key).to eq :kittens\n    end\n  end\n\n  describe \"#start_with?\" do\n    it \"returns true when the given string matches the base segment of the key\" do\n      expect(identifier.start_with?(\"kittens\")).to be true\n    end\n\n    it \"returns true when the given string matches multiple base segments of the key\" do\n      expect(identifier.start_with?(\"kittens.operations\")).to be true\n    end\n\n    it \"returns false if the given string is only a partial base segment of the key\" do\n      expect(identifier.start_with?(\"kitten\")).to be false\n    end\n\n    it \"returns false if the given string is not a base segment of the key\" do\n      expect(identifier.start_with?(\"puppies\")).to be false\n    end\n\n    it \"returns true when the given string matches all segments of the key\" do\n      expect(identifier.start_with?(\"kittens.operations.belly_rub\")).to be true\n    end\n\n    it \"returns true when the given string is nil\" do\n      expect(identifier.start_with?(nil)).to be true\n    end\n\n    it \"returns true if the given string is empty\" do\n      expect(identifier.start_with?(\"\")).to be true\n    end\n\n    context \"component is identified by a single segment\" do\n      let(:key) { \"belly_rub\" }\n\n      it \"returns true when the given string matches the key\" do\n        expect(identifier.start_with?(\"belly_rub\")).to be true\n      end\n\n      it \"returns false when the given string does not match the key\" do\n        expect(identifier.start_with?(\"head_scratch\")).to be false\n      end\n    end\n  end\n\n  describe \"#end_with?\" do\n    it \"returns true when the given string matches the last segment of the key\" do\n      expect(identifier.end_with?(\"belly_rub\")).to be true\n    end\n\n    it \"returns true when the given string matches multiple trailing segments of the key\" do\n      expect(identifier.end_with?(\"operations.belly_rub\")).to be true\n    end\n\n    it \"returns false if the given string is an incomplete part of a trailing segment\" do\n      expect(identifier.end_with?(\"rub\")).to be false\n      expect(identifier.end_with?(\"ations.belly_rub\")).to be false\n    end\n\n    it \"return false if the given string is not part of any trailing segment\" do\n      expect(identifier.end_with?(\"head_scratch\")).to be false\n    end\n\n    it \"returns true if the given string matches all segments of the key\" do\n      expect(identifier.end_with?(\"kittens.operations.belly_rub\")).to be true\n    end\n\n    it \"returns true if the given string is nil\" do\n      expect(identifier.end_with?(nil)).to be true\n    end\n\n    it \"returns true if the given string is empty\" do\n      expect(identifier.end_with?(\"\")).to be true\n    end\n\n    context \"component key with only a single segment\" do\n      let(:key) { \"belly_rub\" }\n\n      it \"returns true when the given string matches the key\" do\n        expect(identifier.end_with?(\"belly_rub\")).to be true\n      end\n\n      it \"returns false when the given string does not match the key\" do\n        expect(identifier.end_with?(\"head_scratch\")).to be false\n      end\n    end\n  end\n\n  describe \"#include?\" do\n    it \"returns true when the given string matches one or more whole key segments\" do\n      expect(identifier.include?(\"kittens.operations\")).to be true\n    end\n\n    it \"returns false when the given string is an incomplete part of a key segment\" do\n      expect(identifier.include?(\"kitten\")).to be false\n      expect(identifier.include?(\"kittens.operation\")).to be false\n    end\n\n    it \"returns false when the given string is not any of the key segments\" do\n      expect(identifier.include?(\"puppies\")).to be false\n    end\n\n    it \"returns false if the given string is nil\" do\n      expect(identifier.include?(nil)).to be false\n    end\n\n    it \"returns false if the given string is blank\" do\n      expect(identifier.include?(\"\")).to be false\n    end\n  end\n\n  describe \"#key_with_separator\" do\n    it \"returns the key split by the given separator\" do\n      expect(identifier.key_with_separator(\"/\")).to eq \"kittens/operations/belly_rub\"\n    end\n  end\n\n  describe \"#namespaced\" do\n    let(:new_identifier) { identifier.namespaced(from: from, to: to, **opts) }\n\n    let(:from) { \"kittens\" }\n    let(:to) { \"cats\" }\n    let(:opts) { {} }\n\n    it \"returns a new identifier\" do\n      expect(new_identifier).to be_an_instance_of(described_class)\n    end\n\n    it \"replaces the leading namespace\" do\n      expect(new_identifier.key).to eq \"cats.operations.belly_rub\"\n    end\n\n    context \"multiple leading namespaces\" do\n      let(:from) { \"kittens.operations\" }\n\n      it \"replaces the namespaces\" do\n        expect(new_identifier.key).to eq \"cats.belly_rub\"\n      end\n    end\n\n    context \"removing the leading namespace\" do\n      let(:to) { nil }\n\n      it \"removes the namespace\" do\n        expect(new_identifier.key).to eq \"operations.belly_rub\"\n      end\n    end\n\n    context \"adding a leading namespace\" do\n      let(:from) { nil }\n\n      it \"adds the namespace\" do\n        expect(new_identifier.key).to eq \"cats.kittens.operations.belly_rub\"\n      end\n    end\n\n    it \"returns itself if the key is unchanged\" do\n      expect(identifier.namespaced(from: nil, to: nil)).to be identifier\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/indirect_component_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/identifier\"\nrequire \"dry/system/indirect_component\"\n\nRSpec.describe Dry::System::IndirectComponent do\n  subject(:component) { described_class.new(identifier) }\n  let(:identifier) { Dry::System::Identifier.new(\"test.foo\") }\n\n  it \"is not loadable\" do\n    expect(component).not_to be_loadable\n  end\n\n  describe \"#identifier\" do\n    it \"is the given identifier\" do\n      expect(component.identifier).to be identifier\n    end\n  end\n\n  describe \"#key\" do\n    it \"returns the identifier's key\" do\n      expect(component.key).to eq \"test.foo\"\n    end\n  end\n\n  describe \"#root_key\" do\n    it \"returns the identifier's root key\" do\n      expect(component.root_key).to eq :test\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/loader/autoloading_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/loader/autoloading\"\nrequire \"dry/system/component\"\nrequire \"dry/system/config/namespace\"\nrequire \"dry/system/identifier\"\n\nRSpec.describe Dry::System::Loader::Autoloading do\n  describe \"#require!\" do\n    subject(:loader) { described_class }\n    let(:component) {\n      Dry::System::Component.new(\n        Dry::System::Identifier.new(\"test.not_loaded_const\"),\n        file_path: \"/path/to/test/not_loaded_const.rb\",\n        namespace: Dry::System::Config::Namespace.default_root\n      )\n    }\n\n    before do\n      allow(loader).to receive(:require)\n      allow(Test).to receive(:const_missing)\n    end\n\n    it \"loads the constant \" do\n      loader.require!(component)\n      expect(loader).not_to have_received(:require)\n      expect(Test).to have_received(:const_missing).with :NotLoadedConst\n    end\n\n    it \"returns self\" do\n      expect(loader.require!(component)).to eql loader\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/loader_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/loader\"\n\nrequire \"dry/inflector\"\nrequire \"dry/system/component\"\nrequire \"dry/system/config/namespace\"\nrequire \"dry/system/identifier\"\nrequire \"singleton\"\n\nRSpec.describe Dry::System::Loader do\n  subject(:loader) { described_class }\n\n  describe \"#require!\" do\n    let(:component) {\n      Dry::System::Component.new(\n        Dry::System::Identifier.new(\"test.bar\"),\n        file_path: \"/path/to/test/bar.rb\",\n        namespace: Dry::System::Config::Namespace.default_root\n      )\n    }\n\n    before do\n      expect(loader).to receive(:require).with(\"test/bar\").at_least(1)\n    end\n\n    it \"requires the components's path\" do\n      loader.require!(component)\n    end\n\n    it \"returns self\" do\n      expect(loader.require!(component)).to eql loader\n    end\n  end\n\n  describe \"#call\" do\n    shared_examples_for \"object loader\" do\n      let(:instance) { loader.call(component) }\n\n      context \"not singleton\" do\n        it \"returns a new instance of the constant\" do\n          expect(instance).to be_instance_of(constant)\n          expect(instance).not_to be(loader.call(component))\n        end\n      end\n\n      context \"singleton\" do\n        before { constant.send(:include, Singleton) }\n\n        it \"returns singleton instance\" do\n          expect(instance).to be(constant.instance)\n        end\n      end\n    end\n\n    context \"with a singular name\" do\n      let(:component) {\n        Dry::System::Component.new(\n          Dry::System::Identifier.new(\"test.bar\"),\n          file_path: \"/path/to/test/bar.rb\",\n          namespace: Dry::System::Config::Namespace.default_root\n        )\n      }\n\n      let(:constant) { Test::Bar }\n\n      before do\n        expect(loader).to receive(:require).with(\"test/bar\").at_least(1)\n\n        module Test\n          Bar = Class.new\n        end\n      end\n\n      it_behaves_like \"object loader\"\n    end\n\n    context \"with a constructor accepting args\" do\n      let(:component) {\n        Dry::System::Component.new(\n          Dry::System::Identifier.new(\"test.bar\"),\n          file_path: \"/path/to/test/bar.rb\",\n          namespace: Dry::System::Config::Namespace.default_root\n        )\n      }\n\n      before do\n        expect(loader).to receive(:require).with(\"test/bar\").at_least(1)\n\n        module Test\n          Bar = Struct.new(:one, :two)\n        end\n      end\n\n      it \"passes args to the constructor\" do\n        instance = loader.call(component, 1, 2)\n\n        expect(instance.one).to be(1)\n        expect(instance.two).to be(2)\n      end\n    end\n\n    context \"with a custom inflector\" do\n      let(:component) {\n        Dry::System::Component.new(\n          Dry::System::Identifier.new(\"test.api_bar\"),\n          file_path: \"/path/to/test/api_bar.rb\",\n          namespace: Dry::System::Config::Namespace.default_root,\n          inflector: Dry::Inflector.new { |i| i.acronym(\"API\") }\n        )\n      }\n\n      let(:constant) { Test::APIBar }\n\n      before do\n        expect(loader).to receive(:require).with(\"test/api_bar\").at_least(1)\n\n        Test::APIBar = Class.new\n      end\n\n      it_behaves_like \"object loader\"\n    end\n  end\n\n  describe \"#constant\" do\n    let(:component) {\n      Dry::System::Component.new(\n        Dry::System::Identifier.new(\"test.api_bar\"),\n        file_path: \"/path/to/test/api_bar.rb\",\n        namespace: Dry::System::Config::Namespace.default_root,\n        inflector: Dry::Inflector.new { |i| i.acronym(\"API\") }\n      )\n    }\n    describe \"successful constant loading\" do\n      before do\n        Test::APIBar = Class.new\n      end\n\n      it \"returns the constant\" do\n        expect(loader.constant(component)).to eq(Test::APIBar)\n      end\n    end\n\n    describe \"unsuccessful constant loading\" do\n      before do\n        Test::APIBoo = Class.new\n      end\n\n      it \"raises custom error\" do\n        expect { loader.constant(component) }.to raise_error(\n          Dry::System::ComponentNotLoadableError\n        ).with_message(\n          <<~ERROR_MESSAGE.chomp\n            Component 'test.api_bar' is not loadable.\n            Looking for Test::APIBar.\n\n            Did you mean?  Test::APIBoo\n          ERROR_MESSAGE\n        )\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/magic_comments_parser_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/magic_comments_parser\"\n\nRSpec.describe Dry::System::MagicCommentsParser, \".call\" do\n  let(:file_name) { SPEC_ROOT.join(\"fixtures/magic_comments/comments.rb\") }\n  let(:comments) { described_class.(file_name) }\n\n  it \"makes comment names available as symbols\" do\n    expect(comments.key?(:valid_comment)).to eql true\n  end\n\n  it \"finds magic comments after other commented lines or blank lines\" do\n    expect(comments[:valid_comment]).to eq \"hello\"\n  end\n\n  it \"does not match comments with invalid names\" do\n    expect(comments.values).not_to include \"value for comment using dashes\"\n  end\n\n  it \"supports comment names with alpha-numeric characters and underscores (numbers not allowed for first character)\" do\n    expect(comments[:comment_123]).to eq \"alpha-numeric and underscores allowed\"\n    expect(comments.keys).not_to include(:\"123_will_not_match\")\n  end\n\n  it \"only matches comments at the start of the line\" do\n    expect(comments.key?(:not_at_start_of_line)).to eql false\n  end\n\n  it \"does not match any comments after any lines of code\" do\n    expect(comments.key?(:after_code)).to eql false\n  end\n\n  describe \"coercions\" do\n    it 'coerces \"true\" to true' do\n      expect(comments[:true_comment]).to eq true\n    end\n\n    it 'coerces \"false\" to false' do\n      expect(comments[:false_comment]).to eq false\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/provider/source_spec.rb",
    "content": "# frozen_string_literal: true\n\nRSpec.describe Dry::System::Provider::Source do\n  let(:target_container) do\n    Dry::Core::Container.new\n  end\n\n  let(:provider_container) do\n    Dry::Core::Container.new\n  end\n\n  shared_examples_for \"a provider class\" do\n    let(:provider) do\n      provider_class.new(\n        provider_container: provider_container, target_container: target_container\n      )\n    end\n\n    it \"exposes start callback\" do\n      expect(provider.provider_container.key?(\"persistence\")).to be(false)\n\n      provider.start\n\n      expect(provider.provider_container.key?(\"persistence\")).to be(true)\n    end\n  end\n\n  context \"using a base class\" do\n    it_behaves_like \"a provider class\" do\n      let(:provider_class) do\n        described_class.for(name: \"Persistence\") do\n          start do\n            register(:persistence, {})\n          end\n        end\n      end\n    end\n  end\n\n  context \"using a sub-class\" do\n    it_behaves_like \"a provider class\" do\n      let(:parent_class) do\n        described_class.for(name: \"Persistence\") do\n          start do\n            register(:persistence, {})\n          end\n        end\n      end\n\n      let(:provider_class) do\n        Class.new(parent_class)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/provider_sources/settings/loader_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"dry/system/provider_sources/settings/loader\"\n\nRSpec.describe Dry::System::ProviderSources::Settings::Loader do\n  subject(:loader) { described_class.new(root: root, env: env) }\n  let(:root) { \"/system/root\" }\n  subject(:env) { :development }\n\n  before do\n    allow_any_instance_of(described_class).to receive(:require).with(\"dotenv\")\n  end\n\n  describe \"#initialize\" do\n    context \"dotenv available\" do\n      let(:dotenv) { spy(:dotenv) }\n\n      before do\n        stub_const \"Dotenv\", dotenv\n      end\n\n      context \"non-test environment\" do\n        let(:env) { :development }\n\n        it \"requires dotenv and loads a range of .env files\" do\n          loader\n\n          expect(loader).to have_received(:require).with(\"dotenv\").ordered\n          expect(dotenv).to have_received(:load).ordered.with(\n            \"/system/root/.env.development.local\",\n            \"/system/root/.env.local\",\n            \"/system/root/.env.development\",\n            \"/system/root/.env\"\n          )\n        end\n      end\n\n      context \"test environment\" do\n        let(:env) { :test }\n\n        it \"loads a range of .env files, not including .env.local\" do\n          loader\n\n          expect(dotenv).to have_received(:load).ordered.with(\n            \"/system/root/.env.test.local\",\n            \"/system/root/.env.test\",\n            \"/system/root/.env\"\n          )\n        end\n      end\n    end\n\n    context \"dotenv unavailable\" do\n      it \"attempts to require dotenv\" do\n        loader\n        expect(loader).to have_received(:require).with(\"dotenv\")\n      end\n\n      it \"does not raise any error\" do\n        expect { loader }.not_to raise_error\n      end\n    end\n  end\n\n  describe \"#[]\" do\n    it \"returns a values from ENV\" do\n      allow(ENV).to receive(:[]).and_call_original\n      allow(ENV).to receive(:[]).with(\"SOME_KEY\").and_return \"some value\"\n\n      expect(loader[\"SOME_KEY\"]).to eq \"some value\"\n    end\n  end\nend\n"
  },
  {
    "path": "zizmor.yml",
    "content": "rules:\n  unpinned-uses:\n    config:\n      policies:\n        hanakai-rb/*: ref-pin\n"
  }
]