Git Product home page Git Product logo

dartx's Introduction

Dart CI Codecov dartx flutterx

If you miss an extension, please open an issue or pull request

Resources:

On this page you can find some of the extensions. Take a look at the docs to see all of them.

Getting started 🎉

Add the following to your pubspec.yaml:

dependencies:
  dartx: any

After you import the library, you can use the extensions.

import 'package:dartx/dartx.dart';

final slice = [1, 2, 3, 4, 5].slice(1, -2); // [2, 3, 4]

Iterable

.slice()

Returns elements at indices between start (inclusive) and end (inclusive).

final list = [0, 1, 2, 3, 4, 5];
final last = list.slice(-1); // [5]
final lastHalf = list.slice(3); // [3, 4, 5]
final allButFirstAndLast = list.slice(1, -2); // [1, 2, 3, 4]

.sortedBy() & .thenBy()

Sort lists by multiple properties.

final dogs = [
  Dog(name: "Tom", age: 3),
  Dog(name: "Charlie", age: 7),
  Dog(name: "Bark", age: 1),
  Dog(name: "Cookie", age: 4),
  Dog(name: "Charlie", age: 2),
];

final sorted = dogs
    .sortedBy((dog) => dog.name)
    .thenByDescending((dog) => dog.age);
// Bark, Charlie (7), Charlie (2), Cookie, Tom

.distinctBy()

Get distinct elements from a list.

final list = ['this', 'is', 'a', 'test'];
final distinctByLength = list.distinctBy((it) => it.length); // ['this', 'is', 'a']

.flatten()

Get a new lazy Iterable of all elements from all collections in a collection.

final nestedList = [[1, 2, 3], [4, 5, 6]];
final flattened = nestedList.flatten(); // [1, 2, 3, 4, 5, 6]

.chunkWhile() & .splitWhen()

Chunk entries as long as two elements match a predicate:

final list = [1, 2, 4, 9, 10, 11, 12, 15, 16, 19, 20, 21];
final increasingSubSequences = list.chunkWhile((a, b) => a + 1 == b);

// increasingSubSequences = [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]

splitWhen is the opposite of chunkWhile that starts a new chunk every time the predicate didn't match.

int

buildString()

Builds new string by populating newly created StringBuffer using provided builderAction and then converting it to String.

final word = buildString((sb) {
  for (var i = 0; i < 10; i++) {
    sb.write(i);
  }
});
// 0123456789

.ordinal

Returns an ordinal number of String type for any integer

final a = 1.ordinal();  // 1st
final b = 108.ordinal();  // 108th

String

.capitalize

Returns a copy of the string having its first letter uppercased, or the original string, if it's empty or already starts with an upper case letter.

final word = 'abcd'.capitalize(); // Abcd
final anotherWord = 'Abcd'.capitalize(); // Abcd

.decapitalize

Returns a copy of the string having its first letter lowercased, or the original string, if it's empty or already starts with a lower case letter.

final word = 'abcd'.decapitalize(); // abcd
final anotherWord = 'Abcd'.decapitalize(); // abcd

.isAscii

Returns true if the string is ASCII encoded.

final isAscii = 'abc123 !,.~'.isAscii; // true
final isNotAscii = '§3'.isAscii; // false

.isBlank

Returns true if this string is empty or consists solely of whitespace characters.

final notBlank = '   .'.isBlank; // false
final blank = '  '.isBlank; // true

.isDouble

Returns true if the string can be parsed as a double.

final a = ''.isDouble; // false
final b = 'a'.isDouble; // false
final c = '1'.isDouble; // true
final d = '1.0'.isDouble; // true
final e = '123456789.987654321'.isDouble; // true
final f = '1,000'.isDouble; // false

.isInt

Returns true if the string can be parsed as an integer.

final a = ''.isInt; // false
final b = 'a'.isInt; // false
final c = '1'.isInt; // true
final d = '1.0'.isInt; // false
final e = '1,000'.isInt; // false

.isLatin1

Returns true if the string is Latin 1 encoded.

final isLatin1 = '§Êü'.isLatin1; // true
final isNotLatin1 = 'ő'.isLatin1; // false

.isLowerCase

Returns true if the entire string is lower case.

final a = 'abc'.isLowerCase; // true
final b = 'abC'.isLowerCase; // false
final c = '   '.isLowerCase; // true
final d = ''.isLowerCase; // false

.isNotBlank

Returns true if this string is not empty and contains characters except whitespace characters.

final blank = '  '.isNotBlank; // false
final notBlank = '   .'.isNotBlank; // true

