A recursive syntax for the procedural generation of random sentences in Ruby.
Perhaps you want to generate emails, text messages, or webpages that are all readable, but have different wordings. Perhaps you're writing a game and want to vary character dialog. Perhaps you're writing a testing language and need a concise way to express linguistic possibilities. Perhaps you don't need a reason.
gem install confabulator
require 'confabulator'
Choice blocks let the parser make a random choice.
> 5.times { puts Confabulator::Parser.new("{Choice one|Choice two} and stuff").confabulate }
Choice two and stuff
Choice one and stuff
Choice two and stuff
...
Choices inside of choices (ad infinitum) are fine:
> 5.times { puts Confabulator::Parser.new("This is {an example|a {good|great|mediocre} demonstration}").confabulate }
This is a great demonstration
This is a mediocre demonstration
This is an example
This is a good demonstration
This is an example
This is an example
This is a good demonstration
...
You can differentially weight the options: {5:This is 5 times more likely|than this}
Substitutions let you re-use common templates.
> knowledge = Confabulator::Knowledge.new
> knowledge.add "friend", "{friend|world|there}" # a hash is also acceptable
> Confabulator::Parser.new("Hello, [friend]!", :knowledge => knowledge).confabulate
=> "Hello, there!"
> Confabulator::Parser.new("Hello, [friend]!", :knowledge => knowledge).confabulate
=> "Hello, world!"
...
Equivalently, as a helper on the Knowledge object:
> knowledge.confabulate("Hello, [friend]!")
=> "Hello, there!"
You can ask a substitution to be capitalized:
> knowledge.confabulate("Hello, [friend:c]!")
=> "Hello, World!"
Or pluralized:
> knowledge.add "dude" => "friend"
> knowledge.confabulate("Hello, [dude:p]!")
=> "Hello, friends!"
Substitutions can contain other substitutions inside of choice nodes inside of other substitutions, etc., ad infinitum. Just try to avoid infinite loops!
You must escape the special characters {, [, `, and | with backslashes:
> knowledge.add "dude" => "friend"
> knowledge.confabulate("Hello, \\{friend\\|something\\} \\`\\`stuff\\`\\` \\[dude:p]!")
=> "Hello, {friend|something} ``stuff`` [dude:p]!!"
Sometimes you want to insert user generated content without having to escape every {, [, `, and |. For this you use protected regions.
> knowledge.add "dude" => "friend"
> user_content = "protect regions [and stuff] with double backticks (`)!"
> knowledge.confabulate("Hello, ``#{user_content}``")
=> "Hello, protect regions [and stuff] with double backticks (`)!"
At the moment, sequences of more than one backtick are never allowed inside of a protected region.
You can output an array of all possible confabulations using all_confabulations
, like so:
> Confabulator::Parser.new("{Hello|Hi} {world|there}").all_confabulations
=> [
"Hello world",
"Hello there",
"Hi world",
"Hi there"
]
Internally, this calls tree
, which outputs a simplified confabulation parse tree.
Here are some things that could be added to this library:
- Depth limits / recursion detection
- Learning through back propagation of a reward signal and optimization of the choice nodes to make the rewarded or penalized outcome more or less likely.
- Whatever you want!
Fork, write specs, add a feature, write documentation, send me a pull request!