Class: Dat::Science::Experiment

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

Overview

Public: Try things in code.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) {|_self| ... } ⇒ Experiment

Public: Create a new experiment instance. self is yielded to an optional block if it’s provided.

Yields:

  • (_self)

Yield Parameters:



14
15
16
17
18
19
20
21
22
23
# File 'lib/dat/science/experiment.rb', line 14

def initialize(name, &block)
  @candidate  = nil
  @cleaner    = lambda { |r| r }
  @comparator = lambda { |a, b| a == b }
  @context    = { :experiment => name }
  @control    = nil
  @name       = name

  yield self if block_given?
end

Instance Attribute Details

#nameObject (readonly)

Public: The name of this experiment.



10
11
12
# File 'lib/dat/science/experiment.rb', line 10

def name
  @name
end

Instance Method Details

#candidate(&block) ⇒ Object

Public: Declare the candidate behavior block for this experiment. Returns block.



27
28
29
30
# File 'lib/dat/science/experiment.rb', line 27

def candidate(&block)
  @candidate = block if block
  @candidate
end

#clean(value) ⇒ Object

Internal: Run the cleaner on a value.



33
34
35
# File 'lib/dat/science/experiment.rb', line 33

def clean(value)
  cleaner.call value
end

#cleaner(&block) ⇒ Object

Public: Declare a cleaner block to scrub the result before it’s published. block is called twice, once with the result of the control behavior and once with the result of the candidate. Exceptions during cleaning are treated as if they were raised in a candidate or control behavior block: They’re reported as part of the result.

Returns block.



45
46
47
48
# File 'lib/dat/science/experiment.rb', line 45

def cleaner(&block)
  @cleaner = block if block
  @cleaner
end

#comparator(&block) ⇒ Object

Public: Declare a comparator block. Results are compared with ‘==` by default.

Returns block.



59
60
61
62
# File 'lib/dat/science/experiment.rb', line 59

def comparator(&block)
  @comparator = block if block
  @comparator
end

#compare(a, b) ⇒ Object

Internal: Run the comparator on two values.



51
52
53
# File 'lib/dat/science/experiment.rb', line 51

def compare(a, b)
  comparator.call a, b
end

#context(payload = nil) ⇒ Object

Public: Add a Hash of payload data to be included when events are published or returns the current context if payload is nil.



66
67
68
69
# File 'lib/dat/science/experiment.rb', line 66

def context(payload = nil)
  @context.merge! payload if payload
  @context
end

#control(&block) ⇒ Object

Public: Declare the control behavior block for this experiment. Returns block.



73
74
75
76
# File 'lib/dat/science/experiment.rb', line 73

def control(&block)
  @control = block if block
  @control
end

#evaluate(control, candidate) ⇒ Object

Public: Determine the outcome of an experiment run

control - result from running control method candidate - result from running candidate method

Returns :match if control and candidate produced the same result, :mismatch otherwise.



119
120
121
# File 'lib/dat/science/experiment.rb', line 119

def evaluate(control, candidate)
  control == candidate ? :match : :mismatch
end

#runObject

Public: Run the control and candidate behaviors, timing each and comparing the results. The run order is randomized. Returns the control behavior’s result.

If the experiment is disabled or candidate behavior isn’t provided the control behavior’s result will be returned immediately.



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
110
# File 'lib/dat/science/experiment.rb', line 84

def run
  return run_control unless candidate? && enabled?

  timestamp = Time.now

  if control_runs_first?
    control   = observe_control
    candidate = observe_candidate
  else
    candidate = observe_candidate
    control   = observe_control
  end

  payload = {
    :timestamp => timestamp,
    :candidate => candidate.payload,
    :control   => control.payload,
    :first     => control_runs_first? ? :control : :candidate
  }

  kind = evaluate control, candidate
  publish_with_context kind, payload

  raise control.exception if control.raised?

  control.value
end