rom 5.4.1 → 6.0.0.alpha1
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 +58 -65
- data/LICENSE +1 -1
- data/README.md +7 -6
- data/lib/rom/array_dataset.rb +46 -0
- data/lib/rom/associations/abstract.rb +217 -0
- data/lib/rom/associations/definitions/abstract.rb +150 -0
- data/lib/rom/associations/definitions/many_to_many.rb +29 -0
- data/lib/rom/associations/definitions/many_to_one.rb +14 -0
- data/lib/rom/associations/definitions/one_to_many.rb +14 -0
- data/lib/rom/associations/definitions/one_to_one.rb +14 -0
- data/lib/rom/associations/definitions/one_to_one_through.rb +14 -0
- data/lib/rom/associations/definitions.rb +7 -0
- data/lib/rom/associations/many_to_many.rb +128 -0
- data/lib/rom/associations/many_to_one.rb +65 -0
- data/lib/rom/associations/one_to_many.rb +65 -0
- data/lib/rom/associations/one_to_one.rb +13 -0
- data/lib/rom/associations/one_to_one_through.rb +13 -0
- data/lib/rom/associations/through_identifier.rb +41 -0
- data/lib/rom/attribute.rb +425 -0
- data/lib/rom/auto_curry.rb +70 -0
- data/lib/rom/cache.rb +87 -0
- data/lib/rom/changeset/associated.rb +110 -0
- data/lib/rom/changeset/create.rb +18 -0
- data/lib/rom/changeset/delete.rb +15 -0
- data/lib/rom/changeset/extensions/relation.rb +26 -0
- data/lib/rom/changeset/pipe.rb +81 -0
- data/lib/rom/changeset/pipe_registry.rb +27 -0
- data/lib/rom/changeset/stateful.rb +285 -0
- data/lib/rom/changeset/update.rb +81 -0
- data/lib/rom/changeset.rb +185 -0
- data/lib/rom/command.rb +351 -0
- data/lib/rom/command_compiler.rb +201 -0
- data/lib/rom/command_proxy.rb +36 -0
- data/lib/rom/commands/class_interface.rb +236 -0
- data/lib/rom/commands/composite.rb +55 -0
- data/lib/rom/commands/create.rb +15 -0
- data/lib/rom/commands/delete.rb +16 -0
- data/lib/rom/commands/graph/class_interface.rb +64 -0
- data/lib/rom/commands/graph/input_evaluator.rb +94 -0
- data/lib/rom/commands/graph.rb +88 -0
- data/lib/rom/commands/lazy/create.rb +35 -0
- data/lib/rom/commands/lazy/delete.rb +39 -0
- data/lib/rom/commands/lazy/update.rb +46 -0
- data/lib/rom/commands/lazy.rb +106 -0
- data/lib/rom/commands/update.rb +16 -0
- data/lib/rom/commands.rb +5 -0
- data/lib/rom/compat/auto_registration.rb +115 -0
- data/lib/rom/compat/auto_registration_strategies/base.rb +29 -0
- data/lib/rom/compat/auto_registration_strategies/custom_namespace.rb +84 -0
- data/lib/rom/compat/auto_registration_strategies/no_namespace.rb +33 -0
- data/lib/rom/compat/auto_registration_strategies/with_namespace.rb +29 -0
- data/lib/rom/compat/command.rb +74 -0
- data/lib/rom/compat/components/dsl/schema.rb +130 -0
- data/lib/rom/compat/components.rb +91 -0
- data/lib/rom/compat/global.rb +17 -0
- data/lib/rom/compat/mapper.rb +22 -0
- data/lib/rom/compat/registries.rb +47 -0
- data/lib/rom/compat/relation.rb +40 -0
- data/lib/rom/compat/schema/dsl.rb +260 -0
- data/lib/rom/compat/setting_proxy.rb +44 -0
- data/lib/rom/compat/setup.rb +151 -0
- data/lib/rom/compat/transformer.rb +49 -0
- data/lib/rom/compat.rb +22 -0
- data/lib/rom/components/association.rb +26 -0
- data/lib/rom/components/command.rb +24 -0
- data/lib/rom/components/core.rb +148 -0
- data/lib/rom/components/dataset.rb +60 -0
- data/lib/rom/components/dsl/association.rb +47 -0
- data/lib/rom/components/dsl/command.rb +60 -0
- data/lib/rom/components/dsl/core.rb +126 -0
- data/lib/rom/components/dsl/dataset.rb +33 -0
- data/lib/rom/components/dsl/gateway.rb +14 -0
- data/lib/rom/components/dsl/mapper.rb +70 -0
- data/lib/rom/components/dsl/relation.rb +49 -0
- data/lib/rom/components/dsl/schema.rb +150 -0
- data/lib/rom/components/dsl/view.rb +82 -0
- data/lib/rom/components/dsl.rb +255 -0
- data/lib/rom/components/gateway.rb +50 -0
- data/lib/rom/components/mapper.rb +29 -0
- data/lib/rom/components/provider.rb +160 -0
- data/lib/rom/components/registry.rb +154 -0
- data/lib/rom/components/relation.rb +41 -0
- data/lib/rom/components/schema.rb +61 -0
- data/lib/rom/components/view.rb +55 -0
- data/lib/rom/components.rb +55 -0
- data/lib/rom/configuration_dsl.rb +4 -0
- data/lib/rom/constants.rb +135 -0
- data/lib/rom/container.rb +182 -0
- data/lib/rom/core.rb +125 -0
- data/lib/rom/data_proxy.rb +97 -0
- data/lib/rom/enumerable_dataset.rb +70 -0
- data/lib/rom/gateway.rb +232 -0
- data/lib/rom/global.rb +56 -0
- data/lib/rom/header/attribute.rb +190 -0
- data/lib/rom/header.rb +198 -0
- data/lib/rom/inferrer.rb +55 -0
- data/lib/rom/initializer.rb +80 -0
- data/lib/rom/lint/enumerable_dataset.rb +56 -0
- data/lib/rom/lint/gateway.rb +120 -0
- data/lib/rom/lint/linter.rb +79 -0
- data/lib/rom/lint/spec.rb +22 -0
- data/lib/rom/lint/test.rb +98 -0
- data/lib/rom/loader.rb +161 -0
- data/lib/rom/mapper/attribute_dsl.rb +480 -0
- data/lib/rom/mapper/dsl.rb +107 -0
- data/lib/rom/mapper/model_dsl.rb +61 -0
- data/lib/rom/mapper.rb +99 -0
- data/lib/rom/mapper_compiler.rb +84 -0
- data/lib/rom/memory/associations/many_to_many.rb +12 -0
- data/lib/rom/memory/associations/many_to_one.rb +12 -0
- data/lib/rom/memory/associations/one_to_many.rb +12 -0
- data/lib/rom/memory/associations/one_to_one.rb +12 -0
- data/lib/rom/memory/associations.rb +6 -0
- data/lib/rom/memory/commands.rb +60 -0
- data/lib/rom/memory/dataset.rb +127 -0
- data/lib/rom/memory/gateway.rb +66 -0
- data/lib/rom/memory/mapper_compiler.rb +10 -0
- data/lib/rom/memory/relation.rb +91 -0
- data/lib/rom/memory/schema.rb +32 -0
- data/lib/rom/memory/storage.rb +61 -0
- data/lib/rom/memory/types.rb +11 -0
- data/lib/rom/memory.rb +7 -0
- data/lib/rom/model_builder.rb +103 -0
- data/lib/rom/open_struct.rb +112 -0
- data/lib/rom/pipeline.rb +111 -0
- data/lib/rom/plugin.rb +130 -0
- data/lib/rom/plugins/class_methods.rb +37 -0
- data/lib/rom/plugins/command/schema.rb +45 -0
- data/lib/rom/plugins/command/timestamps.rb +149 -0
- data/lib/rom/plugins/dsl.rb +53 -0
- data/lib/rom/plugins/relation/changeset.rb +97 -0
- data/lib/rom/plugins/relation/instrumentation.rb +66 -0
- data/lib/rom/plugins/relation/registry_reader.rb +36 -0
- data/lib/rom/plugins/schema/timestamps.rb +59 -0
- data/lib/rom/plugins.rb +100 -0
- data/lib/rom/processor/composer.rb +37 -0
- data/lib/rom/processor/transformer.rb +415 -0
- data/lib/rom/processor.rb +30 -0
- data/lib/rom/registries/associations.rb +26 -0
- data/lib/rom/registries/commands.rb +11 -0
- data/lib/rom/registries/container.rb +12 -0
- data/lib/rom/registries/datasets.rb +21 -0
- data/lib/rom/registries/gateways.rb +8 -0
- data/lib/rom/registries/mappers.rb +21 -0
- data/lib/rom/registries/nestable.rb +32 -0
- data/lib/rom/registries/relations.rb +8 -0
- data/lib/rom/registries/root.rb +203 -0
- data/lib/rom/registries/schemas.rb +44 -0
- data/lib/rom/registries/views.rb +11 -0
- data/lib/rom/relation/class_interface.rb +61 -0
- data/lib/rom/relation/combined.rb +160 -0
- data/lib/rom/relation/commands.rb +65 -0
- data/lib/rom/relation/composite.rb +53 -0
- data/lib/rom/relation/curried.rb +129 -0
- data/lib/rom/relation/graph.rb +107 -0
- data/lib/rom/relation/loaded.rb +136 -0
- data/lib/rom/relation/materializable.rb +62 -0
- data/lib/rom/relation/name.rb +122 -0
- data/lib/rom/relation/wrap.rb +64 -0
- data/lib/rom/relation.rb +625 -0
- data/lib/rom/repository/class_interface.rb +162 -0
- data/lib/rom/repository/relation_reader.rb +48 -0
- data/lib/rom/repository/root.rb +75 -0
- data/lib/rom/repository/session.rb +60 -0
- data/lib/rom/repository.rb +179 -0
- data/lib/rom/schema/associations_dsl.rb +222 -0
- data/lib/rom/schema/inferrer.rb +106 -0
- data/lib/rom/schema.rb +471 -0
- data/lib/rom/settings.rb +141 -0
- data/lib/rom/setup.rb +297 -0
- data/lib/rom/struct.rb +99 -0
- data/lib/rom/struct_compiler.rb +114 -0
- data/lib/rom/support/configurable.rb +213 -0
- data/lib/rom/support/inflector.rb +31 -0
- data/lib/rom/support/memoizable.rb +61 -0
- data/lib/rom/support/notifications.rb +238 -0
- data/lib/rom/transaction.rb +26 -0
- data/lib/rom/transformer.rb +46 -0
- data/lib/rom/types.rb +74 -0
- data/lib/rom/version.rb +1 -1
- data/lib/rom-changeset.rb +4 -0
- data/lib/rom-core.rb +3 -0
- data/lib/rom-repository.rb +4 -0
- data/lib/rom.rb +3 -3
- metadata +302 -23
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rom/lint/linter"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module Lint
|
7
|
+
# Ensures that a [ROM::Gateway] extension provides datasets through the
|
8
|
+
# expected methods
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
class Gateway < ROM::Lint::Linter
|
12
|
+
# The gateway identifier e.g. +:memory+
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
attr_reader :identifier
|
16
|
+
|
17
|
+
# The gateway class
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
attr_reader :gateway
|
21
|
+
|
22
|
+
# The optional URI
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
attr_reader :uri
|
26
|
+
|
27
|
+
# Gateway instance used in lint tests
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
attr_reader :gateway_instance
|
31
|
+
|
32
|
+
# Create a gateway linter
|
33
|
+
#
|
34
|
+
# @param [Symbol] identifier
|
35
|
+
# @param [Class] gateway
|
36
|
+
# @param [String] uri optional
|
37
|
+
def initialize(identifier, gateway, uri = nil)
|
38
|
+
@identifier = identifier
|
39
|
+
@gateway = gateway
|
40
|
+
@uri = uri
|
41
|
+
@gateway_instance = setup_gateway_instance
|
42
|
+
end
|
43
|
+
|
44
|
+
# Lint: Ensure that +gateway+ setups up its instance
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def lint_gateway_setup
|
48
|
+
return if gateway_instance.instance_of? gateway
|
49
|
+
|
50
|
+
complain <<-STRING
|
51
|
+
#{gateway}.setup must return a gateway instance but
|
52
|
+
returned #{gateway_instance.inspect}
|
53
|
+
STRING
|
54
|
+
end
|
55
|
+
|
56
|
+
# Lint: Ensure that +gateway_instance+ responds to +[]+
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
def lint_dataset_reader
|
60
|
+
return if gateway_instance.respond_to? :[]
|
61
|
+
|
62
|
+
complain "#{gateway_instance} must respond to []"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Lint: Ensure that +gateway_instance+ responds to +dataset?+
|
66
|
+
#
|
67
|
+
# @api public
|
68
|
+
def lint_dataset_predicate
|
69
|
+
return if gateway_instance.respond_to? :dataset?
|
70
|
+
|
71
|
+
complain "#{gateway_instance} must respond to dataset?"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Lint: Ensure +gateway_instance+ supports +transaction+ interface
|
75
|
+
#
|
76
|
+
# @api public
|
77
|
+
def lint_transaction_support
|
78
|
+
result = gateway_instance.transaction { 1 }
|
79
|
+
|
80
|
+
complain "#{gateway_instance} must return the result of a transaction block" if result != 1
|
81
|
+
|
82
|
+
gateway_instance.transaction do |t|
|
83
|
+
t.rollback!
|
84
|
+
|
85
|
+
complain "#{gateway_instance} must interrupt a transaction on rollback"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Lint: Ensure +gateway_instance+ returns adapter name
|
90
|
+
def lint_adapter_reader
|
91
|
+
if gateway_instance.adapter != identifier
|
92
|
+
complain "#{gateway_instance} must have the adapter identifier set to #{identifier.inspect}"
|
93
|
+
end
|
94
|
+
rescue MissingAdapterIdentifierError
|
95
|
+
complain "#{gateway_instance} is missing the adapter identifier"
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# Setup gateway instance
|
101
|
+
#
|
102
|
+
# @api private
|
103
|
+
def setup_gateway_instance
|
104
|
+
if uri
|
105
|
+
ROM::Gateway.setup(identifier, uri)
|
106
|
+
else
|
107
|
+
ROM::Gateway.setup(identifier)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Run Gateway#disconnect
|
112
|
+
#
|
113
|
+
# @api private
|
114
|
+
def after_lint
|
115
|
+
super
|
116
|
+
gateway_instance.disconnect
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Lint
|
5
|
+
# Base class for building linters that check source code
|
6
|
+
#
|
7
|
+
# Linters are used by authors of ROM adapters to verify that their
|
8
|
+
# integration complies with the ROM api.
|
9
|
+
#
|
10
|
+
# Most of the time, authors won't need to construct linters directly
|
11
|
+
# because the provided test helpers will automatically run when required
|
12
|
+
# in tests and specs.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# require 'rom/lint/spec'
|
16
|
+
#
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
class Linter
|
20
|
+
# A failure raised by +complain+
|
21
|
+
Failure = Class.new(StandardError)
|
22
|
+
|
23
|
+
# Iterate over all lint methods
|
24
|
+
#
|
25
|
+
# @yield [String, ROM::Lint]
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def self.each_lint
|
29
|
+
return to_enum unless block_given?
|
30
|
+
|
31
|
+
lints.each { |lint| yield lint, self }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Run a lint method
|
35
|
+
#
|
36
|
+
# @param [String] name
|
37
|
+
#
|
38
|
+
# @raise [ROM::Lint::Linter::Failure] if linting fails
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
def lint(name)
|
42
|
+
before_lint
|
43
|
+
public_send name
|
44
|
+
after_lint
|
45
|
+
true # for assertions
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return a list a lint methods
|
49
|
+
#
|
50
|
+
# @return [String]
|
51
|
+
#
|
52
|
+
# @api private
|
53
|
+
def self.lints
|
54
|
+
public_instance_methods(true).grep(/^lint_/).map(&:to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Raise a failure if a lint verification fails
|
60
|
+
#
|
61
|
+
# @raise [ROM::Lint::Linter::Failure]
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
def complain(*args)
|
65
|
+
raise Failure, *args
|
66
|
+
end
|
67
|
+
|
68
|
+
# Hook method executed before each lint method run
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
def before_lint; end
|
72
|
+
|
73
|
+
# Hook method executed after each lint method run
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
def after_lint; end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rom/lint/gateway"
|
4
|
+
require "rom/lint/enumerable_dataset"
|
5
|
+
|
6
|
+
RSpec.shared_examples "a rom gateway" do
|
7
|
+
ROM::Lint::Gateway.each_lint do |name, linter|
|
8
|
+
it name do
|
9
|
+
result = linter.new(identifier, gateway, uri).lint(name)
|
10
|
+
expect(result).to be_truthy
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.shared_examples "a rom enumerable dataset" do
|
16
|
+
ROM::Lint::EnumerableDataset.each_lint do |name, linter|
|
17
|
+
it name do
|
18
|
+
result = linter.new(dataset, data).lint(name)
|
19
|
+
expect(result).to be_truthy
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rom/lint/gateway"
|
4
|
+
require "rom/lint/enumerable_dataset"
|
5
|
+
|
6
|
+
module ROM
|
7
|
+
module Lint
|
8
|
+
# A module that helps to define test methods
|
9
|
+
module Test
|
10
|
+
# Defines a test method converting lint failures to assertions
|
11
|
+
#
|
12
|
+
# @param [String] name
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
def define_test_method(name, &block)
|
16
|
+
define_method "test_#{name}" do
|
17
|
+
instance_eval(&block)
|
18
|
+
rescue ROM::Lint::Linter::Failure => e
|
19
|
+
raise Minitest::Assertion, e.message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# This is a simple lint-test for gateway class to ensure the
|
25
|
+
# basic interfaces are in place
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
#
|
29
|
+
# class MyGatewayTest < Minitest::Test
|
30
|
+
# include ROM::Lint::TestGateway
|
31
|
+
#
|
32
|
+
# def setup
|
33
|
+
# @gateway = MyGateway
|
34
|
+
# @uri = "super_db://something"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
module TestGateway
|
40
|
+
extend ROM::Lint::Test
|
41
|
+
|
42
|
+
# Returns the gateway identifier e.g. +:memory+
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
attr_reader :identifier
|
46
|
+
|
47
|
+
# Returns the gateway class
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
attr_reader :gateway
|
51
|
+
|
52
|
+
# Returns gateway's URI e.g. "super_db://something"
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
attr_reader :uri
|
56
|
+
|
57
|
+
ROM::Lint::Gateway.each_lint do |name, linter|
|
58
|
+
define_test_method name do
|
59
|
+
assert linter.new(identifier, gateway, uri).lint(name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# This is a simple lint-test for a gateway dataset class to ensure the
|
65
|
+
# basic behavior is correct
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
#
|
69
|
+
# class MyDatasetLintTest < Minitest::Test
|
70
|
+
# include ROM::Lint::TestEnumerableDataset
|
71
|
+
#
|
72
|
+
# def setup
|
73
|
+
# @data = [{ name: 'Jane', age: 24 }, { name: 'Joe', age: 25 }]
|
74
|
+
# @dataset = MyDataset.new(@data, [:name, :age])
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# @api public
|
78
|
+
module TestEnumerableDataset
|
79
|
+
extend ROM::Lint::Test
|
80
|
+
|
81
|
+
# Returns the dataset instance
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
attr_reader :dataset
|
85
|
+
|
86
|
+
# Returns the expected data
|
87
|
+
#
|
88
|
+
# @api public
|
89
|
+
attr_reader :data
|
90
|
+
|
91
|
+
ROM::Lint::EnumerableDataset.each_lint do |name, linter|
|
92
|
+
define_test_method name do
|
93
|
+
assert linter.new(dataset, data).lint(name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/rom/loader.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
require "zeitwerk"
|
5
|
+
|
6
|
+
require "rom/support/inflector"
|
7
|
+
|
8
|
+
require "rom/types"
|
9
|
+
require "rom/initializer"
|
10
|
+
require "rom/loader"
|
11
|
+
|
12
|
+
module ROM
|
13
|
+
# AutoRegistration is used to load component files automatically from the provided directory path
|
14
|
+
#
|
15
|
+
# @api public
|
16
|
+
class Loader
|
17
|
+
extend Initializer
|
18
|
+
|
19
|
+
NamespaceType = Types::Strict::Bool | Types.Instance(Module)
|
20
|
+
|
21
|
+
PathnameType = Types.Constructor(Pathname, &Kernel.method(:Pathname))
|
22
|
+
|
23
|
+
InflectorType = Types.Interface(:camelize)
|
24
|
+
|
25
|
+
ComponentDirs = Types::Strict::Hash.constructor { |hash| hash.transform_values(&:to_s) }
|
26
|
+
|
27
|
+
DEFAULT_MAPPING = {
|
28
|
+
relations: "relations",
|
29
|
+
mappers: "mappers",
|
30
|
+
commands: "commands"
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
# @!attribute [r] directory
|
34
|
+
# @return [Pathname] The root path
|
35
|
+
param :root_directory, type: PathnameType.optional
|
36
|
+
|
37
|
+
# @!attribute [r] auto_load
|
38
|
+
# @return [Boolean]
|
39
|
+
# Whether files should be auto-loadable
|
40
|
+
option :auto_load, type: Types::Strict::Bool, default: -> { false }
|
41
|
+
|
42
|
+
# @!attribute [r] namespace
|
43
|
+
# @return [Boolean,String]
|
44
|
+
# The name of the top level namespace or true/false which
|
45
|
+
# enables/disables default top level namespace inferred from the dir name
|
46
|
+
option :namespace, type: NamespaceType, default: -> { true }
|
47
|
+
|
48
|
+
# @!attribute [r] component_dirs
|
49
|
+
# @return [Hash] component => dir-name map
|
50
|
+
option :component_dirs, type: ComponentDirs, default: -> { DEFAULT_MAPPING }
|
51
|
+
|
52
|
+
# @!attribute [r] inflector
|
53
|
+
# @return [Dry::Inflector] String inflector
|
54
|
+
# @api private
|
55
|
+
option :inflector, type: InflectorType, default: -> { Inflector }
|
56
|
+
|
57
|
+
# @!attribute [r] components
|
58
|
+
# @return [ROM::Components]
|
59
|
+
# @api private
|
60
|
+
option :components
|
61
|
+
|
62
|
+
# Load components
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
def call
|
66
|
+
return if @loaded || root_directory.nil?
|
67
|
+
|
68
|
+
setup
|
69
|
+
|
70
|
+
backend.eager_load unless auto_load
|
71
|
+
|
72
|
+
@loaded = true
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
def auto_load_component_file(type, key)
|
77
|
+
return unless component_dirs.include?(type)
|
78
|
+
|
79
|
+
const_parts = key.split(".").map { |name| inflector.camelize(name) }
|
80
|
+
const_parts.unshift(namespace_const_name) if namespace_const_name
|
81
|
+
const_name = const_parts.join("::")
|
82
|
+
|
83
|
+
inflector.constantize(const_name)
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# @api private
|
89
|
+
def namespace_const_name
|
90
|
+
case namespace
|
91
|
+
when true
|
92
|
+
inflector.classify(root_directory.basename)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# @api private
|
97
|
+
def backend
|
98
|
+
@backend ||= Zeitwerk::Loader.new
|
99
|
+
end
|
100
|
+
|
101
|
+
# @api private
|
102
|
+
# rubocop:disable Metrics/AbcSize
|
103
|
+
def setup
|
104
|
+
backend.inflector = inflector
|
105
|
+
|
106
|
+
case namespace
|
107
|
+
when true
|
108
|
+
top_directory = root_directory.join("..").realpath
|
109
|
+
|
110
|
+
backend.push_dir(top_directory)
|
111
|
+
|
112
|
+
others = top_directory.children.select(&:directory?).reject { |dir| dir == root_directory }
|
113
|
+
|
114
|
+
others.each do |dir|
|
115
|
+
backend.ignore(dir)
|
116
|
+
end
|
117
|
+
when false
|
118
|
+
backend.push_dir(root_directory)
|
119
|
+
else
|
120
|
+
backend.push_dir(root_directory, namespace: namespace)
|
121
|
+
end
|
122
|
+
|
123
|
+
excluded_dirs.each do |dir|
|
124
|
+
backend.ignore(dir)
|
125
|
+
end
|
126
|
+
|
127
|
+
backend.on_load do |_, constant, path|
|
128
|
+
if (type = path_to_component_type(path))
|
129
|
+
begin
|
130
|
+
components.add(type, constant: constant, config: constant.config.component)
|
131
|
+
rescue StandardError => e
|
132
|
+
raise "Failed to load #{constant} from #{path}: #{e.message}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
backend.setup
|
138
|
+
end
|
139
|
+
# rubocop:enable Metrics/AbcSize
|
140
|
+
|
141
|
+
# @api private
|
142
|
+
def path_to_component_type(path)
|
143
|
+
return unless File.file?(path)
|
144
|
+
|
145
|
+
component_dirs
|
146
|
+
.detect { |_, dir|
|
147
|
+
path.start_with?(root_directory.join(dir).to_s)
|
148
|
+
}
|
149
|
+
&.first
|
150
|
+
end
|
151
|
+
|
152
|
+
# @api private
|
153
|
+
def excluded_dirs
|
154
|
+
root_directory
|
155
|
+
.children
|
156
|
+
.select(&:directory?)
|
157
|
+
.reject { |dir| component_dirs.values.include?(dir.basename.to_s) }
|
158
|
+
.map { |name| root_directory.join(name) }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|