From b25703484348da76179c81997cc59d0349bfd669 Mon Sep 17 00:00:00 2001 From: Juergen Bocklage-Ryannel Date: Thu, 3 Aug 2017 11:45:06 +0200 Subject: Added features support for rule generator --- docs/extending.rst | 36 +++++++++++++++++++++++++++++++++++- qface/generator.py | 21 +++++++++++++++++---- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/docs/extending.rst b/docs/extending.rst index 010c810..9e1b671 100644 --- a/docs/extending.rst +++ b/docs/extending.rst @@ -75,7 +75,7 @@ The `RuleGenerator` allows you to extract the documentation rules into an extern generator = RuleGenerator(search_path=here/'templates', destination=output) generator.process_rules(here/'docs.yaml', system) -The rules document is divided into several targets. Each target can have an own destination. A target is typical for exampe and app, client, server. Each target can have rules for the different symbols (system, module, interface, struct, enum). An each rule finally consists of a destination modifier, additional context and a documents collection. +The rules document is divided into several targets. Each target can have an own destination. A target is typical for example and app, client, server. Each target can have rules for the different symbols (system, module, interface, struct, enum). An each rule finally consists of a destination modifier, additional context and a documents collection. .. code-block:: python @@ -123,3 +123,37 @@ Here is an example (``docs.yaml``) The rule generator adds the ``dst``, ``project`` as also the corresponding symbols to the context automatically. On each level you are able to change the destination or update the context. + +.. rubric:: Features + +The rules document allows to conditional write files based on a feature set. The feature set must be a set of tags indicating the features which will then be checked in the ``when`` section of a rule. + +The features are passed to the generator in your custom generator code. The existence of a feature tells the rules engine to check if a ``when`` section exists conditionally execute this rule. + +.. code-block:: yaml + + plugin: + when: plugin_enabled + destination: '{{dst}}/plugin' + module: + ... + +Here the plugin rule will only be run when the feature set contains a 'plugin_enabled' string. + +.. rubric:: Preserve + +Documents can be marked as preserved to prevent them to be overwritten when the user has edited them. the rules documents has an own marker for this called ``preserve``. This is a list of target documents which shall be be marked preserved by the generator. + + +.. code-block:: yaml + + plugin: + interface: + documents: + '{{interface|lower}}.h': 'plugin/interface.h' + '{{interface|lower}}.cpp': 'plugin/interface.cpp' + preserve: + - '{{interface|lower}}.h' + - '{{interface|lower}}.cpp' + +IN the example above the two interface documents will not be overwritten during a second generator call and can be edited by the user. diff --git a/qface/generator.py b/qface/generator.py index ac1baeb..ef02062 100644 --- a/qface/generator.py +++ b/qface/generator.py @@ -156,16 +156,18 @@ class Generator(object): class RuleGenerator(Generator): """Generates documents based on a rule YAML document""" - def __init__(self, search_path: str, destination: Path, context: dict= {}): + def __init__(self, search_path: str, destination:Path, context:dict={}, features:set=set()): super().__init__(search_path, context) self.context.update({ 'dst': destination, 'project': Path(destination).name, }) self.destination = '{{dst}}' + self.features = features - def process_rules(self, path: Path, system: System): + def process_rules(self, path: Path, system: System, features:set=set()): """writes the templates read from the rules document""" + self.features.update(features) self.context.update({'system': system}) document = FileSystem.load_yaml(path, required=True) for module, rules in document.items(): @@ -174,6 +176,8 @@ class RuleGenerator(Generator): def _process_rules(self, rules: dict, system: System): """ process a set of rules for a target """ + if not self._shall_proceed(rules): + return self.context.update(rules.get('context', {})) self.destination = rules.get('destination', '{{dst}}') self._process_rule(rules.get('system', None), {'system': system}) @@ -188,7 +192,7 @@ class RuleGenerator(Generator): def _process_rule(self, rule: dict, context: dict): """ process a single rule """ - if not rule: + if not rule or not self._shall_proceed(rule): return self.context.update(context) self.context.update(rule.get('context', {})) @@ -198,6 +202,15 @@ class RuleGenerator(Generator): preserve = target in preserved self.write(target, source, preserve=preserve) + def _shall_proceed(self, obj): + conditions = obj.get('when', []) + if not conditions: + return True + if not isinstance(conditions, list): + conditions = [conditions] + result = self.features.intersection(set(conditions)) + return bool(len(result)) + class FileSystem(object): """QFace helper functions to work with the file system""" @@ -302,5 +315,5 @@ class FileSystem(object): try: return yaml.load(document.text(), Loader=Loader) except yaml.YAMLError as exc: - click.secho(exc, fg='red') + click.secho(str(exc), fg='red') return {} -- cgit v1.2.1