hanami 2.0.0.alpha2 → 2.0.0.alpha3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee3c6a367cfd05f2b18ae080da80b75a08a8680bd922ac8b00433e0c59f53f2b
4
- data.tar.gz: 2de0d4102bf80606d130c04d83716370fe2c1c985986cd034ce232ff08e9be61
3
+ metadata.gz: f322cd4a751d83369d2d20f0f209bfb1dca92a78f6a3dd7c4027ea672df84e36
4
+ data.tar.gz: 801be572c3df6e61bfaee8b72f0a164dcbe83216f33c72972c67334f9b2619cf
5
5
  SHA512:
6
- metadata.gz: a7d143ccf35f088d91fa1702d40b5aac22b3cada72cf566b239403d97fdd22b0839f93a1c20286853ae440ea4898902605b0bfbd3b05854f149de98ef9a78a83
7
- data.tar.gz: 8f512b014ed54456df5beb0d3ecccbe260f0186d3ebfba7fb2fc51f9d80956b511ab87e08e1149dd2dd02d94939a1b260059f2cfcaa1ee34ca6681aee1408434
6
+ metadata.gz: 244ab662705c248857bc4d4e3f42b1de6dc92003fb3c8fe6d3cd006194be272d1aac36f570baa319a971dfcdd6f24eb691c270fa57b852fdbc4da863bc1908d1
7
+ data.tar.gz: 3d6b72d227de112fbedefb7f8f6fbcb1e010fb37bf3d97e5826b6fe134dc0facd2a36bba0ad5e2118f731ee2bb1d18ae4f7307377c0fd31e5b81a3e307c56ae0
data/CHANGELOG.md CHANGED
@@ -1,6 +1,53 @@
1
1
  # Hanami
2
2
  The web, with simplicity.
3
3
 
4
+ ## v2.0.0.alpha3 - 2021-11-09
5
+ ### Added
6
+ - [Luca Guidi] Added `Hanami.shutdown` to stop all bootable components in the application container
7
+ - [Tim Riley] Added `component_dir_paths` application setting to allow for components to be loaded from additional directories inside each slice directory. To begin with, this defaults to `%w[actions repositories views]`. Components inside these directories are expected to be namespaced to match the directory name; e.g. given a `main` slice, `slices/main/actions/home.rb` is expected to define `Main::Actions::Home`, and will be registered in the slice container as `"actions.home"`.
8
+
9
+ ### Changed
10
+ - [Tim Riley] A slice's classes can now be defined directly inside `slices/[slice_name]/lib/`; e.g. given a `main` slice, `slices/main/lib/example.rb` is expected to define `Main::Example`, and will be registered in the slice container as `"example"`
11
+ - [Tim Riley] The root `lib/` directory is no longer configured as a component dir, and classes inside `lib/[app_namespace]/` will no longer be auto-registered into the container. If you need to share components, create them in their own slices as appropriate, and import those slices into the other slices that require them.
12
+ - [Tim Riley] `lib/[app_namespace]/` is configured for autoloading, and `lib/` is added to `$LOAD_PATH` to support explicit requires for source files outside `lib/[app_namespace]/`.
13
+ - [Tim Riley] (Internal) Ported `Hanami::Configuration` and related classes to use dry-configurable
14
+ - [Tim Riley] Application inflector can be entirely replaced, if required, via `Hanami::Configuration#inflector=`. Custom inflection rules can still be provided to the default inflector via `Hanami::Configuration#inflections`.
15
+ - [Marc Busqué] App settings are defined within a concrete class rather than an anonymous block, to allow for users to leverage the typical behavior of Ruby classes, such as for defining their own types module to use for coercing setting values. This class also relies on dry-configurable for its settings implementation, so the standard dry-configurable `setting` API is available, such as the `constructor:` and `default:` options.
16
+ ```ruby
17
+ # frozen_string_literal: true
18
+
19
+ require "dry/types"
20
+ require "hanami/application/settings"
21
+
22
+ module TestApp
23
+ class Settings < Hanami::Application::Settings
24
+ # Example usage of a types module (previously not possible inside the anonymous block)
25
+ Types = Dry.Types()
26
+
27
+ setting :session_secret, constructor: Types::String.constrained(min_size: 20)
28
+
29
+ setting :some_bool, constructor: Types::Params::Bool, default: false
30
+ end
31
+ end
32
+ ```
33
+ - [Marc Busqué] Application `settings_loader` and `settings_loader_options` have been replaced with `settings_store`, which is an updated abstraction for providing setting values to work with the new `Hanami::Application::Settings` implementation noted above (see `Application::Settings::DotenvStore` for the default store, which provides the same behavior as previously)
34
+ - [Marc Busqué] Routes are defined within a concrete class rather than an anonymous block, to provide consistency with the settings (noted above), as well a place for additional behavior (in future releases):
35
+ ```ruby
36
+ # frozen_string_literal: true
37
+
38
+ require "hanami/application/routes"
39
+
40
+ module MyApp
41
+ class Routes < Hanami::Application::Routes
42
+ define do
43
+ slice :main, at: "/" do
44
+ root to: "home.show"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ ```
50
+
4
51
  ## v2.0.0.alpha2 - 2021-05-04
