Class: Servactory::ToolKit::DynamicOptions::Target

Inherits:
Must
  • Object
show all
Defined in:
lib/servactory/tool_kit/dynamic_options/target.rb

Overview

Validates that Class-typed attribute value matches one of the target classes.

## Purpose

Target provides class matching validation for Class-typed attributes. It ensures that the passed class is one of the specified target classes, supporting both single class and arrays of acceptable classes. This is useful for validating service classes, strategy patterns, or any scenario where specific classes are expected.

## Usage

This option is **NOT included by default**. Register it for each attribute type where you want to use it:

“‘ruby configuration do

input_option_helpers([
  Servactory::ToolKit::DynamicOptions::Target.use
])

internal_option_helpers([
  Servactory::ToolKit::DynamicOptions::Target.use
])

output_option_helpers([
  Servactory::ToolKit::DynamicOptions::Target.use
])

end “‘

Use in your service definition:

“‘ruby class ProcessOrderService < ApplicationService::Base

input :service_class, type: Class, target: UserService
input :handler_class, type: Class, target: [CreateHandler, UpdateHandler]

end “‘

## Simple Mode

Specify target class directly or as an array:

“‘ruby input :service_class, type: Class, target: UserService input :handler_class, type: Class, target: [CreateHandler, UpdateHandler] “`

## Advanced Mode

Specify target with custom error message using a hash. Note: Advanced mode uses ‘:in` key (not `:is`).

With static message:

“‘ruby input :handler_class, type: Class, target:

in: [CreateHandler, UpdateHandler],
message: "Input `handler_class` must be one of: CreateHandler, UpdateHandler"

“‘

With dynamic lambda message:

“‘ruby input :handler_class, type: Class, target:

in: [CreateHandler, UpdateHandler],
message: lambda do |input:, value:, option_value:, **|
  "Input `#{input.name` received `#value`, expected: #')"
end

} “‘

Lambda receives the following parameters:

  • For inputs: ‘input:, value:, option_value:, reason:, **`

  • For internals: ‘internal:, value:, option_value:, reason:, **`

  • For outputs: ‘output:, value:, option_value:, reason:, **`

## Validation Rules

  • Class must exactly match one of the target classes

  • Supports single class or array of classes

  • Optional inputs with nil value validate against default

## Important Notes

  • Use ‘target: { in: […] }` syntax for specifying allowed values

  • Returns ‘:invalid_option` error if target is nil

  • For optional inputs with nil value and default, validates the default

  • Internal/output attributes do NOT have default value handling (unlike inputs)

  • For Class-typed attributes, arrays of classes are preserved as-is rather than being wrapped (e.g., ‘[User, Admin]` stays as array, not `[[User, Admin]]`)

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Must

#equivalent_with, #initialize, #must, #must_content_message_with, #must_content_value_with, #must_content_with

Constructor Details

This class inherits a constructor from Servactory::ToolKit::DynamicOptions::Must

Class Method Details

.use(option_name = :target) ⇒ Servactory::Maintenance::Attributes::OptionHelper

Creates a Target validator instance.

Parameters:

  • option_name (Symbol) (defaults to: :target)

    The option name (default: :target)

Returns:



104
105
106
107
# File 'lib/servactory/tool_kit/dynamic_options/target.rb', line 104

def self.use(option_name = :target)
  instance = new(option_name, :in)
  instance.must(:"be_#{option_name}")
end

Instance Method Details

#condition_for_input_with(input:, value:, option:) ⇒ Boolean, Array

Validates target condition for input attribute.

Parameters:

  • input (Object)

    Input attribute object

  • value (Object)

    Value to validate

  • option (WorkOption)

    Target configuration

Returns:

  • (Boolean, Array)

    true if valid, or [false, reason]



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/servactory/tool_kit/dynamic_options/target.rb', line 115

def condition_for_input_with(input:, value:, option:) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
  return [false, :invalid_option] if option.value.nil?

  target_values = normalize_target_values(option.value, input.types)

  # Required inputs or optional with non-nil value.
  return target_values.include?(value) if input.required? || (input.optional? && !value.nil?)

  # Optional with nil value but has default.
  return target_values.include?(input.default) if input.optional? && value.nil? && !input.default.nil?

  true
