dry-system 0.18.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +93 -0
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/dry-system.gemspec +3 -4
- data/lib/dry/system/auto_registrar.rb +16 -58
- data/lib/dry/system/booter.rb +34 -15
- data/lib/dry/system/component.rb +56 -94
- data/lib/dry/system/component_dir.rb +128 -0
- data/lib/dry/system/config/component_dir.rb +202 -0
- data/lib/dry/system/config/component_dirs.rb +184 -0
- data/lib/dry/system/container.rb +78 -143
- data/lib/dry/system/errors.rb +21 -12
- data/lib/dry/system/identifier.rb +157 -0
- data/lib/dry/system/loader.rb +40 -41
- data/lib/dry/system/loader/autoloading.rb +26 -0
- data/lib/dry/system/version.rb +1 -1
- metadata +17 -27
- data/lib/dry/system/auto_registrar/configuration.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c09b2200301d76a2ac09297583d2a58711db80b43fbe191086bd859f1d3b4fe
|
4
|
+
data.tar.gz: 7f08ad0fb730b2a7281737f799722c30dc649926f36e18e2cd07144637edbb20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 646a9ef47bce754608ae670ebb43aaad911e2c8b67d79a10f7c0f284cd379c4ce4992263fb22f48f42768e180cfdb6e9f1a3df8bb590245a9a29579858862000
|
7
|
+
data.tar.gz: 293fddcf0085814fc9628ee77ad6360d04ae076fb8b623117a1a336aceb39be1d5c1a8a44c92f10b7e48ca53e4939284ae91b8e6ed2a3514039f65c15d7d5d54
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,96 @@
|
|
1
|
+
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
|
+
|
3
|
+
## 0.19.0 2021-04-22
|
4
|
+
|
5
|
+
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.
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- 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.
|
10
|
+
|
11
|
+
Each added component dir is relative to the container's `root`, and can have its own set of settings configured:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
class MyApp::Container < Dry::System::Container
|
15
|
+
configure do |config|
|
16
|
+
config.root = __dir__
|
17
|
+
|
18
|
+
# Defaults for all component dirs can be configured separately
|
19
|
+
config.component_dirs.auto_register = true # default is already true
|
20
|
+
|
21
|
+
# Component dirs can be added and configured independently
|
22
|
+
config.component_dirs.add "lib" do |dir|
|
23
|
+
dir.add_to_load_path = true # defaults to true
|
24
|
+
dir.default_namespace = "my_app"
|
25
|
+
end
|
26
|
+
|
27
|
+
# All component dir settings are optional. Component dirs relying on default
|
28
|
+
# settings can be added like so:
|
29
|
+
config.component_dirs.add "custom_components"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
The following settings are available for configuring added `component_dirs`:
|
35
|
+
|
36
|
+
- `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
|
37
|
+
- `add_to_load_path`, a boolean
|
38
|
+
- `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)
|
39
|
+
- `loader`, a custom replacement for the default `Dry::System::Loader` to be used for the component dir
|
40
|
+
- `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
|
41
|
+
|
42
|
+
_All component dir settings are optional._
|
43
|
+
|
44
|
+
(@timriley in #155, #157, and #162)
|
45
|
+
- A new autoloading-friendly `Dry::System::Loader::Autoloading` is available, which is tested to work with [Zeitwerk](https://github.com/fxn/zeitwerk) 🎉
|
46
|
+
|
47
|
+
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.
|
48
|
+
|
49
|
+
This loader presumes an autoloading system like Zeitwerk has already been enabled and appropriately configured.
|
50
|
+
|
51
|
+
A recommended setup is as follows:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
require "dry/system/container"
|
55
|
+
require "dry/system/loader/autoloading"
|
56
|
+
require "zeitwerk"
|
57
|
+
|
58
|
+
class MyApp::Container < Dry::System::Container
|
59
|
+
configure do |config|
|
60
|
+
config.root = __dir__
|
61
|
+
|
62
|
+
config.component_dirs.loader = Dry::System::Loader::Autoloading
|
63
|
+
config.component_dirs.add_to_load_path = false
|
64
|
+
|
65
|
+
config.component_dirs.add "lib" do |dir|
|
66
|
+
# ...
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
loader = Zeitwerk::Loader.new
|
72
|
+
loader.push_dir MyApp::Container.config.root.join("lib").realpath
|
73
|
+
loader.setup
|
74
|
+
```
|
75
|
+
|
76
|
+
(@timriley in #153)
|
77
|
+
- [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)
|
78
|
+
|
79
|
+
### Changed
|
80
|
+
|
81
|
+
- Components with `# auto_register: false` magic comments in their source files are now properly ignored when lazy loading (@timriley in #155)
|
82
|
+
- `# memoize: true` and `# memoize: false` magic comments at top of component files are now respected (@timriley in #155)
|
83
|
+
- [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)
|
84
|
+
- [BREAKING] `auto_register` container setting has been removed. Configured directories to be auto-registered by adding `component_dirs` instead (@timriley in #155)
|
85
|
+
- [BREAKING] `default_namespace` container setting has been removed. Set it when adding `component_dirs` instead (@timriley in #155)
|
86
|
+
- [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)
|
87
|
+
- [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)
|
88
|
+
- [BREAKING] `Dry::System::Container.auto_register!` has been removed. Configure `component_dirs` instead. (@timriley in #157)
|
89
|
+
- [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)
|
90
|
+
- [BREAKING] `Dry::System::Container.require_path` has been removed. Provide custom require behavior by configuring your own `loader` (@timriley in #153)
|
91
|
+
|
92
|
+
[Compare v0.18.1...v0.19.0](https://github.com/dry-rb/dry-system/compare/v0.18.1...v0.19.0)
|
93
|
+
|
1
94
|
## 0.18.1 2020-08-26
|
2
95
|
|
3
96
|
|
data/LICENSE
CHANGED
data/README.md
CHANGED
data/dry-system.gemspec
CHANGED
@@ -25,15 +25,14 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-system'
|
26
26
|
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-system/issues'
|
27
27
|
|
28
|
-
spec.required_ruby_version = ">= 2.
|
28
|
+
spec.required_ruby_version = ">= 2.5.0"
|
29
29
|
|
30
30
|
# to update dependencies edit project.yml
|
31
31
|
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
32
32
|
spec.add_runtime_dependency "dry-auto_inject", ">= 0.4.0"
|
33
|
-
spec.add_runtime_dependency "dry-configurable", "~> 0.
|
33
|
+
spec.add_runtime_dependency "dry-configurable", "~> 0.12", ">= 0.12.1"
|
34
34
|
spec.add_runtime_dependency "dry-container", "~> 0.7", ">= 0.7.2"
|
35
|
-
spec.add_runtime_dependency "dry-core", "~> 0.
|
36
|
-
spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
|
35
|
+
spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5"
|
37
36
|
spec.add_runtime_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
|
38
37
|
spec.add_runtime_dependency "dry-struct", "~> 1.0"
|
39
38
|
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "dry/system/constants"
|
4
|
-
|
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
|
-
|
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(
|
34
|
-
|
35
|
-
|
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.
|
40
|
-
register(component.identifier, memoize: registration_config.memoize) {
|
41
|
-
registration_config.instance.(component)
|
42
|
-
}
|
43
|
-
end
|
35
|
+
container.register(component.identifier, memoize: component.memoize?) { component.instance }
|
44
36
|
end
|
45
37
|
end
|
46
38
|
|
47
39
|
private
|
48
40
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
85
|
-
|
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) && component.auto_register?
|
97
55
|
end
|
98
56
|
end
|
99
57
|
end
|
data/lib/dry/system/booter.rb
CHANGED
@@ -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
|
-
|
119
|
-
|
120
|
-
|
136
|
+
if (component = find_component(component.root_key))
|
137
|
+
start(component)
|
138
|
+
end
|
121
139
|
end
|
122
140
|
|
123
|
-
#
|
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
|
|
data/lib/dry/system/component.rb
CHANGED
@@ -2,11 +2,12 @@
|
|
2
2
|
|
3
3
|
require "concurrent/map"
|
4
4
|
|
5
|
-
require "dry
|
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, :
|
20
|
+
include Dry::Equalizer(:identifier, :file_path, :options)
|
23
21
|
|
24
22
|
DEFAULT_OPTIONS = {
|
25
23
|
separator: DEFAULT_SEPARATOR,
|
26
|
-
|
27
|
-
|
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]
|
35
|
-
# @return [String] component's
|
36
|
-
attr_reader :
|
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(
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
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
|
-
@
|
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
|
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
|
-
|
126
|
-
|
127
|
-
paths.any? { |path| path.join(file).exist? }
|
82
|
+
def key
|
83
|
+
identifier.to_s
|
128
84
|
end
|
129
85
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
139
|
-
|
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
|
146
|
-
options[:
|
103
|
+
def loader
|
104
|
+
options[:loader]
|
147
105
|
end
|
148
106
|
|
149
107
|
# @api private
|
150
|
-
def
|
151
|
-
options[:
|
108
|
+
def inflector
|
109
|
+
options[:inflector]
|
152
110
|
end
|
153
111
|
|
154
112
|
# @api private
|
155
113
|
def auto_register?
|
156
|
-
|
114
|
+
callable_option?(options[:auto_register])
|
157
115
|
end
|
158
116
|
|
159
117
|
# @api private
|
160
|
-
def
|
161
|
-
|
118
|
+
def memoize?
|
119
|
+
callable_option?(options[:memoize])
|
162
120
|
end
|
163
121
|
|
164
122
|
private
|
165
123
|
|
166
|
-
def
|
167
|
-
|
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
|