map_list_dot

Last updated:

0 purchases

map_list_dot Image
map_list_dot Images
Add to Cart

Description:

map list dot

MapList : quick prototyping #
Create pseudo class with accessors from json descriptor #
A json String, a json 'Dart', or any maps & lists set, are enough to create a class with a dot notation to access properties.
dynamic p1 = MapListMap({
"name": "Polo",
"firstName": "marco",
"birthDate": { "day": 15, "month": 9, "year": 1254 }
});
copied to clipboard
use getter in dot notation
print('${p1.firstName} ${p1.name} have now ${DateTime.now().year - p1.birthDate.year} years');
// -> marco Polo have now 766 years
copied to clipboard
can apply setters #
p1.firstName = 'Marco';
copied to clipboard
can dynamically create new named properties #
// add a collection for business cards
p1.cards = [];
// add a new card with a pre-filled map
p1.cards.add({
"mail": "[email protected]",
});
copied to clipboard
Continue freely the creation chain
// add to this -last added- map a new entry
p1.cards.last.phone = "+99 01 02 03 04 05";
print(p1.cards.last.mail);
print(p1.cards.last.phone);
//@see examples for more code
copied to clipboard
At any time the underlying json is updated and available
print(p1.json);
copied to clipboard
Access and update your Data Objects with scripts #
What is available in dot notation within Dart is also available by script :
var scriptLines = [
'persons=[]',
'''persons.add({ "name": "Magellan", "firstName": "Fernando",
"birthDate": { "day": 15,"month": 3,"year": 1480}
})
''',
'persons.last.cards = {"mail": "[email protected]"})',
'persons.last.cards.phone = "+99 01 02 03 04 05"'
];
copied to clipboard
Script executor is under a MapList responsibility
dynamic myKB = MapListMap();
for (String line in scriptLines) myKB.eval(line);
copied to clipboard
Resulting data can be accessed by code or by script
print( myKB.persons.last.cards.phone); // code
print(myKB.eval('persons.last.cards.phone')); // interpreter
copied to clipboard
now some details #
constructors #
There is two kinds of structures : MapListMap and MapListList
If you decide by yourself, choose your root within this two options:
dynamic myRootMap = MapListMap(); // empty map { }
dynamic myRootList = MapListList(); // empty list [ ]
copied to clipboard
If you rely on a variable json , you can leave a higher factory do the choice :
dynamic myRoot = Maplist(someJson); // return a MapListMap or a MapListList
copied to clipboard
constructors with json data #
Each constructor can be default as above, or can be initialised with :

a Json String
an inline maps and lists in dart
an already loaded 'Dart Json'

dynamic myRootMap = MapListMap('{"name":"Polo"}'); // string
dynamic myRootMap = MapListMap({"name":"Polo"}); // inline

var myJson = json.decode('{"name":"Polo"}');
dynamic myRootMap = MapListMap(myJson); // already json dart
copied to clipboard
Same options are for MapListList constructors, but beginning by a List [ ]
Same options with the Factory MapList which will decide of the following.
accessing data #
Classical and dot notation are usable in code and in scripts.
The result is the last leaf which could be a simple data, a List, a Map or a null if not found.
classical notation
root["show"]["videos"][1]["name"]
copied to clipboard
dot notation
root.show.videos[1].name
copied to clipboard
General access
a .someName indicates a key entry in a map.

if the result is another Map

can continue with another key : .someName.someList


if the result is a List

can continue with an index : someList[1]
can use the keyword last : someList.last

The result of the result can be a Map or another List

someList [10].anotherKey
somelist [10] [2]






if the result is a simple data, cannot continue notation : must be the last leaf.

the full name allows to get data : someName.someList[1] // returns an int;
the full name allows to set data : someName.someList[1] = 12;



