Dart streams, equivalent of await for - dart

I like the await for construct in Dart.
How can I implement something similar with a regular for loop?
Something like
// beware! fictional code.
var element = stream.next();
for(; stream.isEndReached(); element = stream.next()) {
// use element here
}
// or probably it will be like this, right?
var element = await stream.next();
for(; await stream.isEndReached(); element = await stream.next()) {
// use element here
}
But I can't figure out what functions to use instead of next() and isEndReached() here. If you could give me a full example that acts exactly like async for, that would be great.
Edit: Here is the actual reason that I asked for this: I want to do something like this:
if (!stream.isEndReached()) {
var a = await stream.next();
// use a
}
if (!stream.isEndReached()) {
var b = await stream.next();
// use b
}
// have an arbitrary number of these
I need to consume items one by one like this. This is why I'm asking what my made up .next() and .isEndReached() methods map to which actual methods in the stream class.

The async package contains a StreamQueue class that might do what you want.
See also this great article http://news.dartlang.org/2016/04/unboxing-packages-async-part-3.html
StreamQueue provides a pull-based API for streams.
A code snipped from the article mentioned above
void main() async {
var queue = new StreamQueue(new Stream.fromIterable([1, 2, 3]));
var first = queue.next;
var second = queue.next;
var third = queue.next;
print(await Future.wait([first, second, third])); // => [1, 2, 3]
}
update
WebStorm (uses a feature of the dartanalyzer) doesn't provide quick fixes for imports when nothing was yet imported from that package. It doesn't read packages if they are not refered to in your source code. As mentioned in my answer StreamQueue is from the async package. import 'package:async/async.dart'; is usually enough (it's a convention to name the main entrypoint file (async.dart) of a package the same as the package) and all exported identifiers become available in your library. Otherwise you can search the source of your project and WebStorm will also search dependencies and show what library contains the StreamQueue class. Then you can import this file.

Related

How to use Dart's analysis server method search.findTopLevelDeclarations?

I'm trying to get list of top level class declarations with Dart's analysis server. So, I'm sending search.findTopLevelDeclarations request, but search results are always empty.
It seems to me that analysis server don't know where to search. I've tried to set my project's root as execution context (execution.createContext) root and/or analysis root (analysis.setAnalysisRoots), but search results are still empty.
What should I do to make server understand where to search declarations?
Never played with this before so I got into quite a journey...
I don't know how you are interacting with the analysis server but I have made a working example using the analysis_server_client package. One problem doing that is that the version on pub.dev is quite old so I ended up fetching the version from the stable branch of Dart SDK:
https://github.com/dart-lang/sdk/tree/stable/pkg/analysis_server_client
You can then import the package in your pubspec.yaml by doing:
dependencies:
analysis_server_client:
path: /path/to/analysis_server_client
I then made a simplified version of the example code from:
https://github.com/dart-lang/sdk/blob/stable/pkg/analysis_server_client/example/example.dart
import 'dart:io' show exit;
import 'package:analysis_server_client/handler/connection_handler.dart';
import 'package:analysis_server_client/handler/notification_handler.dart';
import 'package:analysis_server_client/protocol.dart';
import 'package:analysis_server_client/server.dart';
final server = Server();
Future<void> main(List<String> args) async {
const targetDirPath = r'C:\tmp\simple_project';
const searchPattern = 'main';
// Launch the server
await server.start();
// Connect to the server
final handler = _Handler(server);
server.listenToOutput(notificationProcessor: handler.handleEvent);
if (!await handler.serverConnected(timeLimit: const Duration(seconds: 15))) {
exit(1);
}
await server.send(ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS,
AnalysisSetAnalysisRootsParams([targetDirPath], const []).toJson());
await server.send(SEARCH_REQUEST_FIND_TOP_LEVEL_DECLARATIONS,
SearchFindTopLevelDeclarationsParams(searchPattern).toJson());
}
class _Handler with NotificationHandler, ConnectionHandler {
#override
final Server server;
_Handler(this.server);
#override
void onSearchResults(SearchResultsParams params) {
print('-- Start of result --');
params.results.forEach(print);
print('-- End of result --');
server.stop();
}
}
The project at C:\tmp\simple_project is a simple project created with the following which means it just contains a single main method:
dart create -t console-simple simple_project
When I run my analyzer program I get the following output:
-- Start of result --
{"location":{"file":"C:\\tmp\\simple_project\\bin\\simple_project.dart","offset":5,"length":4,"startLine":1,"startColumn":6,"endLine":1,"endColumn":10},"kind":"DECLARATION","isPotential":false,"path":[{"kind":"FUNCTION","name":"main","location":{"file":"C:\\tmp\\simple_project\\bin\\simple_project.dart","offset":5,"length":4,"startLine":1,"startColumn":6,"endLine":1,"endColumn":10},"flags":8,"parameters":"(List<String> arguments)","returnType":"void"},{"kind":"COMPILATION_UNIT","name":"simple_project.dart","location":{"file":"C:\\tmp\\simple_project\\bin\\simple_project.dart","offset":0,"length":0,"startLine":1,"startColumn":1,"endLine":1,"endColumn":1},"flags":16},{"kind":"LIBRARY","name":"","location":{"file":"C:\\tmp\\simple_project\\bin\\simple_project.dart","offset":0,"length":0,"startLine":1,"startColumn":1,"endLine":1,"endColumn":1},"flags":0}]}
-- End of result --
If I change searchPattern to an empty String, I gets a long list of top level declarations around the default included Dart SDK libraries. I am sure there are a way to exclude those.
But as far as I can see, the searchPattern is a regular expression tested against the name of each top level declaration and includes the declaration if its name contain any part of the regular expression.
I found the code responsible for the search here:
#override
Future<List<SearchMatch>> searchTopLevelDeclarations(String pattern) async {
var allElements = <Element>{};
var regExp = RegExp(pattern);
var drivers = _drivers.toList();
for (var driver in drivers) {
var elements = await driver.search.topLevelElements(regExp);
allElements.addAll(elements);
}
return allElements.map(SearchMatchImpl.forElement).toList();
}
https://github.com/dart-lang/sdk/blob/1278bd5adb6a857580f137e47bc521976222f7b9/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart#L113-L123
Which calls into:
/// Returns top-level elements with names matching the given [regExp].
Future<List<Element>> topLevelElements(RegExp regExp) async {
List<Element> elements = <Element>[];
void addElement(Element element) {
if (!element.isSynthetic && regExp.hasMatch(element.displayName)) {
elements.add(element);
}
}
List<FileState> knownFiles = _driver.fsState.knownFiles.toList();
for (FileState file in knownFiles) {
var unitResult = await _driver.getUnitElement(file.path);
if (unitResult is UnitElementResult) {
CompilationUnitElement unitElement = unitResult.element;
unitElement.accessors.forEach(addElement);
unitElement.classes.forEach(addElement);
unitElement.enums.forEach(addElement);
unitElement.extensions.forEach(addElement);
unitElement.functions.forEach(addElement);
unitElement.mixins.forEach(addElement);
unitElement.topLevelVariables.forEach(addElement);
unitElement.typeAliases.forEach(addElement);
}
}
return elements;
}
https://github.com/dart-lang/sdk/blob/1278bd5adb6a857580f137e47bc521976222f7b9/pkg/analyzer/lib/src/dart/analysis/search.dart#L166-L192

Using Vaadin components in a kotlin js project

This question is about a Kotlin JS project which uses the Kotlin Frontend Plugin.
I want to use some UI components from the Vaadin Components library.
I have two questions about this:
(1) What would be the best way to include web components in Kotlin JS
=> for my complete code, see the link to the source below. In summary the relevant details are:
build.gradle.kts
kotlinFrontend {
npm {
dependency("#vaadin/vaadin-grid")
}
}
vaadin.grid.Imports.kt
#file:JsModule("#vaadin/vaadin-grid")
#file:JsNonModule
package vaadin.grid
external class GridElement {
companion object
}
Why the companion object? I need it for the workaround (see below).
foo.kt
fun main() {
document.getElementById("container")!!.append {
vaadin_grid {
attributes["id"] = "grid"
}
}
initUI()
}
fun initUI() {
// Force the side-effects of the vaadin modules. Is there a better way?
console.log(GridElement)
val grid = document.querySelector("#grid") /* ?? as GridElement ?? */
}
The console.log is the ugly workaround trick I want to avoid. If I don't do anything with GridElement then it's just not included in my bundle.
The vaadin_grid DSL is defined as a custom kotlinx.html tag which is unrelated code.
(2) I want to keep my code as typed as possible to avoid asDynamic but when I cast the HTMLElement to a Vaadin Element I get ClassCastExceptions (because GridElement is undefined).
For example I want to write something like this:
val grid : GridElement = document.querySelector("#grid") as GridElement
grid.items = ... // vs grid.asDynamic().items which does work
Here is how I define the external GridElement
vaadin/button/Imports.kt
#file:JsModule("#vaadin/vaadin-grid")
#file:JsNonModule
package vaadin.grid
import org.w3c.dom.HTMLElement
abstract external class GridElement : HTMLElement {
var items: Array<*> = definedExternally
}
build/node_modules/#vaadin/vaadin-grid/src/vaadin-grid.js
...
customElements.define(GridElement.is, GridElement);
export { GridElement };
Source example
To run:
From the root of the git repo:
./gradlew 05-kt-frontend-vaadin:build && open 05-kt-frontend-vaadin/frontend.html
I found the answer(s)
For the first question
(1) What would be the best way to include web components in Kotlin JS
Instead of the console.log to trigger the side effects I use require(...)
external fun require(module: String): dynamic
fun main() {
require("#vaadin/vaadin-button")
require("#vaadin/vaadin-text-field")
require("#vaadin/vaadin-grid")
...
}
(credits to someone's answer on the kotlin-frontend-plugin list)
(2) I want to keep my code as typed as possible to avoid asDynamic
Instead of importing #vaadin/vaadin-grid I have to import the file which actually exposes the element. Then it seems to work and I can even add generics to my GridElement:
#file:JsModule("#vaadin/vaadin-grid/src/vaadin-grid")
#file:JsNonModule
package vaadin.grid
import org.w3c.dom.HTMLElement
abstract external class GridElement<T> : HTMLElement {
var items: Array<out T> = definedExternally
}
This way I was able to get rid of all the asDynamics
val firstNameField = document.querySelector("#firstName") as TextFieldElement?
val lastNameField = document.querySelector("#lastName") as TextFieldElement?
val addButton = document.querySelector("#addButton") as ButtonElement?
val grid = document.querySelector("#grid") as GridElement<Person>?
val initialPeople: Array<out Person> = emptyArray()
grid?.items = initialPeople
addButton?.addEventListener("click", {
// Read the new person's data
val person = Person(firstNameField?.value, lastNameField?.value)
// Add it to the items
if(grid != null){
val people = grid.items
grid.items = people.plus(person)
}
// Reset the form fields
firstNameField?.value = ""
lastNameField?.value = ""
})

Flutter Dart: Future.wait() pass value by reference?

In a scenario like the following, how to pass a variable List<Document> itemList by reference ?
Future.wait([futDocs]).then((dataRet){
dataRet.forEach((doco) {
var docList = doco.documents;
docList.forEach((doc){
var docTitle = doc['title'];
print("data is $docTitle");
itemList.add(docTitle); <--- change not reflected outside this function
The itemList does not change when itemList.add(docTitle) is performed in the above Future.wait(). I believe the reason is because itemList is not passed by reference. If I cannot pass itemList by reference, how can I make this work? Can I return dataRet as a list and use it outside Future.wait()?
Adding more info...
Above call is performed within the constructor of class ListBuilder as shown in the following code:
class ListBuilder {
List<Document> itemList = new List<Document>();
ListBuilder(){
var futDocs = Firestore.instance.collection('Data').orderBy('time').limit(10).getDocuments();
Future.wait([futDocs]).then((dataRet) {
dataRet.forEach((doco) {
var docList = doco.documents;
docList.forEach((doc){
var docTitle = doc['title'];
print("data is $docTitle");
itemList.add(docTitle); <--- change not reflected outside this function
[...]
While waiting for an answer, i have tried custom setters and getters as well as the use of this.itemList.add(...) but without success.
Any help, it is much appreciated.
Thanks in advance!
All objects in Dart are passed by reference.
The problem is likely [itemList] isn't updated immediately because Future.wait is an async function. Any code dealing with itemList has to run inside the callback function ( .then((dataret) { ... }); ).
class ListBuilder {
List<Document> itemList = new List<Document>();
ListBuilder() {
var Docs =
Firestore.instance.collection('Data').orderBy('time').limit(10).getDocuments();
Future.wait([futDocs]).then((dataRet) {
dataRet.forEach((doco) {
var docList = doco.documents;
docList.forEach((doc) {
var docTitle = doc['title'];
itemList.add(docTitle);
});
});
/*
itemList has been updated here because we are inside a callback function that
runs _after_ Future.wait has completed.
*/
});
/*
itemList hasn't been updated here _yet_ because this code runs immediately,
regardless how long the Future.wait call takes to complete.
*/
}
}
If you want you can use async/await logic instead of a callback function, which is often easier to read and maintain. More info here: https://www.dartlang.org/tutorials/language/futures
More code would be helpful, but the first things that come to mind are these:
It will probably work to call await before your Future.wait so that the asynchronous code is for sure run
This seems less likely, but you may have to call setState when adding your to your list
Edit:
I would suggest code like this:
class ListBuilder {
List<Document> itemList = new List<Document>();
Future<void> myFunc(var futDocs) async {
await Future.wait([futDocs]).then((dataRet){
[...] *Rest of your Future code here*
}
ListBuilder() {
var futDocs = Firestore.instance.collection('Data').orderBy('time').limit(10).getDocuments();
myFunc(futDocs)
[...]
I have solved the problem however it was not related to pass value by reference. Thank you for your answers, they actually got me thinking and pointed me in the right direction.
The following was the solution to a problem which is not the one raised above :D LOL
Tl;dr; answer:
Change the widget to use streamBuilder
Long answer
The problem was due to the fact that changes to a list were not reflected outside the .then() function. Well, the issue itself is not related to how the list was passed to the function but to the use of async/await logic. When the app is executed, it will populate the itemList in Widget with the current items in the list - this is empty when it starts. In the meanwhile, with an async call, firebase fetch the data and list is updated. However, the UI is not changed. Now, setState gave me an idea but was not the solution. In my case, I don't need a stateful Widget but rather the use of StreamBuilder within the creation of the widget. This bind the list to the async call with the use of stream
new StreamBuilder(
stream: Firestore.instance.collection('data').orderBy('time').limit(10).snapshots(),
builder: (context, snapshot) {
return itemList...
Thanks again!

Dart JSON Decoder

I am surprised that dart does not have a built in object-to-json and json-to-object mapper.
I read that we have to hand code the mapping ourselves, which is not pleasant.
Anyways, although I have not thoroughly tested it for my use case, I found dart-exportable to be very helpful for half of my requirement.
Any suggested package for json to object decoding?
Your best option is to use the Smoke library.
It's a subset of the Mirrors functionality but has both a Mirrors-based and a Codegen-based implementation. It's written by the PolymerDart team, so it's as close to "Official" as we're going to get.
While developing, it'll use the Mirrors-based encoding/decoding; but for publishing you can create a small transformer that will generate code.
Seth Ladd created a code sample here, which I extended slightly to support child-objects:
abstract class Serializable {
static fromJson(Type t, Map json) {
var typeMirror = reflectType(t);
T obj = typeMirror.newInstance(new Symbol(""), const[]).reflectee;
json.forEach((k, v) {
if (v is Map) {
var d = smoke.getDeclaration(t, smoke.nameToSymbol(k));
smoke.write(obj, smoke.nameToSymbol(k), Serializable.fromJson(d.type, v));
} else {
smoke.write(obj, smoke.nameToSymbol(k), v);
}
});
return obj;
}
Map toJson() {
var options = new smoke.QueryOptions(includeProperties: false);
var res = smoke.query(runtimeType, options);
var map = {};
res.forEach((r) => map[smoke.symbolToName(r.name)] = smoke.read(this, r.name));
return map;
}
}
Currently, there is no support to get generic type information (eg. to support List) in Smoke; however I've raised a case about this here:
https://code.google.com/p/dart/issues/detail?id=20584
Until this issue is implemented, a "good" implementation of what you want is not really feasible; but I'm hopeful it'll be implemented soon; because doing something as basic as JSON serialisation kinda hinges on it!
I haven't had the time to complete it yet but dartson is currently working using mirrors. However a better solution would be using a transformer when compiling to JavaScript. https://pub.dartlang.org/packages/dartson

Reading static files under a library in Dart?

I am writing a library in Dart and I have static files under the library folder. I want to be able to read those files, but I'm not sure how to retrieve the path to it... there is not __FILE__ or $0 like in some other languages.
Update: It seems that I was not clear enough. Let this help you understand me:
test.dart
import 'foo.dart';
void main() {
print(Foo.getMyPath());
}
foo.dart
library asd;
class Foo {
static Path getMyPath() => new Path('resources/');
}
It gives me the wrong folder location. It gives me the path to test.dart + resources/, but I want the path to foo.dart + resources/.
As mentioned, you can use mirrors. Here's an example using what you wanted to achieve:
test.dart
import 'foo.dart';
void main() {
print(Foo.getMyPath());
}
foo.dart
library asd;
import 'dart:mirrors';
class Foo {
static Path getMyPath() => new Path('${currentMirrorSystem().libraries['asd'].url}/resources/');
}
It should output something like:
/Users/Kai/test/lib/resources/
There will probably be a better way to do this in a future release. I will update the answer when this is the case.
Update: You could also define a private method in the library:
/**
* Returns the path to the root of this library.
*/
_getRootPath() {
var pathString = new Path(currentMirrorSystem().libraries['LIBNAME'].url).directoryPath.toString().replaceFirst('file:///', '');
return pathString;
}
The dart mirrors API (still experimental, and not available on all platforms such as dart2js yet) exposes a url getter on the LibraryMirror. This should give you what you want.
I'm not aware of any other way to get this information on a library.
#import('dart:mirrors');
#import('package:mylib/mylib.dart');
main(){
final urlOfLib = currentMirrorSystem().libraries['myLibraryName'].url;
}
Generally the usual method of accessing resources which are located at a static position with your library is by use using a relative path.
#import('dart:io');
...
var filePath = new Path('resources/cool.txt');
var file = new File.fromPath(filePath);
// And if you really wanted, you can then get the full path
// Note: below is for example only. It is missing various
// integrity checks like error handling.
file.fullPath.then((path_str) {
print(path_str);
});
See addition API information on Path and on File
As an aside.. If you absolutely wanted to get the same type of output as __FILE__ you can do something like the following:
#import('dart:io');
...
var opts = new Options();
var path = new Path(opts.script);
var file = new File.fromPath(path);
file.fullPath().then((path_str) {
print(path_str);
});

Resources