5
52
  ### Added
6
53
  - [Luca Guidi] Official support for Ruby: MRI 3.0
data/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  The web, with simplicity.
4
4
 
5
+ ## Version
6
+
7
+ **This branch contains the code for `hanami` 2.0.x.**
8
+
5
9
  ## Frameworks
6
10
 
7
11
  Hanami is a **full-stack** Ruby web framework.
@@ -25,8 +29,8 @@ These components are designed to be used independently or together in a Hanami a
25
29
  ## Status
26
30
 
27
31
  [![Gem Version](https://badge.fury.io/rb/hanami.svg)](https://badge.fury.io/rb/hanami)
28
- [![CI](https://github.com/hanami/hanami/workflows/ci/badge.svg?branch=unstable)](https://github.com/hanami/hanami/actions?query=workflow%3Aci+branch%3Aunstable)
29
- [![Test Coverage](https://codecov.io/gh/hanami/hanami/branch/unstable/graph/badge.svg)](https://codecov.io/gh/hanami/hanami)
32
+ [![CI](https://github.com/hanami/hanami/workflows/ci/badge.svg?branch=main)](https://github.com/hanami/hanami/actions?query=workflow%3Aci+branch%3Amain)
33
+ [![Test Coverage](https://codecov.io/gh/hanami/hanami/branch/main/graph/badge.svg)](https://codecov.io/gh/hanami/hanami)
30
34
  [![Depfu](https://badges.depfu.com/badges/ba000e0f69e6ef1c44cd3038caaa1841/overview.svg)](https://depfu.com/github/hanami/hanami?project=Bundler)
31
35
  [![Inline Docs](http://inch-ci.org/github/hanami/hanami.svg)](http://inch-ci.org/github/hanami/hanami)
32
36
 
data/hanami.gemspec CHANGED
@@ -22,10 +22,11 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
22
22
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
23
23
 
24
24
  spec.add_dependency "bundler", ">= 1.16", "< 3"
25
+ spec.add_dependency "dry-configurable", "~> 0.12", ">= 0.12.1"
25
26
  spec.add_dependency "dry-core", "~> 0.4"
26
- spec.add_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
27
+ spec.add_dependency "dry-inflector", "~> 0.2", ">= 0.2.1"
27
28
  spec.add_dependency "dry-monitor"
28
- spec.add_dependency "dry-system", "~> 0.19", ">= 0.19.0"
29
+ spec.add_dependency "dry-system", "~> 0.19", ">= 0.21.0"
29
30
  spec.add_dependency "hanami-cli", "~> 2.0.alpha"
30
31
  spec.add_dependency "hanami-utils", "~> 2.0.alpha"
31
32
  spec.add_dependency "zeitwerk", "~> 2.4"
@@ -2,7 +2,6 @@
2
2
 
3
3
  Hanami.application.register_bootable :logger do
4
4
  start do
5
- require "hanami/logger"
6
- register :logger, Hanami::Logger.new(**Hanami.application.configuration.logger)
5
+ register :logger, Hanami.application.configuration.logger_instance
7
6
  end
8
7
  end
@@ -9,7 +9,7 @@ Hanami.application.register_bootable :rack_logger do |container|
9
9
 
10
10
  rack_logger = Hanami::Web::RackLogger.new(
11
11
  container[:logger],
12
- filter_params: Hanami.application.configuration.rack_logger_filter_params
12
+ filter_params: Hanami.application.configuration.logger.filter_params
13
13
  )
14
14
 
15
15
  rack_logger.attach container[:rack_monitor]
@@ -0,0 +1,54 @@
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
+ # @returns [Proc]
37
+ def self.define(&block)
38
+ @_routes = block
39
+ end
40
+
41
+ # @api private
42
+ def self.routes
43
+ @_routes || raise(<<~MSG)
44
+ Routes need to be defined before being able to fetch them. E.g.,
45
+ define do
46
+ slice :main, at: "/" do
47
+ root to: "home.show"
48
+ end
49
+ end
50
+ MSG
51
+ end
52
+ end
53
+ end
54
+ end
@@ -72,7 +72,7 @@ module Hanami
72
72
  def resolve_string_identifier(path, identifier)
73
73
  slice_name = slices_registry.find(path) or raise "missing slice for #{path.inspect} (#{identifier.inspect})"
74
74
  slice = slices[slice_name]
75
- action_key = "actions.#{identifier.gsub(/[#\/]/, '.')}"
75
+ action_key = "actions.#{identifier}"
76
76
 
77
77
  slice[action_key]
78
78
  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
@@ -1,22 +1,92 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/configurable"
3
4
  require "dry/core/constants"
4
- require_relative "settings/definition"
5
- require_relative "settings/struct"
6
5
 
7
6
  module Hanami
8
7
  class Application
9
8
  # Application settings
10
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
11
41
  # @since 2.0.0
12
- module Settings
13
- Undefined = Dry::Core::Constants::Undefined
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
14
74
 
15
- def self.build(loader, loader_options, &definition_block)
16
- definition = Definition.new(&definition_block)
17
- settings = loader.new(**loader_options).call(definition.settings)
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
18
87
 
19
- Struct[settings.keys].new(settings)
88
+ def respond_to_missing?(name, _include_all = false)
89
+ config.respond_to?(name) || super
20
90
  end
21
91
  end
22
92
  end
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/system/container"
4
+ require "dry/system/loader/autoloading"
4
5
  require "hanami/configuration"
5
6
  require "pathname"
6
7
  require "rack"
8
+ require "zeitwerk"
7
9
  require_relative "slice"
8
10
  require_relative "application/autoloader/inflector_adapter"
11
+ require_relative "application/routes"
9
12
  require_relative "application/settings"
10
13
 
11
14
  module Hanami
@@ -52,7 +55,10 @@ module Hanami
52
55
  def init # rubocop:disable Metrics/MethodLength
53
56
  return self if inited?
54
57
 
55
- configuration.finalize
58
+ configuration.finalize!
59
+
60
+ @autoloader = Zeitwerk::Loader.new
61
+ autoloader.inflector = Autoloader::InflectorAdapter.new(inflector)
56
62
 
57
63
  load_settings
58
64
 
@@ -63,10 +69,7 @@ module Hanami
63
69
  slices.values.each(&:init)
64
70
  slices.freeze
65
71
 
66
- if configuration.autoloader
67
- configuration.autoloader.inflector = Autoloader::InflectorAdapter.new(inflector)
68
- configuration.autoloader.setup
69
- end
72
+ autoloader.setup
70
73
 
71
74
  load_routes
72
75
 
@@ -78,6 +81,12 @@ module Hanami
78
81
  @inited
79
82
  end
80
83
 
84
+ def autoloader
85
+ raise "Application not init'ed" unless defined?(@autoloader)
86
+
87
+ @autoloader
88
+ end
89
+
81
90
  def container
82
91
  raise "Application not init'ed" unless defined?(@container)
83
92
 
@@ -151,32 +160,17 @@ module Hanami
151
160
  @booted
152
161
  end
153
162
 
154
- def settings(&block) # rubocop:disable Metrics/MethodLength
155
- if block
156
- @_settings = Application::Settings.build(
157
- configuration.settings_loader,
158
- configuration.settings_loader_options,
159
- &block
160
- )
161
- elsif instance_variable_defined?(:@_settings)
162
- @_settings
163
- else
164
- # Load settings lazily so they can be used to configure the
165
- # Hanami::Application subclass (before the application has inited)
166
- load_settings
167
- @_settings ||= nil
168
- end
163
+ def shutdown
164
+ container.shutdown!
169
165
  end
170
166
 
171
- def routes(&block)
172
- @_mutex.synchronize do
173
- if block.nil?
174
- raise "Hanami.application.routes not configured" unless defined?(@_routes)
167
+ def settings
168
+ @_settings ||= load_settings
169
+ end
175
170
 
176
- @_routes
177
- else
178
- @_routes = block
179
- end
171
+ def routes
172
+ @_mutex.synchronize do
173
+ @_routes ||= load_routes
180
174
  end
181
175
  end
182
176
 
@@ -187,6 +181,10 @@ module Hanami
187
181
  inflector.constantize(name.split(MODULE_DELIMITER)[0..-2].join(MODULE_DELIMITER))
188
182
  end
189
183
 
184
+ def namespace_name
185
+ namespace.name
186
+ end
187
+
190
188
  def namespace_path
191
189
  inflector.underscore(namespace)
192
190
  end
@@ -256,21 +254,19 @@ module Hanami
256
254
  Pathname(__dir__).join("application/container/boot").realpath,
257
255
  ]
258
256
 
259
- if configuration.autoloader
260
- require "dry/system/loader/autoloading"
261
- config.component_dirs.loader = Dry::System::Loader::Autoloading
262
- config.component_dirs.add_to_load_path = false
263
- end
264
-
265
- if root.join("lib").directory?
266
- config.component_dirs.add "lib" do |dir|
267
- dir.default_namespace = application_name.to_s
268
- end
257
+ config.component_dirs.loader = Dry::System::Loader::Autoloading
258
+ config.component_dirs.add_to_load_path = false
259
+ end
269
260
 
270
- configuration.autoloader&.push_dir(root.join("lib"))
271
- end
261
+ # Autoload classes defined in lib/[app_namespace]/
262
+ if root.join("lib", namespace_path).directory?
263
+ autoloader.push_dir(root.join("lib", namespace_path), namespace: namespace)
272
264
  end
273
265
 
266
+ # Add lib/ to to the $LOAD_PATH so other files there (outside the app namespace)
267
+ # are require-able
268
+ container.add_to_load_path!("lib") if root.join("lib").directory?
269
+
274
270
  container
275
271
  end
276
272
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
@@ -317,14 +313,23 @@ module Hanami
317
313
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
318
314
 
319
315
  def load_routes
320
- require File.join(configuration.root, configuration.router.routes)
316
+ require File.join(configuration.root, configuration.router.routes_path)
317
+ routes_class = autodiscover_application_constant(configuration.router.routes_class_name)
318
+ routes_class.routes
321
319
  rescue LoadError # rubocop:disable Lint/SuppressedException
322
320
  end
323
321
 
324
322
  def load_settings
325
323
  prepare_base_load_path
326
324
  require File.join(configuration.root, configuration.settings_path)
327
- rescue LoadError # rubocop:disable Lint/SuppressedException
325
+ settings_class = autodiscover_application_constant(configuration.settings_class_name)
326
+ settings_class.new(configuration.settings_store)
327
+ rescue LoadError
328
+ Settings.new
329
+ end
330
+
331
+ def autodiscover_application_constant(constants)
332
+ inflector.constantize([namespace_name, *constants].join(MODULE_DELIMITER))
328
333
  end
329
334
  end
330
335
  # rubocop:enable Metrics/ModuleLength
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+ require "hanami/logger"
5
+
6
+ module Hanami
7
+ class Configuration
8
+ # Hanami logger configuration
9
+ #
10
+ # @since 2.0.0
11
+ class Logger
12
+ include Dry::Configurable
13
+
14
+ protected :config
15
+
16
+ setting :logger_class, default: Hanami::Logger
17
+
18
+ setting :options, default: {level: :debug}
19
+
20
+ # Currently used for logging of Rack requests only.
21
+ #
22
+ # TODO: incorporate this into the standard logging some way or another
23
+ setting :filter_params, default: %w[_csrf password password_confirmation].freeze
24
+
25
+ private
26
+
27
+ def method_missing(name, *args, &block)
28
+ if config.respond_to?(name)
29
+ config.public_send(name, *args, &block)
30
+ else
31
+ super
32
+ end
33
+ end
34
+
35
+ def respond_to_missing?(name, _incude_all = false)
36
+ config.respond_to?(name) || super
37
+ end
38
+ end
39
+ end
40
+ end
@@ -6,6 +6,8 @@ module Hanami
6
6
  #
7
7
  # @since 2.0.0
8
8
  class Middleware
9
+ attr_reader :stack
10
+
9
11
  def initialize
10
12
  @stack = []
11
13
  end
@@ -13,8 +15,6 @@ module Hanami
13
15
  def use(middleware, *args, &block)
14
16
  stack.push([middleware, *args, block].compact)
15
17
  end
16
-
17
- attr_reader :stack
18
18
  end
19
19
  end
20
20
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+
5
+ module Hanami
6
+ class Configuration
7
+ # NullConfiguration can serve as a fallback configuration object when out-of-gem
8
+ # configuration objects are not available (specifically, when the hanami-controller or
9
+ # hanami-view gems are not loaded)
10
+ class NullConfiguration
11
+ include Dry::Configurable
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/configurable"
4
+ require_relative "../application/routing/resolver"
5
+
3
6
  module Hanami
4
7
  class Configuration
5
8
  # Hanami router configuration
@@ -7,44 +10,43 @@ module Hanami
7
10
  # @since 2.0.0
8
11
  # @api private
9
12
  class Router
10
- # @api private
11
- # @since 2.0.0
12
- attr_writer :routes
13
-
14
- # @api private
15
- # @since 2.0.0
16
- attr_reader :routes
13
+ include Dry::Configurable
17
14
 
18
- # @api private
19
- # @since 2.0.0
20
- attr_writer :resolver
15
+ # Base configuration is provided so router config can include the `base_url`
16
+ attr_reader :base_configuration
17
+ private :base_configuration
21
18
 
22
19
  # @api private
23
20
  # @since 2.0.0
24
- def initialize(base_url, routes: DEFAULT_ROUTES)
25
- @base_url = base_url
26
- @routes = routes
21
+ def initialize(base_configuration)
22
+ @base_configuration = base_configuration
27
23
  end
28
24
 
29
- # @api private
30
- # @since 2.0.0
31
- def resolver
32
- @resolver ||= begin
33
- require_relative "../application/routing/resolver"
34
- Application::Routing::Resolver
35
- end
36
- end
25
+ setting :routes_path, default: File.join("config", "routes")
26
+
27
+ setting :routes_class_name, default: "Routes"
28
+
29
+ setting :resolver, default: Application::Routing::Resolver
37
30
 
38
31
  # @api private
39
32
  # @since 2.0.0
40
33
  def options
41
- { base_url: @base_url }
34
+ {base_url: base_configuration.base_url}
42
35
  end
43
36
 
44
- # @api private
45
- # @since 2.0.0
46
- DEFAULT_ROUTES = File.join("config", "routes")
47
- private_constant :DEFAULT_ROUTES
37
+ private
38
+
39
+ def method_missing(name, *args, &block)
40
+ if config.respond_to?(name)
41
+ config.public_send(name, *args, &block)
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ def respond_to_missing?(name, _include_all = false)
48
+ config.respond_to?(name) || super
49
+ end
48
50
  end
49
51
  end
50
52
  end