From 4893cf5ece77ab042b34cc1e2d6e56f58a970214 Mon Sep 17 00:00:00 2001 From: Laurent Couturier Date: Fri, 5 Jul 2024 18:01:11 +0200 Subject: [PATCH] feat: :sparkles: add when extension method on base state --- packages/value_state/lib/src/extensions.dart | 46 ++++++++--- .../value_state/test/extensions_test.dart | 79 ++++++++++++------- 2 files changed, 89 insertions(+), 36 deletions(-) diff --git a/packages/value_state/lib/src/extensions.dart b/packages/value_state/lib/src/extensions.dart index 3720f11..5f5a90c 100644 --- a/packages/value_state/lib/src/extensions.dart +++ b/packages/value_state/lib/src/extensions.dart @@ -2,6 +2,39 @@ import 'perform.dart'; import 'states.dart'; extension ObjectWithValueExtensions on BaseState { + /// Destructuring pattern-matching + /// + /// Example : + /// ```dart + /// const String? nullStr = null; + /// final result = nullStr.toState().when( + /// onValue: (state) => 'Value', + /// onError: (error) => 'Error', + /// orElse: () => 'Null value', + /// ); + /// ``` + R when({ + R Function()? onWaiting, + R Function()? onNoValue, + R Function(T value)? onValue, + R Function(Object error)? onError, + required R Function() orElse, + }) { + final state = this; + + if (state is WaitingState) { + return onWaiting?.call() ?? orElse(); + } else if (state is NoValueState) { + return onNoValue?.call() ?? orElse(); + } else if (state is ValueState) { + return onValue?.call(state.value) ?? orElse(); + } else if (state is ErrorState) { + return onError?.call(state.error) ?? orElse(); + } + + return orElse(); + } + /// Shortcut on [BaseState] to easily handle [WithValueState] state. It can be used in different case : /// * To return a value /// ```dart @@ -27,12 +60,10 @@ extension ObjectWithValueExtensions on BaseState { /// Shorcut to [withValue] with its parameter `onlyValueState` set to `true`. It is equivalent to handle only /// [ValueState] state. - R? whenValue(R Function(T value) onValue) => - withValue(onValue, onlyValueState: true); + R? whenValue(R Function(T value) onValue) => withValue(onValue, onlyValueState: true); /// Shorcut to [withValue] which return the value if avaible. [onlyValueState] is the same as [withValue]. - T? toValue({bool onlyValueState = false}) => - withValue((value) => value, onlyValueState: onlyValueState); + T? toValue({bool onlyValueState = false}) => withValue((value) => value, onlyValueState: onlyValueState); } extension OrExtensions on R? { @@ -55,9 +86,7 @@ extension ToReadyStateExtensions on T? { /// * else it returns a [NoValueState] ReadyState toState({bool refreshing = false}) { final state = this; - return state == null - ? NoValueState(refreshing: refreshing) - : ValueState(state, refreshing: refreshing); + return state == null ? NoValueState(refreshing: refreshing) : ValueState(state, refreshing: refreshing); } } @@ -71,6 +100,5 @@ extension FutureValueStateExtension on Future { } /// Generate a stream of [BaseState] during a processing [Future]. - Stream> toStates() => - InitState().perform((_) => toFutureState()); + Stream> toStates() => InitState().perform((_) => toFutureState()); } diff --git a/packages/value_state/test/extensions_test.dart b/packages/value_state/test/extensions_test.dart index 578aee2..1fe948f 100644 --- a/packages/value_state/test/extensions_test.dart +++ b/packages/value_state/test/extensions_test.dart @@ -5,18 +5,57 @@ void main() { const myStr = 'My String'; const myStrOrElse = 'My String orElse'; + group('when()', () { + test('on a non null String', () { + final result = myStr.toState().when( + onWaiting: () => 'Waiting', + onNoValue: () => 'No Value', + onValue: (value) => value, + onError: (error) => 'Error', + orElse: () => 'Else', + ); + + expect(result, 'My String'); + }); + + test('on null', () { + const String? nullStr = null; + + final result = nullStr.toState().when( + onWaiting: () => 'Waiting', + onNoValue: () => 'No Value', + onValue: (state) => 'Value', + onError: (error) => 'Error', + orElse: () => 'Else', + ); + + expect(result, 'No Value'); + }); + + test('orElse', () { + const String? nullStr = null; + + final result = nullStr.toState().when( + onValue: (state) => 'Value', + onError: (error) => 'Error', + orElse: () => 'Else', + ); + + expect(result, 'Else'); + }); + }); + group('toState()', () { test('on a non null String', () { expect(myStr.toState(), const ValueState(myStr)); - expect(myStr.toState(refreshing: true), - const ValueState(myStr, refreshing: true)); + expect(myStr.toState(refreshing: true), const ValueState(myStr, refreshing: true)); }); + test('on null', () { const String? nullStr = null; expect(nullStr.toState(), const NoValueState()); - expect(nullStr.toState(refreshing: true), - const NoValueState(refreshing: true)); + expect(nullStr.toState(refreshing: true), const NoValueState(refreshing: true)); }); }); @@ -42,39 +81,32 @@ void main() { }); test('on a $InitState with onlyValueState to true', () { - final result = - const InitState().withValue(modifier, onlyValueState: true); + final result = const InitState().withValue(modifier, onlyValueState: true); expect(result, isNull); }); test('on a $ErrorState', () { - final result = - ErrorState(error: 'Error', previousState: myStr.toState()) - .withValue(modifier); + final result = ErrorState(error: 'Error', previousState: myStr.toState()).withValue(modifier); expect(result, modifier(myStr)); }); test('on a $ErrorState with onlyValueState to true', () { final result = - ErrorState(error: 'Error', previousState: myStr.toState()) - .withValue(modifier, onlyValueState: true); + ErrorState(error: 'Error', previousState: myStr.toState()).withValue(modifier, onlyValueState: true); expect(result, isNull); }); test('orElse on a $ValueState', () { - final result = - myStr.toState().withValue(modifier).orElse(() => myStrOrElse); + final result = myStr.toState().withValue(modifier).orElse(() => myStrOrElse); expect(result, modifier(myStr)); }); test('orElse on a $InitState', () { - final result = const InitState() - .withValue(modifier) - .orElse(() => myStrOrElse); + final result = const InitState().withValue(modifier).orElse(() => myStrOrElse); expect(result, myStrOrElse); }); @@ -97,9 +129,7 @@ void main() { }); test('on a $ErrorState', () { - final result = - ErrorState(error: 'Error', previousState: myStr.toState()) - .whenValue(modifier); + final result = ErrorState(error: 'Error', previousState: myStr.toState()).whenValue(modifier); expect(result, isNull); }); @@ -131,17 +161,13 @@ void main() { }); test('on a $ErrorState', () { - final result = - ErrorState(error: 'Error', previousState: myStr.toState()) - .toValue(); + final result = ErrorState(error: 'Error', previousState: myStr.toState()).toValue(); expect(result, myStr); }); test('on a $ErrorState with onlyValueState to true', () { - final result = - ErrorState(error: 'Error', previousState: myStr.toState()) - .toValue(onlyValueState: true); + final result = ErrorState(error: 'Error', previousState: myStr.toState()).toValue(onlyValueState: true); expect(result, isNull); }); @@ -151,8 +177,7 @@ void main() { const value = 'Result'; expect(Future.value(value).toFutureState(), completion(value.toState())); - expect(Future.value(null).toFutureState(), - completion(const NoValueState())); + expect(Future.value(null).toFutureState(), completion(const NoValueState())); }); test('toStates', () {