Crate tracery[][src]

Rust implementation of the tracery generative grammar language.

This library is a Rust port/implementation of tracery, the generative grammar language designed and created by Kate Compton. Given a set of rules written in the tracery syntax, it will use them to procedurally generate strings of text. For more information about the tracery language, see the Language Concepts section below.

Usage

Usage of the library can be divided into two areas: creation of grammars and the generation of output strings.

Grammar Creation

Grammars can be created using the grammar! macro, from an any iterable rust object of strings and associated lists of strings, or for compatibility with the original tracery, from a string representing a JSON map.

The grammar! macro

Accepts input in the form "key" => [ "list", "of", "rules" ] or, in the case of a key having only one rule, "key" => "rule". Equivalent to manually building a map and then calling Grammar::from_map

use tracery::grammar;
let g = grammar! {
    "origin" => "#tool# is #description#!",
    "tool" => "tracery",
    "description" => [ "fun", "awesome" ]
}?;

From a map/iterator

A grammar can be created from any object implementing, essentially, IntoIterator<Item = (Into<String>, Into<Vec<Into<String>>)>. For example, HashMap<String, Vec<String>> or BTreeMap<&str, &[&str]>.

let map = hashmap! {
    "origin" => vec![ "#tool# is #description#!" ],
    "tool" => vec![ "tracery" ],
    "description" => vec![ "fun", "awesome" ]
};
let g = tracery::from_map(map)?;

From a JSON string

For compatibility with the original tracery, a Grammar can be created from a string representing a JSON object. This feature is controlled by the tracery_json feature, which is enabled by default. It can be turned off if you do not require this functionality.

let json = r##"{
    "origin": [ "#tool# is #description#!" ],
    "tool": [ "tracery" ],
    "description": [ "fun", "awesome" ]
}"##;
let g = tracery::from_json(json)?;

Generating output strings

There are two methods for getting a generated output string from a created Grammar: execute and flatten. Generally, execute should be preferred if possible.

execute

execute takes two parameters: the rule to expand and an RNG to use during generation. The RNG can be any type implementing rand::Rng.

use tracery::grammar;
let mut g = grammar! {
    "origin" => "#tool# is #description#!",
    "tool" => "tracery",
    "description" => [ "fun", "awesome" ]
}?;

// Generate an output (either "tracery is fun!" or "tracery is awesome!")
let key = String::from("origin");
let output = g.execute(&key, &mut rand::thread_rng())?;

execute generates its output using the Grammar in-place. Since Grammars are allowed to modify their own rule stacks, execute must take a &mut self reference. This means that any modifications made during an execution will persist in the Grammar.

use tracery::grammar;
// This time, origin has a side-effect: it creates the rule 'aside'
let mut g = grammar! {
    "origin" => "#[aside:Rust is, too]tool# is #description#!",
    "tool" => "tracery",
    "description" => [ "fun", "awesome" ]
}?;

// Generate an output (either "tracery is fun!" or "tracery is awesome!")
let key = String::from("origin");
let output = g.execute(&key, &mut rand::thread_rng())?;

// The previous call to execute created the 'aside' rule
let key = String::from("aside");
// Generates the string "Rust is, too"
let output = g.execute(&key, &mut rand::thread_rng())?;

flatten

flatten, unlike execute, always operates on the default rule of the Grammar (“origin” by default), but like execute, takes an instance of rand::Rng to use during generation. In addition, flatten creates a clone of the Grammar to use during generation, then discards it, which means that any side-effects that occur will be discarded when it’s done.

use tracery::grammar;
let g = grammar! {
    "origin" => "#tool# is #description#!",
    "tool" => "tracery",
    "description" => [ "fun", "awesome" ]
}?;

// Generate an output (either "tracery is fun!" or "tracery is awesome!")
let output = g.flatten(&mut rand::thread_rng())?;

Language Concepts

A grammar is a map from a set of string keys to a stack of rulesets, notionally rooted at an “origin” node, associated by default with the key “origin”

A key is any valid UTF-8 String that does not contain the reserved characters [, ], ., :, or #. A key is associated with a stack of rulesets, and the topmost ruleset is used when expanding the key or popping a ruleset off the stack using a pop action.

A ruleset is a list (internally a Vec<String>) of strings, each representing a possible expansion of the associated key, to be chosen at random when expanding that key, containing one or more plaintexts, tags, or actions.

An action is enclosed by square brackets ([, ]) and can be either labeled or unlabeled.

A labeled action takes the form [key:rule], where rule is any valid tracery rule string, and key is a valid key. The rule will be executed and the result pushed onto the top of the ruleset stack associated with key. If key does not exist already, it will be created. A special exception is a pop action which takes the form [key:POP], and will pop the top ruleset off the stack of rulesets associated with key. If the stack becomes empty, the key will be deleted from the associated grammar.

An unlabeled action is a single tag encased in square brackets such as [#setPronouns#] and is typically used to call a function-like ruleset which will use labeled actions to set values for some set of keys (like setting a character’s pronouns for a story).

A tag is a key, encased in hashes (#), which will be replaced in the output by a random rule chosen from the topmost ruleset of the key’s associated ruleset stack. The key in a tag can also be preceded by one or more actions, which will be executed before the tag is expanded. Some examples of valid tags include: #foo#, #[foo:#bar#]baz#, and #[#setPronouns#][#setJob#][#setPet#]hero#.

A plaintext is any text in a rule which is not a tag or action.

Macros

grammar

Convenience macro that allows for shorthand creation of Grammars.

Structs

Grammar

Represents a single, complete tracery grammar.

Enums

Error

The tracery error type

Functions

flatten_json

Creates a new grammar from a JSON grammar string, then uses it to create a random output string, using the “origin” rule

flatten_map

Creates a new grammar from an input map, then uses it to create a random output string, using the “origin” rule

from_json

Creates a new grammar from a JSON grammar string

from_map

Creates a new grammar from an input map

Type Definitions

Result

A convenience type for a Result of T or Error