lab_coat 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35fcc39652cc2ab43879a6a513214962c139d6b5751f5a1d4b4e8dba7b72b5e3
4
- data.tar.gz: 5b54b1fb3fcabe26a80b2cdd619308f51b7fc44c6b0b93572550eb3e9a50aedd
3
+ metadata.gz: 0c1c5580cec0ec677137fcbf23a90291fab80564c955a1d8b10fb48903f1f43b
4
+ data.tar.gz: 15540d166b6a0d6098c07979efc8b780ecebb26d5059ac3db1217489e2448e06
5
5
  SHA512:
6
- metadata.gz: 48e1e6af3c47d799f6eecd76dcac57a168da9c1729fc29091742b79ae114d36741a9d72bac6348db0db43a868ee5f75087ced725d270ae55074221a2dc152cd5
7
- data.tar.gz: 6b98f3702d8a8cc8494bc2c9eb5e09e1ecc6aff21d204be93d54485eba4754fa60aa89aa832b2644910e42d6ac42c4cdc683db0ac4d0b49b7c3fe2025b417488
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 forwards them to `enabled?`, `control`, and `candidate` in case you need to provide data at runtime. This means the [arity](https://en.wikipedia.org/wiki/Arity) of the three methods needs to be the same. This is enforced by `LabCoat` at runtime.
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(user_id: @user.id)
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 and the `Experiment`'s state.
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
 
@@ -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!(...) # rubocop:disable Metrics/MethodLength
63
- enforce_arity!
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) do
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) do
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LabCoat
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.4"
5
5
  end
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.3
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-18 00:00:00.000000000 Z
11
+ date: 2024-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest