Class: Treaty::Entity::Attribute::Option::Modifiers::ComputedModifier

Inherits:
Base
  • Object
show all
Defined in:
lib/treaty/entity/attribute/option/modifiers/computed_modifier.rb

Overview

Computes attribute values from all available raw data.

Key Difference from Transform

  • transform: receives only value: (the current attribute's value)
  • computed: receives **attributes (ALL raw data from root level)

Usage Examples

Simple mode:

string :full_name, computed: (lambda do |**attributes|
"#{attributes.dig(:user, :first_name)} #{attributes.dig(:user, :last_name)}"
end)

Advanced mode with custom error message:

string :full_name, computed: {
is: ->(**attributes) { "#{attributes.dig(:user, :first_name)} #{attributes.dig(:user, :last_name)}" },
message: "Failed to compute full name"
}

Use Cases

  1. Derived fields (full name from parts):

    response 200 do
      object :user do
        string :first_name
        string :last_name
        string :full_name, computed: (lambda do |**attributes|
          "#{attributes.dig(:user, :first_name)} #{attributes.dig(:user, :last_name)}"
        end)
      end
    end
    
  2. Calculated values (word count):

    response 200 do
      object :post do
        string :content
        integer :word_count, computed: (lambda do |**attributes|
          attributes.dig(:post, :content).to_s.split.size
        end)
      end
    end
    
  3. Cross-object computations:

    response 200 do
      object :order do
        integer :quantity
        integer :unit_price
        integer :total, computed: (lambda do |**attributes|
          attributes.dig(:order, :quantity).to_i * attributes.dig(:order, :unit_price).to_i
        end)
      end
    end
    

Important Notes

  • Lambda must accept **attributes (named argument splat)
  • Receives full raw data from root level (not just current object)
  • Always computes - ignores any existing value, result replaces everything
  • All exceptions raised in lambda are caught and re-raised as Validation errors
  • Computation is applied during Phase 3 (transformation phase)
  • Executes FIRST in modifier chain: computed -> transform -> cast -> default -> as

Advanced Mode

Schema format: { is: lambda, message: nil }

Instance Method Summary collapse

Methods inherited from Base

#initialize, #target_name, #transforms_name?, #validate_value!

Constructor Details

This class inherits a constructor from Treaty::Entity::Attribute::Option::Base

Instance Method Details

#transform_value(_value, root_data = {}) ⇒ Object

Computes value using the provided lambda and full root data Always executes - ignores any existing value

Parameters:

  • _value (Object)

    The current value (ignored - always computes)

  • root_data (Hash) (defaults to: {})

    Full raw data from root level

Returns:

  • (Object)

    Computed value



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/treaty/entity/attribute/option/modifiers/computed_modifier.rb', line 104

def transform_value(_value, root_data = {}) # rubocop:disable Metrics/MethodLength
  computed_lambda = option_value

  # Call lambda with full root data as named arguments
  computed_lambda.call(**root_data)
rescue StandardError => e
  attributes = {
    attribute: @attribute_name,
    error: e.message
  }

  # Catch all exceptions from lambda execution
  error_message = resolve_custom_message(**attributes) || I18n.t(
    "treaty.attributes.modifiers.computed.execution_error",
    **attributes
  )

  raise Treaty::Exceptions::Validation, error_message
end

#validate_schema!void

This method returns an undefined value.

Validates that computed value is a lambda

Raises:



85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/treaty/entity/attribute/option/modifiers/computed_modifier.rb', line 85

def validate_schema!
  computed_lambda = option_value

  return if computed_lambda.respond_to?(:call)

  raise Treaty::Exceptions::Validation,
        I18n.t(
          "treaty.attributes.modifiers.computed.invalid_type",
          attribute: @attribute_name,
          type: computed_lambda.class
        )
end