# Processing YAML in Lua

You may need to deal with YAML data in your Lua code.

## root/usr/libexec/rpcd/luci.example
These are the changes you would need in the `usr/libexec/rpcd/luci.example` file.

First, declare that you want YAML libraries:

```lua
-- If you need to process YAML, opkg install lyaml
local lyaml = require "lyaml"
```

Then, declare a function to handle the YAML data, and a helper to read the file

```lua
local function readfile(path)
    local s = fs.readfile(path)
    return s and (s:gsub("^%s+", ""):gsub("%s+$", ""))
end

local function reading_from_yaml()
    -- Use the locally declared readfile() function to read in the
    -- sample YAML file that ships with this package.
    local example_config = readfile("/etc/luci.example.yaml")

    -- Map that string to a Lua table via lyaml's load() method
    local example_table = lyaml.load(example_config)

    -- Convert the table to JSON
    local example_json = jsonc.stringify(example_table)

    -- Pass the JSON back
    return example_json
end
```

Declare the method in the `methods` table

```lua
    -- Converts the AGH YAML configuration into JSON for consumption by
    -- the LuCI app.
    get_yaml_file_sample = {
        -- A special key of 'call' points to a function definition for execution.
        call = function()

            local r = {}
            r.result = reading_from_yaml()
            -- The 'call' handler will refer to '.code', but also defaults if not found.
            r.code = 0
            -- Return the table object; the call handler will access the attributes
            -- of the table.
            return r
        end
    },
```

## htdocs/luci-static/resources/view/example/rpc.js

These are the changes you need in the `rpc.js` file.

Declare the RPC call

```js
const load_sample_yaml = rpc.declare({
    object: 'luci.example',
    method: 'get_yaml_file_sample'
});
```

Add this declaration to the `view.extend()` call

```js
    render_sample_yaml: function(sample) {
        console.log('render_sample_yaml()');
        console.log(sample);

        if (sample.error) {
            return this.generic_failure(sample.error)
        }
        // Basically, a fully static table declaration.
        var table = E('table', { 'class': 'table', 'id': 'sample-yaml' }, [
            E('tr', {}, [
                E('td', { 'class': 'td left', 'width': '33%' }, _("Top Level Int")),
                E('td', { 'class': 'td left' }, sample.top_level_int),
            ]),
            E('tr', {}, [
                E('td', { 'class': 'td left', 'width': '33%' }, _("Top Level String")),
                E('td', { 'class': 'td left' }, sample.top_level_string),
            ])
        ]);
        return table;
    },
```

Add a call to the `load` function in `view.extend()`

```js
    load: function () {
        return Promise.all([
            load_sample_yaml(),
            load_sample1()
        ]);
    },
```

Add this code to the `render` function in `view.extend()`

```js
                E('div', { 'class': 'cbi-section', 'id': 'cbi-sample-yaml' }, [
                    E('div', { 'class': 'left' }, [
                        E('h3', _('Sample YAML via RPC')),
                        E('div', {}), _("YAML transformed to JSON, table built explicitly"),
                        this.render_sample_yaml(sample_yaml),
                    ]),
                ]),
```

## root/usr/share/rpcd/acl.d/luci-app-example.json

Allow access to the new RPC API

```json
    "read": {
      "ubus": {
        "luci.example": [
          "get_yaml_file_sample",
          "get_sample1",
          "get_sample2"
        ]
      },
```

## root/etc/luci.example.yaml

Set up the sample YAML file, by placing it either in `root/etc` of the development tree, or directly
in `/etc` on the target machine and call it `luci.example.yaml` to match up to the `reading_from_yaml`
function's expectations.

```yaml
top_level_string: example
top_level_int: 8080
top_level:
  list_elements:
  - foo
  - bar
```

That's it. Don't forget to also update the `LUCI_DEPENDS` segment of the `Makefile` to include
`+lyaml` so that the packaging system knows your code needs the YAML parsing package.
