Skip to content

Commit

Permalink
Merge branch 'release/1.8'
Browse files Browse the repository at this point in the history
  • Loading branch information
Juergen Bocklage-Ryannel committed Aug 3, 2017
2 parents 9c1e691 + 24ae273 commit 4368a21
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 15 deletions.
36 changes: 35 additions & 1 deletion docs/extending.rst
Expand Up @@ -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
Expand Down Expand Up @@ -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.
2 changes: 1 addition & 1 deletion qface/__about__.py
Expand Up @@ -9,7 +9,7 @@
__title__ = "qface"
__summary__ = "A generator framework based on a common modern IDL"
__url__ = "https://pelagicore.github.io/qface/"
__version__ = "1.7"
__version__ = "1.8"
__author__ = "JRyannel"
__author_email__ = "qface-generator@googlegroups.com"
__copyright__ = "2017 Pelagicore"
41 changes: 28 additions & 13 deletions qface/generator.py
Expand Up @@ -137,9 +137,9 @@ def _write(self, file_path: Path, template: str, context: dict, preserve: bool =
data = self.render(template, context)
if self._has_different_content(data, path):
if path.exists() and preserve:
click.secho('preserve changed file: {0}'.format(path), fg='blue')
click.secho('preserve: {0}'.format(path), fg='blue')
else:
click.secho('write changed file: {0}'.format(path), fg='blue')
click.secho('create: {0}'.format(path), fg='blue')
path.open('w', encoding='utf-8').write(data)

def _has_different_content(self, data, path):
Expand All @@ -156,24 +156,28 @@ def register_filter(self, name, callback):

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, document: 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})
rules = FileSystem.load_yaml(document, required=True)
for name, target in rules.items():
click.secho('process target: {0}'.format(name), fg='green')
self._process_target(target, system)
document = FileSystem.load_yaml(path, required=True)
for module, rules in document.items():
click.secho('module: {0}'.format(module), fg='green')
self._process_rules(rules, system)

def _process_target(self, rules: dict, system: System):
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})
Expand All @@ -188,13 +192,24 @@ def _process_target(self, rules: dict, system: System):

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', {}))
self.destination = rule.get('destination', None)
preserved = rule.get('preserve', [])
for target, source in rule.get('documents', {}).items():
self.write(target, source)
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):
Expand Down Expand Up @@ -249,7 +264,7 @@ def merge_annotations(system, document):
updates the tag information of that symbol
"""
meta = FileSystem.load_yaml(document)
click.secho('merge tags from {0}'.format(document), fg='blue')
click.secho('merge: {0}'.format(document.name), fg='blue')
for identifier, data in meta.items():
symbol = system.lookup(identifier)
if symbol:
Expand Down Expand Up @@ -300,5 +315,5 @@ def load_yaml(document: Path, required=False):
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 {}

0 comments on commit 4368a21

Please sign in to comment.