doc(family):
This commit is contained in:
parent
2d2adf8972
commit
4756e84d2e
5 changed files with 218 additions and 155 deletions
291
docs/family.rst
291
docs/family.rst
|
|
@ -9,43 +9,60 @@ Synopsis
|
||||||
family
|
family
|
||||||
subfamily
|
subfamily
|
||||||
|
|
||||||
A family (or a subnfamiliy) of variables is simply a collection of variables that refer to
|
A family (or a subfamily) is simply a collection of variables that refer to
|
||||||
the same business model category. It's just a variables container.
|
the same business model category. It's just a variables container.
|
||||||
Think of it as a container as well as a namespace.
|
Think of it as a container as well as a namespace.
|
||||||
|
|
||||||
.. attention:: A family without a subfamily or subvariable will be automatically deleted.
|
.. attention:: A family without a subfamily or subvariable will be automatically deleted.
|
||||||
|
|
||||||
Naming conventions
|
Naming
|
||||||
------------------------
|
---------
|
||||||
|
|
||||||
It is with its name that we will be able to interact with the family.
|
It is with its name that we will be able to interact with the family.
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
Have a look at the :ref:`convention on variable names`.
|
Have a look at the :ref:`family naming convention <namingconvention>`
|
||||||
|
|
||||||
Shorthand declaration
|
Shorthand declaration
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
Shorthand declaration is a way to declare a family in a single line. But you can only define family name and description.
|
Shorthand declaration is a way to declare a family in a single line.
|
||||||
|
|
||||||
To create a family, just add a key with it's name and variables as values. Attention, do not declare any other attributs.
|
To create a family, just add a key with it's name and variables as values.
|
||||||
|
|
||||||
By default, the description of the variable is the family name.
|
Here is a simple example:
|
||||||
If you add comment in same line of name, this comment is use as description:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
version: '1.1'
|
version: 1.1
|
||||||
my_family: # This is a great family
|
my_family:
|
||||||
|
|
||||||
variable:
|
variable:
|
||||||
|
...
|
||||||
|
|
||||||
|
By default, the description of the variable is the family name.
|
||||||
|
It's a best practice to description a family. Just add comment in same line of name, this comment is use as description.
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
version: 1.1
|
||||||
|
my_family: # This is a great family
|
||||||
|
|
||||||
|
variable:
|
||||||
|
...
|
||||||
|
|
||||||
|
But in shorthand notation, you can only define family name and description.
|
||||||
|
|
||||||
|
.. attention:: Any other parameters will be considered as a variable. Do not use shorthand in this case.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
.. todo:: faire une page sur la "convention on variable names"
|
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
:widths: 15 45
|
:widths: 15 45
|
||||||
:header-rows: 1
|
:header-rows: 1
|
||||||
|
|
@ -53,18 +70,6 @@ Parameters
|
||||||
* - Parameter
|
* - Parameter
|
||||||
- Comments
|
- Comments
|
||||||
|
|
||||||
* - type, _type
|
|
||||||
|
|
||||||
`string`
|
|
||||||
|
|
||||||
- possile values:
|
|
||||||
|
|
||||||
- `family` (**default value**)
|
|
||||||
- `leadership`
|
|
||||||
- `dynamic`
|
|
||||||
|
|
||||||
.. note:: If a subfamily or a subvariable already has the name `"type"`, it is possible to use the `"_type"` attribute.
|
|
||||||
|
|
||||||
* - description, _description
|
* - description, _description
|
||||||
|
|
||||||
`string`
|
`string`
|
||||||
|
|
@ -72,14 +77,12 @@ Parameters
|
||||||
|
|
||||||
User information to understand the usefulness of the family.
|
User information to understand the usefulness of the family.
|
||||||
|
|
||||||
..note:: If a subfamily or subvariable already has the name "description" it is possible to use the "_description" attribute.
|
|
||||||
|
|
||||||
* - help, _help
|
* - help, _help
|
||||||
|
|
||||||
`string`
|
`string`
|
||||||
- Additional help associated with the family.
|
- Additional help associated with the family.
|
||||||
|
|
||||||
.. note:: If a subfamily or a subvariable already has the name "help" it is possible to use the "_help" attribute.
|
.. seealso:: tutorial with a real world sample :ref:`help parameter <tutorial/examples>` (the tutorial focuses on variable, but the principle is the same for a family)
|
||||||
|
|
||||||
* - mode, _mode
|
* - mode, _mode
|
||||||
|
|
||||||
|
|
@ -90,22 +93,34 @@ Parameters
|
||||||
|
|
||||||
This mode also allows you to define the default mode for variables or families included in this family.
|
This mode also allows you to define the default mode for variables or families included in this family.
|
||||||
|
|
||||||
.. note:: If a subfamily or a subvariable already has the name "mode" it is possible to add the "_mode" attribute.
|
.. seealso:: tutorial with a real world sample :ref:`mode parameter <tutorial/mode>` (the tutorial focuses on variable, but the principle is the same for a family)
|
||||||
|
|
||||||
|
* - type, _type
|
||||||
|
|
||||||
|
`string`
|
||||||
|
|
||||||
|
- possible values:
|
||||||
|
|
||||||
|
- `family` (**default value**)
|
||||||
|
- `dynamic`
|
||||||
|
- `leadership`
|
||||||
|
|
||||||
* - hidden, _hidden
|
* - hidden, _hidden
|
||||||
|
|
||||||
`string`
|
`boolean` or `calculation`
|
||||||
- Invisible family.
|
- Invisible family.
|
||||||
|
|
||||||
Allows you to hide a family as well as the variables or families included in this family.
|
Allows you to hide a family as well as the variables or families included in this family.
|
||||||
|
|
||||||
This means that the family will no longer be visible in `read-write` mode, but only for calculations or in `read-only` mode.
|
This means that the family will no longer be visible in `read-write` mode, but only for calculations or in `read-only` mode.
|
||||||
|
|
||||||
.. note:: If a subfamily or a subvariable already has the name "hidden" it is possible to add the "_hidden" attribute.
|
The default value is `false`.
|
||||||
|
|
||||||
|
.. seealso:: tutorial with a real world sample :ref:`hidden parameter <tutorial/properties>`
|
||||||
|
|
||||||
* - disabled, _disabled
|
* - disabled, _disabled
|
||||||
|
|
||||||
`string`
|
`boolean` or `calculation`
|
||||||
|
|
||||||
- Disabled family.
|
- Disabled family.
|
||||||
|
|
||||||
|
|
@ -113,159 +128,137 @@ Parameters
|
||||||
|
|
||||||
This means that the family will no longer be visible to the user but also to a :term:`calculation`.
|
This means that the family will no longer be visible to the user but also to a :term:`calculation`.
|
||||||
|
|
||||||
.. note:: If a subfamily or a subvariable already has the name "disabled" it is possible to use the "_disabled" attribute.
|
The default value is `false`.
|
||||||
|
|
||||||
Dynamically created family
|
.. seealso:: tutorial with a real world sample :ref:`disabled parameter <tutorial/properties>`
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
To create a family dynamically, you must create a fictitious family linked to a calculation.
|
* - dynamic, _dynamic
|
||||||
The family name will actually be the prefix of the new name. Alternativly you can specify the suffix in the name, ie `my_{{ suffix }}_name`.
|
|
||||||
The suffix will come from the calculation.
|
|
||||||
|
|
||||||
Obviously if the result of calculation were to evolve, new dynamic families will appear or disappear.
|
`calculation` or a list of `calculation` or `string`
|
||||||
|
|
||||||
Leader or follower variable
|
- Dynamic identifiers.
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
A leader family has a typical attribute of “leadership”. The type is required.
|
.. important:: this parameter is only available for dynamically built family
|
||||||
|
|
||||||
A leader family
|
.. note::
|
||||||
----------------
|
|
||||||
|
|
||||||
The leader and follower variables are placed in a leader family.
|
If a subfamily or a subvariable already has the name of a parameter it is possible to use the "_<parameter>" name.
|
||||||
|
You can have a look at the tutorial with a real world sample :ref:`of parameter with "_" <tutorial/underscore_parameter>`.
|
||||||
|
|
||||||
A leader family cannot contain other families.
|
A family
|
||||||
|
---------
|
||||||
|
|
||||||
The default mode of the leader family is the mode of the leader variable.
|
Here is a simple example:
|
||||||
|
|
||||||
Leader variable
|
|
||||||
----------------
|
|
||||||
|
|
||||||
A leader variable is a variable that will guide the length of other variables (called follower variables).
|
|
||||||
|
|
||||||
A leader variable is a :doc:`variable` that must have the `multiple` type.
|
|
||||||
|
|
||||||
A leader variable may be mandatory.
|
|
||||||
|
|
||||||
The default mode corresponds to the smallest mode defined for the follower variables.
|
|
||||||
|
|
||||||
Follower variable
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
A follower variable is a variable whose length is not determined by itself, but is identical to that of the leader variable on which it depends.
|
|
||||||
|
|
||||||
A follower variable is a variable placed just behind a leader variable or another follower variable.
|
|
||||||
|
|
||||||
The order in which the tracking variables are defined is important.
|
|
||||||
|
|
||||||
This variable can be of multiple type. In this case, for a determined index of the leading variable, it is possible to put several values to the same variable.
|
|
||||||
|
|
||||||
A follower variable may be required. This means that when a leader variable is entered, the follower variable must also be a value at the index considered. If no value is defined for the leader variable, no value is specified for the follower variable.
|
|
||||||
|
|
||||||
The default mode of a follower variable corresponds to the mode of the leader variable.
|
|
||||||
|
|
||||||
If a leader variable is hidden or disabled, the follower variables will be hidden or disabled as well.
|
|
||||||
|
|
||||||
Examples
|
|
||||||
----------
|
|
||||||
|
|
||||||
Simple family:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
version: '1.1'
|
version: 1.1
|
||||||
my_family:
|
my_family:
|
||||||
type: family
|
|
||||||
description: This is a great family
|
description: This is a great family
|
||||||
help: This is the help of a great family
|
help: This family is great because we have great variables inside
|
||||||
mode: expert
|
|
||||||
|
|
||||||
Dynamically created family
|
variable:
|
||||||
----------------------------
|
...
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
You can have a look at the tutorial with a real world sample:
|
||||||
|
|
||||||
|
- :ref:`family <tutorial/family>`
|
||||||
|
- :ref:`help parameter <tutorial/examples>` (the tutorial focuses on variable, but the principle is the same for a family)
|
||||||
|
|
||||||
|
A dynamically built family
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
To create a family dynamically, you must create a fictitious family linked to a list of uniq identifiers.
|
||||||
|
This list could be hard coded or resulting from a calculation
|
||||||
|
|
||||||
|
In this case if the result of calculation were to evolve, new dynamic families will appear or disappear.
|
||||||
|
|
||||||
|
The name of this family is particular. You have to add `{{ identifier }}` string inside. It will be replace by each identifiers.
|
||||||
|
|
||||||
|
Here is an simple example:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
version: '1.1'
|
version: 1.1
|
||||||
varname:
|
|
||||||
multi: true
|
my_{{ identifier }}_family:
|
||||||
default:
|
description: 'A family for {{ identifier }}'
|
||||||
- val1
|
|
||||||
- val2
|
|
||||||
my_dyn_family_:
|
|
||||||
type: dynamic
|
|
||||||
dynamic:
|
dynamic:
|
||||||
type: variable
|
- one thing
|
||||||
variable: rougail.varname
|
- another
|
||||||
description: 'Describe'
|
|
||||||
my_dyn_var:
|
variable:
|
||||||
type: string
|
description: 'A variable for {{ identifier }}'
|
||||||
description: 'Variable description'
|
...
|
||||||
|
|
||||||
This will dynamically create two families:
|
This will dynamically create two families:
|
||||||
|
|
||||||
- "rougail.my_dyn_family_val1"
|
- "my_one_thing_family"
|
||||||
- "rougail.my_dyn_family_val2"
|
- "my_another_family"
|
||||||
|
|
||||||
In the dynamic family "rougail.my_dyn_family_val1" we will find a variable "my_dyn_var".
|
.. seealso::
|
||||||
|
|
||||||
Here is a second example:
|
You can have a look at the tutorial with a real world sample :ref:`dynamically built family <tutorial/dynfam>`
|
||||||
|
|
||||||
|
Similar object sequence
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
A family with `type` set to `leadership` is a sequence of similar object.
|
||||||
|
|
||||||
|
Let's start the explanation with a concrete example:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
version: '1.1'
|
version: 1.1
|
||||||
varname:
|
|
||||||
multi: true
|
|
||||||
default:
|
|
||||||
- val1
|
|
||||||
- val2
|
|
||||||
my_dyn_{{ suffix }}_family:
|
|
||||||
type: dynamic
|
|
||||||
dynamic:
|
|
||||||
type: variable
|
|
||||||
variable: rougail.varname
|
|
||||||
description: 'Describe'
|
|
||||||
my_dyn_var:
|
|
||||||
type: string
|
|
||||||
description: 'Variable description'
|
|
||||||
|
|
||||||
This will dynamically create two families:
|
accounts:
|
||||||
|
description: All accounts
|
||||||
- "rougail.my_dyn_val1_family"
|
|
||||||
- "rougail.my_dyn_val2_family"
|
|
||||||
|
|
||||||
In the dynamic family "rougail.my_dyn_val1_family" we will find a variable "my_dyn_var".
|
|
||||||
|
|
||||||
Leader or follower variable
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
Definition of leader and follower variables
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Here is an example of defining a leading variable and two following variables:
|
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
---
|
|
||||||
version: '1.1'
|
|
||||||
family:
|
|
||||||
type: leadership
|
type: leadership
|
||||||
leader:
|
|
||||||
multi: true
|
|
||||||
follower1:
|
|
||||||
follower2:
|
|
||||||
multi: true
|
|
||||||
|
|
||||||
Adding a new follower variable
|
login:
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
description: Account login
|
||||||
|
type: unix_user
|
||||||
|
|
||||||
To add a new follower variable, in a new dictionary, simply define one or more new variables in the leader family:
|
secret:
|
||||||
|
description: Account secret
|
||||||
|
type: secret
|
||||||
|
...
|
||||||
|
|
||||||
|
What is expected, it's something like:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
---
|
---
|
||||||
version: '1.1'
|
accounts:
|
||||||
family:
|
- login: foo
|
||||||
follower3:
|
secret: 0hM%G0dW4a7ASecr3t
|
||||||
|
- login: bar
|
||||||
|
secret: NotGoodSecret
|
||||||
|
|
||||||
|
It's what we call a sequence of similar object.
|
||||||
|
|
||||||
|
.. attention:: A sequence cannot contain other families.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
You can have a look at the tutorial with a real world sample :ref:`similar object sequence <tutorial/sequence>`
|
||||||
|
|
||||||
|
A custom type family
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
In short, a custom type is nothing more than a kind of a template for a family.
|
||||||
|
Define a custom type family is much like defining families.
|
||||||
|
|
||||||
|
This custom type family can be used as many times as desired and customized as you wish.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
You can have a look at the tutorial with a real world sample :ref:`family custom type <tutorial/family>`
|
||||||
|
|
|
||||||
|
|
@ -250,6 +250,8 @@ command-line utility when you type the command with the `--help` or `-h` option.
|
||||||
|
|
||||||
A `help` helps to clarify any ambiguity about the variable’s purpose. It can be long and detailed.
|
A `help` helps to clarify any ambiguity about the variable’s purpose. It can be long and detailed.
|
||||||
|
|
||||||
|
We can set `help` attribute to a variable or to a family.
|
||||||
|
|
||||||
.. keypoints:: Key points
|
.. keypoints:: Key points
|
||||||
|
|
||||||
- We have seen how to give examples, simply with the `examples` parameter
|
- We have seen how to give examples, simply with the `examples` parameter
|
||||||
|
|
|
||||||
|
|
@ -270,3 +270,7 @@ Let's recap about the user data. We can see in this Rougail CLI output that:
|
||||||
|
|
||||||
- we have a :term:`family` named `manual` and a sub family named `http_proxy`
|
- we have a :term:`family` named `manual` and a sub family named `http_proxy`
|
||||||
- And we have now two variables: :confval:`proxy_mode` and :confval:`address`.
|
- And we have now two variables: :confval:`proxy_mode` and :confval:`address`.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
Full documentation about :ref:`family <family>`
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ What do we want to be implemented
|
||||||
|
|
||||||
You need to think about:
|
You need to think about:
|
||||||
|
|
||||||
- choose a file name that respect the :ref:`file naming and organizing convention <namingconvention>`
|
- choose a file name that respect the :ref:`file naming and organizing convention <filenamingconvention>`
|
||||||
- define an appropriate variable name, have a look at our :ref:`file naming convention <filenamingconvention>`
|
- define an appropriate variable name, have a look at our :ref:`variable naming convention <namingconvention>`
|
||||||
- the Firefox description is in negative mode, which is not a good practice for us, we rewrite it in positive mode
|
- the Firefox description is in negative mode, which is not a good practice for us, we rewrite it in positive mode
|
||||||
- the variable is a boolean with the default value `true` (the opposite of unchecked option)
|
- the variable is a boolean with the default value `true` (the opposite of unchecked option)
|
||||||
- the variable is available for all proxy mode choice by user, so disable it only when the `proxy mode` is "No proxy".
|
- the variable is available for all proxy mode choice by user, so disable it only when the `proxy mode` is "No proxy".
|
||||||
|
|
@ -98,8 +98,8 @@ What do we want to be implemented
|
||||||
|
|
||||||
You need to think about:
|
You need to think about:
|
||||||
|
|
||||||
- the choice of a file name that respect the :ref:`file naming and organizing convention <namingconvention>`
|
- the choice of a file name that respect the :ref:`file naming and organizing convention <filenamingconvention>`
|
||||||
- in order to define an appropriate variable name,
|
- define an appropriate variable name, have a look at our :ref:`variable naming convention <namingconvention>`
|
||||||
- the `description` parameter will be the Firefox description,
|
- the `description` parameter will be the Firefox description,
|
||||||
- the variable is a boolean with the default value `false` (unchecked option),
|
- the variable is a boolean with the default value `false` (unchecked option),
|
||||||
- the variable is only available with the `"Manual proxy configuration"` proxy mode and when the proxy socks version is not v4.
|
- the variable is only available with the `"Manual proxy configuration"` proxy mode and when the proxy socks version is not v4.
|
||||||
|
|
|
||||||
64
docs/tutorial/underscore_parameter.rst
Normal file
64
docs/tutorial/underscore_parameter.rst
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
A variable name that conflict with a defined family's attribute
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
.. objectives:: Objectives
|
||||||
|
|
||||||
|
Have a good variable name is really important.
|
||||||
|
|
||||||
|
We will learn how to create a variable name that conflict with a defineed attribute name.
|
||||||
|
|
||||||
|
.. 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 tag :tutorial:`v1.1_210 <src/tag/v1.1_210/README.md>`
|
||||||
|
in the repository.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
|
||||||
|
git switch --detach v1.1_210
|
||||||
|
|
||||||
|
.. type-along:: Let's recap how far we've come
|
||||||
|
|
||||||
|
We have this leadership family in its structure definition file:
|
||||||
|
|
||||||
|
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_202/foxyproxy/00-foxyproxy.yml
|
||||||
|
:linenos:
|
||||||
|
:language: yaml
|
||||||
|
:caption: The `proxies` family with `leadership` type in the :file:`foxyproxy/00-foxyproxy.yml` structure file
|
||||||
|
|
||||||
|
The variable "type" that conflit with the family attribute "type"
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Choice a good variable name is important. It's with this name that user will interact with here value.
|
||||||
|
|
||||||
|
The user has to define the type of the new proxy. So instinctively the name of the variable will be `type`.
|
||||||
|
|
||||||
|
But in the current family we have already the attribute `type` with the `leadership` value.
|
||||||
|
YAML do not permit to have two key with the same name.
|
||||||
|
Maybe we could choice an other variable name like `proxy_type` but the full path will be `proxies.proxy_type`.
|
||||||
|
Repeating the word proxy is not appropriate.
|
||||||
|
|
||||||
|
So the best way it to rename the `type` attribute to `_type`
|
||||||
|
|
||||||
|
Let's create a family named `manual` which obviously corresponds to the proxy's manual configuration choice.
|
||||||
|
|
||||||
|
.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_210/foxyproxy/00-foxyproxy.yml
|
||||||
|
:language: yaml
|
||||||
|
:caption: The `proxies` family with `leadership` type and a variable with the name `type` in the :file:`foxyproxy/00-foxyproxy.yml` structure file
|
||||||
|
|
||||||
|
Technically it's possible to put `_` in front of each attribute name, but it's still less readable.
|
||||||
|
|
||||||
|
.. keypoints:: Let's review the key points
|
||||||
|
|
||||||
|
**Keywords**
|
||||||
|
|
||||||
|
- attributes could start by "_" character or not
|
||||||
|
- do not add `_` in front of all attributes name
|
||||||
Loading…
Reference in a new issue