File: visitor.rst

package info (click to toggle)
fonttools 4.62.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 27,652 kB
  • sloc: python: 145,583; xml: 103; makefile: 24
file content (111 lines) | stat: -rw-r--r-- 3,518 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
####################################################
visitor: Tools for traversing nested data structures
####################################################

.. contents:: On this page:
    :local:

.. rubric:: Overview
   :heading-level: 2

The :mod:`.visitor` module provides an extensible `visitor pattern`_, which can
be used for traversing, inspecting, and editing nested Python data structures.

The utility class :class:`Visitor <fontTools.misc.visitor.Visitor>`
automatically handles recursion into most common data types, which allows for
user code to skip boilerplate and focus on operation logic. This recursion logic
is documented in full under the :func:`visit() <fontTools.misc.visitor.Visitor>`
function.

Commonly targeted data structures in font projects and ``fonttools`` include:

* :class:`TTFont <fontTools.ttLib.ttFont.TTFont>`: Compiled font files
* :class:`FeatureFile <fontTools.feaLib.ast.FeatureFile>`: Feature code syntax trees

Commonly implemented operations include:

* Summarizing
* Subsetting
* Scaling

.. _visitor pattern: https://en.wikipedia.org/wiki/Visitor_pattern


Specializations
---------------

The :mod:`ttLib.ttVisitor <fontTools.ttLib.ttVisitor>` module provides the
:class:`TTVisitor <fontTools.ttLib.ttVisitor.TTVisitor>` class, which handles
common edge cases when using visitors with :class:`TTFont
<fontTools.ttLib.ttFont.TTFont>` objects. For this reason, it should be
preferred in that scenario.


Guide
-----

1. Create a new class extending :class:`Visitor <fontTools.misc.visitor.Visitor>`.
2. Register operations for specific types or attributes with the *register* annotations.
3. Instantiate the class and call :func:`visit() <fontTools.misc.visitor.Visitor>` on the target object.


Example code
^^^^^^^^^^^^

One can create a visitor class that checks the case of feature names::

    >>> from fontTools.feaLib.ast import FeatureNameStatement
    >>> from fontTools.misc.visitor import Visitor
    >>>
    >>> class SpellCheckVisitor(Visitor):
    ...     found: list[FeatureNameStatement]
    ...
    ...     def __init__(self):
    ...         self.found = []
    >>>
    >>> @SpellCheckVisitor.register(FeatureNameStatement)
    ... def visit(visitor: SpellCheckVisitor, statement: FeatureNameStatement):
    ...     # Find name statements that are not in title case.
    ...     if statement.string != statement.string.title():
    ...         visitor.found.append(statement)

This can then be applied on a feature file object::

    >>> io = StringIO("""
    ...     feature ss01 {
    ...         featureNames {
    ...             name "Monolinear Grotesque";
    ...         };
    ...     } ss01;
    ...
    ...     feature ss02 {
    ...         featureNames {
    ...             name "Optical Apertures";
    ...         };
    ...     } ss02;
    ...
    ...     feature ss03 {
    ...         featureNames {
    ...             name "slanted Humanism";
    ...         };
    ...     } ss03;
    ... """)
    >>> fea = Parser(io).parse()
    >>>
    >>> visitor = SpellCheckVisitor()
    >>> visitor.visit(fea)
    >>>
    >>> for statement in visitor.found:
    ...     print(
    ...         "Found feature name that was not in title case: "
    ...         f"'{statement.string}' at location '{statement.location}'",
    ... )
    Found feature name that was not in title case: 'slanted Humanism' at location '<features>:16:13'


Package contents
----------------

.. automodule:: fontTools.misc.visitor
   :members:
   :undoc-members: