lib/hanami/config.rb in hanami-2.0.0.beta4 vs lib/hanami/config.rb in hanami-2.0.0.rc1
- old
+ new
@@ -1,111 +1,227 @@
# frozen_string_literal: true
require "uri"
-require "concurrent/hash"
-require "concurrent/array"
+require "pathname"
require "dry/configurable"
require "dry/inflector"
-require "pathname"
require_relative "constants"
-require_relative "config/logger"
-require_relative "config/sessions"
-require_relative "settings/env_store"
-require_relative "slice/routing/middleware/stack"
module Hanami
- # Hanami app configuration
+ # Hanami app config
#
# @since 2.0.0
class Config
include Dry::Configurable
+ # @!attribute [rw] root
+ # Sets the root for the app or slice.
+ #
+ # For the app, this defaults to `Dir.pwd`. For slices detected in `slices/` `config/slices/`,
+ # this defaults to `slices/[slice_name]/`.
+ #
+ # Accepts a string path and will return a `Pathname`.
+ #
+ # @return [Pathname]
+ #
+ # @api public
+ # @since 2.0.0
setting :root, constructor: ->(path) { Pathname(path) if path }
- setting :no_auto_register_paths, default: %w[entities]
-
+ # @!attribute [rw] inflector
+ # Sets the app's inflector.
+ #
+ # This expects a `Dry::Inflector` (or compatible) inflector instance.
+ #
+ # To configure custom inflection rules without having to assign a whole inflector, see
+ # {#inflections}.
+ #
+ # @return [Dry::Inflector]
+ #
+ # @see #inflections
+ #
+ # @api public
+ # @since 2.0.0
setting :inflector, default: Dry::Inflector.new
+ # @!attribute [rw] settings_store
+ # Sets the store used to retrieve {Hanami::Settings} values.
+ #
+ # Defaults to an instance of {Hanami::Settings::EnvStore}.
+ #
+ # @return [#fetch]
+ #
+ # @see Hanami::Settings
+ # @see Hanami::Settings::EnvStore#fetch
+ #
+ # @api public
+ # @since 2.0.0
setting :settings_store, default: Hanami::Settings::EnvStore.new
+ # @!attribute [rw] slices
+ # Sets the slices to load when the app is preared or booted.
+ #
+ # Defaults to `nil`, which will load all slices. Set this to an array of slice names to load
+ # only those slices.
+ #
+ # This attribute is also populated from the `HANAMI_SLICES` environment variable.
+ #
+ # @example
+ # config.slices = ["admin", "search"]
+ #
+ # @example
+ # ENV["HANAMI_SLICES"] # => "admin,search"
+ # config.slices # => ["admin", "search"]
+ #
+ # @return [Array<String>, nil]
+ #
+ # @api public
+ # @since 2.0.0
+ setting :slices
+
+ # @!attribute [rw] shared_app_component_keys
+ # Sets the keys for the components to be imported from the app into all other slices.
+ #
+ # You should append items to this array, since the default shared components are essential for
+ # slices to operate within the app.
+ #
+ # @example
+ # config.shared_app_component_keys += ["shared_component_a", "shared_component_b"]
+ #
+ # @return [Array<String>]
+ #
+ # @api public
+ # @since 2.0.0
setting :shared_app_component_keys, default: %w[
inflector
logger
notifications
rack.monitor
routes
settings
]
- setting :slices
+ # @!attribute [rw] no_auto_register_paths
+ # Sets the paths to skip from container auto-registration.
+ #
+ # Defaults to `["entities"]`.
+ #
+ # @return [Array<String>] array of relative paths
+ #
+ # @api public
+ # @since 2.0.0
+ setting :no_auto_register_paths, default: %w[entities]
+ # @!attribute [rw] base_url
+ # Sets the base URL for app's web server.
+ #
+ # This is passed to the {Slice::ClassMethods#router router} and used for generating links.
+ #
+ # Defaults to `"http://0.0.0.0:2300"`. String values passed are turned into `URI` instances.
+ #
+ # @return [URI]
+ #
+ # @see Slice::ClassMethods#router
+ #
+ # @api public
+ # @since 2.0.0
setting :base_url, default: "http://0.0.0.0:2300", constructor: ->(url) { URI(url) }
- setting :sessions, default: :null, constructor: ->(*args) { Sessions.new(*args) }
-
- setting :logger, cloneable: true
-
- DEFAULT_ENVIRONMENTS = Concurrent::Hash.new { |h, k| h[k] = Concurrent::Array.new }
- private_constant :DEFAULT_ENVIRONMENTS
-
- # @return [Symbol] The name of the application
+ # Returns the app or slice's {Hanami::SliceName slice_name}.
#
- # @api public
+ # This is useful for default config values that depend on this name.
+ #
+ # @return [Hanami::SliceName]
+ #
+ # @api private
+ # @since 2.0.0
attr_reader :app_name
- # @return [String] The current environment
+ # Returns the app's environment.
#
- # @api public
+ # @example
+ # config.env # => :development
+ #
+ # @return [Symbol]
+ #
+ # @see #environment
+ #
+ # @api private
+ # @since 2.0.0
attr_reader :env
- # @return [Hanami::Config::Actions]
+ # Returns the app's actions config, or a null config if hanami-controller is not bundled.
#
+ # @example When hanami-controller is bundled
+ # config.actions.default_request_format # => :html
+ #
+ # @example When hanami-controller is not bundled
+ # config.actions.default_request_format # => NoMethodError
+ #
+ # @return [Hanami::Config::Actions, Hanami::Config::NullConfig]
+ #
# @api public
+ # @since 2.0.0
attr_reader :actions
- # @return [Hanami::Slice::Routing::Middleware::Stack]
+ # Returns the app's middleware stack, or nil if hanami-router is not bundled.
#
+ # Use this to configure middleware that should apply to all routes.
+ #
+ # @example
+ # config.middleware.use :body_parser, :json
+ # config.middleware.use MyCustomMiddleware
+ #
+ # @return [Hanami::Slice::Routing::Middleware::Stack, nil]
+ #
# @api public
+ # @since 2.0.0
attr_reader :middleware
# @api private
+ # @since 2.0.0
alias_method :middleware_stack, :middleware
- # @return [Hanami::Config::Router]
+ # Returns the app's router config, or a null config if hanami-router is not bundled.
#
+ # @example When hanami-router is bundled
+ # config.router.resolver # => Hanami::Slice::Routing::Resolver
+ #
+ # @example When hanami-router is not bundled
+ # config.router.resolver # => NoMethodError
+ #
+ # @return [Hanami::Config::Router, Hanami::Config::NullConfig]
+ #
# @api public
+ # @since 2.0.0
attr_reader :router
- # @return [Hanami::Config::Views]
+ # Returns the app's views config, or a null config if hanami-view is not bundled.
#
- # @api public
+ # This is NOT RELEASED as of 2.0.0.
+ #
+ # @api private
attr_reader :views
- # @return [Hanami::Assets::AppConfiguration]
+ # Returns the app's assets config.
#
- # @api public
- attr_reader :assets
-
- # @return [Concurrent::Hash] A hash of default environments
+ # This is NOT RELEASED as of 2.0.0.
#
# @api private
- attr_reader :environments
- private :environments
+ attr_reader :assets
# @api private
def initialize(app_name:, env:)
@app_name = app_name
-
- @environments = DEFAULT_ENVIRONMENTS.clone
@env = env
# Apply default values that are only knowable at initialize-time (vs require-time)
self.root = Dir.pwd
load_from_env
- config.logger = Config::Logger.new(env: env, app_name: app_name)
+ @logger = Config::Logger.new(env: env, app_name: app_name)
# TODO: Make assets config dependent
require "hanami/assets/app_config"
@assets = Hanami::Assets::AppConfig.new
@@ -126,88 +242,134 @@
}
yield self if block_given?
end
- # Apply config for the given environment
- #
- # @param env [String] the environment name
- #
- # @return [Hanami::Config]
- #
- # @api public
- def environment(env_name, &block)
- environments[env_name] << block
- apply_env_config
-
- self
- end
-
- # Configure application's inflections
- #
- # @see https://dry-rb.org/gems/dry-inflector
- #
- # @return [Dry::Inflector]
- #
- # @api public
- def inflections(&block)
- self.inflector = Dry::Inflector.new(&block)
- end
-
# @api private
def initialize_copy(source)
super
@app_name = app_name.dup
- @environments = environments.dup
@assets = source.assets.dup
@actions = source.actions.dup
@middleware = source.middleware.dup
@router = source.router.dup.tap do |router|
router.instance_variable_set(:@base_config, self)
end
@views = source.views.dup
end
+ private :initialize_copy
+ # Finalizes the config.
+ #
+ # This is called when the app or slice is prepared. After this, no further changes to config can
+ # be made.
+ #
# @api private
def finalize!
- apply_env_config
-
# Finalize nested configs
assets.finalize!
actions.finalize!
views.finalize!
logger.finalize!
router.finalize!
super
end
- # Set a default global logger instance
+ # Configures the app's custom inflections.
#
+ # You should call this one time only. Subsequent calls will override previously configured
+ # inflections.
+ #
+ # @example
+ # config.inflections do |inflections|
+ # inflections.acronym "WNBA"
+ # end
+ #
+ # @see https://dry-rb.org/gems/dry-inflector
+ #
+ # @return [Dry::Inflector] the configured inflector
+ #
# @api public
+ # @since 2.0.0
+ def inflections(&block)
+ self.inflector = Dry::Inflector.new(&block)
+ end
+
+ # Disabling this to permit distinct documentation for `#logger` vs `#logger=`
+ #
+ # rubocop:disable Style/TrivialAccessors
+
+ # Returns the logger config.
+ #
+ # Use this to configure various options for the default `Dry::Logger::Dispatcher` logger instance.
+ #
+ # @example
+ # config.logger.level = :debug
+ #
+ # @return [Hanami::Config::Logger]
+ #
+ # @see Hanami::Config::Logger
+ #
+ # @api public
+ # @since 2.0.0
+ def logger
+ @logger
+ end
+
+ # Sets the app's logger instance.
+ #
+ # This entirely replaces the default `Dry::Logger::Dispatcher` instance that would have been
+ #
+ # @see #logger_instance
+ #
+ # @api public
+ # @since 2.0.0
def logger=(logger_instance)
@logger_instance = logger_instance
end
- # Return configured logger instance
+ # rubocop:enable Style/TrivialAccessors
+
+ # Returns the configured logger instance.
#
+ # Unless you've replaced the logger with {#logger=}, this returns a `Dry::Logger::Dispatcher` configured
+ # with the options configured through {#logger}.
+ #
+ # This configured logger is registered in all app and slice containers as `"logger"`. For
+ # typical usage, you should access the logger via this component, not directly from config.
+ #
+ # @example Accessing the logger component
+ # Hanami.app["logger"] # => #<Dry::Logger::Dispatcher>
+ #
+ # @example Injecting the logger as a dependency
+ # module MyApp
+ # class MyClass
+ # include Deps["logger"]
+ #
+ # def my_method
+ # logger.info("hello")
+ # end
+ # end
+ # end
+ #
+ # @return [Dry::Logger::Dispatcher]
+ #
+ # @see #logger
+ # @see Hanami::Config::Logger
+ #
# @api public
+ # @since 2.0.0
def logger_instance
@logger_instance || logger.instance
end
private
def load_from_env
self.slices = ENV["HANAMI_SLICES"]&.split(",")&.map(&:strip)
- end
-
- def apply_env_config(env = self.env)
- environments[env].each do |block|
- instance_eval(&block)
- end
end
# @api private
def load_dependent_config(gem_name)
if Hanami.bundled?(gem_name)