hanami 2.0.0.alpha1 → 2.0.0.alpha5
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 +306 -5
- data/FEATURES.md +9 -1
- data/LICENSE.md +1 -1
- data/README.md +9 -6
- data/hanami.gemspec +12 -11
- data/lib/hanami/application/autoloader/inflector_adapter.rb +22 -0
- data/lib/hanami/application/container/boot/inflector.rb +7 -0
- data/lib/hanami/application/container/boot/logger.rb +7 -0
- data/lib/hanami/application/container/boot/rack_logger.rb +19 -0
- data/lib/hanami/application/container/boot/rack_monitor.rb +12 -0
- data/lib/hanami/application/container/boot/routes_helper.rb +9 -0
- data/lib/hanami/application/container/boot/settings.rb +7 -0
- data/lib/hanami/application/router.rb +59 -0
- data/lib/hanami/application/routes.rb +55 -0
- data/lib/hanami/application/routes_helper.rb +34 -0
- data/lib/hanami/application/routing/middleware/stack.rb +89 -0
- data/lib/hanami/application/routing/resolver/node.rb +50 -0
- data/lib/hanami/application/routing/resolver/trie.rb +59 -0
- data/lib/hanami/application/routing/resolver.rb +87 -0
- data/lib/hanami/application/routing/router.rb +36 -0
- data/lib/hanami/application/settings/dotenv_store.rb +60 -0
- data/lib/hanami/application/settings.rb +93 -0
- data/lib/hanami/application.rb +330 -34
- data/lib/hanami/assets/application_configuration.rb +63 -0
- data/lib/hanami/assets/configuration.rb +54 -0
- data/lib/hanami/boot/source_dirs.rb +44 -0
- data/lib/hanami/boot.rb +1 -2
- data/lib/hanami/cli/application/cli.rb +40 -0
- data/lib/hanami/cli/application/command.rb +47 -0
- data/lib/hanami/cli/application/commands/console.rb +81 -0
- data/lib/hanami/cli/application/commands.rb +16 -0
- data/lib/hanami/cli/base_command.rb +48 -0
- data/lib/hanami/cli/commands/command.rb +4 -4
- data/lib/hanami/cli/commands.rb +3 -2
- data/lib/hanami/configuration/logger.rb +84 -0
- data/lib/hanami/configuration/middleware.rb +4 -4
- data/lib/hanami/configuration/null_configuration.rb +14 -0
- data/lib/hanami/configuration/router.rb +52 -0
- data/lib/hanami/configuration/sessions.rb +5 -5
- data/lib/hanami/configuration/source_dirs.rb +42 -0
- data/lib/hanami/configuration.rb +122 -131
- data/lib/hanami/init.rb +5 -0
- data/lib/hanami/setup.rb +9 -0
- data/lib/hanami/slice.rb +189 -0
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +96 -0
- data/lib/hanami.rb +17 -30
- metadata +116 -50
- data/bin/hanami +0 -8
- data/lib/hanami/configuration/cookies.rb +0 -24
- data/lib/hanami/configuration/security.rb +0 -141
- data/lib/hanami/container.rb +0 -107
- data/lib/hanami/frameworks.rb +0 -28
- data/lib/hanami/routes.rb +0 -31
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Application
|
5
|
+
# Application routes
|
6
|
+
#
|
7
|
+
# Users are expected to inherit from this class to define their application
|
8
|
+
# routes.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # config/routes.rb
|
12
|
+
# # frozen_string_literal: true
|
13
|
+
#
|
14
|
+
# require "hanami/application/routes"
|
15
|
+
#
|
16
|
+
# module MyApp
|
17
|
+
# class Routes < Hanami::Application::Routes
|
18
|
+
# define do
|
19
|
+
# slice :main, at: "/" do
|
20
|
+
# root to: "home.show"
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# See {Hanami::Application::Router} for the syntax allowed within the
|
27
|
+
# `define` block.
|
28
|
+
#
|
29
|
+
# @see Hanami::Application::Router
|
30
|
+
# @since 2.0.0
|
31
|
+
class Routes
|
32
|
+
# Defines application routes
|
33
|
+
#
|
34
|
+
# @yield DSL syntax to define application routes executed in the context
|
35
|
+
# of {Hanami::Application::Router}
|
36
|
+
#
|
37
|
+
# @return [Proc]
|
38
|
+
def self.define(&block)
|
39
|
+
@_routes = block
|
40
|
+
end
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
def self.routes
|
44
|
+
@_routes || raise(<<~MSG)
|
45
|
+
Routes need to be defined before being able to fetch them. E.g.,
|
46
|
+
define do
|
47
|
+
slice :main, at: "/" do
|
48
|
+
root to: "home.show"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
MSG
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Application
|
5
|
+
# Hanami application routes helpers
|
6
|
+
#
|
7
|
+
# An instance of this class gets registered in the container
|
8
|
+
# (`routes_helper` key) once the Hanami application is booted. You can use
|
9
|
+
# it to get the route helpers for your application.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# MyApp::Application["routes_helper"].path(:root) # => "/"
|
13
|
+
#
|
14
|
+
# @see Hanami::Router::UrlHelpers
|
15
|
+
# @since 2.0.0
|
16
|
+
class RoutesHelper
|
17
|
+
# @since 2.0.0
|
18
|
+
# @api private
|
19
|
+
def initialize(router)
|
20
|
+
@router = router
|
21
|
+
end
|
22
|
+
|
23
|
+
# @see Hanami::Router::UrlHelpers#path
|
24
|
+
def path(*args, **kwargs, &block)
|
25
|
+
@router.path(*args, **kwargs, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @see Hanami::Router::UrlHelpers#url
|
29
|
+
def url(*args, **kwargs, &block)
|
30
|
+
@router.url(*args, **kwargs, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack/builder"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
class Application
|
7
|
+
module Routing
|
8
|
+
# Hanami::Applicatione::Router middleware stack
|
9
|
+
#
|
10
|
+
# @since 2.0.0
|
11
|
+
# @api private
|
12
|
+
module Middleware
|
13
|
+
# Middleware stack
|
14
|
+
#
|
15
|
+
# @since 2.0.0
|
16
|
+
# @api private
|
17
|
+
class Stack
|
18
|
+
# @since 2.0.0
|
19
|
+
# @api private
|
20
|
+
ROOT_PREFIX = "/"
|
21
|
+
private_constant :ROOT_PREFIX
|
22
|
+
|
23
|
+
# @since 2.0.0
|
24
|
+
# @api private
|
25
|
+
def initialize
|
26
|
+
@prefix = ROOT_PREFIX
|
27
|
+
@stack = Hash.new { |hash, key| hash[key] = [] }
|
28
|
+
end
|
29
|
+
|
30
|
+
# @since 2.0.0
|
31
|
+
# @api private
|
32
|
+
def use(middleware, *args, &blk)
|
33
|
+
@stack[@prefix].push([middleware, args, blk])
|
34
|
+
end
|
35
|
+
|
36
|
+
# @since 2.0.0
|
37
|
+
# @api private
|
38
|
+
def with(path)
|
39
|
+
prefix = @prefix
|
40
|
+
@prefix = path
|
41
|
+
yield
|
42
|
+
ensure
|
43
|
+
@prefix = prefix
|
44
|
+
end
|
45
|
+
|
46
|
+
# @since 2.0.0
|
47
|
+
# @api private
|
48
|
+
def to_rack_app(app) # rubocop:disable Metrics/MethodLength
|
49
|
+
s = self
|
50
|
+
|
51
|
+
Rack::Builder.new do
|
52
|
+
s.each do |prefix, stack|
|
53
|
+
s.mapped(self, prefix) do
|
54
|
+
stack.each do |middleware, args, blk|
|
55
|
+
use(middleware, *args, &blk)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
run app
|
60
|
+
end
|
61
|
+
end.to_app
|
62
|
+
end
|
63
|
+
|
64
|
+
# @since 2.0.0
|
65
|
+
# @api private
|
66
|
+
def empty?
|
67
|
+
@stack.empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
# @since 2.0.0
|
71
|
+
# @api private
|
72
|
+
def each(&blk)
|
73
|
+
@stack.each(&blk)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @since 2.0.0
|
77
|
+
# @api private
|
78
|
+
def mapped(builder, prefix, &blk)
|
79
|
+
if prefix == ROOT_PREFIX
|
80
|
+
builder.instance_eval(&blk)
|
81
|
+
else
|
82
|
+
builder.map(prefix, &blk)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Application
|
5
|
+
module Routing
|
6
|
+
class Resolver
|
7
|
+
# Endpoint resolver node to register slices in a tree
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
# @since 2.0.0
|
11
|
+
class Node
|
12
|
+
# @api private
|
13
|
+
# @since 2.0.0
|
14
|
+
attr_reader :slice
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
# @since 2.0.0
|
18
|
+
def initialize
|
19
|
+
@slice = nil
|
20
|
+
@children = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
# @since 2.0.0
|
25
|
+
def put(segment)
|
26
|
+
@children[segment] ||= self.class.new
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
# @since 2.0.0
|
31
|
+
def get(segment)
|
32
|
+
@children.fetch(segment) { self if leaf? }
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
# @since 2.0.0
|
37
|
+
def leaf!(slice)
|
38
|
+
@slice = slice
|
39
|
+
end
|
40
|
+
|
41
|
+
# @api private
|
42
|
+
# @since 2.0.0
|
43
|
+
def leaf?
|
44
|
+
@slice
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "hanami/application/routing/resolver/node"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
class Application
|
7
|
+
module Routing
|
8
|
+
class Resolver
|
9
|
+
# Endpoint resolver trie to register slices
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 2.0.0
|
13
|
+
class Trie
|
14
|
+
# @api private
|
15
|
+
# @since 2.0.0
|
16
|
+
def initialize
|
17
|
+
@root = Node.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
# @since 2.0.0
|
22
|
+
def add(path, name)
|
23
|
+
node = @root
|
24
|
+
for_each_segment(path) do |segment|
|
25
|
+
node = node.put(segment)
|
26
|
+
end
|
27
|
+
|
28
|
+
node.leaf!(name)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @api private
|
32
|
+
# @since 2.0.0
|
33
|
+
def find(path)
|
34
|
+
node = @root
|
35
|
+
|
36
|
+
for_each_segment(path) do |segment|
|
37
|
+
break unless node
|
38
|
+
|
39
|
+
node = node.get(segment)
|
40
|
+
end
|
41
|
+
|
42
|
+
return node.slice if node&.leaf?
|
43
|
+
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
# @since 2.0.0
|
51
|
+
def for_each_segment(path, &blk)
|
52
|
+
_, *segments = path.split(/\//)
|
53
|
+
segments.each(&blk)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
class Application
|
5
|
+
module Routing
|
6
|
+
# Hanami application router endpoint resolver
|
7
|
+
#
|
8
|
+
# @since 2.0.0
|
9
|
+
class Resolver
|
10
|
+
ENDPOINT_KEY_NAMESPACE = "actions"
|
11
|
+
|
12
|
+
require_relative "resolver/trie"
|
13
|
+
|
14
|
+
# @since 2.0.0
|
15
|
+
class NotCallableEndpointError < StandardError
|
16
|
+
def initialize(endpoint)
|
17
|
+
super("#{endpoint.inspect} is not compatible with Rack. Please make sure it implements #call.")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
# @since 2.0.0
|
23
|
+
def initialize(slices:, inflector:)
|
24
|
+
@slices = slices
|
25
|
+
@inflector = inflector
|
26
|
+
@slice_registry = Trie.new
|
27
|
+
end
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
# @since 2.0.0
|
31
|
+
#
|
32
|
+
# rubocop:disable Metrics/MethodLength
|
33
|
+
def call(path, identifier)
|
34
|
+
endpoint =
|
35
|
+
case identifier
|
36
|
+
when String
|
37
|
+
resolve_string_identifier(path, identifier)
|
38
|
+
when Class
|
39
|
+
identifier.respond_to?(:call) ? identifier : identifier.new
|
40
|
+
else
|
41
|
+
identifier
|
42
|
+
end
|
43
|
+
|
44
|
+
unless endpoint.respond_to?(:call) # rubocop:disable Style/IfUnlessModifier
|
45
|
+
raise NotCallableEndpointError.new(endpoint)
|
46
|
+
end
|
47
|
+
|
48
|
+
endpoint
|
49
|
+
end
|
50
|
+
# rubocop:enable Metrics/MethodLength
|
51
|
+
|
52
|
+
# @api private
|
53
|
+
# @since 2.0.0
|
54
|
+
def register_slice_at_path(name, path)
|
55
|
+
slice_registry.add(path, name)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# @api private
|
61
|
+
# @since 2.0.0
|
62
|
+
attr_reader :slices
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
# @since 2.0.0
|
66
|
+
attr_reader :inflector
|
67
|
+
|
68
|
+
# @api private
|
69
|
+
# @since 2.0.0
|
70
|
+
attr_reader :slice_registry
|
71
|
+
|
72
|
+
# @api private
|
73
|
+
# @since 2.0.0
|
74
|
+
def resolve_string_identifier(path, identifier)
|
75
|
+
slice_name = slice_registry.find(path) or raise "missing slice for #{path.inspect} (#{identifier.inspect})"
|
76
|
+
slice = slices[slice_name]
|
77
|
+
endpoint_key = "#{ENDPOINT_KEY_NAMESPACE}.#{identifier}"
|
78
|
+
|
79
|
+
# Lazily resolve endpoint from the slice to reduce router initialization time,
|
80
|
+
# and break potential endless loops from the resolved endpoint itself requiring
|
81
|
+
# access to router-related concerns
|
82
|
+
-> (*args) { slice[endpoint_key].call(*args) }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# # frozen_string_literal: true
|
2
|
+
|
3
|
+
# require "hanami/application/router"
|
4
|
+
|
5
|
+
# Hanami.application.register_bootable :router do
|
6
|
+
# start do
|
7
|
+
# configuration = Hanami.application.configuration
|
8
|
+
|
9
|
+
# routes = begin
|
10
|
+
# require File.join(configuration.root, configuration.router.routes_path)
|
11
|
+
# routes_class = Hanami.application.send(:autodiscover_application_constant, configuration.router.routes_class_name) # WIP private
|
12
|
+
# routes_class.routes
|
13
|
+
# rescue LoadError
|
14
|
+
# proc {}
|
15
|
+
# end
|
16
|
+
|
17
|
+
# resolver = configuration.router.resolver.new(
|
18
|
+
# slices: Hanami.application.slices,
|
19
|
+
# inflector: Hanami.application.inflector # TODO: use container[:inflector]?
|
20
|
+
# )
|
21
|
+
|
22
|
+
# router = Hanami::Application::Router.new(
|
23
|
+
# routes: routes,
|
24
|
+
# resolver: resolver,
|
25
|
+
# **configuration.router.options,
|
26
|
+
# ) do
|
27
|
+
# use Hanami.application[:rack_monitor]
|
28
|
+
|
29
|
+
# Hanami.application.config.for_each_middleware do |m, *args, &block|
|
30
|
+
# use(m, *args, &block)
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
|
34
|
+
# register :router, router
|
35
|
+
# end
|
36
|
+
# end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/constants"
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
class Application
|
7
|
+
class Settings
|
8
|
+
# Default application settings store.
|
9
|
+
#
|
10
|
+
# Uses [dotenv](https://github.com/bkeepers/dotenv) (if available) to load
|
11
|
+
# .env files and then loads settings from ENV. For a given `HANAMI_ENV`
|
12
|
+
# environment, the following `.env` files are looked up in the following order:
|
13
|
+
#
|
14
|
+
# - .env.{environment}.local
|
15
|
+
# - .env.local (except if the environment is `test`)
|
16
|
+
# - .env.{environment}
|
17
|
+
# - .env
|
18
|
+
#
|
19
|
+
# @since 2.0.0
|
20
|
+
# @api private
|
21
|
+
class DotenvStore
|
22
|
+
Undefined = Dry::Core::Constants::Undefined
|
23
|
+
|
24
|
+
attr_reader :store,
|
25
|
+
:hanami_env
|
26
|
+
|
27
|
+
def initialize(store: ENV, hanami_env: Hanami.env)
|
28
|
+
@store = store
|
29
|
+
@hanami_env = hanami_env
|
30
|
+
end
|
31
|
+
|
32
|
+
def fetch(name, default_value = Undefined, &block)
|
33
|
+
name = name.to_s.upcase
|
34
|
+
args = (default_value == Undefined) ? [name] : [name, default_value]
|
35
|
+
|
36
|
+
store.fetch(*args, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def with_dotenv_loaded
|
40
|
+
require "dotenv"
|
41
|
+
Dotenv.load(*dotenv_files) if defined?(Dotenv)
|
42
|
+
self
|
43
|
+
rescue LoadError
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def dotenv_files
|
50
|
+
[
|
51
|
+
".env.#{hanami_env}.local",
|
52
|
+
(".env.local" unless hanami_env == :test),
|
53
|
+
".env.#{hanami_env}",
|
54
|
+
".env"
|
55
|
+
].compact
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require "dry/core/constants"
|
5
|
+
|
6
|
+
module Hanami
|
7
|
+
class Application
|
8
|
+
# Application settings
|
9
|
+
#
|
10
|
+
# Users are expected to inherit from this class to define their application
|
11
|
+
# settings.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# # config/settings.rb
|
15
|
+
# # frozen_string_literal: true
|
16
|
+
#
|
17
|
+
# require "hanami/application/settings"
|
18
|
+
# require "my_app/types"
|
19
|
+
#
|
20
|
+
# module MyApp
|
21
|
+
# class Settings < Hanami::Application::Settings
|
22
|
+
# setting :database_url
|
23
|
+
# setting :feature_flag, default: false, constructor: Types::Params::Bool
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# Settings are defined with
|
28
|
+
# [dry-configurable](https://dry-rb.org/gems/dry-configurable/), so you can
|
29
|
+
# take a look there to see the supported syntax.
|
30
|
+
#
|
31
|
+
# Users work with an instance of this class made available within the
|
32
|
+
# `settings` key in the container. The instance gets its settings populated
|
33
|
+
# from a configurable store, which defaults to
|
34
|
+
# {Hanami::Application::Settings::DotenvStore}.
|
35
|
+
#
|
36
|
+
# A different store can be set through the `settings_store` Hanami
|
37
|
+
# configuration option. All it needs to do is implementing a `#fetch` method
|
38
|
+
# with the same signature as `Hash#fetch`.
|
39
|
+
#
|
40
|
+
# @see Hanami::Application::Settings::DotenvStore
|
41
|
+
# @since 2.0.0
|
42
|
+
class Settings
|
43
|
+
# Exception for errors in the definition of settings.
|
44
|
+
#
|
45
|
+
# Its message collects all the individual errors that can be raised for
|
46
|
+
# each setting.
|
47
|
+
InvalidSettingsError = Class.new(StandardError) do
|
48
|
+
def initialize(errors)
|
49
|
+
@errors = errors
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
<<~STR.strip
|
54
|
+
Could not initialize settings. The following settings were invalid:
|
55
|
+
|
56
|
+
#{@errors.map { |setting, message| "#{setting}: #{message}" }.join("\n")}
|
57
|
+
STR
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# @api private
|
62
|
+
EMPTY_STORE = Dry::Core::Constants::EMPTY_HASH
|
63
|
+
|
64
|
+
include Dry::Configurable
|
65
|
+
|
66
|
+
# @api private
|
67
|
+
def initialize(store = EMPTY_STORE)
|
68
|
+
errors = config._settings.map(&:name).reduce({}) do |errs, name|
|
69
|
+
public_send("#{name}=", store.fetch(name) { Dry::Core::Constants::Undefined })
|
70
|
+
errs
|
71
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
72
|
+
errs.merge(name => e)
|
73
|
+
end
|
74
|
+
|
75
|
+
raise InvalidSettingsError, errors if errors.any?
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def method_missing(name, *args, &block)
|
81
|
+
if config.respond_to?(name)
|
82
|
+
config.send(name, *args, &block)
|
83
|
+
else
|
84
|
+
super
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def respond_to_missing?(name, _include_all = false)
|
89
|
+
config.respond_to?(name) || super
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|