lab_coat 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +11 -6
- data/lib/lab_coat/experiment.rb +13 -12
- data/lib/lab_coat/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c1c5580cec0ec677137fcbf23a90291fab80564c955a1d8b10fb48903f1f43b
|
4
|
+
data.tar.gz: 15540d166b6a0d6098c07979efc8b780ecebb26d5059ac3db1217489e2448e06
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c84bde55abd4974f068a802f181552111d847c3eeca07e28046fe3492919ba25a12fdefb10ac547bc22fbce90c1785fa01d73084db769f51ebe55993d52b2cc9
|
7
|
+
data.tar.gz: 128f1a14f2a2ec4f370d40d5c5b147d35b26abd75f558d5f19755fb71e82cfe8aad4de8673835a82c9b12f21088642ea346aa3bba4d29cdcc7d334a15b4622db
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## [0.1.4] - Unreleased
|
2
|
+
- Remove the arity check, it's not very intuitive
|
3
|
+
- Adds a `@context` that gets set at runtime and reset after each run. This is a much simpler way for methods to access a shared runtime context that can be set per `run!`.
|
4
|
+
|
1
5
|
## [0.1.3] - 2024-04-17
|
2
6
|
- `Experiment` now enforces arity at runtime for the `#enabled?`, `control`, and `candidate` methods.
|
3
7
|
|
data/README.md
CHANGED
@@ -57,7 +57,7 @@ See the [`Experiment`](lib/lab_coat/experiment.rb) class for more details.
|
|
57
57
|
|`publish!`|This is not _technically_ required, but `Experiments` are not useful unless you can analyze the results. Override this method to record the `Result` however you wish.|
|
58
58
|
|
59
59
|
> [!IMPORTANT]
|
60
|
-
> The `#run!` method accepts arbitrary arguments and
|
60
|
+
> The `#run!` method accepts arbitrary key word arguments and stores them in an instance variable called `@context` in case you need to provide data at runtime. You can access the runtime context via `@context` or `context`. The runtime context **is reset** after each run.
|
61
61
|
|
62
62
|
#### Additional methods
|
63
63
|
|
@@ -88,13 +88,16 @@ You might want to `publish!` all experiments in a consistent way so that you can
|
|
88
88
|
# application_experiment.rb
|
89
89
|
class ApplicationExperiment < LabCoat::Experiment
|
90
90
|
def publish!(result)
|
91
|
-
payload = result.to_h.merge(
|
91
|
+
payload = result.to_h.merge(
|
92
|
+
user_id: @user.id, # e.g. something from the `Experiment` state
|
93
|
+
build_number: context.version # e.g. something from the runtime context
|
94
|
+
)
|
92
95
|
YourO11yService.track_experiment_result(payload)
|
93
96
|
end
|
94
97
|
end
|
95
98
|
```
|
96
99
|
|
97
|
-
You might have a common way to enable experiments such as a feature flag system and/or common guards you want to enforce application wide. These might come from a mix of services
|
100
|
+
You might have a common way to enable experiments such as a feature flag system and/or common guards you want to enforce application wide. These might come from a mix of services, the `Experiment`'s state, or the runtime `context`.
|
98
101
|
|
99
102
|
```ruby
|
100
103
|
# application_experiment.rb
|
@@ -123,6 +126,8 @@ end
|
|
123
126
|
|
124
127
|
You don't have to create an `Observation` yourself; that happens automatically when you call `Experiment#run!`. The control and candidate `Observations` are packaged into a `Result` and [passed to `Experiment#publish!`](#publish-the-result).
|
125
128
|
|
129
|
+
The `run!` method accepts arbitrary keyword arguments, to allow you to set runtime context for the specific run of the experiment. You can access this `Hash` via the `context` reader method, or directly via the `@context` instance variable.
|
130
|
+
|
126
131
|
|Attribute|Description|
|
127
132
|
|---|---|
|
128
133
|
|`duration`|The duration of the run represented as a `Benchmark::Tms` object.|
|
@@ -180,14 +185,14 @@ A `Result` represents a single run of an `Experiment`.
|
|
180
185
|
|`matched?`|Whether or not the `control` and `candidate` match, as defined by `Experiment#compare`|
|
181
186
|
|`to_h`|A hash representation of the `Result`. Useful for publishing and/or reporting.|
|
182
187
|
|
183
|
-
The `Result` is passed to your implementation of `#publish!` when an `Experiment` is finished running. The `to_h` method on a Result is a good place to start and might be sufficient for most experiments.
|
188
|
+
The `Result` is passed to your implementation of `#publish!` when an `Experiment` is finished running. The `to_h` method on a Result is a good place to start and might be sufficient for most experiments. You might want to `merge` additional data such as the runtime `context` or other state if you find that relevant for analysis.
|
184
189
|
|
185
190
|
```ruby
|
186
191
|
# your_experiment.rb
|
187
192
|
def publish!(result)
|
188
193
|
return if result.ignored?
|
189
194
|
|
190
|
-
puts result.to_h
|
195
|
+
puts result.to_h.merge(run_context: context)
|
191
196
|
end
|
192
197
|
```
|
193
198
|
|
@@ -276,7 +281,7 @@ end
|
|
276
281
|
```
|
277
282
|
|
278
283
|
> [!WARNING]
|
279
|
-
> Be careful when using `Observation` instances without an `Experiment` set. Some methods like `#publishable_value` and `#slug` depend on an `experiment` and may raise an error when called.
|
284
|
+
> Be careful when using `Observation` instances without an `Experiment` set. Some methods like `#publishable_value` and `#slug` depend on an `experiment` and may raise an error or return unexpected values when called without one.
|
280
285
|
|
281
286
|
## Development
|
282
287
|
|
data/lib/lab_coat/experiment.rb
CHANGED
@@ -3,10 +3,11 @@
|
|
3
3
|
module LabCoat
|
4
4
|
# A base experiment class meant to be subclassed to define various experiments.
|
5
5
|
class Experiment
|
6
|
-
attr_reader :name
|
6
|
+
attr_reader :name, :context
|
7
7
|
|
8
8
|
def initialize(name)
|
9
9
|
@name = name
|
10
|
+
@context = {}
|
10
11
|
end
|
11
12
|
|
12
13
|
# Override this method to control whether or not the experiment runs.
|
@@ -18,13 +19,13 @@ module LabCoat
|
|
18
19
|
# Override this method to define the existing aka "control" behavior. This method is always run, even when
|
19
20
|
# `enabled?` is false.
|
20
21
|
# @return [Object] Anything.
|
21
|
-
def control
|
22
|
+
def control
|
22
23
|
raise InvalidExperimentError, "`#control` must be implemented in your Experiment class."
|
23
24
|
end
|
24
25
|
|
25
26
|
# Override this method to define the new aka "candidate" behavior. Only run if the experiment is enabled.
|
26
27
|
# @return [Object] Anything.
|
27
|
-
def candidate
|
28
|
+
def candidate
|
28
29
|
raise InvalidExperimentError, "`#candidate` must be implemented in your Experiment class."
|
29
30
|
end
|
30
31
|
|
@@ -59,25 +60,25 @@ module LabCoat
|
|
59
60
|
|
60
61
|
# Runs the control and candidate and publishes the result. Always returns the result of `control`.
|
61
62
|
# @param context [Hash] Any data needed at runtime.
|
62
|
-
def run!(
|
63
|
-
|
63
|
+
def run!(**context)
|
64
|
+
# Set the context for this run.
|
65
|
+
@context = context
|
64
66
|
|
65
67
|
# Run the control and exit early if the experiment is not enabled.
|
66
|
-
control_obs = Observation.new("control", self)
|
67
|
-
control(...)
|
68
|
-
end
|
68
|
+
control_obs = Observation.new("control", self) { control }
|
69
69
|
raised(control_obs) if control_obs.raised?
|
70
|
-
return control_obs.value unless enabled?
|
70
|
+
return control_obs.value unless enabled?
|
71
71
|
|
72
|
-
candidate_obs = Observation.new("candidate", self)
|
73
|
-
candidate(...)
|
74
|
-
end
|
72
|
+
candidate_obs = Observation.new("candidate", self) { candidate }
|
75
73
|
raised(candidate_obs) if candidate_obs.raised?
|
76
74
|
|
77
75
|
# Compare and publish the results.
|
78
76
|
result = Result.new(self, control_obs, candidate_obs)
|
79
77
|
publish!(result)
|
80
78
|
|
79
|
+
# Reset the context for this run.
|
80
|
+
@context = {}
|
81
|
+
|
81
82
|
# Always return the control.
|
82
83
|
control_obs.value
|
83
84
|
end
|
data/lib/lab_coat/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lab_coat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Omkar Moghe
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|