.isNullOrEmpty

Returns true if the String is either null or empty.

final isNull = null.isNullOrEmpty; // true
final isEmpty = ''.isNullOrEmpty; // true
final isBlank = ' '.isNullOrEmpty; // false
final isLineBreak = '\n'.isNullOrEmpty; // false

.isNotNullOrEmpty

Returns true if the String is neither null nor empty.

final isNull = null.isNullOrEmpty; // true
final isEmpty = ''.isNullOrEmpty; // true
final isBlank = ' '.isNullOrEmpty; // false
final isLineBreak = '\n'.isNullOrEmpty; // false

.isNullOrBlank

Returns true if the String is either null or blank.

final isNull = null.isNullOrBlank; // true
final isEmpty = ''.isNullOrBlank; // true
final isBlank = ' '.isNullOrBlank; // true
final isLineBreak = '\n'.isNullOrBlank; // true
final isFoo = ' foo '.isNullOrBlank; // false

.isNotNullOrBlank

Returns true if the String is neither null nor blank.

final isNull = null.isNullOrBlank; // true
final isEmpty = ''.isNullOrBlank; // true
final isBlank = ' '.isNullOrBlank; // true
final isLineBreak = '\n'.isNullOrBlank; // true
final isFoo = ' foo '.isNullOrBlank; // true

.isUpperCase

Returns true if the entire string is upper case.

final a = 'ABC'.isUpperCase; // true
final b = 'ABc'.isUpperCase; // false
final c = '   '.isUpperCase; // true
final d = ''.isUpperCase; // false

.md5

Calculates the MD5 digest and returns the value as a string of hexadecimal digits.

final a = 'abc'.md5; // 900150983cd24fb0d6963f7d28e17f72
final b = 'ഐ⌛酪Б👨‍👨‍👧‍👦'.md5; // c7834eff7c967101cfb65b8f6d15ad46

.urlEncode

Translates a string into application/x-www-form-urlencoded format using a specific encoding scheme.

const originalUrl = 'Hello Ladies + Gentlemen, a signed OAuth request!';
final encodedUrl = originalUrl.urlEncode;
// 'Hello%20Ladies%20+%20Gentlemen,%20a%20signed%20OAuth%20request!'

.urlDecode

Decodes an application/x-www-form-urlencoded string using a specific encoding scheme.

const encodedUrl = 'Hello%20Ladies%20+%20Gentlemen,%20a%20signed%20OAuth%20request!';
final decodedUrl = encodingUrl.urlDecode;
// 'Hello Ladies + Gentlemen, a signed OAuth request!'

.removePrefix(), .removeSuffix() and .removeSurrounding()

Remove a prefix, a suffix, or both from a given string:

final name = 'James Bond'.removePrefix('James '); // Bond
final milliseconds = '100ms'.removeSuffix('ms'); // 100
final text = '<p>Some HTML</p>'
  .removeSurrounding(prefix: '<p>', suffix: '</p>'); // Some HTML

.reversed

Returns a new string with characters in reversed order.

final emptyString = ''.reversed; // ''
final reversed = 'abc🤔'.reversed; // '🤔cba'

.slice()

Returns a new substring containing all characters including indices [start] and [end]. If [end] is omitted, it is being set to lastIndex.

final sliceOne = 'awesomeString'.slice(0,6)); // awesome
final sliceTwo = 'awesomeString'.slice(7)); // String

.toDoubleOrNull()

Parses the string as a double and returns the result or null if the String is not a valid representation of a number.

final numOne = '1'.toDoubleOrNull(); // 1.0
final numTwo = '1.2'.toDoubleOrNull(); // 1.2
final blank = ''.toDoubleOrNull(); // null

.toInt()

Parses the string as an integer and returns the result. The radix (base) thereby defaults to 10. Throws a FormatException if parsing fails.

final a = '1'.toInt(); // 1
final b = '100'.toInt(radix: 2); // 4
final c = '100'.toInt(radix: 16); // 256
final d = '1.0'.toInt(); // throws FormatException

.toIntOrNull()

Parses the string as an integer or returns null if it is not a number.

final number = '12345'.toIntOrNull(); // 12345
final notANumber = '123-45'.toIntOrNull(); // null

.toUtf8()

Converts String to UTF-8 encoding.

final emptyString = ''.toUtf8(); // []
final hi = 'hi'.toUtf8(); // [104, 105]
final emoji = '😄'.toUtf8(); // [240, 159, 152, 132]

.toUtf16()

Converts String to UTF-16 encoding.

