Expand description
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§
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