.. _reflection:

Reflection capabilities in MuranoPL.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Reflection provides objects that describes MuranoPL classes and packages.

The first important function is ``typeinfo`` . Usage:

.. code-block:: yaml

    $typeInfo: typeinfo($someObject)



Now ``$typeInfo`` variable contains instance of type of ``$someObject`` (``MuranoClass`` instance).

MuranoPL provide following abilities to reflection:


.. _types_reflection:

Types
-----

.. list-table::
   :header-rows: 1
   :widths: 20 80
   :stub-columns: 0
   :class: borderless

   * - Property
     - Description
   * - ``name``
     - name of MuranoPL class
   * - ``version``
     - version (`SemVer`_) of MuranoPL class.
   * - ``ancestors``
     - list of class ancestors
   * - ``properties``
     - list of class properties. See :ref:`properties_reflection`
   * - ``package``
     - package information. See :ref:`package_reflection`
   * - ``methods``
     - list of methods. See :ref:`methods_reflection`
   * - ``type``
     - reference to type, which can be used as argument in engine functions



*Example*

.. code-block:: yaml

   - $typeInfo: typeinfo($)
   ...
   # log name, version and package name of this class
   - $log.info("This is "{class_name}/{version} from {package}",
        class_name => $typeInfo.name,
        version => str($typeInfo.version),
        package => $typeInfo.package.name))
   - $log.info("Ancestors:")
   - For: ancestor
     In: $typeInfo.ancestors
     Do:
       #log all ancestors names
       - $log.info("{ancestor_name}", ancestor_name => $ancestor.name)
   # log full class version
   - $log.info("{version}", version => str($typeInfo.version))
   # create object with same class
   - $newObject = new($typeInfo.type)


.. _properties_reflection:

Properties
----------


Property introspection
++++++++++++++++++++++

.. list-table::
   :header-rows: 1
   :widths: 20 80
   :stub-columns: 0
   :class: borderless

   * - Property
     - Description
   * - ``name``
     - name of property
   * - ``hasDefault``
     - boolean value. `True`, if property has default value, `False` otherwise
   * - ``usage``
     - `Usage` property's field. See :ref:`property_usage` for details
   * - ``declaringType``
     - type - owner of declared property


Property access
+++++++++++++++

.. list-table::
   :header-rows: 1
   :widths: 20 80
   :stub-columns: 0
   :class: borderless

   * - Methods
     - Description
   * - ``$property.setValue($target, $value)``
     - set value of ``$property`` for object ``$target`` to ``$value``
   * - ``$property.getValue($target)``
     - get value of ``$property`` for object ``$target``

*Example*

.. code-block:: yaml

    - $typeInfo: typeinfo($)
    ...
    # select first property
    - $selectedPropety: $typeInfo.properties.first()
    # log property name
    - $log.info("Hi, my name is {p_name}, p_name => $selectedProperty.name)
    # set new property value
    - $selectedProperty.setValue($, "new_value")
    # log new property value using reflection
    - $log.info("My new value is {value}", value => $selectedProperty.getValue($))
    # also, if property static, $target can be null
    - $log.info("Static property value is {value},
        value => $staticProperty.getValue(null))



.. _package_reflection:

Packages
--------

.. list-table::
   :header-rows: 1
   :widths: 20 80
   :stub-columns: 0
   :class: borderless

   * - Property
     - Description
   * - ``types``
     - list of types, declared in package
   * - ``name``
     - package name
   * - ``version``
     - package version


*Example*

.. code-block:: yaml

    - $typeInfo: typeinfo($)
    ...
    - $packageRef: $typeInfo.package
    - $log.info("This is package {p_name}/{p_version}",
        p_name => $packageRef.name,
        p_version => str($packageRef.version))
    - $log.info("Types in package:")
    - For: type_
      In: $packageRef.types
      Do:
        - $log.info("{typename}", typename => type_.name)


.. _methods_reflection:

Methods
-------

Methods properties
++++++++++++++++++

.. list-table::
   :header-rows: 1
   :widths: 20 80
   :stub-columns: 0
   :class: borderless

   * - Property
     - Description
   * - ``name``
     - method's name
   * - ``declaringType``
     - type - owner of declared method
   * - ``arguments``
     - list of method's arguments. See :ref:`arguments_reflection`


Method invoking
+++++++++++++++

.. list-table::
   :header-rows: 1
   :widths: 20 80
   :stub-columns: 0
   :class: borderless

   * - Methods
     - Description
   * - ``$method.invoke($target, $arg1, ... $argN, kwarg1 => value1, ..., kwargN => valueN)``
     - call ``$target``'s method $method with ``$arg1``, ..., ``$argN`` positional arguments and ``kwarg1``, .... ``kwargN`` named arguments

*Example*

.. code-block:: yaml

    - $typeInfo: typeinfo($)
    ...
    # select single method by name
    - $selectedMethod: $typeInfo.methods.where($.name = sampleMethodName).single()
    # log method name
    - $log.info("Method name: {m_name}", m_name => $selectedMethod.name)
    # log method arguments names
    - For: argument
      In: $selectedMethod.arguments
      Do:
         - $log.info("{name}", name => $argument.name)
    # call method with positional argument 'bar' and named `baz` == 'baz'
    - $selectedMethod.invoke($, 'bar', baz => baz)


.. _arguments_reflection:

Method arguments
----------------

.. list-table::
   :header-rows: 1
   :widths: 20 80
   :stub-columns: 0
   :class: borderless

   * - Property
     - Description
   * - ``name``
     - argument's name
   * - ``hasDefault``
     - `True` if argument has default value, `False` otherwise
   * - ``declaringMethod``
     - method - owner of argument

.. code-block:: yaml

    - $firstArgument: $selectedMethod.arguments.first()
    # store argument's name
    - $argName = $firstArgument.name
    # store owner's name
    - $methodName = $firstArgument.declaringMethod.name
    - $log.info("Hi, my name is {a_name} ! My owner is {m_name}",
        a_name => $argName,
        m_name => $methodName)


.. Links:
.. _`SemVer`: http://semver.org