end

#condition_for_internal_with(value:, option:, internal: nil) ⇒ Boolean, Array

Validates target condition for internal attribute.

Parameters:

  • internal (Object) (defaults to: nil)

    Internal attribute object

  • value (Object)

    Value to validate

  • option (WorkOption)

    Target configuration

Returns:

  • (Boolean, Array)

    true if valid, or [false, reason]



135
136
137
138
139
140
141
# File 'lib/servactory/tool_kit/dynamic_options/target.rb', line 135

def condition_for_internal_with(value:, option:, internal: nil, **)
  return [false, :invalid_option] if option.value.nil?

  target_values = normalize_target_values(option.value, internal.types)

  target_values.include?(value)
end

#condition_for_output_with(value:, option:, output: nil) ⇒ Boolean, Array

Validates target condition for output attribute.

Parameters:

  • output (Object) (defaults to: nil)

    Output attribute object

  • value (Object)

    Value to validate

  • option (WorkOption)

    Target configuration

Returns:

  • (Boolean, Array)

    true if valid, or [false, reason]



149
150
151
152
153
154
155
# File 'lib/servactory/tool_kit/dynamic_options/target.rb', line 149

def condition_for_output_with(value:, option:, output: nil, **)
  return [false, :invalid_option] if option.value.nil?

  target_values = normalize_target_values(option.value, output.types)

  target_values.include?(value)
end

#message_for_input_with(service:, input:, value:, option_name:, option_value:, reason:) ⇒ String

Generates error message for input validation failure.

Parameters:

  • service (Object)

    Service context

  • input (Object)

    Input attribute

  • value (Object)

    Failed value

  • option_name (Symbol)

    Option name

  • option_value (Object)

    Expected target values

  • reason (Symbol)

    Failure reason

Returns:

  • (String)

    Localized error message



168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/servactory/tool_kit/dynamic_options/target.rb', line 168

def message_for_input_with(service:, input:, value:, option_name:, option_value:, reason:, **)
  i18n_key = "inputs.validations.must.dynamic_options.target"
  i18n_key += reason.present? ? ".#{reason}" : ".default"

  service.translate(
    i18n_key,
    input_name: input.name,
    value: value.inspect,
    expected_target: option_value.inspect,
    option_name:
  )
end

#message_for_internal_with(service:, internal:, value:, option_name:, option_value:, reason:) ⇒ String

Generates error message for internal validation failure.

Parameters:

  • service (Object)

    Service context

  • internal (Object)

    Internal attribute

  • value (Object)

    Failed value

  • option_name (Symbol)

    Option name

  • option_value (Object)

    Expected target values

  • reason (Symbol)

    Failure reason

Returns:

  • (String)

    Localized error message



190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/servactory/tool_kit/dynamic_options/target.rb', line 190

def message_for_internal_with(service:, internal:, value:, option_name:, option_value:, reason:, **)
  i18n_key = "internals.validations.must.dynamic_options.target"
  i18n_key += reason.present? ? ".#{reason}" : ".default"

  service.translate(
    i18n_key,
    internal_name: internal.name,
    value: value.inspect,
    expected_target: option_value.inspect,
    option_name:
  )
end

#message_for_output_with(service:, output:, value:, option_name:, option_value:, reason:) ⇒ String

Generates error message for output validation failure.

Parameters:

  • service (Object)

    Service context

  • output (Object)

    Output attribute

  • value (Object)

    Failed value

  • option_name (Symbol)

    Option name

  • option_value (Object)

    Expected target values

  • reason (Symbol)

    Failure reason

Returns:

  • (String)

    Localized error message



212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/servactory/tool_kit/dynamic_options/target.rb', line 212

def message_for_output_with(service:, output:, value:, option_name:, option_value:, reason:, **)
  i18n_key = "outputs.validations.must.dynamic_options.target"
  i18n_key += reason.present? ? ".#{reason}" : ".default"

  service.translate(
    i18n_key,
    output_name: output.name,
    value: value.inspect,
    expected_target: option_value.inspect,
    option_name:
  )
end