lab_coat 0.1.2 → 0.1.3

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: 22451390278d5dff8546f421b305107ea5e6d6636ea288eb674ab980353dcd20
4
- data.tar.gz: 0a97027504a75312e42501283898021c9417b6e283e22cb5d86a614ebf939ae8
3
+ metadata.gz: 35fcc39652cc2ab43879a6a513214962c139d6b5751f5a1d4b4e8dba7b72b5e3
4
+ data.tar.gz: 5b54b1fb3fcabe26a80b2cdd619308f51b7fc44c6b0b93572550eb3e9a50aedd
5
5
  SHA512:
6
- metadata.gz: d59adedb051274080954bd28c23b0fbbdc4b6914d90a19f45e5a4c8d3d8f46a06b334e7a2c1e5698eee9adbc9bdfb0f8d4270d37c37430978d952635f4186711
7
- data.tar.gz: eb3f5aadd5a01813521b81941052a699ce5ced2b7e9f8d0964942d4a419524e001a0664cd55170069a9fff149eddc6f36885d704e035cc139309115f35c8d856
6
+ metadata.gz: 48e1e6af3c47d799f6eecd76dcac57a168da9c1729fc29091742b79ae114d36741a9d72bac6348db0db43a868ee5f75087ced725d270ae55074221a2dc152cd5
7
+ data.tar.gz: 6b98f3702d8a8cc8494bc2c9eb5e09e1ecc6aff21d204be93d54485eba4754fa60aa89aa832b2644910e42d6ac42c4cdc683db0ac4d0b49b7c3fe2025b417488
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## [0.1.3] - 2024-04-17
2
+ - `Experiment` now enforces arity at runtime for the `#enabled?`, `control`, and `candidate` methods.
3
+
1
4
  ## [0.1.2] - 2024-04-15
2
5
  - use `Benchmark` to capture the duration with more details
3
6
  - add `to_h` methods to `Result` and `Observation` for convenience
data/README.md CHANGED
@@ -8,6 +8,7 @@ This library is heavily inspired by [Scientist](https://github.com/github/scient
8
8
  - `Experiments` are `classes`, not `modules` which means they are stateful by default.
9
9
  - There is no app wide default experiment that gets magically set.
10
10
  - The `Result` only supports one comparison at a time, i.e. only 1 `candidate` is allowed per run.
11
+ - The `duration` is measured using Ruby's `Benchmark`.
11
12
 
12
13
  ## Installation
13
14
 
@@ -55,8 +56,8 @@ See the [`Experiment`](lib/lab_coat/experiment.rb) class for more details.
55
56
  |`enabled?`|Returns a `Boolean` that controls whether or not the experiment runs.|
56
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.|
57
58
 
58
- > [!TIP]
59
- > The `#run!` method accepts arbitrary arguments and forwards them to `enabled?`, `control`, and `candidate` in case you need to provide data at runtime.
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
61
 
61
62
  #### Additional methods
62
63
 
@@ -190,7 +191,7 @@ def publish!(result)
190
191
  end
191
192
  ```
192
193
 
193
- > ![NOTE]
194
+ > [!NOTE]
194
195
  > All `Results` are passed to `publish!`, **including ignored ones**. It is your responsibility to call the `ignored?` method and handle those as you wish.
195
196
 
196
197
  You can always access all of the attributes of the `Result` and its `Observations` directly to fully customize what your experiment publishing looks like.
@@ -60,24 +60,38 @@ module LabCoat
60
60
  # Runs the control and candidate and publishes the result. Always returns the result of `control`.
61
61
  # @param context [Hash] Any data needed at runtime.
62
62
  def run!(...) # rubocop:disable Metrics/MethodLength
63
+ enforce_arity!
64
+
63
65
  # Run the control and exit early if the experiment is not enabled.
64
- control = Observation.new("control", self) do
66
+ control_obs = Observation.new("control", self) do
65
67
  control(...)
66
68
  end
67
- raised(control) if control.raised?
68
- return control.value unless enabled?(...)
69
+ raised(control_obs) if control_obs.raised?
70
+ return control_obs.value unless enabled?(...)
69
71
 
70
- candidate = Observation.new("candidate", self) do
72
+ candidate_obs = Observation.new("candidate", self) do
71
73
  candidate(...)
72
74
  end
73
- raised(candidate) if candidate.raised?
75
+ raised(candidate_obs) if candidate_obs.raised?
74
76
 
75
77
  # Compare and publish the results.
76
- result = Result.new(self, control, candidate)
78
+ result = Result.new(self, control_obs, candidate_obs)
77
79
  publish!(result)
78
80
 
79
81
  # Always return the control.
80
- control.value
82
+ control_obs.value
83
+ end
84
+
85
+ private
86
+
87
+ # Because `run!` forwards arbitrary args to `#enabled?`, `control`, and `candidate`, the methods must have the same
88
+ # arity. Otherwise
89
+ def enforce_arity!
90
+ return if %i[enabled? control candidate].map { |m| method(m).arity }.uniq.size == 1
91
+
92
+ raise InvalidExperimentError,
93
+ "The `#enabled?`, `#control` and `#candidate` methods must have the same arity. All runtime args passed " \
94
+ "to `#run!` are forwarded to these methods."
81
95
  end
82
96
  end
83
97
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LabCoat
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
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.2
4
+ version: 0.1.3
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-15 00:00:00.000000000 Z
11
+ date: 2024-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest