Full Code of dry-rb/dry-system for AI

main 37df3d71bebc cached
262 files
424.6 KB
112.3k tokens
707 symbols
1 requests
Download .txt
Showing preview only (493K chars total). Download the full file or copy to clipboard to get everything.
Repository: dry-rb/dry-system
Branch: main
Commit: 37df3d71bebc
Files: 262
Total size: 424.6 KB

Directory structure:
gitextract_5feq0jid/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.md
│   │   └── config.yml
│   ├── SUPPORT.md
│   └── workflows/
│       ├── ci-lint.yml
│       ├── ci.yml
│       ├── pr-comments.yml
│       ├── repo-sync-preview.yml
│       └── rubocop.yml
├── .gitignore
├── .rspec
├── .yardopts
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Gemfile
├── Gemfile.devtools
├── LICENSE
├── README.md
├── Rakefile
├── bin/
│   ├── .gitkeep
│   └── console
├── docsite/
│   └── source/
│       ├── component-dirs.html.md
│       ├── container/
│       │   └── hooks.html.md
│       ├── container.html.md
│       ├── dependency-auto-injection.html.md
│       ├── external-provider-sources.html.md
│       ├── index.html.md
│       ├── plugins.html.md
│       ├── providers.html.md
│       ├── settings.html.md
│       └── test-mode.html.md
├── dry-system.gemspec
├── examples/
│   ├── custom_configuration_auto_register/
│   │   ├── Gemfile
│   │   ├── lib/
│   │   │   ├── entities/
│   │   │   │   └── user.rb
│   │   │   └── user_repo.rb
│   │   ├── run.rb
│   │   └── system/
│   │       ├── boot/
│   │       │   └── persistence.rb
│   │       ├── container.rb
│   │       └── import.rb
│   ├── standalone/
│   │   ├── Gemfile
│   │   ├── lib/
│   │   │   ├── empty_service.rb
│   │   │   ├── not_registered.rb
│   │   │   ├── service_with_dependency.rb
│   │   │   └── user_repo.rb
│   │   ├── run.rb
│   │   └── system/
│   │       ├── container.rb
│   │       ├── import.rb
│   │       └── providers/
│   │           └── persistence.rb
│   └── zeitwerk/
│       ├── Gemfile
│       ├── lib/
│       │   ├── service_with_dependency.rb
│       │   └── user_repo.rb
│       ├── run.rb
│       └── system/
│           ├── container.rb
│           └── import.rb
├── lib/
│   ├── dry/
│   │   ├── system/
│   │   │   ├── auto_registrar.rb
│   │   │   ├── component.rb
│   │   │   ├── component_dir.rb
│   │   │   ├── config/
│   │   │   │   ├── component_dir.rb
│   │   │   │   ├── component_dirs.rb
│   │   │   │   ├── namespace.rb
│   │   │   │   └── namespaces.rb
│   │   │   ├── constants.rb
│   │   │   ├── container.rb
│   │   │   ├── errors.rb
│   │   │   ├── identifier.rb
│   │   │   ├── importer.rb
│   │   │   ├── indirect_component.rb
│   │   │   ├── loader/
│   │   │   │   └── autoloading.rb
│   │   │   ├── loader.rb
│   │   │   ├── magic_comments_parser.rb
│   │   │   ├── manifest_registrar.rb
│   │   │   ├── plugins/
│   │   │   │   ├── bootsnap.rb
│   │   │   │   ├── dependency_graph/
│   │   │   │   │   └── strategies.rb
│   │   │   │   ├── dependency_graph.rb
│   │   │   │   ├── env.rb
│   │   │   │   ├── logging.rb
│   │   │   │   ├── monitoring/
│   │   │   │   │   └── proxy.rb
│   │   │   │   ├── monitoring.rb
│   │   │   │   ├── notifications.rb
│   │   │   │   ├── plugin.rb
│   │   │   │   ├── zeitwerk/
│   │   │   │   │   └── compat_inflector.rb
│   │   │   │   └── zeitwerk.rb
│   │   │   ├── plugins.rb
│   │   │   ├── provider/
│   │   │   │   ├── source.rb
│   │   │   │   └── source_dsl.rb
│   │   │   ├── provider.rb
│   │   │   ├── provider_registrar.rb
│   │   │   ├── provider_source_registry.rb
│   │   │   ├── provider_sources/
│   │   │   │   ├── settings/
│   │   │   │   │   ├── config.rb
│   │   │   │   │   └── loader.rb
│   │   │   │   └── settings.rb
│   │   │   ├── provider_sources.rb
│   │   │   ├── stubs.rb
│   │   │   └── version.rb
│   │   └── system.rb
│   └── dry-system.rb
├── repo-sync.yml
├── spec/
│   ├── fixtures/
│   │   ├── app/
│   │   │   ├── lib/
│   │   │   │   ├── ignored_spec_service.rb
│   │   │   │   └── spec_service.rb
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           └── client.rb
│   │   ├── autoloading/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── entities/
│   │   │           │   └── foo_entity.rb
│   │   │           └── foo.rb
│   │   ├── components/
│   │   │   └── test/
│   │   │       ├── bar/
│   │   │       │   ├── abc.rb
│   │   │       │   └── baz.rb
│   │   │       ├── bar.rb
│   │   │       ├── foo.rb
│   │   │       └── no_register.rb
│   │   ├── components_with_errors/
│   │   │   └── test/
│   │   │       └── constant_error.rb
│   │   ├── deprecations/
│   │   │   └── bootable_dirs_config/
│   │   │       └── system/
│   │   │           ├── boot/
│   │   │           │   └── logger.rb
│   │   │           └── custom_boot/
│   │   │               └── logger.rb
│   │   ├── external_components/
│   │   │   ├── alt-components/
│   │   │   │   ├── db.rb
│   │   │   │   └── logger.rb
│   │   │   ├── components/
│   │   │   │   ├── logger.rb
│   │   │   │   ├── mailer.rb
│   │   │   │   └── notifier.rb
│   │   │   └── lib/
│   │   │       └── external_components.rb
│   │   ├── external_components_deprecated/
│   │   │   ├── components/
│   │   │   │   └── logger.rb
│   │   │   └── lib/
│   │   │       └── external_components.rb
│   │   ├── import_test/
│   │   │   ├── config/
│   │   │   │   └── application.yml
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── bar.rb
│   │   │           └── foo.rb
│   │   ├── lazy_loading/
│   │   │   ├── auto_registration_disabled/
│   │   │   │   └── lib/
│   │   │   │       ├── entities/
│   │   │   │       │   └── kitten.rb
│   │   │   │       └── fetch_kitten.rb
│   │   │   └── shared_root_keys/
│   │   │       ├── lib/
│   │   │       │   └── kitten_service/
│   │   │       │       ├── fetch_kitten.rb
│   │   │       │       └── submit_kitten.rb
│   │   │       └── system/
│   │   │           └── providers/
│   │   │               └── kitten_service.rb
│   │   ├── lazytest/
│   │   │   ├── config/
│   │   │   │   └── application.yml
│   │   │   ├── lib/
│   │   │   │   └── test/
│   │   │   │       ├── dep.rb
│   │   │   │       ├── foo.rb
│   │   │   │       ├── models/
│   │   │   │       │   ├── book.rb
│   │   │   │       │   └── user.rb
│   │   │   │       └── models.rb
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           └── bar.rb
│   │   ├── magic_comments/
│   │   │   └── comments.rb
│   │   ├── manifest_registration/
│   │   │   ├── lib/
│   │   │   │   └── test/
│   │   │   │       └── foo.rb
│   │   │   └── system/
│   │   │       └── registrations/
│   │   │           └── foo.rb
│   │   ├── memoize_magic_comments/
│   │   │   └── test/
│   │   │       ├── memoize_false_comment.rb
│   │   │       ├── memoize_no_comment.rb
│   │   │       └── memoize_true_comment.rb
│   │   ├── mixed_namespaces/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── external/
│   │   │           │   └── external_component.rb
│   │   │           └── my_app/
│   │   │               └── app_component.rb
│   │   ├── multiple_namespaced_components/
│   │   │   └── multiple/
│   │   │       └── level/
│   │   │           ├── baz.rb
│   │   │           └── foz.rb
│   │   ├── multiple_provider_dirs/
│   │   │   ├── custom_bootables/
│   │   │   │   └── logger.rb
│   │   │   └── default_bootables/
│   │   │       ├── inflector.rb
│   │   │       └── logger.rb
│   │   ├── namespaced_components/
│   │   │   └── namespaced/
│   │   │       ├── bar.rb
│   │   │       └── foo.rb
│   │   ├── other/
│   │   │   ├── config/
│   │   │   │   └── providers/
│   │   │   │       ├── bar.rb
│   │   │   │       └── hell.rb
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── dep.rb
│   │   │           ├── foo.rb
│   │   │           ├── models/
│   │   │           │   ├── book.rb
│   │   │           │   └── user.rb
│   │   │           └── models.rb
│   │   ├── require_path/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           └── foo.rb
│   │   ├── settings_test/
│   │   │   └── types.rb
│   │   ├── standard_container_with_default_namespace/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── dep.rb
│   │   │           └── example_with_dep.rb
│   │   ├── standard_container_without_default_namespace/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── dep.rb
│   │   │           └── example_with_dep.rb
│   │   ├── stubbing/
│   │   │   ├── lib/
│   │   │   │   └── test/
│   │   │   │       └── car.rb
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           └── db.rb
│   │   ├── test/
│   │   │   ├── config/
│   │   │   │   ├── application.yml
│   │   │   │   └── subapp.yml
│   │   │   ├── lib/
│   │   │   │   └── test/
│   │   │   │       ├── dep.rb
│   │   │   │       ├── foo.rb
│   │   │   │       ├── models/
│   │   │   │       │   ├── book.rb
│   │   │   │       │   └── user.rb
│   │   │   │       ├── models.rb
│   │   │   │       └── singleton_dep.rb
│   │   │   ├── log/
│   │   │   │   └── .gitkeep
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           ├── bar.rb
│   │   │           ├── client.rb
│   │   │           ├── db.rb
│   │   │           ├── hell.rb
│   │   │           └── logger.rb
│   │   ├── umbrella/
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           └── db.rb
│   │   └── unit/
│   │       ├── component/
│   │       │   ├── component_dir_1/
│   │       │   │   ├── namespace/
│   │       │   │   │   └── nested/
│   │       │   │   │       ├── component_file.rb
│   │       │   │   │       └── component_file_with_auto_register_false.rb
│   │       │   │   └── outside_namespace/
│   │       │   │       └── component_file.rb
│   │       │   └── component_dir_2/
│   │       │       └── namespace/
│   │       │           └── nested/
│   │       │               └── component_file.rb
│   │       └── component_dir/
│   │           └── component_file.rb
│   ├── integration/
│   │   ├── boot_spec.rb
│   │   ├── container/
│   │   │   ├── auto_registration/
│   │   │   │   ├── component_dir_namespaces/
│   │   │   │   │   ├── autoloading_loader_spec.rb
│   │   │   │   │   ├── deep_namespace_paths_spec.rb
│   │   │   │   │   ├── default_loader_spec.rb
│   │   │   │   │   ├── multiple_namespaces_spec.rb
│   │   │   │   │   └── namespaces_as_defaults_spec.rb
│   │   │   │   ├── custom_auto_register_proc_spec.rb
│   │   │   │   ├── custom_instance_proc_spec.rb
│   │   │   │   ├── custom_loader_spec.rb
│   │   │   │   ├── memoize_spec.rb
│   │   │   │   └── mixed_namespaces_spec.rb
│   │   │   ├── auto_registration_spec.rb
│   │   │   ├── autoloading_spec.rb
│   │   │   ├── importing/
│   │   │   │   ├── container_registration_spec.rb
│   │   │   │   ├── exports_spec.rb
│   │   │   │   ├── import_namespaces_spec.rb
│   │   │   │   ├── imported_component_protection_spec.rb
│   │   │   │   └── partial_imports_spec.rb
│   │   │   ├── lazy_loading/
│   │   │   │   ├── auto_registration_disabled_spec.rb
│   │   │   │   ├── bootable_components_spec.rb
│   │   │   │   └── manifest_registration_spec.rb
│   │   │   ├── plugins/
│   │   │   │   ├── bootsnap_spec.rb
│   │   │   │   ├── dependency_graph_spec.rb
│   │   │   │   ├── env_spec.rb
│   │   │   │   ├── logging_spec.rb
│   │   │   │   └── zeitwerk/
│   │   │   │       ├── eager_loading_spec.rb
│   │   │   │       ├── namespaces_spec.rb
│   │   │   │       ├── resolving_components_spec.rb
│   │   │   │       └── user_configured_loader_spec.rb
│   │   │   ├── plugins_spec.rb
│   │   │   └── providers/
│   │   │       ├── conditional_providers_spec.rb
│   │   │       ├── custom_provider_registrar_spec.rb
│   │   │       ├── custom_provider_superclass_spec.rb
│   │   │       ├── multiple_provider_dirs_spec.rb
│   │   │       ├── provider_sources/
│   │   │       │   └── provider_options_spec.rb
│   │   │       ├── registering_components_spec.rb
│   │   │       └── resolving_root_key_spec.rb
│   │   ├── did_you_mean_integration_spec.rb
│   │   ├── external_components_spec.rb
│   │   ├── import_spec.rb
│   │   └── settings_component_spec.rb
│   ├── spec_helper.rb
│   ├── support/
│   │   ├── coverage.rb
│   │   ├── loaded_constants_cleaning.rb
│   │   ├── rspec.rb
│   │   ├── tmp_directory.rb
│   │   ├── warnings.rb
│   │   └── zeitwerk_loader_registry.rb
│   └── unit/
│       ├── auto_registrar_spec.rb
│       ├── component_dir/
│       │   ├── component_for_identifier_key.rb
│       │   └── each_component_spec.rb
│       ├── component_dir_spec.rb
│       ├── component_spec.rb
│       ├── config/
│       │   ├── component_dirs_spec.rb
│       │   └── namespaces_spec.rb
│       ├── container/
│       │   ├── auto_register_spec.rb
│       │   ├── boot_spec.rb
│       │   ├── config/
│       │   │   └── root_spec.rb
│       │   ├── configuration_spec.rb
│       │   ├── decorate_spec.rb
│       │   ├── hooks/
│       │   │   ├── after_hooks_spec.rb
│       │   │   └── load_path_hook_spec.rb
│       │   ├── hooks_spec.rb
│       │   ├── import_spec.rb
│       │   ├── injector_spec.rb
│       │   ├── load_path_spec.rb
│       │   ├── monitor_spec.rb
│       │   └── notifications_spec.rb
│       ├── container_spec.rb
│       ├── errors_spec.rb
│       ├── identifier_spec.rb
│       ├── indirect_component_spec.rb
│       ├── loader/
│       │   └── autoloading_spec.rb
│       ├── loader_spec.rb
│       ├── magic_comments_parser_spec.rb
│       ├── provider/
│       │   └── source_spec.rb
│       └── provider_sources/
│           └── settings/
│               └── loader_spec.rb
└── zizmor.yml

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
github: hanami


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: "\U0001F41B Bug report"
about: See CONTRIBUTING.md for more information
title: ''
labels: bug, help wanted
assignees: ''

---

## Describe the bug

A clear and concise description of what the bug is.

## To Reproduce

Provide detailed steps to reproduce, **an executable script would be best**.

## Expected behavior

A clear and concise description of what you expected to happen.

## My environment

- Ruby version: ...
- OS: ...


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: Community support
    url: https://discourse.hanamirb.org
    about: Please ask and answer questions here.


================================================
FILE: .github/SUPPORT.md
================================================
## Support

If 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:


================================================
FILE: .github/workflows/ci-lint.yml
================================================
name: CI lint

on:
  push:
    branches: ["main", "release-*", "ci/*"]
    tags: ["v*"]
    paths:
      - ".github/**"
  pull_request:
    branches: ["main", "release-*"]
    paths:
      - ".github/**"
  schedule:
    - cron: "0 0 * * 0" # every Sunday at midnight

permissions: {}

jobs:
  zizmor:
    name: Run zizmor
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
        with:
          persist-credentials: false

      - name: Run zizmor
        uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d
        with:
          advanced-security: false


================================================
FILE: .github/workflows/ci.yml
================================================
# This file is synced from hanakai-rb/repo-sync

name: CI
run-name: ${{ github.ref_type == 'tag' && format('Release {0}', github.ref_name) || 'CI' }}

on:
  push:
    branches: ["main", "release-*", "ci/*"]
    tags: ["v*"]
  pull_request:
    branches: ["main", "release-*"]
  schedule:
    - cron: "30 4 * * *"

permissions:
  contents: read

jobs:
  tests:
    name: Tests (Ruby ${{ matrix.ruby }})
    runs-on: ubuntu-latest
    continue-on-error: ${{ matrix.optional || false }}
    strategy:
      fail-fast: false
      matrix:
        ruby:
          - "4.0"
          - "3.4"
          - "3.3"
          - "3.2"
          - "3.3.0"
          - "jruby"
        include:
          - ruby: "4.0"
            coverage: "true"
    env:
      COVERAGE: ${{ matrix.coverage }}
    steps:
      - name: Checkout
        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
        with:
          persist-credentials: false
      - name: Install package dependencies
        run: "[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS"
      - name: Set up Ruby
        uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # zizmor: ignore[cache-poisoning]
        with:
          ruby-version: ${{ matrix.ruby }}
          bundler-cache: true
      - name: Run all tests
        id: test
        run: |
          status=0
          bundle exec rake || status=$?
          if [ ${status} -ne 0 ] && [ "${{ matrix.optional }}" == "true" ]; then
            echo "::warning::Optional matrix job failed."
            echo "optional_fail=true" >> "${GITHUB_OUTPUT}"
            echo "optional_fail_status=${status}" >> "${GITHUB_OUTPUT}"
            exit 0  # Ignore error here to keep the green checkmark
          fi
          exit ${status}
      - name: Create optional failure comment
        if: ${{ matrix.optional && github.event.pull_request }}
        uses: hanakai-rb/repo-sync/pr-comment-artifact@main
        with:
          name: ci-ruby-${{ matrix.ruby }}
          pr-number: ${{ github.event.pull_request.number }}
          comment-tag: ruby-${{ matrix.ruby }}-optional-failure
          message: "ℹ️ Optional job failed: Ruby ${{ matrix.ruby }}"
          mode: ${{ steps.test.outputs.optional_fail == 'true' && 'upsert' || 'delete' }}

  workflow-keepalive:
    if: github.event_name == 'schedule'
    runs-on: ubuntu-latest
    permissions:
      actions: write
    steps:
      - uses: liskin/gh-workflow-keepalive@7a9194bad497f0b993708eeaf10fc0a2d726eb71

  release:
    runs-on: ubuntu-latest
    if: github.ref_type == 'tag'
    needs: tests
    steps:
      - name: Trigger release workflow
        uses: actions/github-script@450193c5abd4cdb17ba9f3ffcfe8f635c4bb6c2a
        with:
          github-token: ${{ secrets.RELEASE_MACHINE_DISPATCH_TOKEN }}
          script: |
            const tag = context.ref.replace("refs/tags/", "");
            const repo = context.repo.owner + "/" + context.repo.repo;

            const tagMessage = await github.rest.git.getTag({
              owner: context.repo.owner,
              repo: context.repo.repo,
              tag_sha: context.sha
            }).then(res => res.data.message).catch(() => "");
            const announce = /(skip-announce|no-announce)/i.test(tagMessage) ? "false" : "true";

            await github.rest.actions.createWorkflowDispatch({
              owner: "hanakai-rb",
              repo: "release-machine",
              workflow_id: "release.yml",
              ref: "main",
              inputs: { repo, tag, announce }
            });

            const workflowUrl = "https://github.com/hanakai-rb/release-machine/actions/workflows/release.yml";
            await core.summary
              .addHeading("Release Triggered")
              .addRaw(`Triggered release workflow for <code>${tag}</code>`)
              .addLink("View release workflow", workflowUrl)
              .write();
  



================================================
FILE: .github/workflows/pr-comments.yml
================================================
# This file is synced from hanakai-rb/repo-sync

# Downloads comment artifacts from completed workflows and posts them to PRs. This allows source
# workflows to run with read-only permissions on fork PRs while still posting comments via this
# privileged workflow that runs in the base repo context.
#
# Comment artifacts should be generated using the `hanakai-rb/repo-sync/pr-comment-artifact@main`
# action.

name: PR comments

on: # zizmor: ignore[dangerous-triggers]
  workflow_run:
    workflows: ["CI"]
    types:
      - completed

permissions:
  pull-requests: write

jobs:
  post-comments:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    if: github.event.workflow_run.event == 'pull_request'

    steps:
      - name: Post comments
        uses: hanakai-rb/repo-sync/pr-comments-from-artifacts@main
        with:
          workflow-run-id: ${{ github.event.workflow_run.id }}


================================================
FILE: .github/workflows/repo-sync-preview.yml
================================================
name: Repo-sync preview

on: # zizmor: ignore[dangerous-triggers]
  workflow_run:
    workflows: ["CI", "RuboCop", "CI lint"]
    types: [completed]
    branches:
      - "ci/repo-sync-preview-*"

jobs:
  report:
    runs-on: ubuntu-latest
    permissions: {}
    if: >
      github.event.workflow_run.event == 'push' &&
      github.event.workflow_run.head_repository.fork == false
    steps:
      - name: Dispatch status to repo-sync
        uses: actions/github-script@450193c5abd4cdb17ba9f3ffcfe8f635c4bb6c2a
        with:
          github-token: ${{ secrets.REPO_SYNC_DISPATCH_TOKEN }}
          script: |
            const { BRANCH, REPO, WORKFLOW, STATUS, RUN_URL } = process.env;
            await github.rest.actions.createWorkflowDispatch({
              owner: "hanakai-rb",
              repo: "repo-sync",
              workflow_id: "aggregate-preview-status.yml",
              ref: "main",
              inputs: {
                pr_number: BRANCH.replace("ci/repo-sync-preview-", ""),
                repo_name: REPO,
                workflow_name: WORKFLOW,
                status: STATUS,
                run_url: RUN_URL
              }
            });
        env:
          BRANCH: ${{ github.event.workflow_run.head_branch }}
          REPO: ${{ github.repository }}
          WORKFLOW: ${{ github.event.workflow_run.name }}
          STATUS: ${{ github.event.workflow_run.conclusion }}
          RUN_URL: ${{ github.event.workflow_run.html_url }}


================================================
FILE: .github/workflows/rubocop.yml
================================================
# frozen_string_literal: true

# This file is synced from hanakai-rb/repo-sync

name: RuboCop

on:
  push:
    branches: ["main", "release-*", "ci/*"]
    tags: ["v*"]
  pull_request:
    branches: ["main", "release-*"]

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      BUNDLE_ONLY: tools

    steps:
      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
        with:
          persist-credentials: false

      - name: Set up Ruby 4.0
        uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # zizmor: ignore[cache-poisoning]
        with:
          ruby-version: 4.0
          bundler-cache: true

      - name: Run RuboCop
        run: bundle exec rubocop --parallel


================================================
FILE: .gitignore
================================================
*.gem
*.rbc
*.log
/.rubocop*
/.config
/coverage/
/InstalledFiles
/pkg/
/spec/reports/
/test/tmp/
/test/version_tmp/
/tmp/

## Specific to RubyMotion:
.dat*
.repl_history
build/

## Documentation cache and generated files:
/.yardoc/
/_yardoc/
/doc/
/rdoc/

## Environment normalisation:
/.bundle/
/vendor/bundle
/lib/bundler/man/

# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
# .ruby-version
# .ruby-gemset

# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
Gemfile.lock

## Specific to RubyMine
.idea

## Tests
/spec/examples.txt
/spec/fixtures/test/tmp/cache


================================================
FILE: .rspec
================================================
--color
--require spec_helper
--order random
--warnings


================================================
FILE: .yardopts
================================================
--no-private
--hide-void-return

--markup-provider=redcarpet
--markup=markdown


