diff --git a/CHANGELOG.md b/CHANGELOG.md index 8027204..43e108e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,48 @@ +## [2.0.0] - 2024-12-11 + +- This version aims to reduce the `Result` boilerplate by making the `Failure` type Exception by default. This will free the Result from having to type `Failure`, making the declaration smaller. + +If there is a need to type `Failure`, use `ResultDart`. + +### Added +- Introduced `typedef` for `Result` and `AsyncResult` to simplify usage: + - `Result` is a simplified alias for `ResultDart`. + - `AsyncResult` is a simplified alias for `AsyncResultDart`. + +### Changed +- Replaced `Result` class with `ResultDart` as the base class for all results. + - Default failure type for `ResultDart` is now `Exception`. + - This change reduces boilerplate and improves usability by eliminating the need to specify the failure type explicitly in most cases. + +### Removed + +- Remove factories `Result.success` and `Result.failure`. + + +### Migration Guide +- In version >=2.0.0, the Failure typing is by default an `Exception`, but if there is a need to type it, use `ResultDart`. + +only `Success` type: +```dart +// Old +Result myResult = Success(42); + +// NEW +Result myResult = Success(42); + +``` + +with `Success` and `Failure` types: +```dart +// Old +Result myResult = Success(42); + +// NEW +ResultDart myResult = Success(42); + +``` + + ## [1.1.1] - 2023-07-05 * pump Dart version to 3.0.0 diff --git a/README.md b/README.md index 3fbf74d..b62ba6b 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@

This package aims to create an implemetation of Kotlin's and Swift's Result class and own operators. - Inspired by Higor Lapa's multiple_result package, the `dartz` package and the `fpdart` package. + Inspired by `multiple_result` package, the `dartz` package and the `fpdart` package.
Explore the docs ยป @@ -46,8 +46,7 @@

