.. _tutorial_nullable:

Nullable variable
==========================

.. objectives:: Objectives

   Now in this section we would like to make it possible that it is not necessary to specify a value
   for a variable.
   
   With Rougail, it is possible for a variable's settings to have no value (nothing, null, None), 
   that is, neither a default value nor a user assigned value.
   
.. prerequisites:: Prerequisites

    - We assume that Rougail's library is :ref:`installed <installation>` on your computer.

    - It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
      by checking out the corresponding tag of the `rougail-tutorials` git repository.
      Each tag corresponds to a stage of progress in the tutorial.
      Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.

    If you want to follow this tutorial with the help of the corresponding :tutorial:`rougail-tutorials git repository <src/branch/1.1>`,
    this workshop page corresponds to the tags :tutorial:`v1.1_090 <src/tag/v1.1_090/README.md>` to :tutorial:`v1.1_091 <src/tag/v1.1_091/README.md>`
    in the repository.

    ::

       git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
       git switch --detach v1.1_090


Variable with the value "null"
------------------------------------

.. note:: It is important to keep in mind that in Rougail a variable is :term:`mandatory` by default, 
         meaning that it must either have a :term:`default value` set or a :term:`user data` value assigned for example in a :term:`user data file`\ .
         This is Rougail's default behavior.

         Besides, note that the explicit keyword to express the setting "no value, nothing" in YAML is the `null` explicit keyword.

Here is how we are going to specify a "no value" (nothing, `null`) as a possible setting for the `address` variable in the `socks_proxy` family.

There are a few things to set in the variable. We need to:

- explicitely disable the default :term:`mandatory` behavior of the `address` variable (just by setting it to `false`),
- redefine the `address` variable inside the `socks_proxy` because this family uses the `proxy` type definition,
- finally removes the `address` default value as determined in the `proxy` type definition.

.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_090/firefox/20-manual.yml
   :language: yaml
   :caption: The :file:`firefox/20-manual.yml` structure file with the `mandatory` set to `false` and the `null` (nothing) setting

..
    %YAML 1.2
    ---
    version: 1.1

    manual:

      use_for_https: true  # Also use this proxy for HTTPS

      https_proxy:
        description: HTTPS Proxy
        type: proxy
        hidden:
          variable: _.use_for_https

        address:
          redefine: true
          description: HTTPS proxy address

        port:
          redefine: true
          description: HTTPS proxy port

      socks_proxy:
        description: SOCKS Proxy
        type: proxy

        address:
          redefine: true
          description: SOCKS proxy address
          default: null
          mandatory: false

        port:
          redefine: true
          description: SOCKS proxy port
          default: 1080

        version:
          description: SOCKS host version used by proxy
          choices:
            - v4
            - v5
          default: v5
    ...


Some more, maybe usefull, explanations about our `address` variable in the `socks_proxy` family: 

- Allowing the "no value, nothing" behavior is easy, we just add the `mandatory: false` attribute, 
- we explicitely need to set the `redefine: true` attribute because in the type `proxy` type setting
  we didn't set the `mandatory` attribute to false, this is then a type redefinition,
- finally we can set the `default: null` that means that we can set no value to our address variable.

Note too that is is necessary to redefine (to set a `redefine` attribute) as soon as you 
modify the type definition. Here we have set a default value to our `socks_proxy`'s `port` variable.
We need then to redefine not only because of the `description` attribute but because of the default value too.


Variables disabled when condition is null
--------------------------------------------

.. type-along:: For those who follow the tutorial with the help of the git repository

    Now you need to checkout the :tutorial:`v1.1_091 <src/tag/v1.1_091/README.md>` version::

          git switch --detach v1.1_091

.. questions:: Question

   But actually, why did we want a variable to be non-mandatory?

Well, what we need is to be able to :term:`disable <disabled>` either the `port` and the `version` in case of the `address` has no value set:
   
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_091/firefox/20-manual.yml
   :language: yaml
   :caption: The :file:`firefox/20-manual.yml` structure file with the `disabled` set in case of the `address` has no value set

..
    %YAML 1.2
    ---
    version: 1.1

    manual:

      use_for_https: true  # Also use this proxy for HTTPS

      https_proxy:
        description: HTTPS Proxy
        type: proxy
        hidden:
          variable: _.use_for_https

        address:
          redefine: true
          description: HTTPS proxy address

        port:
          redefine: true
          description: HTTPS proxy port

      socks_proxy:
        description: SOCKS Proxy
        type: proxy

        address:
          redefine: true
          description: SOCKS proxy address
          default: null
          mandatory: false

        port:
          redefine: true
          description: SOCKS proxy port
          default: 1080
          disabled:
            variable: _.address
            when: null

        version:
          description: SOCKS host version used by proxy
          choices:
            - v4
            - v5
          default: v5
          disabled:
            variable: _.address
            when: null
    ...

For the `disabled` property to trigger, the condition `when: null` must appear,
pointing to the `_.address` variable, that is the `socks_proxy.address` variable.


.. note:: The `_.` is a :term:`relative path` notation and means the current path (of the current family).

          In the python quasi algorithmic notation we could say that:  
          
          .. code-block:: python

              _.address == socks_proxy.address

          This is true only because in our use case `socks_proxy` is located on the root path.

.. keypoints:: Key points

   As one of the main objectives of Rougail is to determine if a variable has a value, 
   therefore the value of a variable is in principle *required*.
   We say that a value is :term:`mandatory` by default. 
   However, it is possible to change this default behavior with the `mandatory: false` parameter 
   explicitely declared in a variable. 
   In this section we learned how to define a variable as having no value; it's possible with Rougail.
   
   In this section we also continued using some type redefinition, which we learned in the previous section.
   And we have :term:`disabled` a variable depending this on 
   the presence or absence of a value. 
   
   
