Module: Synthra::Personas

Defined in:
lib/synthra/personas.rb

Overview

Personas: Named Data Profiles

Define reusable data profiles that represent different user types, test cases, or data states. More semantic than "modes" - think in terms of WHO you're generating data for.

Examples:

Define personas

Synthra::Personas.define(:happy_path) do
  mode :random
  override User, email_verified: true, subscription: "premium"
end

Synthra::Personas.define(:edge_case_user) do
  mode :edge
  override User, name: "X", email: "a@b.co"
end

Use personas

Synthra.as(:happy_path) { User.generate }
Synthra.as(:edge_case_user) { User.generate }

Defined Under Namespace

Classes: Persona, PersonaContext

Class Method Summary collapse

Class Method Details

.[](name) ⇒ Persona?

Get a persona by name

Parameters:

  • name (Symbol)

    persona name

Returns:



50
51
52
# File 'lib/synthra/personas.rb', line 50

def [](name)
  registry[name]
end

.as(persona_name) { ... } ⇒ Object

Generate data using a persona

Parameters:

  • persona_name (Symbol)

    persona to use

Yields:

  • block for generation

Returns:

  • (Object)

    result of the block

Raises:

  • (ArgumentError)


68
69
70
71
72
73
# File 'lib/synthra/personas.rb', line 68

def as(persona_name, &block)
  persona = registry[persona_name]
  raise ArgumentError, "Unknown persona: #{persona_name}" unless persona

  persona.apply(&block)
end

.define(name) { ... } ⇒ Persona

Define a new persona

Parameters:

  • name (Symbol)

    persona name

Yields:

  • persona configuration block

Returns:

  • (Persona)

    the defined persona



38
39
40
41
42
43
# File 'lib/synthra/personas.rb', line 38

def define(name, &block)
  persona = Persona.new(name)
  persona.instance_eval(&block) if block
  registry[name] = persona
  persona
end

.define_built_in_personas!Object

Define built-in personas



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/synthra/personas.rb', line 116

def define_built_in_personas!
  define(:default) do
    mode :random
  end

  define(:happy_path) do
    mode :random
    # Most common, valid data
  end

  define(:edge_cases) do
    mode :edge
    # Boundary values, empty strings, max lengths
  end

  define(:invalid) do
    mode :invalid
    # Invalid data for validation testing
  end

  define(:security_test) do
    mode :hostile
    # SQL injection, XSS, malicious payloads
  end

  define(:stress_test) do
    mode :edge
    transform do |data, _context|
      # Make strings very long
      data.transform_values do |v|
        v.is_a?(String) ? v * 100 : v
      end
    end
  end
end

.listArray<Symbol>

List all personas

Returns:

  • (Array<Symbol>)


58
59
60
# File 'lib/synthra/personas.rb', line 58

def list
  registry.keys
end

.load_config(config) ⇒ Object

Load personas from configuration

Parameters:

  • config (Hash)

    configuration hash



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/synthra/personas.rb', line 79

def load_config(config)
  config.each do |name, definition|
    define(name.to_sym) do
      # :nocov: the `&.` nil-arm is unreachable — the trailing `if definition["mode"]` guard
      # already guarantees definition["mode"] is truthy whenever this line runs.
      mode definition["mode"]&.to_sym if definition["mode"]
      # :nocov:
      seed definition["seed"] if definition["seed"]

      definition["overrides"]&.each do |schema, overrides|
        override schema, **Personas.send(:symbolize_keys, overrides)
      end

      definition["traits"]&.each do |trait|
        include_trait trait.to_sym
      end
    end
  end
end

.load_file(path) ⇒ Object

Load personas from YAML file

Parameters:

  • path (String)

    path to YAML file



103
104
105
106
107
# File 'lib/synthra/personas.rb', line 103

def load_file(path)
  require "yaml"
  config = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
  load_config(config["personas"] || config)
end

.registryObject

Registry of defined personas



28
29
30
# File 'lib/synthra/personas.rb', line 28

def registry
  @registry ||= {}
end

.reset!Object

Reset all personas (clears custom personas, preserves built-ins)



110
111
112
113
# File 'lib/synthra/personas.rb', line 110

def reset!
  @registry = {}
  define_built_in_personas!
end

.symbolize_keys(hash) ⇒ Object (private)



154
155
156
# File 'lib/synthra/personas.rb', line 154

def symbolize_keys(hash)
  hash.transform_keys(&:to_sym)
end