Skip to content

Releases: SandroMaglione/fpdart

v1.1.0

13 Aug 11:13
6757450
Compare
Choose a tag to compare
  • Improved performance of some iterable based functions in Iterable and Map extension (thanks to @lrhn 🎉)

  • Added lookupEq and dropRight on Iterable extension

[].lookupEq(Eq.eqInt, 5) // None()
[1, 2, 3, 4].lookupEq(Eq.eqInt, 5) // None()
[1, 2, 3, 4].lookupEq(Eq.eqInt, 3) // Some(3)
[1, 6, 4, 3, 2].lookupEq(Eq.by((n) => n % 3, Eq.eqInt), 0) // Some(6)

[1, 2].dropRight(3) // []
[1, 2, 3, 4].dropRight(1) // [1, 2, 3]
  • Added lookupKeyEq on Map extension
<String, int>{'a': 1, 'b': 2, 'c': 3, 'd': 4}.lookupKeyEq(Eq.eqString, 'b'); // Some('b')
<String, int>{'a': 1, 'b': 2, 'c': 3, 'd': 4}.lookupKeyEq(Eq.eqString, 'e'); // None()

v1.0.0

26 Jul 10:35
a4fad89
Compare
Choose a tag to compare
  • Minimum environment dart sdk to 3.0.0 ⚠️ (Dart 3️⃣)
environment:
  sdk: ">=3.0.0 <4.0.0"
  • Added new ReaderTaskEither type
    • ReaderTaskEither models a complete program using Reader for dependency injection, Task to perform asynchronous computation, and Either to handle errors 🎯
  • Added new ReaderTask type
  • Either as sealed class (Dart 3️⃣)
    • You can now use exhaustive pattern matching (Left or Right)
/// Pattern matching
final match = right.match(
  (l) => print('Left($l)'),
  (r) => print('Right($r)'),
);

/// or use Dart's pattern matching as well 🤝
final dartMatch = switch (right) {
  Left(value: final l) => 'Left($l)',
  Right(value: final r) => 'Right($r)',
};
  • Option as sealed class (Dart 3️⃣)
    • You can now use exhaustive pattern matching (None or Some)
/// Pattern matching
final match = option.match(
  () => print('None'),
  (a) => print('Some($a)'),
);

