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

#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 = control == candidate ? :match : :mismatch
  publish_with_context kind, payload

  raise control.exception if control.raised?

  control.value
end