final emptyString = ''.toUtf16(); // []
final hi = 'hi'.toUtf16(); // [104, 105]
final emoji = '😄'.toUtf16(); // [55357, 56836]

.orEmpty()

Returns the string if it is not null, or the empty string otherwise.

String? nullableStr;
final str = nullableStr.orEmpty(); // ''

.matches()

Returns true if this char sequence matches the given regular expression.

print('as'.matches(RegExp('^.s\$'))) // true
print('mst'.matches(RegExp('^.s\$'))) // false

Time utils

Dartx exports @jogboms great ⏰ time.dart package so you can do the following:

int secondsInADay = 1.days.inSeconds;

Duration totalTime = [12.5.seconds, 101.milliseconds, 2.5.minutes].sum();

DateTime oneWeekLater = DateTime.now() + 1.week;

Check out ⏰ time.dart for more information and examples.

num

.coerceIn()

Ensures that this value lies in the specified range.

final numberInRange = 123.coerceIn(0, 1000); // 123
final numberOutOfRange = -123.coerceIn(0, 1000); // 0

.toBytes()

Converts this value to binary form.

.toChar()

Converts this value to character

final character = 97.toChar(); // a

range

rangeTo

Creates a range between two ints (upwards, downwards and with custom steps)

// upwards with default step size 1
for (final i in 1.rangeTo(5)) {
  print(i); // 1, 2, 3, 4, 5
}
// downwards with custom step
for (final i in 10.rangeTo(2).step(2)) {
  print(i); // 10, 8, 6, 4, 2
}

Function

.partial(), .partial2() ...

Applies some of the required arguments to a function and returns a function which takes the remaining arguments.

void greet(String firstName, String lastName) {
  print('Hi $firstName $lastName!');
}

final greetStark = greet.partial('Stark');
greetStark('Sansa'); // Hi Sansa Stark!
greetStark('Tony'); // Hi Tony Stark!

File

.name

Get the name and extension of a file.

final file = File('some/path/testFile.dart');
print(file.name); // testFile.dart
print(file.nameWithoutExtension); // testFile

.appendText()

Append text to a file.

await File('someFile.json').appendText('{test: true}');

.isWithin()

Checks if a file is inside a directory.

final dir = Directory('some/path');
File('some/path/file.dart').isWithin(dir); // true

Directory

.file(String)

References a file within a Directory

Directory androidDir = Directory('flutter-app/android');
File manifestFile = androidDir.file("app/src/main/AndroidManifest.xml");

References a directory within a Directory

.directory(String)

Directory androidDir = Directory('flutter-app/android');
Directory mainSrc = androidDir.directory("app/src/main");

.contains(FileSystemEntity entity, {bool recursive = false})

Checks if a Directory contains a FileSystemEntity. This can be a File or a Directory.

Use the recursive argument to include the subdirectories.

final File someFile = File('someFile.txt');
final Directory someDir = Directory('some/dir');

final Directory parentDir = Directory('parent/dir');

parentDir.contains(someFile);
parentDir.contains(someDir);
parentDir.contains(someFile, recursive: true);
parentDir.contains(someDir, recursive: true);

This is the async method, which returns a Future<bool>.

.containsSync(FileSystemEntity entity, {bool recursive = false})

Same as .contains(FileSystemEntity entity, {bool recursive = false}) but synchronous. Returns a bool.

License

Copyright 2019 Simon Leier

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

dartx's People

Contributors

akushwarrior avatar cyjaysong avatar eeppuj avatar ghasemdev avatar hosseinyousefi avatar hpoul avatar igoriuz avatar jinyus avatar kevmoo avatar knaeckekami avatar komape avatar minhqdao avatar mjstel avatar mohiuddinm avatar mreichelt avatar nohli avatar passsy avatar rishabhdeepsingh avatar rrousselgit avatar rskvazh avatar shinayser avatar simc avatar simolus3 avatar sososdk avatar thinkdigitalsoftware avatar vincevargadev avatar vitaly-v avatar wurikiji avatar xsahil03x avatar yongjhih avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dartx's Issues

Can I add ELEMENT between LIST of ELEMENTS?

// List of Texts
final texts = <Widget>[
    Text('text1'),
    Text('text2'),
    Text('text3'),
];

// Extension Functionality
texts.insertDivider(Divider());

// Output
<Widget>[
    Text('text1'),
    Divider()
    Text('text2'),
    Divider()
    Text('text3'),
];

Is there any way I can achieve this using this packages easily? Thanks

Offering my switchCase Extension

