Can't figure out how to load yaml document in Dart - dart

According to the readme for the Dart-Yaml pub package, I should be able to do the following:
var db = loadYamlDocument("db.yaml");
with print(db['hostname']); giving me the value I have specified for port in that yaml, however I'm told that YamlDocument has no instance method []. Okay, I guess that object doesn't have map behaviors, which is something I would have expected it to have. Looking through the docs, there's mention of a YamlMap, but I don't see how to implement that at all.
If I simply try print(db); I actually get the string: 'db.yaml'.
So I tried using new File('db.yaml'); and then sending that variable into the loadYamlDocument method, but that doesn't work either.
Does anyone have any luck reading a yaml document and getting a map out of it in Dart?

import "dart:io";
import "package:yaml/yaml.dart";
main() {
File file = new File('pubspec.yaml');
String yamlString = file.readAsStringSync();
Map yaml = loadYaml(yamlString);
}
EDIT:
Map loadYamlFileSync(String path) {
File file = new File(path);
if (file?.existsSync() == true) {
return loadYaml(file.readAsStringSync());
}
return null;
}
Future<Map> loadYamlFile(String path) async{
File file = new File(path);
if ((await file?.exists()) == true) {
String content = await file.readAsString();
return loadYaml(content);
}
return null;
}
main(List<String> args){
print(loadYamlFileSync("pubspec.yaml"));
}

Check the documentation pages for the Yaml package.
loadYamlDocument() returns a YamlDocument which is a 'heavyweight' class that gives you access to all the features of a Yaml document.
You probably want to use loadYaml, which in most cases is going to return a Map. The description says that the actual implementation of the map is a YamlMap (the Yaml package's implementation of a Map, that they presumably need to use instead of a HashMap for some technical reason).

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

FLUTTER How to get variable based on passed string name?

I have stored variables in a class with their code names.
Suppose I want to get XVG from that class, I want to do
String getIconsURL(String symbol) {
var list = new URLsList();
//symbol = 'XVG'
return list.(symbol);
}
class URLsList{
var XVG = 'some url';
var BTC = 'some url';
}
Can someone help me achieve this or provide me with a better solution?
Dart when used in flutter doesn't support reflection.
If it's text that you want to have directly in your code for some reason, I'd advise using a text replace (using your favourite tool or using intellij's find + replace with regex) to change it into a map, i.e.
final Map<String, String> whee = {
'XVG': 'url 1',
'BTC': 'url 2',
};
Another alternative is saving it as a JSON file in your assets, and then loading it and reading it when the app opens, or even downloading it from a server on first run / when needed (in case the URLs need updating more often than you plan on updating the app). Hardcoding a bunch of data like that isn't necessarily always a good idea.
EDIT: how to use.
final Map<String, String> whee = .....
String getIconsURL(String symbol) {
//symbol = 'XVG'
return whee[symbol];
}
If you define it in a class make sure you set it to static as well so it doesn't make another each time the class is instantiated.
Also, if you want to iterate through them you have the option of using entries, keys, or values - see the Map Class documentation
I'd just implement a getProperty(String name) method or the [] operator like:
class URLsList{
var XVG = 'some url';
var BTC = 'some url';
String get operator [](String key) {
switch(key) {
case 'XVG': return XVG;
case 'BTC': return BTC;
}
}
}
String getIconsURL(String symbol) {
var list = new URLsList();
return list[symbol];
}
You can also use reflectable package that enables you to use reflection-like code by code generation.
Assuming that the class is being created from a JSON Object, you can always use objectName.toJSON() and then use the variable names are array indices to do your computations.

Analyzer package - How to recursively search in the results of parseDartFile()

Currently trying to understand 'analyzer' package, because I need to analyze and edit .dart file from another file (maybe it's a terrible idea).
I think I understand how to go deep into the childEntities tree.
But can't understand how to search in it.
I mean, theoretically I can write a recursive search that will find me a class named "FindABetterSolution". But is there a built in method for that?
What I'm trying to do:
var file = parseDartFile("test.dart");
file.childEntities.forEach((SyntacticEntity entity) {
if(entity is AstNode) {
//then it has its own child nodes which can be AstNode-s or Tokens.
} else if(entity is Token) {
Token token = entity;
print("${token.lexeme} ${token.type} ${token.runtimeType} ${token.keyword}");
//this will output "class KEYWORD KeywordToken CLASS" for "class" in "class MyClass {"
}
});
//I need a way to find certain functions/classes/variables/methods e.t.c.
var myClassNode = file.searchClass("MyClass", abstract: false);
var myMethod = myClassNode.searchMethod("myMethod", static: true);
var globalFunction = file.searchFunction("myFunc", returns: "bool");
UPD: Ok, I think I found a way to search and replace nodes. But how to insert new node after/before another?
You can call file.accept() or file.visitChildren() with a RecursiveAstVisitor that implements visitClassDeclaration, visitMethodDeclaration, or visitFunctionDeclaration.

Dart streams, equivalent of await for

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.

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