Class: Hanami::Settings

Inherits:
Object
  • Object
show all
Includes:
Dry::Configurable
Defined in:
lib/hanami/settings.rb,
lib/hanami/settings/env_store.rb

Overview

Provides user-defined settings for an Hanami app or slice.

Define your own settings by inheriting from this class in ‘config/settings.rb` within an app or slice. Your settings will be loaded from matching ENV vars (with upper-cased names) and be registered as a component as part of the Hanami app prepare step.

The settings instance is registered in your app and slice containers as a ‘“settings”` component. You can use the `Deps` mixin to inject this dependency and make settings available to your other components as required.

Settings are defined with [dry-configurable]‘s `setting` method. You may likely want to provide `default:` and `constructor:` options for your settings.

If you have [dry-types] bundled, then a nested ‘Types` module will be available for type checking your setting values. Pass type objects to the setting `constructor:` options to ensure their values meet your type expectations. You can use dry-types’ default type objects or define your own.

When the settings are initialized, all type errors will be collected and presented together for correction. Settings are loaded early, as part of the Hanami app’s prepare step, to ensure that the app boots only when valid settings are present.

Setting values are loaded from a configurable store, which defaults to EnvStore, which fetches the values from equivalent upper-cased keys in ‘ENV`. You can configure an alternative store via Config#settings_store. Setting stores must implement a `#fetch` method with the same signature as `Hash#fetch`.

[dry-c]: dry-rb.org/gems/dry-configurable/ [dry-t]: dry-rb.org/gems/dry-types/

Examples:

# config/settings.rb
# frozen_string_literal: true

module MyApp
  class Settings < Hanami::Settings
    Secret = Types::String.constrained(min_size: 20)

    setting :database_url, constructor: Types::String
    setting :session_secret, constructor: Secret
    setting :some_flag, default: false, constructor: Types::Params::Bool
  end
end

See Also:

  • DotenvStore

Since:

  • 2.0.0

Defined Under Namespace

Classes: EnvStore, InvalidSettingsError

Constant Summary collapse

Undefined =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Since:

  • 2.0.0

Dry::Core::Constants::Undefined
EMPTY_STORE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Since:

  • 2.0.0

Dry::Core::Constants::EMPTY_HASH

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(store = EMPTY_STORE) ⇒ Settings

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Settings.

Raises:

Since:

  • 2.0.0



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/hanami/settings.rb', line 158

def initialize(store = EMPTY_STORE)
  errors = config._settings.map(&:name).each_with_object({}) do |name, errs|
    value = store.fetch(name, Undefined)

    if value.eql?(Undefined)
      # When a key is missing entirely from the store, _read_ its value from the config instead.
      # This ensures its setting constructor runs (with a `nil` argument given) and raises any
      # necessary errors.
      public_send(name)
    else
      public_send("#{name}=", value)
    end
  rescue => e # rubocop:disable Style/RescueStandardError
    errs[name] = e
  end

  raise InvalidSettingsError, errors if errors.any?

  config.finalize!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object (private)

Since:

  • 2.0.0



222
223
224
225
226
227
228
# File 'lib/hanami/settings.rb', line 222

def method_missing(name, *args, &block)
  if config.respond_to?(name)
    config.send(name, *args, &block)
  else
    super
  end
end

Class Method Details

.inherited(subclass) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Defines a nested ‘Types` constant in `Settings` subclasses if dry-types is bundled.

See Also:

Since:

  • 2.0.0



93
94
95
96
97
98
99
100
# File 'lib/hanami/settings.rb', line 93

def inherited(subclass)
  super

  if Hanami.bundled?("dry-types")
    require "dry/types"
    subclass.const_set(:Types, Dry.Types())
  end
end

.load_for_slice(slice) ⇒ Settings?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Loads the settings for a slice.

Returns nil if no settings class is defined.

Returns:

Since:

  • 2.0.0



109
110
111
112
113
114
115
# File 'lib/hanami/settings.rb', line 109

def load_for_slice(slice)
  return unless settings_defined?(slice)

  require_slice_settings(slice) unless slice_settings_class?(slice)

  slice_settings_class(slice).new(slice.config.settings_store)
end

Instance Method Details

#inspectString

Returns a string containing a human-readable representation of the settings.

This includes setting names only, not any values, to ensure that sensitive values do not inadvertently leak.

Use #inspect_values to inspect settings with their values.

Examples:

settings.inspect
# => #<MyApp::Settings [database_url, session_secret, some_flag]>

Returns:

  • (String)

See Also:

Since:

  • 2.0.0



196
197
198
# File 'lib/hanami/settings.rb', line 196

def inspect
  "#<#{self.class} [#{config._settings.map(&:name).join(", ")}]>"
end

#inspect_valuesString

Returns a string containing a human-readable representation of the settings and their values.

Examples:

settings.inspect_values
# => #<MyApp::Settings database_url="postgres://localhost/my_db", session_secret="xxx", some_flag=true]>

Returns:

  • (String)

See Also:

Since:

  • 2.0.0



214
215
216
# File 'lib/hanami/settings.rb', line 214

def inspect_values
  "#<#{self.class} #{config._settings.map { |setting| "#{setting.name}=#{config[setting.name].inspect}" }.join(" ")}>"
end