From 365fabdf67a75453ef79465a3c9fcf5df924429a Mon Sep 17 00:00:00 2001 From: dozens Date: Fri, 2 Aug 2024 12:22:14 -0600 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20first?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 33 ++ doc/Tutorial.md | 48 ++ doc/meta.rec | 9 + doc/versions.rec | 481 +++++++++++++++ justfile | 34 ++ src/main.fnl | 49 ++ src/story.fnl | 80 +++ test/morpheme-word-epithet.txt | 1013 ++++++++++++++++++++++++++++++++ test/story.test.fnl | 23 + 10 files changed, 1771 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 doc/Tutorial.md create mode 100644 doc/meta.rec create mode 100644 doc/versions.rec create mode 100644 justfile create mode 100644 src/main.fnl create mode 100644 src/story.fnl create mode 100644 test/morpheme-word-epithet.txt create mode 100644 test/story.test.fnl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..272c8bd --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tbls diff --git a/README.md b/README.md new file mode 100644 index 0000000..eae8621 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# tbls + +for expanding random table entries + +## Requirements + +Built with +Fennel 1.3.1 on PUC Lua 5.4 + +## Usage + +You can run the script: `fennel src/main.fnl`. + +Or you can compile a binary and use that. +See `just compile`. + +## Roadmap + +- [x] random table entries (ADDED in vHydrogen) +- [x] expanding macros (ADDED in vHydrogen) +- [ ] table files plugin: syntax highlighting + folding +- [ ] expansion filters + +## Resources + +inspired heavily by tracery: +https://github.com/galaxykate/tracery + +and paper elemental's list-to-html generator: +https://paperelemental.blogspot.com/p/list-to-html-generator.html + +and perchance: +https://perchance.org/welcome diff --git a/doc/Tutorial.md b/doc/Tutorial.md new file mode 100644 index 0000000..6e8399d --- /dev/null +++ b/doc/Tutorial.md @@ -0,0 +1,48 @@ +## Tutorial + +At its most basic, `tbls` selects a random element from a table. + +Suppose you have a few tables: + +``` +:: suit +Hearts +Bells +Whistles +Cups +Knives +Shovels + +:: card +Ace +One +Two +... +Ten +Eleven +Twelve +Thief +Queen +King +Beast +``` + +`tbls` might return "Whistles" from suit. +Or "Twelve" from card. + +But wait there's more. +`tbls` will also expand macros found in table entries. + +Let's add another table: + +``` +:: draw +[card] of [suit] +``` + +When you place the name of a table in `[squarebrackets]`, +then `tbls` views that as a placeholder +for a random item from that table. +And it will expand the text. +So this might end up being "Thief of Shovels" +or "Twelve or Cups". diff --git a/doc/meta.rec b/doc/meta.rec new file mode 100644 index 0000000..6123ac5 --- /dev/null +++ b/doc/meta.rec @@ -0,0 +1,9 @@ +%rec: meta +%doc: project metadata +%type: version rec version + +name: tbls +author: dozens@tilde.team +created: 2024-07-31 +updated: 2024-08-01 +version: Hydrogen diff --git a/doc/versions.rec b/doc/versions.rec new file mode 100644 index 0000000..ebc540c --- /dev/null +++ b/doc/versions.rec @@ -0,0 +1,481 @@ +%rec: version +%doc: a table of version names for "tables" based on the most famous table +%type: Number int +%type: Symbol,Name line +%allowed: Number Symbol Name +%mandatory: Number Symbol Name +%unique: Number Symbol Name +%sort: Number +%key: Name + +Number: 1 +Symbol: H +Name: Hydrogen + +Number: 2 +Symbol: He +Name: Helium + +Number: 3 +Symbol: Li +Name: Lithium + +Number: 4 +Symbol: Be +Name: Beryllium + +Number: 5 +Symbol: B +Name: Boron + +Number: 6 +Symbol: C +Name: Carbon + +Number: 7 +Symbol: N +Name: Nitrogen + +Number: 8 +Symbol: O +Name: Oxygen + +Number: 9 +Symbol: F +Name: Fluorine + +Number: 10 +Symbol: Ne +Name: Neon + +Number: 11 +Symbol: Na +Name: Sodium + +Number: 12 +Symbol: Mg +Name: Magnesium + +Number: 13 +Symbol: Al +Name: Aluminum + +Number: 14 +Symbol: Si +Name: Silicon + +Number: 15 +Symbol: P +Name: Phosphorus + +Number: 16 +Symbol: S +Name: Sulfur + +Number: 17 +Symbol: Cl +Name: Chlorine + +Number: 18 +Symbol: Ar +Name: Argon + +Number: 19 +Symbol: K +Name: Potassium + +Number: 20 +Symbol: Ca +Name: Calcium + +Number: 21 +Symbol: Sc +Name: Scandium + +Number: 22 +Symbol: Ti +Name: Titanium + +Number: 23 +Symbol: V +Name: Vanadium + +Number: 24 +Symbol: Cr +Name: Chromium + +Number: 25 +Symbol: Mn +Name: Manganese + +Number: 26 +Symbol: Fe +Name: Iron + +Number: 27 +Symbol: Co +Name: Cobalt + +Number: 28 +Symbol: Ni +Name: Nickel + +Number: 29 +Symbol: Cu +Name: Copper + +Number: 30 +Symbol: Zn +Name: Zinc + +Number: 31 +Symbol: Ga +Name: Gallium + +Number: 32 +Symbol: Ge +Name: Germanium + +Number: 33 +Symbol: As +Name: Arsenic + +Number: 34 +Symbol: Se +Name: Selenium + +Number: 35 +Symbol: Br +Name: Bromine + +Number: 36 +Symbol: Kr +Name: Krypton + +Number: 37 +Symbol: Rb +Name: Rubidium + +Number: 38 +Symbol: Sr +Name: Strontium + +Number: 39 +Symbol: Y +Name: Yttrium + +Number: 40 +Symbol: Zr +Name: Zirconium + +Number: 41 +Symbol: Nb +Name: Niobium + +Number: 42 +Symbol: Mo +Name: Molybdenum + +Number: 43 +Symbol: Tc +Name: Technetium + +Number: 44 +Symbol: Ru +Name: Ruthenium + +Number: 45 +Symbol: Rh +Name: Rhodium + +Number: 46 +Symbol: Pd +Name: Palladium + +Number: 47 +Symbol: Ag +Name: Silver + +Number: 48 +Symbol: Cd +Name: Cadmium + +Number: 49 +Symbol: In +Name: Indium + +Number: 50 +Symbol: Sn +Name: Tin + +Number: 51 +Symbol: Sb +Name: Antimony + +Number: 52 +Symbol: Te +Name: Tellurium + +Number: 53 +Symbol: I +Name: Iodine + +Number: 54 +Symbol: Xe +Name: Xenon + +Number: 55 +Symbol: Cs +Name: Cesium + +Number: 56 +Symbol: Ba +Name: Barium + +Number: 57 +Symbol: La +Name: Lanthanum + +Number: 58 +Symbol: Ce +Name: Cerium + +Number: 59 +Symbol: Pr +Name: Praseodymium + +Number: 60 +Symbol: Nd +Name: Neodymium + +Number: 61 +Symbol: Pm +Name: Promethium + +Number: 62 +Symbol: Sm +Name: Samarium + +Number: 63 +Symbol: Eu +Name: Europium + +Number: 64 +Symbol: Gd +Name: Gadolinium + +Number: 65 +Symbol: Tb +Name: Terbium + +Number: 66 +Symbol: Dy +Name: Dysprosium + +Number: 67 +Symbol: Ho +Name: Holmium + +Number: 68 +Symbol: Er +Name: Erbium + +Number: 69 +Symbol: Tm +Name: Thulium + +Number: 70 +Symbol: Yb +Name: Ytterbium + +Number: 71 +Symbol: Lu +Name: Lutetium + +Number: 72 +Symbol: Hf +Name: Hafnium + +Number: 73 +Symbol: Ta +Name: Tantalum + +Number: 74 +Symbol: W +Name: Tungsten + +Number: 75 +Symbol: Re +Name: Rhenium + +Number: 76 +Symbol: Os +Name: Osmium + +Number: 77 +Symbol: Ir +Name: Iridium + +Number: 78 +Symbol: Pt +Name: Platinum + +Number: 79 +Symbol: Au +Name: Gold + +Number: 80 +Symbol: Hg +Name: Mercury + +Number: 81 +Symbol: Tl +Name: Thallium + +Number: 82 +Symbol: Pb +Name: Lead + +Number: 83 +Symbol: Bi +Name: Bismuth + +Number: 84 +Symbol: Po +Name: Polonium + +Number: 85 +Symbol: At +Name: Astatine + +Number: 86 +Symbol: Rn +Name: Radon + +Number: 87 +Symbol: Fr +Name: Francium + +Number: 88 +Symbol: Ra +Name: Radium + +Number: 89 +Symbol: Ac +Name: Actinium + +Number: 90 +Symbol: Th +Name: Thorium + +Number: 91 +Symbol: Pa +Name: Protactinium + +Number: 92 +Symbol: U +Name: Uranium + +Number: 93 +Symbol: Np +Name: Neptunium + +Number: 94 +Symbol: Pu +Name: Plutonium + +Number: 95 +Symbol: Am +Name: Americium + +Number: 96 +Symbol: Cm +Name: Curium + +Number: 97 +Symbol: Bk +Name: Berkelium + +Number: 98 +Symbol: Cf +Name: Californium + +Number: 99 +Symbol: Es +Name: Einsteinium + +Number: 100 +Symbol: Fm +Name: Fermium + +Number: 101 +Symbol: Md +Name: Mendelevium + +Number: 102 +Symbol: No +Name: Nobelium + +Number: 103 +Symbol: Lr +Name: Lawrencium + +Number: 104 +Symbol: Rf +Name: Rutherfordium + +Number: 105 +Symbol: Db +Name: Dubnium + +Number: 106 +Symbol: Sg +Name: Seaborgium + +Number: 107 +Symbol: Bh +Name: Bohrium + +Number: 108 +Symbol: Hs +Name: Hassium + +Number: 109 +Symbol: Mt +Name: Meitnerium + +Number: 110 +Symbol: Ds +Name: Darmstadtium + +Number: 111 +Symbol: Rg +Name: Roentgenium + +Number: 112 +Symbol: Cn +Name: Copernicium + +Number: 113 +Symbol: Nh +Name: Nihonium + +Number: 114 +Symbol: Fl +Name: Flerovium + +Number: 115 +Symbol: Mc +Name: Moscovium + +Number: 116 +Symbol: Lv +Name: Livermorium + +Number: 117 +Symbol: Ts +Name: Tennessine + +Number: 118 +Symbol: Og +Name: Oganesson diff --git a/justfile b/justfile new file mode 100644 index 0000000..0a988e1 --- /dev/null +++ b/justfile @@ -0,0 +1,34 @@ +# show all recipes +default: + just --list --unsorted + +# compile binary +compile: + fennel --compile-binary src/main.fnl tbls /usr/local/lib/liblua.a /usr/local/include/lua5.4 + +# run test file +_test-story: + fennel test/story.test.fnl + +# test main +_test-main: + for i in $(seq 1 10); do fennel src/main.fnl -i test/morpheme-word-epithet.txt -k name; done + +# run all tests +test: _test-main _test-story + +# bump version +bump: + #!/usr/local/bin/bash + currname=$(recsel doc/meta.rec -P version) + currnum=$(recsel doc/versions.rec -e "Name = '$currname'" -P Number) + nextnum=$((currnum + 1)) + nextname=$(recsel doc/versions.rec -e "Number = $nextnum" -P Name) + echo "Bumping version from $currname to $nextname:" + recset doc/meta.rec -f version -s $nextname + recset doc/meta.rec -f updated -S $(gdate +'%Y-%m-%d') + recsel doc/meta.rec + +# show full metadata +meta: + awk 'FNR==1{print ""}{print}' doc/*.rec | recsel -t meta -j version diff --git a/src/main.fnl b/src/main.fnl new file mode 100644 index 0000000..9e592e1 --- /dev/null +++ b/src/main.fnl @@ -0,0 +1,49 @@ +(local { + : flatten + : create-corpus +} (require :src.story)) + +(fn show-help [] + (print "Usage: tbls [options]") + (print) + (print "Basic Options:") + (print " -h|--help print this message and exit") + (print " -i|--input name of input file") + (print " -k|--origin-table-key name of a table in the input file") + (print " -s|--origin-table-string a string template") + (print) + (print "You must specify an input file") + (print "You must specify either a string or a key to serve as an origin")) + +(fn parse-args [t] + (if (= 0 (length t)) + (do + (show-help) + (os.exit 0))) + (fn inner [t opts] + (if (= 0 (length t)) opts + (do + (case t + (where [a] (or (= a "-h") (= a "--help"))) + (do + (show-help) + (os.exit 0)) + (where [a input] (or (= a "-i") (= a "--input"))) + (set opts.input input) + (where [a key] (or (= a "-k") (= a "--origin-table-key"))) + (set opts.key key) + (where [a str] (or (= a "-s") (= a "--origin-table-string"))) + (set opts.string str)) + (let [next-t (icollect [i v (ipairs t)] (if (> i 2) v))] + (inner next-t opts))))) + (inner t {})) + +(fn main [] + (let [opts (parse-args arg) + corpus (create-corpus opts.input) + ] + (if opts.key + (print (flatten corpus (. corpus opts.key))) + (print (flatten corpus opts.string))))) + +(main) diff --git a/src/story.fnl b/src/story.fnl new file mode 100644 index 0000000..e1871e9 --- /dev/null +++ b/src/story.fnl @@ -0,0 +1,80 @@ +;; helper funs +(local tbl { + :contains? (fn contains [t x] + "does sequence t contain element x?" + (accumulate [found false + _ v (ipairs t) + &until found] ; escape early + (or found (= x v)))) + :keys (fn keys [t] + "takes a table returns a sequential list of its keys" + (local out []) + (each [k v (pairs t)] (table.insert out k)) + out) +}) +(fn has-key? [t k] + (tbl.contains? (tbl.keys t) k)) + + +(fn lines [filename callback] + (case (pcall #(with-open [file (io.open filename)] (each [line (file:lines)] (callback line)))) + (false err) (print (string.format "Error: Could not open file %s\n%s" filename err)))) + +(fn _create-corpus [lines data] + (var current-key nil) + (var corpus {}) + (lines data + #(let [key (string.match $1 "^::%s+([%a-]+)") + blank? (or (= nil $1) (= "" $1)) + comment? (string.match $1 "^#") + ] + (when (and (not blank?) (not comment?)) + (if (not key) + (let [list (. corpus current-key)] + (table.insert list $1) + (tset corpus current-key list)) + (do + (set current-key key) + (tset corpus current-key [])))))) + corpus) +(local create-corpus (partial _create-corpus lines)) + +(fn one-of [t] + "returns a random element of a sequential or non-sequential table" + (let [len (accumulate [l 0 _ _ (pairs t)] (+ l 1)) ;; do it the hard way + ;; because nonseq tables + ;; have no length? + handle (io.popen "echo $RANDOM") + output (handle:read "*a") + random (output:gsub "[\n\r]" "") + seed (math.randomseed random) ;; SIDE EFFECT + whatever (handle:close) ;; SIDE EFFECT + idx (math.random len) + keys (accumulate [acc [] k v (pairs t)] (do (table.insert acc k) acc)) + rndkey (. keys idx) + ] + (. t rndkey))) + +(fn flatten [corpus origin] + (let [str (case (type origin) + "string" origin + "table" (one-of origin) + _ (error "Origin must be a table or a string")) + template-pattern "%[[%a-]+%]" ; [word] + word-pattern "%[([%a-]+)%]" ; word + (i j) (string.find str template-pattern) ; indices + word (string.match str word-pattern)] ; the actual keyword + (if (not i) + str + (do + (assert (has-key? corpus word) + (string.format "Error trying to expand \"%s\". Corpus does not contain a table called \"%s\"" str word)) + (let [next-str (string.format "%s%s%s" + (string.sub str 1 (- i 1)) + (one-of (. corpus word)) + (string.sub str (+ j 1)))] + (flatten corpus next-str j)))))) ;; this is a tail call! + +{: create-corpus + : flatten + } diff --git a/test/morpheme-word-epithet.txt b/test/morpheme-word-epithet.txt new file mode 100644 index 0000000..1b0ff0a --- /dev/null +++ b/test/morpheme-word-epithet.txt @@ -0,0 +1,1013 @@ +# https://foreignplanets.blogspot.com/2024/05/name-generator-morphemewordepithet.html + +:: name +## Entry point / origin +[morpheme][word] [epithet] +[prefix] [morpheme][word] +[prefix] [morpheme][word] [epithet] +[morpheme][word]'[morpheme] +[morpheme] [morpheme][word] + +:: morpheme +## A random sound +Brog +Guyn +Driz +Oy +Poin +Broin +Dray +Hoy +Khu +Elbb +Zee +Teg +Thig +Volor +Moror +Zarn +Zark +Zarzl +Zhong +Zok +Krinc +Prunc +Seld +Serd +Quo +Quog +Wast +Writ +Wub +Eem +Eo +Ev +Wuld +Rond +Trop +Yhoo +Urdd +Ing +Ogg +Phef +Aph +Fro +Drov +Frol +Gis +Hirn +Wilk +Rof +Roch +Thip +Throg +Teng +Tirk +Tenk +Twu +Twal +Yuth +Yirg +Ull +Uk +Iv +Irch +Ok +Ort +Ool +Oon +Oos +Oop +Pur +Purth +Pux +Pix +Ang +Ank +Ack +Arr +Arc +Sor +Shri +Sarc +Sib +Spo +Snil +Dral +Dax +Druz +Droon +Tiong +Snid +Phra +Vang +Gawp +Hool +Grul +Dhoop +Jair +Qim +Quisl +Fiaz +Prax +Aal +Righ +Ugh +Yog +Yig +Yair +Var +Vaq +Skog +Drij +Volg +Dem +Ghil +Uvar +Err +Azil +Obil +Zanzil +Zhat +Blug +Blig +Hroo +Waf +Xar +Grar +Lorp +Vuh +Ee +Ay +Oo +Ux +Ix +Whal +Mun +Ilun +Fargl +Xab +Frang +Bao +Bif +Xif +Zij +Quix +Vonch +Van +Klanc +Lug +Nirm +Zirm +Sil +Wev +Vil +Vran +Quiv +Squan +Squank +Squop +Akun +Apar +Epar +Iq +Exy +Eny +Ery +Uth +Ist +Ost +Hrosh +Imb +Omb +Onk +Arem +Urum +Irim +Irik +Eliv +Wep +Wroov +Droov +Seef +Hiqa +Ayy +Jaal +Khee +Ish +Xiliv +Whij +Koj +Krong +Swue +Aur +Eth +Qeth +Neth +Veth +Yeth +Aer +Aen +Ain +Aun +Uon +Xiv +Ung +Ong +Eng +Ehal +Dhar +Dhom +Hom +Kom +Rom +Qom +Eez +Dhezz +Elpz +Upz +Akz +Auz +Goaz +Goz +Mepz +Tepz +Crunz +Grenz +Purb +Ony +Igy +Eart +Ehng +Leng +Jub +Zhoon +Zhewt +Juju +Lhop +Lhow +Ewl +Ewil +Avul +Ap +Ip +Ep +Eb +En +El +Ek +Eh +Ez +Es +Ej +Ol +Om +Ob +Oc +Ot +Oz +Os +Oq +Mork +Morg +Borg +Franken +Pranken +Lankim +Khim +Khem +Vinken +Inken +Swohd +Glup +Blubil +Bulbil +Ziz +Miz +Lilip +Soong +Yolp +Grang +Grunc +Gharn +Bral +Criv +Durn +Flom +Griv +Harn +Jurn +Klom +Larn +Mird +Norl +Plen +Qarn +Rilk +Skiv +Tarm +Ulm +Vorn +Wim +Yorn +Blen +Cril +Dorn +Frel +Glim +Jiln +Kren +Lom +Morn +Nix +Polm +Quen +Ralk +Shil +Trok +Ulk +Vlim +Yiln +Brim +Crev +Dril +Flon +Gril +Jorn +Kliv +Lorn +Mirk +Norn +Plim +Qril +Rik +Skon +Trel +Ulv +Vril + +:: word +## A regular old word +strong +sour +queer +wait +want +egg +earth +end +bib +eye +chin +leer +cheek +butt +yo +evil +ebb +when +wrath +rude +ruse +red +root +rose +thin +toad +thing +young +urn +utter +itch +ilk +old +trust +rust +oak +odd +pole +prole +prude +pong +pink +purse +poke +fist +ache +asp +age +angst +soul +south +cried +sad +stung +song +bite +cries +mile +scar +dead +dog +dork +drink +forth +for +fool +ford +gem +goad +good +goat +grow +guide +grab +greed +game +hide +hurl +hulk +hung +joke +job +joy +arm +leg +jump +know +lord +long +link +lynx +zoo +crown +crow +vault +vat +bat +bird +bank +brink +bad +bang +brain +bong +birch +nut +north +man +mouth +monk +milk +hold +king +love +zazz +cane +vein +bald +nail +mail +quail +wail +eel +rail +enter +ink +prose +add +down +dark +spur +axe +wash +wink +toil +pit +poor +far +way +walk +pounce +hound +flung +leap +clench +twist +crude +lewd +stab +grip +choke +snore +bore +gore +blood +grind +weird +bone +spit +bile +vile +jest +snort +snarl +snatch +busy +blue +spurt +whoop +slime +pin +fox +ape +miser +mister +foil +wraith +slow +quick +mad +lush +boom +panda +spies +dies +claws +play +stick +beer +wine +vine +gross +belch +burp +roar +kiss +grunt +corn +stone +flight +pig +hog +sly +wish +soap +mud +hill +sure +mean +pain +hurt +strike +lapse +probe +prod +stamp +chimp +pinch +spurn +quote +rinse +pincer +spank +drool +stink +stein +bud +gun +gunner +hum +gum +wallow +wallop +wasp +hook +herb +glare +crank +wrench +snap +willow +berry +spire +spoil +well +head +burn +line +cube +cub +trot +ochre +flay +drown +gander +lick +swirl +thistle +dapple +mingle +flounder +grapple +dazzle +slumber +bumble +sizzle +ripple +wither +tingle +murmur +tremble +twirl +slink +flicker +quiver +rustle +giggle +whisper +mumble +flutter +shimmer +crinkle +snicker +quaver +blaze +glare +blight +blush +whisk +chirp +bloom +clang +thud +wisp +flare +rumble +drift +way +brisk +gust +fleck +shrub +blurt +parch +whim +scour +pluck +squirm +glimpse +grasp +whisker +foam +breeze +thrum +hiss +mirth +dusk +fuzz +tusk +jolt +thrift +glint +trill +ridge +glimmer +purr +gleam +perch +grumble +rattle +puddle +glisten +mutter +nudge +spark +dabble +fizzle +dribble +flinch +crackle +throb +sputter +glide +nuzzle +green + +:: epithet +## A title, a moniker, a descriptor +Long-Beard +Silver-Shins +the Hanged +the Beetlekind +the Big +the Small +Long-Tongue +the Elder +the Younger +Tower-Master +who squashed the butterfly +Pig-Thief +The Man-Farmer +the Sage +the Wise +Thick-Thewed +the Red +the Black +the Blue +the White +the Golden +the White +the Gilt +the Guilty +the Snatcher +the Liar +the Fist +the Foot +the Fox +the Silent +of the Heptarchy +of the Greater Peace +the Flea +the Fool +of the Winterlands +the Swift +the Horse +the Snake +the Thrice-Cursed +the Yellow +the Howler +the Foul +the Unready +the Conqueror +the Ant +the Stone +the Feather +of the Great Jungle +of Many Colours +of Spindle-Spire +of the Depths +of the Deep Darkness +of Many Teeth +of Many Talents +the Smooth +the Notorious +the Coward +the Beggar +the Weak +the Spiteful +the Uncomely +the Fair +the Ape +the Worm +the Crawler +the Nobody +the Wit +the Wiseman +the Undertaker +the Ghoul +the Mole +the Vile +of Six-Fingers +the Hemicastrated +the Energumen +the Eunuch +the Beast +the Mad +the Weird +the Mouse +the Wrathful +the Monk +the Bulging +the Pumpkin +the Traitor +the Omnibenevolent +the Oaf +the Imbecile +the Witch-Sniffer +the Rake +of the Waters +of the Smokeless Fire +the Flagellant +the Arrow-Catcher +the Peculiar +the Slobberer +the One-Eyed +the Three-Eyed +the Twelve-Souled +the Fanged +the Bellringer +the Luxurious +the Unavoidable +the Unfortunate +the Caped +the Unmysterious +the Fateless +the First +the 88th +the Shrew +the Shrimp +the Shameful +the Shameless +the Usurper +the Gourmand +the Nice +the BeeBiter +the Salubrious +the Onanist +the Stork +the one who stalks panthers +the one who runs at night +the Night-Whistler +the Beast-Brained +the Clone +the Squid-Staker +the Gorilla-Charmer +the Debrained +the Half-Formed +the Whistler +the Onomatopoeic +the Needle-like +the Eel-Baiter +the Beautifier +The Slatternly +the Superior +the Defier +the Undefiled +the Narcissist +the Lowest Knave +The Lord of Men +the High-Hearted +the White-Armed +the Oread +the Man-Killer +the Albicant +the Amaranthine +the Eburnean +the Mazarine +the Sarcoline +the Xanthic +the Zinnober +the Nice Chap +the Conqueror +the Great +the Magician +the Sorcerer +the Sorceress +the Night-Walker +the Whisper in the Woods +the Enchantress +the Demon +the Dragon-Slayer +who is bound by many rings +the Groper +the Handler +the Marvellous +the Leaper +the Rake +the Puddle +the Precarious +the Unravelling +the Weeping +the Yellow +the Meaty +the Impaler +the Phlogistonal +the Magophile +the Striated +the Unfaltering +the Personable +the Human +the Benthic +the Challenger +the Fat +the Bald +the Twice-Murdered +the Burnt +the Second-Sighted +the Muscle +the Troll-Buster +Ill-Luck +Slender-Legs +the Fair-Haired +Axe-Nose +the Worm-Mouthed +the Mutagenised +the Pontifical +the Aberrant +the Abominable +who is like living fire +the Aggressionist +the Agrarian +the Antediluvian +the Bicephalist +the Plotter +the Absolute +The King-Killer +Broke-Nose +Spider-Eater +Nose-Picker +Parrot-Masher +Ink-Drinker +without whose consent no king ascends the throne +Prayer-Stealer +who boasts of his perfection +who is wife of the gods +who bathes in poison +the Bear-Butcher +the Bloated +who is as sweet as honey +Blood-Licker +Horse-Flesh +the Elastic +the Alarmist +whose warcry fills the enemy with fear +who shouts 'OOOBLARGHOO!' +the Apiarist +the Wake +who is like the effulgence of fire +who is unsullied by arrows +the Unborn Lord +the stealer of pure hearts +the Exuberant +the Resplendent +Gold-Groveller +whose blade hums for blood +who devours red roses +who endlessly utters "Ua, Ua, Ua!" +whose heart is iron +whose blood is black +the Alabaster +the Sinewy +the Tattooed +the Corsair +the Small-Brained +the Dust-Snorter +the Knife +the Self-Immolator +the Neck-Twister +the Arm-Breaker +the Snail +Battle-Butcher +Battle-Axe +the Sipahi +the Eunuch +Pasha +the Shah of Shahs +whose mantra is "[morpheme]-[morpheme]-[morpheme]" +who eats sand +the Clock-Winder +the Gravedigger +the Leech +the Star-Formed +the Formican +the Iron-Scribe +of the Teeth +Broken-Shins +the Beetling +the Cloud-Gazer +the Nephomancer +the Molybdomancer +the Star-Namer +who loves [morpheme][word] +who slew [morpheme][word] +the [morpheme][word] +of [morpheme]land +the [morpheme]man +the [morpheme]woman + +:: prefix +## A title, a descriptor, a vocation +Uncle +Mr +Miss +Mrs +Doctor +Professor +Captain +General +Master +Lord +Lady +Emperor +Chief +Count +Wild +Old +Young +Honest +Good +Bad +Poxy +Toothsome +Supple +Devilish +Sweet +Screaming +Brother +Father +Mother +Sister +Sour +Pickled +The Machine known as diff --git a/test/story.test.fnl b/test/story.test.fnl new file mode 100644 index 0000000..f9fe37a --- /dev/null +++ b/test/story.test.fnl @@ -0,0 +1,23 @@ +(let [{ + : flatten + : create-corpus + } (require :src.story)] + + (let [corpus (create-corpus "test/morpheme-word-epithet.txt") + origin-key :name + origin-table ["[morpheme][word] [epithet]" + "[prefix] [morpheme][word] [epithet]" + "[prefix] [morpheme][word]" + ] + origin-string "[morpheme][word] [epithet]" + get-story-with-key + (partial flatten corpus (. corpus origin-key)) + get-story-with-table + (partial flatten corpus origin-table) + get-story-with-string + (partial flatten corpus origin-string) + ] + (print "\n== Cast of Characters ==") + (for [_ 1 4] (print (get-story-with-key))) + (for [_ 1 4] (print (get-story-with-table))) + (for [_ 1 4] (print (get-story-with-string)))))