rom-core 4.0.0.beta1
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 +7 -0
- data/CHANGELOG.md +603 -0
- data/LICENSE +20 -0
- data/README.md +18 -0
- data/lib/rom-core.rb +1 -0
- data/lib/rom/array_dataset.rb +44 -0
- data/lib/rom/association_set.rb +16 -0
- data/lib/rom/associations/abstract.rb +135 -0
- data/lib/rom/associations/definitions.rb +5 -0
- data/lib/rom/associations/definitions/abstract.rb +116 -0
- data/lib/rom/associations/definitions/many_to_many.rb +24 -0
- data/lib/rom/associations/definitions/many_to_one.rb +11 -0
- data/lib/rom/associations/definitions/one_to_many.rb +11 -0
- data/lib/rom/associations/definitions/one_to_one.rb +11 -0
- data/lib/rom/associations/definitions/one_to_one_through.rb +11 -0
- data/lib/rom/associations/many_to_many.rb +81 -0
- data/lib/rom/associations/many_to_one.rb +37 -0
- data/lib/rom/associations/one_to_many.rb +37 -0
- data/lib/rom/associations/one_to_one.rb +8 -0
- data/lib/rom/associations/one_to_one_through.rb +8 -0
- data/lib/rom/associations/through_identifier.rb +39 -0
- data/lib/rom/auto_curry.rb +55 -0
- data/lib/rom/cache.rb +46 -0
- data/lib/rom/command.rb +488 -0
- data/lib/rom/command_compiler.rb +239 -0
- data/lib/rom/command_proxy.rb +24 -0
- data/lib/rom/command_registry.rb +141 -0
- data/lib/rom/commands.rb +3 -0
- data/lib/rom/commands/class_interface.rb +270 -0
- data/lib/rom/commands/composite.rb +53 -0
- data/lib/rom/commands/create.rb +13 -0
- data/lib/rom/commands/delete.rb +14 -0
- data/lib/rom/commands/graph.rb +88 -0
- data/lib/rom/commands/graph/class_interface.rb +62 -0
- data/lib/rom/commands/graph/input_evaluator.rb +62 -0
- data/lib/rom/commands/lazy.rb +99 -0
- data/lib/rom/commands/lazy/create.rb +23 -0
- data/lib/rom/commands/lazy/delete.rb +27 -0
- data/lib/rom/commands/lazy/update.rb +34 -0
- data/lib/rom/commands/result.rb +96 -0
- data/lib/rom/commands/update.rb +14 -0
- data/lib/rom/configuration.rb +114 -0
- data/lib/rom/configuration_dsl.rb +87 -0
- data/lib/rom/configuration_dsl/command.rb +41 -0
- data/lib/rom/configuration_dsl/command_dsl.rb +35 -0
- data/lib/rom/configuration_dsl/relation.rb +26 -0
- data/lib/rom/configuration_plugin.rb +17 -0
- data/lib/rom/constants.rb +64 -0
- data/lib/rom/container.rb +147 -0
- data/lib/rom/core.rb +46 -0
- data/lib/rom/create_container.rb +60 -0
- data/lib/rom/data_proxy.rb +94 -0
- data/lib/rom/enumerable_dataset.rb +68 -0
- data/lib/rom/environment.rb +70 -0
- data/lib/rom/gateway.rb +184 -0
- data/lib/rom/global.rb +58 -0
- data/lib/rom/global/plugin_dsl.rb +47 -0
- data/lib/rom/initializer.rb +64 -0
- data/lib/rom/lint/enumerable_dataset.rb +54 -0
- data/lib/rom/lint/gateway.rb +120 -0
- data/lib/rom/lint/linter.rb +78 -0
- data/lib/rom/lint/spec.rb +20 -0
- data/lib/rom/lint/test.rb +98 -0
- data/lib/rom/mapper_registry.rb +24 -0
- data/lib/rom/memory.rb +4 -0
- data/lib/rom/memory/associations.rb +4 -0
- data/lib/rom/memory/associations/many_to_many.rb +10 -0
- data/lib/rom/memory/associations/many_to_one.rb +10 -0
- data/lib/rom/memory/associations/one_to_many.rb +10 -0
- data/lib/rom/memory/associations/one_to_one.rb +10 -0
- data/lib/rom/memory/commands.rb +56 -0
- data/lib/rom/memory/dataset.rb +97 -0
- data/lib/rom/memory/gateway.rb +64 -0
- data/lib/rom/memory/relation.rb +62 -0
- data/lib/rom/memory/schema.rb +23 -0
- data/lib/rom/memory/storage.rb +59 -0
- data/lib/rom/memory/types.rb +9 -0
- data/lib/rom/pipeline.rb +105 -0
- data/lib/rom/plugin.rb +25 -0
- data/lib/rom/plugin_base.rb +45 -0
- data/lib/rom/plugin_registry.rb +197 -0
- data/lib/rom/plugins/command/schema.rb +37 -0
- data/lib/rom/plugins/configuration/configuration_dsl.rb +21 -0
- data/lib/rom/plugins/relation/instrumentation.rb +51 -0
- data/lib/rom/plugins/relation/registry_reader.rb +44 -0
- data/lib/rom/plugins/schema/timestamps.rb +58 -0
- data/lib/rom/registry.rb +71 -0
- data/lib/rom/relation.rb +548 -0
- data/lib/rom/relation/class_interface.rb +282 -0
- data/lib/rom/relation/commands.rb +23 -0
- data/lib/rom/relation/composite.rb +46 -0
- data/lib/rom/relation/curried.rb +103 -0
- data/lib/rom/relation/graph.rb +197 -0
- data/lib/rom/relation/loaded.rb +127 -0
- data/lib/rom/relation/materializable.rb +66 -0
- data/lib/rom/relation/name.rb +111 -0
- data/lib/rom/relation/view_dsl.rb +64 -0
- data/lib/rom/relation/wrap.rb +83 -0
- data/lib/rom/relation_registry.rb +10 -0
- data/lib/rom/schema.rb +437 -0
- data/lib/rom/schema/associations_dsl.rb +195 -0
- data/lib/rom/schema/attribute.rb +419 -0
- data/lib/rom/schema/dsl.rb +164 -0
- data/lib/rom/schema/inferrer.rb +66 -0
- data/lib/rom/schema_plugin.rb +27 -0
- data/lib/rom/setup.rb +68 -0
- data/lib/rom/setup/auto_registration.rb +74 -0
- data/lib/rom/setup/auto_registration_strategies/base.rb +16 -0
- data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +63 -0
- data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +20 -0
- data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +18 -0
- data/lib/rom/setup/finalize.rb +103 -0
- data/lib/rom/setup/finalize/finalize_commands.rb +60 -0
- data/lib/rom/setup/finalize/finalize_mappers.rb +56 -0
- data/lib/rom/setup/finalize/finalize_relations.rb +135 -0
- data/lib/rom/support/configurable.rb +85 -0
- data/lib/rom/support/memoizable.rb +58 -0
- data/lib/rom/support/notifications.rb +103 -0
- data/lib/rom/transaction.rb +24 -0
- data/lib/rom/types.rb +26 -0
- data/lib/rom/version.rb +5 -0
- metadata +289 -0
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'dry/equalizer'
|
2
|
+
|
3
|
+
require 'rom/types'
|
4
|
+
require 'rom/schema/attribute'
|
5
|
+
require 'rom/schema/associations_dsl'
|
6
|
+
|
7
|
+
module ROM
|
8
|
+
# Relation schema
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
class Schema
|
12
|
+
# @api public
|
13
|
+
class DSL < BasicObject
|
14
|
+
KERNEL_METHODS = %i(extend method).freeze
|
15
|
+
KERNEL_METHODS.each { |m| define_method(m, ::Kernel.instance_method(m)) }
|
16
|
+
|
17
|
+
extend Initializer
|
18
|
+
|
19
|
+
param :relation
|
20
|
+
|
21
|
+
option :inferrer, default: -> { DEFAULT_INFERRER }
|
22
|
+
|
23
|
+
option :schema_class, default: -> { Schema }
|
24
|
+
|
25
|
+
option :attr_class, default: -> { Attribute }
|
26
|
+
|
27
|
+
option :adapter, default: -> { :default }
|
28
|
+
|
29
|
+
attr_reader :attributes, :plugins, :definition, :associations_dsl
|
30
|
+
|
31
|
+
# @api private
|
32
|
+
def initialize(*, &block)
|
33
|
+
super
|
34
|
+
|
35
|
+
@attributes = {}
|
36
|
+
@plugins = {}
|
37
|
+
|
38
|
+
@definition = block
|
39
|
+
end
|
40
|
+
|
41
|
+
# Defines a relation attribute with its type
|
42
|
+
#
|
43
|
+
# @see Relation.schema
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def attribute(name, type, options = EMPTY_HASH)
|
47
|
+
if attributes.key?(name)
|
48
|
+
::Kernel.raise ::ROM::Schema::AttributeAlreadyDefinedError,
|
49
|
+
"Attribute #{ name.inspect } already defined"
|
50
|
+
end
|
51
|
+
|
52
|
+
attributes[name] = build_type(name, type, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Define associations for a relation
|
56
|
+
#
|
57
|
+
# @example
|
58
|
+
# class Users < ROM::Relation[:sql]
|
59
|
+
# schema(infer: true) do
|
60
|
+
# associations do
|
61
|
+
# has_many :tasks
|
62
|
+
# has_many :posts
|
63
|
+
# has_many :posts, as: :priority_posts, view: :prioritized
|
64
|
+
# belongs_to :account
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# class Posts < ROM::Relation[:sql]
|
70
|
+
# schema(infer: true) do
|
71
|
+
# associations do
|
72
|
+
# belongs_to :users, as: :author
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# view(:prioritized) do
|
77
|
+
# where { priority <= 3 }
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# @return [AssociationDSL]
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
def associations(&block)
|
85
|
+
@associations_dsl = AssociationsDSL.new(relation, &block)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Builds a type instance from a name, options and a base type
|
89
|
+
#
|
90
|
+
# @return [Dry::Types::Type] Type instance
|
91
|
+
#
|
92
|
+
# @api private
|
93
|
+
def build_type(name, type, options = EMPTY_HASH)
|
94
|
+
if options[:read]
|
95
|
+
type.meta(name: name, source: relation, read: options[:read])
|
96
|
+
else
|
97
|
+
type.meta(name: name, source: relation)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Specify which key(s) should be the primary key
|
102
|
+
#
|
103
|
+
# @api public
|
104
|
+
def primary_key(*names)
|
105
|
+
names.each do |name|
|
106
|
+
attributes[name] = attributes[name].meta(primary_key: true)
|
107
|
+
end
|
108
|
+
self
|
109
|
+
end
|
110
|
+
|
111
|
+
# Enables for the schema
|
112
|
+
#
|
113
|
+
# @param [Symbol] plugin Plugin name
|
114
|
+
# @param [Hash] options Plugin options
|
115
|
+
#
|
116
|
+
# @api public
|
117
|
+
def use(plugin, options = ::ROM::EMPTY_HASH)
|
118
|
+
mod = ::ROM.plugin_registry.schemas.adapter(adapter).fetch(plugin)
|
119
|
+
app_plugin(mod, options)
|
120
|
+
end
|
121
|
+
|
122
|
+
# @api private
|
123
|
+
def app_plugin(plugin, options = ::ROM::EMPTY_HASH)
|
124
|
+
plugin_name = ::ROM.plugin_registry.schemas.adapter(adapter).plugin_name(plugin)
|
125
|
+
plugin.extend_dsl(self)
|
126
|
+
@plugins[plugin_name] = [plugin, plugin.config.to_hash.merge(options)]
|
127
|
+
end
|
128
|
+
|
129
|
+
# @api private
|
130
|
+
def call(&block)
|
131
|
+
instance_exec(&block) if block
|
132
|
+
instance_exec(&definition) if definition
|
133
|
+
|
134
|
+
schema_class.define(relation, opts) do |schema|
|
135
|
+
plugins.values.each { |(plugin, options)|
|
136
|
+
plugin.apply_to(schema, options)
|
137
|
+
}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# @api private
|
142
|
+
def plugin_options(plugin)
|
143
|
+
@plugins[plugin][1]
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
# Return schema opts
|
149
|
+
#
|
150
|
+
# @return [Hash]
|
151
|
+
#
|
152
|
+
# @api private
|
153
|
+
def opts
|
154
|
+
opts = { attributes: attributes.values, inferrer: inferrer, attr_class: attr_class }
|
155
|
+
|
156
|
+
if associations_dsl
|
157
|
+
{ **opts, associations: associations_dsl.call }
|
158
|
+
else
|
159
|
+
opts
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'dry/core/class_attributes'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
class Schema
|
5
|
+
# @api private
|
6
|
+
class Inferrer
|
7
|
+
extend Dry::Core::ClassAttributes
|
8
|
+
extend Initializer
|
9
|
+
|
10
|
+
defines :attributes_inferrer, :attr_class
|
11
|
+
|
12
|
+
MissingAttributesError = Class.new(StandardError) do
|
13
|
+
def initialize(name, attributes)
|
14
|
+
super("missing attributes in #{name.inspect} schema: #{attributes.map(&:inspect).join(', ')}")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
DEFAULT_ATTRIBUTES = [EMPTY_ARRAY, EMPTY_ARRAY].freeze
|
19
|
+
|
20
|
+
attributes_inferrer -> * { DEFAULT_ATTRIBUTES }
|
21
|
+
|
22
|
+
attr_class Attribute
|
23
|
+
|
24
|
+
include Dry::Equalizer(:options)
|
25
|
+
|
26
|
+
option :attr_class, default: -> { self.class.attr_class }
|
27
|
+
|
28
|
+
option :enabled, default: -> { true }
|
29
|
+
|
30
|
+
alias_method :enabled?, :enabled
|
31
|
+
|
32
|
+
option :attributes_inferrer, default: -> { self.class.attributes_inferrer }
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def call(schema, gateway)
|
36
|
+
if enabled?
|
37
|
+
inferred, missing = attributes_inferrer.(schema, gateway, options)
|
38
|
+
else
|
39
|
+
inferred, missing = DEFAULT_ATTRIBUTES
|
40
|
+
end
|
41
|
+
|
42
|
+
attributes = merge_attributes(schema.attributes, inferred)
|
43
|
+
|
44
|
+
check_all_attributes_defined(schema, attributes, missing)
|
45
|
+
|
46
|
+
{ attributes: attributes }
|
47
|
+
end
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
def check_all_attributes_defined(schema, all_known, not_inferred)
|
51
|
+
not_defined = not_inferred - all_known.map(&:name)
|
52
|
+
|
53
|
+
if not_defined.size > 0
|
54
|
+
raise MissingAttributesError.new(schema.name, not_defined)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# @api private
|
59
|
+
def merge_attributes(defined, inferred)
|
60
|
+
defined_names = defined.map(&:name)
|
61
|
+
|
62
|
+
defined + inferred.reject { |attr| defined_names.include?(attr.name) }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rom/plugin_base'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
# @api private
|
5
|
+
class SchemaPlugin < PluginBase
|
6
|
+
include Configurable
|
7
|
+
|
8
|
+
# Apply this plugin to the provided configuration
|
9
|
+
#
|
10
|
+
# @param [ROM::Schema] schema A schema instance for extension
|
11
|
+
# @param [Hash] options Extension options
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
def apply_to(schema, options = EMPTY_HASH)
|
15
|
+
mod.apply(schema, options) if mod.respond_to?(:apply)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Extends a DSL instance with a module provided by the plugin
|
19
|
+
#
|
20
|
+
# @param [ROM::Schema::DSL] dsl
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
def extend_dsl(dsl)
|
24
|
+
dsl.extend(mod.const_get(:DSL)) if mod.const_defined?(:DSL)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/rom/setup.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rom/setup/auto_registration'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
class Setup
|
5
|
+
# @return [Array] registered relation subclasses
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
attr_reader :relation_classes
|
9
|
+
|
10
|
+
# @return [Array] registered mapper subclasses
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
attr_reader :mapper_classes
|
14
|
+
|
15
|
+
# @return [Array] registered command subclasses
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
attr_reader :command_classes
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
attr_reader :plugins
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
attr_reader :notifications
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
def initialize(notifications)
|
28
|
+
@relation_classes = []
|
29
|
+
@command_classes = []
|
30
|
+
@mapper_classes = []
|
31
|
+
@plugins = []
|
32
|
+
@notifications = notifications
|
33
|
+
end
|
34
|
+
|
35
|
+
# Relation sub-classes are being registered with this method during setup
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
def register_relation(*klasses)
|
39
|
+
klasses.reduce(@relation_classes, :<<)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Mapper sub-classes are being registered with this method during setup
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
def register_mapper(*klasses)
|
46
|
+
klasses.reduce(@mapper_classes, :<<)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Command sub-classes are being registered with this method during setup
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
def register_command(*klasses)
|
53
|
+
klasses.reduce(@command_classes, :<<)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @api private
|
57
|
+
def register_plugin(plugin)
|
58
|
+
plugins << plugin
|
59
|
+
end
|
60
|
+
|
61
|
+
def auto_registration(directory, options = {})
|
62
|
+
auto_registration = AutoRegistration.new(directory, options)
|
63
|
+
auto_registration.relations.map { |r| register_relation(r) }
|
64
|
+
auto_registration.commands.map { |r| register_command(r) }
|
65
|
+
auto_registration.mappers.map { |r| register_mapper(r) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
require 'dry/core/inflector'
|
4
|
+
|
5
|
+
require 'rom/types'
|
6
|
+
require 'rom/initializer'
|
7
|
+
require 'rom/setup/auto_registration_strategies/no_namespace'
|
8
|
+
require 'rom/setup/auto_registration_strategies/with_namespace'
|
9
|
+
require 'rom/setup/auto_registration_strategies/custom_namespace'
|
10
|
+
|
11
|
+
module ROM
|
12
|
+
class AutoRegistration
|
13
|
+
extend Initializer
|
14
|
+
|
15
|
+
NamespaceType = Types::Strict::Bool | Types::Strict::String
|
16
|
+
PathnameType = Types.Constructor(Pathname, &Kernel.method(:Pathname))
|
17
|
+
DEFAULT_MAPPING = {
|
18
|
+
relations: :relations,
|
19
|
+
mappers: :mappers,
|
20
|
+
commands: :commands
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
param :directory, type: PathnameType
|
24
|
+
|
25
|
+
option :namespace, type: NamespaceType, default: -> { true }
|
26
|
+
|
27
|
+
option :component_dirs, type: Types::Strict::Hash, default: -> { DEFAULT_MAPPING }
|
28
|
+
|
29
|
+
option :globs, default: -> {
|
30
|
+
Hash[
|
31
|
+
component_dirs.map { |component, path|
|
32
|
+
[component, directory.join("#{path}/**/*.rb")]
|
33
|
+
}
|
34
|
+
]
|
35
|
+
}
|
36
|
+
|
37
|
+
def relations
|
38
|
+
load_entities(:relations)
|
39
|
+
end
|
40
|
+
|
41
|
+
def commands
|
42
|
+
load_entities(:commands)
|
43
|
+
end
|
44
|
+
|
45
|
+
def mappers
|
46
|
+
load_entities(:mappers)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def load_entities(entity)
|
52
|
+
Dir[globs[entity]].map do |file|
|
53
|
+
require file
|
54
|
+
klass_name =
|
55
|
+
case namespace
|
56
|
+
when String
|
57
|
+
AutoRegistrationStrategies::CustomNamespace.new(
|
58
|
+
namespace: namespace, file: file, directory: directory
|
59
|
+
).call
|
60
|
+
when TrueClass
|
61
|
+
AutoRegistrationStrategies::WithNamespace.new(
|
62
|
+
file: file, directory: directory
|
63
|
+
).call
|
64
|
+
when FalseClass
|
65
|
+
AutoRegistrationStrategies::NoNamespace.new(
|
66
|
+
file: file, directory: directory, entity: component_dirs.fetch(entity)
|
67
|
+
).call
|
68
|
+
end
|
69
|
+
|
70
|
+
Dry::Core::Inflector.constantize(klass_name)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rom/types'
|
2
|
+
require 'rom/initializer'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module AutoRegistrationStrategies
|
6
|
+
class Base
|
7
|
+
extend Initializer
|
8
|
+
|
9
|
+
PathnameType = Types.Definition(Pathname).constrained(type: Pathname)
|
10
|
+
|
11
|
+
option :file, type: Types::Strict::String
|
12
|
+
|
13
|
+
EXTENSION_REGEX = /\.rb\z/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
require 'dry/core/inflector'
|
4
|
+
require 'rom/types'
|
5
|
+
require 'rom/setup/auto_registration_strategies/base'
|
6
|
+
|
7
|
+
module ROM
|
8
|
+
module AutoRegistrationStrategies
|
9
|
+
class CustomNamespace < Base
|
10
|
+
option :directory, type: PathnameType
|
11
|
+
option :namespace, type: Types::Strict::String
|
12
|
+
|
13
|
+
def call
|
14
|
+
potential = []
|
15
|
+
attempted = []
|
16
|
+
|
17
|
+
path_arr.reverse.each do |dir|
|
18
|
+
const_fragment = potential.unshift(
|
19
|
+
Dry::Core::Inflector.camelize(dir)
|
20
|
+
).join("::")
|
21
|
+
|
22
|
+
constant = "#{namespace}::#{const_fragment}"
|
23
|
+
|
24
|
+
return constant if ns_const.const_defined?(const_fragment)
|
25
|
+
|
26
|
+
attempted << constant
|
27
|
+
end
|
28
|
+
|
29
|
+
# If we have reached this point, its means constant is not defined and
|
30
|
+
# NameError will be thrown if we attempt to camelize something like:
|
31
|
+
# `"#{namespace}::#{Dry::Core::Inflector.camelize(filename)}"`
|
32
|
+
# so we can assume naming convention was not respected in required
|
33
|
+
# file.
|
34
|
+
|
35
|
+
raise NameError, name_error_message(attempted)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def name_error_message(attempted)
|
41
|
+
"required file does not define expected constant name; either " \
|
42
|
+
"register your constant explicitly of try following the path" \
|
43
|
+
"naming convention like:\n\n\t- #{attempted.join("\n\t- ")}\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
def filename
|
47
|
+
Pathname(file).basename('.rb')
|
48
|
+
end
|
49
|
+
|
50
|
+
def ns_const
|
51
|
+
@namespace_constant ||= Dry::Core::Inflector.constantize(namespace)
|
52
|
+
end
|
53
|
+
|
54
|
+
def path_arr
|
55
|
+
file_path << filename
|
56
|
+
end
|
57
|
+
|
58
|
+
def file_path
|
59
|
+
File.dirname(file).split("/") - directory.to_s.split("/")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|