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,20 @@
|
|
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 NoNamespace < Base
|
10
|
+
option :directory, type: PathnameType
|
11
|
+
option :entity, type: Types::Strict::Symbol
|
12
|
+
|
13
|
+
def call
|
14
|
+
Dry::Core::Inflector.camelize(
|
15
|
+
file.sub(/^#{directory}\/#{entity}\//, '').sub(EXTENSION_REGEX, '')
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
require 'dry/core/inflector'
|
4
|
+
require 'rom/setup/auto_registration_strategies/base'
|
5
|
+
|
6
|
+
module ROM
|
7
|
+
module AutoRegistrationStrategies
|
8
|
+
class WithNamespace < Base
|
9
|
+
option :directory, type: PathnameType
|
10
|
+
|
11
|
+
def call
|
12
|
+
Dry::Core::Inflector.camelize(
|
13
|
+
file.sub(/^#{directory.dirname}\//, '').sub(EXTENSION_REGEX, '')
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'rom/relation'
|
2
|
+
require 'rom/command'
|
3
|
+
|
4
|
+
require 'rom/registry'
|
5
|
+
require 'rom/command_registry'
|
6
|
+
require 'rom/mapper_registry'
|
7
|
+
|
8
|
+
require 'rom/container'
|
9
|
+
require 'rom/setup/finalize/finalize_commands'
|
10
|
+
require 'rom/setup/finalize/finalize_relations'
|
11
|
+
require 'rom/setup/finalize/finalize_mappers'
|
12
|
+
|
13
|
+
# temporary
|
14
|
+
require 'rom/configuration_dsl/relation'
|
15
|
+
|
16
|
+
module ROM
|
17
|
+
# This giant builds an container using defined classes for core parts of ROM
|
18
|
+
#
|
19
|
+
# It is used by the setup object after it's done gathering class definitions
|
20
|
+
#
|
21
|
+
# @private
|
22
|
+
class Finalize
|
23
|
+
attr_reader :gateways, :repo_adapter,
|
24
|
+
:relation_classes, :mapper_classes, :mapper_objects,
|
25
|
+
:command_classes, :plugins, :config, :notifications
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def initialize(options)
|
29
|
+
@gateways = options.fetch(:gateways)
|
30
|
+
|
31
|
+
@relation_classes = options.fetch(:relation_classes)
|
32
|
+
@command_classes = options.fetch(:command_classes)
|
33
|
+
|
34
|
+
mappers = options.fetch(:mappers, [])
|
35
|
+
@mapper_classes = mappers.select { |mapper| mapper.is_a?(Class) }
|
36
|
+
@mapper_objects = (mappers - @mapper_classes).reduce(:merge) || {}
|
37
|
+
|
38
|
+
@config = options.fetch(:config)
|
39
|
+
@notifications = options.fetch(:notifications)
|
40
|
+
|
41
|
+
@plugins = options.fetch(:plugins)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return adapter identifier for a given gateway object
|
45
|
+
#
|
46
|
+
# @return [Symbol]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
def adapter_for(gateway)
|
50
|
+
gateways[gateway].adapter
|
51
|
+
end
|
52
|
+
|
53
|
+
# Run the finalization process
|
54
|
+
#
|
55
|
+
# This creates relations, mappers and commands
|
56
|
+
#
|
57
|
+
# @return [Container]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
def run!
|
61
|
+
mappers = load_mappers
|
62
|
+
relations = load_relations(mappers)
|
63
|
+
commands = load_commands(relations)
|
64
|
+
|
65
|
+
container = Container.new(gateways, relations, mappers, commands)
|
66
|
+
container.freeze
|
67
|
+
container
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
# Build entire relation registry from all known relation subclasses
|
73
|
+
#
|
74
|
+
# This includes both classes created via DSL and explicit definitions
|
75
|
+
#
|
76
|
+
# @api private
|
77
|
+
def load_relations(mappers)
|
78
|
+
global_plugins = plugins.select { |p| p.relation? || p.schema? }
|
79
|
+
|
80
|
+
FinalizeRelations.new(
|
81
|
+
gateways,
|
82
|
+
relation_classes,
|
83
|
+
mappers: mappers,
|
84
|
+
plugins: global_plugins,
|
85
|
+
notifications: notifications
|
86
|
+
).run!
|
87
|
+
end
|
88
|
+
|
89
|
+
# @api private
|
90
|
+
def load_mappers
|
91
|
+
FinalizeMappers.new(mapper_classes, mapper_objects).run!
|
92
|
+
end
|
93
|
+
|
94
|
+
# Build entire command registries
|
95
|
+
#
|
96
|
+
# This includes both classes created via DSL and explicit definitions
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
def load_commands(relations)
|
100
|
+
FinalizeCommands.new(relations, gateways, command_classes, notifications).run!
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rom/registry'
|
2
|
+
require 'rom/command_compiler'
|
3
|
+
require 'rom/command_registry'
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
class Finalize
|
7
|
+
class FinalizeCommands
|
8
|
+
attr_reader :notifications
|
9
|
+
|
10
|
+
# Build command registry hash for provided relations
|
11
|
+
#
|
12
|
+
# @param [RelationRegistry] relations registry
|
13
|
+
# @param [Hash] gateways
|
14
|
+
# @param [Array] command_classes a list of command subclasses
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def initialize(relations, gateways, command_classes, notifications)
|
18
|
+
@relations = relations
|
19
|
+
@gateways = gateways
|
20
|
+
@command_classes = command_classes
|
21
|
+
@notifications = notifications
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Hash]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def run!
|
28
|
+
commands = @command_classes.map do |klass|
|
29
|
+
relation = @relations[klass.relation]
|
30
|
+
gateway = @gateways[relation.gateway]
|
31
|
+
|
32
|
+
notifications.trigger(
|
33
|
+
'configuration.commands.class.before_build',
|
34
|
+
command: klass, gateway: gateway, dataset: relation.dataset
|
35
|
+
)
|
36
|
+
|
37
|
+
klass.extend_for_relation(relation) if klass.restrictable
|
38
|
+
|
39
|
+
klass.build(relation)
|
40
|
+
end
|
41
|
+
|
42
|
+
registry = Registry.new({})
|
43
|
+
compiler = CommandCompiler.new(@gateways, @relations, registry, notifications)
|
44
|
+
|
45
|
+
@relations.each do |(name, relation)|
|
46
|
+
commands.
|
47
|
+
select { |c| c.relation.name == relation.name }.
|
48
|
+
each { |c| relation.commands.elements[c.class.register_as || c.class.default_name] = c }
|
49
|
+
|
50
|
+
relation.commands.set_compiler(compiler)
|
51
|
+
relation.commands.set_mappers(relation.mappers)
|
52
|
+
|
53
|
+
registry.elements[name] = relation.commands
|
54
|
+
end
|
55
|
+
|
56
|
+
registry
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rom/registry'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
class Finalize
|
5
|
+
class FinalizeMappers
|
6
|
+
attr_reader :mapper_classes, :mapper_objects, :registry_hash
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
def initialize(mapper_classes, mapper_objects)
|
10
|
+
@mapper_classes = mapper_classes
|
11
|
+
@mapper_objects = mapper_objects
|
12
|
+
|
13
|
+
check_duplicate_registered_mappers
|
14
|
+
|
15
|
+
@registry_hash = [@mapper_classes.map(&:base_relation) + @mapper_objects.keys].
|
16
|
+
flatten.
|
17
|
+
uniq.
|
18
|
+
each_with_object({}) { |n, h| h[n] = {} }
|
19
|
+
end
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
def run!
|
23
|
+
mappers = registry_hash.each_with_object({}) do |(relation_name, relation_mappers), h|
|
24
|
+
relation_mappers.update(build_mappers(relation_name))
|
25
|
+
|
26
|
+
if mapper_objects.key?(relation_name)
|
27
|
+
relation_mappers.update(mapper_objects[relation_name])
|
28
|
+
end
|
29
|
+
|
30
|
+
h[relation_name] = MapperRegistry.new(relation_mappers)
|
31
|
+
end
|
32
|
+
|
33
|
+
Registry.new(mappers)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def check_duplicate_registered_mappers
|
39
|
+
mappers_register_as = mapper_classes.map(&:register_as).compact
|
40
|
+
mappers_register_as.select { |register_as| mappers_register_as.count(register_as) > 1 }
|
41
|
+
.uniq
|
42
|
+
.each do |duplicated_mappers|
|
43
|
+
raise MapperAlreadyDefinedError,
|
44
|
+
"Mapper with `register_as #{duplicated_mappers.inspect}` registered more " \
|
45
|
+
"than once"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_mappers(relation_name)
|
50
|
+
mapper_classes.
|
51
|
+
select { |klass| klass.base_relation == relation_name }.
|
52
|
+
each_with_object({}) { |klass, h| h[klass.register_as || klass.relation] = klass.build }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'rom/constants'
|
2
|
+
require 'rom/relation_registry'
|
3
|
+
require 'rom/mapper_registry'
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
class Finalize
|
7
|
+
class FinalizeRelations
|
8
|
+
attr_reader :notifications
|
9
|
+
|
10
|
+
# Build relation registry of specified descendant classes
|
11
|
+
#
|
12
|
+
# This is used by the setup
|
13
|
+
#
|
14
|
+
# @param [Hash] gateways
|
15
|
+
# @param [Array] relation_classes a list of relation descendants
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
def initialize(gateways, relation_classes, notifications:, mappers: nil, plugins: EMPTY_ARRAY)
|
19
|
+
@gateways = gateways
|
20
|
+
@relation_classes = relation_classes
|
21
|
+
@mappers = mappers
|
22
|
+
@plugins = plugins
|
23
|
+
@notifications = notifications
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Hash]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
def run!
|
30
|
+
relation_registry = RelationRegistry.new do |registry, relations|
|
31
|
+
@relation_classes.each do |klass|
|
32
|
+
unless klass.adapter
|
33
|
+
raise MissingAdapterIdentifierError,
|
34
|
+
"Relation class +#{klass}+ is missing the adapter identifier"
|
35
|
+
end
|
36
|
+
|
37
|
+
key = klass.relation_name.to_sym
|
38
|
+
|
39
|
+
if registry.key?(key)
|
40
|
+
raise RelationAlreadyDefinedError,
|
41
|
+
"Relation with name #{key.inspect} registered more than once"
|
42
|
+
end
|
43
|
+
|
44
|
+
klass.use(:registry_reader, relation_names)
|
45
|
+
|
46
|
+
notifications.trigger('configuration.relations.class.ready', relation: klass)
|
47
|
+
|
48
|
+
relations[key] = build_relation(klass, registry)
|
49
|
+
end
|
50
|
+
|
51
|
+
registry.each do |_, relation|
|
52
|
+
notifications.trigger(
|
53
|
+
'configuration.relations.object.registered',
|
54
|
+
relation: relation, registry: registry
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
notifications.trigger(
|
60
|
+
'configuration.relations.registry.created', registry: relation_registry
|
61
|
+
)
|
62
|
+
|
63
|
+
relation_registry
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [ROM::Relation]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
def build_relation(klass, registry)
|
70
|
+
# TODO: raise a meaningful error here and add spec covering the case
|
71
|
+
# where klass' gateway points to non-existant repo
|
72
|
+
gateway = @gateways.fetch(klass.gateway)
|
73
|
+
|
74
|
+
if klass.schema_proc && !klass.schema
|
75
|
+
plugins = schema_plugins
|
76
|
+
|
77
|
+
resolved_schema = klass.schema_proc.call do
|
78
|
+
plugins.each { |plugin| app_plugin(plugin) }
|
79
|
+
end
|
80
|
+
|
81
|
+
klass.set_schema!(resolved_schema)
|
82
|
+
end
|
83
|
+
|
84
|
+
notifications.trigger(
|
85
|
+
'configuration.relations.schema.allocated',
|
86
|
+
schema: klass.schema, gateway: gateway, registry: registry
|
87
|
+
)
|
88
|
+
|
89
|
+
relation_plugins.each do |plugin|
|
90
|
+
plugin.apply_to(klass)
|
91
|
+
end
|
92
|
+
|
93
|
+
notifications.trigger(
|
94
|
+
'configuration.relations.schema.set',
|
95
|
+
schema: resolved_schema, relation: klass, adapter: klass.adapter
|
96
|
+
)
|
97
|
+
|
98
|
+
schema = klass.schema
|
99
|
+
rel_key = schema.name.to_sym
|
100
|
+
dataset = gateway.dataset(schema.name.dataset).instance_exec(klass, &klass.dataset)
|
101
|
+
|
102
|
+
notifications.trigger(
|
103
|
+
'configuration.relations.dataset.allocated',
|
104
|
+
dataset: dataset, relation: klass, adapter: klass.adapter
|
105
|
+
)
|
106
|
+
|
107
|
+
mappers = @mappers.key?(rel_key) ? @mappers[rel_key] : MapperRegistry.new
|
108
|
+
|
109
|
+
options = { __registry__: registry, mappers: mappers, schema: schema, **plugin_options }
|
110
|
+
|
111
|
+
klass.new(dataset, options)
|
112
|
+
end
|
113
|
+
|
114
|
+
# @api private
|
115
|
+
def plugin_options
|
116
|
+
relation_plugins.map(&:config).map(&:to_hash).reduce(:merge) || EMPTY_HASH
|
117
|
+
end
|
118
|
+
|
119
|
+
# @api private
|
120
|
+
def relation_plugins
|
121
|
+
@plugins.select(&:relation?)
|
122
|
+
end
|
123
|
+
|
124
|
+
# @api private
|
125
|
+
def schema_plugins
|
126
|
+
@plugins.select(&:schema?)
|
127
|
+
end
|
128
|
+
|
129
|
+
# @api private
|
130
|
+
def relation_names
|
131
|
+
@relation_classes.map(&:relation_name).map(&:relation).uniq
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module ROM
|
2
|
+
# @api private
|
3
|
+
module Configurable
|
4
|
+
class Config
|
5
|
+
WRITER_REGEXP = /=$/.freeze
|
6
|
+
|
7
|
+
attr_reader :settings
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
def initialize(settings = {})
|
11
|
+
@settings = settings
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api public
|
15
|
+
def [](name)
|
16
|
+
public_send(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def key?(name)
|
21
|
+
settings.key?(name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_hash
|
25
|
+
settings
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def freeze
|
30
|
+
settings.each_value(&:freeze)
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def respond_to_missing?(_name, _include_private = false)
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def dup
|
40
|
+
self.class.new(dup_settings(settings))
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def dup_settings(settings)
|
46
|
+
settings.each_with_object({}) do |(key, value), new_settings|
|
47
|
+
if value.is_a?(self.class)
|
48
|
+
new_settings[key] = value.dup
|
49
|
+
else
|
50
|
+
new_settings[key] = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
def method_missing(meth, *args, &_block)
|
57
|
+
return settings.fetch(meth, nil) if frozen?
|
58
|
+
|
59
|
+
name = meth.to_s
|
60
|
+
key = name.gsub(WRITER_REGEXP, '').to_sym
|
61
|
+
|
62
|
+
if writer?(name)
|
63
|
+
settings[key] = args.first
|
64
|
+
else
|
65
|
+
settings.fetch(key) { settings[key] = self.class.new }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# @api private
|
70
|
+
def writer?(name)
|
71
|
+
!WRITER_REGEXP.match(name).nil?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def config
|
76
|
+
@config ||= Config.new
|
77
|
+
end
|
78
|
+
|
79
|
+
# @api public
|
80
|
+
def configure
|
81
|
+
yield(config)
|
82
|
+
self
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|