interp
A randomized text-interpolation tool inspired by Tracery, in Haskell.
Installation
Prerequisites
- Haskell
- Stack, unless you can work Cabal yourself
Clone this repo, cd
into it, and then:
- if you want to use the CLI, run
stack install
- if you want to use it as a library, just run
stack build
Development
Fork this repo, make some changes, run stack test
to make sure everything's ok, then (if you want) submit a PR. Thank you!
Use
CLI
Usage: interp (--substitutions ARG | SUBST) (--interpolations ARG | INTERP)
Randomly interpolate values into a template
Available options:
--substitutions ARG JSON file containing map of substitutions
SUBST JSON file containing map of substitutions
--interpolations ARG file containing text to interpolate
INTERP file containing text to interpolate
-h,--help Show this help text
substitutions
is the (path to the) file containing the JSON map of substitutions. interpolations
is (path to the) file containing the text to interpolate. See below for more on both.
Library
Data.Text.Interp.Interpolate.interp
is probably what you'll want to use. It takes a Subst
object (usually parsed from JSON, but you can make one yourself) and a NonEmpty
list of IText
s. Check out Data.Text.Interp.Types
for more on those types.
Syntax
In both substitution and interpolation files, keys can be comprised of any letter or number, or the characters "_" or "-". Spaces and other punctuation are not allowed and will give you Problems.
Substitutions
{"coolThings": [
{"name": "computers",
"reason": "you can do haskell on them"
},
{"name": "dogs",
"reason": "they're good"
}
],
"badThings": [
{"name": "flat tires",
"reason": "they make you late"
},
{"name": "jobs",
"reason": "they make you tired"
}
],
"sam": {
"likes": "computers"
}
The substitutions file is a JSON file. JSON maps are treated how one would expect. The values in a JSON array are chosen among randomly (but see also below on binding). Regular values are treated regularly, but note:
- because of how JSON is parsed, all numeric literals are treated as floating-point, so a
1
will be interpolated as "1.0"
. If this is an issue, just wrap your numbers in quotes and they'll be treated as strings.
null
values are explicitly forbidden; empty lists and maps should be avoided.
Interpolations
{{ ... }}
sets off a thing to interpolate. Keys, corresponding to keys in the substitutions file, can be period-separated to 'dig into' nested maps. Thus, in the example above, sam.likes
will be have the value "computers"
.
Binding
Within braces, values can be bound to variables using the syntax (varToBind#keys.to.bind).other.keys
. When a variable is bound, references to that variable will be interpolated with that same value. Thus, given the interpolation template
{{ (cool#coolThings).name }} are cool because {{ cool.reason }}. {{ (bad#badThings).name }} are bad because {{ bad.reason }}.
cool
in the first interpolation will be the same as cool
in the second. Note that keys within the parentheses are part of the binding, while those after the closing parentheses are interpolated normally--{{ (cool#coolThings).name }}
will be either "computers"
or "dogs"
, while {{ cool.reason }}
will be "you can do haskell on them"
or "they're good"
, depending on which sub-map was randomly chosen to be bound to cool
.
Binding is primarily useful for map values. It's possible to bind arrays, but since array elements are chosen randomly evey time, there's not much of a point. Similarly, there's no real difference between binding a simple value and just using the full path to it, unless you're trying to save characters.
Etc.
To-Do
Contributing
PRs, issues, feature requests, etc. are always more than welcome! Feel free to hit me up on twitter or email me at sam dot raker at gmail dot com. Let me know if you like this, hate this, wish it were better, wish it were worse, whatever.