Class: LabCoat::Experiment

Inherits:
Object
  • Object
show all
Defined in:
lib/lab_coat/experiment.rb

Overview

A base experiment class meant to be subclassed to define various experiments.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Experiment

Returns a new instance of Experiment.



8
9
10
11
# File 'lib/lab_coat/experiment.rb', line 8

def initialize(name)
  @name = name
  @context = {}
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



6
7
8
# File 'lib/lab_coat/experiment.rb', line 6

def context
  @context
end

#nameObject (readonly)

Returns the value of attribute name.



6
7
8
# File 'lib/lab_coat/experiment.rb', line 6

def name
  @name
end

Instance Method Details

#candidateObject

Override this method to define the new aka “candidate” behavior. Only run if the experiment is enabled.

Returns:

  • (Object)

    Anything.

Raises:



28
29
30
# File 'lib/lab_coat/experiment.rb', line 28

def candidate
  raise InvalidExperimentError, "`#candidate` must be implemented in your Experiment class."
end

#compare(control, candidate) ⇒ TrueClass, FalseClass

Override this method to define what is considered a match or mismatch. Must return a boolean.

Parameters:

Returns:

  • (TrueClass, FalseClass)


36
37
38
# File 'lib/lab_coat/experiment.rb', line 36

def compare(control, candidate)
  control.value == candidate.value
end

#controlObject

Override this method to define the existing aka “control” behavior. This method is always run, even when ‘enabled?` is false.

Returns:

  • (Object)

    Anything.

Raises:



22
23
24
# File 'lib/lab_coat/experiment.rb', line 22

def control
  raise InvalidExperimentError, "`#control` must be implemented in your Experiment class."
end

#enabled?TrueClass, FalseClass

Override this method to control whether or not the experiment runs.

Returns:

  • (TrueClass, FalseClass)

Raises:



15
16
17
# File 'lib/lab_coat/experiment.rb', line 15

def enabled?(...)
  raise InvalidExperimentError, "`#enabled?` must be implemented in your Experiment class."
end

#ignore?(_control, _candidate) ⇒ Boolean

Override this method to define which results are ignored. Must return a boolean.

Returns:

  • (Boolean)


41
42
43
# File 'lib/lab_coat/experiment.rb', line 41

def ignore?(_control, _candidate)
  false
end

#publish!(result) ⇒ Object

Override this method to publish the ‘Result`. It’s recommended to override this once in an application wide base class.

Parameters:



59
# File 'lib/lab_coat/experiment.rb', line 59

def publish!(result); end

#publishable_value(observation) ⇒ Object

Override this method to transform the value for publishing. This could mean turning the value into something serializable (e.g. JSON).

Parameters:



52
53
54
# File 'lib/lab_coat/experiment.rb', line 52

def publishable_value(observation)
  observation.value
end

#raised(observation) ⇒ Object

Called when the control and/or candidate observations raise an error.

Parameters:



47
# File 'lib/lab_coat/experiment.rb', line 47

def raised(observation); end

#run!(**context) ⇒ Object

Runs the control and candidate and publishes the result. Always returns the result of ‘control`.

Parameters:

  • context (Hash)

    Any data needed at runtime.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/lab_coat/experiment.rb', line 63

def run!(**context)
  # Set the context for this run.
  @context = context

  # Run the control and exit early if the experiment is not enabled.
  control_obs = Observation.new("control", self) { control }
  raised(control_obs) if control_obs.raised?
  return control_obs.value unless enabled?

  candidate_obs = Observation.new("candidate", self) { candidate }
  raised(candidate_obs) if candidate_obs.raised?

  # Compare and publish the results.
  result = Result.new(self, control_obs, candidate_obs)
  publish!(result)

  # Reset the context for this run.
  @context = {}

  # Always return the control.
  control_obs.value
end