I just adapted a little utility I've been using to work as extension, and I think it'd fit in well with your library. It does the equivalent of switch(string) { case "txt1": etc, only cleaner and easier inside a widget structure, or wherever you'd use a standard switch case break default statement.. Here it is:

extension switchString on String {
  /// Performs a switch-case statement on String using a map for cases & conditions, optional default value 
  /// ```dart
  /// child: roomType.switchCase({
  ///   "public": Text("It's public"),
  ///   "private": Text("It's private"),
  ///   "custom": () { ... },
  /// }, Text("Default type")),
  /// ```
  TValue switchCase<String, TValue>(Map<String, TValue> cases, [TValue defaultValue]) {
    if (cases.containsKey(this)) return cases[this];
    return defaultValue;
  }
}

extension switchInt on int {
  /// Performs a switch-case statement on int using a map for cases & conditions, optional default value 
  /// ```dart
  /// child: typeNumber.switchCase({
  ///   1: Text("It's one"),
  ///   2: () { ... },
  ///   3: Text("It's three"),
  /// }, Text("Other number")),
  /// ```
  TValue switchCase<int, TValue>(Map<int, TValue> cases, [TValue defaultValue]) {
    if (cases.containsKey(this)) return cases[this];
    return defaultValue;
  }
}

Simple and fairly elegant code with the optional default: parameter, I could give you the original generic TOptionType version as well (I didn't write it), but it's nicer as extension on String and int and maybe another type too. Feel free to add it in, or if you prefer, I can add it in myself with a PR with doc updates. I'm just loving the flexibility of Dart now, so many new toys to play with...

methods .thenBy(), thenWith() and related are not composable

I would expect that I can sort an Iterable by chaining an arbitrary amount of calls to .thenBy(), thenWith() and related methods.

However, _SortedList only supports a maximum number of two comparators at the moment.
So, this test fails:

   test('can sort items by 3 comparators', () {
      const itemList = [
        Item(0, 1, 2),
        Item(2, 1, 0),
        Item(1, 2, 0),
      ];

      final sorted = itemList
          .sortedBy((item) => item.a)
          .thenBy((item) => item.b)
          .thenBy((item) => item.c);

      expect(
          sorted.toList(),
          equals(const [
            Item(0, 1, 2),
            Item(1, 2, 0),
            Item(2, 1, 0),
          ]));
    });

class Item {
  final int a;
  final int b;
  final int c;

  const Item(this.a, this.b, this.c);

  @override
  String toString() {
    return 'Item{a: $a, b: $b, c: $c}';
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Item &&
          runtimeType == other.runtimeType &&
          a == other.a &&
          b == other.b &&
          c == other.c;

  @override
  int get hashCode => a.hashCode ^ b.hashCode ^ c.hashCode;
}

with:

Expected: [
              Item:Item{a: 0, b: 1, c: 2},
              Item:Item{a: 1, b: 2, c: 0},
              Item:Item{a: 2, b: 1, c: 0}
            ]
    Actual: [
              Item:Item{a: 2, b: 1, c: 0},
              Item:Item{a: 0, b: 1, c: 2},
              Item:Item{a: 1, b: 2, c: 0}
            ]
     Which: was Item:<Item{a: 2, b: 1, c: 0}> instead of Item:<Item{a: 0, b: 1, c: 2}> at location [0]

  package:test_api                  expect
  test/sorted_list_test.dart 265:7  main.<fn>.<fn>

Only the last two comparators (that compare first item.b, then item.c) are considered, the first one, that compares item.a get overridden.

Add code coverage

Currently, PR requests seem to fail due to a missing codecov.io key:

Please provide an upload token from codecov.io with valid arguments

Since that's free for open-source projects, and because seeing code coverage on a project like this is probably a good idea, we should add one :)

MD5 getter doesn't work on windows

print('abc'.md5);
the code above outputs "O°Ö?}(ár"

This is what I got when I ran the test:

00:01 +18 -1: StringX .md5) [E]
Expected: 'd41d8cd98f00b204e9800998ecf8427e'
Actual: 'Ô\x1DÙ\x00²\x04é\tøB~'
Which: is different.
Expected: d41d8cd98f ...
Actual: Ô\x1DÙ\x ...
^
Differ at offset 0

package:test_api expect
..\dartx\test\string_test.dart 126:7 main..

Breaks json_serializable

This currently breaks any models using json_serializable if imported into the model file.

https://pub.dev/packages/json_serializable

E.g. if dartx is imported into the example.dart in the above link,

then the example fromJson generated code goes from

Person _$PersonFromJson(Map<String, dynamic> json) {
  return Person(
    firstName: json['firstName'] as String,
    lastName: json['lastName'] as String,
    dateOfBirth: DateTime.parse(json['dateOfBirth'] as String),
  );
}

to

Person _$PersonFromJson(Map<String, dynamic> json) {
  return Person(
    firstName: json['firstName'],
    lastName: json['lastName'],
    dateOfBirth: json['dateOfBirth'],
  );
}

I believe the extensions here applied directly to the types are breaking the type checking in the json_serializable helper functions.

https://github.com/dart-lang/json_serializable/tree/master/json_serializable/lib/src/type_helpers

It seems that using generic extensions would stop this breaking.

i.e. in https://github.com/leisim/dartx/blob/master/lib/src/string.dart instead of

extension StringX on String {

use

extension StringX<T extends String> on T {

Add string slice extension

String slice extension can be very useful. For example:

Instead of:
'awesomeString'.chars.slice(3, -4).joinToString(separator: '')

we could do:
'awesomeString'.slice(3, -4)

Thank you!

Alllow characters dependacy of ^0.5.0

Currently this package depends on characters from 0.3.0 to 0.4.0.

If used with other packages that require ^0.5.0, you get a conflict when resolving packages.

Are we able to widen the dependency range?

Because lottie >=0.3.0+1 depends on characters ^0.5.0 and dartx 0.3.0 depends on characters ^0.3.0, lottie >=0.3.0+1 is incompatible with dartx 0.3.0.

And because no versions of dartx match >0.3.0 <0.4.0, lottie >=0.3.0+1 is incompatible with dartx ^0.3.0.

Get an enum value by String

Get an enum value by String

Would be nice, if the an enum would have by default a method like getValue(String key) that returns the corresponding enum value to that key.

Current situation

Currently it's necessary to iterate through the values and match them manually.

enum MyEnum {
  a, b, c, d
}
String key = 'c';
for(final MyEnum myEnum in MyEnum.values) {
  if(myEnum.toString() == key) return myEnum);
}
// optional fallback value
return MyEnum.a;

Better solution

enum MyEnum {
  a, b, c, d
}
String key = 'c';
MyEnum myEnum = MyEnum.getValue(key, fallback: MyEnum.a);

dartx not compatible with Flutter master

I'm getting this error now on flutter master:

Because every version of flutter_test from sdk depends on characters 1.0.0 and dartx 0.4.1 depends on characters >=0.4.0 <1.0.0, flutter_test from sdk is incompatible with dartx 0.4.1.
And because no versions of dartx match >0.4.1 <0.5.0, flutter_test from sdk is incompatible with dartx ^0.4.1.
So, because documentation depends on both dartx ^0.4.1 and flutter_test any from sdk, version solving failed.
pub finished with exit code 1

Looks like characters just declared their api stable and published 1.0.0

I'm guessing you can just update the constraint to allow characters: ^1.0.0

Add String.removeWhere

Same as List.removeWhere but for characters and patterns. This will basically wrap the replaceAll call and default the second parameter to an empty string

coerceIn is unnecessary

If I understand coerceIn correctly it does the same thing as num.clamp:
https://api.dartlang.org/stable/2.7.0/dart-core/num/clamp.html

The other two coerce methods do the same thing as min() and max(). Maybe your methods are slightly easier to understand, but min and max are so common in other programming languages that keeping the convention might be more important than introducing a second way to do the same thing. If you still want to keep the methods maybe you could at least change the implementation to use min / max instead of the more verbose comparison.

[Feature request]safe cast

I want to cast easyly.

because it is too long.
List<int> hoge = map['hoge']?.cast<int>() ?? [];

I want to do this.

List<int> hoge = map['hoge'].safecast<int>();

Add an `as()` for null-safety casting similar to `as?` in Kotlin

T as<T>(dynamic it) => it is T ? it : null; // that's what I used for a long time.

  test('should as<T>()', () async {
    const dynamic it = "Hello";
    expect(as<String>(it) ?? "", "Hello");
    expect(as<int>(it) ?? 0, 0);
    const nullIt = null;
    expect(as<String>(nullIt) ?? "", "");
  });

I tried to implement it with the following code, but they don't work, I think it's a limitation in Dart:

extension NullableObject on Object {
  R as<R>() => this is R ? this as R : null;
}

or

extension NullableDynamic on dynamic {
  R as<R>() => this is R ? this as R : null;
}

Logos for FlutterX

Didn't know @leisim had already uploaded FlutterX library in pub.dev & I had already made logos for them. @leisim Please use them if you like them. I can also provide SVGs if needed.

Icon

ic_flutterX

Logo

logo_flutterX

Add '.count' method to Lists and maps

I'd like to submit a PR for this when I get time unless someone adds it before me. Basically it would take the same parameters as a where function and will return the number of elements in the list or map that satisfy the condition

Another break after Flutter upgrade with collection

After my latest Flutter upgrade on the Dev channel, looks like it needs the maximum version of collection a little higher than 1.15.0.. Here's the error:
Because every version of flutter from sdk depends on typed_data 1.3.0-nullsafety which depends on collection >=1.15.0-nnbd <1.15.0, every version of flutter from sdk requires collection >=1.15.0-nnbd <1.15.0.
And because every version of black_hole_flutter from git depends on dartx ^0.4.0 which depends on collection >=1.14.11 <1.15.0, flutter from sdk is incompatible with black_hole_flutter from git.

I know the dependency was to dartx ^0.4.0 not 0.4.2, but the collection: version doesn't look changed. When I use 0.4.2 directly, gives me this variation of the error:
Because every version of flutter_test from sdk depends on collection 1.15.0-nullsafety and dartx 0.4.2 depends on collection >=1.14.11 <1.15.0, flutter_test from sdk is incompatible with dartx 0.4.2.
And because no versions of dartx match >0.4.2 <0.5.0, flutter_test from sdk is incompatible with dartx ^0.4.2.

Should be simple fix, just thought I'd bring it up since I'm sure other people are gonna start getting this conflict as soon as they do a flutter upgrade. Thanks..

List.map() with access to the current index

List.map() with access to the current index

The List.map() function should have access to the index such as in JavaScript.

List myList = ['a', 'b', 'c'];

myList.map((val, index) {
  // so something
});

Current Situation

The List.map() has only access to the value.

List myList = ['a', 'b', 'c'];

myList.map((val) {
  // do something
});

The working but ugly alternative is to use asMap() and iterate through its entries.

myList.asMap().entries.map((val) {
  final int index = val.key;
  // do something
}

Better Solution

Give access to the index.

List myList = ['a', 'b', 'c'];

myList.map((val, index) {
  // so something
});

Move `sum` operations to another extension on `Iterable<num>`.

The sum operations in IterableX cast their elements to num.
Consider instead having an

extension IterableNumX<T extends num> on Iterable<T> { 
  T sum() {  ... }
  ...
}

Then you don't need to cast each element (but you will have to be a little clever about finding the correct 0 for the iteration, perhaps:

T sum() {
  T result = 0 is T ? 0 as T : 0.0 as T;
  for (var value in this) result += value;
  return result;
}

zip can only zip iterables of the same type

The zip method is especially useful when we can zip items of different types - but zip in dartx is implemented to only accept a right-hand iterable of the same type. So things like this work:

final numbers = [1, 2, 3];
final multipliers = [3, 4, 5];

final multiplied = numbers.zip(multipliers, (number, multiplier) => number * multiplier).toList();
print(multiplied); // prints [3, 8, 15]

But this doesn't:

final countOfFruits = [1, 2, 3];
final fruits = ['bananas', 'apples', 'oranges'];
final combined = countOfFruits.zip(fruits, (count, fruit) => '$count $fruit').toList();

image

We can try to change the implementation of the original zip, but then we must make sure we don't break any calling code. So let's test this thoroughly. 🤓

Add 'num.minus()' and `num.plus()` for null-safety

I'm not sure if it's a good idea for this project. That would be better if there is a nullable +operator we can overwrite such as 1 +? nullable similar to 1 as? String

  test('should num?.minus()', () async {
    final num value = null;
    expect(value?.minus(1), null);
    expect(value?.minus(1) ?? -1, -1);
    expect((value ?? 0) - 1, -1);
    expect(() => value - 1, throwsNoSuchMethodError);

    expect(value?.plus(1), null);
    expect(value?.plus(1) ?? 1, 1);
    expect((value ?? 0) + 1, 1);
    expect(() => value + 1, throwsNoSuchMethodError);

    expect(1.plus(value), 1);
    expect(1.plusOrNull(value), null);
    expect(1.plusOrNull(value) ?? 1, 1);
    expect(() => 1 + value, throwsNoSuchMethodError);

    expect(1.minus(value), 1);
    expect(1.minusOrNull(value), null);
    expect(1.minusOrNull(value) ?? 1, 1);
    expect(() => 1 - value, throwsNoSuchMethodError);
  });
  test('should int?.minus()', () async {
    final int value = null;
    expect(value?.minus(1), null);
    expect(value?.minus(1) ?? -1, -1);
    expect((value ?? 0) - 1, -1);
    expect(() => value - 1, throwsNoSuchMethodError);

    expect(value?.plus(1), null);
    expect(value?.plus(1) ?? 1, 1);
    expect((value ?? 0) + 1, 1);
    expect(() => value + 1, throwsNoSuchMethodError);

    expect(1.plus(value), 1);
    expect(1.plusOrNull(value), null);
    expect(1.plusOrNull(value) ?? 1, 1);
    expect(() => 1 + value, throwsNoSuchMethodError);

    expect(1.minus(value), 1);
    expect(1.minusOrNull(value), null);
    expect(1.minusOrNull(value) ?? 1, 1);
    expect(() => 1 - value, throwsNoSuchMethodError);
  });
  test('should double?.minus()', () async {
    final double value = null;
    expect(value?.minus(1), null);
    expect(value?.minus(1) ?? -1, -1);
    expect((value ?? 0) - 1, -1);
    expect(() => value - 1, throwsNoSuchMethodError);

    expect(value?.plus(1), null);
    expect(value?.plus(1) ?? 1, 1);
    expect((value ?? 0) + 1, 1);
    expect(() => value + 1, throwsNoSuchMethodError);

    expect(1.0.plus(value), 1);
    expect(1.0.plusOrNull(value), null);
    expect(1.0.plusOrNull(value) ?? 1, 1);
    expect(() => 1.0 + value, throwsNoSuchMethodError);

    expect(1.0.minus(value), 1);
    expect(1.0.minusOrNull(value), null);
    expect(1.0.minusOrNull(value) ?? 1, 1);
    expect(() => 1.0 - value, throwsNoSuchMethodError);
  });
extension IntArithmeticX<T extends int> on T {
  T minus(T it) => it != null ? this - it : this;
  T minusOrNull(T it) => it != null ? this - it : null;
  T plus(T it) => it != null ? this + it : this;
  T plusOrNull(T it) => it != null ? this + it : null;
}

extension NumArithmeticX<T extends num> on T {
  T minus(T it) => it != null ? this - it : this;
  T minusOrNull(T it) => it != null ? this - it : null;
  T plus(T it) => it != null ? this + it : this;
  T plusOrNull(T it) => it != null ? this + it : null;
}

extension DoubleArithmeticX<T extends double> on T {
  T minus(T it) => it != null ? this - it : this;
  T minusOrNull(T it) => it != null ? this - it : null;
  T plus(T it) => it != null ? this + it : this;
  T plusOrNull(T it) => it != null ? this + it : null;
}

Add String.removePrefix, removeSuffix, and removeSurrounding

I know these methods from Kotlin: they make development so much easier when you need those.

  • removePrefix: removes a prefix from a string and returns that as a copy, otherwise returns a copy of the original string
  • removeSuffix: same, but for suffix.
  • removeSurrounding: removes a prefix and a suffix if and only if both exist - otherwise keeps that unchanged. Run this Kotlin example.

Would love to implement those as well!

Add `Comparable.between(T, T)` extension method

In Kotlin we can do if (c !in '0'..'9'), unfortunately, the in operator can't be overwritten in Dart, probably we can just add Comparable.between(T, T) extension method as well, but maybe there is a better method name to do it.

  test('Comparable.between()', () async {
    expect(1.between(0, 2), true);
    expect(1.between(1, 2), true);
    expect(1.between(0, 1), true);
    expect(1.between(0, 0), false);
    expect(2.between(0, 1), false);
    expect(0.between(1, 2), false);

    expect(DateTime(1984, 11, 19).between(DateTime(1911, 1, 1), DateTime(2020, 1, 1)), true);
  });
extension ComparableRangeX<T> on Comparable<T> {
  bool between(T min, T max) => compareTo(min) >= 0 && compareTo(max) <= 0;
}

ref. https://gist.github.com/yongjhih/a0a17adaef0eb5fc7dbba5e6924ed8de

path version conflict

dartx: 0.4.0 is incompatible with Flutter 1.17 because of path.

dependencies:
  flutter:
    sdk: flutter
  dartx: ^0.4.0

dev_dependencies:
  flutter_test:
    sdk: flutter
$ flutter packages get
Because every version of flutter_test from sdk depends on path 1.6.4 and dartx 0.4.0 depends on path ^1.7.0, flutter_test from sdk is incompatible with dartx 0.4.0.
And because no versions of dartx match >0.4.0 <0.5.0, flutter_test from sdk is incompatible with dartx ^0.4.0.
So, because spitch depends on both dartx ^0.4.0 and flutter_test any from sdk, version solving failed.

Cloud support DateTime.isLeapYear

Like this

extension DateTimeExtension on DateTime {

  bool get isLeapYear => year % 400 == 0 || year % 100 != 0 && year % 4 == 0;

  int get daysInMonth => _calcDaysInMonth();

  int _calcDaysInMonth() {
    switch (month) {
      case DateTime.january:
      case DateTime.march:
      case DateTime.may:
      case DateTime.july:
      case DateTime.august:
      case DateTime.october:
      case DateTime.december:
        return 31;
      case DateTime.february:
        return isLeapYear ? 29 : 28;
      case DateTime.april:
      case DateTime.june:
      case DateTime.september:
      case DateTime.november:
      default:
        return 30;
    }
  }
}

[Feature request]Validation String extension

validation extension is also concept?

like this

extension EmailValidator on String {
  bool isValidEmail() {
    return RegExp(
        r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
        .hasMatch(this);
  }

  bool isValidHoge() {
     // blah-blah-blah
  }

  // ....
}

If it is. I will do pull-request.

Do we need `invoke` method?

Dart, basically, supports thecall() method for all Functions. So we can already use myFunction?.call(). In addition, call() method can take any number of arguments.

Add .range method on int

Very often, ranges go from 0 to n. Instead of having 0.rangeTo(n), we could use n.range as a shortcut.

please update package versions. I'm getting errors including hive_generator

Because no versions of hive_generator match >0.7.0 <0.8.0 and hive_generator 0.7.0 depends on dartx ^0.2.0, hive_generator ^0.7.0 requires dartx ^0.2.0.
Because dartx 0.2.0 depends on characters ^0.3.0 and no versions of dartx match >0.2.0 <0.3.0, dartx ^0.2.0 requires characters ^0.3.0.

Thus, hive_generator ^0.7.0 requires characters ^0.3.0.
So, because therapist_training depends on both characters ^0.5.0 and hive_generator ^0.7.0, version solving failed.

Transform paramenter on "windowed' should not be required

Hello!
Most of time when using the windowed method you just want to go through the list, without worring about its transformation. But the current api has the transform method required, wich leads to some silly usages like:

var myList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
myList.windowed(3, (win) => win).forEach( ...)

I suggest making it optional, just like the step and partialWindows are, with a default value return the current iteration object, just like the sample above.

Like this:

myList.windowed(3, transform: (win) => win).forEach( ...)

Of course this is a breaking change, but well documented in the change logs will not cause much problem.

What you think?

About the duplicated methods...

Originally this issue was to discuss the need of the coerceIn method, but before I searched on the issues history and found that this issue already exists #18.
The argument that @leisim used on it is pretty valid as it helps other developers from other languages to find more easily some of their correspondents on dart language.

But this causes a problem: too many methods on the auto complete window that does the same thing.

And if you allow me to question: why we are only providing methods for the Kotlin users? Why not provide also duplicated methods for Swift, Javascript, PhP, Python, c++... see my point?

But I think I have a nice sollution for this problems and would like to hear other collaborators thoughts:

  • Instead of providing methods that does the same thing of the Dart method's, we could add a section to the README file that does a one-to-one correspondency to other languages methods.

This would resolve the methods overflooding and also help other developers to find correspondents on the Dart language.

What you guys folks think?

Correct file to add this extension.

@passsy can you suggest the correct file to add this particular extension function. I don't really think this should be part of String extension.

extension StringX on String {
  /// Creates a `Duration` object from an ISO8601 formatted string.
  ///
  /// This method parses out a subset of the ISO8601 duration format. As years
  /// and months are not of a set length this method does not support that. We
  /// are then left with support for weeks, days, hours, minutes and seconds.
  Duration get toDuration {
    if (!RegExp(
            r"^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$")
        .hasMatch(this)) {
      throw ArgumentError("String does not follow correct format");
    }

    final weeks = _parseTime(this, "W");
    final days = _parseTime(this, "D");
    final hours = _parseTime(this, "H");
    final minutes = _parseTime(this, "M");
    final seconds = _parseTime(this, "S");

    return Duration(
      days: days + (weeks * 7),
      hours: hours,
      minutes: minutes,
      seconds: seconds,
    );
  }

  /// Private helper method for extracting a time value from the ISO8601 string.
  int _parseTime(String duration, String timeUnit) {
    final timeMatch = RegExp(r"\d+" + timeUnit).firstMatch(duration);

    if (timeMatch == null) {
      return 0;
    }
    final timeString = timeMatch.group(0);
    return int.parse(timeString.substring(0, timeString.length - 1));
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.