Class: Synthra::Behaviors::Applicator

Inherits:
Object
  • Object
show all
Defined in:
lib/synthra/behaviors/applicator.rb

Overview

Applies behaviors to generated data

The Applicator coordinates behavior application, looking up behavior classes from the registry and applying them in order. It handles both schema-level and field-level behaviors.

Examples:

Apply schema behaviors

applicator = Applicator.new(schema, rng)
result = applicator.apply_schema_behaviors({ "name" => "John" })
# May add latency, raise errors, etc.

Apply field behaviors

value = applicator.apply_field_behaviors(field, "original_value")
# => modified value or :omit to remove field

Instance Method Summary collapse

Constructor Details

#initialize(schema, rng) ⇒ Applicator

Create a new Applicator

Examples:

applicator = Applicator.new(schema, rng)

Parameters:

  • schema (Schema)

    the schema containing behavior definitions

  • rng (Generator::RNG)

    random number generator for deterministic behavior



49
50
51
52
# File 'lib/synthra/behaviors/applicator.rb', line 49

def initialize(schema, rng)
  @schema = schema
  @rng = rng
end

Instance Method Details

#apply_field_behaviors(field, value) ⇒ Object, Symbol

Apply field-level behaviors to a field value

Applies behaviors defined on individual fields (e.g., @partial_data, @latency). Field behaviors can modify the value or indicate that the field should be omitted entirely.

Examples:

Apply partial_data behavior

# Field with @partial_data 20%
result = applicator.apply_field_behaviors(field, "value")
# => "value" (80% of the time) or :omit (20% of the time)

Parameters:

  • field (Field)

    the field definition with behaviors

  • value (Object)

    the generated field value

Returns:

  • (Object, Symbol)

    the modified value, or :omit to remove the field



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/synthra/behaviors/applicator.rb', line 128

def apply_field_behaviors(field, value)
  field.behaviors.each do |fb|
    begin

      # Look up and instantiate the behavior
      behavior_class = Registry.lookup(fb.type)
      behavior = behavior_class.respond_to?(:new) ?
        (behavior_class.is_a?(Class) ? behavior_class.new(fb.value, @rng) : behavior_class.new(fb.value, @rng)) :
        behavior_class


      # Special handling for partial_data - return :omit symbol
      if fb.type == :partial_data && behavior.should_apply?
        return :omit
      end


      # Apply other behaviors normally
      value = behavior.apply(value)
    rescue ArgumentError => e

      # Only skip if it's an "Unknown behavior" error
      # Re-raise other ArgumentErrors (e.g., wrong number of arguments)
      if e.message.include?("Unknown behavior")

        # Unknown behavior - skip silently
      else

        # Re-raise real argument errors
        raise
      end
    end
  end
  value
end

#apply_schema_behaviors(result) ⇒ Hash

Apply schema-level behaviors to a generated record

Applies all behaviors defined at the schema level (e.g., @latency, @failure) to the complete generated record. Behaviors are applied in the order they were defined.

Examples:

# Schema with @latency 100ms @failure 10%
result = applicator.apply_schema_behaviors({ "id" => "123" })
# May add 100ms delay, or raise SimulatedFailure 10% of the time

Parameters:

  • result (Hash)

    the generated record

Returns:

  • (Hash)

    the result after all behaviors have been applied

Raises:



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
# File 'lib/synthra/behaviors/applicator.rb', line 73

def apply_schema_behaviors(result)
  @schema.all_behaviors.each do |behavior_config|
    name = behavior_config[:name]
    value = behavior_config[:value]

    begin

      # Look up the behavior class from registry
      behavior_class = Registry.lookup(name)


      # Create behavior instance
      # Handle both Class and BlockBehavior patterns
      behavior = behavior_class.respond_to?(:new) ?
        (behavior_class.is_a?(Class) ? behavior_class.new(value, @rng) : behavior_class.new(value, @rng)) :
        behavior_class


      # Apply the behavior, which may modify result or raise errors
      result = behavior.apply(result)
    rescue ArgumentError => e

      # Only skip if it's an "Unknown behavior" error
      # Re-raise other ArgumentErrors (e.g., wrong number of arguments)
      if e.message.include?("Unknown behavior")

        # Unknown behavior - skip silently
        # This allows forward compatibility with unknown behaviors
      else

        # Re-raise real argument errors
        raise
      end
    end
  end
  result
end