Module: Micro::Attributes::Features::Options

Defined in:
lib/micro/attributes/features.rb

Constant Summary collapse

KEYS =
[
  DIFF = 'Diff'.freeze,
  INIT = 'Initialize'.freeze,
  ACCEPT = 'Accept'.freeze,
  INIT_STRICT = 'InitializeStrict'.freeze,
  ACCEPT_STRICT = 'AcceptStrict'.freeze,
  KEYS_AS_SYMBOL = 'KeysAsSymbol'.freeze,
  AM_VALIDATIONS = 'ActiveModelValidations'.freeze
].sort.freeze
KEYS_TO_MODULES =
begin
  combinations = (1..KEYS.size).map { |n| KEYS.combination(n).to_a }.flatten(1).sort_by { |i| "#{i.size}#{i.join}" }
  combinations.delete_if { |combination| combination.include?(INIT_STRICT) && !combination.include?(INIT) }
  combinations.delete_if { |combination| combination.include?(ACCEPT_STRICT) && !combination.include?(ACCEPT) }
  combinations.each_with_object({}) do |combination, features|
    included = [
      'def self.included(base)',
      '  base.send(:include, ::Micro::Attributes)',
      combination.map { |key| "  base.send(:include, ::#{KEYS_TO_FEATURES[key].name})" },
      'end'
    ].flatten.join("\n")

    key = BuildKey.call(combination)

    With.const_set(key, Module.new.tap { |mod| mod.instance_eval(included) })

    features[key] = With.const_get(key, false)
  end.freeze
end
ACTIVEMODEL_VALIDATION =
'activemodel_validation'.freeze

Class Method Summary collapse

Class Method Details

.expand_hash_entry(key, value) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/micro/attributes/features.rb', line 144

def self.expand_hash_entry(key, value)
  case key
  when :initialize
    case value
    when true    then [:initialize]
    when :strict then [{ initialize: :strict }]
    when false, nil then []
    else [{ key => value }]
    end
  when :accept
    case value
    when true    then [:accept]
    when :strict then [{ accept: :strict }]
    when false, nil then []
    else [{ key => value }]
    end
  when :diff
    case value
    when true       then [:diff]
    when false, nil then []
    else [{ key => value }]
    end
  when :keys_as
    case value
    when :symbol                                  then [:keys_as_symbol]
    when :string, :indifferent, nil, false        then []
    else [{ key => value }]
    end
  when :active_model
    case value
    when :validations then [:activemodel_validations]
    when nil, false   then []
    else [{ key => value }]
    end
  else
    [{ key => value }]
  end
end

.fetch_key(arg) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/micro/attributes/features.rb', line 89

def self.fetch_key(arg)
  if arg.is_a?(Hash)
    return ACCEPT_STRICT if arg[:accept] == :strict

    INIT_STRICT if arg[:initialize] == :strict
  else
    str = String(arg)

    name = str == ACTIVEMODEL_VALIDATION ? Name::ACTIVEMODEL_VALIDATIONS : str

    KEYS_TO_MODULES.key?(name) ? name : NAMES_TO_KEYS[name]
  end
end

.fetch_keys(args) {|keys| ... } ⇒ Object

Yields:

  • (keys)

Raises:

  • (ArgumentError)


108
109
110
111
112
113
114
# File 'lib/micro/attributes/features.rb', line 108

def self.fetch_keys(args)
  keys = Array(args).flat_map { |name| split_strict_hash(name) }.map { |name| fetch_key(name) }

  raise ArgumentError, INVALID_NAME if keys.empty? || !(keys - KEYS).empty?

  yield(keys)
end

.fetch_module_by_keys(combination) ⇒ Object



195
196
197
198
199
# File 'lib/micro/attributes/features.rb', line 195

def self.fetch_module_by_keys(combination)
  key = BuildKey.call(combination)

  KEYS_TO_MODULES.fetch(key)
end

.remove_base_if_has_strict(keys) ⇒ Object



183
184
185
186
# File 'lib/micro/attributes/features.rb', line 183

def self.remove_base_if_has_strict(keys)
  keys.delete_if { |key| key == INIT } if keys.include?(INIT_STRICT)
  keys.delete_if { |key| key == ACCEPT } if keys.include?(ACCEPT_STRICT)
end

.split_strict_hash(arg) ⇒ Object

Normalize a Hash arg passed to ‘Micro::Attributes.with(…)` into the per-entry form that `fetch_key` consumes.

Handles BOTH:

  • The legacy single-key strict form (‘:strict`, `:strict`) — preserved as-is, returned in a single-key hash so the existing `fetch_key` branch matches it.

  • The new self-documenting hash API:

    Micro::Attributes.with(
      initialize: true | :strict,
      accept:     true | :strict,
      diff:       true,
      keys_as:    :symbol | :string | :indifferent,
      active_model: :validations
    )
    

    Each entry expands into the corresponding legacy feature symbol (or single-key strict hash). ‘false`/`nil`/the no-op variants for `keys_as` (`:string`/`:indifferent`) expand to nothing, so “omit a key = feature off” reads naturally.



138
139
140
141
142
# File 'lib/micro/attributes/features.rb', line 138

def self.split_strict_hash(arg)
  return [arg] unless arg.is_a?(Hash)

  arg.flat_map { |key, value| expand_hash_entry(key, value) }
end

.without_keys(keys_to_exclude) ⇒ Object



188
189
190
191
192
193
# File 'lib/micro/attributes/features.rb', line 188

def self.without_keys(keys_to_exclude)
  keys = (KEYS - keys_to_exclude)
  keys.delete_if { |key| key == INIT || key == INIT_STRICT } if keys_to_exclude.include?(INIT)
  keys.delete_if { |key| key == ACCEPT || key == ACCEPT_STRICT } if keys_to_exclude.include?(ACCEPT)
  keys
end