Skip to content

Commit a575d12

Browse files
Merge pull request #81 from EtaCassiopeia/feat/batch-add-hooks
Add batch addHooks method to FeatureFlags
2 parents 123b9be + 3f253ad commit a575d12

5 files changed

Lines changed: 22 additions & 10 deletions

File tree

core/src/main/scala/zio/openfeature/FeatureFlags.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ trait FeatureFlags {
155155
def on(eventType: ProviderEventType, handler: ProviderEvent => UIO[Unit]): UIO[UIO[Unit]]
156156

157157
def addHook(hook: FeatureHook): UIO[Unit]
158+
def addHooks(hooks: List[FeatureHook]): UIO[Unit]
158159
def clearHooks: UIO[Unit]
159160
def hooks: UIO[List[FeatureHook]]
160161

@@ -347,6 +348,9 @@ object FeatureFlags {
347348
def addHook(hook: FeatureHook): ZIO[FeatureFlags, Nothing, Unit] =
348349
ZIO.serviceWithZIO(_.addHook(hook))
349350

351+
def addHooks(hooks: List[FeatureHook]): ZIO[FeatureFlags, Nothing, Unit] =
352+
ZIO.serviceWithZIO(_.addHooks(hooks))
353+
350354
def clearHooks: ZIO[FeatureFlags, Nothing, Unit] =
351355
ZIO.serviceWithZIO(_.clearHooks)
352356

core/src/main/scala/zio/openfeature/FeatureFlagsLive.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,9 @@ final private[openfeature] class FeatureFlagsLive(
658658
override def addHook(hook: FeatureHook): UIO[Unit] =
659659
state.hooksRef.update(_ :+ hook)
660660

661+
override def addHooks(hooks: List[FeatureHook]): UIO[Unit] =
662+
state.hooksRef.update(_ ++ hooks)
663+
661664
override def clearHooks: UIO[Unit] =
662665
state.hooksRef.set(List.empty)
663666

docs/hooks.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,8 @@ FeatureFlags.addHook(combined)
226226
Hooks are executed in the order they were added:
227227

228228
```scala
229-
FeatureFlags.addHook(loggingHook) // Runs first in before
230-
FeatureFlags.addHook(metricsHook) // Runs second in before
231-
FeatureFlags.addHook(validatorHook) // Runs third in before
229+
// Hooks run in registration order (first added = first to run in `before`)
230+
FeatureFlags.addHooks(List(loggingHook, metricsHook, validatorHook))
232231
```
233232

234233
For the `before` stage, hooks run in order. For `after`, `error`, and `finallyAfter`, they run in reverse order.
@@ -261,6 +260,9 @@ Client-level hooks apply to a specific FeatureFlags instance:
261260
// Add a single hook at runtime
262261
FeatureFlags.addHook(myHook)
263262

263+
// Add multiple hooks atomically
264+
FeatureFlags.addHooks(List(loggingHook, metricsHook, validatorHook))
265+
264266
// Create layer with initial hooks
265267
val hooks = List(
266268
FeatureHook.logging(),
@@ -444,11 +446,7 @@ override def after[A](...): UIO[Unit] =
444446
Consider hook order for dependencies:
445447

446448
```scala
447-
// Validation should run first
448-
FeatureFlags.addHook(validatorHook)
449-
// Then enrichment
450-
FeatureFlags.addHook(enrichmentHook)
451-
// Then logging/metrics
452-
FeatureFlags.addHook(loggingHook)
449+
// Order matters: validation → enrichment → logging
450+
FeatureFlags.addHooks(List(validatorHook, enrichmentHook, loggingHook))
453451
```
454452

docs/spec-compliance.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ FeatureFlags.booleanDetails("flag", false, context, options)
124124
| Hook hints || `HookHints` for passing data between stages |
125125
| Hook data (4.6.1) || `HookData` per-hook mutable state across stages |
126126
| API-level hooks || `FeatureFlags.addApiHook` / `clearApiHooks` |
127-
| Client-level hooks || `FeatureFlags.addHook` / `clearHooks` |
127+
| Client-level hooks || `FeatureFlags.addHook` / `addHooks` / `clearHooks` |
128128
| Invocation-level hooks || Via `EvaluationOptions` |
129129
| Provider-level hooks || Automatically included from `provider.getProviderHooks()` |
130130
| Execution order || API → Client → Invocation → Provider (reversed for after/error/finally) |

testkit/src/test/scala/zio/openfeature/testkit/FeatureFlagsSpec.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,13 @@ object FeatureFlagsSpec extends ZIOSpecDefault {
237237
} yield assertTrue(initial.isEmpty) &&
238238
assertTrue(after.length == 1)
239239
}.provide(testLayer()),
240+
test("addHooks adds multiple hooks atomically") {
241+
val hooks = List(FeatureHook.noop, FeatureHook.noop, FeatureHook.noop)
242+
for {
243+
_ <- FeatureFlags.addHooks(hooks)
244+
after <- FeatureFlags.hooks
245+
} yield assertTrue(after.length == 3)
246+
}.provide(testLayer()),
240247
test("clearHooks removes all hooks") {
241248
val hook = FeatureHook.noop
242249
for {

0 commit comments

Comments
 (0)