by
tundish
2021 November 08
Monday afternoon

Note

This page explains Balladeer's classic syntax, which is no longer maintained.

Refer to a more recent article for its replacement, Balladeer lite.

Properties

If you've done any Python programming, you may know what a property is. It's a way of giving an object a getter and a setter for an internal attribute.

It is intrinsic to Balladeer that a Drama and its Dialogue interact with each other. The main way they do this is via a property called state.

For this first example we'll treat that state as an integer value. In a future article though, we'll discover that it's much more flexible than that.

Green Bottles

We are going to create a version of the song 10 Green Bottles. You can find the full code example in the Balladeer repository.

drama.py

Here's a Drama class which on every turn reduces its integer state value by one:

class Bottles(Drama):
    def interlude(self, folder, index, *args, **kwargs):
        self.state = max(0, self.state - 1)
        return self.facts

Interlude methods are expected to return a dictionary. Drama objects have a dictionary attribute called facts. So for simplicity that can be our return value here.

The state needs initially setting to 10, which we can do like this:

drama = Bottles().set_state(10)

song.rst

The dialogue needs access to the number of bottles, so we'll use a reStructuredText substitution to reference the drama state property:

.. |BOTTLES| property:: DRAMA.state

The main challenge to generating the lyrics correctly, is the way they change according to the number of bottles.

We use a condition directive to decide which form of words to use. Though state is an integer, in dialogue files everything is treated as a string.

Our conditional might look for an explicit string representation of the state integer, or we can define a regular expression instead. Regexes must be supplied inside parentheses, just as you see here:

.. entity:: DRAMA
    :types: balladeer.Drama

.. |BOTTLES| property:: DRAMA.state

Song
====

Many
----

.. condition:: DRAMA.state ([^01]+)

|BOTTLES| green bottles, hanging on the wall.

And if one green bottle should accidentally fall,
There'll be...

One
---

.. condition:: DRAMA.state 1

|BOTTLES| green bottle, hanging on the wall.

And if one green bottle should accidentally fall,
There'll be...

None
----

.. condition:: DRAMA.state 0

No green bottles hanging on the wall.

Please take a moment to download the example and run this yourself.

This has been a simple case with which to start. In the next article we will complicate things slightly in order to learn more features of Balladeer.

Comments hosted at Disqus