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 [][rubygem] [][actions]
[][forum]
[][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
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
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.