Card 07/ 08

ExerciseDifficulty: Advanced1 min

Practice: Text Formatting Decorators in the Right Order

Trim, then upper-case, then wrap in brackets; build the stack that prints the expected line.

Text formatters are a natural Decorator, and this exercise asks you to build a stack and then predict a different one. Each formatter implements render() and holds another text. Plain(" hello ") renders its value unchanged, Trim strips spaces from both ends, Upper converts to capitals, and Brackets puts square brackets round the text.

  1. Build the stack that renders "[HELLO]" from Plain(" hello ").
  2. Predict what Trim(Brackets(Upper(Plain(" hello ")))) renders, and say why.
Show a solution
py
from abc import ABC, abstractmethod


class Text(ABC):
    @abstractmethod
    def render(self) -> str: ...


class Plain(Text):
    def __init__(self, value: str) -> None:
        self._value = value

    def render(self) -> str:
        return self._value


class TextDecorator(Text):
    def __init__(self, inner: Text) -> None:
        self._inner = inner


class Trim(TextDecorator):
    def render(self) -> str:
        return self._inner.render().strip()


class Upper(TextDecorator):
    def render(self) -> str:
        return self._inner.render().upper()


class Brackets(TextDecorator):
    def render(self) -> str:
        return f"[{self._inner.render()}]"


source = Plain("  hello  ")
print(repr(Brackets(Upper(Trim(source))).render()))
print(repr(Trim(Brackets(Upper(source))).render()))
OutputRan with python:3.12-slim (Python 3.12.13)
'[HELLO]'
'[  HELLO  ]'
The trim must be innermost, applied before the brackets are added.
How the reordered stack renders
LayerReceivesReturns
Plainnothing' hello '
Upper' hello '' HELLO '
Brackets' HELLO ''[ HELLO ]'
Trim'[ HELLO ]''[ HELLO ]'

The innermost decorator acts first on the way out, so Brackets(Upper(Trim(source))) trims, then capitalises, then brackets. In the reordered stack the trim is outermost and acts last, after the brackets are in place, so the spaces are inside the brackets and there is nothing at either end to strip.