Class: ROM::Configurable::DSL Private

Inherits:
Object
  • Object
show all
Includes:
ExtensionMethods::DSL
Defined in:
lib/rom/support/configurable/dsl.rb

Overview

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

Setting DSL used by the class API

Constant Summary collapse

VALID_NAME =

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.

/\A[a-z_]\w*\z/i.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ DSL

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 DSL.



23
24
25
26
27
# File 'lib/rom/support/configurable/dsl.rb', line 23

def initialize(&block)
  @compiler = Compiler.new
  @ast = []
  instance_exec(&block) if block
end

Instance Attribute Details

#astObject (readonly)

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.



20
21
22
# File 'lib/rom/support/configurable/dsl.rb', line 20

def ast
  @ast
end

#compilerObject (readonly)

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.



17
18
19
# File 'lib/rom/support/configurable/dsl.rb', line 17

def compiler
  @compiler
end

Instance Method Details

#setting(name, default = Undefined, **options, &block) ⇒ 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.

Registers a new setting node and compile it into a setting object

Returns:

  • Setting

See Also:



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rom/support/configurable/dsl.rb', line 34

def setting(name, default = Undefined, **options, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
  unless VALID_NAME.match?(name.to_s)
    raise ArgumentError, "#{name} is not a valid setting name"
  end

  if default != Undefined
    if ROM::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 ROM::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 ROM::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)

  node = [:setting, [name.to_sym, options]]

  if block
    ast << [:nested, [node, DSL.new(&block).ast]]
  else
    ast << node
  end

  compiler.visit(ast.last)
end

#setting_import(name, setting) ⇒ Object Originally defined in module ExtensionMethods::DSL

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.

#settingsObject Originally defined in module ExtensionMethods::DSL

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.