/// or use Dart's pattern matching as well 🤝
final dartMatch = switch (option) {
  None() => 'None',
  Some(value: final a) => 'Some($a)',
};
  • Types marked as final (no extends nor implements) (Dart 3️⃣)
    • Unit
    • Reader
    • State
    • StateAsync
    • IO
    • IORef
    • IOOption
    • IOEither
    • Task
    • TaskOption
    • TaskEither
    • ReaderTask
    • ReaderTaskEither
  • Removed Tuple2, use Dart 3 Records instead (Tuple2(a, b) becomes simply (a, b) 🎯) ⚠️ (Dart 3️⃣)
    • Updated all internal APIs to use records instead of Tuple2
  • Major refactoring of Iterable and List extension methods
    • Improved performance
    • Correct return types (Iterable and List) (#65)
    • Added the following methods
      • prependAll (Iterable)
      • intersperse (Iterable)
      • difference (Iterable)
      • filterWithIndex (Iterable)
    • Fixed the following methods ⚠️
      • takeWhileRight: Resulting List now in reversed order as expected
      • dropWhileRight: Resulting List now in reversed order as expected
    • Updated the following methods ⚠️
      • foldRight, foldRightWithIndex (List): Changed parameter order in combine function
      • zipWith (Iterable): Changed parameters definition, no more curried
    • Renamed the following methods ⚠️
      • plusconcat (Iterable)
      • concatflatten (on Iterable<Iterable<T>>)
    • Removed the following methods ⚠️
      • concatMap (use flatMap instead)
      • bind (use flatMap instead)
      • bindWithIndex (use flatMapWithIndex instead)
      • concatMapWithIndex (use flatMapWithIndex instead)
  • Refactoring of Map extension methods
    • Improved performance
    • Added the following methods
      • lookupEq
      • lookupWithKeyEq
    • Removed the following methods ⚠️
      • member (use containsKey instead)
      • elem (use containsValue instead)
      • toIterable (use toSortedList instead)
    • Updated the following methods ⚠️
      • toIterable renamed to toSortedList (return a List instead of Iterable)
      • modifyAt changed parameter order and no more curried
      • modifyAtIfPresent changed parameter order and no more curried
      • updateAt no more curried
      • updateAtIfPresent no more curried
      • deleteAt no more curried
      • upsertAt no more curried
      • pop no more curried
      • foldLeft no more curried
      • foldLeftWithKey no more curried
      • foldLeftWithIndex no more curried
      • foldLeftWithKeyAndIndex no more curried
      • foldRight no more curried
      • foldRightWithKey no more curried
      • foldRightWithIndex no more curried
      • foldRightWithKeyAndIndex no more curried
      • union no more curried
      • intersection no more curried
      • isSubmap no more curried
      • collect no more curried
      • difference no more curried
  • Added conversions helpers from String to num, int, double, and bool using Option and Either (both as extension methods on String and as functions) (#80)
    • toNumOption
    • toIntOption
    • toDoubleOption
    • toBoolOption
    • toNumEither
    • toIntEither
    • toDoubleEither
    • toBoolEither
/// As extension on [String]
final result = "10".toNumOption; /// `Some(10)`
final result = "10.5".toNumOption; /// `Some(10.5)`
final result = "0xFF".toIntOption; /// `Some(255)`
final result = "10.5".toDoubleOption; /// `Some(10.5)`
final result = "NO".toBoolEither(() => "left"); /// `Left("left")`

/// As functions
final result = toNumOption("10"); /// `Some(10)`
final result = toNumOption("10.5"); /// `Some(10.5)`
final result = toIntOption("0xFF"); /// `Some(255)`
final result = toDoubleOption("10.5"); /// `Some(10.5)`
final result = toBoolEither("NO", () => "left"); /// `Left("left")`
  • Changed dateNow, now, random, and randomBool to getter functions
/// Before
Option<T> getRandomOption<T>(T value) => randomBool()
    .map((isValid) => isValid ? some(value) : none<T>())
    .run();

/// Now
Option<T> getRandomOption<T>(T value) => randomBool
    .map((isValid) => isValid ? some(value) : none<T>())
    .run();
  • Removed Predicate class and added extension methods in its place ⚠️
bool isEven(int n) => n % 2 == 0;
bool isDivisibleBy3(int n) => n % 3 == 0;

final isOdd = isEven.negate;
final isEvenAndDivisibleBy3 = isEven.and(isDivisibleBy3);
final isEvenOrDivisibleBy3 = isEven.or(isDivisibleBy3);
final isStringWithEvenLength = isEven.contramap<String>((n) => n.length);
  • Updated curry / uncarry extensions ⚠️
    • Renamed curry to curryAll for functions with 3, 4, 5 parameters
    • Changed definition of curry to curry only the first parameter
    • Changed uncurry and curry extension to getter function
    • Removed curry and uncurry as functions (use extension method instead)
    • Added curryLast (curry last parameter)
int Function(int) subtractCurried(int n1) => (n2) => n1 - n2;

/// Before
subtractCurried.uncurry()(10, 5);

final addFunction = (int a, int b) => a + b;
final add = curry2(addFunction);

[1, 2, 3].map(add(1));  // returns [2, 3, 4]

/// New
subtractCurried.uncurry(10, 5);

final addFunction = (int a, int b) => a + b;
final add = addFunction.curry;

[1, 2, 3].map(add(1)); // returns [2, 3, 4]
[1, 2, 3].map(addFunction.curry(1)); // returns [2, 3, 4]
  • Changed Eq static constructors to methods
    • or
    • and
  • Added xor method to Eq
  • Moved DateTime instances of Eq as Eq static members
/// Before
final eq = dateEqYear; // Global

/// Now
final eq = Eq.dateEqYear;
  • Added Eq instances for num, int, double, String, and bool
[1, 2, 3].difference(Eq.eqInt, [2, 3, 4]); /// `[1]`
  • Added new method to Eq
    • contramap
class Parent {
  final int value1;
  final double value2;
  const Parent(this.value1, this.value2);
}

/// Equality for values of type [Parent] based on their `value1` ([int]).
final eqParentInt = Eq.eqInt.contramap<Parent>(
  (p) => p.value1,
);

/// Equality for of type [Parent] based on their `value2` ([double]).
final eqParentDouble = Eq.eqDouble.contramap<Parent>(
  (p) => p.value2,
);
  • Changed reverse in Order from static constructor to getter method
/// Before
final reversed = Order.reverse(instance);

/// Now
final reversed = instance.reverse;
  • Moved DateTime instances of Order as Order static members
  • Added Order instances for num, int, double
  • Added new methods to Order
    • between
    • clamp
    • contramap
class Parent {
  final int value1;
  final double value2;
  const Parent(this.value1, this.value2);
}

/// Order values of type [Parent] based on their `value1` ([int]).
final orderParentInt = Order.orderInt.contramap<Parent>(
  (p) => p.value1,
);

/// Order values of type [Parent] based on their `value2` ([double]).
final orderParentDouble = Order.orderDouble.contramap<Parent>(
  (p) => p.value2,
);
  • Removed bool extension (match and fold), use the ternary operator or pattern matching instead ⚠️
final boolValue = Random().nextBool();

/// Before
final result = boolValue.match<int>(() => -1, () => 1);
final result = boolValue.fold<int>(() => -1, () => 1);

/// Now
final result = boolValue ? 1 : -1;
final result = switch (boolValue) { true => 1, false => -1 };

v0.6.0

06 May 10:03
46f28a1
Compare
Choose a tag to compare
  • Do notation #97 (Special thanks to @tim-smart 🎉)
    • All the main types now have a Do() constructor used to initialize a Do notation chain
    • Updated examples to use Do notation (new recommended API 🎯)
/// Without the Do notation
String goShopping() => goToShoppingCenter()
    .alt(goToLocalMarket)
    .flatMap(
      (market) => market.buyBanana().flatMap(
            (banana) => market.buyApple().flatMap(
                  (apple) => market.buyPear().flatMap(
                        (pear) => Option.of('Shopping: $banana, $apple, $pear'),
                      ),
                ),
          ),
    )
    .getOrElse(
      () => 'I did not find 🍌 or 🍎 or 🍐, so I did not buy anything 🤷‍♂️',
    );
/// Using the Do notation
String goShoppingDo() => Option.Do(
      ($) {
        final market = $(goToShoppingCenter().alt(goToLocalMarket));
        final amount = $(market.buyAmount());

        final banana = $(market.buyBanana());
        final apple = $(market.buyApple());
        final pear = $(market.buyPear());

        return 'Shopping: $banana, $apple, $pear';
      },
    ).getOrElse(
      () => 'I did not find 🍌 or 🍎 or 🍐, so I did not buy anything 🤷‍♂️',
    );
  • Added new IOOption type
  • Added conversion methods from and to all classes (IO, IOOption, IOEither, Task, TaskOption, TaskEither)
    • Removed toTask in IOEither (use toTaskEither instead) ⚠️
  • Improved performance of fpdart's sortBy list extension #101 (thanks to @hbock-42 🎉)
  • Updated pokeapi_functional example to Riverpod v2 #99 (thanks to @utamori 🎉)
  • Updated repository folder structure #105

v0.5.0

04 Mar 11:27
f716d65
Compare
Choose a tag to compare
  • Updates to Option type #92 [⚠️ BREAKING CHANGE]
    • Added const factory constructor for None (fixes #95)
    • Removed Alt and Foldable type classes, the following methods are not available anymore
      • foldLeft
      • foldRight
      • foldMap
      • foldRightWithIndex
      • foldLeftWithIndex
      • length
      • any
      • all
      • concatenate
      • plus
      • prepend
      • append
  • Updated examples and fixed lint warnings #93 (thanks to tim-smart 🎉)

v0.4.1

25 Feb 17:18
e892c8d
Compare
Choose a tag to compare
  • New methods for Option type (thanks to tim-smart 🎉)
    • flatMapNullable
    • flatMapThrowable
final option = Option.of(10);

option.flatMapNullable((a) => a + 1); /// 👈 `Some(11)`
option.flatMapThrowable((a) => a + 1); /// 👈 `Some(11)`

option.flatMapNullable<int>((a) => null); /// 👈 `None()`
option.flatMapThrowable<int>((a) => throw "fail"); /// 👈 `None()`
  • Improved support fromJson for Option type (thanks [again] to tim-smart 🎉)
    • Allow for decoding of non-primitive types (with custom fromJson constructors)
/// `fromJson` on `DateTime` with `Option` type
final now = DateTime.now();
Option<DateTime>.fromJson(now.toIso8601String(), (a) => DateTime.parse(a as String)); /// 👈 `Some(now)`

Option<DateTime>.fromJson("fail", (a) => DateTime.parse(a as String)); /// 👈 `None()`
  • New extension methods for Map (thanks [once again] to tim-smart 🎉)
    • extract
    • extractMap
final map = <String, dynamic>{'a': 1, 'b': 2, 'c': 3, 'd': 4};
map.extract<int>('b'); /// 👈 `Some(2)`
map.extract<String>('b'); /// 👈 `None()`, not of type `String` ⚠️

final map = <String, dynamic>{'a': 1};
map.extractMap('a'); /// 👈 `None()`, not a `Map`

final map = <String, dynamic>{'a': {'b': 2} };
map.extractMap('a'); /// 👈 `Some({'b': 2})`
  • Option.of and Option.none factories const (thanks to f-person 🎉)

Note: People who have the prefer_const_constructors lint enabled will notice a warning to use const 🤝

v0.4.0

16 Dec 04:50
201b3d0
Compare
Choose a tag to compare
  • Added extension methods to work with nullable types (T?)
    • From T? to fpdart's types
      • toOption
      • toEither
      • toTaskOption
      • toIOEither
      • toTaskEither
      • toTaskEitherAsync
      • fromNullable (Either, IOEither, TaskOption TaskEither)
      • fromNullableAsync (TaskEither)
    • From fpdart's types to T?
      • toNullable (Either)
/// [Option] <-> `int?`
int? value1 = 10.toOption().map((t) => t + 10).toNullable();

bool? value2 = value1?.isEven;

/// `bool?` -> [Either] -> `int?`
int? value3 = value2
    .toEither(() => "Error")
    .flatMap((a) => a ? right<String, int>(10) : left<String, int>("None"))
    .toNullable();

/// `int?` -> [Option]
Option<int> value4 = (value3?.abs().round()).toOption().flatMap(Option.of);
  • Added toIOEither to Either
  • Removed parameter from Either fromNullable [⚠️ BREAKING CHANGE]
final either = Either<String, int>.fromNullable(value, (r) => 'none');

/// 👆 Removed the value `(r)` (it was always null anyway 💁🏼‍♂️) 👇

final either = Either<String, int>.fromNullable(value, () => 'none');
  • Added chainEither to TaskEither
  • Added safeCast (Either and Option)
  • Added safeCastStrict (Either and Option)
int intValue = 10;

/// Unhandled exception: type 'int' is not a subtype of type 'List<int>' in type cast
final waitWhat = intValue as List<int>;
final first = waitWhat.first;

/// Safe 🎯
final wellYeah = Either<String, List<int>>.safeCast(
  intValue,
  (dynamic value) => 'Not a List!',
);
final firstEither = wellYeah.map((list) => list.first);

v0.3.0

11 Oct 13:07
e844fd9
Compare
Choose a tag to compare
  • Inverted onSome and onNone functions parameters in match method of Option [⚠️ BREAKING CHANGE] (Read more on why 👉 #56)
/// Everywhere you are using `Option.match` you must change this:
final match = option.match(
  (a) => print('Some($a)'),
  () => print('None'), // <- `None` second 👎 
);

/// to this (invert parameters order):
final match = option.match(
  () => print('None'), // <- `None` first 👍
  (a) => print('Some($a)'),
);
  • Added traverse and sequence methods (#55)
    • traverseList
    • traverseListWithIndex
    • sequenceList
    • traverseListSeq
    • traverseListWithIndexSeq
    • sequenceListSeq
/// "a40" is invalid 💥
final inputValues = ["10", "20", "30", "a40"];

/// Verify that all the values can be converted to [int] 🔐
///
/// If **any** of them is invalid, then the result is [None] 🙅‍♂️
final traverseOption = inputValues.traverseOption(
  (a) => Option.tryCatch(
    /// If `a` does not contain a valid integer literal a [FormatException] is thrown
    () => int.parse(a),
  ),
);
  • Added bindEither method in TaskEither (#58)
/// Chain [Either] to [TaskEither]
TaskEither<String, int> binding =
    TaskEither<String, String>.of("String").bindEither(Either.of(20));
  • Added lefts, rights, and partitionEithers methods to Either (#57)
final list = [
  right<String, int>(1),
  right<String, int>(2),
  left<String, int>('a'),
  left<String, int>('b'),
  right<String, int>(3),
];
final result = Either.partitionEithers(list);
expect(result.first, ['a', 'b']);
expect(result.second, [1, 2, 3]);
  • Added bimap method to Either, IOEither, and Tuple2 (#57)
  • Added mapLeft method to IOEither (#57)
  • Added fold method to Option (same as match) (#56)
  • Fixed chainFirst for Either, TaskEither, and IOEither when chaining on a failure (Left) (#47) by DevNico 🎉
  • Added const to all constructors in which it was missing (#59)
  • Minimum environment dart sdk to 2.17.0 ⚠️
environment:
  sdk: ">=2.17.0 <3.0.0"

v0.2.0

16 Jul 08:09
Compare
Choose a tag to compare

v0.1.0

17 Jun 14:22
Compare
Choose a tag to compare
  • Added idFuture and identityFuture methods (#38 by f-person 🎉)
  • Added mapBoth method to Tuple2 (#30)
  • Fixed linting warnings
  • Fixed issue with upsert method for Map (#37) ⚠️
  • Minimum environment dart sdk to 2.16.0 ⚠️
environment:
  sdk: ">=2.16.0 <3.0.0"

v0.0.14

31 Jan 17:34
Compare
Choose a tag to compare
  • Updated package linting to lints