simc / dartx Goto Github PK
View Code? Open in Web Editor NEWSuperpowers for Dart. Collection of useful static extension methods.
Home Page: https://pub.dev/packages/dartx
License: Apache License 2.0
Superpowers for Dart. Collection of useful static extension methods.
Home Page: https://pub.dev/packages/dartx
License: Apache License 2.0
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
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!
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...
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
});
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
}
Give access to the index.
List myList = ['a', 'b', 'c'];
myList.map((val, index) {
// so something
});
@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));
}
}
Often, you want to get the file extension, but there's currently no way to get it.
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 {
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 :)
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
Iterable.groupBy returns a map but if it returns List of Lists optionally or with another extension, it will be more useful with nested Listview.
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.
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;
}
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;
}
We already got the method every
from the core library, that does the same thing.
Is the method all
really necessary?
The title pretty much says everything.
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>();
Great to filter Iterables.
Will be even more helpful when NNBD lands.
Google's basics package provides them and they are more readable than just comparing objects with == null
and != null
.
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.
Please add equals extensions based on ListEquality and so on...
Using num.clamp(lower,upper)
, it returns the same thing.
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
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..
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;
}
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.
It is available as a function:
https://api.flutter.dev/flutter/package-collection_collection/groupBy.html
But, it can be more useful as an extension.
There is a discussion on dart-lang repo but the issue is closed:
dart-lang/sdk#30376
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..
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.
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 stringremoveSuffix
: 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!
// 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
Dart, basically, supports thecall()
method for all Function
s. So we can already use myFunction?.call()
. In addition, call()
method can take any number of arguments.
Add '.name' on FileSystemEntity, Directory
Very often, ranges go from 0
to n
. Instead of having 0.rangeTo(n)
, we could use n.range
as a shortcut.
I don't see value in having dartx
and flutterx
in the same repository. I'd prefer moving flutterx
to leisim/flutterx
and keep both separate.
Many times we would need index along with value. This extension could help a lot when added to a list.
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.
The joinToString
function in IterableX
does repeated string concatenation. It should probably use a StringBuffer
to avoid creating so many intermediate strings.
There's lastOrNull
and firstOrNull
, but Iterable
s also have the single
accessor. It would be great if this package would also support singleOrNull
.
This will allow for null type checking while we wait for the new dart version
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
.
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;
enum MyEnum {
a, b, c, d
}
String key = 'c';
MyEnum myEnum = MyEnum.getValue(key, fallback: MyEnum.a);
Unlike having classes which will be auto imported in IDE when using them , extension methods will be shown only when I import the dartx file.
Doing this for every file is tedious. Is there some way to get IDE completion to auto import this ?
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();
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. 🤓
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
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.
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:
This would resolve the methods overflooding and also help other developers to find correspondents on the Dart language.
What you guys folks think?
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?
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;
}
}
}
The function doesn't just check the first character. Ditto for isLowerCase
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.