special words #
Some words are identified as questions or actions.
// on Lists
root.show.videos.length
root.show.videos.clear()
root.show.videos.isEmpty
root.show.videos.isNotEmpty
root.show.videos.last
// on Maps
root.show.length
root.show.clear()
root.show.isEmpty
root.show.isNotEmpty
copied to clipboard
create and set data with dot notation #
create empty structures
dynamic squad = MapListMap(); // create an empty map as squad.
squad.members = []; // add an empty list named 'members'
squad.activities = {}; // add also an empty map 'activities' at first level
dynamic squad = MapListMap({members: [], activities: {}); // the same in one line at construction
copied to clipboard
Note : With dot notation, create unknown data one level at a time (or use json).
create with more pre-filled data
// creation with direct structure
root = MapListMap({"dico":{"hello":{"US": "Hi", "FR": "bonjour"} }});
// If you plan to use heterogeneous data : better to precise type:
root = MapListMap( {"dico":<String,dynamic>{"hello":{"US": "Hi", "FR": "bonjour"} }});
// or use json string message that do the job with its internal types:
root = MapListMap(' {"dico":{"hello":{"US": "Hi", "FR": "bonjour"} }} ');

copied to clipboard
can use relay to simplify access
// follow previous sample : create with more complex data
root.dico.numbers = {"US": ["zero","one","two","three","four","five","sic","seven","eight","nine"]};
var numbers = root.dico.numbers;
var USnumbers = numbers.US;
print(USnumbers[3]);
copied to clipboard
Note : except for the root which must be declared dynamic, you can leave var at lower levels as the returned class is a MapList.
add a Map into another Map (both MapListMap)
dynamic car = MapListMap(); // use dynamic to allow dot notation on root
car.brand = "Ford";
car.colors = ["blue","black","white"];
car.chosenColor = "white";
// now add this car to a larger set
dynamic myStuff = MapListMap();
myStuff.myCar = car; // create a property myCar with given values
copied to clipboard
Add to a List : one element with add, another List with addAll
dynamic list = MapListList();
list.add(15);
list.addAll([1, 2, 3]);
list.add({"date":"october 16"});
print(list); //[15, 1, 2, 3, {date: october 16}]
copied to clipboard
add or change elements of a map with another map : addAll
dynamic car = MapListMap();
car.name = "ford";
// add to this map several key:value in one shot or change existing
car.addAll({ "name":"Ford","price": 5000, "fuel":"diesel","hybrid":false});
copied to clipboard
Check nullable while accessing data #
store.wrongName.someData
copied to clipboard
To avoid the error "NoSuchMethodError: The getter 'someData' was called on null",
Dart takes care of the nullable notation.
The following code will return null or the data, without throwing error.
store.wrongName?.someData
store.eval('wrongName?.someData');
copied to clipboard
note: The interpreter takes care of the null notation.
MapLists return null on unknown data #

unknown key in a Map
wrong index on a List
misused of types , like indexing a Map or using key on a List
for interpreter :

wrong syntax
malformed json



In all cases, MapList will returns null and logs a Warning on the standard logger.
Wrong index on a List : sample of log
MapList logs a Warning with a reminder of the initial error :
print(store.book[400]); // -> null
// WARNING: unexisting book [400] : null returned .
// Original message : RangeError (index): Invalid value: Not in range 0..3, inclusive: 4
copied to clipboard
You can protect downstream errors with a nullable option :
store.book[400]?.author = "zaza" ;
copied to clipboard
Non existing List
If the list doesn't exist at all, the nullable must be checked before the index to avoid error on the operator [ ]:
store.pocketBookList?[0].author = "zaza";
copied to clipboard
Dart allows this syntax recently with Dart 2.9.2.
Before 2.9.2 you cannot compile with a nullable before [0] in code.
The interpreter already allows this syntax.
The hell of data types and how to protect code #
MapList works on a basis of Map<String,dynamic> and List<dynamic> .
Using and adding json data, which are Map<dynamic,dynamic> and List<dynamic>, is full compliant.
warn with inline coded structure
This codes with a List will fail:
root.data = [11, 12, 13]; // will infer a List<int>
root.data.add(14); // ok
root.data.add("hello"); // will fail :type 'String' is not a subtype of type 'int'
copied to clipboard
If a type is not indicated, Dart infers the type from the current assignment and [11,12,13] will be a List<int>.
From there, you can only add other <int> without errors, nothing else like "hello" without a crash.
Similar things can happen with a map.
This code will fail :
root.results = {"elapsed_time": 30, "temperature": 18} // is ok but result is a List of Map<String, int>
root.results.time = "12:58:00"; // will fail : type 'String' ("12:58:00") is not a subtype of type 'int' of 'value'
copied to clipboard
add <dynamic>
Think about adding type
root.data = <dynamic> [11, 12, 13];
root.data.add(14); // ok
root.data.add("hello"); // ok
copied to clipboard
root.results = <String,dynamic>{"elapsed_time": 60, "temperature": 40};
root.results.time = "12:58:00"; // now ok !
copied to clipboard
If you use constructors with a String structure, or 'dart json', MapList do the job of enlarging types to dynamic.
Logged errors #
MapList try to avoid runtime errors:
If something is wrong, it logs Warning but continue without errors:

On a wrong get, it logs message and returns null .
On a wrong set : it logs message and do nothing else .
(To see the messages, you must set a logging listener in your code (@see standard logging package).)

common warning : using List as Map or Map as List
aList["toto"]="riri";
**WARNING** index ["toto"] must be applied to a map. no action done.
copied to clipboard
aMap[0]="lulu":
**WARNING** [0] must be applied to a List. no action done.
copied to clipboard
print(aList.price);
**WARNING** Naming error: trying to get a key "price" in a List. null returned
copied to clipboard
Wrong index in List
print(root[200]);
**WARNING**: unknown accessor: . [200] : null returned .(followed by original dart error 'Not in range..')
copied to clipboard
Wrong json data in a String at runtime (if direct inline code, compiler will warn )
dynamic root = MapList('{"this": is not a valid entry }');
**WARNING** wrong json data. null returned .
(followed by original conversion error)
copied to clipboard
remaining runtime that can throw errors
Mainly Type mismatch if inline data are not correctly casted .
Forgotten nullable in the evaluated path.
Leaving dart inline tolerance in script or json : comma at the end [11,12,]
some words about Yaml
I do prefer coding in yaml rather in json, but this have some defaults :
var yamlStructure = loadYaml(yamlString);
dynamic root = MapList(yamlStructure);
print(root.show.name); // ok
root.show.name = "new video title";
-> 'runtime Error: Unsupported operation: Cannot modify an unmodifiable Map';
copied to clipboard
If all get can work, no set are allowed because the standards yamlMap and yamlList are read only.
tips for Yaml
The most simple way to transform a read-only yaml in a full compliant json is the following :
root = MapList(json.decode(json.encode(yamlStructure)));
copied to clipboard
Some More details #
A MapList has a .json accessor to get the wrapped one if necessary.
MapList works with pointers, not copies :
json data stay synchronised between :

direct access to json
use with MapList in code
or use of MapList interpreter.

Embed MapList in a class with specific methods #
As is, MapListMap and MapListList are in the category of DataObjects
You can mix free dynamic set of data and classical methods within a class that extends a MapList flavour.
Such a class is in an example with the following class Person :
class Person extends MapListMap{
Person(some):super(some);
}
copied to clipboard
using dot notation inside the class : keyword me. #
As properties are free and in a json , a method cannot use this.someProperty as someProperty is not declared in class.
To allow retrieval of properties with dot notation, just use the keyword me. ( which is a cast of this as dynamic ).
In examples, we define an internal getter to the class Person, using dynamic data with me. :
int get age {
return (DateTime.now().year - me.birthDate.year);
}
copied to clipboard


MapList access interpreter #
An interpreter have some well known use cases :

applying create or update on a data set from textual messages
free interaction with data not known at compile time (knowledge base, blackboard pattern,...)
using maps and lists as an open graph

underlying base : JsonNode #
You don't really need to use JsonNode as such, but MapList uses it to walk the graph.
JsonNode is a kind of canoe that navigates on the data graph with :

fromNode
edge
toNode
(ascript : the path or the remaining path)

When you create a JsonNode with a path, it returns the last step of its journey.
To view itn the toString returns (type) fromNode -- last edge in use---> (type) toNode
(As a node could be a large thing, toString returns the beginning... of the data )
returning a data leaf
Below is shown the internal structure to see internal data.
var aJson = [ [1, 2, 3], [11, 12], {"A": "AA", "B": "BB"}, "andSoOn" ];
print(JsonNode(aJson, '[0][1]')); // (list)[1, 2, 3] --- 1 -> (int) 2
print(JsonNode(aJson, '[2]["B"]')); // (map){A: AA, B: BB} --- B -> (String) BB
print(JsonNode(aJson, '[2].length')); // (map){A: AA, B: BB} --- length -> (int) 2
copied to clipboard
returning a tree branch
var aJson = [ [1, 2, 3], [11, 12], {"A": "AA", "B": "BB"}, "andSoOn" ];
print(JsonNode(aJson,'[0]')); // (list)[[1, 2, 3], [11... --- 0 -> (list) [1, 2, 3]
print(JsonNode(aJson,'[2]')); //(list)[[1, 2, 3], [11... --- 2 -> (map) {A: AA, B: BB}
copied to clipboard
If you plan to use directly JsonNode, you can get the data by .value
(which is a convenient name to get the last toNode )
assert(JsonNode(aJson, '[2].B').value == "BB");
special words
JsonNode recognize some keywords:

.length
.isEmpty
.isNotEmpty
.last (on Lists )
.clear()

Note about length
Always use .length to get the length of a List or a Map. If there is a key length in a map, you can reach it with notation ["length"]
dynamic store = MapList('{"bikes":[{"name":"Fonlupt", "length":2.1, "color" : "green" }]}');
assert(store.eval('bikes[0].length') == 3);
assert(store.eval('bikes[0]["length"]')== 2.1);
copied to clipboard
how a caller can create unknown new data
When a path ends with an unknown name in a map, the last node is null but not the trip :
print(JsonNode(aJson, 'questions.newData'));// (map){A: AA, B: BB} --- newData -> (Null) null
copied to clipboard
A caller, like MapList do, can check the results and set the data with fromNode[edge] .
(if the path starts at the very beginning, the fromNode is also null and the edge must be applied to the root )
Same Hell of types in interpreter
Same precautions has to be taken on datatypes to avoid bad surprises.
Writing inline data with types could be cumbersome :
var aJson = <dynamic>[ [1, 2, 3], <String,dynamic> {"A": "AA", "B": "BB"}, "andSoOn" ];
copied to clipboard
Tip: Prefer using a json String and let MapList do a json.decode(string) do the job.

type in your inline structure to see its correctness : [ [1, 2, 3], {"A": "AA", "B": "BB"}, "andSoOn" ]
wrap it in quotes : '[ [1, 2, 3], {"A": "AA", "B": "BB"}, "andSoOn" ]'
use it in MapList(someString)

MapList eval(script) method : get and set data by script #
MapList uses underline the previous JsonNode mechanism, get the value and allows to create and set data.
get data
You can use same notations than in code to access a data, classical or dot notation.
MapList will return directly the data:

for an end leaf, it returns the value,
for an intermediary node, it returns the json wrapped in a new MapList (returning a MapList allows to combine interpreter and direct code with dot notation in code.)

Notice that the root is the executor and is not repeated in the path :
The script below returns a simple data :
dynamic book = MapList('{ "name":"zaza", "friends": [{"name": "lulu" }]}');
print(book.eval('friends[0].name')); // --> lulu);
copied to clipboard
All notation styles are allowed :
root.eval('["show"]["videos"][1]["questions"][1]["name"]') // classical notation
root.eval('show.videos[1].questions[1].options[2].answer') // dot notation
Special word returns also direct values:
if (store.eval('store.bikes.isEmpty')) print ('what a disaster');
copied to clipboard
scripts to set data #
assignment with equal symbol
MapList interpreter takes care of an assignment in the script.
The Left Hand Side of a script with assignment is the path to get by MapList.
The Right Hand Side is evaluated as a simple type data or as a json structure.
dynamic squad = MapList(); // will create a default Map
squad.eval('name = "Super hero squad"'); // add a String data
squad.eval('homeTown = "Metro City"'); // another
squad.eval('formed = 2016'); // add an int
squad.eval('active = true'); // add a bool
squad.eval('score = 38.5'); // add a double
squad.eval('overhauls = ["2008/04/10", "2102/05/01", "2016/04/17"]'); // add structured data
copied to clipboard
special functions to create or update data

add(something)

Only for Lists : add a new element


addAll(several something)

add all elements of a map to a map
all elements of a list to a list.


remove(something)

Remove an entry of a map
Remove an element in a list


length = <int>

force the length of a List



errors and logs #
See the previous chapter on errors and logs for common access errors.
Some errors normally detected by compiler can happen in interpreted string.
As an example below is a missing parenthesis around functions.
root.eval('clear'); // WARNING cannot search a key (clear) in a List<dynamic>
root.eval('clear()'); // ok
copied to clipboard
Nullable capacities #
Interpreter takes care of nullable notations at all levels :
store.eval('wrongName?.someData')
store.eval("book[4]?.author
store.eval("bookList?[0]") // Even if Dart is not in 9.2, the interpreter allows this nullable.
store.eval("bookList?[0]?.date")
copied to clipboard
Weakness
Probably some in the analysis of syntax in interpreter : in case of trouble verify deeply your strings.
MapList uses Symbol without mirrors and get the symbol name by hand : This could have issues with dart.js minifier, this has not been tested here.

License:

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Files In This Product:

Customer Reviews

There are no reviews.