dry-system 0.18.2 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de2d1a6333450270f4b10f90b2dfc7c3436b9885504544224970e3075bae0a90
4
- data.tar.gz: a7506b0e02c0b3511b921d3390562d1ad59f67ffb8970c9573b5fd5f5437bbc8
3
+ metadata.gz: ed86f20c6700f29644fe61cc3bd215f50b93177963eb67076523cbf295f18051
4
+ data.tar.gz: b7ec3d205804cc17033450f7585c809f6a9942ea89fea906799cb02c94e2b64b
5
5
  SHA512:
6
- metadata.gz: ab86a3f981d2bf26468a950f31d90993f096e2c8523fd275762f42ab5728e74e2fbc038b30566eecfaf41f15792bc34fedc2bd8733ffc6c03bb7ede4715b0cc0
7
- data.tar.gz: 4969d94cc2e88c17646f96904e309892c02bbfbc311b08523ca01ff2bd3b08c3c132bf4f0eb641f7a6b6043f424fda0ffdb99ea3ef36ca899ce7a4790b258a43
6
+ metadata.gz: b422ce21011d20c5fedd6eab5cae91c0f03e7ee42d2f7e279b915fbba6826477bfa3393933f4e56417a6f284a2782f56ec184843cae8364a69e1073199d70c05
7
+ data.tar.gz: f2ded5f38dd0fffc72f6262f0c844b430e26f5b411ffd576284c02ec379bbd4b0638c83cae4070d283891f99376b1a6c5700fe453ba938ae4ef17e26cdbf47c5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
+
3
+ ## 0.20.0 2021-09-12
4
+
5
+
6
+ ### Fixed
7
+
8
+ - Fixed dependency graph plugin to work with internal changes introduced in 0.19.0 (@wuarmin in #173)
9
+ - 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)
10
+ - Fixed compatibility of `finalize!` signature provided in `Container::Stubs` (@mpokrywka in #178)
11
+
12
+ ### Changed
13
+
14
+ - [internal] Upgraded to new `setting` API provided in dry-configurable 0.13.0 (@timriley in #179)
15
+
16
+ [Compare v0.19.2...v0.20.0](https://github.com/dry-rb/dry-system/compare/v0.19.2...v0.20.0)
17
+
18
+ ## 0.19.2 2021-08-30
19
+
20
+
21
+ ### Changed
22
+
23
+ - [internal] Improved compatibility with upcoming dry-configurable 0.13.0 release (@timriley in #186)
24
+
25
+ [Compare v0.18.2...v0.19.2](https://github.com/dry-rb/dry-system/compare/v0.18.2...v0.19.2)
26
+
1
27
  ## 0.18.2 2021-08-30
2
28
 
3
29
 
@@ -5,7 +31,108 @@
5
31
 
6
32
  - [internal] Improved compatibility with upcoming dry-configurable 0.13.0 release (@timriley in #187)
7
33
 
8
- [Compare v0.18.1...v0.18.2](https://github.com/dry-rb/dry-system/compare/v0.18.1...v0.18.2)
34
+ [Compare v0.19.1...v0.18.2](https://github.com/dry-rb/dry-system/compare/v0.19.1...v0.18.2)
35
+
36
+ ## 0.19.1 2021-07-11
37
+
38
+
39
+ ### Fixed
40
+
41
+ - Check for registered components (@timriley in #175)
42
+
43
+
44
+ [Compare v0.19.0...v0.19.1](https://github.com/dry-rb/dry-system/compare/v0.19.0...v0.19.1)
45
+
46
+ ## 0.19.0 2021-04-22
47
+
48
+ 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.
49
+
50
+ ### Added
51
+
52
+ - 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.
53
+
54
+ Each added component dir is relative to the container's `root`, and can have its own set of settings configured:
55
+
56
+ ```ruby
57
+ class MyApp::Container < Dry::System::Container
58
+ configure do |config|
59
+ config.root = __dir__
60
+
61
+ # Defaults for all component dirs can be configured separately
62
+ config.component_dirs.auto_register = true # default is already true
63
+
64
+ # Component dirs can be added and configured independently
65
+ config.component_dirs.add "lib" do |dir|
66
+ dir.add_to_load_path = true # defaults to true
67
+ dir.default_namespace = "my_app"
68
+ end
69
+
70
+ # All component dir settings are optional. Component dirs relying on default
71
+ # settings can be added like so:
72
+ config.component_dirs.add "custom_components"
73
+ end
74
+ end
75
+ ```
76
+
77
+ The following settings are available for configuring added `component_dirs`:
78
+
79
+ - `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
80
+ - `add_to_load_path`, a boolean
81
+ - `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)
82
+ - `loader`, a custom replacement for the default `Dry::System::Loader` to be used for the component dir
83
+ - `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
84
+
85
+ _All component dir settings are optional._
86
+
87
+ (@timriley in #155, #157, and #162)
88
+ - A new autoloading-friendly `Dry::System::Loader::Autoloading` is available, which is tested to work with [Zeitwerk](https://github.com/fxn/zeitwerk) 🎉
89
+
90
+ 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.
91
+
92
+ This loader presumes an autoloading system like Zeitwerk has already been enabled and appropriately configured.
93
+
94
+ A recommended setup is as follows:
95
+
96
+ ```ruby
97
+ require "dry/system/container"
98
+ require "dry/system/loader/autoloading"
99
+ require "zeitwerk"
100
+
101
+ class MyApp::Container < Dry::System::Container
102
+ configure do |config|
103
+ config.root = __dir__
104
+
105
+ config.component_dirs.loader = Dry::System::Loader::Autoloading
106
+ config.component_dirs.add_to_load_path = false
107
+
108
+ config.component_dirs.add "lib" do |dir|
109
+ # ...
110
+ end
111
+ end
112
+ end
113
+
114
+ loader = Zeitwerk::Loader.new
115
+ loader.push_dir MyApp::Container.config.root.join("lib").realpath
116
+ loader.setup
117
+ ```
118
+
119
+ (@timriley in #153)
120
+ - [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)
121
+
122
+ ### Changed
123
+
124
+ - Components with `# auto_register: false` magic comments in their source files are now properly ignored when lazy loading (@timriley in #155)
125
+ - `# memoize: true` and `# memoize: false` magic comments at top of component files are now respected (@timriley in #155)
126
+ - [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)
127
+ - [BREAKING] `auto_register` container setting has been removed. Configured directories to be auto-registered by adding `component_dirs` instead (@timriley in #155)
128
+ - [BREAKING] `default_namespace` container setting has been removed. Set it when adding `component_dirs` instead (@timriley in #155)
129
+ - [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)
130
+ - [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)
131
+ - [BREAKING] `Dry::System::Container.auto_register!` has been removed. Configure `component_dirs` instead. (@timriley in #157)
132
+ - [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)
133
+ - [BREAKING] `Dry::System::Container.require_path` has been removed. Provide custom require behavior by configuring your own `loader` (@timriley in #153)
134
+
135
+ [Compare v0.18.1...v0.19.0](https://github.com/dry-rb/dry-system/compare/v0.18.1...v0.19.0)
9
136
 
10
137
  ## 0.18.1 2020-08-26
11
138
 
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2020 dry-rb team
3
+ Copyright (c) 2015-2021 dry-rb team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ <!--- this file is synced from dry-rb/template-gem project -->
1
2
  [gem]: https://rubygems.org/gems/dry-system
2
3
  [actions]: https://github.com/dry-rb/dry-system/actions
3
4
  [codacy]: https://www.codacy.com/gh/dry-rb/dry-system
@@ -7,22 +8,22 @@
7
8
  # dry-system [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
8
9
 
9
10
  [![Gem Version](https://badge.fury.io/rb/dry-system.svg)][gem]
10
- [![CI Status](https://github.com/dry-rb/dry-system/workflows/ci/badge.svg)][actions]
11
+ [![CI Status](https://github.com/dry-rb/dry-system/workflows/CI/badge.svg)][actions]
11
12
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/3a0e30d0ae2542c7ba047ba5f923c0bb)][codacy]
12
13
  [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/3a0e30d0ae2542c7ba047ba5f923c0bb)][codacy]
13
14
  [![Inline docs](http://inch-ci.org/github/dry-rb/dry-system.svg?branch=master)][inchpages]
14
15
 
15
16
  ## Links
16
17
 
17
- * [User documentation](http://dry-rb.org/gems/dry-system)
18
+ * [User documentation](https://dry-rb.org/gems/dry-system)
18
19
  * [API documentation](http://rubydoc.info/gems/dry-system)
19
20
 
20
21
  ## Supported Ruby versions
21
22
 
22
23
  This library officially supports the following Ruby versions:
23
24
 
24
- * MRI >= `2.4`
25
- * jruby >= `9.2`
25
+ * MRI `>= 2.6.0`
26
+ * ~~jruby~~ `>= 9.3` (we are waiting for [2.6 support](https://github.com/jruby/jruby/issues/6161))
26
27
 
27
28
  ## License
28
29
 
data/dry-system.gemspec CHANGED
@@ -1,39 +1,39 @@
1
1
  # frozen_string_literal: true
2
- # this file is managed by dry-rb/devtools project
3
2
 
4
- lib = File.expand_path('lib', __dir__)
3
+ # this file is synced from dry-rb/template-gem project
4
+
5
+ lib = File.expand_path("lib", __dir__)
5
6
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
- require 'dry/system/version'
7
+ require "dry/system/version"
7
8
 
8
9
  Gem::Specification.new do |spec|
9
- spec.name = 'dry-system'
10
+ spec.name = "dry-system"
10
11
  spec.authors = ["Piotr Solnica"]
11
12
  spec.email = ["piotr.solnica@gmail.com"]
12
- spec.license = 'MIT'
13
+ spec.license = "MIT"
13
14
  spec.version = Dry::System::VERSION.dup
14
15
 
15
16
  spec.summary = "Organize your code into reusable components"
16
17
  spec.description = spec.summary
17
- spec.homepage = 'https://dry-rb.org/gems/dry-system'
18
+ spec.homepage = "https://dry-rb.org/gems/dry-system"
18
19
  spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-system.gemspec", "lib/**/*"]
19
- spec.bindir = 'bin'
20
+ spec.bindir = "bin"
20
21
  spec.executables = []
21
- spec.require_paths = ['lib']
22
+ spec.require_paths = ["lib"]
22
23
 
23
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
24
- spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-system/blob/master/CHANGELOG.md'
25
- spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-system'
26
- spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-system/issues'
24
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
25
+ spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-system/blob/master/CHANGELOG.md"
26
+ spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-system"
27
+ spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-system/issues"
27
28
 
28
- spec.required_ruby_version = ">= 2.4.0"
29
+ spec.required_ruby_version = ">= 2.6.0"
29
30
 
30
31
  # to update dependencies edit project.yml
31
32
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
32
33
  spec.add_runtime_dependency "dry-auto_inject", ">= 0.4.0"
33
- spec.add_runtime_dependency "dry-configurable", "~> 0.11", ">= 0.11.1"
34
- spec.add_runtime_dependency "dry-container", "~> 0.7", ">= 0.7.2"
35
- spec.add_runtime_dependency "dry-core", "~> 0.3", ">= 0.3.1"
36
- spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
34
+ spec.add_runtime_dependency "dry-configurable", "~> 0.13", ">= 0.13.0"
35
+ spec.add_runtime_dependency "dry-container", "~> 0.9", ">= 0.9.0"
36
+ spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5"
37
37
  spec.add_runtime_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
38
38
  spec.add_runtime_dependency "dry-struct", "~> 1.0"
39
39
 
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/system/constants"
4
- require "dry/system/magic_comments_parser"
5
- require "dry/system/auto_registrar/configuration"
4
+ require_relative "component"
6
5
 
7
6
  module Dry
8
7
  module System
@@ -17,83 +16,42 @@ module Dry
17
16
  class AutoRegistrar
18
17
  attr_reader :container
19
18
 
20
- attr_reader :config
21
-
22
19
  def initialize(container)
23
20
  @container = container
24
- @config = container.config
25
21
  end
26
22
 
27
23
  # @api private
28
24
  def finalize!
29
- Array(config.auto_register).each { |dir| call(dir) }
25
+ container.component_dirs.each do |component_dir|
26
+ call(component_dir) if component_dir.auto_register?
27
+ end
30
28
  end
31
29
 
32
30
  # @api private
33
- def call(dir)
34
- registration_config = Configuration.new
35
- yield(registration_config) if block_given?
36
- components(dir).each do |component|
37
- next if !component.auto_register? || registration_config.exclude.(component)
31
+ def call(component_dir)
32
+ components(component_dir).each do |component|
33
+ next unless register_component?(component)
38
34
 
39
- container.require_component(component) do
40
- register(component.identifier, memoize: registration_config.memoize) {
41
- registration_config.instance.(component)
42
- }
43
- end
35
+ container.register(component.key, memoize: component.memoize?) { component.instance }
44
36
  end
45
37
  end
46
38
 
47
39
  private
48
40
 
49
- # @api private
50
- def components(dir)
51
- files(dir)
52
- .map { |file_name| [file_name, file_options(file_name)] }
53
- .map { |file_name, options| component(relative_path(dir, file_name), **options) }
54
- .reject { |component| registered?(component.identifier) }
41
+ def components(component_dir)
42
+ files(component_dir.full_path).map { |file_path|
43
+ component_dir.component_for_path(file_path)
44
+ }
55
45
  end
56
46
 
57
- # @api private
58
47
  def files(dir)
59
- components_dir = File.join(root, dir)
60
-
61
- unless ::Dir.exist?(components_dir)
62
- raise ComponentsDirMissing, "Components dir '#{components_dir}' not found"
63
- end
64
-
65
- ::Dir["#{components_dir}/**/#{RB_GLOB}"].sort
66
- end
67
-
68
- # @api private
69
- def relative_path(dir, file_path)
70
- dir_root = root.join(dir.to_s.split("/")[0])
71
- file_path.to_s.sub("#{dir_root}/", "").sub(RB_EXT, EMPTY_STRING)
72
- end
48
+ raise ComponentDirNotFoundError, dir unless Dir.exist?(dir)
73
49
 
74
- # @api private
75
- def file_options(file_name)
76
- MagicCommentsParser.(file_name)
77
- end
78
-
79
- # @api private
80
- def component(path, **options)
81
- container.component(path, **options)
50
+ Dir["#{dir}/**/#{RB_GLOB}"].sort
82
51
  end
83
52
 
84
- # @api private
85
- def root
86
- container.root
87
- end
88
-
89
- # @api private
90
- def registered?(name)
91
- container.registered?(name)
92
- end
93
-
94
- # @api private
95
- def register(*args, &block)
96
- container.register(*args, &block)
53
+ def register_component?(component)
54
+ !container.registered?(component.key) && component.auto_register?
97
55
  end
98
56
  end
99
57
  end
@@ -30,17 +30,28 @@ module Dry
30
30
  @components = ComponentRegistry.new
31
31
  end
32
32
 
33
- # @api private
34
- def bootable?(component)
35
- !boot_file(component).nil?
36
- end
37
-
38
33
  # @api private
39
34
  def register_component(component)
40
35
  components.register(component)
41
36
  self
42
37
  end
43
38
 
39
+ # Returns a bootable component if it can be found or loaded, otherwise nil
40
+ #
41
+ # @return [Dry::System::Components::Bootable, nil]
42
+ # @api private
43
+ def find_component(name)
44
+ name = name.to_sym
45
+
46
+ return components[name] if components.exists?(name)
47
+
48
+ return if finalized?
49
+
50
+ require_boot_file(name)
51
+
52
+ components[name] if components.exists?(name)
53
+ end
54
+
44
55
  # @api private
45
56
  def finalize!
46
57
  boot_files.each do |path|
@@ -54,6 +65,13 @@ module Dry
54
65
  freeze
55
66
  end
56
67
 
68
+ # @!method finalized?
69
+ # Returns true if the booter has been finalized
70
+ #
71
+ # @return [Boolean]
72
+ # @api private
73
+ alias_method :finalized?, :frozen?
74
+
57
75
  # @api private
58
76
  def shutdown
59
77
  components.each do |component|
@@ -115,12 +133,19 @@ module Dry
115
133
 
116
134
  # @api private
117
135
  def boot_dependency(component)
118
- boot_file = boot_file(component)
119
-
120
- start(boot_file.basename(".*").to_s.to_sym) if boot_file
136
+ if (component = find_component(component.root_key))
137
+ start(component)
138
+ end
121
139
  end
122
140
 
123
- # @api private
141
+ # Returns all boot files within the configured paths
142
+ #
143
+ # Searches for files in the order of the configured paths. In the case of multiple
144
+ # identically-named boot files within different paths, the file found first will be
145
+ # returned, and other matching files will be discarded.
146
+ #
147
+ # @return [Array<Pathname>]
148
+ # @api public
124
149
  def boot_files
125
150
  @boot_files ||= paths.each_with_object([[], []]) { |path, (boot_files, loaded)|
126
151
  files = Dir["#{path}/#{RB_GLOB}"].sort
@@ -161,12 +186,6 @@ module Dry
161
186
  self
162
187
  end
163
188
 
164
- def boot_file(name)
165
- name = name.respond_to?(:root_key) ? name.root_key.to_s : name
166
-
167
- find_boot_file(name)
168
- end
169
-
170
189
  def require_boot_file(identifier)
171
190
  boot_file = find_boot_file(identifier)
172
191
 
@@ -2,11 +2,12 @@
2
2
 
3
3
  require "concurrent/map"
4
4
 
5
- require "dry-equalizer"
5
+ require "dry/core/equalizer"
6
6
  require "dry/inflector"
7
7
  require "dry/system/loader"
8
8
  require "dry/system/errors"
9
9
  require "dry/system/constants"
10
+ require_relative "identifier"
10
11
 
11
12
  module Dry
12
13
  module System
@@ -14,106 +15,62 @@ module Dry
14
15
  # They expose an API to query this information and use a configurable
15
16
  # loader object to initialize class instances.
16
17
  #
17
- # Components are created automatically through auto-registration and can be
18
- # accessed through `Container.auto_register!` which yields them.
19
- #
20
18
  # @api public
21
19
  class Component
22
- include Dry::Equalizer(:identifier, :path)
20
+ include Dry::Equalizer(:identifier, :file_path, :options)
23
21
 
24
22
  DEFAULT_OPTIONS = {
25
23
  separator: DEFAULT_SEPARATOR,
26
- namespace: nil,
27
- inflector: Dry::Inflector.new
24
+ inflector: Dry::Inflector.new,
25
+ loader: Loader
28
26
  }.freeze
29
27
 
30
28
  # @!attribute [r] identifier
31
29
  # @return [String] component's unique identifier
32
30
  attr_reader :identifier
33
31
 
34
- # @!attribute [r] path
35
- # @return [String] component's relative path
36
- attr_reader :path
37
-
38
- # @!attribute [r] file
39
- # @return [String] component's file name
40
- attr_reader :file
32
+ # @!attribute [r] file_path
33
+ # @return [String, nil] full path to the component's file, if found
34
+ attr_reader :file_path
41
35
 
42
36
  # @!attribute [r] options
43
37
  # @return [Hash] component's options
44
38
  attr_reader :options
45
39
 
46
- # @!attribute [r] loader
47
- # @return [Object#call] component's loader object
48
- attr_reader :loader
49
-
50
40
  # @api private
51
- def self.new(*args, &block)
52
- cache.fetch_or_store([*args, block].hash) do
53
- name, options = args
54
- options = DEFAULT_OPTIONS.merge(options || EMPTY_HASH)
55
-
56
- ns, sep, inflector = options.values_at(:namespace, :separator, :inflector)
57
- identifier = extract_identifier(name, ns, sep)
58
-
59
- path = name.to_s.gsub(sep, PATH_SEPARATOR)
60
- loader = options.fetch(:loader, Loader).new(path, inflector)
61
-
62
- super(identifier, path, options.merge(loader: loader))
63
- end
64
- end
65
-
66
- # @api private
67
- def self.extract_identifier(name, ns, sep)
68
- name_s = name.to_s
69
- identifier = ns ? remove_namespace_from_name(name_s, ns) : name_s
70
-
71
- identifier.scan(WORD_REGEX).join(sep)
72
- end
73
-
74
- # @api private
75
- def self.remove_namespace_from_name(name, ns)
76
- match_value = name.match(/^(?<remove_namespace>#{ns})(?<separator>\W)(?<identifier>.*)/)
77
-
78
- match_value ? match_value[:identifier] : name
41
+ def self.new(identifier, options = EMPTY_HASH)
42
+ options = DEFAULT_OPTIONS.merge(options)
43
+
44
+ namespace = options.delete(:namespace)
45
+ separator = options.delete(:separator)
46
+
47
+ identifier =
48
+ if identifier.is_a?(Identifier)
49
+ identifier
50
+ else
51
+ Identifier.new(
52
+ identifier,
53
+ namespace: namespace,
54
+ separator: separator
55
+ )
56
+ end
57
+
58
+ super(identifier, **options)
79
59
  end
80
60
 
81
61
  # @api private
82
- def self.cache
83
- @cache ||= Concurrent::Map.new
84
- end
85
-
86
- # @api private
87
- def initialize(identifier, path, options)
62
+ def initialize(identifier, file_path: nil, **options)
88
63
  @identifier = identifier
89
- @path = path
64
+ @file_path = file_path
90
65
  @options = options
91
- @file = "#{path}#{RB_EXT}"
92
- @loader = options.fetch(:loader)
93
- freeze
94
66
  end
95
67
 
96
- # Returns components instance
97
- #
98
- # @example
99
- # class MyApp < Dry::System::Container
100
- # configure do |config|
101
- # config.name = :my_app
102
- # config.root = Pathname('/my/app')
103
- # end
104
- #
105
- # auto_register!('lib/clients') do |component|
106
- # # some custom initialization logic, ie:
107
- # constant = component.loader.constant
108
- # constant.create
109
- # end
110
- # end
68
+ # Returns the component's instance
111
69
  #
112
70
  # @return [Object] component's class instance
113
- #
114
71
  # @api public
115
72
  def instance(*args)
116
- loader.call(*args)
73
+ loader.call(self, *args)
117
74
  end
118
75
  ruby2_keywords(:instance) if respond_to?(:ruby2_keywords, true)
119
76
 
@@ -122,49 +79,54 @@ module Dry
122
79
  false
123
80
  end
124
81
 
125
- # @api private
126
- def file_exists?(paths)
127
- paths.any? { |path| path.join(file).exist? }
82
+ def key
83
+ identifier.to_s
128
84
  end
129
85
 
130
- # @api private
131
- def prepend(name)
132
- self.class.new(
133
- [name, identifier].join(separator), options.merge(loader: loader.class)
134
- )
86
+ def path
87
+ identifier.path
88
+ end
89
+
90
+ def root_key
91
+ identifier.root_key
135
92
  end
136
93
 
94
+ # Returns true if the component has a corresponding file
95
+ #
96
+ # @return [Boolean]
137
97
  # @api private
138
- def namespaced(namespace)
139
- self.class.new(
140
- path, options.merge(loader: loader.class, namespace: namespace)
141
- )
98
+ def file_exists?
99
+ !!file_path
142
100
  end
143
101
 
144
102
  # @api private
145
- def separator
146
- options[:separator]
103
+ def loader
104
+ options[:loader]
147
105
  end
148
106
 
149
107
  # @api private
150
- def namespace
151
- options[:namespace]
108
+ def inflector
109
+ options[:inflector]
152
110
  end
153
111
 
154
112
  # @api private
155
113
  def auto_register?
156
- !!options.fetch(:auto_register) { true }
114
+ callable_option?(options[:auto_register])
157
115
  end
158
116
 
159
117
  # @api private
160
- def root_key
161
- namespaces.first
118
+ def memoize?
119
+ callable_option?(options[:memoize])
162
120
  end
163
121
 
164
122
  private
165
123
 
166
- def namespaces
167
- identifier.split(separator).map(&:to_sym)
124
+ def callable_option?(value)
125
+ if value.respond_to?(:call)
126
+ !!value.call(self)
127
+ else
128
+ !!value
129
+ end
168
130
  end
169
131
  end
170
132
  end