2018-08-01 13:10:12 +00:00
# pluie-yaml
2018-08-01 15:15:45 +00:00
**pluie-yaml** is a vala shared library managing yaml files (v 1.2) and yaml nodes in vala language.
As json is now a valid subset of yaml, you can use this lib to load json files too.
2018-08-01 13:10:12 +00:00
2018-08-01 15:15:45 +00:00
The purpose of this project is to make vala able to load and deal with yaml configuration files.
2018-08-07 22:56:38 +00:00
So, currently the lib deal only with one yaml document (it's not recommended to use multiples doc),
but you can use a special `^imports` clause (special mapping node) to load a subset of yaml files
in the main yaml document.
2018-08-01 15:49:01 +00:00
2018-08-11 00:28:19 +00:00
The lib partially manage tag directives and tag values (basic types and Yaml.Object extended objects types).
2018-08-20 01:38:31 +00:00
with version 0.5, **pluie-yaml** is now able to :
2018-08-06 14:57:20 +00:00
2018-08-20 01:38:31 +00:00
* parse yaml file with vala tags => transform to Yaml.Node
* Build Yaml.Object from Yaml.Node (with some glue for struct and non Yaml.Object derived types)
* Build Yaml.Node from Yaml.Object (with some glue for struct and non Yaml.Object derived types)
2018-08-07 18:14:38 +00:00
2018-08-20 01:38:31 +00:00
**pluie-yaml** use the ![libyaml c library ](https://github.com/yaml/libyaml ) (License MIT, many thanks to Kirill Simonov) to parse and retriew related yaml events.
2018-08-18 21:54:18 +00:00
2018-08-20 01:44:36 +00:00
![pluie-yaml-1 ](https://www.meta-tech.academy/img/pluie-yaml-1.png?tmp=1 )
2018-08-18 21:54:18 +00:00
2018-08-20 01:38:31 +00:00
![pluie-yaml-2 ](https://www.meta-tech.academy/img/pluie-yaml-2.png )
2018-08-07 22:56:38 +00:00
2018-08-01 15:15:45 +00:00
## License
GNU GPL v3
2018-08-01 13:10:12 +00:00
## Prerequisites
2018-08-10 00:12:08 +00:00
`valac meson ninja libyaml glib gobject gmodule gee pluie-echo`
2018-08-01 13:10:12 +00:00
2018-08-07 22:56:38 +00:00
see https://git.pluie.org/pluie/libpluie-echo in order to install pluie-echo-0.2 pkg
2018-08-01 13:10:12 +00:00
## Install
2018-08-01 15:15:45 +00:00
git clone the project then cd to project directory and do :
2018-08-01 13:10:12 +00:00
```
meson --prefix=/usr ./ build
sudo ninja install -C build
```
## Compilation
```
2018-08-10 00:12:08 +00:00
valac --pkg pluie-echo-0.2 --pkg pluie-yaml-0.4 main.vala
2018-08-01 13:10:12 +00:00
```
2018-08-18 23:18:55 +00:00
You can use `./build.sh` to rebuild/install the **pluie-yaml** lib and compile samples files
2018-08-01 15:15:45 +00:00
2018-08-07 22:56:38 +00:00
2018-08-01 13:10:12 +00:00
## Api / Documentation
2018-08-18 23:18:55 +00:00
https://pluie.org/pluie-yaml-0.5/index.htm
2018-08-01 13:10:12 +00:00
2018-08-07 22:56:38 +00:00
2018-08-01 13:10:12 +00:00
## Docker
2018-08-18 23:18:55 +00:00
A demo image is now available on docker hub. To run a container :
2018-08-01 13:10:12 +00:00
```
docker run --rm -it pluie/libyaml
```
2018-08-18 23:18:55 +00:00
Then you can execute any samples, for example :
2018-08-07 18:14:38 +00:00
```
./json-loader
```
![pluie-yaml-json ](https://www.meta-tech.academy/img/pluie-yaml-json.png )
2018-08-07 22:56:38 +00:00
see ![pluie/docker-images repository ](https://github.com/pluie-org/docker-images )
for more details
2018-08-07 18:14:38 +00:00
2018-08-01 13:10:12 +00:00
## Usage
2018-08-02 21:44:36 +00:00
-------------------
2018-08-01 15:49:01 +00:00
### config
2018-08-02 21:44:36 +00:00
```vala
2018-08-01 15:49:01 +00:00
var config = new Yaml.Config (path);
var node = config.get ("ship-to.address.city{0}");
if (node != null) {
of.echo (node.data)
}
```
2018-08-07 22:56:38 +00:00
see Finder below to get precisions about config.get parameter (search path definition)
2018-08-05 13:18:25 +00:00
2018-08-02 21:44:36 +00:00
-------------------
### config with ^imports clause
```yml
# | use special key word '^imports' to import other yaml config files in
# | current yaml document
# | '^imports' must be uniq and a direct child of root node
# | imported files are injected as mapping nodes at top document level
# | so you cannot use keys that already exists in the document
^imports :
# you can redefine default import path with the special key '^path'
# if you do not use it, the default path value will be the current directory
# redefined path values are relative to the current directory (if a relative path
# is provided)
^path : ./config
# you can also define any other var by prefixing key with ^
^dir : subdir
# and use it enclosed by ^
# here final test path will be "./config/subdir/test.yml"
test : ^dir^/test.yml
# here final db path will be "./config/db.yml"
db : db.yml
```
2018-08-20 01:38:31 +00:00
![pluie-yaml ](https://www.meta-tech.academy/img/pluie-yaml-imports2.png )
2018-08-20 01:44:36 +00:00
__legend display_childs__ :
2018-08-20 01:38:31 +00:00
```
[ node.name [refCount] node.parent.name node.level node.ntype.infos () node.count () node.uuid node.tag]
```
You can easily manage display tracing of yaml nodes by setting these var according to your needs :
```vala
using Pluie
...
// general debug display usefull informations
Yaml.DEBUG = false;
// drive display_childs method :
Yaml.DBG_SHOW_INDENT = true;
Yaml.DBG_SHOW_PARENT = false;
Yaml.DBG_SHOW_UUID = true;
Yaml.DBG_SHOW_LEVEL = false;
Yaml.DBG_SHOW_REF = false;
Yaml.DBG_SHOW_COUNT = true;
Yaml.DBG_SHOW_TAG = true;
Yaml.DBG_SHOW_TYPE = true;
...
```
2018-08-02 21:44:36 +00:00
-------------------
2018-08-01 15:49:01 +00:00
2018-08-01 15:15:45 +00:00
### loader
2018-08-02 21:44:36 +00:00
load a single document.
`^imports` clause is out of effects here.
```vala
2018-08-01 15:15:45 +00:00
var path = "./config/main.yml";
// uncomment to enable debug
2018-08-18 21:01:07 +00:00
// Pluie.Yaml.DEBUG = true;
2018-08-01 15:15:45 +00:00
var loader = new Yaml.Loader (path /* , displayFile, displayNode */);
2018-08-01 13:10:12 +00:00
if ((done = loader.done)) {
2018-08-05 13:18:25 +00:00
Yaml.Node root = loader.get_nodes ();
2018-08-01 13:10:12 +00:00
root.display_childs ();
}
```
2018-08-02 21:44:36 +00:00
-------------------
2018-08-01 13:10:12 +00:00
2018-08-01 15:15:45 +00:00
### finder
2018-08-18 21:01:07 +00:00
**pluie-yaml** provide a `Yaml.Finder` to easily retriew a particular yaml node.
2018-08-01 15:15:45 +00:00
Search path definition has two mode.
2018-08-02 21:44:36 +00:00
The default mode is `Yaml.FIND_MODE.DOT`
2018-08-01 15:15:45 +00:00
- child mapping node are separated by dot
- sequence entry must be enclosed in curly brace
ex : `grandfather.father.son{2}.age`
2018-08-02 21:44:36 +00:00
The Other mode is Yaml.FIND_MODE.SQUARE_BRACKETS
- node's key name must be enclosed in square brackets
- sequence entry must be enclosed in curly brace
ex : `[grandfather][father][son]{2}[age]`
2018-08-01 15:15:45 +00:00
with singlepair node, you can retriew corresponding scalar node with {0}
2018-08-02 21:44:36 +00:00
ex yaml file :
```yml
2018-08-01 15:15:45 +00:00
product:
- sku : BL394D
quantity : 4
description : Basketball
2018-08-02 21:44:36 +00:00
```
vala code :
```vala
2018-08-01 15:15:45 +00:00
...
2018-08-05 13:18:25 +00:00
var loader = new Yaml.Loader (path, true);
if ((done = loader.done)) {
Yaml.Node root = loader.get_nodes ();
var finder = new Yaml.Finder(root);
Yaml.Node? node = null;
if ((node = finder.find ("product{0}.description")) != null) {
var val = node.val ();
}
...
}
```
### Traversing
#### via iterator
2018-08-08 16:01:10 +00:00
```vala
var config = new Yaml.Config (path);
var root = config.root_node ();
2018-08-08 16:14:57 +00:00
if (root != null & & !root.empty ()) {
foreach (var child in root) {
// do stuff
of.echo (child.to_string ());
}
2018-08-08 16:01:10 +00:00
}
```
or
2018-08-06 14:57:20 +00:00
```vala
2018-08-05 13:18:25 +00:00
var config = new Yaml.Config (path);
var root = config.root_node ();
2018-08-08 16:14:57 +00:00
if (root != null & & root.count () > 0) {
Iterator< Yaml.Node > it = root.iterator ();
Yaml.Node? child = null;
for (var has_next = it.next (); has_next; has_next = it.next ()) {
child = it.get ();
// do stuff
of.echo (child.to_string ());
}
2018-08-01 15:15:45 +00:00
}
```
2018-08-05 13:18:25 +00:00
#### other
2018-08-06 14:57:20 +00:00
```vala
2018-08-05 13:18:25 +00:00
if (!node.empty ()) {
Yaml.Node child = node.first();
of.action("loop throught mapping next sibling", child.name);
while (child!=null & & !child.is_last()) {
// do stuff
of.echo (child.to_string ());
child = child.next_sibling ();
}
}
```
2018-08-06 14:57:20 +00:00
```vala
2018-08-05 13:18:25 +00:00
if (node.count () > 0) {
child = node.last();
of.action("loop throught mapping previous sibling", child.name);
while (child!=null & & !child.is_first()) {
// do stuff
of.echo (child.to_string ());
child = child.previous_sibling ();
}
}
```
2018-08-02 21:44:36 +00:00
-------------------
2018-08-01 15:15:45 +00:00
2018-08-11 00:28:19 +00:00
### Tag Directives & Tag values
an example is available with `samples/yaml-tag.vala` sample
and `resources/tag.yml` file
on yaml side, proceed like that :
```yaml
%YAML 1.2
%TAG !v! tag:pluie.org,2018:vala/
---
!v!Pluie.Yaml.Example test1 :
myname : test1object
type_int : !v!int 3306
type_bool : !v!bool false
type_char : !v!char c
type_string : !v!string mystring1
type_uchar : !v!uchar L
type_uint : !v!uint 62005
type_float : !v!float 42.36
type_double : !v!double 95542123.4579512128
2018-08-18 21:54:18 +00:00
type_enum : !v!Pluie.Yaml.NODE_TYPE scalar # or int
2018-08-18 21:22:55 +00:00
!v!Pluie.Yaml.ExampleChild type_object :
2018-08-11 00:28:19 +00:00
toto : totovalue1
tata : tatavalue1
titi : 123
tutu : 1
2018-08-18 21:54:18 +00:00
!v!Pluie.Yaml.ExampleStruct type_struct :
red : !v!uint8 214
green : !v!uint8 78
blue : 153
!v!Gee.ArrayList type_gee_al :
- ab_1
- ab_2
- ab_3
- ab_4
2018-08-11 00:28:19 +00:00
```
2018-08-18 21:22:55 +00:00
**note :**
only the first level of yaml node matching a vala object need a tag.
**pluie-yaml** has mechanisms to retriew properties types of a Yaml.Object.
So basic vala types tag, enum tag, struct tag and derived Yaml.Object (here ExampleChild)
or GLib.Object vala tags are not necessary inside a Yaml.Object.
2018-08-11 00:28:19 +00:00
on vala side :
```vala
...
2018-08-18 21:01:07 +00:00
var obj = (Yaml.Example) Yaml.Builder.from_node (root.first ());
2018-08-18 21:54:18 +00:00
of.echo("obj.type_int : %d".printf (obj.type_int));
// calling ExampleChild method
2018-08-11 00:28:19 +00:00
obj.type_object.method_a ()
```
2018-08-18 21:54:18 +00:00
![pluie-yaml-tag ](https://www.meta-tech.academy/img/pluie-yaml-tag-directives-yaml-node.png?tmp=2 )
2018-08-11 00:28:19 +00:00
2018-08-18 21:01:07 +00:00
### Builder
2018-08-18 21:22:55 +00:00
**pluie-yaml** provide a Yaml.Builder which has automatic mechanisms to build Yaml.Object instances (and derived classes)
and set basics types properties, enum properties and based Yaml.Object properties from Yaml.node.
2018-08-18 21:01:07 +00:00
2018-08-18 21:22:55 +00:00
Other types like struct or native GLib.Object (Gee.ArrayList for example) properties need some stuff in order to be populated appropriately
2018-08-18 21:01:07 +00:00
We cannot do introspection on Structure's properties, so you need to implement a method which will do the job.
2018-08-18 21:22:55 +00:00
First at all, in the static construct of your class, you need to register (properties) types that need some glue for instanciation.
2018-08-18 21:01:07 +00:00
```vala
2018-08-20 01:44:36 +00:00
public class Yaml.Example : Yaml.Object
2018-08-18 21:01:07 +00:00
{
static construct
{
2018-08-24 16:43:19 +00:00
Yaml.Register.add_type (
2018-08-20 01:38:31 +00:00
typeof (Yaml.Example), // owned type
typeof (Yaml.ExampleStruct), // property type
typeof (Gee.ArrayList) // property type
);
2018-08-18 21:01:07 +00:00
}
...
```
2018-08-20 01:38:31 +00:00
Secondly you must override the `public void populate_from_node (Glib.Type, Yaml.Node node)` Yaml.Object original method.
`populate_from_node` is automatically called by the Yaml.Builder if the type property is prealably registered.
2018-08-18 21:01:07 +00:00
Example of implementation from `src/vala/Pluie/Yaml.Example.vala` :
2018-08-18 21:22:55 +00:00
```vala
2018-08-19 21:15:24 +00:00
public override void populate_from_node(GLib.Type type, Yaml.Node node)
2018-08-18 21:01:07 +00:00
{
2018-08-18 21:22:55 +00:00
if (type == typeof (Yaml.ExampleStruct)) {
this.type_struct = ExampleStruct.from_yaml_node (node);
}
else if (type == typeof (Gee.ArrayList)) {
this.type_gee_al = new Gee.ArrayList< string > ();
if (!node.empty ()) {
foreach (var child in node) {
this.type_gee_al.add(child.data);
2018-08-18 21:01:07 +00:00
}
2018-08-18 21:22:55 +00:00
}
2018-08-18 21:01:07 +00:00
}
}
```
2018-08-18 21:54:18 +00:00
Once your class has this glue, you can deal with complex object and populate them
directly from yaml files.
2018-08-18 21:01:07 +00:00
for more details see :
* `src/vala/Pluie/Yaml.Example.vala`
* `src/vala/Pluie/Yaml.ExampleChild.vala`
* `src/vala/Pluie/Yaml.ExampleStruct.vala`
* `samples/yaml-tag.vala`
2018-08-11 00:28:19 +00:00
code from samples/yaml-tag.vala :
2018-08-18 21:54:18 +00:00
![pluie-yaml-tag ](https://www.meta-tech.academy/img/pluie-yaml-sample-tag-code.png )
2018-08-11 00:28:19 +00:00
output from samples/yaml-tag.vala :
2018-08-18 21:54:18 +00:00
![pluie-yaml-tag ](https://www.meta-tech.academy/img/pluie-yaml-sample-tag-output.png?tmp=53 )
2018-08-11 00:28:19 +00:00
2018-08-20 01:38:31 +00:00
### Build Yaml.Node from Yaml.Object
reverse build mechanism is also possible but have the same limitation.
2018-08-20 01:44:36 +00:00
```vala
var config = new Yaml.Config (path, true);
var root = config.root_node ();
root.display_childs ();
of.action ("Yaml.Builder.from_node", root.first ().name);
var obj = (Yaml.Example) Yaml.Builder.from_node (root.first ());
obj.type_object.method_a ();
of.action ("Yaml.Builder.to_node", obj.get_type ().name ());
var n = Yaml.Builder.to_node (obj);
if ((done = n !=null)) {
n.display_childs ();
}
```
you need to override the `public Yaml.Node? populate_to_node(GLib.Type type, string name)` Yaml.Object original method
2018-08-20 01:38:31 +00:00
`populate_to_node` is also automatically called by the Yaml.Builder if the type property is prealably registered.
Example of implementation from `src/vala/Pluie/Yaml.Example.vala` :
```vala
public override Yaml.Node? populate_to_node(GLib.Type type, string name)
{
Yaml.Node? node = base.populate_to_node (type, name);
// non Yaml.Object type & registered type
if (node == null) {
if (type == typeof (Yaml.ExampleStruct)) {
2018-08-24 16:43:19 +00:00
node = this.type_struct.to_yaml_node (name);
2018-08-20 01:38:31 +00:00
}
else if (type == typeof (Gee.ArrayList)) {
node = new Yaml.Sequence (null, name);
foreach (var data in this.type_gee_al) {
new Yaml.Scalar (node, data);
}
}
}
return node;
}
```
2018-08-24 16:43:19 +00:00
### Serialize/Deserialize
2018-08-11 00:28:19 +00:00
-------------------
2018-08-01 13:10:12 +00:00
### more samples
see samples files in ./samples directory
2018-08-01 15:15:45 +00:00
2018-08-02 21:44:36 +00:00
-------------------
2018-08-01 15:15:45 +00:00
### todo
2018-08-02 21:44:36 +00:00
* ~~imports clause~~
2018-08-05 13:18:25 +00:00
* ~~fix nodes traversing~~
* ~~rewrite nodes classes~~
2018-08-06 14:57:20 +00:00
* ~~put doc online~~
2018-08-07 22:56:38 +00:00
* ~~add docker image~~
2018-08-20 01:44:36 +00:00
* ~~transform Yaml.Node nodes to Yaml.Object objects~~
* ~~transform Yaml.Object objects to Yaml.Node nodes~~
2018-08-24 16:43:19 +00:00
* ~~dumper~~
* ~~serialize/deserialize~~
2018-08-11 00:28:19 +00:00
* manage tag directives & tag (partially done)
2018-08-06 14:57:20 +00:00
* improve doc
2018-08-24 16:43:19 +00:00