Class: Servactory::ToolKit::DynamicOptions::MultipleOf
- Defined in:
- lib/servactory/tool_kit/dynamic_options/multiple_of.rb
Overview
Validates that numeric value is a multiple of a specified number.
## Purpose
MultipleOf ensures that numeric values are evenly divisible by a specified divisor. This is useful for validating quantities, prices, or any values that must conform to specific increments.
## 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::MultipleOf.use
])
internal_option_helpers([
Servactory::ToolKit::DynamicOptions::MultipleOf.use
])
output_option_helpers([
Servactory::ToolKit::DynamicOptions::MultipleOf.use
])
end “‘
Use in your service definition:
“‘ruby class ProcessOrderService < ApplicationService::Base
input :quantity, type: Integer, multiple_of: 5
input :price, type: Float, multiple_of: 0.25
input :batch_size, type: Integer, multiple_of: 100
end “‘
## Simple Mode
Specify divisor directly:
“‘ruby class ProcessOrderService < ApplicationService::Base
input :quantity, type: Integer, multiple_of: 5
input :price, type: Float, multiple_of: 0.25
input :batch_size, type: Integer, multiple_of: 100
end “‘
## Advanced Mode
Specify divisor with custom error message using a hash:
With static message:
“‘ruby input :quantity, type: Integer, multiple_of:
is: 5,
message: "Input `quantity` must be a multiple of 5"
“‘
With dynamic lambda message:
“‘ruby input :quantity, type: Integer, multiple_of:
is: 5,
message: lambda do |input:, value:, option_value:, **|
"Input `#{input.name` must be divisible by #option_value, got #value"
end
} “‘
Lambda receives the following parameters:
-
For inputs: ‘input:, option_value:, value:, **`
-
For internals: ‘internal:, option_value:, value:, **`
-
For outputs: ‘output:, option_value:, value:, **`
## Supported Types
-
Integer
-
Float
-
Rational
-
BigDecimal
## Important Notes
-
Divisor must be a non-zero Numeric
-
Uses epsilon comparison for floating point precision
-
Returns false for non-numeric values
-
Provides specific error messages for blank and zero divisors
Class Method Summary collapse
-
.use(option_name = :multiple_of) ⇒ Servactory::Maintenance::Attributes::OptionHelper
Creates a MultipleOf validator instance.
Instance Method Summary collapse
-
#common_condition_with(value:, option:) ⇒ Boolean
Common validation logic for all attribute types.
-
#condition_for_input_with ⇒ Boolean
Validates multiple_of condition for input attribute.
-
#condition_for_internal_with ⇒ Boolean
Validates multiple_of condition for internal attribute.
-
#condition_for_output_with ⇒ Boolean
Validates multiple_of condition for output attribute.
-
#message_for_input_with(service:, input:, value:, option_name:, option_value:) ⇒ String
Generates error message for input validation failure.
-
#message_for_internal_with(service:, internal:, value:, option_name:, option_value:) ⇒ String
Generates error message for internal validation failure.
-
#message_for_output_with(service:, output:, value:, option_name:, option_value:) ⇒ String
Generates error message for output validation failure.
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 = :multiple_of) ⇒ Servactory::Maintenance::Attributes::OptionHelper
Creates a MultipleOf validator instance.
104 105 106 |
# File 'lib/servactory/tool_kit/dynamic_options/multiple_of.rb', line 104 def self.use(option_name = :multiple_of) new(option_name).must(:be_multiple_of) end |
Instance Method Details
#common_condition_with(value:, option:) ⇒ Boolean
Common validation logic for all attribute types.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/servactory/tool_kit/dynamic_options/multiple_of.rb', line 143 def common_condition_with(value:, option:, **) # rubocop:disable Naming/PredicateMethod case value when Integer, Float, Rational, BigDecimal # Validate divisor is present and valid. return false if option.value.blank? return false unless option.value.is_a?(Numeric) return false if option.value.zero? # Calculate remainder with epsilon tolerance for floats. remainder = value % option.value remainder.zero? || remainder.abs < Float::EPSILON * [value.abs, option.value.abs].max else false end end |
#condition_for_input_with ⇒ Boolean
Validates multiple_of condition for input attribute.
114 115 116 |
# File 'lib/servactory/tool_kit/dynamic_options/multiple_of.rb', line 114 def condition_for_input_with(...) common_condition_with(...) end |
#condition_for_internal_with ⇒ Boolean
Validates multiple_of condition for internal attribute.
124 125 126 |
# File 'lib/servactory/tool_kit/dynamic_options/multiple_of.rb', line 124 def condition_for_internal_with(...) common_condition_with(...) end |
#condition_for_output_with ⇒ Boolean
Validates multiple_of condition for output attribute.
134 135 136 |
# File 'lib/servactory/tool_kit/dynamic_options/multiple_of.rb', line 134 def condition_for_output_with(...) common_condition_with(...) end |
#message_for_input_with(service:, input:, value:, option_name:, option_value:) ⇒ String
Generates error message for input validation failure.
Selects appropriate message based on divisor state:
-
blank: divisor is nil or empty
-
divided_by_0: divisor is zero
-
default: standard not-multiple-of message
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/servactory/tool_kit/dynamic_options/multiple_of.rb', line 174 def (service:, input:, value:, option_name:, option_value:, **) # rubocop:disable Metrics/MethodLength i18n_key = "inputs.validations.must.dynamic_options.multiple_of" i18n_key += if option_value.blank? ".blank" elsif option_value.is_a?(Numeric) && option_value.zero? ".divided_by_0" else ".default" end service.translate( i18n_key, input_name: input.name, value:, option_name:, option_value: option_value.inspect ) end |
#message_for_internal_with(service:, internal:, value:, option_name:, option_value:) ⇒ String
Generates error message for internal validation failure.
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/servactory/tool_kit/dynamic_options/multiple_of.rb', line 202 def (service:, internal:, value:, option_name:, option_value:, **) # rubocop:disable Metrics/MethodLength i18n_key = "internals.validations.must.dynamic_options.multiple_of" i18n_key += if option_value.blank? ".blank" elsif option_value.is_a?(Numeric) && option_value.zero? ".divided_by_0" else ".default" end service.translate( i18n_key, internal_name: internal.name, value:, option_name:, option_value: option_value.inspect ) end |
#message_for_output_with(service:, output:, value:, option_name:, option_value:) ⇒ String
Generates error message for output validation failure.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/servactory/tool_kit/dynamic_options/multiple_of.rb', line 230 def (service:, output:, value:, option_name:, option_value:, **) # rubocop:disable Metrics/MethodLength i18n_key = "outputs.validations.must.dynamic_options.multiple_of" i18n_key += if option_value.blank? ".blank" elsif option_value.is_a?(Numeric) && option_value.zero? ".divided_by_0" else ".default" end service.translate( i18n_key, output_name: output.name, value:, option_name:, option_value: option_value.inspect ) end |