dry-system 0.18.2 → 0.20.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 +128 -1
- data/LICENSE +1 -1
- data/README.md +5 -4
- data/dry-system.gemspec +17 -17
- 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 +91 -156
- data/lib/dry/system/errors.rb +21 -12
- data/lib/dry/system/identifier.rb +158 -0
- data/lib/dry/system/loader/autoloading.rb +26 -0
- data/lib/dry/system/loader.rb +41 -42
- data/lib/dry/system/plugins/bootsnap.rb +1 -1
- data/lib/dry/system/plugins/dependency_graph.rb +4 -4
- data/lib/dry/system/plugins/env.rb +1 -1
- data/lib/dry/system/plugins/logging.rb +7 -3
- data/lib/dry/system/stubs.rb +1 -1
- data/lib/dry/system/version.rb +1 -1
- metadata +20 -30
- data/lib/dry/system/auto_registrar/configuration.rb +0 -43
data/lib/dry/system/container.rb
CHANGED
@@ -7,11 +7,11 @@ require "dry-configurable"
|
|
7
7
|
require "dry-container"
|
8
8
|
require "dry/inflector"
|
9
9
|
|
10
|
+
require "dry/core/constants"
|
10
11
|
require "dry/core/deprecations"
|
11
12
|
|
12
13
|
require "dry/system"
|
13
14
|
require "dry/system/errors"
|
14
|
-
require "dry/system/loader"
|
15
15
|
require "dry/system/booter"
|
16
16
|
require "dry/system/auto_registrar"
|
17
17
|
require "dry/system/manual_registrar"
|
@@ -20,6 +20,9 @@ require "dry/system/component"
|
|
20
20
|
require "dry/system/constants"
|
21
21
|
require "dry/system/plugins"
|
22
22
|
|
23
|
+
require_relative "component_dir"
|
24
|
+
require_relative "config/component_dirs"
|
25
|
+
|
23
26
|
module Dry
|
24
27
|
module System
|
25
28
|
# Abstract container class to inherit from
|
@@ -61,7 +64,7 @@ module Dry
|
|
61
64
|
# end
|
62
65
|
#
|
63
66
|
# # this will configure $LOAD_PATH to include your `lib` dir
|
64
|
-
#
|
67
|
+
# add_dirs_to_load_paths!('lib')
|
65
68
|
# end
|
66
69
|
#
|
67
70
|
# @api public
|
@@ -71,19 +74,17 @@ module Dry
|
|
71
74
|
extend Dry::System::Plugins
|
72
75
|
|
73
76
|
setting :name
|
74
|
-
setting :
|
75
|
-
setting
|
76
|
-
setting :
|
77
|
-
setting :
|
78
|
-
setting :
|
79
|
-
setting :
|
80
|
-
setting :
|
81
|
-
setting :
|
82
|
-
setting :
|
83
|
-
setting :
|
84
|
-
setting :
|
85
|
-
setting :importer, Dry::System::Importer
|
86
|
-
setting(:components, {}, reader: true, &:dup)
|
77
|
+
setting :root, default: Pathname.pwd.freeze, constructor: -> path { Pathname(path) }
|
78
|
+
setting :system_dir, default: "system"
|
79
|
+
setting :bootable_dirs, default: ["system/boot"]
|
80
|
+
setting :registrations_dir, default: "container"
|
81
|
+
setting :component_dirs, default: Config::ComponentDirs.new, cloneable: true
|
82
|
+
setting :inflector, default: Dry::Inflector.new
|
83
|
+
setting :booter, default: Dry::System::Booter
|
84
|
+
setting :auto_registrar, default: Dry::System::AutoRegistrar
|
85
|
+
setting :manual_registrar, default: Dry::System::ManualRegistrar
|
86
|
+
setting :importer, default: Dry::System::Importer
|
87
|
+
setting :components, default: {}, reader: true, constructor: :dup.to_proc
|
87
88
|
|
88
89
|
class << self
|
89
90
|
def strategies(value = nil)
|
@@ -101,13 +102,12 @@ module Dry
|
|
101
102
|
# @see https://dry-rb.org/gems/dry-configurable
|
102
103
|
#
|
103
104
|
# @api public
|
104
|
-
def setting(name,
|
105
|
-
super(name,
|
105
|
+
def setting(name, default = Dry::Core::Constants::Undefined, **options, &block)
|
106
|
+
super(name, default, **options, &block)
|
106
107
|
# TODO: dry-configurable needs a public API for this
|
107
108
|
config._settings << _settings[name]
|
108
109
|
self
|
109
110
|
end
|
110
|
-
ruby2_keywords(:setting) if respond_to?(:ruby2_keywords, true)
|
111
111
|
|
112
112
|
# Configures the container
|
113
113
|
#
|
@@ -126,7 +126,6 @@ module Dry
|
|
126
126
|
def configure(&block)
|
127
127
|
hooks[:before_configure].each { |hook| instance_eval(&hook) }
|
128
128
|
super(&block)
|
129
|
-
load_paths!(config.system_dir)
|
130
129
|
hooks[:after_configure].each { |hook| instance_eval(&hook) }
|
131
130
|
self
|
132
131
|
end
|
@@ -385,7 +384,7 @@ module Dry
|
|
385
384
|
self
|
386
385
|
end
|
387
386
|
|
388
|
-
#
|
387
|
+
# Adds the directories (relative to the container's root) to the Ruby load path
|
389
388
|
#
|
390
389
|
# @example
|
391
390
|
# class MyApp < Dry::System::Container
|
@@ -393,7 +392,7 @@ module Dry
|
|
393
392
|
# # ...
|
394
393
|
# end
|
395
394
|
#
|
396
|
-
#
|
395
|
+
# add_to_load_path!('lib')
|
397
396
|
# end
|
398
397
|
#
|
399
398
|
# @param [Array<String>] dirs
|
@@ -401,12 +400,9 @@ module Dry
|
|
401
400
|
# @return [self]
|
402
401
|
#
|
403
402
|
# @api public
|
404
|
-
def
|
405
|
-
dirs.map(&root.method(:join)).each do |path|
|
406
|
-
|
407
|
-
|
408
|
-
load_paths << path
|
409
|
-
$LOAD_PATH.unshift(path.to_s)
|
403
|
+
def add_to_load_path!(*dirs)
|
404
|
+
dirs.reverse.map(&root.method(:join)).each do |path|
|
405
|
+
$LOAD_PATH.prepend(path.to_s) unless $LOAD_PATH.include?(path.to_s)
|
410
406
|
end
|
411
407
|
self
|
412
408
|
end
|
@@ -417,47 +413,6 @@ module Dry
|
|
417
413
|
self
|
418
414
|
end
|
419
415
|
|
420
|
-
# Auto-registers components from the provided directory
|
421
|
-
#
|
422
|
-
# Typically you want to configure auto_register directories, and it will
|
423
|
-
# work automatically. Use this method in cases where you want to have an
|
424
|
-
# explicit way where some components are auto-registered, or if you want
|
425
|
-
# to exclude some components from being auto-registered
|
426
|
-
#
|
427
|
-
# @example
|
428
|
-
# class MyApp < Dry::System::Container
|
429
|
-
# configure do |config|
|
430
|
-
# # ...
|
431
|
-
# end
|
432
|
-
#
|
433
|
-
# # with a dir
|
434
|
-
# auto_register!('lib/core')
|
435
|
-
#
|
436
|
-
# # with a dir and a custom registration block
|
437
|
-
# auto_register!('lib/core') do |config|
|
438
|
-
# config.instance do |component|
|
439
|
-
# # custom way of initializing a component
|
440
|
-
# end
|
441
|
-
#
|
442
|
-
# config.exclude do |component|
|
443
|
-
# # return true to exclude component from auto-registration
|
444
|
-
# end
|
445
|
-
# end
|
446
|
-
# end
|
447
|
-
#
|
448
|
-
# @param [String] dir The dir name relative to the root dir
|
449
|
-
#
|
450
|
-
# @yield AutoRegistrar::Configuration
|
451
|
-
# @see AutoRegistrar::Configuration
|
452
|
-
#
|
453
|
-
# @return [self]
|
454
|
-
#
|
455
|
-
# @api public
|
456
|
-
def auto_register!(dir, &block)
|
457
|
-
auto_registrar.(dir, &block)
|
458
|
-
self
|
459
|
-
end
|
460
|
-
|
461
416
|
# Builds injector for this container
|
462
417
|
#
|
463
418
|
# An injector is a useful mixin which injects dependencies into
|
@@ -526,8 +481,8 @@ module Dry
|
|
526
481
|
end
|
527
482
|
|
528
483
|
# @api public
|
529
|
-
def resolve(key
|
530
|
-
load_component(key
|
484
|
+
def resolve(key)
|
485
|
+
load_component(key) unless finalized?
|
531
486
|
|
532
487
|
super
|
533
488
|
end
|
@@ -558,8 +513,8 @@ module Dry
|
|
558
513
|
end
|
559
514
|
|
560
515
|
# @api private
|
561
|
-
def
|
562
|
-
|
516
|
+
def component_dirs
|
517
|
+
config.component_dirs.to_a.map { |dir| ComponentDir.new(config: dir, container: self) }
|
563
518
|
end
|
564
519
|
|
565
520
|
# @api private
|
@@ -595,67 +550,6 @@ module Dry
|
|
595
550
|
@importer ||= config.importer.new(self)
|
596
551
|
end
|
597
552
|
|
598
|
-
# @api private
|
599
|
-
def component(identifier, **options)
|
600
|
-
if (component = booter.components.detect { |c| c.identifier == identifier })
|
601
|
-
component
|
602
|
-
else
|
603
|
-
Component.new(
|
604
|
-
identifier,
|
605
|
-
loader: config.loader,
|
606
|
-
namespace: config.default_namespace,
|
607
|
-
separator: config.namespace_separator,
|
608
|
-
inflector: config.inflector,
|
609
|
-
**options
|
610
|
-
)
|
611
|
-
end
|
612
|
-
end
|
613
|
-
|
614
|
-
# @api private
|
615
|
-
def require_component(component)
|
616
|
-
return if registered?(component.identifier)
|
617
|
-
|
618
|
-
raise FileNotFoundError, component unless component.file_exists?(load_paths)
|
619
|
-
|
620
|
-
require_path(component.path)
|
621
|
-
|
622
|
-
yield
|
623
|
-
end
|
624
|
-
|
625
|
-
# Allows subclasses to use a different strategy for required files.
|
626
|
-
#
|
627
|
-
# E.g. apps that use `ActiveSupport::Dependencies::Loadable#require_dependency`
|
628
|
-
# will override this method to allow container managed dependencies to be reloaded
|
629
|
-
# for non-finalized containers.
|
630
|
-
#
|
631
|
-
# @api private
|
632
|
-
def require_path(path)
|
633
|
-
require path
|
634
|
-
end
|
635
|
-
|
636
|
-
# @api private
|
637
|
-
def load_component(key, &block)
|
638
|
-
return self if registered?(key)
|
639
|
-
|
640
|
-
component(key).tap do |component|
|
641
|
-
if component.bootable?
|
642
|
-
booter.start(component)
|
643
|
-
else
|
644
|
-
root_key = component.root_key
|
645
|
-
|
646
|
-
if (root_bootable = component(root_key)).bootable?
|
647
|
-
booter.start(root_bootable)
|
648
|
-
elsif importer.key?(root_key)
|
649
|
-
load_imported_component(component.namespaced(root_key))
|
650
|
-
end
|
651
|
-
|
652
|
-
load_local_component(component, &block) unless registered?(key)
|
653
|
-
end
|
654
|
-
end
|
655
|
-
|
656
|
-
self
|
657
|
-
end
|
658
|
-
|
659
553
|
# @api private
|
660
554
|
def after(event, &block)
|
661
555
|
hooks[:"after_#{event}"] << block
|
@@ -672,46 +566,87 @@ module Dry
|
|
672
566
|
|
673
567
|
# @api private
|
674
568
|
def inherited(klass)
|
675
|
-
new_hooks = Container.hooks.dup
|
676
|
-
|
677
569
|
hooks.each do |event, blocks|
|
678
|
-
|
679
|
-
new_hooks[event].concat(klass.hooks[event])
|
570
|
+
klass.hooks[event].concat blocks.dup
|
680
571
|
end
|
681
572
|
|
682
|
-
klass.instance_variable_set(:@hooks, new_hooks)
|
683
573
|
klass.instance_variable_set(:@__finalized__, false)
|
574
|
+
|
684
575
|
super
|
685
576
|
end
|
686
577
|
|
687
|
-
|
578
|
+
protected
|
688
579
|
|
689
580
|
# @api private
|
690
|
-
def
|
691
|
-
|
692
|
-
booter.boot_dependency(component) unless finalized?
|
581
|
+
def load_component(key)
|
582
|
+
return self if registered?(key)
|
693
583
|
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
584
|
+
component = component(key)
|
585
|
+
|
586
|
+
if component.bootable?
|
587
|
+
booter.start(component)
|
588
|
+
return self
|
589
|
+
end
|
590
|
+
|
591
|
+
booter.boot_dependency(component)
|
592
|
+
return self if registered?(key)
|
593
|
+
|
594
|
+
if component.file_exists?
|
595
|
+
load_local_component(component)
|
699
596
|
elsif manual_registrar.file_exists?(component)
|
700
597
|
manual_registrar.(component)
|
701
|
-
elsif
|
702
|
-
|
703
|
-
else
|
704
|
-
raise ComponentLoadError, component
|
598
|
+
elsif importer.key?(component.identifier.root_key)
|
599
|
+
load_imported_component(component.identifier)
|
705
600
|
end
|
601
|
+
|
602
|
+
self
|
706
603
|
end
|
707
604
|
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
605
|
+
private
|
606
|
+
|
607
|
+
def load_local_component(component)
|
608
|
+
if component.auto_register?
|
609
|
+
register(component.identifier, memoize: component.memoize?) { component.instance }
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
def load_imported_component(identifier)
|
614
|
+
import_namespace = identifier.root_key
|
615
|
+
|
616
|
+
container = importer[import_namespace]
|
617
|
+
|
618
|
+
container.load_component(identifier.dequalified(import_namespace).key)
|
619
|
+
|
620
|
+
importer.(import_namespace, container)
|
621
|
+
end
|
622
|
+
|
623
|
+
def component(identifier)
|
624
|
+
if (bootable_component = booter.find_component(identifier))
|
625
|
+
return bootable_component
|
626
|
+
end
|
627
|
+
|
628
|
+
# Find the first matching component from within the configured component dirs.
|
629
|
+
# If no matching component is found, return a plain component instance with no
|
630
|
+
# associated file path. This fallback is important because the component may
|
631
|
+
# still be loadable via the manual registrar or an imported container.
|
632
|
+
component_dirs.detect { |dir|
|
633
|
+
if (component = dir.component_for_identifier(identifier))
|
634
|
+
break component
|
635
|
+
end
|
636
|
+
} || Component.new(identifier)
|
713
637
|
end
|
714
638
|
end
|
639
|
+
|
640
|
+
# Default hooks
|
641
|
+
after :configure do
|
642
|
+
# Add appropriately configured component dirs to the load path
|
643
|
+
#
|
644
|
+
# Do this in a single pass to preserve ordering (i.e. earliest dirs win)
|
645
|
+
paths = config.component_dirs.to_a.each_with_object([]) { |dir, arr|
|
646
|
+
arr << dir.path if dir.add_to_load_path
|
647
|
+
}
|
648
|
+
add_to_load_path!(*paths)
|
649
|
+
end
|
715
650
|
end
|
716
651
|
end
|
717
652
|
end
|
data/lib/dry/system/errors.rb
CHANGED
@@ -2,13 +2,22 @@
|
|
2
2
|
|
3
3
|
module Dry
|
4
4
|
module System
|
5
|
+
# Error raised when a component dir is added to configuration more than once
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
ComponentDirAlreadyAddedError = Class.new(StandardError) do
|
9
|
+
def initialize(dir)
|
10
|
+
super("Component directory #{dir.inspect} already added")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
5
14
|
# Error raised when the container tries to load a component with missing
|
6
15
|
# file
|
7
16
|
#
|
8
17
|
# @api public
|
9
18
|
FileNotFoundError = Class.new(StandardError) do
|
10
19
|
def initialize(component)
|
11
|
-
super("could not resolve require file for #{component.identifier}")
|
20
|
+
super("could not resolve require file for component '#{component.identifier}'")
|
12
21
|
end
|
13
22
|
end
|
14
23
|
|
@@ -18,20 +27,11 @@ module Dry
|
|
18
27
|
ComponentFileMismatchError = Class.new(StandardError) do
|
19
28
|
def initialize(component)
|
20
29
|
super(<<-STR)
|
21
|
-
Bootable component #{component.identifier
|
30
|
+
Bootable component '#{component.identifier}' not found
|
22
31
|
STR
|
23
32
|
end
|
24
33
|
end
|
25
34
|
|
26
|
-
# Error raised when a resolved component couldn't be found
|
27
|
-
#
|
28
|
-
# @api public
|
29
|
-
ComponentLoadError = Class.new(StandardError) do
|
30
|
-
def initialize(component)
|
31
|
-
super("could not load component #{component.inspect}")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
35
|
# Error raised when resolved component couldn't be loaded
|
36
36
|
#
|
37
37
|
# @api public
|
@@ -81,8 +81,17 @@ module Dry
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
|
84
|
+
# Error raised when a configured component directory could not be found
|
85
|
+
#
|
86
|
+
# @api public
|
87
|
+
ComponentDirNotFoundError = Class.new(StandardError) do
|
88
|
+
def initialize(dir)
|
89
|
+
super("Component dir '#{dir}' not found")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
85
93
|
DuplicatedComponentKeyError = Class.new(ArgumentError)
|
94
|
+
|
86
95
|
InvalidSettingsError = Class.new(ArgumentError) do
|
87
96
|
# @api private
|
88
97
|
def initialize(attributes)
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
require_relative "constants"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
module System
|
8
|
+
# An identifier representing a component to be registered.
|
9
|
+
#
|
10
|
+
# Components are eventually registered in the container using plain string
|
11
|
+
# identifiers, available as the `identifier` or `key` attribute here. Additional
|
12
|
+
# methods are provided to make it easier to evaluate or manipulate these identifiers.
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
class Identifier
|
16
|
+
include Dry::Equalizer(:identifier, :namespace, :separator)
|
17
|
+
|
18
|
+
# @return [String] the identifier string
|
19
|
+
# @api public
|
20
|
+
attr_reader :identifier
|
21
|
+
|
22
|
+
# @return [String, nil] the namespace for the component
|
23
|
+
# @api public
|
24
|
+
attr_reader :namespace
|
25
|
+
|
26
|
+
# @return [String] the configured namespace separator
|
27
|
+
# @api public
|
28
|
+
attr_reader :separator
|
29
|
+
|
30
|
+
# @api private
|
31
|
+
def initialize(identifier, namespace: nil, separator: DEFAULT_SEPARATOR)
|
32
|
+
@identifier = identifier.to_s
|
33
|
+
@namespace = namespace
|
34
|
+
@separator = separator
|
35
|
+
end
|
36
|
+
|
37
|
+
# @!method key
|
38
|
+
# Returns the identifier string
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
# @see #identifier
|
42
|
+
# @api public
|
43
|
+
alias_method :key, :identifier
|
44
|
+
|
45
|
+
# @!method to_s
|
46
|
+
# Returns the identifier string
|
47
|
+
#
|
48
|
+
# @return [String]
|
49
|
+
# @see #identifier
|
50
|
+
# @api public
|
51
|
+
alias_method :to_s, :identifier
|
52
|
+
|
53
|
+
# Returns the root namespace segment of the identifier string, as a symbol
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
# identifier.key # => "articles.operations.create"
|
57
|
+
# identifier.root_key # => :articles
|
58
|
+
#
|
59
|
+
# @return [Symbol] the root key
|
60
|
+
# @api public
|
61
|
+
def root_key
|
62
|
+
segments.first.to_sym
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns a path-delimited representation of the identifier, with the namespace
|
66
|
+
# incorporated. This path is intended for usage when requiring the component's
|
67
|
+
# source file.
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# identifier.key # => "articles.operations.create"
|
71
|
+
# identifier.namespace # => "admin"
|
72
|
+
#
|
73
|
+
# identifier.path # => "admin/articles/operations/create"
|
74
|
+
#
|
75
|
+
# @return [String] the path
|
76
|
+
# @api public
|
77
|
+
def path
|
78
|
+
@require_path ||= identifier.gsub(separator, PATH_SEPARATOR).yield_self { |path|
|
79
|
+
if namespace
|
80
|
+
namespace_path = namespace.to_s.gsub(separator, PATH_SEPARATOR)
|
81
|
+
"#{namespace_path}#{PATH_SEPARATOR}#{path}"
|
82
|
+
else
|
83
|
+
path
|
84
|
+
end
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns true if the given namespace prefix is part of the identifier's leading
|
89
|
+
# namespaces
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# identifier.key # => "articles.operations.create"
|
93
|
+
#
|
94
|
+
# identifier.start_with?("articles.operations") # => true
|
95
|
+
# identifier.start_with?("articles") # => true
|
96
|
+
# identifier.start_with?("article") # => false
|
97
|
+
#
|
98
|
+
# @param leading_namespaces [String] the one or more leading namespaces to check
|
99
|
+
# @return [Boolean]
|
100
|
+
# @api public
|
101
|
+
def start_with?(leading_namespaces)
|
102
|
+
identifier.start_with?("#{leading_namespaces}#{separator}") ||
|
103
|
+
identifier.eql?(leading_namespaces)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns a copy of the identifier with the given leading namespaces removed from
|
107
|
+
# the identifier string.
|
108
|
+
#
|
109
|
+
# Additional options may be provided, which are passed to #initialize when
|
110
|
+
# constructing the new copy of the identifier
|
111
|
+
#
|
112
|
+
# @param leading_namespace [String] the one or more leading namespaces to remove
|
113
|
+
# @param options [Hash] additional options for initialization
|
114
|
+
#
|
115
|
+
# @return [Dry::System::Identifier] the copy of the identifier
|
116
|
+
#
|
117
|
+
# @see #initialize
|
118
|
+
# @api private
|
119
|
+
def dequalified(leading_namespaces, **options)
|
120
|
+
new_identifier = identifier.gsub(
|
121
|
+
/^#{Regexp.escape(leading_namespaces)}#{Regexp.escape(separator)}/,
|
122
|
+
EMPTY_STRING
|
123
|
+
)
|
124
|
+
|
125
|
+
return self if new_identifier == identifier
|
126
|
+
|
127
|
+
self.class.new(
|
128
|
+
new_identifier,
|
129
|
+
namespace: namespace,
|
130
|
+
separator: separator,
|
131
|
+
**options
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns a copy of the identifier with the given options applied
|
136
|
+
#
|
137
|
+
# @param namespace [String, nil] a new namespace to be used
|
138
|
+
#
|
139
|
+
# @return [Dry::System::Identifier] the copy of the identifier
|
140
|
+
#
|
141
|
+
# @see #initialize
|
142
|
+
# @api private
|
143
|
+
def with(namespace:)
|
144
|
+
self.class.new(
|
145
|
+
identifier,
|
146
|
+
namespace: namespace,
|
147
|
+
separator: separator
|
148
|
+
)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def segments
|
154
|
+
@segments ||= identifier.split(separator)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|