lib/dry/configurable/dsl.rb in dry-configurable-0.15.0 vs lib/dry/configurable/dsl.rb in dry-configurable-0.16.0
- old
+ new
@@ -1,148 +1,60 @@
# frozen_string_literal: true
-require "dry/configurable/constants"
-require "dry/configurable/flags"
-require "dry/configurable/setting"
-require "dry/configurable/settings"
-require "dry/configurable/compiler"
require "dry/core/deprecations"
module Dry
module Configurable
# Setting DSL used by the class API
#
# @api private
class DSL
VALID_NAME = /\A[a-z_]\w*\z/i.freeze
- # @api private
attr_reader :compiler
- # @api private
attr_reader :ast
- # @api private
- def initialize(&block)
+ attr_reader :options
+
+ def initialize(**options, &block)
@compiler = Compiler.new
@ast = []
+ @options = options
instance_exec(&block) if block
end
# Registers a new setting node and compile it into a setting object
#
# @see ClassMethods.setting
# @api private
# @return Setting
- def setting(name, default = Undefined, **options, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
+ def setting(name, **options, &block) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
unless VALID_NAME.match?(name.to_s)
raise ArgumentError, "#{name} is not a valid setting name"
end
- if default != Undefined
- if Dry::Configurable.warn_on_setting_positional_default
- Dry::Core::Deprecations.announce(
- "default value as positional argument to settings",
- "Provide a `default:` keyword argument instead",
- tag: "dry-configurable",
- uplevel: 2
- )
- end
-
- options = options.merge(default: default)
- end
-
- if RUBY_VERSION < "3.0" &&
- default == Undefined &&
- (valid_opts, invalid_opts = valid_and_invalid_options(options)) &&
- invalid_opts.any? &&
- valid_opts.none?
- # In Ruby 2.6 and 2.7, when a hash is given as the second positional argument
- # (i.e. the hash is intended to be the setting's default value), and there are
- # no other keyword arguments given, the hash is assigned to the `options`
- # variable instead of `default`.
- #
- # For example, for this setting:
- #
- # setting :hash_setting, {my_hash: true}
- #
- # We'll have a `default` of `Undefined` and an `options` of `{my_hash: true}`
- #
- # If any additional keyword arguments are provided, e.g.:
- #
- # setting :hash_setting, {my_hash: true}, reader: true
- #
- # Then we'll have a `default` of `{my_hash: true}` and an `options` of `{reader:
- # true}`, which is what we want.
- #
- # To work around that first case and ensure our (deprecated) backwards
- # compatibility holds for Ruby 2.6 and 2.7, we extract all invalid options from
- # `options`, and if there are no remaining valid options (i.e. if there were no
- # keyword arguments given), then we can infer the invalid options to be a
- # default hash value for the setting.
- #
- # This approach also preserves the behavior of raising an ArgumentError when a
- # distinct hash is _not_ intentionally provided as the second positional
- # argument (i.e. it's not enclosed in braces), and instead invalid keyword
- # arguments are given alongside valid ones. So this setting:
- #
- # setting :some_setting, invalid_option: true, reader: true
- #
- # Would raise an ArgumentError as expected.
- #
- # However, the one case we can't catch here is when invalid options are supplied
- # without hash literal braces, but there are no other keyword arguments
- # supplied. In this case, a setting like:
- #
- # setting :hash_setting, my_hash: true
- #
- # Is parsed identically to the first case described above:
- #
- # setting :hash_setting, {my_hash: true}
- #
- # So in both of these cases, the default value will become `{my_hash: true}`. We
- # consider this unlikely to be a problem in practice, since users are not likely
- # to be providing invalid options to `setting` and expecting them to be ignored.
- # Additionally, the deprecation messages will make the new behavior obvious, and
- # encourage the users to upgrade their setting definitions.
-
- if Dry::Configurable.warn_on_setting_positional_default
- Dry::Core::Deprecations.announce(
- "default value as positional argument to settings",
- "Provide a `default:` keyword argument instead",
- tag: "dry-configurable",
- uplevel: 2
- )
- end
-
- options = {default: invalid_opts}
- end
-
- if block && !block.arity.zero?
- if Dry::Configurable.warn_on_setting_constructor_block
- Dry::Core::Deprecations.announce(
- "passing a constructor as a block",
- "Provide a `constructor:` keyword argument instead",
- tag: "dry-configurable",
- uplevel: 2
- )
- end
-
- options = options.merge(constructor: block)
- block = nil
- end
-
ensure_valid_options(options)
+ options = {default: default, config_class: config_class, **options}
+
node = [:setting, [name.to_sym, options]]
if block
ast << [:nested, [node, DSL.new(&block).ast]]
else
ast << node
end
compiler.visit(ast.last)
+ end
+
+ def config_class
+ options[:config_class]
+ end
+
+ def default
+ options[:default_undefined] ? Undefined : nil
end
private
def ensure_valid_options(options)