= Metanorma LutaML plugin (metanorma-plugin-lutaml) image:https://github.com/metanorma/metanorma-plugin-lutaml/workflows/rake/badge.svg["Build Status", link="https://github.com/metanorma/metanorma-plugin-lutaml/actions?workflow=rake"] == Purpose LutaML is a data model accessor that supports various data model formats, including: * EXPRESS (`*.exp` files) * OMG UML in XMI format (`*.xmi` files) This plugin allows you to access LutaML models from within a Metanorma document. == Installation [source,console] ---- $ gem install metanorma-plugin-lutaml ---- == Usage with EXPRESS === General LutaML supports accessing EXPRESS models via the https://github.com/lutaml/expressir[Expressir] parser. === Usage of the `lutaml_express` EXPRESS macro Given an `example.exp` EXPRESS file with the content: [source,exp] ---- SCHEMA test_schema 'test'; (* Need select elements for measure_value *) REFERENCE FROM measure_schema (measure_value); TYPE my_type1 = EXTENSIBLE SELECT; END_TYPE; TYPE my_type2 = EXTENSIBLE ENUMERATION; END_TYPE; TYPE my_type3 = EXTENSIBLE ENUMERATION; END_TYPE; TYPE my_type4 = EXTENSIBLE ENUMERATION; END_TYPE; TYPE my_type5 = EXTENSIBLE ENUMERATION; END_TYPE; END_SCHEMA; ---- And the `lutaml_express` macro block: [source,adoc] ----- [lutaml_express,example.exp,my_context] ---- {% for schema in my_context.schemas %} == {{schema.id}} {% for entity in schema.entities %} === {{entity.id}} {% endfor %} {% endfor %} ---- ----- Where: * content within the block is called the "`template`"; * `{example.exp}` is the location of the EXPRESS schema file (`*.exp`) that contains data to be loaded. Location of the file is computed relative to the source directory that `[lutaml]` is used (e.g., if `[lutaml_express,example.exp,my_context]` is invoked in an `.adoc` file located at `/foo/bar/doc.adoc`, the data file is expected to be found at `/foo/bar/example.exp`); * `{my_context}` is the name where the EXPRESS Repository read from the `.exp` file can be accessed with. ** The `context` object is a serialized `Expressir::Model::Repository` object with all variable names available. See https://github.com/lutaml/expressir[Expressir] docs for reference. `{my_context}` has `schemas` method to access Expressir https://github.com/lutaml/expressir/blob/master/lib/expressir/model/schema.rb[schemas] Will produce this output: [source,adoc] ----- == test_schema === my_type1 === my_type2 === my_type3 === my_type4 === my_type5 ----- This macro also supports `.lutaml` files. Instead of using the direct path to the file one can use `lutaml-express-index` document attribute to supply directory with express files or YAML index file to parse as well as the cache file location. The syntax is as follows: [source,adoc] ----- :lutaml-express-index: my_custom_name; dir_or_index_path[; cache=cache_path] ----- Where: * `my_custom_name` - is name of the parsed EXPRESS files context for the later use with lutaml macro * `dir_or_index_path` - location of directory with EXPRESS files or path to the YAML index file to parse * `cache_path` - optional, location of the Expressir cache file to use Example of usage: [source,adoc] ----- = Document title Author :lutaml-express-index: my_custom_name; /path/to/express_files; cache=/path/to/cache_file.yaml [lutaml_express,my_custom_name,my_context] ---- {% for schema in my_context.schemas %} == {{schema.id}} {% endfor %} ---- ----- === Usage, `lutaml_diagram` macro This macro allows to quickly render lutaml file as diagram image. Given `example.lutaml` file with the content: [source,java] ---- diagram MyView { title "my diagram" enum AddressClassProfile { imlicistAttributeProfile: CharacterString [0..1] { definition this is multiline with `asciidoc` end definition } } class AttributeProfile { +addressClassProfile: CharacterString [0..1] imlicistAttributeProfile: CharacterString [0..1] { definition this is attribute definition } } } ---- And the `lutaml_diagram` macro: [source,adoc] ----- lutaml_diagram::example.lutaml[] ----- Will add diagram image to the document Also one can use `lutaml_diagram` block with embed lutaml code instead of block macro. Example: [source,java] ---- [lutaml_diagram] .... diagram MyView { title "my diagram" enum AddressClassProfile { imlicistAttributeProfile: CharacterString [0..1] { definition this is multiline with `ascidoc` end definition } } class AttributeProfile { +addressClassProfile: CharacterString [0..1] imlicistAttributeProfile: CharacterString [0..1] { definition this is attribute definition } } } .... ---- === Usage of `lutaml_uml_attributes_table` macro This macro allows to quickly render data model attributes/values tables. Given `example.lutaml` file with the content: [source,java] ---- diagram MyView { title "my diagram" enum AddressClassProfile { imlicistAttributeProfile: CharacterString [0..1] { definition this is multiline with `ascidoc` end definition } } class AttributeProfile { +addressClassProfile: CharacterString [0..1] imlicistAttributeProfile: CharacterString [0..1] { definition this is attribute definition } } } ---- And the `lutaml_uml_attributes_table` macro: [source,adoc] ----- [lutaml_uml_attributes_table, example.lutaml, AttributeProfile] ----- Will produce this output: [source,adoc] ----- === AttributeProfile .AttributeProfile attributes |=== |Name |Definition |Mandatory/ Optional/ Conditional |Max Occur |Data Type |addressClassProfile |TODO: enum 's definition |M |1 | `CharacterString` |imlicistAttributeProfile |this is attribute definition with multiply lines |M |1 | `CharacterString` |=== ----- In case of "enumeration" (AddressClassProfile) entity: [source,adoc] ----- [lutaml_uml_attributes_table, example.lutaml, AddressClassProfile] ----- Will produce this output: [source,adoc] ----- === AddressClassProfile .AddressClassProfile values |=== |Name |Definition |imlicistAttributeProfile |this is multiline with `asciidoc` |=== ----- === Usage of `lutaml_uml_datamodel_description` macro This macro allows to quickly render data model packages and its dependent objects for supplied XMI file. Given an Enterprise Architect `example.xmi` file with 2 packages: * 'Another' * 'CityGML' The `lutaml_uml_datamodel_description` macro can be used: [source,adoc] ----- [lutaml_uml_datamodel_description, path/to/example.xmi] -- [.before] .... my text .... [.diagram_include_block, base_path="requirements/", format="emf"] .... Diagram text .... [.include_block, package="Another", base_path="spec/fixtures"] .... my text .... [.include_block, base_path="spec/fixtures"] .... my text .... [.before, package="Another"] .... text before Another package .... [.after, package="Another"] .... text after Another package .... [.after, package="CityGML"] .... text after CityGML package .... [.after] .... footer text .... -- -- ----- Where: * `path/to/example.xmi` - required, path to the XMI file to render * `[.before]` - macro to add additional text before the rendered output, can be used only once, additional occurrences of macro will overwrite text, not that `literal` block style must be used in there(eg `....`) * `[.after]` - macro to add additional text after the rendered output, can be used only once, additional occurrences of macro will overwrite text * `[.after, package="Another"]` - macro with text to be inserted before(after in case of `.before` name) the package * `[.diagram_include_block]` - macro to automatically include diagram images. Attribute `base_path` is a required attribute to supply path prefix where to look for a diagram image. `format` is an optional attribute that tells what file extension to use when including diagram file. The logic is as follows: [source,adoc] ----- {% for diagram in package.diagrams %} [[figure-{{ diagram.xmi_id }}]] .{{ diagram.name }} image::{{ image_base_path }}/{{ diagram.xmi_id }}.{{ format | default: 'png' }}[] {% if diagram.definition %} {{ diagram.definition | html2adoc }} {% endif %} {% endfor %} ----- For instance, the script will take package diagrams supplied in the XMI file and will try to include `image` with the name equal to diagram' xmi_id attribute plus `.png`. Also one can add any text to the macro text, it will be added as paragraph before each image include. * `[.diagram_include_block, package="Another"]` - same as above, but diagram will be included only for supplied package name * `[.include_block, base_path="spec/fixtures"]` - macro to include files (`*.adoc` or `*.liquid`) for each package name. Attribute `base_path` is a required attribute to supply path prefix where to look for file to include. Macro will look for a file called `base_path` + `/` `_package_name`(downcase, replace : -> '', ' ' -> '_') + `.adoc`[`.liquid`], eg for package 'My Package name' and `base_path` eq to `my/path`, macro will look for the following file path: `my/path/_my_package_name.adoc`. * `[.include_block, package="Another", base_path="spec/fixtures"]` - same as above, but include block will be included only for supplied package name In addition to the macros listed above that can be used only inside `lutaml_uml_datamodel_description` macro there is another macro called `lutaml_figure`. `lutaml_figure` is used to lookup and reference xmi package diagrams. The syntax is as follows: [source,adoc] ----- This is lutaml_figure::[package="Wrapper root package", name="Fig B1 Full model"] figure ----- This code will be transformed into `<>` and will point to diagram figure. One can only use this macro when document rendered `lutaml_uml_datamodel_description` macro as it needs diagram lookup table in order to reference package diagram. Will produce this output: [source,adoc] ----- my text == CityGML package === CityGML overview Diagram text [[figure-EAID_ACBB5EE3_3428_40f5_9C7C_E41923419F29]] .CityGML Package Diagram image::requirements/EAID_ACBB5EE3_3428_40f5_9C7C_E41923419F29.png[] BuildingFurnitureFunctionValue is a code list that enumerates the different purposes of a BuildingFurniture. [[figure-EAID_938AE961_1C57_4052_B964_997D1894A58D]] .Use of ISO and OASIS standards in CityGML image::requirements/EAID_938AE961_1C57_4052_B964_997D1894A58D.png[] The CityGML package is organized into 2 packages with 1 modules: . Another package . CityTML package my text Content for CityGML package ==== Defining tables .<> -- Elements of “Another::AbstractAtomicTimeseries” (class) [[tab-P-another-C-{XMI_ID}]] .Elements of “Another::AbstractAtomicTimeseries” (class) [width="100%",cols="a,a,a,a,a,a,a,a"] |=== h|Name: 7+| AbstractAtomicTimeseries h|Definition: 7+| h|Stereotype: 7+| interface h|Abstract: 7+| h|Associations: 7+| (none) .4+h|Public attributes: | _Name_ 2+| _Definition_ | _Derived_ | _Obligation_ | _Maximum occurrence_ | _Data type_ | adeOfAbstractAtomicTimeseries 2+| | | C | * | ADEOfAbstractAtomicTimeseries | observationProperty 2+| | | M | 1 | CharacterString | uom 2+| | | C | 1 | CharacterString h|Constraints: 7+| (none) |=== === Additional Information text after CityGML package ----- In addition to just supplying an XMI file, this macro also supports a YAML configuration file. The format for using YAML is this: [source,yaml] ----- --- packages: # includes these packages - "Package *" - two* - three # skips these packages - skip: four render_style: entity_list|data_dictionary|default section_depth: 2 ----- Where: * `packages` - required, root element with the list of strings or objects * `Package *` - pattern matching, specifies lookup condition for packages to render. + NOTE: In this example, it is equal to the following regular expression: `/^Package.*$/` * `skip: four` - object with package name to skip * `render_style` - what template to use to render packages, can be: entity_list, data_dictionary or default * `section_depth` - what package to use as root package for render, eg `section_depth` equal to 2 tells processor to use first nested package of the first root packages in xmi file. Example: if xmi file has this package structure: [{ name: 'One', packages: [{ name: 'one-1' }, { name: 'one-2' }] }, { name: 'Two', packages: [{ name: 'two-1' }, { name: 'two-2' }] }] and we have `section_depth` equal to 2, root package will be `one-1` Usage with macro: [source,adoc] -- [lutaml_uml_datamodel_description, path/to/example.xmi, path/to/config.yml] ---- [.diagram_include_block, base_path="models/Images", format="png"] ... ... ---- -- The macro processor will read supplied YAML file and arrange packages according to the order supplied in the config file, also all packages supplied as `skip` will be skipped during render == Documentation Please refer to https://www.metanorma.com.