================================================
FILE: CHANGELOG.md
================================================
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Break Versioning](https://www.taoensso.com/break-versioning).

## [Unreleased]

[Unreleased]: https://github.com/dry-rb/dry-system/compare/v1.2.5...main

## [1.2.5] - 2025-12-01

### Fixed

- Pass through keyword arguments to monitored objects in `monitoring` plugin. (@yuszuv in #290)

[1.2.5]: https://github.com/dry-rb/dry-system/compare/v1.2.4...v1.2.5

## [1.2.4] - 2025-08-14


### Fixed

- Allow imported components to be lazy loaded when both strings and symbols are given as the
namespace to `Container.import` (@timriley in #287)


[Compare v1.2.3...v1.2.4](https://github.com/dry-rb/dry-system/compare/v1.2.3...v1.2.4)

## [1.2.3] - 2025-07-29


### Added

- Add :register after-hook to detect container key registration dynamically. (via #274, @alassek)

### Fixed

- Re-register components from manifest registrars in apps that reload the container (e.g. when
using dry-rails and Rails development mode) (via #286, @alassek)

### Changed

- :finalize after-hook now executes before container freeze to allow mutation. (via #274, @alassek)

[Compare v1.2.2...v1.2.3](https://github.com/dry-rb/dry-system/compare/v1.2.2...v1.2.3)

## [1.2.2] - 2025-01-31


### Fixed

- Syntax errors on 3.3.0 (@flash-gordon, see #284)


[Compare v1.2.1...v1.2.2](https://github.com/dry-rb/dry-system/compare/v1.2.1...v1.2.2)

## [1.2.1] - 2025-01-08


### Fixed

- `eager_load` was removed from `finalize!`. It was introduced with `true` by default that
wasn't the intention #281 (via #282) (@flash-gordon)


[Compare v1.2.0...v1.2.1](https://github.com/dry-rb/dry-system/compare/v1.2.0...v1.2.1)

## [1.2.0] - 2025-01-07


### Added

- Option to skip eager loading during finalize with `eager_load: false` (via #276) (@cllns)

### Changed

- Update required Ruby version to 3.1 (@flash-gordon)

[Compare v1.1.1...v1.2.0](https://github.com/dry-rb/dry-system/compare/v1.1.1...v1.2.0)

## [1.1.1] - 2024-11-03


### Fixed

- Restore `ProviderRegistrar#find_and_load_provider` as an alias of `#[]`


[Compare v1.1.0...v1.1.1](https://github.com/dry-rb/dry-system/compare/v1.1.0...v1.1.1)

## [1.1.0] - 2024-10-31



[Compare v1.1.0.beta2...v1.1.0](https://github.com/dry-rb/dry-system/compare/v1.1.0.beta2...v1.1.0)

## [1.1.0.beta2] - 2024-09-25


### Changed

- Allow provider sources to use a custom superclass. This requires a custom provider registrar
to be configured, with its own implementations of `#provider_source_class` (the superclass to
use) and `#provider_source_options` (custom initialization args to pass to the provider
source). (via #275) (@alassek, @timriley)

[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)

## [1.1.0.beta1] - 2024-07-03


### Added

- Add `Dry::System::ProviderRegistrar#target_container`, to be passed when initializing
providers. By default this is an alias of `#container`. This allows for custom provider
registrars to override `#target_container` to provide a custom `#target` within providers.
An overridden value **MUST** still wrap the original `#target_container` to ensure components
are registered in the right place. (via #270) (@timriley)

### Changed

- Make `Dry::System::ProviderRegistrar` public API (via #270) (@timriley)
- When registering a provider source, you can now provide a `provider_options:` hash of default
options for providers to be registered using that source. The one provider option currently
supported is `namespace:`. (via #271) (@timriley)
- Load providers when accessing them via `Dry::System::ProviderRegistrar#[]`. The previous,
behavior of `#[]` returning `nil` if a provider had not been explicitly loaded was a
potential source of confusion. Now `#[]` can serve as the one and only interface for fetching
a provider. (via #273) (@timriley)

[Compare v1.0.1...v1.1.0.beta1](https://github.com/dry-rb/dry-system/compare/v1.0.1...v1.1.0.beta1)

## [1.0.1] - 2022-11-18


### Changed

- Bumped dry-auto_inject dependency to its 1.0.0 final release (@solnic)

[Compare v1.0.0...v1.0.1](https://github.com/dry-rb/dry-system/compare/v1.0.0...v1.0.1)

## [1.0.0] - 2022-11-18


### Fixed

- Only use DidYouMean-integrated Error for Component loading failure (via #261) (@cllns + @solnic)

### Changed

- This version uses dry-core 1.0 and dry-configurable 1.0 (@solnic + @flash-gordon)
- Raise error on import after finalize (via #254) (@timriley + @tak1n)
- Validate settings even if loader does not set value (via #246) (@oeoeaio)
- Remove all deprecated functionality and deprecation messages (via #255) (@timriley)
- Use main dry/monitor entrypoint for autoloading (via #257) (@timriley)
- Use dry-configurable 1.0 (via 43c79095ccf54c6251e825ae20c97a9415e78209) (@flash-gordon)
- Use dry-core 1.0 (via 3d0cf95aef120601e67f3e8fbbf16d004017d376) (@flash-gordon)
- Remove dry-container dependency and update to use `Dry::Core::Container` (via 2b76554e5925fc92614627d5c1e0a9177cecf12f) (@solnic)

[Compare v0.27.2...v1.0.0](https://github.com/dry-rb/dry-system/compare/v0.27.2...v1.0.0)

## [0.27.2] - 2022-10-17


### Fixed

- Removed remaining manual require left-overs (@solnic)


[Compare v0.27.1...v0.27.2](https://github.com/dry-rb/dry-system/compare/v0.27.1...v0.27.2)

## [0.27.1] - 2022-10-15


### Fixed

- Tweak for zeitwerk loader (@flash-gordon)


[Compare v0.27.0...v0.27.1](https://github.com/dry-rb/dry-system/compare/v0.27.0...v0.27.1)

## [0.27.0] - 2022-10-15


### Changed

- [BREAKING] Use zeitwerk for auto-loading dry-system (@flash-gordon + @solnic)

From now on you need to do `require "dry/system"` as it sets up its Zeitwerk loader and from
there, everything else will be auto-loaded.

[Compare v0.26.0...v0.27.0](https://github.com/dry-rb/dry-system/compare/v0.26.0...v0.27.0)

## [0.26.0] - 2022-10-08


### Changed

- Update dry-configurable dependency to 0.16.0 and make internal adjustments to suit (@timriley in #249)
- Remove now-unused concurrent-ruby gem dependency (@timriley in #250)

[Compare v0.25.0...v0.26.0](https://github.com/dry-rb/dry-system/compare/v0.25.0...v0.26.0)

## [0.25.0] - 2022-07-10


### Fixed

- Fix incorrect type in `ManifestRegistrar#finalize!` (@alassek)

### Changed

- Import root components via `nil` import namespace (via #236) (@timriley)
- Allow deeper `Provider::Source` hierarchies (via #240) (@timriley + @solnic)
- Prefer local components when importing (via #241) (@timriley  + @solnic)

[Compare v0.24.0...v0.25.0](https://github.com/dry-rb/dry-system/compare/v0.24.0...v0.25.0)

## [0.24.0] - 


### Changed

- dry-struct depedency was removed (@flash-gordon)

[Compare v0.23.0...master](https://github.com/dry-rb/dry-system/compare/v0.23.0...master)

## [0.23.0] - 2022-02-08

This is a major overhaul of bootable components (now known as “Providers”), and brings major advancements to other areas, including container imports and exports.

Deprecations are in place for otherwise breaking changes to commonly used parts of dry-system, though some breaking changes remain.

This prepares the way for dry-system 1.0, which will be released in the coming months.


### Added

- Containers can configure specific components for export using `config.exports` (@timriley in #209).

  ```ruby
  class MyContainer < Dry::System::Container
    configure do |config|
      config.exports = %w[component_a component_b]
    end
  end
  ```

  Containers importing another container with configured exports will import only those components.

  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.
- 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)

  This makes it possible to enable Zeitwerk with a one-liner:

  ```ruby
  class MyContainer < Dry::System::Container
    use :zeitwerk

    configure do |config|
      config.component_dirs.add "lib"
      # ...
    end
  end
  ```

  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`.

  The plugin accepts the following options:

  - `loader:` - (optional) to use a pre-initialized loader, if required.
  - `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.
  - `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`.
  - `debug:` - (optional) a bool to set whether Zeitwerk should log to `$stdout`.
- New `Identifier#end_with?` and `Identifier#include?` predicates (@timriley in #219)

  These are key segment-aware predicates that can be useful when checking components as part of container configuration.

  ```ruby
  identifier.key # => "articles.operations.create"

  identifier.end_with?("create") # => true
  identifier.end_with?("operations.create") # => true
  identifier.end_with?("ate") # => false, not a whole segment
  identifier.end_with?("nope") # => false, not part of the key at all

  identifier.include?("operations") # => true
  identifier.include?("articles.operations") # => true
  identifier.include?("operations.create") # => true
  identifier.include?("article") # false, not a whole segment
  identifier.include?("update") # => false, not part of the key at all
  ```
- An `instance` setting for component dirs allows simpler per-dir control over component instantiation (@timriley in #215)

  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.

  ```ruby
  configure do |config|
    config.component_dirs.add "lib" do |dir|
      dir.instance = proc do |component|
        if component.identifier.include?("workers")
          # Register classes for jobs
          component.loader.constant(component)
        else
          # Otherwise register regular instances per default loader
          component.loader.call(component)
        end
      end
    end
  end
  ```

  For complete control of component loading, you should continue to configure the component dir’s `loader` instead.
- 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).

  The error shows expected and found class names, and inflector configuration that may be required in the case of class names containing acronyms.

### Fixed

- 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).
- Providers can no longer implicitly re-start themselves while in the process of starting and cause an infinite loop (@timriley #213).

  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.

### Changed

- “Bootable components” (also referred to in some places simply as “components”) have been renamed to “Providers” (@timriley in #200).

  Register a provider with `Dry::System::Container.register_provider` (`Dry::System::Container.boot` has been deprecated):

  ```ruby
  MyContainer.register_provider(:mailer) do
    # ...
  end
  ```
- Provider `init` lifecycle step has been deprecated and renamed to `prepare` (@timriley in #200).

  ```ruby
  MyContainer.reigster_provider(:mailer) do
    # Rename `init` to `prepare`
    prepare do
      require "some/third_party/mailer"
    end
  end
  ```
- Provider behavior is now backed by a class per provider, known as the “Provider source” (@timriley in #202).

  The provider source class is created for each provider as a subclass of `Dry::System::Provider::Source`.

  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:

  ```ruby
  MyContainer.reigster_provider(:mailer) do
    prepare do
      require "some/third_party/mailer"
      @some_config = ThirdParty::Mailer::Config.new
    end

    start do
      # Since the `prepare` step will always run before start, we can access
      # @some_config here
      register "mailer", ThirdParty::Mailer.new(@some_config)
    end
  end
  ```

  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.

  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:

  ```ruby
  MyContainer.register_provider(:mailer, source: Class.new(Dry::System::Provider::Source) {
    # The provider lifecycle steps are ordinary methods
    def prepare
    end

    def start
      mailer = some_complex_logic_to_build_the_mailer(some: "config")
      register(:mailer, mailer)
    end

    private

    def some_complex_logic_to_build_the_mailer(**options)
      # ...
    end
  })
  ```
- The block argument to `Dry::System::Container.register_provider` (previously `.boot`) has been deprecated. (@timriley in #202).

  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).

  To access the target container, you can use `#target_container` (or `#target` as a convenience alias) instead.

  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).
- `use(provider_name)` inside a provider step has been deprecated. Use `target_container.start(provider_name)` instead (@timriley in #211 and #224)

  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)`.
- `method_missing`-based delegation within providers to target container registrations has been removed (**BREAKING**) (@timriley in #202)

  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:

  ```ruby
  MyContainer.register_provider(:mailer, namespace: true) do
    prepare do
      register :config, "mailer config here"
    end

    start do
      config # => "mailer config here"
    end
  end
  ```
- 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).

  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):

  ```ruby
  require "dry/system"

  Dry::System.register_provider_sources(path)
  ```

  You can register an individual external provider source via `Dry::System.register_provider_source` (`Dry::System.register_component` has been deprecated):

  ```ruby
  Dry::System.register_provider_source(:something, group: :my_gem) do
    start do
      # ...
    end
  end
  ```

  Just like providers, you can also register a class as an external provider source:

  ```ruby
  module MyGem
    class MySource < Dry::System::Provider::Source
      def start
        # ...
      end
    end
  end

  Dry::System.register_provider_source(:something, group: :my_gem, source: MyGem::MySource)
  ```

  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.
- Registering a provider using an explicitly named external provider source via `key:` argument is deprecated, use the `source:` argument instead (@timriley in #202).

  You can register a provider using the same name as an external provider source by specifying the `from:` argument only, as before:

  ```ruby
  # Elsewhere
  Dry::System.register_provider_source(:something, group: :my_gem) { ... }

  # In your app:
  MyContainer.register_provider(:something, from: :my_gem)
  ```

  When you wish the name your provider differently, this is when you need to use the `source:` argument:

  ```ruby
  MyContainer.register_provider(:differently_named, from: :my_gem, source: :something)
  ```

  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.
- Provider source settings are now defined using dry-configurable’s `setting` API at the top-level scope (@timriley in #202).

  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`:

  ```ruby
  # In the external provider source
  Dry::System.register_provider_source(:something, group: :my_gem) do
    setting :my_option

    start do
      # Do something with `config.my_option` here
    end
  end
  ```

  When using an external provider source, configure the source via the `#configure`:

  ```ruby
  # In your application's provider using the external source
  MyContainer.register_provider(:something, from: :my_gem) do
    configure do |config|
      config.my_option = "some value"
    end
  end
  ```

  To provide default values and type checking or constraints for your settings, use the dry-configurable’s `default:` and `constructor:` arguments:

  ```ruby
  # Constructor can take any proc being passed the provided value
  setting :my_option, default: "hello", constructor: -> (v) { v.to_s.upcase }

  # Constructor will also work with dry-types objects
  setting :my_option, default: "hello", constructor: Types::String.constrained(min_size: 3)
  ```
- External provider sources can define their own methods for use by the providers alongside lifecycle steps (@timriley in #202).

  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:

  ```ruby
  # In the external provider source

  module MyGem
    class MySource < Dry::System::Provider::Source
      # Standard lifecycle steps
      def start
        # Do something with @on_start here
      end

      # Custom behavior available when this provider source is used in a provider
      def on_start(&block)
        @on_start = block
      end
    end
  end

  Dry::System.register_provider_source(:something, group: :my_gem, source: MyGem::MySource)

  # In your application's provider using the external source

  MyContainer.register_provider(:something, from: :my_gem) do
    # Use the custom method!
    on_start do
      # ...
    end
  end
  ```
- Providers can be registered conditionally using the `if:` option (@timriley in #218).

  You should provide a simple truthy or falsey value to `if:`, and in the case of falsey value, the provider will not be registered.

  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.
- `bootable_dirs` container setting has been deprecated and replaced by `provider_dirs` (@timriley in #200).

  The default value for `provider_dirs` is now `"system/providers`".
- Removed the unused `system_dir` container setting (**BREAKING**) (@timriley in #200)

  If you’ve configured this inside your container, you can remove it.
- 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).
- 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).

  ```ruby
  MyContainer.register_provider(:settings, from: :dry_system) do
    # ...
  end
- 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).

  This `setting` method uses the dry-configurable setting API:

  ```ruby
  MyContainer.register_provider(:settings, from: :dry_system) do
    settings do
      # Previously:
      # key :my_int_setting, MyTypes::Coercible::Integer

      # Now:
      setting :my_setting, default: 0, constructor: MyTypes::Coercible::Integer
    end
  end
  ```
- The `:settings` provider source now requires the dotenv gem to load settings from `.env*` files (**BREAKING**) (@timriley in #204)

  To ensure you can load your settings from these `.env*` files, add `gem "dotenv"` to your `Gemfile`.
- `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).

   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.
- `Dry::System::Container.configure(&block)` will now finalize (freeze) the `config` object by default, before returning (@timriley in #207).

  You can opt out of this behavior by passing the `finalize_config: false` option:

  ```ruby
  class MyContainer < Dry::System::Container
    configure(finalize_config: false) do |config|
      # ...
    end

    # `config` is still non-finalized here
  end
  ```
- `Dry::System::Container.finalize!` will call `.configured!` (if it has not yet been called) before doing its work (@timriley in #207)

  This ensures config finalization is an intrinsic part of the overall container finalization process.
- The `Dry::System::Container` `before(:configure)` hook has been removed (**BREAKING**) (@timriley in #207).

  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.
- 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).

  This ensures the plugin settings are available immediately after you’ve enabled the plugin via `Dry::System::Container.use`.
- 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)
- 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)

  To import specific components:

  ```ruby
  class MyContainer < Dry::System::Container
    # config, etc.

    # Will import components with keys "other.component_a", "other.component_b"
    import(
      keys: %w[component_a component_b],
      from: OtherContainer,
      as: :other
    )
  ```

  Omitting `keys:` will import all the components available from the other container.
- Components imported into a container from another will be protected from subsequent export unless explicitly configured in `config.exports` (@timriley in #209)

  Imported components are considered “private” by default because they did not originate in container that imported them.

  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.
- Container imports are now made without finalizing the exporting container in most cases, ensuring more efficient imports (@timriley in #209)

  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`.
- [Internal] The `manual_registrar` container setting and associated `ManualRegistrar` class have been renamed to `manifest_registrar` and `ManifestRegistrar` respectively (**BREAKING**) (@timriley in #208).
- The default value for the container `registrations_dir` setting has been changed from `"container"` to `"system/registrations"` (**BREAKING**) (@timriley in #208)
- The `:dependency_graph` plugin now supports all dry-auto_inject injector strategies (@davydovanton and @timriley in #214)

[Compare v0.22.0...v0.23.0](https://github.com/dry-rb/dry-system/compare/v0.22.0...v0.23.0)

## [0.22.0] - 2022-01-06


### Added

- 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)

### Changed

- Deprecated `Dry::System::Config::Namespaces#root` as the way to add and configure a root namespace. Use `#add_root` instead (@timriley in #195)
- Allow bootsnap plugin to use bootsnap on Ruby versions up to 3.0 (pusewicz in #196)

[Compare v0.21.0...v0.22.0](https://github.com/dry-rb/dry-system/compare/v0.21.0...v0.22.0)

## [0.21.0] - 2021-11-01


### Added

- 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)

### Changed

- `default_namespace` setting on component dirs has been deprecated. Add a component dir namespace instead, e.g. instead of:

  ```ruby
  # Inside Dry::System::Container.configure
  config.component_dirs.add "lib" do |dir|
    dir.default_namespace = "admin"
  end
  ```

  Add this:

  ```ruby
  config.component_dirs.add "lib" do |dir|
    dir.namespaces.add "admin", key: nil
  end
  ```

  (@timriley in #181)
- `Dry::System::Component#path` has been removed and replaced by `Component#require_path` and `Component#const_path` (@timriley in #181)
- Unused `Dry::System::FileNotFoundError` and `Dry::System::InvalidComponentIdentifierTypeError` errors have been removed (@timriley in #194)
- Allow bootsnap for Rubies up to 3.0.x (via #196) (@pusewicz)

[Compare v0.20.0...v0.21.0](https://github.com/dry-rb/dry-system/compare/v0.20.0...v0.21.0)

## [0.20.0] - 2021-09-12


### Fixed

- Fixed dependency graph plugin to work with internal changes introduced in 0.19.0 (@wuarmin in #173)
- 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)
- Fixed compatibility of `finalize!` signature provided in `Container::Stubs` (@mpokrywka in #178)

### Changed

- [internal] Upgraded to new `setting` API provided in dry-configurable 0.13.0 (@timriley in #179)

[Compare v0.19.2...v0.20.0](https://github.com/dry-rb/dry-system/compare/v0.19.2...v0.20.0)

## [0.19.2] - 2021-08-30


### Changed

- [internal] Improved compatibility with upcoming dry-configurable 0.13.0 release (@timriley in #186)

[Compare v0.18.2...v0.19.2](https://github.com/dry-rb/dry-system/compare/v0.18.2...v0.19.2)

## [0.18.2] - 2021-08-30


### Changed

- [internal] Improved compatibility with upcoming dry-configurable 0.13.0 release (@timriley in #187)

[Compare v0.19.1...v0.18.2](https://github.com/dry-rb/dry-system/compare/v0.19.1...v0.18.2)

## [0.19.1] - 2021-07-11


### Fixed

- Check for registered components (@timriley in #175)


[Compare v0.19.0...v0.19.1](https://github.com/dry-rb/dry-system/compare/v0.19.0...v0.19.1)

## [0.19.0] - 2021-04-22

This 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.

### Added

- 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.

  Each added component dir is relative to the container's `root`, and can have its own set of settings configured:

  ```ruby
  class MyApp::Container < Dry::System::Container
    configure do |config|
      config.root = __dir__

      # Defaults for all component dirs can be configured separately
      config.component_dirs.auto_register = true # default is already true

      # Component dirs can be added and configured independently
      config.component_dirs.add "lib" do |dir|
        dir.add_to_load_path = true # defaults to true
        dir.default_namespace = "my_app"
      end

      # All component dir settings are optional. Component dirs relying on default
      # settings can be added like so:
      config.component_dirs.add "custom_components"
    end
  end
  ```

  The following settings are available for configuring added `component_dirs`:

  - `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
  - `add_to_load_path`, a boolean
  - `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)
  - `loader`, a custom replacement for the default `Dry::System::Loader` to be used for the component dir
  - `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

  _All component dir settings are optional._

  (@timriley in #155, #157, and #162)
- A new autoloading-friendly `Dry::System::Loader::Autoloading` is available, which is tested to work with [Zeitwerk](https://github.com/fxn/zeitwerk) 🎉

  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.

  This loader presumes an autoloading system like Zeitwerk has already been enabled and appropriately configured.

  A recommended setup is as follows:

  ```ruby
  require "dry/system/container"
  require "dry/system/loader/autoloading"
  require "zeitwerk"

  class MyApp::Container < Dry::System::Container
    configure do |config|
      config.root = __dir__

      config.component_dirs.loader = Dry::System::Loader::Autoloading
      config.component_dirs.add_to_load_path = false

      config.component_dirs.add "lib" do |dir|
        # ...
      end
    end
  end

  loader = Zeitwerk::Loader.new
  loader.push_dir MyApp::Container.config.root.join("lib").realpath
  loader.setup
  ```

  (@timriley in #153)
- [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)

### Changed

- Components with `# auto_register: false` magic comments in their source files are now properly ignored when lazy loading (@timriley in #155)
- `# memoize: true` and `# memoize: false` magic comments at top of component files are now respected (@timriley in #155)
- [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)
- [BREAKING] `auto_register` container setting has been removed. Configured directories to be auto-registered by adding `component_dirs` instead (@timriley in #155)
- [BREAKING] `default_namespace` container setting has been removed. Set it when adding `component_dirs` instead (@timriley in #155)
- [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)
- [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)
- [BREAKING] `Dry::System::Container.auto_register!` has been removed. Configure `component_dirs` instead. (@timriley in #157)
- [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)
- [BREAKING] `Dry::System::Container.require_path` has been removed. Provide custom require behavior by configuring your own `loader` (@timriley in #153)

[Compare v0.18.1...v0.19.0](https://github.com/dry-rb/dry-system/compare/v0.18.1...v0.19.0)

## [0.18.1] - 2020-08-26


### Fixed

- Made `Booter#boot_files` a public method again, since it was required by dry-rails (@timriley)


[Compare v0.18.0...v0.18.1](https://github.com/dry-rb/dry-system/compare/v0.18.0...v0.18.1)

## [0.18.0] - 2020-08-24


### Added

- New `bootable_dirs` setting on `Dry::System::Container`, which accepts paths to multiple directories for looking up bootable component files. (@timriley in PR #151)

  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.

  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.


[Compare v0.17.0...v0.18.0](https://github.com/dry-rb/dry-system/compare/v0.17.0...v0.18.0)

## [0.17.0] - 2020-02-19


### Fixed

- Works with the latest dry-configurable version (issue #141) (@solnic)

### Changed

- Depends on dry-configurable `=> 0.11.1` now (@solnic)

[Compare v0.16.0...v0.17.0](https://github.com/dry-rb/dry-system/compare/v0.16.0...v0.17.0)

## [0.16.0] - 2020-02-15


### Changed

- Plugins can now define their own settings which are available in the `before(:configure)` hook (@solnic)
- Dependency on dry-configurable was bumped to `~> 0.11` (@solnic)

[Compare v0.15.0...v0.16.0](https://github.com/dry-rb/dry-system/compare/v0.15.0...v0.16.0)

## [0.15.0] - 2020-01-30


### Added

- New hook - `before(:configure)` which a plugin should use if it needs to declare new settings (@solnic)

```ruby
# in your plugin code
before(:configure) { setting :my_new_setting }

after(:configure) { config.my_new_setting = "awesome" }
```


### Changed

- Centralize error definitions in `lib/dry/system/errors.rb` (@cgeorgii)
- All built-in plugins use `before(:configure)` now to declare their settings (@solnic)

[Compare v0.14.1...v0.15.0](https://github.com/dry-rb/dry-system/compare/v0.14.1...v0.15.0)

## [0.14.1] - 2020-01-22


### Changed

- Use `Kernel.require` explicitly to avoid issues with monkey-patched `require` from ActiveSupport (@solnic)

[Compare v0.14.0...v0.14.1](https://github.com/dry-rb/dry-system/compare/v0.14.0...v0.14.1)

## [0.14.0] - 2020-01-21


### Fixed

- Misspelled plugin name raises meaningful error (issue #132) (@cgeorgii)
- Fail fast if auto_registrar config contains incorrect path (@cutalion)


[Compare v0.13.2...v0.14.0](https://github.com/dry-rb/dry-system/compare/v0.13.2...v0.14.0)

## [0.13.2] - 2019-12-28


### Fixed

- More keyword warnings (flash-gordon)


[Compare v0.13.1...v0.13.2](https://github.com/dry-rb/dry-system/compare/v0.13.1...v0.13.2)

## [0.13.1] - 2019-11-07


### Fixed

- Fixed keyword warnings reported by Ruby 2.7 (flash-gordon)
- Duplicates in `Dry::System::Plugins.loaded_dependencies` (AMHOL)


[Compare v0.13.0...v0.13.1](https://github.com/dry-rb/dry-system/compare/v0.13.0...v0.13.1)

## [0.13.0] - 2019-10-13


### Added

- `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)
  ```ruby
  App.resolve('missing.dep') { :fallback } # => :fallback
  ```

### Changed

- [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)

[Compare v0.12.0...v0.13.0](https://github.com/dry-rb/dry-system/compare/v0.12.0...v0.13.0)

## [0.12.0] - 2019-04-24


### Changed

- Compatibility with dry-struct 1.0 and dry-types 1.0 (flash-gordon)

[Compare v0.11.0...v0.12.0](https://github.com/dry-rb/dry-system/compare/v0.11.0...v0.12.0)

## [0.11.0] - 2019-03-22


### Changed

- [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)
- [internal] Compatibility with dry-struct 0.7.0 and dry-types 0.15.0

[Compare v0.10.1...v0.11.0](https://github.com/dry-rb/dry-system/compare/v0.10.1...v0.11.0)

## [0.10.1] - 2018-07-05


### Added

- Support for stopping bootable components with `Container.stop(component_name)` (GustavoCaso)

### Fixed

- 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)


[Compare v0.10.0...v0.10.1](https://github.com/dry-rb/dry-system/compare/v0.10.0...v0.10.1)

## [0.10.0] - 2018-06-07


### Added

- 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)

  ```ruby
  class MyContainer < Dry::System::Container
    configure do |config|
      config.inflector = Dry::Inflector.new do |inflections|
        inflections.acronym('API')
      end
    end
  end
  ```

### Changed

- A helpful error will be raised if an invalid setting value is provided (GustavoCaso)
- When using setting plugin, will use default values from types (GustavoCaso)
- Minimal supported ruby version was bumped to `2.3` (flash-gordon)
- `dry-struct` was updated to `~> 0.5` (flash-gordon)

[Compare v0.9.2...v0.10.0](https://github.com/dry-rb/dry-system/compare/v0.9.2...v0.10.0)

## [0.9.2] - 2018-02-08


### Fixed

- Default namespace no longer breaks resolving dependencies with identifier that includes part of the namespace (ie `mail.mailer`) (GustavoCaso)


[Compare v0.9.1...v0.9.2](https://github.com/dry-rb/dry-system/compare/v0.9.1...v0.9.2)

## [0.9.1] - 2018-01-03


### Fixed

- Plugin dependencies are now auto-required and a meaningful error is raised when a dep failed to load (solnic)


[Compare v0.9.0...v0.9.1](https://github.com/dry-rb/dry-system/compare/v0.9.0...v0.9.1)

## [0.9.0] - 2018-01-02


### Added

- Plugin API (solnic)
- `:env` plugin which adds support for setting `env` config value (solnic)
- `:logging` plugin which adds a default logger (solnic)
- `:decorate` plugin for decorating registered objects (solnic)
- `:notifications` plugin adding pub/sub bus to containers (solnic)
- `:monitoring` plugin which adds `monitor` method for monitoring object method calls (solnic)
- `:bootsnap` plugin which adds support for bootsnap (solnic)

### Changed

- [BREAKING] renamed `Container.{require=>require_from_root}` (GustavoCaso)

[Compare v0.8.1...v0.9.0](https://github.com/dry-rb/dry-system/compare/v0.8.1...v0.9.0)

## [0.8.1] - 2017-10-17


### Fixed

- Aliasing an external component works correctly (solnic)
- Manually calling `:init` will also finalize a component (solnic)


[Compare v0.8.0...v0.8.1](https://github.com/dry-rb/dry-system/compare/v0.8.0...v0.8.1)

## [0.8.0] - 2017-10-16


### Added

- Support for external bootable components (solnic)
- Built-in `:system` components including `:settings` component (solnic)

### Fixed

- Lazy-loading components work when a container has `default_namespace` configured (GustavoCaso)

### Changed

- [BREAKING] Improved boot DSL with support for namespacing and lifecycle before/after callbacks (solnic)

[Compare v0.7.3...v0.8.0](https://github.com/dry-rb/dry-system/compare/v0.7.3...v0.8.0)

## [0.7.3] - 2017-08-02


### Fixed

- `Container.enable_stubs!` calls super too, which actually adds `stub` API (solnic)
- Issues with lazy-loading and import in stub mode are gone (solnic)


[Compare v0.7.2...v0.7.3](https://github.com/dry-rb/dry-system/compare/v0.7.2...v0.7.3)

## [0.7.2] - 2017-08-02


### Added

- `Container.enable_stubs!` for test environments which enables stubbing components (GustavoCaso)

### Changed

- Component identifiers can now include same name more than once ie `foo.stuff.foo` (GustavoCaso)
- `Container#boot!` was renamed to `Container#start` (davydovanton)
- `Container#boot` was renamed to `Container#init` (davydovanton)

[Compare v0.7.1...v0.7.2](https://github.com/dry-rb/dry-system/compare/v0.7.1...v0.7.2)

## [0.7.1] - 2017-06-16


### Changed

- Accept string values for Container's `root` config (timriley)

[Compare v0.7.0...v0.7.1](https://github.com/dry-rb/dry-system/compare/v0.7.0...v0.7.1)

## [0.7.0] - 2017-06-15


### Added

- 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)
- 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)
- `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):

  ```ruby
  class MyContainer < Dry::System::Container
    auto_register!('lib') do |config|
      config.instance do |component|
        # custom logic for initializing a component
      end

      config.exclude do |component|
        # return true to skip auto-registration of the component, e.g.
        # component.path =~ /entities/
      end
    end
  end
  ```
- A helpful error will be raised if a bootable component's finalize block name doesn't match its boot file name (GustavoCaso)

### Changed

- The `default_namespace` container setting now supports multi-level namespaces (GustavoCaso)
- `Container.auto_register!` yields a configuration block instead of a block for returning a custom instance (see above) (GustavoCaso)
- `Container.import` now requires an explicit local name for the imported container (e.g. `import(local_name: AnotherContainer)`) (timriley)

[Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-system/compare/v0.6.0...v0.7.0)

## [0.6.0] - 2016-02-02


### Changed

- Lazy load components as they are resolved, rather than on injection (timriley)
- Perform registration even though component already required (blelump)

[Compare v0.5.1...v0.6.0](https://github.com/dry-rb/dry-system/compare/v0.5.1...v0.6.0)

## [0.5.1] - 2016-08-23


### Fixed

- Undefined locals or method calls will raise proper exceptions in Lifecycle DSL (aradunovic)


[Compare v0.5.0...v0.5.1](https://github.com/dry-rb/dry-system/compare/v0.5.0...v0.5.1)

## [0.5.0] - 2016-08-15

for multi-container setups. As part of this release `dry-system` has been renamed to `dry-system`.

### Added

- Boot DSL with:
  - Lifecycle triggers: `init`, `start` and `stop` (solnic)
  - `use` method which auto-boots a dependency and makes it available in the booting context (solnic)
- When a component relies on a bootable component, and is being loaded in isolation, the component will be booted automatically (solnic)

### Changed

- [BREAKING] `Dry::Component::Container` is now `Dry::System::Container` (solnic)
- [BREAKING] Configurable `loader` is now a class that accepts container's config and responds to `#constant` and `#instance` (solnic)
- [BREAKING] `core_dir` renameda to `system_dir` and defaults to `system` (solnic)
- [BREAKING] `auto_register!` yields `Component` objects (solnic)

[Compare v0.4.3...v0.5.0](https://github.com/dry-rb/dry-system/compare/v0.4.3...v0.5.0)

## [0.4.3] - 2016-08-01


### Fixed

- 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))


[Compare v0.4.2...v0.4.3](https://github.com/dry-rb/dry-system/compare/v0.4.2...v0.4.3)

## [0.4.2] - 2016-07-26


### Fixed

- 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)


[Compare v0.4.1...v0.4.2](https://github.com/dry-rb/dry-system/compare/v0.4.1...v0.4.2)

## [0.4.1] - 2016-07-26


### Fixed

- Require the 0.4.0 release of dry-auto_inject for the features below (in 0.4.0) to work properly (timriley)


[Compare v0.4.0...v0.4.1](https://github.com/dry-rb/dry-system/compare/v0.4.0...v0.4.1)

## [0.4.0] - 2016-07-26


### Added

- 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))

  ```ruby
  # Set up container with default namespace
  module Admin
    class Container < Dry::Component::Container
      configure do |config|
        config.root = Pathname.new(__dir__).join("../..")
        config.default_namespace = "admin"
      end
    end

    Import = Container.injector
  end

  module Admin
    class CreateUser
      # "users.repository" will resolve an Admin::Users::Repository instance,
      # where previously you had to identify it as "admin.users.repository"
      include Admin::Import["users.repository"]
    end
  end
  ```
- 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))
- 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))

### Changed

- 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))

[Compare v0.3.0...v0.4.0](https://github.com/dry-rb/dry-system/compare/v0.3.0...v0.4.0)

## [0.3.0] - 2016-06-18

Removed two pieces that are moving to dry-web:

### Changed

- Removed two pieces that are moving to dry-web:
- Removed `env` setting from `Container` (timriley)
- Removed `Dry::Component::Config` and `options` setting from `Container` (timriley)
- Changed `Component#configure` behavior so it can be run multiple times for configuration to be applied in multiple passes (timriley)

[Compare v0.2.0...v0.3.0](https://github.com/dry-rb/dry-system/compare/v0.2.0...v0.3.0)

## [0.2.0] - 2016-06-13


### Fixed

- Fixed bug where specified auto-inject strategies were not respected (timriley)

### Changed

- Component core directory is now `component/` by default (timriley)
- Injector default stragegy is now whatever dry-auto_inject's default is (rather than hard-coding a particular default strategy for dry-system) (timriley)

[Compare v0.1.0...v0.2.0](https://github.com/dry-rb/dry-system/compare/v0.1.0...v0.2.0)

## [0.1.0] - 2016-06-07


### Added

- 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)
- Support aliased dependency names when calling the injector object (e.g. `MyComponent::Inject[foo: "my_app.foo", bar: "another.thing"]`) (timriley)
- Allow a custom dependency loader to be set on a container via its config (AMHOL)

  ```ruby
  class MyContainer < Dry::Component::Container
    configure do |config|
      # other config
      config.loader = MyLoader
    end
  end
  ```

### Changed

- `Container.boot` now only makes a simple `require` for the boot file (solnic)
- Container object is passed to `Container.finalize` blocks (solnic)
- Allow `Pathname` objects passed to `Container.require` (solnic)
- Support lazily loading missing dependencies from imported containers (solnic)
- `Container.import_module` renamed to `.injector` (timriley)
- Default injection strategy is now `kwargs`, courtesy of the new dry-auto_inject default (timriley)

[Compare v0.0.2...v0.1.0](https://github.com/dry-rb/dry-system/compare/v0.0.2...v0.1.0)

## [0.0.2] - 2015-12-24


### Added

- Containers have a `name` setting (solnic)
- Containers can be imported into one another (solnic)

### Changed

- Container name is used to determine the name of its config file (solnic)

[Compare v0.0.1...v0.0.2](https://github.com/dry-rb/dry-system/compare/v0.0.1...v0.0.2)

## [0.0.1] - 2015-12-24

First public release, extracted from rodakase project


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We pledge to make our community welcoming, safe, and equitable for all.

We 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.

## Encouraged Behaviors

While 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.

With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including:

1. Respecting the **purpose of our community**, our activities, and our ways of gathering.
2. Engaging **kindly and honestly** with others.
3. Respecting **different viewpoints** and experiences.
4. **Taking responsibility** for our actions and contributions.
5. Gracefully giving and accepting **constructive feedback**.
6. Committing to **repairing harm** when it occurs.
7. Behaving in other ways that promote and sustain the **well-being of our community**.

## Restricted Behaviors

We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct.

1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop.
2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people.
3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits.
4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community.
5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission.
6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.
7. Behaving in other ways that **threaten the well-being** of our community.

### Other Restrictions

1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions.
2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.
3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community.
4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors.

## Reporting an Issue

Tensions 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.

When an incident does occur, it is important to report it promptly. To report a possible violation, email conduct@hanakai.org.

Community 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.

## Addressing and Repairing Harm

If 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.

1) Warning
   1) Event: A violation involving a single incident or series of incidents.
   2) Consequence: A private, written warning from the Community Moderators.
   3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations.
2) Temporarily Limited Activities
   1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation.
   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.
   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.
3) Temporary Suspension
   1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation.
   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.
   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.
4) Permanent Ban
   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.
   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.
   3) Repair: There is no possible repair in cases of this severity.

This 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.

## Scope

This 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.

## Attribution

This 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/).

Contributor 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/)

For 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).


================================================
FILE: CONTRIBUTING.md
================================================
# Issue guidelines

## Reporting bugs

If 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.

## Reporting feature requests

Report 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.

## Reporting questions, support requests, ideas, concerns etc.

**Please don’t.** Use [our forum](https://discourse.hanamirb.org) instead.

# Pull request guidelines

A pull request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.

Other requirements:

1. 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.
2. Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
3. Add API documentation if it's a new feature.
4. Update API documentation if it changes an existing feature.
5. Bonus points for sending a PR which updates user documentation in our [site repository](https://github.com/hanakai-rb/site).

# Asking for help

If 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).


================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

source "https://rubygems.org"

eval_gemfile "Gemfile.devtools"

gemspec

# Remove verson constraint once latter versions release their -java packages
gem "bootsnap"
gem "dotenv"
gem "dry-events"
gem "dry-monitor"
gem "dry-types"

gem "zeitwerk"

group :test do
  gem "ostruct"
end


================================================
FILE: Gemfile.devtools
================================================
# frozen_string_literal: true

# This file is synced from hanakai-rb/repo-sync

gem "rake", ">= 12.3.3"

group :test do
  gem "simplecov", require: false, platforms: :ruby
  gem "simplecov-cobertura", require: false, platforms: :ruby
  gem "rexml", require: false

  gem "warning"
end

group :tools do
  gem "rubocop"
end


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015-2026 Hanakai team

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
<!--- This file is synced from hanakai-rb/repo-sync -->

[actions]: https://github.com/dry-rb/dry-system/actions
[chat]: https://discord.gg/naQApPAsZB
[forum]: https://discourse.hanamirb.org
[rubygem]: https://rubygems.org/gems/dry-system

# 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]

[![Forum](https://img.shields.io/badge/Forum-dc360f?logo=discourse&logoColor=white)][forum]
[![Chat](https://img.shields.io/badge/Chat-717cf8?logo=discord&logoColor=white)][chat]

## Links

- [User documentation](https://dry-rb.org/gems/dry-system)
- [API documentation](http://rubydoc.info/gems/dry-system)
- [Forum](https://discourse.dry-rb.org)

## License

See `LICENSE` file.



================================================
FILE: Rakefile
================================================
#!/usr/bin/env rake
# frozen_string_literal: true

require "bundler/gem_tasks"

$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib"))

require "rspec/core"
require "rspec/core/rake_task"

task default: :spec

desc "Run all specs in spec directory"
RSpec::Core::RakeTask.new(:spec)


================================================
FILE: bin/.gitkeep
================================================


================================================
FILE: bin/console
================================================
#!/usr/bin/env ruby
# frozen_string_literal: true

require "bundler/setup"

begin
  require "pry-byebug"
  Pry.start
rescue LoadError
  require "irb"
  IRB.start
end


================================================
FILE: docsite/source/component-dirs.html.md
================================================
---
title: Component dirs
layout: gem-single
name: dry-system
---

The container auto-registers its components from one or more component dirs, the directories holding the Ruby source files for your classes.

You can configure one or more component dirs:

```ruby
class Application < Dry::System::Container
  configure do |config|
    config.root = __dir__

    config.component_dirs.add "lib"
    config.component_dirs.add "app"
  end
end
```

Component 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.

### Component dir configuration

You can configure many aspects of component auto-registration via component dirs.

#### auto_register

`auto_register` sets the auto-registration policy for the component dir.

This 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.

`auto_register` defaults to `true`.

```ruby
config.component_dirs.add "lib" do |dir|
  dir.auto_register = false
end
```

```ruby
config.component_dirs.add "lib" do |dir|
  dir.auto_register = proc do |component|
    !component.identifier.start_with?("entities")
  end
end
```

#### memoize

`memoize` sets whether to memoize components from the dir when registered in the container (ordinarily, components are initialized every time they are resolved).

This 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.

`memoize` defaults to `false`.

```ruby
config.component_dirs.add "lib" do |dir|
  dir.memoize = true
end
```
```ruby
config.component_dirs.add "lib" do |dir|
  dir.memoize = proc do |component|
    component.identifier.start_with?("providers")
  end
end
```

#### namespaces

`namespaces` allows one or more namespaces to be added for paths within the component dir. For the given path, the namespace determines:

1. The leading segments of its components' registered identifiers, and
2. The expected constant namespace of their class constants.

When adding a namespace, you can specify:

- A `key:` namespace, which determines the leading part of the key used to register each component in the container. It can be:
  - Omitted, in which case it defaults to the value of `path`
  - A string, which will become the leading part of the registered keys
  - `nil`, which will make the registered keys top-level, with no additional leading parts
- A `const:` namespace, which is the Ruby namespace expected to contain the class constants defined within each component's source file.

  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:
  - Omitted, in which case it defaults to the value of `path`
  - A string, which will be constantized to the expected constant namespace per the rules above
  - `nil`, to indicate the class constants will be in the top-level constant namespace

Only a single namespace can be added for any distinct path.

To illustrate these options:

**Top-level key namespace**

```ruby
config.component_dirs.add "lib" do |dir|
  dir.namespaces.add "admin", key: nil
end
```

- `admin/foo.rb` is expected to define `Admin::Foo`, will be registered as `"foo"`
- `admin/bar/baz.rb` is expected to define `Admin::Bar::Baz`, will be registered as `"bar.baz"`

**Top-level const namespace**

```ruby
config.component_dirs.add "lib" do |dir|
  dir.namespaces.add "admin/top", const: nil
end
```

- `admin/top/foo.rb` is expected to define `Foo`, will be registered as `"admin.top.foo"`
- `admin/top/bar/baz.rb` is expected to define `Bar::Baz`, will be registered as `"admin.top.bar.baz"`

**Distinct const namespace**

```ruby
config.component_dirs.add "lib" do |dir|
  dir.namespaces.add "admin", key: nil, const: "super/admin"
end
```

- `admin/foo.rb` is expected to define `Super::Admin::Foo`, will be registered as `"foo"`
- `admin/bar/baz.rb` is expected to define `Super::Admin::Bar::Baz`, will be registered as `"bar.baz"`

**Omitted key namespace, with keys keeping their natural prefix**

```ruby
config.component_dirs.add "lib" do |dir|
  dir.namespaces.add "admin", const: "super/admin"
end
```

- `admin/foo.rb` is expected to define `Super::Admin::Foo`, will be registered as `"admin.foo"`
- `admin/bar/baz.rb` is expected to define `Super::Admin::Bar::Baz`, will be registered as `"admin.bar.baz"`

##### Each component dir may have multiple namespaces

The examples above show a component dir with a single configured namespace, but component dir may have any number of namespaces:

```ruby
config.component_dirs.add "lib" do |dir|
  dir.namespaces.add "admin/system_adapters", key: nil, const: nil
  dir.namespaces.add "admin", key: nil
  dir.namespaces.add "elsewhere", key: "stuff.and.things"
end
```

When the container loads its components, namespaces are searched and evaluated in order of definition. So for the example above:

- Files within `lib/admin/system_adapters/` will have the `key: nil, const: nil` namespace rules applied
- All other files in `lib/admin/` will have the `key: nil` namespace rules applied
- Files in `lib/elsewhere/` will have the `key: "stuff.and.things"` namespace rules applied

##### A root namespace is implicitly appended to a component dir's configured namespaces

To 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.

A 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.

The default root namespace is effectively the following:

```ruby
namespaces.add nil, key: nil, const: nil
```

It 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).

These 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.

##### The root namespace may be explicitly configured

There 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`.

In this example, files in `lib/` are all expected to provide class constants in the `Admin` namespace:

```ruby
config.component_dirs.add "lib" do |dir|
  dir.namespaces.root const: "admin"
end
```

Root namespaces can be configured alongside other namespaces. The same namespace ordering preferences apply to root namespaces as to all others.

#### add_to_load_path

`add_to_load_path` sets whether the component dir should be added to the `$LOAD_PATH` after the container is configured.

Set this to false if you’re using dry-container with an autoloader.

`add_to_load_path` defaults to `true`.

#### loader

`loader` sets the loader to use when registering components from the dir in the container.

`loader` defaults to `Dry::System::Loader`.

When using a class autoloader, consider setting this to `Dry::System::Loader::Autoloading`:

```ruby
require "dry/system"

class Application < Dry::System::Container
  configure do |config|
    config.root = __dir__

    config.component_dirs.add "lib" do |dir|
      dir.loader = Dry::System::Loader::Autoloading
    end
  end
end
```

To provide a custom loader, you must implement the same interface as `Dry::System::Loader`.

### Component dir defaults configuration

If 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.

Configuration 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.

```ruby
class MyApp::Container < Dry::System::Container
  configure do |config|
    config.root = __dir__

    # Configure defaults for all component dirs
    config.component_dirs.auto_register = proc do |component|
      !component.identifier.start_with?("entities")
    end
    config.component_dirs.namespaces.add "admin", key: nil

    config.component_dirs.add "lib"
    config.component_dirs.add "app"
  end
end
```

### Inline component configuration with magic comments

You 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.

The following settings can be configured by magic comments:

- `auto_register`
- `memoize`

In the magic comments, you can set `true` or `false` values only.

For example, to disable auto-registration of a particular component:

```ruby
# auto_register: false
# frozen_string_literal: true

class MyClass
end
```

Or to enable memoization of a particular component:

```ruby
# memoize: true
# frozen_string_literal: true

class MyClass
end
```


================================================
FILE: docsite/source/container/hooks.html.md
================================================
---
title: Hooks
layout: gem-single
name: dry-system
---

There are a few lifecycle events that you can hook into if you need to ensure things happen in a particular order.

Hooks are executed within the context of the container instance.

### `configure` Event

You can register a callback to fire after the container is configured, which happens one of three ways:

1. The `configure` method is called on the container
2. The `configured!` method is called
3. The `finalize!` method is called when neither of the other two have been

```ruby
class MyApp::Container < Dry::System::Container
  after(:configure) do
    # do something here
  end
end
```

### `register` Event

Most of the time, you will know what keys you are working with ahead of time. But for certain cases you may want to
react to keys dynamically.

```ruby
class MyApp::Container < Dry::System::Container
  use :monitoring

  after(:register) do |key|
    next unless key.end_with?(".gateway")

    monitor(key) do |event|
      resolve(:logger).debug(key:, method: event[:method], time: event[:time])
    end
  end
end
```

Now let's say you register `api_client.gateway` into your container. Your API methods will be automatically monitored
and their timing measured and logged.

### `finalize` Event

Finalization is the point at which the container is made ready, such as booting a web application.

The following keys are loaded in sequence:

1. Providers
2. Auto-registered components
3. Manually-registered components
4. Container imports

At the conclusion of this process, the container is frozen thus preventing any further changes. This makes the
`finalize` event quite important: it's the last call before your container will disallow mutation.

Unlike the previous events, you can register before hooks in addition to after hooks.

The after hooks will run immediately prior to the container freeze. This allows you to enumerate the container keys
while they can still be mutated, such as with `decorate` or `monitor`.

```ruby
class MyApp::Container < Dry::System::Container
  before(:finalize) do
    # Before system boot, no keys registered yet
  end

  after(:finalize) do
    # After system boot, all keys registered
  end
end
```


================================================
FILE: docsite/source/container.html.md
================================================
---
title: Container
layout: gem-single
name: dry-system
sections:
  - hooks
---

The 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.

Let's say you want to define an application container that will provide a logger:

``` ruby
require 'dry/system'

class Application < Dry::System::Container
  configure do |config|
    config.root = Pathname('./my/app')
  end
end

# now you can register a logger
require 'logger'
Application.register('utils.logger', Logger.new($stdout))

# and access it
Application['utils.logger']
```

### Auto-Registration

By using simple naming conventions we can automatically register objects within our container.

Let's provide a custom logger object and put it under a custom load-path that we will configure:

``` ruby
require "dry/system"

class Application < Dry::System::Container
  configure do |config|
    config.root = Pathname("./my/app")

    # Add a 'lib' component dir (relative to `root`), containing class definitions
    # that can be auto-registered
    config.component_dirs.add "lib"
  end
end

# under /my/app/lib/logger.rb we put
class Logger
  # some neat logger implementation
end

# we can finalize the container which triggers auto-registration
Application.finalize!

# the logger becomes available
Application["logger"]
```


================================================
FILE: docsite/source/dependency-auto-injection.html.md
================================================
---
title: Dependency auto-injection
layout: gem-single
name: dry-system
---

After defining your container, you can use its auto-injector as a mixin to declare a component's dependencies using their container keys.

For example, if you have an `Application` container and an object that will need a logger:

``` ruby
# system/import.rb
require "system/container"
Import = Application.injector

# In a class definition you simply specify what it needs
# lib/post_publisher.rb
require "import"
class PostPublisher
  include Import["logger"]

  def call(post)
    # some stuff
    logger.debug("post published: #{post}")
  end
end
```

### Auto-registered component keys

When 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`.

Resolving 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.

For 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:

- `system/providers/persistence.rb` - where you register your `:persistence` provider
- `lib/persistence/user_repo` - where you can define any components that need the components or setup established by the `persistence` provider

Here's a sample setup for this scenario:

``` ruby
# system/container.rb
require "dry/system"

class Application < Dry::System::Container
  configure do |config|
    config.root = Pathname("/my/app")
    config.component_dirs.add "lib"
  end
end

# system/import.rb
require_relative "container"

Import = Application.injector

# system/providers/persistence.rb
Application.register_provider(:persistence) do
  start do
    require "sequel"
    container.register("persistence.db", Sequel.connect(ENV['DB_URL']))
  end

  stop do
    container["persistence.db"].disconnect
  end
end

# lib/persistence/user_repo.rb
require "import"

module Persistence
  class UserRepo
    include Import["persistence.db"]

    def find(conditions)
      db[:users].where(conditions)
    end
  end
end
```


================================================
FILE: docsite/source/external-provider-sources.html.md
================================================
---
title: External provider sources
layout: gem-single
name: dry-system
---

You 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.

Provider 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.

To distribute a group of provider sources (defined in their own files), register them with `Dry::System`:

``` ruby
# my_gem
#  |- lib/my_gem/provider_sources.rb

Dry::System.register_provider_sources(:common, boot_path: File.join(__dir__, "provider_sources"))
```

Then, define your provider source:

``` ruby
# my_gem
#  |- lib/my_gem/provider_sources/exception_notifier.rb

Dry::System.register_provider_source(:exception_notifier, group: :my_gem) do
  prepare do
    require "some_exception_notifier"
  end

  start do
    register(:exception_notifier, SomeExceptionNotifier.new)
  end
end
```

Then you can use this provider source when you register a provider in a dry-system container:

``` ruby
# system/app/container.rb

require "dry/system"
require "my_gem/provider_sources"

module App
  class Container < Dry::System::Container
    register_provider(:exception_notifier, from: :my_gem)
  end
end

App::Container[:exception_notifier]
```

### Customizing provider sources

You can customize a provider source for your application via `before` and `after` callbacks for its lifecycle steps.

For example, you can register additional components based on the provider source's own registrations via an `after(:start)` callback:

``` ruby
module App
  class Container < Dry::System::Container
    register_provider(:exception_notifier, from: :my_gem) do
      after(:start)
        register(:my_notifier, container[:exception_notifier])
      end
    end
  end
end
```

The following callbacks are supported:

- `before(:prepare)`
- `after(:prepare)`
- `before(:start)`
- `after(:start)`

### Providing component configuration

Provider 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`.

For example, here’s an extended `:exception_notifier` provider source with settings:

``` ruby
# my_gem
#  |- lib/my_gem/provider_sources/exception_notifier.rb

Dry::System.register_component(:exception_notifier, provider: :common) do
  setting :environments, default: :production, constructor: Types::Strict::Array.of(Types::Strict::Symbol)
  setting :logger

  prepare do
    require "some_exception_notifier"
  end

  start do
    # Now we have access to `config`
    register(:exception_notifier, SomeExceptionNotifier.new(config.to_h))
  end
end
```

This defines two settings:

- `:environments`, which is a list of environment identifiers with default value set to `[:production]`
- `:logger`, an object that should be used as the logger, which must be configured

To configure this provider source, you can use a `configure` block when defining your provider using the source:

``` ruby
module App
  class Container < Dry::System::Container
    register_provider(:exception_notifier, from: :my_gem) do
      require "logger"

      configure do |config|
        config.logger = Logger.new($stdout)
      end
    end
  end
end
```


================================================
FILE: docsite/source/index.html.md
================================================
---
title: Introduction
layout: gem-single
name: dry-system
type: gem
sections:
  - container
  - component-dirs
  - providers
  - dependency-auto-injection
  - plugins
  - external-provider-sources
  - settings
  - test-mode
---

Object 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.

This 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.

It does a couple of things for you:

* Provides an abstract dependency container implementation
* Integrates with an autoloader, or handles `$LOAD_PATH` for you and loads needed files using `require`
* Resolves object dependencies automatically
* Supports auto-registration of dependencies via file/dir naming conventions
* Supports multi-system setups (ie your application is split into multiple sub-systems)
* Supports configuring component providers, which can be used to share common components between many systems
* Supports test-mode with convenient stubbing API

To 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.

This comes with a bunch of nice benefits:

* Your system relies on abstractions rather than concrete classes and modules
* It helps in decoupling your code from 3rd party code
* 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.
* It opens up doors to better instrumentation and debugging tools

You 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).

### Rails support

If 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.

### Credits

* 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).
* System/Component and lifecycle triggers are inspired by Clojure's [component](https://github.com/stuartsierra/component) library by [Stuart Sierra](https://github.com/stuartsierra)



================================================
FILE: docsite/source/plugins.html.md
================================================
---
title: Plugins
layout: gem-single
name: dry-system
---

dry-system has already built-in plugins that you can enable, and it’s very easy to write your own.

## Zeitwerk

With the `:zeitwerk` plugin you can easily use [Zeitwerk](https://github.com/fxn/zeitwerk) as your applications's code loader:

> 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)

### Example

Here is an example of using Zeitwerk plugin:

```ruby
class App < Dry::System::Container
  use :env, inferrer: -> { ENV.fetch("RACK_ENV", :development).to_sym }
  use :zeitwerk

  configure do |config|
    config.component_dirs.add "lib"
  end
end
```

For a more in depth and runnable example, [see here](https://github.com/dry-rb/dry-system/tree/master/examples/zeitwerk).

### Inflections

The 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:

```ruby
class App < Dry::System::Container
  use :zeitwerk

  configure do |config|
    config.inflector = Dry::Inflector.new do |inflections|
      inflections.acronym('REST')
    end

    # ...
  end
end
```

### Eager Loading

By 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:

```ruby
class App < Dry::System::Container
  use :zeitwerk, eager_load: true
end
```

### Debugging

When 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.

```ruby
class App < Dry::System::Container
  use :zeitwerk, debug: true
end
```

### Advanced Configuration

If you need to adjust the Zeitwerk configuration, you can do so by accessing the `Zeitwerk::Loader` instance directly on the container, as `.autoloader`:

```ruby
# After you have configured the container but before you have finalized it

MyContainer.autoloader.ignore("./some_path.rb)
```

## Application environment

You can use the `:env` plugin to set and configure an `env` setting for your application.

```ruby
class App < Dry::System::Container
  use :env

  configure do |config|
    config.env = :staging
  end
end
```

You can provide environment inferrer, which is probably something you want to do, here’s how dry-web sets up its environment:

```ruby
module Dry
  module Web
    class Container < Dry::System::Container
      use :env, inferrer: -> { ENV.fetch("RACK_ENV", :development).to_sym }
    end
  end
end
```

## Logging

You 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.

```ruby
class App < Dry::System::Container
  use :logging
end

# default logger is registered as a standard object, so you can inject it via auto-injection
App[:logger]

# short-cut method is provided too, which is convenient in some cases
App.logger
```

## Monitoring

Another 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:

```ruby
class App < Dry::System::Container
  use :logging
  use :monitoring
end

App.monitor("users.operations.create") do |event|
  App.logger.debug "user created: #{event.payload} in #{event[:time]}ms"
end
```

You can also provide specific methods that should be monitored, let’s say we’re only interested in `#call` method:

```ruby
App.monitor("users.operations.create", methods: %i[call]) do |event|
  App.logger.debug "user created: #{event.payload} in #{event[:time]}ms"
end
```

## Experimental bootsnap support

dry-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:

```ruby
class App < Dry::System::Container
  use :bootsnap # that's it
end
```

We’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.


================================================
FILE: docsite/source/providers.html.md
================================================
---
title: Providers
layout: gem-single
name: dry-system
---

Some 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.

You can define your providers as individual source files in `system/providers/`, for example:

``` ruby
# system/providers/persistence.rb

Application.register_provider(:database) do
  prepare do
    require "third_party/db"
  end

  start do
    register(:database, ThirdParty::DB.new)
  end
end
```

The provider’s lifecycle steps will not run until the provider is required by another component, is started directly, or when the container finalizes.

This means you can require your container and ask it to start just that one provider:

``` ruby
# system/application/container.rb
class Application < Dry::System::Container
  configure do |config|
    config.root = Pathname("/my/app")
  end
end

Application.start(:database)

# and now `database` becomes available
Application["database"]
```

### Provider lifecycle

The provider lifecycle consists of three steps, each with a distinct purpose:

* `prepare` - basic setup code, here you can require third party code and perform basic configuration
* `start` - code that needs to run for a component to be usable at application's runtime
* `stop` - code that needs to run to stop a component, ie close a database connection, clear some artifacts etc.

Here's a simple example:

``` ruby
# system/providers/db.rb

Application.register_provider(:database) do
  prepare do
    require 'third_party/db'

    register(:database, ThirdParty::DB.configure(ENV['DB_URL']))
  end

  start do
    container[:database].establish_connection
  end

  stop do
    container[:database].close_connection
  end
end
```

### Using other providers

You 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):

``` ruby
# system/providers/logger.rb
Application.register_provider(:logger) do
  prepare do
    require "logger"
  end

  start do
    register(:logger, Logger.new($stdout))
  end
end

# system/providers/db.rb
Application.register_provider(:db) do
  start do
    target.start :logger

    register(DB.new(ENV['DB_URL'], logger: target[:logger]))
  end
end
```


================================================
FILE: docsite/source/settings.html.md
================================================
---
title: Settings
layout: gem-single
name: dry-system
---

## Basic usage

dry-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):

```ruby
# system/providers/settings.rb:

require "dry/system"

Application.register_provider(:settings, from: :dry_system) do
  before :prepare do
    # Change this to load your own `Types` module if you want type-checked settings
    require "your/types/module"
  end

  settings do
    setting :database_url, constructor: Types::String.constrained(filled: true)

    setting :logger_level, default: :info, constructor: Types::Symbol
      .constructor { |value| value.to_s.downcase.to_sym }
      .enum(:trace, :unknown, :error, :fatal, :warn, :info, :debug)
  end
end
```

Your 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:

```ruby
Application[:settings].database_url # => "postgres://..."
Application[:settings].logger_level # => :info
```

You can use this settings object in other providers:

```ruby
Application.register_provider(:redis) do
  start do
    use :settings

    uri = URI.parse(target[:settings].redis_url)
    redis = Redis.new(host: uri.host, port: uri.port, password: uri.password)

    register('persistance.redis', redis)
  end
end
```

Or as an injected dependency in your classes:

```ruby
  module Operations
    class CreateUser
      include Import[:settings]

      def call(params)
        settings # => your settings struct
      end
    end
  end
end
```


================================================
FILE: docsite/source/test-mode.html.md
================================================
---
title: Test Mode
layout: gem-single
name: dry-system
---

In some cases it is useful to stub a component in your tests. To enable this, dry-system provides a test mode,
in which a container will not be frozen during finalization. This allows you to use `stub` API to stub a given component.

``` ruby
require 'dry/system'

class Application < Dry::System::Container
  configure do |config|
    config.root = Pathname('./my/app')
  end
end

require 'dry/system/stubs'

Application.enable_stubs!

Application.stub('persistence.db', stubbed_db)
```

Typically, you want to use `enable_stubs!` in a test helper file, before booting your system.


================================================
FILE: dry-system.gemspec
================================================
# frozen_string_literal: true

# This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.

lib = File.expand_path("lib", __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "dry/system/version"

Gem::Specification.new do |spec|
  spec.name          = "dry-system"
  spec.authors       = ["Hanakai team"]
  spec.email         = ["info@hanakai.org"]
  spec.license       = "MIT"
  spec.version       = Dry::System::VERSION.dup

  spec.summary       = "Organize your code into reusable components"
  spec.description   = spec.summary
  spec.homepage      = "https://dry-rb.org/gems/dry-system"
  spec.files         = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-system.gemspec", "lib/**/*"]
  spec.bindir        = "exe"
  spec.executables   = Dir["exe/*"].map { |f| File.basename(f) }
  spec.require_paths = ["lib"]

  spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE"]

  spec.metadata["changelog_uri"]     = "https://github.com/dry-rb/dry-system/blob/main/CHANGELOG.md"
  spec.metadata["source_code_uri"]   = "https://github.com/dry-rb/dry-system"
  spec.metadata["bug_tracker_uri"]   = "https://github.com/dry-rb/dry-system/issues"
  spec.metadata["funding_uri"]       = "https://github.com/sponsors/hanami"

  spec.required_ruby_version = ">= 3.1.0"

  spec.add_runtime_dependency "dry-auto_inject", "~> 1.1"
  spec.add_runtime_dependency "dry-configurable", "~> 1.3"
  spec.add_runtime_dependency "dry-core", "~> 1.1"
  spec.add_runtime_dependency "dry-inflector", "~> 1.1"
  spec.add_development_dependency "bundler"
  spec.add_development_dependency "rake"
  spec.add_development_dependency "rspec"
end



================================================
FILE: examples/custom_configuration_auto_register/Gemfile
================================================
# frozen_string_literal: true

source "https://rubygems.org"

gem "dry-system", path: "../.."
gem "sequel"
gem "sqlite3"


================================================
FILE: examples/custom_configuration_auto_register/lib/entities/user.rb
================================================
# frozen_string_literal: true

module Entities
  class User
    include Import["persistence.db"]
  end
end


================================================
FILE: examples/custom_configuration_auto_register/lib/user_repo.rb
================================================
# frozen_string_literal: true

class UserRepo
  include Import["persistence.db"]
end


================================================
FILE: examples/custom_configuration_auto_register/run.rb
================================================
# frozen_string_literal: true

require "bundler/setup"
require_relative "system/container"
require_relative "system/import"

App.finalize!

user_repo1 = App["user_repo"]
user_repo2 = App["user_repo"]
puts "User has not been loaded" unless App.key?("entities.user")
puts user_repo1.db.inspect
puts user_repo2.db.inspect
puts "user_repo1 and user_repo2 reference the same instance" if user_repo1.equal?(user_repo2)


================================================
FILE: examples/custom_configuration_auto_register/system/boot/persistence.rb
================================================
# frozen_string_literal: true

App.boot(:persistence) do |persistence|
  init do
    require "sequel"
  end

  start do
    persistence.register("persistence.db", Sequel.connect("sqlite::memory"))
  end

  stop do
    db.close_connection
  end
end


================================================
FILE: examples/custom_configuration_auto_register/system/container.rb
================================================
# frozen_string_literal: true

require "dry/system"

class App < Dry::System::Container
  configure do |config|
    config.component_dirs.add "lib" do |dir|
      dir.memoize = true

      dir.auto_register = lambda do |component|
        !component.identifier.start_with?("entities")
      end
    end
  end
end


================================================
FILE: examples/custom_configuration_auto_register/system/import.rb
================================================
# frozen_string_literal: true

require_relative "container"

Import = App.injector


================================================
FILE: examples/standalone/Gemfile
================================================
# frozen_string_literal: true

source "https://rubygems.org"

gem "dry-events"
gem "dry-monitor"
gem "dry-system", path: "../.."
gem "sequel"
gem "sqlite3"


================================================
FILE: examples/standalone/lib/empty_service.rb
================================================
# frozen_string_literal: true

class EmptyService
end


================================================
FILE: examples/standalone/lib/not_registered.rb
================================================
# frozen_string_literal: true

class NotRegistered
end


================================================
FILE: examples/standalone/lib/service_with_dependency.rb
================================================
# frozen_string_literal: true

class ServiceWithDependency
  include Import["user_repo"]
end


================================================
FILE: examples/standalone/lib/user_repo.rb
================================================
# frozen_string_literal: true

class UserRepo
  include Import["persistence.db"]
end


================================================
FILE: examples/standalone/run.rb
================================================
# frozen_string_literal: true

require "bundler/setup"
require_relative "system/container"
require_relative "system/import"
require "dry/events"
require "dry/monitor/notifications"

App[:notifications].subscribe(:resolved_dependency) do |event|
  puts "Event #{event.id}, payload: #{event.to_h}"
end

App[:notifications].subscribe(:registered_dependency) do |event|
  puts "Event #{event.id}, payload: #{event.to_h}"
end

App.finalize!
p App.keys

App["service_with_dependency"]
user_repo = App["user_repo"]

puts user_repo.db.inspect


================================================
FILE: examples/standalone/system/container.rb
================================================
# frozen_string_literal: true

require "dry/events"
require "dry/monitor/notifications"
require "dry/system"

class App < Dry::System::Container
  use :dependency_graph

  configure do |config|
    config.component_dirs.add "lib" do |dir|
      dir.add_to_load_path = true # defaults to true
      dir.auto_register = lambda do |component|
        !component.identifier.start_with?("not_registered")
      end
    end
  end
end


================================================
FILE: examples/standalone/system/import.rb
================================================
# frozen_string_literal: true

require_relative "container"

Import = App.injector


================================================
FILE: examples/standalone/system/providers/persistence.rb
================================================
# frozen_string_literal: true

App.boot(:persistence) do |persistence|
  init do
    require "sequel"
  end

  start do
    persistence.register("persistence.db", Sequel.connect("sqlite::memory"))
  end

  stop do
    db.close_connection
  end
end


================================================
FILE: examples/zeitwerk/Gemfile
================================================
# frozen_string_literal: true

source "https://rubygems.org"

gem "dry-events"
gem "dry-monitor"
gem "dry-system", path: "../.."
gem "zeitwerk"


================================================
FILE: examples/zeitwerk/lib/service_with_dependency.rb
================================================
# frozen_string_literal: true

class ServiceWithDependency
  include Import["user_repo"]
end


================================================
FILE: examples/zeitwerk/lib/user_repo.rb
================================================
# frozen_string_literal: true

class UserRepo
end


================================================
FILE: examples/zeitwerk/run.rb
================================================
# frozen_string_literal: true

require "bundler/setup"
require_relative "system/container"
require_relative "system/import"

App.finalize!

service = App["service_with_dependency"]

puts "Container keys: #{App.keys}"
puts "User repo:      #{service.user_repo.inspect}"
puts "Loader:         #{App.autoloader}"


================================================
FILE: examples/zeitwerk/system/container.rb
================================================
# frozen_string_literal: true

require "dry/system"

class App < Dry::System::Container
  use :env, inferrer: -> { ENV.fetch("RACK_ENV", :development).to_sym }
  use :zeitwerk, debug: true

  configure do |config|
    config.component_dirs.add "lib"
  end
end


================================================
FILE: examples/zeitwerk/system/import.rb
================================================
# frozen_string_literal: true

require_relative "container"

Import = App.injector


================================================
FILE: lib/dry/system/auto_registrar.rb
================================================
# frozen_string_literal: true

require "dry/system/constants"

module Dry
  module System
    # Default auto-registration implementation
    #
    # This is currently configured by default for every System::Container.
    # Auto-registrar objects are responsible for loading files from configured
    # auto-register paths and registering components automatically within the
    # container.
    #
    # @api private
    class AutoRegistrar
      attr_reader :container

      def initialize(container)
        @container = container
      end

      # @api private
      def finalize!
        container.component_dirs.each do |component_dir|
          call(component_dir) if component_dir.auto_register?
        end
      end

      # @api private
      def call(component_dir)
        component_dir.each_component do |component|
          next unless register_component?(component)

          container.register(component.key, memoize: component.memoize?) { component.instance }
        end
      end

      private

      def register_component?(component)
        !container.registered?(component.key) && component.auto_register?
      end
    end
  end
end


================================================
FILE: lib/dry/system/component.rb
================================================
# frozen_string_literal: true

require "pathname"
require "dry/inflector"
require "dry/system/errors"
require "dry/system/constants"

module Dry
  module System
    # Components are objects providing information about auto-registered files.
    # They expose an API to query this information and use a configurable
    # loader object to initialize class instances.
    #
    # @api public
    class Component
      include Dry::Equalizer(:identifier, :file_path, :namespace, :options)

      DEFAULT_OPTIONS = {
        inflector: Dry::Inflector.new,
        loader: Loader
      }.freeze

      # @!attribute [r] identifier
      #   @return [String] the component's unique identifier
      attr_reader :identifier

      # @!attribute [r] file_path
      #   @return [Pathname] the component's source file path
      attr_reader :file_path

      # @!attribute [r] namespace
      #   @return [Dry::System::Config::Namespace] the component's namespace
      attr_reader :namespace

      # @!attribute [r] options
      #   @return [Hash] the component's options
      attr_reader :options

      # @api private
      def initialize(identifier, file_path:, namespace:, **options)
        @identifier = identifier
        @file_path = Pathname(file_path)
        @namespace = namespace
        @options = DEFAULT_OPTIONS.merge(options)
      end

      # Returns true, indicating that the component is directly loadable from the files
      # managed by the container
      #
      # This is the inverse of {IndirectComponent#loadable?}
      #
      # @return [TrueClass]
      #
      # @api private
      def loadable?
        true
      end

      # Returns the component's instance
      #
      # @return [Object] component's class instance
      # @api public
      def instance(*args, **kwargs)
        options[:instance]&.call(self, *args, **kwargs) || loader.call(self, *args, **kwargs)
      end

      # Returns the component's unique key
      #
      # @return [String] the key
      #
      # @see Identifier#key
      #
      # @api public
      def key
        identifier.key
      end

      # Returns the root namespace segment of the component's key, as a symbol
      #
      # @see Identifier#root_key
      #
      # @return [Symbol] the root key
      #
      # @api public
      def root_key
        identifier.root_key
      end

      # Returns a path-delimited representation of the compnent, appropriate for passing
      # to `Kernel#require` to require its source file
      #
      # The path takes into account the rules of the namespace used to load the component.
      #
      # @example Component from a root namespace
      #   component.key # => "articles.create"
      #   component.require_path # => "articles/create"
      #
      # @example Component from an "admin/" path namespace (with `key: nil`)
      #   component.key # => "articles.create"
      #   component.require_path # => "admin/articles/create"
      #
      # @see Config::Namespaces#add
      # @see Config::Namespace
      #
      # @return [String] the require path
      #
      # @api public
      def require_path
        if namespace.path
          "#{namespace.path}#{PATH_SEPARATOR}#{path_in_namespace}"
        else
          path_in_namespace
        end
      end

      # Returns an "underscored", path-delimited representation of the component,
      # appropriate for passing to the inflector for constantizing
      #
      # The const path takes into account the rules of the namespace used to load the
      # component.
      #
      # @example Component from a namespace with `const: nil`
      #   component.key # => "articles.create_article"
      #   component.const_path # => "articles/create_article"
      #   component.inflector.constantize(component.const_path) # => Articles::CreateArticle
      #
      # @example Component from a namespace with `const: "admin"`
      #   component.key # => "articles.create_article"
      #   component.const_path # => "admin/articles/create_article"
      #   component.inflector.constantize(component.const_path) # => Admin::Articles::CreateArticle
      #
      # @see Config::Namespaces#add
      # @see Config::Namespace
      #
      # @return [String] the const path
      #
      # @api public
      def const_path
        namespace_const_path = namespace.const&.gsub(KEY_SEPARATOR, PATH_SEPARATOR)

        if namespace_const_path
          "#{namespace_const_path}#{PATH_SEPARATOR}#{path_in_namespace}"
        else
          path_in_namespace
        end
      end

      # @api private
      def loader
        options.fetch(:loader)
      end

      # @api private
      def inflector
        options.fetch(:inflector)
      end

      # @api private
      def auto_register?
        callable_option?(options[:auto_register])
      end

      # @api private
      def memoize?
        callable_option?(options[:memoize])
      end

      private

      def path_in_namespace
        identifier_in_namespace =
          if namespace.key
            identifier.namespaced(from: namespace.key, to: nil)
          else
            identifier
          end

        identifier_in_namespace.key_with_separator(PATH_SEPARATOR)
      end

      def callable_option?(value)
        if value.respond_to?(:call)
          !!value.call(self)
        else
          !!value
        end
      end
    end
  end
end


================================================
FILE: lib/dry/system/component_dir.rb
================================================
# frozen_string_literal: true

require "pathname"
require "dry/system/constants"

module Dry
  module System
    # A configured component directory within the container's root. Provides access to the
    # component directory's configuration, as well as methods for locating component files
    # within the directory
    #
    # @see Dry::System::Config::ComponentDir
    # @api private
    class ComponentDir
      # @!attribute [r] config
      #   @return [Dry::System::Config::ComponentDir] the component directory configuration
      #   @api private
      attr_reader :config

      # @!attribute [r] container
      #   @return [Dry::System::Container] the container managing the component directory
      #   @api private
      attr_reader :container

      # @api private
      def initialize(config:, container:)
        @config = config
        @container = container
      end

      # Returns a component for the given key if a matching source file is found within
      # the component dir
      #
      # This searches according to the component dir's configured namespaces, in order of
      # definition, with the first match returned as the component.
      #
      # @param key [String] the component's key
      # @return [Dry::System::Component, nil] the component, if found
      #
      # @api private
      def component_for_key(key)
        config.namespaces.each do |namespace|
          identifier = Identifier.new(key)

          next unless identifier.start_with?(namespace.key)

          if (file_path = find_component_file(identifier, namespace))
            return build_component(identifier, namespace, file_path)
          end
        end

        nil
      end

      def each_component
        return enum_for(:each_component) unless block_given?

        each_file do |file_path, namespace|
          yield component_for_path(file_path, namespace)
        end
      end

      private

      def each_file
        return enum_for(:each_file) unless block_given?

        raise ComponentDirNotFoundError, full_path unless Dir.exist?(full_path)

        config.namespaces.each do |namespace|
          files(namespace).each do |file|
            yield file, namespace
          end
        end
      end

      def files(namespace)
        if namespace.path?
          ::Dir[::File.join(full_path, namespace.path, "**", RB_GLOB)]
        else
          non_root_paths = config.namespaces.to_a.reject(&:root?).map(&:path)

          ::Dir[::File.join(full_path, "**", RB_GLOB)].reject { |file_path|
            Pathname(file_path).relative_path_from(full_path).to_s.start_with?(*non_root_paths)
          }
        end
      end

      # Returns the full path of the component directory
      #
      # @return [Pathname]
      def full_path
        container.root.join(path)
      end

      # Returns a component for a full path to a Ruby source file within the component dir
      #
      # @param path [String] the full path to the file
      # @return [Dry::System::Component] the component
      def component_for_path(path, namespace)
        key = Pathname(path).relative_path_from(full_path).to_s
          .sub(RB_EXT, EMPTY_STRING)
          .scan(WORD_REGEX)
          .join(KEY_SEPARATOR)

        identifier = Identifier.new(key)
          .namespaced(
            from: namespace.path&.gsub(PATH_SEPARATOR, KEY_SEPARATOR),
            to: namespace.key
          )

        build_component(identifier, namespace, path)
      end

      def find_component_file(identifier, namespace)
        # To properly find the file within a namespace with a key, we should strip the key
        # from beginning of our given identifier
        if namespace.key
          identifier = identifier.namespaced(from: namespace.key, to: nil)
        end

        file_name = "#{identifier.key_with_separator(PATH_SEPARATOR)}#{RB_EXT}"

        component_file =
          if namespace.path?
            full_path.join(namespace.path, file_name)
          else
            full_path.join(file_name)
          end

        component_file if component_file.exist?
      end

      def build_component(identifier, namespace, file_path)
        options = {
          inflector: container.config.inflector,
          **component_options,
          **MagicCommentsParser.(file_path)
        }

        Component.new(
          identifier,
          namespace: namespace,
          file_path: file_path,
          **options
        )
      end

      def component_options
        {
          auto_register: auto_register,
          loader: loader,
          instance: instance,
          memoize: memoize
        }
      end

      def method_missing(name, ...)
        if config.respond_to?(name)
          config.public_send(name, ...)
        else
          super
        end
      end

      def respond_to_missing?(name, include_all = false)
        config.respond_to?(name) || super
      end
    end
  end
end


================================================
FILE: lib/dry/system/config/component_dir.rb
================================================
# frozen_string_literal: true

require "dry/system/constants"

module Dry
  module System
    module Config
      # @api public
      class ComponentDir
        include ::Dry::Configurable

        # @!group Settings

        # @!method auto_register=(policy)
        #
        #   Sets the auto-registration policy for the component dir.
        #
        #   This may be a simple boolean to enable or disable auto-registration for all
        #   components, or a proc accepting a {Dry::System::Component} and returning a
        #   boolean to configure auto-registration on a per-component basis
        #
        #   Defaults to `true`.
        #
        #   @param policy [Boolean, Proc]
        #   @return [Boolean, Proc]
        #
        #   @example
        #     dir.auto_register = false
        #
        #   @example
        #     dir.auto_register = proc do |component|
        #       !component.identifier.start_with?("entities")
        #     end
        #
        #   @see auto_register
        #   @see Component
        #   @api public
        #
        # @!method auto_register
        #
        #   Returns the configured auto-registration policy.
        #
        #   @return [Boolean, Proc] the configured policy
        #
        #   @see auto_register=
        #   @api public
        setting :auto_register, default: true

        # @!method instance=(instance_proc)
        #
        #   Sets a proc used to return the instance of any component within the component
        #   dir.
        #
        #   This proc should accept a {Dry::System::Component} and return the object to
        #   serve as the component's instance.
        #
        #   When you provide an instance proc, it will be used in preference to the
        #   {loader} (either the default loader or an explicitly configured one). Provide
        #   an instance proc when you want a simple way to customize the instance for
        #   certain components. For complete control, provide a replacement loader via
        #   {loader=}.
        #
        #   Defaults to `nil`.
        #
        #   @param instance_proc [Proc, nil]
        #   @return [Proc]
        #
        #   @example
        #     dir.instance = proc do |component|
        #       if component.key.match?(/workers\./)
        #         # Register classes for jobs
        #         component.loader.constant(component)
        #       else
        #         # Otherwise register regular instances per default loader
        #         component.loader.call(component)
        #       end
        #     end
        #
        #   @see Component, Loader
        #   @api public
        #
        # @!method instance
        #
        #   Returns the configured instance proc.
        #
        #   @return [Proc, nil]
        #
        #   @see instance=
        #   @api public
        setting :instance

        # @!method loader=(loader)
        #
        #   Sets the loader to use when registering components from the dir in the
        #   container.
        #
        #   Defaults to `Dry::System::Loader`.
        #
        #   When using an autoloader like Zeitwerk, consider using
        #   `Dry::System::Loader::Autoloading`
        #
        #   @param loader [#call] the loader
        #   @return [#call] the configured loader
        #
        #   @see loader
        #   @see Loader
        #   @see Loader::Autoloading
        #   @api public
        #
        # @!method loader
        #
        #   Returns the configured loader.
        #
        #   @return [#call]
        #
        #   @see loader=
        #   @api public
        setting :loader, default: Dry::System::Loader

        # @!method memoize=(policy)
        #
        #   Sets whether to memoize components from the dir when registered in the
        #   container.
        #
        #   This 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
        #
        #   Defaults to `false`.
        #
        #   @param policy [Boolean, Proc]
        #   @return [Boolean, Proc] the configured memoization policy
        #
        #   @example
        #     dir.memoize = true
        #
        #   @example
        #     dir.memoize = proc do |component|
        #       !component.identifier.start_with?("providers")
        #     end
        #
        #   @see memoize
        #   @see Component
        #   @api public
        #
        # @!method memoize
        #
        #   Returns the configured memoization policy.
        #
        #   @return [Boolean, Proc] the configured memoization policy
        #
        #   @see memoize=
        #   @api public
        setting :memoize, default: false

        # @!method namespaces
        #
        #   Returns the configured namespaces for the component dir.
        #
        #   Allows namespaces to added on the returned object via {Namespaces#add}.
        #
        #   @return [Namespaces] the namespaces
        #
        #   @see Namespaces#add
        #   @api public
        setting :namespaces, default: Namespaces.new, cloneable: true

        # @!method add_to_load_path=(policy)
        #
        #   Sets whether the dir should be added to the `$LOAD_PATH` after the container
        #   is configured.
        #
        #   Defaults to `true`. This may need to be set to `false` when using a class
        #   autoloading system.
        #
        #   @param policy [Boolean]
        #   @return [Boolean]
        #
        #   @see add_to_load_path
        #   @see Container.configure
        #   @api public
        #
        # @!method add_to_load_path
        #
        #   Returns the configured value.
        #
        #   @return [Boolean]
        #
        #   @see add_to_load_path=
        #   @api public
        setting :add_to_load_path, default: true

        # @!endgroup

        # Returns the component dir path, relative to the configured container root
        #
        # @return [String] the path
        attr_reader :path

        # @api public
        def initialize(path)
          super()
          @path = path
          yield self if block_given?
        end

        # @api private
        def auto_register?
          !!config.auto_register
        end

        private

        def method_missing(name, ...)
          if config.respond_to?(name)
            config.public_send(name, ...)
          else
            super
          end
        end

        def respond_to_missing?(name, include_all = false)
          config.respond_to?(name) || super
        end
      end
    end
  end
end


================================================
FILE: lib/dry/system/config/component_dirs.rb
================================================
# frozen_string_literal: true

require "dry/system/constants"
require "dry/system/errors"

module Dry
  module System
    module Config
      # The configured component dirs for a container
      #
      # @api public
      class ComponentDirs
        # @!group Settings

        # @!method auto_register=(value)
        #
        #   Sets a default `auto_register` for all added component dirs
        #
        #   @see ComponentDir.auto_register=
        #   @see auto_register
        #
        # @!method auto_register
        #
        #   Returns the configured default `auto_register`
        #
        #   @see auto_register=

        # @!method instance=(value)
        #
        #   Sets a default `instance` for all added component dirs
        #
        #   @see ComponentDir.instance=
        #   @see auto_register
        #
        # @!method auto_register
        #
        #   Returns the configured default `instance`
        #
        #   @see instance=

        # @!method loader=(value)
        #
        #   Sets a default `loader` value for all added component dirs
        #
        #   @see ComponentDir.loader=
        #   @see loader
        #
        # @!method loader
        #
        #   Returns the configured default `loader`
        #
        #   @see loader=

        # @!method memoize=(value)
        #
        #   Sets a default `memoize` value for all added component dirs
        #
        #   @see ComponentDir.memoize=
        #   @see memoize
        #
        # @!method memoize
        #
        #   Returns the configured default `memoize`
        #
        #   @see memoize=

        # @!method namespaces
        #
        #   Returns the default configured namespaces for all added component dirs
        #
        #   Allows namespaces to added on the returned object via {Dry::System::Config::Namespaces#add}.
        #
        #   @see Dry::System::Config::Namespaces#add
        #
        #   @return [Namespaces] the namespaces

        # @!method add_to_load_path=(value)
        #
        #   Sets a default `add_to_load_path` value for all added component dirs
        #
        #   @see ComponentDir.add_to_load_path=
        #   @see add_to_load_path
        #
        # @!method add_to_load_path
        #
        #   Returns the configured default `add_to_load_path`
        #
        #   @see add_to_load_path=

        # @!endgroup

        # A ComponentDir for configuring the default values to apply to all added
        # component dirs
        #
        # @see #method_missing
        # @api private
        attr_reader :defaults

        # Creates a new component dirs
        #
        # @api private
        def initialize
          @dirs = {}
          @defaults = ComponentDir.new(nil)
        end

        # @api private
        def initialize_copy(source)
          @dirs = source.dirs.transform_values(&:dup)
          @defaults = source.defaults.dup
        end

        # Returns and optionally yields a previously added component dir
        #
        # @param path [String] the path for the component dir
        # @yieldparam dir [ComponentDir] the component dir
        #
        # @return [ComponentDir] the component dir
        #
        # @api public
        def dir(path)
          dirs[path].tap do |dir|
            # Defaults can be (re-)applied first, since the dir has already been added
            apply_defaults_to_dir(dir) if dir
            yield dir if block_given?
          end
        end
        alias_method :[], :dir

        # @overload add(path)
        #   Adds and configures a component dir for the given path
        #
        #   @param path [String] the path for the component dir, relative to the configured
        #     container root
        #   @yieldparam dir [ComponentDir] the component dir to configure
        #
        #   @return [ComponentDir] the added component dir
        #
        #   @example
        #     component_dirs.add "lib" do |dir|
        #       dir.default_namespace = "my_app"
        #     end
        #
        #   @see ComponentDir
        #   @api public
        #
        # @overload add(dir)
        #   Adds a configured component dir
        #
        #   @param dir [ComponentDir] the configured component dir
        #
        #   @return [ComponentDir] the added component dir
        #
        #   @example
        #     dir = Dry::System::ComponentDir.new("lib")
        #     component_dirs.add dir
        #
        #   @see ComponentDir
        #   @api public
        def add(path_or_dir)
          path, dir_to_add = path_and_dir(path_or_dir)

          raise ComponentDirAlreadyAddedError, path if dirs.key?(path)

          dirs[path] = dir_to_add.tap do |dir|
            # Defaults must be applied after yielding, since the dir is being newly added,
            # and must have its configuration fully in place before we can know which
            # defaults to apply
            yield dir if path_or_dir == path && block_given?
            apply_defaults_to_dir(dir)
          end
        end

        # Deletes and returns a previously added component dir
        #
        # @param path [String] the path for the component dir
        #
        # @return [ComponentDir] the removed component dir
        #
        # @api public
        def delete(path)
          dirs.delete(path)
        end

        # Returns the paths of the component dirs
        #
        # @return [Array<String>] the component dir paths
        #
        # @api public
        def paths
          dirs.keys
        end

        # Returns the count of component dirs
        #
        # @return [Integer]
        #
        # @api public
        def length
          dirs.length
        end
        alias_method :size, :length

        # Returns the added component dirs, with default settings applied
        #
        # @return [Array<ComponentDir>]
        #
        # @api public
        def to_a
          dirs.each { |_, dir| apply_defaults_to_dir(dir) }
          dirs.values
        end

        # Calls the given block once for each added component dir, passing the dir as an
        # argument.
        #
        # @yieldparam dir [ComponentDir] the yielded component dir
        #
        # @api public
        def each(&)
          to_a.each(&)
        end

        protected

        # Returns the hash of component dirs, keyed by their paths
        #
        # Recently changed default configuration may not be applied to these dirs. Use
        # #to_a or #each to access dirs with default configuration fully applied.
        #
        # This method exists to encapsulate the instance variable and to serve the needs
        # of #initialize_copy
        #
        # @return [Hash{String => ComponentDir}]
        #
        # @api private
        attr_reader :dirs

        private

        # Converts a path string or pre-built component dir into a path and dir tuple
        #
        # @param path_or_dir [String,ComponentDir]
        #
        # @return [Array<(String, ComponentDir)>]
        #
        # @see #add
        def path_and_dir(path_or_dir)
          if path_or_dir.is_a?(ComponentDir)
            dir = path_or_dir
            [dir.path, dir]
          else
            path = path_or_dir
            [path, ComponentDir.new(path)]
          end
        end

        # Applies default settings to a component dir. This is run every time the dirs are
        # accessed to ensure defaults are applied regardless of when new component dirs
        # are added. This method must be idempotent.
        #
        # @return [void]
        def apply_defaults_to_dir(dir)
          defaults.config.values.each do |key, _|
            if defaults.configured?(key) && !dir.configured?(key)
              dir.public_send(:"#{key}=", defaults.public_send(key).dup)
            end
          end
        end

        def method_missing(name, ...)
          if defaults.respond_to?(name)
            defaults.public_send(name, ...)
          else
            super
          end
        end

        def respond_to_missing?(name, include_all = false)
          defaults.respond_to?(name) || super
        end
      end
    end
  end
end


================================================
FILE: lib/dry/system/config/namespace.rb
================================================
# frozen_string_literal: true

require "dry/system/constants"

module Dry
  module System
    module Config
      # A configured namespace for a component dir
      #
      # Namespaces consist of three elements:
      #
      # - The `path` within the component dir to which its namespace rules should apply.
      # - A `key`, which determines the leading part of the key used to register
      #   each component in the container.
      # - A `const`, which is the Ruby namespace expected to contain the class constants
      #   defined within each component's source file. This value is expected to be an
      #   "underscored" string, intended to be run through the configured inflector to be
      #   converted into a real constant (e.g. `"foo_bar/baz"` will become `FooBar::Baz`)
      #
      # Namespaces are added and configured for a component dir via {Namespaces#add}.
      #
      # @see Namespaces#add
      #
      # @api public
      class Namespace
        ROOT_PATH = nil

        include Dry::Equalizer(:path, :key, :const)

        # @api public
        attr_reader :path

        # @api public
        attr_reader :key

        # @api public
        attr_reader :const

        # Returns a namespace configured to serve as the default root namespace for a
        # component dir, ensuring that all code within the dir can be loaded, regardless
        # of any other explictly configured namespaces
        #
        # @return [Namespace] the root namespace
        #
        # @api private
        def self.default_root
          new(
            path: ROOT_PATH,
            key: nil,
            const: nil
          )
        end

        # @api private
        def initialize(path:, key:, const:)
          @path = path
          # Default keys (i.e. when the user does not explicitly provide one) for non-root
          # paths will include path separators, which we must convert into key separators
          @key = key && key == path ? key.gsub(PATH_SEPARATOR, KEY_SEPARATOR) : key
          @const = const
        end

        # @api public
        def root?
          path == ROOT_PATH
        end

        # @api public
        def path?
          !root?
        end
      end
    end
  end
end


================================================
FILE: lib/dry/system/config/namespaces.rb
================================================
# frozen_string_literal: true

require "dry/system/errors"

module Dry
  module System
    module Config
      # The configured namespaces for a ComponentDir
      #
      # @see Config::ComponentDir#namespaces
      #
      # @api private
      class Namespaces
        include Dry::Equalizer(:namespaces)

        # @api private
        attr_reader :namespaces

        # @api private
        def initialize
          @namespaces = {}
        end

        # @api private
        def initialize_copy(source)
          super
          @namespaces = source.namespaces.dup
        end

        # Returns the namespace configured for the path, or nil if no such namespace has
        # been configured
        #
        # @return [Namespace, nil] the namespace, if configured
        #
        # @api public
        def namespace(path)
          namespaces[path]
        end
        alias_method :[], :namespace

        # Returns the namespace configured for the root path, or nil if the root namespace
        # has not been configured
        #
        # @return [Namespace, nil] the root namespace, if configured
        #
        # @api public
        def root
          namespaces[Namespace::ROOT_PATH]
        end

        # Adds a component dir namespace
        #
        # A namespace encompasses a given sub-directory of the component dir, and
        # determines (1) the leading segments of its components' registered identifiers,
        # and (2) the expected constant namespace of their class constants.
        #
        # A namespace for a path can only be added once.
        #
        # @example Adding a namespace with top-level identifiers
        #   # Components defined within admin/ (e.g. admin/my_component.rb) will be:
        #   #
        #   # - Registered with top-level identifiers ("my_component")
        #   # - Expected to have constants in `Admin`, matching the namespace's path (Admin::MyComponent)
        #
        #   namespaces.add "admin", key: nil
        #
        # @example Adding a namespace with top-level class constants
        #   # Components defined within adapters/ (e.g. adapters/my_adapter.rb) will be:
        #   #
        #   # - Registered with leading identifiers matching the namespace's path ("adapters.my_adapter")
        #   # - Expected to have top-level constants (::MyAdapter)
        #
        #   namespaces.add "adapters", const: nil
        #
        # @example Adding a namespace with distinct identifiers and class constants
        #   # Components defined within `bananas/` (e.g. bananas/banana_split.rb) will be:
        #   #
        #   # - Registered with the given leading identifier ("desserts.banana_split")
        #   # - Expected to have constants within the given namespace (EatMe::Now::BananaSplit)
        #
        #   namespaces.add "bananas", key: "desserts", const: "eat_me/now"
        #
        # @param path [String] the path to the sub-directory of source files to which this
        #   namespace should apply, relative to the component dir
        # @param key [String, nil] the leading namespace to apply to the container keys
        #   for the components. Set `nil` for the keys to be top-level.
        # @param const [String, nil] the Ruby constant namespace to expect for constants
        #   defined within the components. This should be provided in underscored string
        #   form, e.g. "hello_there/world" for a Ruby constant of `HelloThere::World`. Set
        #   `nil` for the constants to be top-level.
        #
        # @return [Namespace] the added namespace
        #
        # @see Namespace
        #
        # @api public
        def add(path, key: path, const: path)
          raise NamespaceAlreadyAddedError, path if namespaces.key?(path)

          namespaces[path] = Namespace.new(path: path, key: key, const: const)
        end

        # Adds a root component dir namespace
        #
        # @see #add
        #
        # @api public
        def add_root(key: nil, const: nil)
          add(Namespace::ROOT_PATH, key: key, const: const)
        end

        # Deletes the configured namespace for the given path and returns the namespace
        #
        # If no namespace was previously configured for the given path, returns nil
        #
        # @param path [String] the path for the namespace
        #
        # @return [Namespace, nil]
        #
        # @api public
        def delete(path)
          namespaces.delete(path)
        end

        # Deletes the configured root namespace and returns the namespace
        #
        # If no root namespace was previously configured, returns nil
        #
        # @return [Namespace, nil]
        #
        # @api public
        def delete_root
          delete(Namespace::ROOT_PATH)
        end

        # Returns the paths of the configured namespaces
        #
        # @return [Array<String,nil>] the namespace paths, with nil representing the root
        #   namespace
        #
        # @api public
        def paths
          namespaces.keys
        end

        # Returns the count of configured namespaces
        #
        # @return [Integer]
        #
        # @api public
        def length
          namespaces.length
        end
        alias_method :size, :length

        # Returns true if there are no configured namespaces
        #
        # @return [Boolean]
        #
        # @api public
        def empty?
          namespaces.empty?
        end

        # Returns the configured namespaces as an array
        #
        # Adds a default root namespace to the end of the array if one was not added
        # explicitly. This fallback ensures that all components in the component dir can
        # be loaded.
        #
        # @return [Array<Namespace>] the namespaces
        #
        # @api public
        def to_a
          namespaces.values.tap do |arr|
            arr << Namespace.default_root unless arr.any?(&:root?)
          end
        end

        # Calls the given block once for each configured namespace, passing the namespace
        # as an argument.
        #
        # @yieldparam namespace [Namespace] the yielded namespace
        #
        # @api public
        def each(&)
          to_a.each(&)
        end
      end
    end
  end
end


================================================
FILE: lib/dry/system/constants.rb
================================================
# frozen_string_literal: true

module Dry
  module System
    include Dry::Core::Constants

    RB_EXT = ".rb"
    RB_GLOB = "*.rb"
    PATH_SEPARATOR = File::SEPARATOR
    KEY_SEPARATOR = "."
    WORD_REGEX = /\w+/
  end
end


================================================
FILE: lib/dry/system/container.rb
================================================
# frozen_string_literal: true

require "pathname"

require "dry/configurable"
require "dry/auto_inject"
require "dry/inflector"

module Dry
  module System
    # Abstract container class to inherit from
    #
    # Container class is treated as a global registry with all system components.
    # Container can also import dependencies from other containers, which is
    # useful in complex systems that are split into sub-systems.
    #
    # Container can be finalized, which triggers loading of all the defined
    # components within a system, after finalization it becomes frozen. This
    # typically happens in cases like booting a web application.
    #
    # Before finalization, Container can lazy-load components on demand. A
    # component can be a simple class defined in a single file, or a complex
    # component which has init/start/stop lifecycle, and it's defined in a boot
    # file. Components which specify their dependencies using Import module can
    # be safely required in complete isolation, and Container will resolve and
    # load these dependencies automatically.
    #
    # Furthermore, Container supports auto-registering components based on
    # dir/file naming conventions. This reduces a lot of boilerplate code as all
    # you have to do is to put your classes under configured directories and
    # their instances will be automatically registered within a container.
    #
    # Every container needs to be configured with following settings:
    #
    # * `:name` - a unique container name
    # * `:root` - a system root directory (defaults to `pwd`)
    #
    # @example
    #   class MyApp < Dry::System::Container
    #     configure do |config|
    #       config.name = :my_app
    #
    #       # this will auto-register classes from 'lib/components'. ie if you add
    #       # `lib/components/repo.rb` which defines `Repo` class, then it's
    #       # instance will be automatically available as `MyApp['repo']`
    #       config.auto_register = %w(lib/components)
    #     end
    #
    #     # this will configure $LOAD_PATH to include your `lib` dir
    #     add_dirs_to_load_paths!('lib')
    #   end
    #
    # @api public
    class Container
      extend Dry::Core::Container::Mixin
      extend Dry::System::Plugins

      setting :name
      setting :root, default: Pathname.pwd.freeze, constructor: ->(path) { Pathname(path) }
      setting :provider_dirs, default: ["system/providers"]
      setting :registrations_dir, default: "system/registrations"
      setting :component_dirs, default: Config::ComponentDirs.new, cloneable: true
      setting :exports, reader: true
      setting :inflector, default: Dry::Inflector.new
      setting :auto_registrar, default: Dry::System::AutoRegistrar
      setting :manifest_registrar, default: Dry::System::ManifestRegistrar
      setting :provider_registrar, default: Dry::System::ProviderRegistrar
      setting :importer, default: Dry::System::Importer

      # Expect "." as key namespace separator. This is not intended to be user-configurable.
      config.namespace_separator = KEY_SEPARATOR

      class << self
        # @!method config
        #   Returns the configuration for the container
        #
        #   @example
        #     container.config.root = "/path/to/app"
        #     container.config.root # => #<Pathname:/path/to/app>
        #
        #   @return [Dry::Configurable::Config]
        #
        #   @api public

        # Yields a configuration object for the container, which you can use to modify the
        # configuration, then runs the after-`configured` hooks and finalizes (freezes)
        # the {config}.
        #
        # Does not finalize the config when given `finalize_config: false`
        #
        # @example
        #   class MyApp < Dry::System::Container
        #     configure do |config|
        #       config.root = Pathname("/path/to/app")
        #       config.name = :my_app
        #     end
        #   end
        #
        # @param finalize_config [Boolean]
        #
        # @return [self]
        #
        # @see after
        #
        # @api public
        def configure(finalize_config: true, &)
          super(&)
          configured!(finalize_config: finalize_config)
        end

        # Marks the container as configured, runs the after-`configured` hooks, then
        # finalizes (freezes) the {config}.
        #
        # This method is useful to call if you're modifying the container's {config}
        # directly, rather than via the config object yielded when calling {configure}.
        #
        # Does not finalize the config if given `finalize_config: false`.
        #
        # @param finalize_config [Boolean]
        #
        # @return [self]
        #
        # @see after
        #
        # @api public
        def configured!(finalize_config: true)
          return self if configured?

          hooks[:after_configure].each { |hook| instance_eval(&hook) }

          _configurable_finalize! if finalize_config

          @__configured__ = true

          self
        end

        # Finalizes the config for this container
        #
        # @api private
        alias_method :_configurable_finalize!, :finalize!

        def configured?
          @__configured__.equal?(true)
        end

        # Registers another container for import
        #
        # @example
        #   # system/container.rb
        #   require "dry/system"
        #   require "logger"
        #
        #   class Core < Dry::System::Container
        #     register("logger", Logger.new($stdout))
        #   end
        #
        #   # apps/my_app/system/container.rb
        #   require 'system/container'
        #
        #   class MyApp < Dry::System::Container
        #     import(from: Core, as: :core)
        #   end
        #
        #   MyApp.import(keys: ["logger"], from: Core, as: :core2)
        #
        #   MyApp["core.logger"].info("Test")
        #   MyApp["core2.logger"].info("Test2")
        #
        # @param keys [Array<String>] Keys for the components to import
        # @param from [Class] The container to import from
        # @param as [Symbol] Namespace to use for the components of the imported container
        #
        # @raise [Dry::System::ContainerAlreadyFinalizedError] if the container has already
        #  been finalized
        #
        # @api public
        def import(from:, as:, keys: nil)
          raise Dry::System::ContainerAlreadyFinalizedError if finalized?

          importer.register(container: from, namespace: as, keys: keys)

          self
        end

        # @overload register_provider(name, namespace: nil, from: nil, source: nil, if: true, &block)
        #   Registers a provider and its lifecycle hooks
        #
        #   By convention, you should place a file for each provider in one of the
        #   configured `provider_dirs`, and they will be loaded on demand when components
        #   are loaded in isolation, or during container finalization.
        #
        #   @example
        #     # system/container.rb
        #     class MyApp < Dry::System::Container
        #       configure do |config|
        #         config.root = Pathname("/path/to/app")
        #       end
        #     end
        #
        #     # system/providers/db.rb
        #     #
        #     # Simple provider registration
        #     MyApp.register_provider(:db) do
        #       start do
        #         require "db"
        #         register("db", DB.new)
        #       end
        #     end
        #
        #     # system/providers/db.rb
        #     #
        #     # Provider registration with lifecycle triggers
        #     MyApp.register_provider(:db) do |container|
        #       init do
        #         require "db"
        #         DB.configure(ENV["DB_URL"])
        #         container.register("db", DB.new)
        #       end
        #
        #       start do
        #         container["db"].establish_connection
        #       end
        #
        #       stop do
        #         container["db"].close_connection
        #       end
        #     end
        #
        #     # system/providers/db.rb
        #     #
        #     # Provider registration which uses another provider
        #     MyApp.register_provider(:db) do |container|
        #       start do
        #         use :logger
        #
        #         require "db"
        #         DB.configure(ENV['DB_URL'], logger: logger)
        #         container.register("db", DB.new)
        #       end
        #     end
        #
        #     # system/providers/db.rb
        #     #
        #     # Provider registration under a namespace. This will register the
        #     # db object with the "persistence.db" key
        #     MyApp.register_provider(:persistence, namespace: "db") do
        #       start do
        #         require "db"
        #         DB.configure(ENV["DB_URL"])
        #         register("db", DB.new)
        #       end
        #     end
        #
        #   @param name [Symbol] a unique name for the provider
        #   @param namespace [String, nil] the key namespace to use for any registrations
        #     made during the provider's lifecycle
        #   @param from [Symbol, nil] the group for the external provider source (with the
        #     provider source name inferred from `name` or passsed explicitly as
        #     `source:`)
        #   @param source [Symbol, nil] the name of the external provider source to use
        #     (if different from the value provided as `name`)
        #   @param if [Boolean] a boolean to determine whether to register the provider
        #
        #   @see Provider
        #   @see Provider::Source
        #
        #   @return [self]
        #
        #   @api public
        def register_provider(...)
          providers.register_provider(...)
        end

        # Return if a container was finalized
        #
        # @return [TrueClass, FalseClass]
        #
        # @api public
        def finalized?
          @__finalized__.equal?(true)
        end

        # Finalizes the container
        #
        # This triggers importing components from other containers, booting
        # registered components and auto-registering components. It should be
        # called only in places where you want to finalize your system as a
        # whole, ie when booting a web application
        #
        # @example
        #   # system/container.rb
        #   class MyApp < Dry::System::Container
        #     configure do |config|
        #       config.root = Pathname("/path/to/app")
        #       config.name = :my_app
        #       config.auto_register = %w(lib/apis lib/core)
        #     end
        #   end
        #
        #   # You can put finalization file anywhere you want, ie system/boot.rb
        #   MyApp.finalize!
        #
        #   # If you need last-moment adjustments just before the finalization
        #   # you can pass a block and do it there
        #   MyApp.finalize! do |container|
        #     # stuff that only needs to happen for finalization
        #   end
        #
        # @return [self] frozen container
        #
        # @api public
        def finalize!(freeze: true, &)
          return self if finalized?

          configured!

          run_hooks(:finalize) do
            yield(self) if block_given?

            [providers, auto_registrar, manifest_registrar, importer].each(&:finalize!)

            @__finalized__ = true
          end

          self.freeze if freeze

          self
        end

        # Starts a provider
        #
        # As a result, the provider's `prepare` and `start` lifecycle triggers are called
        #
        # @example
        #   MyApp.start(:persistence)
        #
        # @param name [Symbol] the name of a registered provider to start
        #
        # @return [self]
        #
        # @api public
        def start(name)
          providers.start(name)
          self
        end

        # Prepares a provider using its `prepare` lifecycle trigger
        #
        # Preparing (as opposed to starting) a provider is useful in places where some
        # aspects of a heavier dependency are needed, but its fully started environment
        #
        # @example
        #   MyApp.prepare(:persistence)
        #
        # @param name [Symbol] The name of the registered provider to prepare
        #
        # @return [self]
        #
        # @api public
        def prepare(name)
          providers.prepare(name)
          self
        end

        # Stop a specific component but calls only `stop` lifecycle trigger
        #
        # @example
        #   MyApp.stop(:persistence)
        #
        # @param name [Symbol] The name of a registered bootable component
        #
        # @return [self]
        #
        # @api public
        def stop(name)
          providers.stop(name)
          self
        end

        # @api public
        def shutdown!
          providers.shutdown
          self
        end

        # Adds the directories (relative to the container's root) to the Ruby load path
        #
        # @example
        #   class MyApp < Dry::System::Container
        #     configure do |config|
        #       # ...
        #     end
        #
        #     add_to_load_path!('lib')
        #   end
        #
        # @param dirs [Array<String>]
        #
        # @return [self]
        #
        # @api public
        def add_to_load_path!(*dirs)
          dirs.reverse.map(&root.method(:join)).each do |path|
            $LOAD_PATH.prepend(path.to_s) unless $LOAD_PATH.include?(path.to_s)
          end
          self
        end

        # @api public
        def load_registrations!(name)
          manifest_registrar.(name)
          self
        end

        # Builds injector for this container
        #
        # An injector is a useful mixin which injects dependencies into
        # automatically defined constructor.
        #
        # @example
        #   # Define an injection mixin
        #   #
        #   # system/import.rb
        #   Import = MyApp.injector
        #
        #   # Use it in your auto-registered classes
        #   #
        #   # lib/user_repo.rb
        #   require 'import'
        #
        #   class UserRepo
        #     include Import['persistence.db']
        #   end
        #
        #   MyApp['user_repo].db # instance under 'persistence.db' key
        #
        # @param options [Hash] injector options
        #
        # @api public
        def injector(**options)
          Dry::AutoInject(self, **options)
        end

        # Requires one or more files relative to the container's root
        #
        # @example
        #   # single file
        #   MyApp.require_from_root('lib/core')
        #
        #   # glob
        #   MyApp.require_from_root('lib/**/*')
        #
        # @param paths [Array<String>] one or more paths, supports globs too
        #
        # @api public
        def require_from_root(*paths)
          paths.flat_map { |path|
            path.to_s.include?("*") ? ::Dir[root.join(path)] : root.join(path)
          }.each { |path|
            Kernel.require path.to_s
          }
        end

        # Returns container's root path
        #
        # @example
        #   class MyApp < Dry::System::Container
        #     configure do |config|
        #       config.root = Pathname('/my/app')
        #     end
        #   end
        #
        #   MyApp.root # returns '/my/app' pathname
        #
        # @return [Pathname]
        #
        # @api public
        def root
          config.root
        end

        # @api public
        def register(key, *)
          super

          hooks[:after_register].each { |hook| instance_exec(key, &hook) }

          self
        end

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

          super
        end

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

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

        # @api private
        def component_dirs
          config.component_dirs.to_a.map { |dir| ComponentDir.new(config: dir, container: self) }
        end

        # @api private
        def providers
          @providers ||= config.provider_registrar.new(self)
        end

        # @api private
        def auto_registrar
          @auto_registrar ||= config.auto_registrar.new(self)
        end

        # @api private
        def manifest_registrar
          @manifest_registrar ||= config.manifest_registrar.new(self)
        end

        # @api private
        def importer
          @importer ||= config.importer.new(self)
        end

        # Registers a callback hook to run before container lifecycle events.
        #
        # Currently, the only supported event is `:finalized`. This hook is called when
        # you run `{finalize!}`.
        #
        # When the given block is called, `self` is the container class, and no block
        # arguments are given.
        #
        # @param event [Symbol] the event name
        # @param block [Proc] the callback hook to run
        #
        # @return [self]
        #
        # @api public
        def before(event, &block)
          hooks[:"before_#{event}"] << block
          self
        end

        # Registers a callback hook to run after container lifecycle events.
        #
        # The supported events are:
        #
        # - `:configured`, called when you run {configure} or {configured!}, or when
        #   running {finalize!} and neither of the prior two methods have been called.
        # - `:finalized`, called when you run {finalize!}.
        #
        # When the given block is called, `self` is the container class, and no block
        # arguments are given.
        #
        # @param event [Symbol] the event name
        # @param block [Proc] the callback hook to run
        #
        # @return [self]
        #
        # @api public
        def after(event, &block)
          hooks[:"after_#{event}"] << block
          self
        end

        # @api private
        def hooks
          @hooks ||= Hash.new { |h, k| h[k] = [] }
        end

        # @api private
        def inherited(klass)
          hooks.each do |event, blocks|
            klass.hooks[event].concat blocks.dup
          end

          klass.instance_variable_set(:@__configured__, false)
          klass.instance_variable_set(:@__finalized__, false)

          super
        end

        protected

        # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
        # @api private
        def load_component(key)
          return self if registered?(key)

          if (provider = providers[key])
            provider.start
            return self
          end

          component = find_component(key)

          providers[component.root_key]&.start
          return self if registered?(key)

          if component.loadable?
            load_local_component(component)
          elsif manifest_registrar.file_exists?(component)
            manifest_registrar.(component)
          elsif importer.namespace?(component.root_key)
            load_imported_component(component.identifier, namespace: component.root_key)
          elsif importer.namespace?(nil)
            load_imported_component(component.identifier, namespace: nil)
          end

          self
        end
        # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity

        private

        def load_local_component(component)
          if component.auto_register?
            register(component.identifier, memoize: component.memoize?) { component.instance }
          end
        end

        def load_imported_component(identifier, namespace:)
          return unless importer.namespace?(namespace)

          import_key = identifier.namespaced(from: namespace, to: nil).key

          importer.import(namespace, keys: [import_key])
        end

        def find_component(key)
          # Find the first matching component from within the configured component dirs.
          # If no matching component is found, return a null component; this fallback is
          # important because the component may still be loadable via the manifest
          # registrar or an imported container.
          component_dirs.detect { |dir|
            if (component = dir.component_for_key(key))
              break component
            end
          } || IndirectComponent.new(Identifier.new(key))
        end

        def run_hooks(event)
          hooks[:"before_#{event}"].each { instance_eval(&_1) }
          yield
          hooks[:"after_#{event}"].each { instance_eval(&_1) }
        end
      end

      # Default hooks
      after :configure do
        # Add appropriately configured component dirs to the load path
        #
        # Do this in a single pass to preserve ordering (i.e. earliest dirs win)
        paths = config.component_dirs.to_a.each_with_object([]) { |dir, arr|
          arr << dir.path if dir.add_to_load_path
        }
        add_to_load_path!(*paths)
      end
    end
  end
end


================================================
FILE: lib/dry/system/errors.rb
================================================
# frozen_string_literal: true

module Dry
  module System
    # Error raised when import is called on an already finalized container
    #
    # @api public
    ContainerAlreadyFinalizedError = Class.new(StandardError)

    # Error raised when a component dir is added to configuration more than once
    #
    # @api public
    ComponentDirAlreadyAddedError = Class.new(StandardError) do
      def initialize(dir)
        super("Component directory #{dir.inspect} already added")
      end
    end

    # Error raised when a configured component directory could not be found
    #
    # @api public
    ComponentDirNotFoundError = Class.new(StandardError) do
      def initialize(dir)
        super("Component dir '#{dir}' not found")
      end
    end

    # Error raised when a namespace for a component dir is added to configuration more
    # than once
    #
    # @api public
    NamespaceAlreadyAddedError = Class.new(StandardError) do
      def initialize(path)
        path_label = path ? "path #{path.inspect}" : "root path"

        super("Namespace for #{path_label} already added")
      end
    end

    # Error raised when attempting to register provider using a name that has already been
    # registered
    #
    # @api public
    ProviderAlreadyRegisteredError = Class.new(ArgumentError) do
      def initialize(provider_name)
        super("Provider #{provider_name.inspect} has already been registered")
      end
    end

    # Error raised when a named provider could not be found
    #
    # @api public
    ProviderNotFoundError = Class.new(ArgumentError) do
      def initialize(name)
        super("Provider #{name.inspect} not found")
      end
    end

    # Error raised when a named provider source could not be found
    #
    # @api public
    ProviderSourceNotFoundError = Class.new(StandardError) do
      def initialize(name:, group:, keys:)
        msg = "Provider source not found: #{name.inspect}, group: #{group.inspect}"

        key_list = keys.map { |key| "- #{key[:name].inspect}, group: #{key[:group].inspect}" }
        msg += "Available provider sources:\n\n#{key_list}"

        super(msg)
      end
    end

    # Error raised when trying to use a plugin that does not exist.
    #
    # @api public
    PluginNotFoundError = Class.new(StandardError) do
      def initialize(plugin_name)
        super("Plugin #{plugin_name.inspect} does not exist")
      end
    end

    # Exception raise when a plugin dependency failed to load
    #
    # @api public
    PluginDependencyMissing = Class.new(StandardError) do
      # @api private
      def initialize(plugin, message, gem = nil)
        details = gem ? "#{message} - add #{gem} to your Gemfile" : message
        super("dry-system plugin #{plugin.inspect} failed to load its dependencies: #{details}")
      end
    end

    # Exception raised when auto-registerable component is not loadable
    #
    # @api public
    ComponentNotLoadableError = Class.new(NameError) do
      # @api private
      def initialize(component, error,
                     corrections: DidYouMean::ClassNameChecker.new(error).corrections)
        full_class_name = [error.receiver, error.name].join("::")

        message = [
          "Component '#{component.key}' is not loadable.",
          "Looking for #{full_class_name}."
        ]

        if corrections.any?
          case_correction = corrections.find { |correction| correction.casecmp?(full_class_name) }
          if case_correction
            acronyms_needed = case_correction.split("::").difference(full_class_name.split("::"))
            stringified_acronyms_needed = acronyms_needed.map { |acronym|
              "'#{acronym}'"
            } .join(", ")
            message <<
              <<~ERROR_MESSAGE

                You likely need to add:

                    acronym(#{stringified_acronyms_needed})

                to your container's inflector, since we found a #{case_correction} class.
              ERROR_MESSAGE
          else
            message << DidYouMean.formatter.message_for(corrections)
          end
        end

        super(message.join("\n"))
      end
    end
  end
end


================================================
FILE: lib/dry/system/identifier.rb
================================================
# frozen_string_literal: true

require "dry/system/constants"

module Dry
  module System
    # An identifier representing a component to be registered.
    #
    # Components are eventually registered in the container using plain string
    # identifiers, available as the `identifier` or `key` attribute here. Additional
    # methods are provided to make it easier to evaluate or manipulate these identifiers.
    #
    # @api public
    class Identifier
      include Dry::Equalizer(:key)

      # @return [String] the identifier's string key
      # @api public
      attr_reader :key

      # @api private
      def initialize(key)
        @key = key.to_s
      end

      # @!method to_s
      #   Returns the identifier string key
      #
      #   @return [String]
      #   @see #key
      #   @api public
      alias_method :to_s, :key

      # Returns the root namespace segment of the identifier string, as a symbol
      #
      # @example
      #   identifier.key # => "articles.operations.create"
      #   identifier.root_key # => :articles
      #
      # @return [Symbol] the root key
      # @api public
      def root_key
        segments.first.to_sym
      end

      # Returns true if the given leading segments string is a leading part of the {key}.
      #
      # Also returns true if nil or an empty string is given.
      #
      # @example
      #   identifier.key # => "articles.operations.create"
      #
      #   identifier.start_with?("articles.operations") # => true
      #   identifier.start_with?("articles") # => true
      #   identifier.start_with?("article") # => false
      #   identifier.start_with?(nil) # => true
      #
      # @param leading_segments [String] the one or more leading segments to check
      # @return [Boolean]
      # @api public
      def start_with?(leading_segments)
        leading_segments.to_s.empty? ||
          key.start_with?("#{leading_segments}#{KEY_SEPARATOR}") ||
          key.eql?(leading_segments)
      end

      # Returns true if the given trailing segments string is the end part of the {key}.
      #
      # Also returns true if nil or an empty string is given.
      #
      # @example
      #   identifier.key # => "articles.operations.create"
      #
      #   identifier.end_with?("create") # => true
      #   identifier.end_with?("operations.create") # => true
      #   identifier.end_with?("ate") # => false, not a whole segment
      #   identifier.end_with?("nup") # => false, not in key at all
      #
      # @param trailing_segments [String] the one or more trailing key segments to check
      # @return [Boolean]
      # @api public
      def end_with?(trailing_segments)
        trailing_segments.to_s.empty? ||
          key.end_with?("#{KEY_SEPARATOR}#{trailing_segments}") ||
          key.eql?(trailing_segments)
      end

      # Returns true if the given segments string matches whole segments within the {key}.
      #
      # @example
      #   identifier.key # => "articles.operations.create"
      #
      #   identifier.include?("operations") # => true
      #   identifier.include?("articles.operations") # => true
      #   identifier.include?("operations.create") # => true
      #
      #   identifier.include?("article") # => false, not a whole segment
      #   identifier.include?("update") # => false, not in key at all
      #
      # @param segments [String] the one of more key segments to check
      # @return [Boolean]
      # @api public
      def include?(segments)
        return false if segments.to_s.empty?

        sep_re = Regexp.escape(KEY_SEPARATOR)
        key.match?(
          /
            (\A|#{sep_re})
            #{Regexp.escape(segments)}
            (\Z|#{sep_re})
          /x
        )
      end

      # Returns the key with its segments separated by the given separator
      #
      # @example
      #   identifier.key # => "articles.operations.create"
      #   identifier.key_with_separator("/") # => "articles/operations/create"
      #
      # @return [String] the key using the separator
      # @api private
      def key_with_separator(separator)
        segments.join(separator)
      end

      # Returns a copy of the identifier with the key's leading namespace(s) replaced
      #
      # @example Changing a namespace
      #   identifier.key # => "articles.operations.create"
      #   identifier.namespaced(from: "articles", to: "posts").key # => "posts.commands.create"
      #
      # @example Removing a namespace
      #   identifier.key # => "articles.operations.create"
      #   identifier.namespaced(from: "articles", to: nil).key # => "operations.create"
      #
      # @example Adding a namespace
      #   identifier.key # => "articles.operations.create"
      #   identifier.namespaced(from: nil, to: "admin").key # => "admin.articles.operations.create"
      #
      # @param from [String, nil] the leading namespace(s) to replace
      # @param to [String, nil] the replacement for the leading namespace
      #
      # @return [Dry::System::Identifier] the copy of the identifier
      #
      # @see #initialize
      # @api private
      def namespaced(from:, to:)
        return self if from == to

        separated_to = "#{to}#{KEY_SEPARATOR}" if to

        new_key =
          if from.nil?
            "#{separated_to}#{key}"
          else
            key.sub(
              /^#{Regexp.escape(from.to_s)}#{Regexp.escape(KEY_SEPARATOR)}/,
              separated_to || EMPTY_STRING
            )
          end

        return self if new_key == key

        self.class.new(new_key)
      end

      private

      def segments
        @segments ||= key.split(KEY_SEPARATOR)
      end
    end
  end
end


================================================
FILE: lib/dry/system/importer.rb
================================================
# frozen_string_literal: true

require "dry/system/constants"

module Dry
  module System
    # Default importer implementation
    #
    # This is currently configured by default for every System::Container.
    # Importer objects are responsible for importing components from one
    # container to another. This is used in cases where an application is split
    # into multiple sub-systems.
    #
    # @api private
    class Importer
      # @api private
      class Item
        attr_reader :namespace, :container, :import_keys

        def initialize(namespace:, container:, import_keys:)
          @namespace = namespace
          @container = container
          @import_keys = import_keys
        end
      end

      attr_reader :container

      attr_reader :registry

      # @api private
      def initialize(container)
        @container = container
        @registry = {}
      end

      # @api private
      def register(namespace:, container:, keys: nil)
        registry[namespace_key(namespace)] = Item.new(
          namespace: namespace,
          container: container,
          import_keys: keys
        )
      end

      # @api private
      def [](name)
        registry.fetch(namespace_key(name))
      end

      # @api private
      def key?(name)
        registry.key?(namespace_key(name))
      end
      alias_method :namespace?, :key?

      # @api private
      def finalize!
        registry.each_key { import(_1) }
        self
      end

      # @api private
      def import(namespace, keys: Undefined)
        item = self[namespace]
        keys = Undefined.default(keys, item.import_keys)

        if keys
          import_keys(item.container, namespace, keys_to_import(keys, item))
        else
          import_all(item.container, namespace)
        end

        self
      end

      private

      # Returns nil if given a nil (i.e. root) namespace. Otherwise, converts the namespace to a
      # string.
      #
      # This ensures imported components are found when either symbols or strings to given as the
      # namespace in {Container.import}.
      def namespace_key(namespace)
        return nil if namespace.nil?

        namespace.to_s
      end

      def keys_to_import(keys, item)
        keys
          .then { (arr = item.import_keys) ? _1 & arr : _1 }
          .then { (arr = item.container.exports) ? _1 & arr : _1 }
      end

      def import_keys(other, namespace, keys)
        merge(container, build_merge_container(other, keys), namespace: namespace)
      end

      def import_all(other, namespace)
        merge_container =
          if other.exports
            build_merge_container(other, other.exports)
          else
            build_merge_container(other.finalize!, other.keys)
          end

        merge(container, merge_container, namespace: namespace)
      end

      # Merges `other` into `container`, favoring the container's existing registrations
      def merge(container, other, namespace:)
        container.merge(other, namespace: namespace) { |_key, old_item, new_item|
          old_item || new_item
        }
      end

      def build_merge_container(other, keys)
        keys.each_with_object(Core::Container.new) { |key, ic|
          next unless other.key?(key)

          # Access the other container's items directly so that we can preserve all their
          # options when we merge them with the target container (e.g. if a component in
          # the provider container was registered with a block, we want block registration
          # behavior to be exhibited when later resolving that component from the target
          # container). TODO: Make this part of dry-system's public API.
          item = other._container[key]

          # By default, we "protect" components that were themselves imported into the
          # other container from being implicitly exported; imported components are
          # considered "private" and must be explicitly included in `exports` to be
          # exported.
          next if item.options[:imported] && !other.exports

          if item.callable?
            ic.register(key, **item.options, imported: true, &item.item)
          else
            ic.register(key, item.item, **item.options, imported: true)
          end
        }
      end
    end
  end
end


================================================
FILE: lib/dry/system/indirect_component.rb
================================================
# frozen_string_literal: true

module Dry
  module System
    # An indirect component is a component that cannot be directly from a source file
    # directly managed by the container. It may be component that needs to be loaded
    # indirectly, either via a registration manifest file or an imported container
    #
    # Indirect components are an internal abstraction and, unlike ordinary components, are
    # not exposed to users via component dir configuration hooks.
    #
    # @see Container#load_component
    # @see Container#find_component
    #
    # @api private
    class IndirectComponent
      include Dry::Equalizer(:identifier)

      # @!attribute [r] identifier
      #   @return [String] the component's unique identifier
      attr_reader :identifier

      # @api private
      def initialize(identifier)
        @identifier = identifier
      end

      # Returns false, indicating that the component is not directly loadable from the
      # files managed by the container
      #
      # This is the inverse of {Component#loadable?}
      #
      # @return [FalseClass]
      #
      # @api private
      def loadable?
        false
      end

      # Returns the component's unique key
      #
      # @return [String] the key
      #
      # @see Identifier#key
      #
      # @api private
      def key
        identifier.to_s
      end

      # Returns the root namespace segment of the component's key, as a symbol
      #
      # @see Identifier#root_key
      #
      # @return [Symbol] the root key
      #
      # @api private
      def root_key
        identifier.root_key
      end
    end
  end
end


================================================
FILE: lib/dry/system/loader/autoloading.rb
================================================
# frozen_string_literal: true

module Dry
  module System
    class Loader
      # Component loader for autoloading-enabled applications
      #
      # This behaves like the default loader, except instead of requiring the given path,
      # it loads the respective constant, allowing the autoloader to load the
      # corresponding file per its own configuration.
      #
      # @see Loader
      # @api public
      class Autoloading < Loader
        class << self
          def require!(component)
            constant(component)
            self
          end
        end
      end
    end
  end
end


================================================
FILE: lib/dry/system/loader.rb
================================================
# frozen_string_literal: true

require "dry/system/errors"

module Dry
  module System
    # Default component loader implementation
    #
    # This class is configured by default for every System::Container. You can
    # provide your own and use it in your containers too.
    #
    # @example
    #   class MyLoader < Dry::System::Loader
    #     def call(*args)
    #       constant.build(*args)
    #     end
    #   end
    #
    #   class MyApp < Dry::System::Container
    #     configure do |config|
    #       # ...
    #       config.component_dirs.loader = MyLoader
    #     end
    #   end
    #
    # @api public
    class Loader
      class << self
        # Requires the component's source file
        #
        # @api public
        def require!(component)
          require(component.require_path)
          self
        end

        # Returns an instance of the component
        #
        # Provided optional args are passed to object's constructor
        #
        # @param [Array] args Optional constructor args
        #
        # @return [Object]
        #
        # @api public
        def call(component, *args, **kwargs)
          require!(component)

          constant = self.constant(component)

          if singleton?(constant)
            constant.instance(*args, **kwargs)
          else
            constant.new(*args, **kwargs)
          end
        end

        # Returns the component's class constant
        #
        # @return [Class]
        #
        # @api public
        def constant(component)
          inflector = component.inflector
          const_name = inflector.camelize(component.const_path)
          inflector.constantize(const_name)
        rescue NameError => exception
          # Ensure it's this component's constant, not any other NameError within the component
          if exception.message =~ /#{const_name}( |\n|$)/
            raise ComponentNotLoadableError.new(component, exception)
          else
            raise exception
          end
        end

        private

        def singleton?(constant)
          constant.respond_to?(:instance) && !constant.respond_to?(:new)
        end
      end
    end
  end
end


================================================
FILE: lib/dry/system/magic_comments_parser.rb
================================================
# frozen_string_literal: true

module Dry
  module System
    class MagicCommentsParser
      VALID_LINE_RE = /^(#.*)?$/
      COMMENT_RE = /^#\s+(?<name>[A-Za-z]{1}[A-Za-z0-9_]+):\s+(?<value>.+?)$/

      COERCIONS = {
        "true" => true,
        "false" => false
      }.freeze

      def self.call(file_name)
        {}.tap do |options|
          File.foreach(file_name) do |line|
            break unless line =~ VALID_LINE_RE

            if (comment = line.match(COMMENT_RE))
              options[comment[:name].to_sym] = coerce(comment[:value])
            end
          end
        end
      end

      def self.coerce(value)
        COERCIONS.fetch(value) { value }
      end
    end
  end
end


================================================
FILE: lib/dry/system/manifest_registrar.rb
================================================
# frozen_string_literal: true

require "dry/system/constants"

module Dry
  module System
    # Default manifest registration implementation
    #
    # This is configured by default for every System::Container. The manifest registrar is
    # responsible for loading manifest files that contain code to manually register
    # certain objects with the container.
    #
    # @api private
    class ManifestRegistrar
      # @api private
      attr_reader :container

      # @api private
      attr_reader :config

      # @api private
      def initialize(container)
        @container = container
        @config = container.config
      end

      # @api private
      def finalize!
        ::Dir[registrations_dir.join(RB_GLOB)].each do |file|
          call(Identifier.new(File.basename(file, RB_EXT)))
        end
      end

      # @api private
      def call(component)
        load(root.join(config.registrations_dir, "#{component.root_key}#{RB_EXT}"))
      end

      # @api private
      def file_exists?(component)
        ::File.exist?(::File.join(registrations_dir, "#{component.root_key}#{RB_EXT}"))
      end

      private

      # @api private
      def registrations_dir
        root.join(config.registr
Download .txt
gitextract_5feq0jid/

├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.md
│   │   └── config.yml
│   ├── SUPPORT.md
│   └── workflows/
│       ├── ci-lint.yml
│       ├── ci.yml
│       ├── pr-comments.yml
│       ├── repo-sync-preview.yml
│       └── rubocop.yml
├── .gitignore
├── .rspec
├── .yardopts
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Gemfile
├── Gemfile.devtools
├── LICENSE
├── README.md
├── Rakefile
├── bin/
│   ├── .gitkeep
│   └── console
├── docsite/
│   └── source/
│       ├── component-dirs.html.md
│       ├── container/
│       │   └── hooks.html.md
│       ├── container.html.md
│       ├── dependency-auto-injection.html.md
│       ├── external-provider-sources.html.md
│       ├── index.html.md
│       ├── plugins.html.md
│       ├── providers.html.md
│       ├── settings.html.md
│       └── test-mode.html.md
├── dry-system.gemspec
├── examples/
│   ├── custom_configuration_auto_register/
│   │   ├── Gemfile
│   │   ├── lib/
│   │   │   ├── entities/
│   │   │   │   └── user.rb
│   │   │   └── user_repo.rb
│   │   ├── run.rb
│   │   └── system/
│   │       ├── boot/
│   │       │   └── persistence.rb
│   │       ├── container.rb
│   │       └── import.rb
│   ├── standalone/
│   │   ├── Gemfile
│   │   ├── lib/
│   │   │   ├── empty_service.rb
│   │   │   ├── not_registered.rb
│   │   │   ├── service_with_dependency.rb
│   │   │   └── user_repo.rb
│   │   ├── run.rb
│   │   └── system/
│   │       ├── container.rb
│   │       ├── import.rb
│   │       └── providers/
│   │           └── persistence.rb
│   └── zeitwerk/
│       ├── Gemfile
│       ├── lib/
│       │   ├── service_with_dependency.rb
│       │   └── user_repo.rb
│       ├── run.rb
│       └── system/
│           ├── container.rb
│           └── import.rb
├── lib/
│   ├── dry/
│   │   ├── system/
│   │   │   ├── auto_registrar.rb
│   │   │   ├── component.rb
│   │   │   ├── component_dir.rb
│   │   │   ├── config/
│   │   │   │   ├── component_dir.rb
│   │   │   │   ├── component_dirs.rb
│   │   │   │   ├── namespace.rb
│   │   │   │   └── namespaces.rb
│   │   │   ├── constants.rb
│   │   │   ├── container.rb
│   │   │   ├── errors.rb
│   │   │   ├── identifier.rb
│   │   │   ├── importer.rb
│   │   │   ├── indirect_component.rb
│   │   │   ├── loader/
│   │   │   │   └── autoloading.rb
│   │   │   ├── loader.rb
│   │   │   ├── magic_comments_parser.rb
│   │   │   ├── manifest_registrar.rb
│   │   │   ├── plugins/
│   │   │   │   ├── bootsnap.rb
│   │   │   │   ├── dependency_graph/
│   │   │   │   │   └── strategies.rb
│   │   │   │   ├── dependency_graph.rb
│   │   │   │   ├── env.rb
│   │   │   │   ├── logging.rb
│   │   │   │   ├── monitoring/
│   │   │   │   │   └── proxy.rb
│   │   │   │   ├── monitoring.rb
│   │   │   │   ├── notifications.rb
│   │   │   │   ├── plugin.rb
│   │   │   │   ├── zeitwerk/
│   │   │   │   │   └── compat_inflector.rb
│   │   │   │   └── zeitwerk.rb
│   │   │   ├── plugins.rb
│   │   │   ├── provider/
│   │   │   │   ├── source.rb
│   │   │   │   └── source_dsl.rb
│   │   │   ├── provider.rb
│   │   │   ├── provider_registrar.rb
│   │   │   ├── provider_source_registry.rb
│   │   │   ├── provider_sources/
│   │   │   │   ├── settings/
│   │   │   │   │   ├── config.rb
│   │   │   │   │   └── loader.rb
│   │   │   │   └── settings.rb
│   │   │   ├── provider_sources.rb
│   │   │   ├── stubs.rb
│   │   │   └── version.rb
│   │   └── system.rb
│   └── dry-system.rb
├── repo-sync.yml
├── spec/
│   ├── fixtures/
│   │   ├── app/
│   │   │   ├── lib/
│   │   │   │   ├── ignored_spec_service.rb
│   │   │   │   └── spec_service.rb
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           └── client.rb
│   │   ├── autoloading/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── entities/
│   │   │           │   └── foo_entity.rb
│   │   │           └── foo.rb
│   │   ├── components/
│   │   │   └── test/
│   │   │       ├── bar/
│   │   │       │   ├── abc.rb
│   │   │       │   └── baz.rb
│   │   │       ├── bar.rb
│   │   │       ├── foo.rb
│   │   │       └── no_register.rb
│   │   ├── components_with_errors/
│   │   │   └── test/
│   │   │       └── constant_error.rb
│   │   ├── deprecations/
│   │   │   └── bootable_dirs_config/
│   │   │       └── system/
│   │   │           ├── boot/
│   │   │           │   └── logger.rb
│   │   │           └── custom_boot/
│   │   │               └── logger.rb
│   │   ├── external_components/
│   │   │   ├── alt-components/
│   │   │   │   ├── db.rb
│   │   │   │   └── logger.rb
│   │   │   ├── components/
│   │   │   │   ├── logger.rb
│   │   │   │   ├── mailer.rb
│   │   │   │   └── notifier.rb
│   │   │   └── lib/
│   │   │       └── external_components.rb
│   │   ├── external_components_deprecated/
│   │   │   ├── components/
│   │   │   │   └── logger.rb
│   │   │   └── lib/
│   │   │       └── external_components.rb
│   │   ├── import_test/
│   │   │   ├── config/
│   │   │   │   └── application.yml
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── bar.rb
│   │   │           └── foo.rb
│   │   ├── lazy_loading/
│   │   │   ├── auto_registration_disabled/
│   │   │   │   └── lib/
│   │   │   │       ├── entities/
│   │   │   │       │   └── kitten.rb
│   │   │   │       └── fetch_kitten.rb
│   │   │   └── shared_root_keys/
│   │   │       ├── lib/
│   │   │       │   └── kitten_service/
│   │   │       │       ├── fetch_kitten.rb
│   │   │       │       └── submit_kitten.rb
│   │   │       └── system/
│   │   │           └── providers/
│   │   │               └── kitten_service.rb
│   │   ├── lazytest/
│   │   │   ├── config/
│   │   │   │   └── application.yml
│   │   │   ├── lib/
│   │   │   │   └── test/
│   │   │   │       ├── dep.rb
│   │   │   │       ├── foo.rb
│   │   │   │       ├── models/
│   │   │   │       │   ├── book.rb
│   │   │   │       │   └── user.rb
│   │   │   │       └── models.rb
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           └── bar.rb
│   │   ├── magic_comments/
│   │   │   └── comments.rb
│   │   ├── manifest_registration/
│   │   │   ├── lib/
│   │   │   │   └── test/
│   │   │   │       └── foo.rb
│   │   │   └── system/
│   │   │       └── registrations/
│   │   │           └── foo.rb
│   │   ├── memoize_magic_comments/
│   │   │   └── test/
│   │   │       ├── memoize_false_comment.rb
│   │   │       ├── memoize_no_comment.rb
│   │   │       └── memoize_true_comment.rb
│   │   ├── mixed_namespaces/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── external/
│   │   │           │   └── external_component.rb
│   │   │           └── my_app/
│   │   │               └── app_component.rb
│   │   ├── multiple_namespaced_components/
│   │   │   └── multiple/
│   │   │       └── level/
│   │   │           ├── baz.rb
│   │   │           └── foz.rb
│   │   ├── multiple_provider_dirs/
│   │   │   ├── custom_bootables/
│   │   │   │   └── logger.rb
│   │   │   └── default_bootables/
│   │   │       ├── inflector.rb
│   │   │       └── logger.rb
│   │   ├── namespaced_components/
│   │   │   └── namespaced/
│   │   │       ├── bar.rb
│   │   │       └── foo.rb
│   │   ├── other/
│   │   │   ├── config/
│   │   │   │   └── providers/
│   │   │   │       ├── bar.rb
│   │   │   │       └── hell.rb
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── dep.rb
│   │   │           ├── foo.rb
│   │   │           ├── models/
│   │   │           │   ├── book.rb
│   │   │           │   └── user.rb
│   │   │           └── models.rb
│   │   ├── require_path/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           └── foo.rb
│   │   ├── settings_test/
│   │   │   └── types.rb
│   │   ├── standard_container_with_default_namespace/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── dep.rb
│   │   │           └── example_with_dep.rb
│   │   ├── standard_container_without_default_namespace/
│   │   │   └── lib/
│   │   │       └── test/
│   │   │           ├── dep.rb
│   │   │           └── example_with_dep.rb
│   │   ├── stubbing/
│   │   │   ├── lib/
│   │   │   │   └── test/
│   │   │   │       └── car.rb
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           └── db.rb
│   │   ├── test/
│   │   │   ├── config/
│   │   │   │   ├── application.yml
│   │   │   │   └── subapp.yml
│   │   │   ├── lib/
│   │   │   │   └── test/
│   │   │   │       ├── dep.rb
│   │   │   │       ├── foo.rb
│   │   │   │       ├── models/
│   │   │   │       │   ├── book.rb
│   │   │   │       │   └── user.rb
│   │   │   │       ├── models.rb
│   │   │   │       └── singleton_dep.rb
│   │   │   ├── log/
│   │   │   │   └── .gitkeep
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           ├── bar.rb
│   │   │           ├── client.rb
│   │   │           ├── db.rb
│   │   │           ├── hell.rb
│   │   │           └── logger.rb
│   │   ├── umbrella/
│   │   │   └── system/
│   │   │       └── providers/
│   │   │           └── db.rb
│   │   └── unit/
│   │       ├── component/
│   │       │   ├── component_dir_1/
│   │       │   │   ├── namespace/
│   │       │   │   │   └── nested/
│   │       │   │   │       ├── component_file.rb
│   │       │   │   │       └── component_file_with_auto_register_false.rb
│   │       │   │   └── outside_namespace/
│   │       │   │       └── component_file.rb
│   │       │   └── component_dir_2/
│   │       │       └── namespace/
│   │       │           └── nested/
│   │       │               └── component_file.rb
│   │       └── component_dir/
│   │           └── component_file.rb
│   ├── integration/
│   │   ├── boot_spec.rb
│   │   ├── container/
│   │   │   ├── auto_registration/
│   │   │   │   ├── component_dir_namespaces/
│   │   │   │   │   ├── autoloading_loader_spec.rb
│   │   │   │   │   ├── deep_namespace_paths_spec.rb
│   │   │   │   │   ├── default_loader_spec.rb
│   │   │   │   │   ├── multiple_namespaces_spec.rb
│   │   │   │   │   └── namespaces_as_defaults_spec.rb
│   │   │   │   ├── custom_auto_register_proc_spec.rb
│   │   │   │   ├── custom_instance_proc_spec.rb
│   │   │   │   ├── custom_loader_spec.rb
│   │   │   │   ├── memoize_spec.rb
│   │   │   │   └── mixed_namespaces_spec.rb
│   │   │   ├── auto_registration_spec.rb
│   │   │   ├── autoloading_spec.rb
│   │   │   ├── importing/
│   │   │   │   ├── container_registration_spec.rb
│   │   │   │   ├── exports_spec.rb
│   │   │   │   ├── import_namespaces_spec.rb
│   │   │   │   ├── imported_component_protection_spec.rb
│   │   │   │   └── partial_imports_spec.rb
│   │   │   ├── lazy_loading/
│   │   │   │   ├── auto_registration_disabled_spec.rb
│   │   │   │   ├── bootable_components_spec.rb
│   │   │   │   └── manifest_registration_spec.rb
│   │   │   ├── plugins/
│   │   │   │   ├── bootsnap_spec.rb
│   │   │   │   ├── dependency_graph_spec.rb
│   │   │   │   ├── env_spec.rb
│   │   │   │   ├── logging_spec.rb
│   │   │   │   └── zeitwerk/
│   │   │   │       ├── eager_loading_spec.rb
│   │   │   │       ├── namespaces_spec.rb
│   │   │   │       ├── resolving_components_spec.rb
│   │   │   │       └── user_configured_loader_spec.rb
│   │   │   ├── plugins_spec.rb
│   │   │   └── providers/
│   │   │       ├── conditional_providers_spec.rb
│   │   │       ├── custom_provider_registrar_spec.rb
│   │   │       ├── custom_provider_superclass_spec.rb
│   │   │       ├── multiple_provider_dirs_spec.rb
│   │   │       ├── provider_sources/
│   │   │       │   └── provider_options_spec.rb
│   │   │       ├── registering_components_spec.rb
│   │   │       └── resolving_root_key_spec.rb
│   │   ├── did_you_mean_integration_spec.rb
│   │   ├── external_components_spec.rb
│   │   ├── import_spec.rb
│   │   └── settings_component_spec.rb
│   ├── spec_helper.rb
│   ├── support/
│   │   ├── coverage.rb
│   │   ├── loaded_constants_cleaning.rb
│   │   ├── rspec.rb
│   │   ├── tmp_directory.rb
│   │   ├── warnings.rb
│   │   └── zeitwerk_loader_registry.rb
│   └── unit/
│       ├── auto_registrar_spec.rb
│       ├── component_dir/
│       │   ├── component_for_identifier_key.rb
│       │   └── each_component_spec.rb
│       ├── component_dir_spec.rb
│       ├── component_spec.rb
│       ├── config/
│       │   ├── component_dirs_spec.rb
│       │   └── namespaces_spec.rb
│       ├── container/
│       │   ├── auto_register_spec.rb
│       │   ├── boot_spec.rb
│       │   ├── config/
│       │   │   └── root_spec.rb
│       │   ├── configuration_spec.rb
│       │   ├── decorate_spec.rb
│       │   ├── hooks/
│       │   │   ├── after_hooks_spec.rb
│       │   │   └── load_path_hook_spec.rb
│       │   ├── hooks_spec.rb
│       │   ├── import_spec.rb
│       │   ├── injector_spec.rb
│       │   ├── load_path_spec.rb
│       │   ├── monitor_spec.rb
│       │   └── notifications_spec.rb
│       ├── container_spec.rb
│       ├── errors_spec.rb
│       ├── identifier_spec.rb
│       ├── indirect_component_spec.rb
│       ├── loader/
│       │   └── autoloading_spec.rb
│       ├── loader_spec.rb
│       ├── magic_comments_parser_spec.rb
│       ├── provider/
│       │   └── source_spec.rb
│       └── provider_sources/
│           └── settings/
│               └── loader_spec.rb
└── zizmor.yml
Download .txt
SYMBOL INDEX (707 symbols across 149 files)

FILE: examples/custom_configuration_auto_register/lib/entities/user.rb
  type Entities (line 3) | module Entities
    class User (line 4) | class User

FILE: examples/custom_configuration_auto_register/lib/user_repo.rb
  class UserRepo (line 3) | class UserRepo

FILE: examples/custom_configuration_auto_register/system/container.rb
  class App (line 5) | class App < Dry::System::Container

FILE: examples/standalone/lib/empty_service.rb
  class EmptyService (line 3) | class EmptyService

FILE: examples/standalone/lib/not_registered.rb
  class NotRegistered (line 3) | class NotRegistered

FILE: examples/standalone/lib/service_with_dependency.rb
  class ServiceWithDependency (line 3) | class ServiceWithDependency

FILE: examples/standalone/lib/user_repo.rb
  class UserRepo (line 3) | class UserRepo

FILE: examples/standalone/system/container.rb
  class App (line 7) | class App < Dry::System::Container

FILE: examples/zeitwerk/lib/service_with_dependency.rb
  class ServiceWithDependency (line 3) | class ServiceWithDependency

FILE: examples/zeitwerk/lib/user_repo.rb
  class UserRepo (line 3) | class UserRepo

FILE: examples/zeitwerk/system/container.rb
  class App (line 5) | class App < Dry::System::Container

FILE: lib/dry/system.rb
  type Dry (line 6) | module Dry
    type System (line 7) | module System
      function loader (line 9) | def self.loader
      function register_provider_sources (line 26) | def self.register_provider_sources(path)
      function register_provider_source (line 33) | def self.register_provider_source(name, group:, source: nil, provide...
      function provider_sources (line 56) | def self.provider_sources

FILE: lib/dry/system/auto_registrar.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      class AutoRegistrar (line 15) | class AutoRegistrar
        method initialize (line 18) | def initialize(container)
        method finalize! (line 23) | def finalize!
        method call (line 30) | def call(component_dir)
        method register_component? (line 40) | def register_component?(component)

FILE: lib/dry/system/component.rb
  type Dry (line 8) | module Dry
    type System (line 9) | module System
      class Component (line 15) | class Component
        method initialize (line 40) | def initialize(identifier, file_path:, namespace:, **options)
        method loadable? (line 55) | def loadable?
        method instance (line 63) | def instance(*args, **kwargs)
        method key (line 74) | def key
        method root_key (line 85) | def root_key
        method require_path (line 108) | def require_path
        method const_path (line 138) | def const_path
        method loader (line 149) | def loader
        method inflector (line 154) | def inflector
        method auto_register? (line 159) | def auto_register?
        method memoize? (line 164) | def memoize?
        method path_in_namespace (line 170) | def path_in_namespace
        method callable_option? (line 181) | def callable_option?(value)

FILE: lib/dry/system/component_dir.rb
  type Dry (line 6) | module Dry
    type System (line 7) | module System
      class ComponentDir (line 14) | class ComponentDir
        method initialize (line 26) | def initialize(config:, container:)
        method component_for_key (line 41) | def component_for_key(key)
        method each_component (line 55) | def each_component
        method each_file (line 65) | def each_file
        method files (line 77) | def files(namespace)
        method full_path (line 92) | def full_path
        method component_for_path (line 100) | def component_for_path(path, namespace)
        method find_component_file (line 115) | def find_component_file(identifier, namespace)
        method build_component (line 134) | def build_component(identifier, namespace, file_path)
        method component_options (line 149) | def component_options
        method method_missing (line 158) | def method_missing(name, ...)
        method respond_to_missing? (line 166) | def respond_to_missing?(name, include_all = false)

FILE: lib/dry/system/config/component_dir.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      type Config (line 7) | module Config
        class ComponentDir (line 9) | class ComponentDir
          method initialize (line 201) | def initialize(path)
          method auto_register? (line 208) | def auto_register?
          method method_missing (line 214) | def method_missing(name, ...)
          method respond_to_missing? (line 222) | def respond_to_missing?(name, include_all = false)

FILE: lib/dry/system/config/component_dirs.rb
  type Dry (line 6) | module Dry
    type System (line 7) | module System
      type Config (line 8) | module Config
        class ComponentDirs (line 12) | class ComponentDirs
          method initialize (line 102) | def initialize
          method initialize_copy (line 108) | def initialize_copy(source)
          method dir (line 121) | def dir(path)
          method add (line 160) | def add(path_or_dir)
          method delete (line 181) | def delete(path)
          method paths (line 190) | def paths
          method length (line 199) | def length
          method to_a (line 209) | def to_a
          method each (line 220) | def each(&)
          method path_and_dir (line 248) | def path_and_dir(path_or_dir)
          method apply_defaults_to_dir (line 263) | def apply_defaults_to_dir(dir)
          method method_missing (line 271) | def method_missing(name, ...)
          method respond_to_missing? (line 279) | def respond_to_missing?(name, include_all = false)

FILE: lib/dry/system/config/namespace.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      type Config (line 7) | module Config
        class Namespace (line 25) | class Namespace
          method default_root (line 46) | def self.default_root
          method initialize (line 55) | def initialize(path:, key:, const:)
          method root? (line 64) | def root?
          method path? (line 69) | def path?

FILE: lib/dry/system/config/namespaces.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      type Config (line 7) | module Config
        class Namespaces (line 13) | class Namespaces
          method initialize (line 20) | def initialize
          method initialize_copy (line 25) | def initialize_copy(source)
          method namespace (line 36) | def namespace(path)
          method root (line 47) | def root
          method add (line 97) | def add(path, key: path, const: path)
          method add_root (line 108) | def add_root(key: nil, const: nil)
          method delete (line 121) | def delete(path)
          method delete_root (line 132) | def delete_root
          method paths (line 142) | def paths
          method length (line 151) | def length
          method empty? (line 161) | def empty?
          method to_a (line 174) | def to_a
          method each (line 186) | def each(&)

FILE: lib/dry/system/constants.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System

FILE: lib/dry/system/container.rb
  type Dry (line 9) | module Dry
    type System (line 10) | module System
      class Container (line 54) | class Container
        method configure (line 106) | def configure(finalize_config: true, &)
        method configured! (line 126) | def configured!(finalize_config: true)
        method configured? (line 143) | def configured?
        method import (line 178) | def import(from:, as:, keys: nil)
        method register_provider (line 271) | def register_provider(...)
        method finalized? (line 280) | def finalized?
        method finalize! (line 313) | def finalize!(freeze: true, &)
        method start (line 343) | def start(name)
        method prepare (line 361) | def prepare(name)
        method stop (line 376) | def stop(name)
        method shutdown! (line 382) | def shutdown!
        method add_to_load_path! (line 403) | def add_to_load_path!(*dirs)
        method load_registrations! (line 411) | def load_registrations!(name)
        method injector (line 441) | def injector(**options)
        method require_from_root (line 457) | def require_from_root(*paths)
        method root (line 479) | def root
        method register (line 484) | def register(key, *)
        method resolve (line 493) | def resolve(key)
        method key? (line 515) | def key?(key)
        method component_dirs (line 525) | def component_dirs
        method providers (line 530) | def providers
        method auto_registrar (line 535) | def auto_registrar
        method manifest_registrar (line 540) | def manifest_registrar
        method importer (line 545) | def importer
        method before (line 563) | def before(event, &block)
        method after (line 585) | def after(event, &block)
        method hooks (line 591) | def hooks
        method inherited (line 596) | def inherited(klass)
        method load_component (line 611) | def load_component(key)
        method load_local_component (line 640) | def load_local_component(component)
        method load_imported_component (line 646) | def load_imported_component(identifier, namespace:)
        method find_component (line 654) | def find_component(key)
        method run_hooks (line 666) | def run_hooks(event)

FILE: lib/dry/system/errors.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      function initialize (line 14) | def initialize(dir)
      function initialize (line 23) | def initialize(dir)
      function initialize (line 33) | def initialize(path)
      function initialize (line 45) | def initialize(provider_name)
      function initialize (line 54) | def initialize(name)
      function initialize (line 63) | def initialize(name:, group:, keys:)
      function initialize (line 77) | def initialize(plugin_name)
      function initialize (line 87) | def initialize(plugin, message, gem = nil)
      function initialize (line 98) | def initialize(component, error,

FILE: lib/dry/system/identifier.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      class Identifier (line 14) | class Identifier
        method initialize (line 22) | def initialize(key)
        method root_key (line 42) | def root_key
        method start_with? (line 61) | def start_with?(leading_segments)
        method end_with? (line 82) | def end_with?(trailing_segments)
        method include? (line 103) | def include?(segments)
        method key_with_separator (line 124) | def key_with_separator(separator)
        method namespaced (line 149) | def namespaced(from:, to:)
        method segments (line 171) | def segments

FILE: lib/dry/system/importer.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      class Importer (line 15) | class Importer
        class Item (line 17) | class Item
          method initialize (line 20) | def initialize(namespace:, container:, import_keys:)
        method initialize (line 32) | def initialize(container)
        method register (line 38) | def register(namespace:, container:, keys: nil)
        method [] (line 47) | def [](name)
        method key? (line 52) | def key?(name)
        method finalize! (line 58) | def finalize!
        method import (line 64) | def import(namespace, keys: Undefined)
        method namespace_key (line 84) | def namespace_key(namespace)
        method keys_to_import (line 90) | def keys_to_import(keys, item)
        method import_keys (line 96) | def import_keys(other, namespace, keys)
        method import_all (line 100) | def import_all(other, namespace)
        method merge (line 112) | def merge(container, other, namespace:)
        method build_merge_container (line 118) | def build_merge_container(other, keys)

FILE: lib/dry/system/indirect_component.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      class IndirectComponent (line 16) | class IndirectComponent
        method initialize (line 24) | def initialize(identifier)
        method loadable? (line 36) | def loadable?
        method key (line 47) | def key
        method root_key (line 58) | def root_key

FILE: lib/dry/system/loader.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      class Loader (line 27) | class Loader
        method require! (line 32) | def require!(component)
        method call (line 46) | def call(component, *args, **kwargs)
        method constant (line 63) | def constant(component)
        method singleton? (line 78) | def singleton?(constant)

FILE: lib/dry/system/loader/autoloading.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      class Loader (line 5) | class Loader
        class Autoloading (line 14) | class Autoloading < Loader
          method require! (line 16) | def require!(component)

FILE: lib/dry/system/magic_comments_parser.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      class MagicCommentsParser (line 5) | class MagicCommentsParser
        method call (line 14) | def self.call(file_name)
        method coerce (line 26) | def self.coerce(value)

FILE: lib/dry/system/manifest_registrar.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      class ManifestRegistrar (line 14) | class ManifestRegistrar
        method initialize (line 22) | def initialize(container)
        method finalize! (line 28) | def finalize!
        method call (line 35) | def call(component)
        method file_exists? (line 40) | def file_exists?(component)
        method registrations_dir (line 47) | def registrations_dir
        method root (line 52) | def root

FILE: lib/dry/system/plugins.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type Plugins (line 5) | module Plugins
        function register (line 14) | def self.register(name, plugin, &)
        function registry (line 19) | def self.registry
        function loaded_dependencies (line 24) | def self.loaded_dependencies
        function use (line 37) | def use(name, **options)
        function inherited (line 51) | def inherited(klass)
        function enabled_plugins (line 57) | def enabled_plugins

FILE: lib/dry/system/plugins/bootsnap.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type Plugins (line 5) | module Plugins
        type Bootsnap (line 6) | module Bootsnap
          function extended (line 14) | def self.extended(system)
          function dependencies (line 23) | def self.dependencies
          function setup_bootsnap (line 30) | def setup_bootsnap
          function bootsnap_available? (line 37) | def bootsnap_available?

FILE: lib/dry/system/plugins/dependency_graph.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type Plugins (line 5) | module Plugins
        type DependencyGraph (line 7) | module DependencyGraph
          function extended (line 9) | def self.extended(system)
          function dependencies (line 27) | def self.dependencies
          function injector (line 32) | def injector(**options)
          function register (line 37) | def register(key, contents = nil, options = {}, &)

FILE: lib/dry/system/plugins/dependency_graph/strategies.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type Plugins (line 5) | module Plugins
        type DependencyGraph (line 6) | module DependencyGraph
          class Strategies (line 8) | class Strategies
            class Kwargs (line 12) | class Kwargs < Dry::AutoInject::Strategies::Kwargs
              method define_initialize (line 16) | def define_initialize(klass)
            class Args (line 28) | class Args < Dry::AutoInject::Strategies::Args
              method define_initialize (line 32) | def define_initialize(klass)
            class Hash (line 43) | class Hash < Dry::AutoInject::Strategies::Hash
              method define_initialize (line 47) | def define_initialize(klass)

FILE: lib/dry/system/plugins/env.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type Plugins (line 5) | module Plugins
        class Env (line 7) | class Env < Module
          method initialize (line 13) | def initialize(**options)
          method inferrer (line 18) | def inferrer
          method extended (line 23) | def extended(system)

FILE: lib/dry/system/plugins/logging.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      type Plugins (line 7) | module Plugins
        type Logging (line 8) | module Logging
          function extended (line 10) | def self.extended(system)
          function register_logger (line 37) | def register_logger
          function log_level (line 52) | def log_level
          function log_dir_path (line 57) | def log_dir_path
          function log_file_path (line 62) | def log_file_path
          function log_file_name (line 67) | def log_file_name

FILE: lib/dry/system/plugins/monitoring.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      type Plugins (line 7) | module Plugins
        type Monitoring (line 9) | module Monitoring
          function extended (line 11) | def self.extended(system)
          function dependencies (line 22) | def self.dependencies
          function monitor (line 27) | def monitor(key, **options, &block)

FILE: lib/dry/system/plugins/monitoring/proxy.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      type Plugins (line 7) | module Plugins
        type Monitoring (line 8) | module Monitoring
          class Proxy (line 10) | class Proxy < SimpleDelegator
            method for (line 12) | def self.for(target, key:, methods: [])
            method initialize (line 43) | def initialize(target, notifications)

FILE: lib/dry/system/plugins/notifications.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type Plugins (line 5) | module Plugins
        type Notifications (line 7) | module Notifications
          function extended (line 9) | def self.extended(system)
          function dependencies (line 14) | def self.dependencies
          function register_notifications (line 19) | def register_notifications

FILE: lib/dry/system/plugins/plugin.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type Plugins (line 5) | module Plugins
        class Plugin (line 7) | class Plugin
          method initialize (line 15) | def initialize(name, mod, &block)
          method apply_to (line 22) | def apply_to(system, **options)
          method load_dependencies (line 29) | def load_dependencies(dependencies = mod_dependencies, gem = nil)
          method load_dependency (line 40) | def load_dependency(dependency, gem)
          method stateful? (line 48) | def stateful?
          method mod_dependencies (line 53) | def mod_dependencies

FILE: lib/dry/system/plugins/zeitwerk.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      type Plugins (line 7) | module Plugins
        class Zeitwerk (line 9) | class Zeitwerk < Module
          method dependencies (line 11) | def self.dependencies
          method initialize (line 23) | def initialize(loader: nil, run_setup: true, eager_load: nil, de...
          method extended (line 32) | def extended(system)
          method setup_autoloader (line 46) | def setup_autoloader(system)
          method configure_loader (line 61) | def configure_loader(loader, system)
          method push_component_dirs_to_loader (line 70) | def push_component_dirs_to_loader(system, loader)
          method module_for_namespace (line 83) | def module_for_namespace(namespace, inflector)
          method get_or_define_module (line 95) | def get_or_define_module(parent_mod, name)
          method eager_load? (line 101) | def eager_load?(system)

FILE: lib/dry/system/plugins/zeitwerk/compat_inflector.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type Plugins (line 5) | module Plugins
        class Zeitwerk (line 6) | class Zeitwerk < Module
          class CompatInflector (line 8) | class CompatInflector
            method initialize (line 11) | def initialize(config)
            method camelize (line 15) | def camelize(string, _)

FILE: lib/dry/system/provider.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      class Provider (line 54) | class Provider
        method initialize (line 131) | def initialize(name:, namespace: nil, target_container:, source_cl...
        method prepare (line 157) | def prepare
        method start (line 169) | def start
        method stop (line 181) | def stop
        method prepared? (line 190) | def prepared?
        method started? (line 197) | def started?
        method stopped? (line 204) | def stopped?
        method build_provider_container (line 211) | def build_provider_container
        method run_step (line 228) | def run_step(step_name)
        method step_running? (line 258) | def step_running?
        method apply (line 269) | def apply

FILE: lib/dry/system/provider/source.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      class Provider (line 5) | class Provider
        class Source (line 32) | class Source
          method for (line 40) | def for(name:, group: nil, superclass: nil, &block)
          method inherited (line 58) | def inherited(subclass)
          method to_s (line 72) | def to_s
          method inspect (line 77) | def inspect
          method target (line 125) | def target = target_container
          method initialize (line 128) | def initialize(provider_container:, target_container:, &)
          method inspect (line 141) | def inspect
          method prepare (line 159) | def prepare; end
          method start (line 174) | def start; end
          method stop (line 189) | def stop; end
          method before (line 204) | def before(step_name, &block)
          method after (line 222) | def after(step_name, &block)
          method run_callback (line 228) | def run_callback(hook, step)
          method register (line 244) | def register(...)
          method resolve (line 255) | def resolve(key)
          method run_step_block (line 260) | def run_step_block(step_name)
          method method_missing (line 266) | def method_missing(name, *args, &)
          method respond_to_missing? (line 275) | def respond_to_missing?(name, include_all = false)

FILE: lib/dry/system/provider/source_dsl.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      class Provider (line 5) | class Provider
        class SourceDSL (line 12) | class SourceDSL
          method evaluate (line 13) | def self.evaluate(source_class, &)
          method initialize (line 19) | def initialize(source_class)
          method setting (line 23) | def setting(...)
          method prepare (line 27) | def prepare(&)
          method start (line 31) | def start(&)
          method stop (line 35) | def stop(&)
          method method_missing (line 41) | def method_missing(name, ...)
          method respond_to_missing? (line 49) | def respond_to_missing?(name, include_all = false)

FILE: lib/dry/system/provider_registrar.rb
  type Dry (line 8) | module Dry
    type System (line 9) | module System
      class ProviderRegistrar (line 18) | class ProviderRegistrar
        method initialize (line 34) | def initialize(container)
        method freeze (line 40) | def freeze
        method register_provider (line 49) | def register_provider(name, from: nil, source: nil, if: true, **pr...
        method [] (line 92) | def [](provider_name)
        method key? (line 110) | def key?(provider_name)
        method provider_files (line 127) | def provider_files
        method provider_source_class (line 148) | def provider_source_class = Dry::System::Provider::Source
        method provider_source_options (line 155) | def provider_source_options = {}
        method finalize! (line 158) | def finalize!
        method shutdown (line 176) | def shutdown
        method prepare (line 182) | def prepare(provider_name)
        method start (line 188) | def start(provider_name)
        method stop (line 194) | def stop(provider_name)
        method provider_paths (line 202) | def provider_paths
        method build_provider (line 216) | def build_provider(name, options:, source: nil, &)
        method build_provider_from_source (line 239) | def build_provider_from_source(name, source:, group:, options:, &)
        method with_provider (line 260) | def with_provider(provider_name)
        method load_provider (line 270) | def load_provider(path)
        method require_provider_file (line 278) | def require_provider_file(name)
        method find_provider_file (line 284) | def find_provider_file(name)

FILE: lib/dry/system/provider_source_registry.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      class ProviderSourceRegistry (line 8) | class ProviderSourceRegistry
        class Registration (line 10) | class Registration
          method initialize (line 14) | def initialize(source:, provider_options:)
        method initialize (line 22) | def initialize
        method load_sources (line 26) | def load_sources(path)
        method register (line 32) | def register(name:, group:, source:, provider_options:)
        method register_from_block (line 39) | def register_from_block(name:, group:, provider_options:, &)
        method resolve (line 48) | def resolve(name:, group:)
        method key (line 62) | def key(name, group)

FILE: lib/dry/system/provider_sources/settings.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type ProviderSources (line 5) | module ProviderSources
        type Settings (line 6) | module Settings
          class Source (line 7) | class Source < Dry::System::Provider::Source
            method prepare (line 10) | def prepare
            method start (line 14) | def start
            method settings (line 18) | def settings(&block)

FILE: lib/dry/system/provider_sources/settings/config.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type ProviderSources (line 5) | module ProviderSources
        type Settings (line 7) | module Settings
          function initialize (line 10) | def initialize(errors)
          function setting_errors (line 22) | def setting_errors(errors)
          class Config (line 28) | class Config
            method load (line 30) | def self.load(root:, env:, loader: Loader)
            method method_missing (line 58) | def method_missing(name, ...)
            method respond_to_missing? (line 66) | def respond_to_missing?(name, include_all = false)

FILE: lib/dry/system/provider_sources/settings/loader.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System
      type ProviderSources (line 5) | module ProviderSources
        type Settings (line 6) | module Settings
          class Loader (line 8) | class Loader
            method initialize (line 13) | def initialize(root:, env:, store: ENV)
            method [] (line 19) | def [](key)
            method load_dotenv (line 25) | def load_dotenv(root, env)
            method dotenv_files (line 32) | def dotenv_files(root, env)

FILE: lib/dry/system/stubs.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System
      class Container (line 7) | class Container
        type Stubs (line 9) | module Stubs
          function finalize! (line 14) | def finalize!(**, &)
        method enable_stubs! (line 32) | def self.enable_stubs!

FILE: lib/dry/system/version.rb
  type Dry (line 3) | module Dry
    type System (line 4) | module System

FILE: spec/fixtures/app/lib/ignored_spec_service.rb
  class IgnoredSpecService (line 3) | class IgnoredSpecService

FILE: spec/fixtures/app/lib/spec_service.rb
  class SpecService (line 3) | class SpecService

FILE: spec/fixtures/app/system/providers/client.rb
  type Test (line 4) | module Test
    class Client (line 5) | class Client

FILE: spec/fixtures/autoloading/lib/test/entities/foo_entity.rb
  type Test (line 3) | module Test
    type Entities (line 4) | module Entities
      class FooEntity (line 5) | class FooEntity

FILE: spec/fixtures/autoloading/lib/test/foo.rb
  type Test (line 3) | module Test
    class Foo (line 4) | class Foo
      method call (line 5) | def call

FILE: spec/fixtures/components/test/bar.rb
  type Test (line 3) | module Test
    class Bar (line 4) | class Bar
      method call (line 5) | def self.call

FILE: spec/fixtures/components/test/bar/abc.rb
  type Test (line 3) | module Test
    class Bar (line 4) | class Bar
      class ABC (line 5) | class ABC

FILE: spec/fixtures/components/test/bar/baz.rb
  type Test (line 3) | module Test
    class Bar (line 4) | class Bar
      class Baz (line 5) | class Baz

FILE: spec/fixtures/components/test/foo.rb
  type Test (line 3) | module Test
    class Foo (line 4) | class Foo

FILE: spec/fixtures/components/test/no_register.rb
  type Test (line 4) | module Test
    class NoRegister (line 5) | class NoRegister

FILE: spec/fixtures/components_with_errors/test/constant_error.rb
  class ConstantError (line 3) | class ConstantError

FILE: spec/fixtures/external_components/alt-components/db.rb
  type AltComponents (line 7) | module AltComponents
    class DbConn (line 8) | class DbConn

FILE: spec/fixtures/external_components/alt-components/logger.rb
  type AltComponents (line 7) | module AltComponents
    class Logger (line 8) | class Logger

FILE: spec/fixtures/external_components/components/logger.rb
  type ExternalComponents (line 10) | module ExternalComponents
    class Logger (line 11) | class Logger
      method initialize (line 20) | def initialize(log_level = Logger.default_level)

FILE: spec/fixtures/external_components/components/mailer.rb
  type ExternalComponents (line 7) | module ExternalComponents
    class Mailer (line 8) | class Mailer
      method initialize (line 11) | def initialize(client)

FILE: spec/fixtures/external_components/components/notifier.rb
  type ExternalComponents (line 7) | module ExternalComponents
    class Notifier (line 8) | class Notifier
      method initialize (line 11) | def initialize(monitor)

FILE: spec/fixtures/external_components_deprecated/components/logger.rb
  type ExternalComponents (line 10) | module ExternalComponents
    class Logger (line 11) | class Logger
      method initialize (line 20) | def initialize(log_level = Logger.default_level)

FILE: spec/fixtures/import_test/lib/test/bar.rb
  type Test (line 3) | module Test
    class Bar (line 4) | class Bar

FILE: spec/fixtures/import_test/lib/test/foo.rb
  type Test (line 3) | module Test
    class Foo (line 4) | class Foo

FILE: spec/fixtures/lazy_loading/auto_registration_disabled/lib/entities/kitten.rb
  type Entities (line 4) | module Entities
    class Kitten (line 5) | class Kitten

FILE: spec/fixtures/lazy_loading/auto_registration_disabled/lib/fetch_kitten.rb
  class FetchKitten (line 3) | class FetchKitten

FILE: spec/fixtures/lazy_loading/shared_root_keys/lib/kitten_service/fetch_kitten.rb
  type KittenService (line 3) | module KittenService
    class FetchKitten (line 4) | class FetchKitten

FILE: spec/fixtures/lazy_loading/shared_root_keys/lib/kitten_service/submit_kitten.rb
  type KittenService (line 3) | module KittenService
    class SubmitKitten (line 4) | class SubmitKitten

FILE: spec/fixtures/lazy_loading/shared_root_keys/system/providers/kitten_service.rb
  type KittenService (line 5) | module KittenService
    class Client (line 6) | class Client

FILE: spec/fixtures/lazytest/lib/test/dep.rb
  type Test (line 3) | module Test
    class Dep (line 4) | class Dep

FILE: spec/fixtures/lazytest/lib/test/foo.rb
  type Test (line 3) | module Test
    class Foo (line 4) | class Foo

FILE: spec/fixtures/lazytest/lib/test/models.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models

FILE: spec/fixtures/lazytest/lib/test/models/book.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models
      class Book (line 5) | class Book

FILE: spec/fixtures/lazytest/lib/test/models/user.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models
      class User (line 5) | class User

FILE: spec/fixtures/lazytest/system/providers/bar.rb
  type Test (line 6) | module Test
    type Bar (line 7) | module Bar

FILE: spec/fixtures/magic_comments/comments.rb
  type Test (line 16) | module Test

FILE: spec/fixtures/manifest_registration/lib/test/foo.rb
  type Test (line 3) | module Test
    class Foo (line 4) | class Foo
      method initialize (line 7) | def initialize(name)

FILE: spec/fixtures/memoize_magic_comments/test/memoize_false_comment.rb
  type Test (line 4) | module Test
    class MemoizeFalseComment (line 5) | class MemoizeFalseComment

FILE: spec/fixtures/memoize_magic_comments/test/memoize_no_comment.rb
  type Test (line 3) | module Test
    class MemoizeNoComment (line 4) | class MemoizeNoComment

FILE: spec/fixtures/memoize_magic_comments/test/memoize_true_comment.rb
  type Test (line 4) | module Test
    class MemoizeTrueComment (line 5) | class MemoizeTrueComment

FILE: spec/fixtures/mixed_namespaces/lib/test/external/external_component.rb
  type Test (line 3) | module Test
    type External (line 4) | module External
      class ExternalComponent (line 5) | class ExternalComponent

FILE: spec/fixtures/mixed_namespaces/lib/test/my_app/app_component.rb
  type Test (line 3) | module Test
    type MyApp (line 4) | module MyApp
      class AppComponent (line 5) | class AppComponent

FILE: spec/fixtures/multiple_namespaced_components/multiple/level/baz.rb
  type Multiple (line 3) | module Multiple
    type Level (line 4) | module Level
      class Baz (line 5) | class Baz

FILE: spec/fixtures/multiple_namespaced_components/multiple/level/foz.rb
  type Multiple (line 3) | module Multiple
    type Level (line 4) | module Level
      class Foz (line 5) | class Foz

FILE: spec/fixtures/namespaced_components/namespaced/bar.rb
  type Namespaced (line 3) | module Namespaced
    class Bar (line 4) | class Bar

FILE: spec/fixtures/namespaced_components/namespaced/foo.rb
  type Namespaced (line 3) | module Namespaced
    class Foo (line 4) | class Foo

FILE: spec/fixtures/other/config/providers/bar.rb
  type Test (line 5) | module Test
    type Bar (line 6) | module Bar

FILE: spec/fixtures/other/lib/test/dep.rb
  type Test (line 3) | module Test
    class Dep (line 4) | class Dep

FILE: spec/fixtures/other/lib/test/foo.rb
  type Test (line 3) | module Test
    class Foo (line 4) | class Foo

FILE: spec/fixtures/other/lib/test/models.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models

FILE: spec/fixtures/other/lib/test/models/book.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models
      class Book (line 5) | class Book

FILE: spec/fixtures/other/lib/test/models/user.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models
      class User (line 5) | class User

FILE: spec/fixtures/require_path/lib/test/foo.rb
  type Test (line 3) | module Test
    class Foo (line 4) | class Foo

FILE: spec/fixtures/settings_test/types.rb
  type SettingsTest (line 5) | module SettingsTest
    type Types (line 6) | module Types

FILE: spec/fixtures/standard_container_with_default_namespace/lib/test/dep.rb
  type Test (line 3) | module Test
    class Dep (line 4) | class Dep

FILE: spec/fixtures/standard_container_with_default_namespace/lib/test/example_with_dep.rb
  type Test (line 3) | module Test
    class ExampleWithDep (line 4) | class ExampleWithDep

FILE: spec/fixtures/standard_container_without_default_namespace/lib/test/dep.rb
  type Test (line 3) | module Test
    class Dep (line 4) | class Dep

FILE: spec/fixtures/standard_container_without_default_namespace/lib/test/example_with_dep.rb
  type Test (line 3) | module Test
    class ExampleWithDep (line 4) | class ExampleWithDep

FILE: spec/fixtures/stubbing/lib/test/car.rb
  type Test (line 3) | module Test
    class Car (line 4) | class Car
      method wheels_count (line 5) | def wheels_count

FILE: spec/fixtures/stubbing/system/providers/db.rb
  type Test (line 4) | module Test
    class DB (line 5) | class DB

FILE: spec/fixtures/test/lib/test/dep.rb
  type Test (line 3) | module Test
    class Dep (line 4) | class Dep

FILE: spec/fixtures/test/lib/test/foo.rb
  type Test (line 3) | module Test
    class Foo (line 4) | class Foo

FILE: spec/fixtures/test/lib/test/models.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models

FILE: spec/fixtures/test/lib/test/models/book.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models
      class Book (line 5) | class Book

FILE: spec/fixtures/test/lib/test/models/user.rb
  type Test (line 3) | module Test
    type Models (line 4) | module Models
      class User (line 5) | class User

FILE: spec/fixtures/test/lib/test/singleton_dep.rb
  type Test (line 5) | module Test
    class SingletonDep (line 6) | class SingletonDep

FILE: spec/fixtures/test/system/providers/bar.rb
  type Test (line 5) | module Test
    type Bar (line 6) | module Bar

FILE: spec/fixtures/test/system/providers/logger.rb
  type Test (line 3) | module Test
    class LoggerProvider (line 4) | class LoggerProvider < Dry::System::Provider::Source
      method prepare (line 5) | def prepare
      method start (line 9) | def start

FILE: spec/fixtures/umbrella/system/providers/db.rb
  type Db (line 5) | module Db
    class Repo (line 6) | class Repo

FILE: spec/integration/boot_spec.rb
  type Test (line 10) | module Test
    class Db (line 11) | class Db < OpenStruct
    class Client (line 30) | class Client < OpenStruct
    class Db (line 95) | class Db < OpenStruct
  type Test (line 29) | module Test
    class Db (line 11) | class Db < OpenStruct
    class Client (line 30) | class Client < OpenStruct
    class Db (line 95) | class Db < OpenStruct
  class Test::Container (line 47) | class Test::Container < Dry::System::Container
  class Test::Container (line 64) | class Test::Container < Dry::System::Container
  class Test::Container (line 87) | class Test::Container < Dry::System::Container
  type Test (line 94) | module Test
    class Db (line 11) | class Db < OpenStruct
    class Client (line 30) | class Client < OpenStruct
    class Db (line 95) | class Db < OpenStruct

FILE: spec/integration/container/auto_registration/component_dir_namespaces/autoloading_loader_spec.rb
  type MyNamespace (line 111) | module MyNamespace; end
  type MyNamespace (line 168) | module MyNamespace; end

FILE: spec/integration/container/auto_registration/custom_auto_register_proc_spec.rb
  class Test::Container (line 5) | class Test::Container < Dry::System::Container

FILE: spec/integration/container/auto_registration/custom_loader_spec.rb
  class Test::IdentifierLoader (line 6) | class Test::IdentifierLoader
    method call (line 7) | def self.call(component, *_args)
  class Test::Container (line 12) | class Test::Container < Dry::System::Container

FILE: spec/integration/container/auto_registration/memoize_spec.rb
  class Test::Container (line 12) | class Test::Container < Dry::System::Container
  class Test::Container (line 45) | class Test::Container < Dry::System::Container
  class Test::Container (line 93) | class Test::Container < Dry::System::Container
  class Test::Container (line 112) | class Test::Container < Dry::System::Container
  class Test::Container (line 132) | class Test::Container < Dry::System::Container

FILE: spec/integration/container/auto_registration/mixed_namespaces_spec.rb
  class Test::Container (line 5) | class Test::Container < Dry::System::Container

FILE: spec/integration/container/auto_registration_spec.rb
  type Test (line 8) | module Test
    class Container (line 9) | class Container < Dry::System::Container
    class Container (line 27) | class Container < Dry::System::Container
  type Test (line 26) | module Test
    class Container (line 9) | class Container < Dry::System::Container
    class Container (line 27) | class Container < Dry::System::Container

FILE: spec/integration/container/autoloading_spec.rb
  type Test (line 9) | module Test
    class Container (line 10) | class Container < Dry::System::Container

FILE: spec/integration/container/lazy_loading/auto_registration_disabled_spec.rb
  type Test (line 5) | module Test
    class Container (line 6) | class Container < Dry::System::Container

FILE: spec/integration/container/lazy_loading/bootable_components_spec.rb
  type Test (line 6) | module Test
    class Container (line 7) | class Container < Dry::System::Container
    class AnotherContainer (line 28) | class AnotherContainer < Dry::System::Container
  type Test (line 27) | module Test
    class Container (line 7) | class Container < Dry::System::Container
    class AnotherContainer (line 28) | class AnotherContainer < Dry::System::Container

FILE: spec/integration/container/lazy_loading/manifest_registration_spec.rb
  type Test (line 4) | module Test; end
  function build_container (line 6) | def build_container

FILE: spec/integration/container/plugins/logging_spec.rb
  class Test::Container (line 20) | class Test::Container < Dry::System::Container

FILE: spec/integration/container/plugins_spec.rb
  function dependencies (line 25) | def self.dependencies
  function dependencies (line 58) | def self.dependencies
  function dependencies (line 94) | def self.dependencies
  function dependencies (line 113) | def self.dependencies
  function plugin_enabled? (line 133) | def plugin_enabled?
  function initialize (line 210) | def initialize(options)

FILE: spec/integration/container/providers/custom_provider_registrar_spec.rb
  function for_wrapper (line 8) | def self.for_wrapper(wrapper)
  function initialize (line 18) | def initialize(container, wrapper)
  function target_container (line 23) | def target_container
  function register_provider (line 37) | def self.register_provider(...)
  function start (line 41) | def self.start(...)

FILE: spec/integration/container/providers/custom_provider_superclass_spec.rb
  type Test (line 5) | module Test
    class CustomSource (line 6) | class CustomSource < Dry::System::Provider::Source
      method initialize (line 9) | def initialize(custom_setting:, **options, &)
    class CustomRegistrar (line 21) | class CustomRegistrar < Dry::System::ProviderRegistrar
      method provider_source_class (line 22) | def provider_source_class = Test::CustomSource
      method provider_source_options (line 23) | def provider_source_options = {custom_setting: "hello"}
    class Container (line 32) | class Container < Dry::System::Container
    class OtherSource (line 56) | class OtherSource < Dry::System::Provider::Source
      method initialize (line 59) | def initialize(**options, &block)
  type Test (line 20) | module Test
    class CustomSource (line 6) | class CustomSource < Dry::System::Provider::Source
      method initialize (line 9) | def initialize(custom_setting:, **options, &)
    class CustomRegistrar (line 21) | class CustomRegistrar < Dry::System::ProviderRegistrar
      method provider_source_class (line 22) | def provider_source_class = Test::CustomSource
      method provider_source_options (line 23) | def provider_source_options = {custom_setting: "hello"}
    class Container (line 32) | class Container < Dry::System::Container
    class OtherSource (line 56) | class OtherSource < Dry::System::Provider::Source
      method initialize (line 59) | def initialize(**options, &block)
  type Test (line 31) | module Test
    class CustomSource (line 6) | class CustomSource < Dry::System::Provider::Source
      method initialize (line 9) | def initialize(custom_setting:, **options, &)
    class CustomRegistrar (line 21) | class CustomRegistrar < Dry::System::ProviderRegistrar
      method provider_source_class (line 22) | def provider_source_class = Test::CustomSource
      method provider_source_options (line 23) | def provider_source_options = {custom_setting: "hello"}
    class Container (line 32) | class Container < Dry::System::Container
    class OtherSource (line 56) | class OtherSource < Dry::System::Provider::Source
      method initialize (line 59) | def initialize(**options, &block)
  type Test (line 55) | module Test
    class CustomSource (line 6) | class CustomSource < Dry::System::Provider::Source
      method initialize (line 9) | def initialize(custom_setting:, **options, &)
    class CustomRegistrar (line 21) | class CustomRegistrar < Dry::System::ProviderRegistrar
      method provider_source_class (line 22) | def provider_source_class = Test::CustomSource
      method provider_source_options (line 23) | def provider_source_options = {custom_setting: "hello"}
    class Container (line 32) | class Container < Dry::System::Container
    class OtherSource (line 56) | class OtherSource < Dry::System::Provider::Source
      method initialize (line 59) | def initialize(**options, &block)

FILE: spec/integration/container/providers/multiple_provider_dirs_spec.rb
  type Test (line 5) | module Test
    class Container (line 6) | class Container < Dry::System::Container

FILE: spec/integration/container/providers/registering_components_spec.rb
  type Test (line 5) | module Test
    class Thing (line 6) | class Thing; end

FILE: spec/integration/did_you_mean_integration_spec.rb
  class Test::Container (line 10) | class Test::Container < Dry::System::Container

FILE: spec/integration/external_components_spec.rb
  type Test (line 8) | module Test
    class Container (line 9) | class Container < Dry::System::Container

FILE: spec/integration/import_spec.rb
  type Test (line 7) | module Test
    class Umbrella (line 8) | class Umbrella < Dry::System::Container
    class App (line 15) | class App < Dry::System::Container
  type Test (line 42) | module Test
    class Umbrella (line 8) | class Umbrella < Dry::System::Container
    class App (line 15) | class App < Dry::System::Container
  type Test (line 67) | module Test
    class Umbrella (line 8) | class Umbrella < Dry::System::Container
    class App (line 15) | class App < Dry::System::Container

FILE: spec/spec_helper.rb
  type Types (line 25) | module Types

FILE: spec/support/loaded_constants_cleaning.rb
  type TestCleanableNamespace (line 5) | module TestCleanableNamespace
    function remove_constants (line 6) | def remove_constants

FILE: spec/support/tmp_directory.rb
  type RSpec (line 7) | module RSpec
    type Support (line 8) | module Support
      type TmpDirectory (line 9) | module TmpDirectory
        function with_tmp_directory (line 12) | def with_tmp_directory(&)
        function with_directory (line 16) | def with_directory(dir, &)
        function make_tmp_directory (line 20) | def make_tmp_directory
        function write (line 26) | def write(path, *content)

FILE: spec/support/zeitwerk_loader_registry.rb
  type ZeitwerkLoaderRegistry (line 3) | module ZeitwerkLoaderRegistry
    function new_loader (line 5) | def new_loader
    function clear (line 11) | def clear
    function loaders (line 19) | def loaders

FILE: spec/unit/container/auto_register_spec.rb
  class Test::Container (line 8) | class Test::Container < Dry::System::Container
  class Test::Container (line 29) | class Test::Container < Dry::System::Container
  class Test::Container (line 46) | class Test::Container < Dry::System::Container
  class Test::Container (line 64) | class Test::Container < Dry::System::Container
  class Test::Loader (line 80) | class Test::Loader < Dry::System::Loader
    method call (line 81) | def self.call(component, *args)
  class Test::Container (line 90) | class Test::Container < Dry::System::Container
  class Test::Container (line 109) | class Test::Container < Dry::System::Container

FILE: spec/unit/container/boot_spec.rb
  type Test (line 13) | module Test
    class App (line 14) | class App < Dry::System::Container

FILE: spec/unit/container/config/root_spec.rb
  class Test::Container (line 10) | class Test::Container < Dry::System::Container

FILE: spec/unit/container/configuration_spec.rb
  function hooks_trace (line 25) | def hooks_trace
  function hooks_trace (line 42) | def hooks_trace
  function hooks_trace (line 89) | def hooks_trace
  function hooks_trace (line 106) | def hooks_trace
  function hooks_trace (line 147) | def hooks_trace
  function hooks_trace (line 164) | def hooks_trace

FILE: spec/unit/container/import_spec.rb
  class Test::Other (line 36) | class Test::Other < Dry::System::Container
  class Test::Container (line 43) | class Test::Container < Dry::System::Container
  type Test (line 52) | module Test
  class Test::Foo (line 56) | class Test::Foo

FILE: spec/unit/container/load_path_spec.rb
  class Test::Container (line 7) | class Test::Container < Dry::System::Container

FILE: spec/unit/container/monitor_spec.rb
  function name (line 13) | def self.name
  function say (line 17) | def say(word, lang: nil, &block)
  function other (line 22) | def other; end

FILE: spec/unit/container_spec.rb
  class Test::Container (line 11) | class Test::Container < Dry::System::Container
  type Test (line 18) | module Test
  class Test::Container (line 41) | class Test::Container < Dry::System::Container
  class Test::Container (line 85) | class Test::Container < Dry::System::Container
  class Test::Container (line 99) | class Test::Container < Dry::System::Container
  class Test::Container (line 118) | class Test::Container < Dry::System::Container
  class Test::FalseyContainer (line 162) | class Test::FalseyContainer < Dry::System::Container
  class Test::Container (line 168) | class Test::Container < Dry::System::Container
  class Test::Container (line 194) | class Test::Container < Dry::System::Container
  class Test::Container (line 209) | class Test::Container < Dry::System::Container

FILE: spec/unit/errors_spec.rb
  type Dry (line 5) | module Dry
    type System (line 6) | module System

FILE: spec/unit/loader_spec.rb
  type Test (line 70) | module Test
  type Test (line 90) | module Test
Condensed preview — 262 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (474K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 15,
    "preview": "github: hanami\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "chars": 442,
    "preview": "---\nname: \"\\U0001F41B Bug report\"\nabout: See CONTRIBUTING.md for more information\ntitle: ''\nlabels: bug, help wanted\nass"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 160,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: Community support\n    url: https://discourse.hanamirb.org\n    about"
  },
  {
    "path": ".github/SUPPORT.md",
    "chars": 306,
    "preview": "## Support\n\nIf you need help with any of the Hanami, Dry or Rom libraries, feel free to ask questions on our [discussion"
  },
  {
    "path": ".github/workflows/ci-lint.yml",
    "chars": 672,
    "preview": "name: CI lint\n\non:\n  push:\n    branches: [\"main\", \"release-*\", \"ci/*\"]\n    tags: [\"v*\"]\n    paths:\n      - \".github/**\"\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 3935,
    "preview": "# This file is synced from hanakai-rb/repo-sync\n\nname: CI\nrun-name: ${{ github.ref_type == 'tag' && format('Release {0}'"
  },
  {
    "path": ".github/workflows/pr-comments.yml",
    "chars": 912,
    "preview": "# This file is synced from hanakai-rb/repo-sync\n\n# Downloads comment artifacts from completed workflows and posts them t"
  },
  {
    "path": ".github/workflows/repo-sync-preview.yml",
    "chars": 1471,
    "preview": "name: Repo-sync preview\n\non: # zizmor: ignore[dangerous-triggers]\n  workflow_run:\n    workflows: [\"CI\", \"RuboCop\", \"CI l"
  },
  {
    "path": ".github/workflows/rubocop.yml",
    "chars": 742,
    "preview": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync\n\nname: RuboCop\n\non:\n  push:\n    branches:"
  },
  {
    "path": ".gitignore",
    "chars": 708,
    "preview": "*.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"
  },
  {
    "path": ".rspec",
    "chars": 56,
    "preview": "--color\n--require spec_helper\n--order random\n--warnings\n"
  },
  {
    "path": ".yardopts",
    "chars": 79,
    "preview": "--no-private\n--hide-void-return\n\n--markup-provider=redcarpet\n--markup=markdown\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 52794,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 8490,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe pledge to make our community welcoming, safe, and equitable fo"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1510,
    "preview": "# Issue guidelines\n\n## Reporting bugs\n\nIf you’ve found a bug, please report an issue and describe the expected behavior "
  },
  {
    "path": "Gemfile",
    "chars": 312,
    "preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\neval_gemfile \"Gemfile.devtools\"\n\ngemspec\n\n# Remove verson "
  },
  {
    "path": "Gemfile.devtools",
    "chars": 322,
    "preview": "# 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"
  },
  {
    "path": "LICENSE",
    "chars": 1084,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015-2026 Hanakai team\n\nPermission is hereby granted, free of charge, to any person"
  },
  {
    "path": "README.md",
    "chars": 788,
    "preview": "<!--- This file is synced from hanakai-rb/repo-sync -->\n\n[actions]: https://github.com/dry-rb/dry-system/actions\n[chat]:"
  },
  {
    "path": "Rakefile",
    "chars": 288,
    "preview": "#!/usr/bin/env rake\n# frozen_string_literal: true\n\nrequire \"bundler/gem_tasks\"\n\n$LOAD_PATH.unshift(File.join(File.dirnam"
  },
  {
    "path": "bin/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "bin/console",
    "chars": 166,
    "preview": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nrequire \"bundler/setup\"\n\nbegin\n  require \"pry-byebug\"\n  Pry.start\nres"
  },
  {
    "path": "docsite/source/component-dirs.html.md",
    "chars": 9516,
    "preview": "---\ntitle: Component dirs\nlayout: gem-single\nname: dry-system\n---\n\nThe container auto-registers its components from one "
  },
  {
    "path": "docsite/source/container/hooks.html.md",
    "chars": 2220,
    "preview": "---\ntitle: Hooks\nlayout: gem-single\nname: dry-system\n---\n\nThere are a few lifecycle events that you can hook into if you"
  },
  {
    "path": "docsite/source/container.html.md",
    "chars": 1480,
    "preview": "---\ntitle: Container\nlayout: gem-single\nname: dry-system\nsections:\n  - hooks\n---\n\nThe main API of dry-system is the abst"
  },
  {
    "path": "docsite/source/dependency-auto-injection.html.md",
    "chars": 2376,
    "preview": "---\ntitle: Dependency auto-injection\nlayout: gem-single\nname: dry-system\n---\n\nAfter defining your container, you can use"
  },
  {
    "path": "docsite/source/external-provider-sources.html.md",
    "chars": 3485,
    "preview": "---\ntitle: External provider sources\nlayout: gem-single\nname: dry-system\n---\n\nYou can distribute your own components to "
  },
  {
    "path": "docsite/source/index.html.md",
    "chars": 2877,
    "preview": "---\ntitle: Introduction\nlayout: gem-single\nname: dry-system\ntype: gem\nsections:\n  - container\n  - component-dirs\n  - pro"
  },
  {
    "path": "docsite/source/plugins.html.md",
    "chars": 4710,
    "preview": "---\ntitle: Plugins\nlayout: gem-single\nname: dry-system\n---\n\ndry-system has already built-in plugins that you can enable,"
  },
  {
    "path": "docsite/source/providers.html.md",
    "chars": 2418,
    "preview": "---\ntitle: Providers\nlayout: gem-single\nname: dry-system\n---\n\nSome components can be large, stateful, or requiring speci"
  },
  {
    "path": "docsite/source/settings.html.md",
    "chars": 1839,
    "preview": "---\ntitle: Settings\nlayout: gem-single\nname: dry-system\n---\n\n## Basic usage\n\ndry-system provides a `:settings` provider "
  },
  {
    "path": "docsite/source/test-mode.html.md",
    "chars": 645,
    "preview": "---\ntitle: Test Mode\nlayout: gem-single\nname: dry-system\n---\n\nIn some cases it is useful to stub a component in your tes"
  },
  {
    "path": "dry-system.gemspec",
    "chars": 1671,
    "preview": "# frozen_string_literal: true\n\n# This file is synced from hanakai-rb/repo-sync. To update it, edit repo-sync.yml.\n\nlib ="
  },
  {
    "path": "examples/custom_configuration_auto_register/Gemfile",
    "chars": 121,
    "preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngem \"dry-system\", path: \"../..\"\ngem \"sequel\"\ngem \"sqlite3\""
  },
  {
    "path": "examples/custom_configuration_auto_register/lib/entities/user.rb",
    "chars": 107,
    "preview": "# 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",
    "chars": 85,
    "preview": "# frozen_string_literal: true\n\nclass UserRepo\n  include Import[\"persistence.db\"]\nend\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/run.rb",
    "chars": 413,
    "preview": "# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire_relative \"system/container\"\nrequire_relative \"system/impo"
  },
  {
    "path": "examples/custom_configuration_auto_register/system/boot/persistence.rb",
    "chars": 248,
    "preview": "# frozen_string_literal: true\n\nApp.boot(:persistence) do |persistence|\n  init do\n    require \"sequel\"\n  end\n\n  start do\n"
  },
  {
    "path": "examples/custom_configuration_auto_register/system/container.rb",
    "chars": 313,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nclass App < Dry::System::Container\n  configure do |config|\n    conf"
  },
  {
    "path": "examples/custom_configuration_auto_register/system/import.rb",
    "chars": 83,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"container\"\n\nImport = App.injector\n"
  },
  {
    "path": "examples/standalone/Gemfile",
    "chars": 156,
    "preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngem \"dry-events\"\ngem \"dry-monitor\"\ngem \"dry-system\", path:"
  },
  {
    "path": "examples/standalone/lib/empty_service.rb",
    "chars": 54,
    "preview": "# frozen_string_literal: true\n\nclass EmptyService\nend\n"
  },
  {
    "path": "examples/standalone/lib/not_registered.rb",
    "chars": 55,
    "preview": "# frozen_string_literal: true\n\nclass NotRegistered\nend\n"
  },
  {
    "path": "examples/standalone/lib/service_with_dependency.rb",
    "chars": 93,
    "preview": "# frozen_string_literal: true\n\nclass ServiceWithDependency\n  include Import[\"user_repo\"]\nend\n"
  },
  {
    "path": "examples/standalone/lib/user_repo.rb",
    "chars": 85,
    "preview": "# frozen_string_literal: true\n\nclass UserRepo\n  include Import[\"persistence.db\"]\nend\n"
  },
  {
    "path": "examples/standalone/run.rb",
    "chars": 535,
    "preview": "# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire_relative \"system/container\"\nrequire_relative \"system/impo"
  },
  {
    "path": "examples/standalone/system/container.rb",
    "chars": 428,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/events\"\nrequire \"dry/monitor/notifications\"\nrequire \"dry/system\"\n\nclass App "
  },
  {
    "path": "examples/standalone/system/import.rb",
    "chars": 83,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"container\"\n\nImport = App.injector\n"
  },
  {
    "path": "examples/standalone/system/providers/persistence.rb",
    "chars": 248,
    "preview": "# frozen_string_literal: true\n\nApp.boot(:persistence) do |persistence|\n  init do\n    require \"sequel\"\n  end\n\n  start do\n"
  },
  {
    "path": "examples/zeitwerk/Gemfile",
    "chars": 144,
    "preview": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\ngem \"dry-events\"\ngem \"dry-monitor\"\ngem \"dry-system\", path:"
  },
  {
    "path": "examples/zeitwerk/lib/service_with_dependency.rb",
    "chars": 93,
    "preview": "# frozen_string_literal: true\n\nclass ServiceWithDependency\n  include Import[\"user_repo\"]\nend\n"
  },
  {
    "path": "examples/zeitwerk/lib/user_repo.rb",
    "chars": 50,
    "preview": "# frozen_string_literal: true\n\nclass UserRepo\nend\n"
  },
  {
    "path": "examples/zeitwerk/run.rb",
    "chars": 310,
    "preview": "# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire_relative \"system/container\"\nrequire_relative \"system/impo"
  },
  {
    "path": "examples/zeitwerk/system/container.rb",
    "chars": 260,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nclass App < Dry::System::Container\n  use :env, inferrer: -> { ENV.f"
  },
  {
    "path": "examples/zeitwerk/system/import.rb",
    "chars": 83,
    "preview": "# frozen_string_literal: true\n\nrequire_relative \"container\"\n\nImport = App.injector\n"
  },
  {
    "path": "lib/dry/system/auto_registrar.rb",
    "chars": 1162,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Default auto-registratio"
  },
  {
    "path": "lib/dry/system/component.rb",
    "chars": 5390,
    "preview": "# frozen_string_literal: true\n\nrequire \"pathname\"\nrequire \"dry/inflector\"\nrequire \"dry/system/errors\"\nrequire \"dry/syste"
  },
  {
    "path": "lib/dry/system/component_dir.rb",
    "chars": 4941,
    "preview": "# frozen_string_literal: true\n\nrequire \"pathname\"\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # A con"
  },
  {
    "path": "lib/dry/system/config/component_dir.rb",
    "chars": 6725,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    module Config\n      # @api"
  },
  {
    "path": "lib/dry/system/config/component_dirs.rb",
    "chars": 8201,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\nrequire \"dry/system/errors\"\n\nmodule Dry\n  module System\n  "
  },
  {
    "path": "lib/dry/system/config/namespace.rb",
    "chars": 2232,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    module Config\n      # A co"
  },
  {
    "path": "lib/dry/system/config/namespaces.rb",
    "chars": 6283,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/errors\"\n\nmodule Dry\n  module System\n    module Config\n      # The con"
  },
  {
    "path": "lib/dry/system/constants.rb",
    "chars": 226,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    include Dry::Core::Constants\n\n    RB_EXT = \".rb\"\n    RB_GL"
  },
  {
    "path": "lib/dry/system/container.rb",
    "chars": 21785,
    "preview": "# frozen_string_literal: true\n\nrequire \"pathname\"\n\nrequire \"dry/configurable\"\nrequire \"dry/auto_inject\"\nrequire \"dry/inf"
  },
  {
    "path": "lib/dry/system/errors.rb",
    "chars": 4156,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    # Error raised when import is called on an already finaliz"
  },
  {
    "path": "lib/dry/system/identifier.rb",
    "chars": 5696,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # An identifier representi"
  },
  {
    "path": "lib/dry/system/importer.rb",
    "chars": 4316,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Default importer impleme"
  },
  {
    "path": "lib/dry/system/indirect_component.rb",
    "chars": 1640,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    # An indirect component is a component that cannot be dire"
  },
  {
    "path": "lib/dry/system/loader/autoloading.rb",
    "chars": 607,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    class Loader\n      # Component loader for autoloading-enab"
  },
  {
    "path": "lib/dry/system/loader.rb",
    "chars": 2191,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/errors\"\n\nmodule Dry\n  module System\n    # Default component loader im"
  },
  {
    "path": "lib/dry/system/magic_comments_parser.rb",
    "chars": 708,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    class MagicCommentsParser\n      VALID_LINE_RE = /^(#.*)?$/"
  },
  {
    "path": "lib/dry/system/manifest_registrar.rb",
    "chars": 1334,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Default manifest registr"
  },
  {
    "path": "lib/dry/system/plugins/bootsnap.rb",
    "chars": 1152,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      module Bootsnap\n        DEFAULT_OPTIO"
  },
  {
    "path": "lib/dry/system/plugins/dependency_graph/strategies.rb",
    "chars": 1607,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      module DependencyGraph\n        # @api"
  },
  {
    "path": "lib/dry/system/plugins/dependency_graph.rb",
    "chars": 1306,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # @api public\n      module Dependency"
  },
  {
    "path": "lib/dry/system/plugins/env.rb",
    "chars": 578,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # @api public\n      class Env < Modul"
  },
  {
    "path": "lib/dry/system/plugins/logging.rb",
    "chars": 1635,
    "preview": "# frozen_string_literal: true\n\nrequire \"logger\"\n\nmodule Dry\n  module System\n    module Plugins\n      module Logging\n    "
  },
  {
    "path": "lib/dry/system/plugins/monitoring/proxy.rb",
    "chars": 1391,
    "preview": "# frozen_string_literal: true\n\nrequire \"delegate\"\n\nmodule Dry\n  module System\n    module Plugins\n      module Monitoring"
  },
  {
    "path": "lib/dry/system/plugins/monitoring.rb",
    "chars": 1052,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    module Plugins\n      # @ap"
  },
  {
    "path": "lib/dry/system/plugins/notifications.rb",
    "chars": 590,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # @api public\n      module Notificati"
  },
  {
    "path": "lib/dry/system/plugins/plugin.rb",
    "chars": 1614,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # @api private\n      class Plugin\n   "
  },
  {
    "path": "lib/dry/system/plugins/zeitwerk/compat_inflector.rb",
    "chars": 402,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      class Zeitwerk < Module\n        # @ap"
  },
  {
    "path": "lib/dry/system/plugins/zeitwerk.rb",
    "chars": 3160,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    module Plugins\n      # @ap"
  },
  {
    "path": "lib/dry/system/plugins.rb",
    "chars": 1735,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module Plugins\n      # Register a plugin\n      #\n      # @"
  },
  {
    "path": "lib/dry/system/provider/source.rb",
    "chars": 9204,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    class Provider\n      # A provider's source provides the sp"
  },
  {
    "path": "lib/dry/system/provider/source_dsl.rb",
    "chars": 1253,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    class Provider\n      # Configures a Dry::System::Provider:"
  },
  {
    "path": "lib/dry/system/provider.rb",
    "chars": 8594,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # Providers can prepare an"
  },
  {
    "path": "lib/dry/system/provider_registrar.rb",
    "chars": 7371,
    "preview": "# frozen_string_literal: true\n\nrequire \"pathname\"\n\nrequire \"dry/system/errors\"\nrequire \"dry/system/constants\"\n\nmodule Dr"
  },
  {
    "path": "lib/dry/system/provider_source_registry.rb",
    "chars": 1497,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/constants\"\n\nmodule Dry\n  module System\n    # @api private\n    class P"
  },
  {
    "path": "lib/dry/system/provider_sources/settings/config.rb",
    "chars": 1891,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module ProviderSources\n      # @api private\n      module S"
  },
  {
    "path": "lib/dry/system/provider_sources/settings/loader.rb",
    "chars": 1028,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module ProviderSources\n      module Settings\n        # @ap"
  },
  {
    "path": "lib/dry/system/provider_sources/settings.rb",
    "chars": 1149,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    module ProviderSources\n      module Settings\n        class"
  },
  {
    "path": "lib/dry/system/provider_sources.rb",
    "chars": 162,
    "preview": "# frozen_string_literal: true\n\nrequire \"pathname\"\nrequire \"dry/system\"\n\nDry::System.register_provider_sources Pathname(_"
  },
  {
    "path": "lib/dry/system/stubs.rb",
    "chars": 827,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/core/container/stub\"\n\nmodule Dry\n  module System\n    class Container\n      #"
  },
  {
    "path": "lib/dry/system/version.rb",
    "chars": 90,
    "preview": "# frozen_string_literal: true\n\nmodule Dry\n  module System\n    VERSION = \"1.2.5\"\n  end\nend\n"
  },
  {
    "path": "lib/dry/system.rb",
    "chars": 1642,
    "preview": "# frozen_string_literal: true\n\nrequire \"zeitwerk\"\nrequire \"dry/core\"\n\nmodule Dry\n  module System\n    # @api private\n    "
  },
  {
    "path": "lib/dry-system.rb",
    "chars": 52,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n"
  },
  {
    "path": "repo-sync.yml",
    "chars": 517,
    "preview": "name:\n  gem: dry-system\n  constant: Dry::System\ngithub_org: dry-rb\nci:\n  rubies: [\"3.3.0\"]\ngemspec:\n  authors: [\"Hanakai"
  },
  {
    "path": "spec/fixtures/app/lib/ignored_spec_service.rb",
    "chars": 60,
    "preview": "# frozen_string_literal: true\n\nclass IgnoredSpecService\nend\n"
  },
  {
    "path": "spec/fixtures/app/lib/spec_service.rb",
    "chars": 53,
    "preview": "# frozen_string_literal: true\n\nclass SpecService\nend\n"
  },
  {
    "path": "spec/fixtures/app/system/providers/client.rb",
    "chars": 184,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:client) do\n  module Test\n    class Client\n    end\n  en"
  },
  {
    "path": "spec/fixtures/autoloading/lib/test/entities/foo_entity.rb",
    "chars": 99,
    "preview": "# 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",
    "chars": 116,
    "preview": "# 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",
    "chars": 87,
    "preview": "# 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",
    "chars": 87,
    "preview": "# 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",
    "chars": 127,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class Bar\n    def self.call\n      \"Welcome to my Moe's Tavern!\"\n    end\n  e"
  },
  {
    "path": "spec/fixtures/components/test/foo.rb",
    "chars": 65,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/components/test/no_register.rb",
    "chars": 95,
    "preview": "# 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",
    "chars": 77,
    "preview": "# frozen_string_literal: true\n\nclass ConstantError\n  const_get(:NotHere)\nend\n"
  },
  {
    "path": "spec/fixtures/deprecations/bootable_dirs_config/system/boot/logger.rb",
    "chars": 132,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider :logger do\n  start do\n    register \"logger\", \"my logger"
  },
  {
    "path": "spec/fixtures/deprecations/bootable_dirs_config/system/custom_boot/logger.rb",
    "chars": 132,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider :logger do\n  start do\n    register \"logger\", \"my logger"
  },
  {
    "path": "spec/fixtures/external_components/alt-components/db.rb",
    "chars": 264,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:db, group: :alt) do\n  prepare"
  },
  {
    "path": "spec/fixtures/external_components/alt-components/logger.rb",
    "chars": 267,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:logger, group: :alt) do\n  pre"
  },
  {
    "path": "spec/fixtures/external_components/components/logger.rb",
    "chars": 812,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:logger, group: :external_comp"
  },
  {
    "path": "spec/fixtures/external_components/components/mailer.rb",
    "chars": 446,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:mailer, group: :external_comp"
  },
  {
    "path": "spec/fixtures/external_components/components/notifier.rb",
    "chars": 433,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_source(:notifier, group: :external_co"
  },
  {
    "path": "spec/fixtures/external_components/lib/external_components.rb",
    "chars": 231,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider_sources Pathname(__dir__).join(\"../co"
  },
  {
    "path": "spec/fixtures/external_components_deprecated/components/logger.rb",
    "chars": 799,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_component(:logger, provider: :external_compone"
  },
  {
    "path": "spec/fixtures/external_components_deprecated/lib/external_components.rb",
    "chars": 167,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system\"\n\nDry::System.register_provider(\n  :external_components,\n  path: Path"
  },
  {
    "path": "spec/fixtures/import_test/config/application.yml",
    "chars": 19,
    "preview": "test:\n  foo: 'bar'\n"
  },
  {
    "path": "spec/fixtures/import_test/lib/test/bar.rb",
    "chars": 65,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class Bar\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/import_test/lib/test/foo.rb",
    "chars": 96,
    "preview": "# 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",
    "chars": 95,
    "preview": "# 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",
    "chars": 53,
    "preview": "# frozen_string_literal: true\n\nclass FetchKitten\nend\n"
  },
  {
    "path": "spec/fixtures/lazy_loading/shared_root_keys/lib/kitten_service/fetch_kitten.rb",
    "chars": 82,
    "preview": "# 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",
    "chars": 83,
    "preview": "# 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",
    "chars": 254,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:kitten_service, namespace: true) do\n  prepare do\n    m"
  },
  {
    "path": "spec/fixtures/lazytest/config/application.yml",
    "chars": 19,
    "preview": "test:\n  foo: 'bar'\n"
  },
  {
    "path": "spec/fixtures/lazytest/lib/test/dep.rb",
    "chars": 65,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class Dep\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazytest/lib/test/foo.rb",
    "chars": 96,
    "preview": "# 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",
    "chars": 92,
    "preview": "# 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",
    "chars": 92,
    "preview": "# 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",
    "chars": 69,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/lazytest/system/providers/bar.rb",
    "chars": 312,
    "preview": "# frozen_string_literal: true\n\nTest::Container.namespace(:test) do |container|\n  container.register_provider(:bar) do\n  "
  },
  {
    "path": "spec/fixtures/magic_comments/comments.rb",
    "chars": 505,
    "preview": "#!/usr/bin/env ruby\n# rubocop:disable Layout/CommentIndentation\n# frozen_string_literal: true\n\n# This is a file with a m"
  },
  {
    "path": "spec/fixtures/manifest_registration/lib/test/foo.rb",
    "chars": 140,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n    attr_reader :name\n\n    def initialize(name)\n      @name = nam"
  },
  {
    "path": "spec/fixtures/manifest_registration/system/registrations/foo.rb",
    "chars": 175,
    "preview": "# frozen_string_literal: true\n\nTest::Container.namespace(:foo) do |container|\n  container.register(\"special\") do\n    req"
  },
  {
    "path": "spec/fixtures/memoize_magic_comments/test/memoize_false_comment.rb",
    "chars": 98,
    "preview": "# 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",
    "chars": 78,
    "preview": "# 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",
    "chars": 96,
    "preview": "# 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",
    "chars": 107,
    "preview": "# 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",
    "chars": 99,
    "preview": "# 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",
    "chars": 140,
    "preview": "# frozen_string_literal: true\n\nmodule Multiple\n  module Level\n    class Baz\n      include Test::Container.injector[\"foz\""
  },
  {
    "path": "spec/fixtures/multiple_namespaced_components/multiple/level/foz.rb",
    "chars": 94,
    "preview": "# 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",
    "chars": 137,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:logger) do\n  start do\n    register(:logger, \"custom_lo"
  },
  {
    "path": "spec/fixtures/multiple_provider_dirs/default_bootables/inflector.rb",
    "chars": 147,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:inflector) do\n  start do\n    register(:inflector, \"def"
  },
  {
    "path": "spec/fixtures/multiple_provider_dirs/default_bootables/logger.rb",
    "chars": 138,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:logger) do\n  start do\n    register(:logger, \"default_l"
  },
  {
    "path": "spec/fixtures/namespaced_components/namespaced/bar.rb",
    "chars": 115,
    "preview": "# 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",
    "chars": 71,
    "preview": "# frozen_string_literal: true\n\nmodule Namespaced\n  class Foo\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/config/providers/bar.rb",
    "chars": 264,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:bar, namespace: \"test\") do |_container|\n  prepare do\n "
  },
  {
    "path": "spec/fixtures/other/config/providers/hell.rb",
    "chars": 131,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:heaven) do\n  start do\n    register(\"heaven\", \"string\")"
  },
  {
    "path": "spec/fixtures/other/lib/test/dep.rb",
    "chars": 65,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class Dep\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/other/lib/test/foo.rb",
    "chars": 96,
    "preview": "# 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",
    "chars": 92,
    "preview": "# 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",
    "chars": 92,
    "preview": "# 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",
    "chars": 69,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/require_path/lib/test/foo.rb",
    "chars": 65,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class Foo\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/settings_test/types.rb",
    "chars": 122,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/types\"\n\nmodule SettingsTest\n  module Types\n    include Dry::Types()\n  end\nen"
  },
  {
    "path": "spec/fixtures/standard_container_with_default_namespace/lib/test/dep.rb",
    "chars": 65,
    "preview": "# 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",
    "chars": 102,
    "preview": "# 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",
    "chars": 65,
    "preview": "# 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",
    "chars": 107,
    "preview": "# 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",
    "chars": 102,
    "preview": "# 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",
    "chars": 168,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:db) do\n  module Test\n    class DB\n    end\n  end\n\n  sta"
  },
  {
    "path": "spec/fixtures/test/config/application.yml",
    "chars": 19,
    "preview": "test:\n  foo: 'bar'\n"
  },
  {
    "path": "spec/fixtures/test/config/subapp.yml",
    "chars": 19,
    "preview": "test:\n  bar: 'baz'\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/dep.rb",
    "chars": 65,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class Dep\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/foo.rb",
    "chars": 96,
    "preview": "# 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",
    "chars": 92,
    "preview": "# 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",
    "chars": 92,
    "preview": "# 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",
    "chars": 69,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  module Models\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/test/lib/test/singleton_dep.rb",
    "chars": 117,
    "preview": "# 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",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "spec/fixtures/test/system/providers/bar.rb",
    "chars": 251,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:bar, namespace: \"test\") do\n  prepare do\n    module Tes"
  },
  {
    "path": "spec/fixtures/test/system/providers/client.rb",
    "chars": 232,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:client) do\n  start do\n    target.start :logger\n\n    Te"
  },
  {
    "path": "spec/fixtures/test/system/providers/db.rb",
    "chars": 115,
    "preview": "# 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",
    "chars": 131,
    "preview": "# frozen_string_literal: true\n\nTest::Container.register_provider(:heaven) do\n  start do\n    register(\"heaven\", \"string\")"
  },
  {
    "path": "spec/fixtures/test/system/providers/logger.rb",
    "chars": 332,
    "preview": "# frozen_string_literal: true\n\nmodule Test\n  class LoggerProvider < Dry::System::Provider::Source\n    def prepare\n      "
  },
  {
    "path": "spec/fixtures/umbrella/system/providers/db.rb",
    "chars": 213,
    "preview": "# frozen_string_literal: true\n\nTest::Umbrella.register_provider(:db, namespace: \"db\") do\n  prepare do\n    module Db\n    "
  },
  {
    "path": "spec/fixtures/unit/component/component_dir_1/namespace/nested/component_file.rb",
    "chars": 30,
    "preview": "# frozen_string_literal: true\n"
  },
  {
    "path": "spec/fixtures/unit/component/component_dir_1/namespace/nested/component_file_with_auto_register_false.rb",
    "chars": 53,
    "preview": "# auto_register: false\n# frozen_string_literal: true\n"
  },
  {
    "path": "spec/fixtures/unit/component/component_dir_1/outside_namespace/component_file.rb",
    "chars": 30,
    "preview": "# frozen_string_literal: true\n"
  },
  {
    "path": "spec/fixtures/unit/component/component_dir_2/namespace/nested/component_file.rb",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "spec/fixtures/unit/component_dir/component_file.rb",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "spec/integration/boot_spec.rb",
    "chars": 3321,
    "preview": "# frozen_string_literal: true\n\nrequire \"ostruct\"\n\nRSpec.describe Dry::System::Container, \".register_provider\" do\n  subje"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/autoloading_loader_spec.rb",
    "chars": 5063,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/loader/autoloading\"\nrequire \"zeitwerk\"\n\nRSpec.describe \"Component dir"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/deep_namespace_paths_spec.rb",
    "chars": 1323,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Component dir namespaces / Deep namespace paths\" do\n  let(:container) {\n "
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/default_loader_spec.rb",
    "chars": 9390,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Component dir namespaces / Default loader\" do\n  let(:container) {\n    roo"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/multiple_namespaces_spec.rb",
    "chars": 9072,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Component dir namespaces / Multiple namespaces\" do\n  let(:cleanable_const"
  },
  {
    "path": "spec/integration/container/auto_registration/component_dir_namespaces/namespaces_as_defaults_spec.rb",
    "chars": 2587,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Component dir namespaces / Namespaces as component dir defaults\" do\n  let"
  },
  {
    "path": "spec/integration/container/auto_registration/custom_auto_register_proc_spec.rb",
    "chars": 1040,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Auto-registration / Custom auto_register proc\" do\n  before do\n    class T"
  },
  {
    "path": "spec/integration/container/auto_registration/custom_instance_proc_spec.rb",
    "chars": 1087,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Auto-registration / Custom instance proc\" do\n  before :context do\n    wit"
  },
  {
    "path": "spec/integration/container/auto_registration/custom_loader_spec.rb",
    "chars": 1011,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Auto-registration / Custom loader\" do\n  before do\n    # A loader that sim"
  },
  {
    "path": "spec/integration/container/auto_registration/memoize_spec.rb",
    "chars": 4584,
    "preview": "# frozen_string_literal: true\n\nRSpec::Matchers.define :have_memoized_component do |key|\n  match do |container|\n    conta"
  },
  {
    "path": "spec/integration/container/auto_registration/mixed_namespaces_spec.rb",
    "chars": 1116,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Auto-registration / Components with mixed namespaces\" do\n  before do\n    "
  },
  {
    "path": "spec/integration/container/auto_registration_spec.rb",
    "chars": 1349,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\nrequire \"zeitwerk\"\n\nRSpec.describe \"Auto-registration\" do\n"
  },
  {
    "path": "spec/integration/container/autoloading_spec.rb",
    "chars": 903,
    "preview": "# frozen_string_literal: true\n\nrequire \"dry/system/container\"\nrequire \"dry/system/loader/autoloading\"\nrequire \"zeitwerk\""
  },
  {
    "path": "spec/integration/container/importing/container_registration_spec.rb",
    "chars": 1555,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Container / Imports / Container registration\" do\n  let(:exporting_contain"
  },
  {
    "path": "spec/integration/container/importing/exports_spec.rb",
    "chars": 7044,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Container / Imports / Exports\" do\n  before :context do\n    @dir = make_tm"
  },
  {
    "path": "spec/integration/container/importing/import_namespaces_spec.rb",
    "chars": 2896,
    "preview": "# frozen_string_literal: true\n\nRSpec.describe \"Container / Imports / Import namespaces\" do\n  before :context do\n    @dir"
  }
]

// ... and 62 more files (download for full content)

About this extraction

This page contains the full source code of the dry-rb/dry-system GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 262 files (424.6 KB), approximately 112.3k tokens, and a symbol index with 707 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!