Giter Club home page Giter Club logo

quiver-dart's Introduction

A set of utility libraries for Dart that makes using many Dart libraries easier and more convenient, or adds additional functionality.

Build Status Coverage Status Pub

Documentation

API Docs are available.

Main Libraries

Utilities for working with Futures, Streams and async computations.

collect collects the completion events of an Iterable of Futures into a Stream.

enumerate and concat represent Stream versions of the same-named quiver.iterables methods.

StreamBuffer allows for the orderly reading of elements from a stream, such as a socket.

FutureStream turns a Future<Stream> into a Stream which emits the same events as the stream returned from the future.

StreamRouter splits a Stream into multiple streams based on a set of predicates.

CountdownTimer is a simple countdown timer that fires events in regular increments.

Metronome is a self-correcting alternative to Timer.periodic. It provides a simple, tracking periodic stream of DateTime events with optional anchor time.

stringFromByteStream constructs a string from a stream of byte lists.

Cache is a semi-persistent, asynchronously accessed, mapping of keys to values. Caches are similar to Maps, except that the cache implementation might store values in a remote system, so all operations are asynchronous, and caches might have eviction policies.

MapCache is a Cache implementation backed by a Map.

checkArgument throws ArgumentError if the specified argument check expression is false.

checkListIndex throws RangeError if the specified index is out of bounds.

checkState throws StateError if the specified state check expression is false.

listsEqual, mapsEqual and setsEqual check collections for equality.

indexOf finds the first index of an item satisfying a predicate.

LruMap is a map that removes the least recently used item when a threshold length is exceeded.

Multimap is an associative collection that maps keys to collections of values.

BiMap is a bidirectional map and provides an inverse view, allowing lookup of key by value.

TreeSet is a balanced binary tree that offers a bidirectional iterator, the ability to iterate from an arbitrary anchor, and 'nearest' search.

Optional is a way to represent optional values without allowing null.

hashObjects, hash2, hash3, and hash4 generate high-quality hashCodes for a list of objects, or 2, 3, or 4 arguments respectively.

concat, count, cycle, enumerate, merge, partition, range, and zip create, transform, or combine Iterables in different ways, similar to Python's itertools.

min, max, and extent retrieve the minimum and maximum elements from an iterable.

GeneratingIterable is an easy way to create lazy iterables that produce elements by calling a function. A common use-case is to traverse properties in an object graph, like the parent relationship in a tree.

InfiniteIterable is a base class for Iterables that throws on operations that require a finite length.

pattern.dart container utilities for work with Patterns and RegExps.

Glob implements glob patterns that are commonly used with filesystem paths.

matchesAny combines multiple Patterns into one, and allows for exclusions.

matchesFull returns true if a Pattern matches an entire String.

escapeRegex escapes special regex characters in a String so that it can be used as a literal match inside of a RegExp.

isBlank checks if a string is null, empty or made of whitespace characters.

isNotBlank checks if a string is not null, and not blank.

isEmpty checks if a string is null or empty.

isNotEmpty checks if a string is not null and not empty.

equalsIgnoreCase checks if two strings are equal, ignoring case.

compareIgnoreCase compares two strings, ignoring case.

loop allows you to loop through characters in a string starting and ending at arbitrary indices. Out of bounds indices allow you to wrap around the string, supporting a number of use-cases, including:

  • Rotating: loop('lohel', -3, 2) => 'hello'
  • Repeating, like String's operator*, but with better character-level control, e.g.: loop('la ', 0, 8) => 'la la la' // no trailing space
  • Tailing: loop('/path/to/some/file.txt', -3) => 'txt'
  • Reversing: loop('top', 3, 0) => 'pot'

Clock provides points in time relative to the current point in time, for example: now, 2 days ago, 4 weeks from now, etc. For testability, use Clock rather than other ways of accessing time, like new DateTime(), so that you can use a fake time function in your tests to control time.

Now is a typedef for functions that return the current time in microseconds, since Clock deals in DateTime which only have millisecond accuracy.

aMicrosecond, aMillisecond, aSecond, aMinute, anHour, aDay, and aWeek are unit duration constants to allow writing for example:

  • aDay vs. const Duration(days: 1)
  • aSecond * 30 vs. const Duration(seconds: 30)

Testing Libraries

The Quiver testing libraries are intended to be used in testing code, not production code. It currently consists of fake implementations of some Quiver interfaces.

FakeAsync enables testing of units which depend upon timers and microtasks. It supports fake advancements of time and the microtask queue, which cause fake timers and microtasks to be processed. A Clock is provided from which to read the current fake time. Faking synchronous or blocking time advancement is also supported.

areEqualityGroups is a matcher that supports testing operator== and hashCode implementations.

FakeStopwatch is a Stopwatch that uses a provided now() function to get the current time.

quiver-dart's People

Contributors

a14n avatar adamlofts avatar alechenninger avatar blackhc avatar cbracken avatar codelogic avatar davidmorgan avatar dependabot[bot] avatar emesx avatar feinstein avatar fniemann avatar fox32 avatar jacob314 avatar jakemac53 avatar jamesderlin avatar jtmcdole avatar justinfagnani avatar kevmoo avatar lrhn avatar lucyget avatar matanlurey avatar mfiels avatar mt40 avatar munificent avatar seaneagan avatar sethladd avatar srawlins avatar tonio-ramirez avatar vicb avatar yjbanov 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

quiver-dart's Issues

Extent extent(Iterable i) in min_max.dart is wrong.

The definition of the compare function states:

  • a negative integer if [a] is smaller than [b],
  • zero if [a] is equal to [b], and
  • a positive integer if [a] is greater than [b].

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.

SYSTEM_CLOCK should be Clock.SYSTEM or const Clock.system()

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.

Key comparator generation

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 Comparators 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 Comparators, 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.

BiMap.remove does not return anything.

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).

Proposal: Disposer

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);
}

Helper to throttle async

"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);

Simplify streams.concat impl

Similar to the impl of #109, should be as simple as:

Stream concat(Iterable<Stream> streams) =>
    new Stream.fromIterable(streams).asyncExpand((s) => s);

upper bound on SDK constraint is not good practice

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.

Add a streams equivalent of quiver.iterables

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.
  • `groupByAsync - A primitive dispatcher for streams. Create a stream of streams and emit values on different streams according to the value returned by a key function

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.

Consider simplifying forEachAsync

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();

Provide collections that take custom comparators

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.

Add Duration unit constants to quiver.time

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);

add binary search for lists

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;
}

Simplify doWhileAsync impl

This ought to work:

Future<bool> doWhileAsync(Future asyncAction(item), Iterable iterable) =>
    new Stream.fromIterable(iterable).asyncMap(asyncAction).every((x) => x);

Clock has too many methods

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);

Add method to combine parallel streams

#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.

why does firstNonNull return object?

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 firstNonNulls return type would be dynamic (or no return type)

Replace FakeStopwatch with Clock.newStopwatch

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.

Add Optional.wherePresent helper to quiver.core

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] : []);
    ...
}

json pretty printer?

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?

Add a periodic stream which corrects drift

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:

https://gist.github.com/tanepiper/4215634

Add Quantity to quiver.core

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);
}

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.