Table of Contents
  1. About The Project
  2. -
  3. Sponsors
  4. -
  5. Getting Started
  6. + m
  7. Getting Started
  8. How to Use
  9. Features
  10. Contributing
  11. @@ -85,25 +84,39 @@ But the other layers of code need to know about the two main values `[Success, F

    (back to top)

    - - -## Sponsors - - Logo - +## Migrate 1.1.1 to 2.0.0 -

    (back to top)

    -
    +This version aims to reduce the `Result` boilerplate by making the `Failure` type Exception by default. This will free the Result from having to type `Failure`, making the declaration smaller. + +```dart +// Old +Result myResult = Success(42); + +// NEW +Result myResult = Success(42); + +``` + +if there is a need to type it, use `ResultDart`: + +```dart +// Old +Result myResult = Success(42); + +// NEW +ResultDart myResult = Success(42); + +``` ## Getting Started -To get result_dart working in your project follow either of the instructions below: +To get `result_dart` working in your project follow either of the instructions below: -a) Add result_dart as a dependency in your Pubspec.yaml: +a) Add `result_dart` as a dependency in your Pubspec.yaml: ```yaml dependencies: result_dart: x.x.x @@ -129,7 +142,7 @@ Result getSomethingPretty(); then add the Success and the Failure types. ```dart -Result getSomethingPretty() { +Result getSomethingPretty() { } @@ -140,9 +153,6 @@ In the return of the above function, you just need to use: // Using Normal instance return Success('Something Pretty'); -// Using Result factory -return Result.success('Something Pretty'); - // import 'package:result_dart/functions.dart' return successOf('Something Pretty'); @@ -156,9 +166,6 @@ or // Using Normal instance return Failure(Exception('something ugly happened...')); -// Using Result factory -return Result.failure('something ugly happened...'); - // import 'package:result_dart/functions.dart' return failureOf('Something Pretty'); @@ -170,7 +177,7 @@ The function should look something like this: ```dart -Result getSomethingPretty() { +Result getSomethingPretty() { if(isOk) { return Success('OK!'); } else { @@ -183,7 +190,7 @@ or when using extensions, like this: ```dart -Result getSomethingPretty() { +Result getSomethingPretty() { if(isOk) { return 'OK!'.toSuccess(); } else { @@ -412,7 +419,7 @@ void main() { Some results do not need a specific return. Use the Unit type to signal an **empty** return. ```dart - Result + Result ``` ### Help with functions that return their parameter: @@ -423,7 +430,7 @@ NOTE: use import 'package:result_dart/functions.dart' Sometimes it is necessary to return the parameter of the function as in this example: ```dart -final result = Success(0); +final result = Success(0); String value = result.when((s) => '$s', (e) => e); print(string) // "0"; @@ -432,7 +439,7 @@ print(string) // "0"; We can use the `identity` function or its acronym `id` to facilitate the declaration of this type of function that returns its own parameter and does nothing else: ```dart -final result = Success(0); +final result = Success(0); // changed `(e) => e` by `id` String value = result.when((s) => '$s', id); @@ -452,7 +459,7 @@ All **Result** operators is available in **AsyncResult** ```dart -AsyncResult fetchProducts() async { +AsyncResult fetchProducts() async { try { final response = await dio.get('/products'); final products = ProductModel.fromList(response.data); diff --git a/example/cpf_validator.dart b/example/cpf_validator.dart index 0e8d61f..a8e53ca 100644 --- a/example/cpf_validator.dart +++ b/example/cpf_validator.dart @@ -11,13 +11,13 @@ void main(List args) { print('CPF Validator: ${result.isSuccess()}'); } -Result getTerminalInput() { +Result getTerminalInput() { final text = stdin.readLineSync(); if (text == null || text.isEmpty) { - return const Result.failure(ValidatorException('Incorrect input')); + return const Failure(ValidatorException('Incorrect input')); } - return Result.success(text); + return Success(text); } String removeSpecialCharacteres(String input) { @@ -25,28 +25,28 @@ String removeSpecialCharacteres(String input) { return input.replaceAll(reg, ''); } -Result, ValidatorException> parseNumbers(String input) { +Result> parseNumbers(String input) { if (input.isEmpty) { - return const Result.failure(ValidatorException('Input is Empty')); + return const Failure(ValidatorException('Input is Empty')); } try { - final list = input.split('').map((e) => int.parse(e)).toList(); - return Result.success(list); + final list = input.split('').map(int.parse).toList(); + return Success(list); } catch (e) { - return const Result.failure(ValidatorException('Parse error')); + return const Failure(ValidatorException('Parse error')); } } bool validateCPF(List numberDigits) { final secondRef = numberDigits.removeLast(); - final int secondDigit = calculateDigit(numberDigits); + final secondDigit = calculateDigit(numberDigits); if (secondRef != secondDigit) { return false; } final firstRef = numberDigits.removeLast(); - final int firstDigit = calculateDigit(numberDigits); + final firstDigit = calculateDigit(numberDigits); return firstRef == firstDigit; } diff --git a/lib/functions.dart b/lib/functions.dart index 2739177..53b2bfe 100644 --- a/lib/functions.dart +++ b/lib/functions.dart @@ -39,11 +39,11 @@ T identity(T a) => a; T id(T a) => a; /// Build a [Result] that returns a [Failure]. -Result successOf(S success) { - return Result.success(success); +ResultDart successOf(S success) { + return Success(success); } /// Build a [Result] that returns a [Failure]. -Result failureOf(F failure) { - return Result.failure(failure); +ResultDart failureOf(F failure) { + return Failure(failure); } diff --git a/lib/result_dart.dart b/lib/result_dart.dart index d5cd72f..c4764af 100644 --- a/lib/result_dart.dart +++ b/lib/result_dart.dart @@ -1,6 +1,7 @@ library result_dart; export 'src/async_result.dart'; -export 'src/result.dart'; +export 'src/result_dart_base.dart'; export 'src/result_extension.dart'; +export 'src/types.dart'; export 'src/unit.dart'; diff --git a/lib/src/async_result.dart b/lib/src/async_result.dart index f7c10ba..bee0f72 100644 --- a/lib/src/async_result.dart +++ b/lib/src/async_result.dart @@ -2,31 +2,31 @@ import 'dart:async'; import '../result_dart.dart'; -/// `AsyncResult` represents an asynchronous computation. -typedef AsyncResult = Future>; +/// `AsyncResultDart` represents an asynchronous computation. +typedef AsyncResultDart = Future>; -/// `AsyncResult` represents an asynchronous computation. -extension AsyncResultExtension // - on AsyncResult { +/// `AsyncResultDart` represents an asynchronous computation. +extension AsyncResultDartExtension // + on AsyncResultDart { /// Returns a new `Result`, mapping any `Success` value /// using the given transformation and unwrapping the produced `Result`. - AsyncResult flatMap( - FutureOr> Function(S success) fn, + AsyncResultDart flatMap( + FutureOr> Function(S success) fn, ) { return then((result) => result.fold(fn, Failure.new)); } /// Returns a new `Result`, mapping any `Error` value /// using the given transformation and unwrapping the produced `Result`. - AsyncResult flatMapError( - FutureOr> Function(F error) fn, + AsyncResultDart flatMapError( + FutureOr> Function(F error) fn, ) { return then((result) => result.fold(Success.new, fn)); } - /// Returns a new `AsyncResult`, mapping any `Success` value + /// Returns a new `AsyncResultDart`, mapping any `Success` value /// using the given transformation. - AsyncResult map( + AsyncResultDart map( FutureOr Function(S success) fn, ) { return then( @@ -43,7 +43,7 @@ extension AsyncResultExtension // /// Returns a new `Result`, mapping any `Error` value /// using the given transformation. - AsyncResult mapError( + AsyncResultDart mapError( FutureOr Function(F error) fn, ) { return then( @@ -59,18 +59,18 @@ extension AsyncResultExtension // } /// Change a [Success] value. - AsyncResult pure(W success) { + AsyncResultDart pure(W success) { return then((result) => result.pure(success)); } /// Change the [Failure] value. - AsyncResult pureError(W error) { + AsyncResultDart pureError(W error) { return mapError((_) => error); } /// Swap the values contained inside the [Success] and [Failure] - /// of this [AsyncResult]. - AsyncResult swap() { + /// of this [AsyncResultDart]. + AsyncResultDart swap() { return then((result) => result.swap()); } @@ -125,8 +125,8 @@ extension AsyncResultExtension // /// Returns the encapsulated `Result` of the given transform function /// applied to the encapsulated a `Failure` or the original /// encapsulated value if it is success. - AsyncResult recover( - FutureOr> Function(F failure) onFailure, + AsyncResultDart recover( + FutureOr> Function(F failure) onFailure, ) { return then((result) => result.fold(Success.new, onFailure)); } @@ -134,13 +134,13 @@ extension AsyncResultExtension // /// Performs the given action on the encapsulated Throwable /// exception if this instance represents failure. /// Returns the original Result unchanged. - AsyncResult onFailure(void Function(F failure) onFailure) { + AsyncResultDart onFailure(void Function(F failure) onFailure) { return then((result) => result.onFailure(onFailure)); } /// Performs the given action on the encapsulated value if this /// instance represents success. Returns the original Result unchanged. - AsyncResult onSuccess(void Function(S success) onSuccess) { + AsyncResultDart onSuccess(void Function(S success) onSuccess) { return then((result) => result.onSuccess(onSuccess)); } } diff --git a/lib/src/result.dart b/lib/src/result_dart_base.dart similarity index 69% rename from lib/src/result.dart rename to lib/src/result_dart_base.dart index 1d88e6e..2a35c65 100644 --- a/lib/src/result.dart +++ b/lib/src/result_dart_base.dart @@ -1,20 +1,13 @@ import 'package:meta/meta.dart'; +import 'package:result_dart/result_dart.dart'; -import 'async_result.dart'; import 'unit.dart' as type_unit; /// Base Result class /// /// Receives two values [F] and [S] /// as [F] is an error and [S] is a success. -@sealed -abstract class Result { - /// Build a [Result] that returns a [Failure]. - const factory Result.success(S s) = Success; - - /// Build a [Result] that returns a [Failure]. - const factory Result.failure(F e) = Failure; - +sealed class ResultDart { /// Returns the success value as a throwing expression. S getOrThrow(); @@ -49,53 +42,55 @@ abstract class Result { /// Performs the given action on the encapsulated value if this /// instance represents success. Returns the original Result unchanged. - Result onSuccess( + ResultDart onSuccess( void Function(S success) onSuccess, ); /// Performs the given action on the encapsulated Throwable /// exception if this instance represents failure. /// Returns the original Result unchanged. - Result onFailure( + ResultDart onFailure( void Function(F failure) onFailure, ); /// Returns a new `Result`, mapping any `Success` value /// using the given transformation. - Result map(W Function(S success) fn); + ResultDart map(W Function(S success) fn); /// Returns a new `Result`, mapping any `Error` value /// using the given transformation. - Result mapError(W Function(F error) fn); + ResultDart mapError(W Function(F error) fn); /// Returns a new `Result`, mapping any `Success` value /// using the given transformation and unwrapping the produced `Result`. - Result flatMap(Result Function(S success) fn); + ResultDart flatMap( + ResultDart Function(S success) fn, + ); /// Returns a new `Result`, mapping any `Error` value /// using the given transformation and unwrapping the produced `Result`. - Result flatMapError( - Result Function(F error) fn, + ResultDart flatMapError( + ResultDart Function(F error) fn, ); /// Change the [Success] value. - Result pure(W success); + ResultDart pure(W success); /// Change the [Failure] value. - Result pureError(W error); + ResultDart pureError(W error); /// Return a [AsyncResult]. - AsyncResult toAsyncResult(); + AsyncResultDart toAsyncResult(); /// Swap the values contained inside the [Success] and [Failure] /// of this [Result]. - Result swap(); + ResultDart swap(); /// Returns the encapsulated `Result` of the given transform function /// applied to the encapsulated a `Failure` or the original /// encapsulated value if it is success. - Result recover( - Result Function(F failure) onFailure, + ResultDart recover( + ResultDart Function(F failure) onFailure, ); } @@ -104,7 +99,9 @@ abstract class Result { /// return it when the result of a [Result] is /// the expected value. @immutable -class Success implements Result { +final class Success // + implements + ResultDart { /// Receives the [S] param as /// the successful result. const Success( @@ -150,19 +147,21 @@ class Success implements Result { S getOrNull() => _success; @override - Result flatMap(Result Function(S success) fn) { + ResultDart flatMap( + ResultDart Function(S success) fn, + ) { return fn(_success); } @override - Result flatMapError( - Result Function(F failure) fn, + ResultDart flatMapError( + ResultDart Function(F failure) fn, ) { return Success(_success); } @override - Result swap() { + ResultDart swap() { return Failure(_success); } @@ -180,43 +179,43 @@ class Success implements Result { S getOrDefault(S defaultValue) => _success; @override - Result map(W Function(S success) fn) { + ResultDart map(W Function(S success) fn) { final newSuccess = fn(_success); return Success(newSuccess); } @override - Result mapError(W Function(F error) fn) { + ResultDart mapError(W Function(F error) fn) { return Success(_success); } @override - Result pure(W success) { + ResultDart pure(W success) { return map((_) => success); } @override - Result pureError(W error) { + ResultDart pureError(W error) { return Success(_success); } @override - Result recover( - Result Function(F failure) onFailure, + ResultDart recover( + ResultDart Function(F failure) onFailure, ) { return Success(_success); } @override - AsyncResult toAsyncResult() async => this; + AsyncResultDart toAsyncResult() async => this; @override - Result onFailure(void Function(F failure) onFailure) { + ResultDart onFailure(void Function(F failure) onFailure) { return this; } @override - Result onSuccess(void Function(S success) onSuccess) { + ResultDart onSuccess(void Function(S success) onSuccess) { onSuccess(_success); return this; } @@ -224,10 +223,12 @@ class Success implements Result { /// Error Result. /// -/// return it when the result of a [Result] is +/// return it when the result of a [ResultDart] is /// not the expected value. @immutable -class Failure implements Result { +final class Failure // + implements + ResultDart { /// Receives the [F] param as /// the error result. const Failure(this._failure); @@ -270,19 +271,21 @@ class Failure implements Result { S? getOrNull() => null; @override - Result flatMap(Result Function(S success) fn) { + ResultDart flatMap( + ResultDart Function(S success) fn, + ) { return Failure(_failure); } @override - Result flatMapError( - Result Function(F failure) fn, + ResultDart flatMapError( + ResultDart Function(F failure) fn, ) { return fn(_failure); } @override - Result swap() { + ResultDart swap() { return Success(_failure); } @@ -300,44 +303,44 @@ class Failure implements Result { S getOrDefault(S defaultValue) => defaultValue; @override - Result map(W Function(S success) fn) { + ResultDart map(W Function(S success) fn) { return Failure(_failure); } @override - Result mapError(W Function(F failure) fn) { + ResultDart mapError(W Function(F failure) fn) { final newFailure = fn(_failure); return Failure(newFailure); } @override - Result pure(W success) { + ResultDart pure(W success) { return Failure(_failure); } @override - Result pureError(W error) { + ResultDart pureError(W error) { return mapError((failure) => error); } @override - Result recover( - Result Function(F failure) onFailure, + ResultDart recover( + ResultDart Function(F failure) onFailure, ) { return onFailure(_failure); } @override - AsyncResult toAsyncResult() async => this; + AsyncResultDart toAsyncResult() async => this; @override - Result onFailure(void Function(F failure) onFailure) { + ResultDart onFailure(void Function(F failure) onFailure) { onFailure(_failure); return this; } @override - Result onSuccess(void Function(S success) onSuccess) { + ResultDart onSuccess(void Function(S success) onSuccess) { return this; } } diff --git a/lib/src/result_extension.dart b/lib/src/result_extension.dart index 3afbd21..7ac4436 100644 --- a/lib/src/result_extension.dart +++ b/lib/src/result_extension.dart @@ -8,7 +8,7 @@ extension ResultObjectExtension on W { /// Will throw an error if used on a `Result` or `Future` instance. Failure toFailure() { assert( - this is! Result, + this is! ResultDart, 'Don`t use the "toError()" method ' 'on instances of the Result.', ); @@ -26,7 +26,7 @@ extension ResultObjectExtension on W { /// Will throw an error if used on a `Result` or `Future` instance. Success toSuccess() { assert( - this is! Result, + this is! ResultDart, 'Don`t use the "toSuccess()" method ' 'on instances of the Result.', ); diff --git a/lib/src/types.dart b/lib/src/types.dart new file mode 100644 index 0000000..a3d7b66 --- /dev/null +++ b/lib/src/types.dart @@ -0,0 +1,18 @@ +import 'package:result_dart/result_dart.dart'; + +/// A typedef for a `Result` that simplifies the usage of `ResultDart` +/// with `Exception` as the default failure type. +/// +/// This is used to represent operations that can succeed with a +/// value of type `S` +/// or fail with an `Exception`. +typedef Result = ResultDart; + +/// A typedef for an asynchronous `Result`, simplifying the usage +/// of `AsyncResultDart` +/// with `Exception` as the default failure type. +/// +/// This is used to represent asynchronous operations that can succeed +/// with a value of type `S` +/// or fail with an `Exception`. +typedef AsyncResult = AsyncResultDart; diff --git a/pubspec.lock b/pubspec.lock index fa08051..30d3442 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: dart_internal - sha256: dae3976f383beddcfcd07ad5291a422df2c8c0a8a03c52cda63ac7b4f26e0f4e + sha256: "781e0d03812e5b52fdc3f71540b178245021be64d22cbc88da2aee6b45705183" url: "https://pub.dev" source: hosted - version: "0.2.8" + version: "0.2.13" file: dependency: transitive description: @@ -378,4 +378,4 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.0.0 <3.7.0" diff --git a/pubspec.yaml b/pubspec.yaml index 6755b68..97be56d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: result_dart description: Result for dart. It is an implementation based on Kotlin Result and Swift Result. -version: 1.1.1 +version: 2.0.0 repository: https://github.com/Flutterando/result_dart environment: diff --git a/test/src/result_extension_test.dart b/test/src/result_extension_test.dart index 471d749..912d9e5 100644 --- a/test/src/result_extension_test.dart +++ b/test/src/result_extension_test.dart @@ -1,4 +1,4 @@ -import 'package:result_dart/src/result.dart'; +import 'package:result_dart/src/result_dart_base.dart'; import 'package:result_dart/src/result_extension.dart'; import 'package:test/test.dart'; @@ -7,21 +7,21 @@ void main() { test('without result type', () { final result = 'error'.toFailure(); - expect(result, isA>()); + expect(result, isA>()); expect(result.exceptionOrNull(), isA()); expect(result.exceptionOrNull(), 'error'); }); test('with result type', () { - final Result result = 'error'.toFailure(); + final ResultDart result = 'error'.toFailure(); - expect(result, isA>()); + expect(result, isA>()); expect(result.exceptionOrNull(), isA()); expect(result.exceptionOrNull(), 'error'); }); test('throw AssertException if is a Result object', () { - final Result result = 'error'.toFailure(); + final ResultDart result = 'error'.toFailure(); expect(result.toFailure, throwsA(isA())); }); @@ -34,14 +34,14 @@ void main() { test('without result type', () { final result = 'success'.toSuccess(); - expect(result, isA>()); + expect(result, isA>()); expect(result.getOrNull(), 'success'); }); test('with result type', () { - final Result result = 'success'.toSuccess(); + final ResultDart result = 'success'.toSuccess(); - expect(result, isA>()); + expect(result, isA>()); expect(result.getOrNull(), 'success'); }); diff --git a/test/src/result_test.dart b/test/src/result_test.dart index 32bc981..f7491ec 100644 --- a/test/src/result_test.dart +++ b/test/src/result_test.dart @@ -17,7 +17,7 @@ void main() { }); test('Success.unit type infer', () { - Result fn() { + ResultDart fn() { return Success.unit(); } @@ -31,7 +31,7 @@ void main() { }); test('Error.unit type infer', () { - Result fn() { + ResultDart fn() { return Failure.unit(); } @@ -40,16 +40,6 @@ void main() { }); }); - test('Result.success', () { - const result = Result.success(0); - expect(result.getOrNull(), 0); - }); - - test('Result.error', () { - const result = Result.failure(0); - expect(result.exceptionOrNull(), 0); - }); - test(''' Given a success result, When getting the result through tryGetSuccess, @@ -297,12 +287,12 @@ Given a success result, }); } -Result getMockedSuccessResult() { +ResultDart getMockedSuccessResult() { return Success.unit(); } class MyUseCase { - Result call({bool returnError = false}) { + ResultDart call({bool returnError = false}) { if (returnError) { return const Failure(MyException('something went wrong')); } else {