google / quiver-dart Goto Github PK
View Code? Open in Web Editor NEWA set of utility libraries for Dart
Home Page: https://pub.dev/packages/quiver
License: Apache License 2.0
A set of utility libraries for Dart
Home Page: https://pub.dev/packages/quiver
License: Apache License 2.0
eg.
forEachAsync([], action).then((_) => print("done");
will never complete.
"Yes, if you spawn all your expensive async tasks eagerly you're going to have a bad time."
Strawman:
forEachAsync(iterable, (i) => expensive(i), maxTasks: 10);
A common use-case in applications is to use objects as keys whose equals/hashCode is different from the use-case at hand. The most common example that I keep hearing is you want to use database entities as map keys and set elements but you want to have ID-based identity, so for example {id: 1, name: "foo"} and {id: 1, name: "bar"} are considered equal.
Feature request: provide implementations of Map, Set and List that take a comparator function as a constructor parameter and use it to compare keys and elements.
It's much more discoverable when it's in the class' namespace. And it's the style used most commonly by the dart community at large.
I prefer const Clock.system()
over Clock.SYSTEM
just in case arguments need to be added in the future, and a constructor makes it obvious that it returns a Clock without even needing to check the docs.
Of course there should be a deprecation period where both are available to allow people to update.
my proposition:
if 'iterable' is not set, run until action completes with false; IMHO this is more natural extension of while.
See:
http://lodash.com/docs#throttle
http://lodash.com/docs#debounce
In dart these translate to Stream transformations:
Stream throttle(Stream stream, Duration wait, {bool leading: true, bool trailing: true});
Stream debounce(Stream stream, Duration wait, {Duration maxWait, bool leading: false, bool trailing: true});
Here is the existing dart core feature request:
Periodic timers are subject to drift as the timer is not guaranteed to be called exactly when it was scheduled for.
I filed a bug to add this to Stream.periodic (and possibly Timer.periodic):
https://code.google.com/p/dart/issues/detail?id=18642
but in the meantime, would be nice to have this in quiver. It could look like:
Stream onPeriod(Duration duration, [Function computation]);
This could be used by #130.
Implementation inspiration can be taken from:
A tracking bug.
I'm not saying that shuffle was added to the SDK because of my patch, but I'm not not saying that either. :)
The Map<K, V> interface defines remove as: V remove(Object key)
.
The HashBiMap implementation does not return anything, but should return _map.remove(key)
.
Something along the lines of Guava's toString helpers would be nice.
Would it be possible to add a sensible way of unwrapping all the present values in an iterable of optional values? Basically the equivalent of catMaybes
in Haskell's Data.Maybe
class Optional<T> {
/**
* Returns an iterable containing the values of all the values of the optionals
* which are present in the argument.
*/
static Iterable wherePresent(Iterable optionals) =>
optionals.expand((opt) => opt.isPresent ? [opt.value] : []);
...
}
Comparator
is the standard way to compare items in dart. But many languages allow sorting by "key functions", for example python:
https://wiki.python.org/moin/HowTo/Sorting#Key_Functions
Since dart doesn't yet have union types, List.sort for example would have to take a dynamic
sort function in order to allow Comparator
s and key functions, thus giving up on type safety. In the meantime, I think a good solution would be a method to easily convert key functions to Comparator
s, something like:
Comparable Key<T>(T item);
Comparator byKey(Key key) => (a, b) =>
key(a).compareTo(key(b));
Usage:
['bob', 'delores', 'Cathy', 'Alan'].sort(byKey((s) => s.toLowerCase());
#114 introduces a quiver.compare
that this could be added to.
pairwise([1, 2, 3, 4])
-> [[1, 2], [2, 3], [3, 4]]
I've written some code to pretty-print json, so the output doesn't all end up on one line. It's part of a larger app right now, but I'm looking for a better home for it, in order to make it available to more people. Is quiver a good place for something like a json pretty printer?
If forEachAsync didn't have maxTasks
, leaving that use case for something like #105, then it could be:
Future forEachAsync(Future asyncAction(item), Iterable iterable) =>
new Stream.fromIterable(iterable).asyncMap(action).drain();
Since the SDK cannot be downgraded, it is not generally a good practice to put a cap on it. When we asked for SDK constraints we promised never to put an upper bound :)
Concretely, this caused a problem for me because I couldn't use/test quiver on 0.8.x, even though in fact the feature I wanted to use worked just fine.
It should not listen until the first listener has been added to one of the child streams. It should also stop listening when the last child listener has been removed.
I've seen things like this in user code:
date = value > 0 ? _clock.monthsAgo(value) : _clock.monthsFromNow(value);
The definition of the compare function states:
The line(s) in min_max.dart:
if (compare(max, iterator.current) > 0) max = iterator.current;
a = max
b = iterator.current
So essentially the line is currently, and incorrectly read as: if(a(max) > b(current)) max = current; which causes min and max to be switched.
Point folks to collection package instead.
Found this: https://github.com/dart-lang/web-ui/blob/master/lib/src/linked_list.dart
The linkedlist in dart:collection is hard to use, as it forces all entries to extend from LinkedListEntry.
Quiver should have an easy to use linked list.
Thanks!
Not sure what's the best place to add this, but definitely something useful to have.
/// Find the first entry in a sorted [list] that matches a monotonic predicate.
/// A result `n` means that all items before `n` don't match, `n` matches,
/// and all items after `n` match as well. The result is -1 when there are no
/// items, 0 when all items match, and list.length when none does.
int binarySearch(List list, bool matches(item)) {
if (list.length == 0) return -1;
if (matches(list.first)) return 0;
if (!matches(list.last)) return list.length;
int min = 0;
int max = list.length - 1;
while (min < max) {
var half = min + ((max - min) ~/ 2);
if (matches(list[half])) {
max = half;
} else {
min = half + 1;
}
}
return max;
}
Go to https://drone.io/github.com/google/quiver-dart/admin
and make it dart -c test/all_tests.dart
They are all superceded by #98.
Populate with breaking changes & major new features.
Our team found it useful to have a utility that aggregates various types of subscriptions (StreamSubscription, StreamSink (usually StreamController), as well as custom cleanup functions) and clean them up all at once at a certain moment. A popular use-case is a UI component being destroyed while still fetching things from the server. Another use-case I can see is cleaning-up when things go wrong, e.g. closing sockets/files when errors happen.
Proposed API:
class Disposer {
Disposer();
/// [disposable] will be "disposed of" when the [dispose] method is called. The
/// meaning of "dispose" depends on the type of disposable, which can be one of:
///
/// - [StreamSubscription], disposer calls `cancel()` when disposing
/// - [StreamSink], disposer calls `close()` when disposing
/// - [Function] that takes no arguments and returns either `null` or a [Future]. This
/// function is called by the disposer as is. The implementation is defined by the user.
void add(dynamic disposable);
/// Disposes of all disposables [add]ed to `this` disposer.
///
/// The returned future completes when all disposables are successfully disposed of.
Future dispose();
/// Sets a [trigger] used as a signal to dispose everything collected so far. Can be used
/// as an alternative to calling [dispose] directly.
set trigger(Future t);
}
Otherwise:
var a = ['a', 'b'];
var b = ['c', 'd'];
max(a).compareTo(min(b)); // produces compiler warning
#86 provided order-preserving concatenation of streams, but only listens to one stream at a time to allow for lazy creation of the streams, and to avoid buffering. This can lead to dropped events which occur before the stream is reached in the iteration.
When order is not important, it usually makes sense to create (if necessary) and listen to all the streams up front, and simply funnel all the streams' events to a new stream without the need for any buffering. Potential API:
Stream funnel(Iterable<Stream>);
I also like the name union
though it may imply uniqueness of events which is not the case.
Similar to the impl of #109, should be as simple as:
Stream concat(Iterable<Stream> streams) =>
new Stream.fromIterable(streams).asyncExpand((s) => s);
In http://google.github.io/quiver-dart/docs/quiver.strings.html one example of loop is given as loop('ab', 6) == 'ababab'
. It should probably be loop('ab', 0, 6) == 'ababab'
(if I understand the prose description correctly).
If we had #91, then instead of:
clock.ago(days: 1)
clock.weeksAgo(2)
clock.yearsFromNow(1)
could just do:
clock.ago(day)
clock.ago(week * 2)
clock.fromNow(year)
though I'd probably be happy with just doing:
clock.now().subtract(day)
clock.now().subtract(week * 2)
clock.now().add(year)
For months, a special function would still be needed, but it ought to work for any date, not just now()
:
DateTime addMonths(DateTime from, int months);
See http://underscorejs.org/#pluck
This doesn't fit in the core libraries, see http://dartbug.com/15278, since it requires mirrors.
Example implementation:
Iterable pluck(Iterable iterable, Symbol property) =>
iterable.map((item) => reflect(item).getField(property).reflectee);
Usage:
main() {
pluck([{'a': 1}, 'xx', [1, 2, 3]], #length).forEach(print);
}
Output:
1
2
3
This is my first try with quiver.
I use it like
var x = firstNonNull(c.maxWith, 0) + 5
DartEditor shows the warning There is no such operator '-' in 'Object'
.
I think this this would work without warning when firstNonNull
s return type would be dynamic (or no return type)
Requesting a utility method to shuffle aka randomly sort a list.
Constants:
const Duration microsecond = const Duration(microseconds: 1);
const Duration millisecond = const Duration(milliseconds: 1);
const Duration second = const Duration(seconds: 1);
const Duration minute = const Duration(minutes: 1);
const Duration hour = const Duration(hours: 1);
const Duration day = const Duration(days: 1);
const Duration week = const Duration(days: 7);
const Duration year = const Duration(years: 1);
Usage:
if(stopwatch.elapsed > minute) ...
new Timer(millisecond * 500, () {...});
var inOneDay = clock.now().add(day);
Not all of the functions in iterables.dart make sense for streams, but the following would be useful (note: some of these are still in the unmerged pull request I opened today)
concatAsync
- Just a shorthand for stream.expand((i) => i). The returned stream emits an event for each element when it receives an event containing an iterable.zipAsync
- Combine a list of streams into a stream of lists. Unlike Iterables.zip, I think the most sensible behaviour here is to perform a zipLongest on each of the streams, inserting a sentinel value in the list position corresponding to a closed stream.groupJoinAsync
is a tough one. I was thinking about possible use cases, the first useful one I came up with is:
Consider a game with a number of entities in the viewable area. As the entities are created, each emits an event which creates a new stream This stream can be joined with mouse events in the viewable area (with the
on
function testing for hit collision).
There are certainly many more possible uses, but it's certainly abstracting away from the SQL join roots and I can't really decide if it's generic enough to warrant inclusion.
The README.md of the quiver package (https://pub.dartlang.org/packages/quiver) mentions some string operations (compareIgnoreCase, equalsIgnoreCase, padLeft, padRight) that are not in the quiver.strings library documentation (http://google.github.io/quiver-dart/docs/quiver.strings.html). One of them must be wrong.
for now dart:io doesn't support directory copy.
This ought to work:
Future<bool> doWhileAsync(Future asyncAction(item), Iterable iterable) =>
new Stream.fromIterable(iterable).asyncMap(asyncAction).every((x) => x);
Might want to deprecate string repeat given that Dart 1.3 has introduced the *
operator in String
for this purpose.
These failed dart:core feature requests:
http://dartbug.com/3176
http://dartbug.com/1492
seem like good candidates for quiver.core.
Possible API:
class Quantity<T extends Comparable<T>> extends Comparable<T> {
final Comparable<T> _comparable;
Quantity(this._comparable);
int compareTo(T other) => _comparable.compareTo(other);
bool operator < (T other) => compareTo(other) < 0;
bool operator <= (T other) => compareTo(other) <= 0;
bool operator > (T other) => compareTo(other) > 0;
bool operator >= (T other) => compareTo(other) >= 0;
bool operator == (T other) => compareTo(other) == 0;
T min(T other) => this <= other ? _comparable : other;
T max(T other) => this >= other ? _comparable : other;
T clamp(T min, T max) => new Quantity(this.max(min)).min(max);
}
Just a placeholder for this request. Maybe someone is sitting on this code? I tried to find it in quiver, but I didn't find it on the README.
Time-dependent units can receive Clocks as dependencies to mock the passage of time. Doing so exposes nothing about their implementation, only that they depend on the passage of time. #98 removed the need to expose the use of Timers. This issue is to remove the need to expose the use of Stopwatches. Currently quiver has FakeStopwatch for mocking stopwatches. Receiving a Stopwatch (FakeStopwatch) as a dependency, exposes even more of the implementation, specifically that you're using only a single stopwatch. A StopwatchFactory typedef would at least solve that, but it still would expose the use of Stopwatches.
If it were possible to obtain a Stopwatch from a Clock, the time-dependen unit could then just receive a Clock, and create the Stopwatch internally.
Ideally the dart:core Stopwatch impl would be backed by a Clock, see:
https://code.google.com/p/dart/issues/detail?id=18149
But until then, we will want to use the dart:core stopwatch impl in production code, and a clock-backed Stopwatch in test code. The way to handle this is polymorphism, by adding a stopwatch creation method to Clock:
Stopwatch newStopwatch();
createStopwatch
could also work as a name.
It should be a method instead of a getter, since it returns a new mutable object on each invocation.
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.