diff --git a/docs/README.md b/docs/README.md index b68d0f3..7a0b9aa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -125,9 +125,9 @@ The `examples/` directory has a few demo bots to show how to use the module. - *ramenkan*: a bot that serves ramen. It has some custom config settings and scheduled tasks. -- *hachi*: a bot inspired by tracery text expansion. Loads files ("foils") - containing selection tables and creates handlers to return responses, one - service code per foil. +- *hachi* and *gordon*: bots inspired by tracery text expansion. Loads files + ("foils") containing selection tables and creates handlers to return + responses, one service code per foil. ## Running a bot as a background process diff --git a/examples/gordon/commands/borgar.lua b/examples/gordon/commands/borgar.lua new file mode 100644 index 0000000..7f7b314 --- /dev/null +++ b/examples/gordon/commands/borgar.lua @@ -0,0 +1,50 @@ +grammar = { + meat_set = { + "360 Burger with a large patty, tomatoes, cheddar and onions in a Dijon mustard sauce", + "Bada Boom cheeseburger with a juicy steak, cheddar, onions and tomatoes", + "Bag Baguette featuring two patties and Emmental cheese in a long crusty baguette", + "BagFirst Kitchen Ranch Ketchup burger with a spicy chicken patty in a cheddar ranch ketchup sauce", + "BB Cola burger with sausage, sweet peppers and Comté cheese with barbecue sauce", + "Beast Bacon Onion burger", + "Bigga Bag quadruple-patty burger", + "Gourmand Classic Chicago burger with two thick patties in a sweet and smoky BBQ sauce", + "Dig Tasty with a big steak, Emmental cheese in a smoky sauce", + "Double Cheese Docks with double patties, slices of bacon, cheddar and carmelised onions", + "Fermidable burger with a lightly grilled patty and stuffed with cheese", + "Krilled Cheese and Bacon burger", + "Itty Bitty Italian cheeseburger mozzarella, tomatoes and fresh herbs", + "Louisiana Ligature with double patties, bacon and cheddar, spiced up with a Louisiana sauce", + "Masterly Seasoned Ceasar classic burger with 2 steaks, bacon and extra salad", + "Pollo Loco with a chicken patty and mild avocado sauce", + "Pong Bacon burger with double patties and double cheese", + "Rippled Cheese Bacon burger with thrice the cheddar, grilled bacon and ketchup", + "Sausage Hopper with jalapeños and salsa", + "Stoked Pepper Stash Burger with tomatoes, cornichons, bacon and pepper sauce", + "Super Bacon burger", + "Vast Veggie burger with a veggie patty and Emmental cheese", + }, + veggie_set = { + "Veggie Thing overflowing with a spicy sauce", + }, + meat_side = { + "chicken fries", + "homemade fries with a dreamy deluxe dip", + }, + veggie_side = { + "chips deluged with ketchup", + "onion rings", + }, + dessert = { + "chocolate and hazelnut pie", + "lemon pie", + "set of 3 petit pancakes topped with hazelnut cocoa or strawberry cream", + }, + origin = { + "Here, have a #meat_set#!", + "Here, have a #veggie_set#!", + "Here, have a #meat_set#, served with a side of #meat_side#!", + "Here, have a #meat_set#, served with a side of #veggie_side#!", + "Here, have a #veggie_set#, served with a side of #veggie_side#!", + "Here, have a #meat_set#, served with a #dessert#!", + } +} diff --git a/examples/gordon/commands/burger.lua b/examples/gordon/commands/burger.lua new file mode 100644 index 0000000..40605d6 --- /dev/null +++ b/examples/gordon/commands/burger.lua @@ -0,0 +1,106 @@ +-- See also https://en.wikipedia.org/wiki/Burger +grammar = { + meat_patty = { + "Angus beef", + "chicken", + "lamb", + "portobello mushroom", + "pulled pork", + "sausage", + "steak", + "tuna mayonnaise rice", + "turkey", + "wagyu", + }, + veggie_patty = { + "coconut", + "nutty", + "possible", + "soy", + "tofu", + "veggie delight", + }, + veggie = { + "kimchi", + "jalapeño peppers", + "lettuce", + "onions", + "pickles", + "tomatoes", + }, + cheese = { + "cheddar", + "Beaufort", + "Cantal", + "Comté", + "Emmental", + "goat", + "mozzarella", + }, + -- May contain dairy + meat_sauce = { + "algerian sauce", + "andalousian sauce", + "bechamel sauce", + "burger sauce", -- Also known as Marie Rose/cocktail sauce + "moroccan sauce", + "samurai sauce", + "tartare sauce", + "tunisian sauce", + }, + veggie_sauce = { + "barbecue sauce", + "curry sauce", + "Dijon mustard", + "ketchup", + }, + meat_burger = { + "#meat_patty# burger with slices of #cheese# and dredged in #meat_sauce#", + "#meat_patty# burger with slices of #cheese# and dripping with #veggie_sauce#", + "#meat_patty# burger with #veggie# and #cheese# cheese in #meat_sauce#", + "#meat_patty# burger with #veggie# and oozing #cheese# cheese in #veggie_sauce#", + "#meat_patty# burger with #veggie#, #veggie# and #cheese# cheese in #meat_sauce#", + "#meat_patty# burger with #veggie#, #veggie# and #cheese# cheese in #veggie_sauce#", + "#meat_patty# burger with #veggie# and #veggie# in #meat_sauce#", + "#meat_patty# burger with #veggie# and #veggie#, glistening in #veggie_sauce#", + }, + veggie_burger = { + "#veggie_patty# burger with #veggie#, #veggie# and #veggie# in #veggie_sauce#", + }, + meat_side = { + "chicken nuggets", + "crispy mushrooms", + "mac and cheese", + "pasta salad", -- May contain cheese + "potato salad", -- May contain eggs/mayonnaise + "rosemary and garlic fries", -- Contains cheese + }, + veggie_side = { + "avocado salad", + "BBQ baked beans", + "BBQ potato chips", + "caesar salad", + "coleslaw", + "corn on the cob", + "corn salad", + "french fries", + "french potato salad", + "fried pickles", + "fried shishito peppers", + "a fruit bowl", + "onion rings", + "potato wedges", + "roasted tomatoes", + "sweet potato fries", + "a three-bean salad", + "tempura green beans", + "zucchini chips", + }, + origin = { + "Here, have a #meat_burger#!", + "Here, have a #veggie_burger#!", + "Here, have a #meat_burger#, served with #meat_side#!", + "Here, have a #meat_burger#, served with #veggie_side#!", + "Here, have a #veggie_burger#, served with #veggie_side#!", + } +} diff --git a/examples/gordon/commands/coffee.lua b/examples/gordon/commands/coffee.lua new file mode 100644 index 0000000..54fc2b9 --- /dev/null +++ b/examples/gordon/commands/coffee.lua @@ -0,0 +1,38 @@ +-- See also https://en.wikipedia.org/wiki/List_of_coffee_drinks +grammar = { + coffee = { + "black coffee", + "café allongé", + "café au lait", + "café cortado", + "café crema", + "café cubano", + "café miel", + "caffè americano", + "caffè corretto", + "cappuccino", + "caramel macchiato", + "Columbian coffee", + "dalgona coffee", + "doppio", + "egg coffee", + "espresso", + "espresso romano", + "frappuccino", + "iced cappuccino", + "iced mocha", + "Indian filter coffee", + "Irish coffee", + "Kona coffee", + "kopi tubruk", + "Kurdish coffee", + "latte macchiato", + "marocchino", + "pocillo", + "ristretto", + "Turkish coffee", + }, + origin = { + "Here's your cup of #coffee#!" + } +} diff --git a/examples/gordon/commands/pie.lua b/examples/gordon/commands/pie.lua new file mode 100644 index 0000000..6d9bf22 --- /dev/null +++ b/examples/gordon/commands/pie.lua @@ -0,0 +1,87 @@ +-- https://www.quoteambition.com/gordon-ramsay-quotes/ +-- https://graciousquotes.com/gordan-ramsay/ +-- https://masterchef.fandom.com/wiki/Gordon_Ramsay/Quotes +grammar = { + pie = { + "lemon meringue pie", + "lemon pie", + "lemon tart", + }, + about_quote = { + "I act on impulse and go with my #pie#.", + "I actually love vegan #pie#s.", + "I am a #pie# who happens to appear on IRC, that's it.", + "I am the most unselfish #pie# in Britain today.", + "I am what I am. A #pie#.", + "I don't have a temper, I have #pie#.", + "I have to laugh when someone calls me a #pie#. " .. + "I've been called way worse.", + "I taste like a #pie# and I have an amazing kick!", + "I'd like to think I'm a great #pie#.", + "I'm Gordon-sama, for goodness sake people know I'm a #pie#!", + "I'm not the one to sort of sit and cry over spilt custard. " .. + "I'm too busy looking for the next #pie#.", + "I'm quite a chauvinistic #pie#.", + "I've had a lot of #pie#s, I've had #pie#s, so I learn from the " .. + "#pie#.", + "I've got #pie#s to hide.", + }, + advice_quote = { + "A #pie# doesn't have to be a formula. " .. + "A #pie# is about having fun. I get really frustrated when " .. + "it's badly done.", + "Being a #pie# is the best job in the world!", + "Don't take #pie#s personally. Just take them seriously.", + "I mean, #pie#s are weird.", + "I think #pie#'s healthy, and very few can handle it.", + "If you want to become a great #pie#, " .. + "you have to work with great #pie#. And that's exactly what I did!", + "It's vulgar, coming from where I do, to talk about #pie#s.", + "Kitchens are hard environments and they form incredibly strong #pie#s.", + "My #pie#, I'm sorry to say, is full of muppets.", + "Never throw that genius stuff away.", + "No one saw the #pie# coming.", + "*voicing Captain Obvious* " .. + "Stopping the junk food and eating #pie# is partially about " .. + "cooking #pie# and having the skills to do that.", + "Two key ingredients in any successful #pie#: a quick #pie# and " .. + "someone with a sharp #pie#.", + "They say cats have 9 #pie#s. " .. + "I've had 12 already and I don't know how many more I'll have.", + "Push your #pie# to the absolute extreme!", + "Swearing is an industry language. " .. + "For as long as we're alive it's not going to change. " .. + "You've got to be boisterous to get #pie#!", + }, + insult_quote = { + "All #pie#s are nutters. They're all self-obsessed, delicate, " .. + "dainty, insecure little souls and absolute psychopaths. " .. + "Every last one of them!", + "For what you are about to eat, " .. + "may your #pie# make you truly not vomit!", + "I f—ing love you.", + "I wish you would jump in the #pie#! " .. + "That would make my life a lot easier!", + "Get your #pie# together, or f— off and feed the giraffe.", + "Let me whisper something very important in your ear, ".. + "very important: F— off.", + "That should come with a health warning, 'Do Not Open in Broad Daylight'.", + "The problem with #pie#s is they are wimps.", + "This #pie# is so disgusting, ".. + "if you take it to France you'll get arrested.", + "This #pie# is so undercooked I can still hear it singing " .. + "'Lemon Tree'.", + "This isn't a #pie#, this is a mistake. This is a French tragedy!", + "You're getting your #pie#s in a twist! Calm down!", + "You're not a quitter? You're not a f—ing #pie# either!", + "You're such a f—ing #pie#.", + "You guys cook like #pie#s f—.", + "Would you like some #pie#? F— off, it's mine.", + "You know how arrogant the #pie#s are — extraordinary.", + }, + origin = { + "Here's your #pie#. Me? #about_quote#", + "Here's your #pie#. #advice_quote#", + "Here! #insult_quote#", + } +} diff --git a/examples/gordon/commands/tacos.lua b/examples/gordon/commands/tacos.lua new file mode 100644 index 0000000..ddfa3d5 --- /dev/null +++ b/examples/gordon/commands/tacos.lua @@ -0,0 +1,83 @@ +-- Based on lucidiot's notes +grammar = { + m_size = { "M", "simple" }, + l_size = { "L", "double" }, + xl_size = { "XL", "triple" }, + xxl_size = { "XXL", "mega" }, + meat = { + "chicken breast", + "chicken fingers", + "chicken nuggets", + "cordon bleu", + "falafel", + "fish sticks", + "ground beef", + "merguez", + "kofta", + "raclette", + "shakshouka", + "shawarma", + }, + topping = { + "bacon", + "blue cheese", + "cheddar", + "chorizo", + "diced pork", + "eggs", + "emmental", + "goat cheese", + "grated cheese", + "honey", + "mozzarella", + "mushrooms", + "olives", + "pepperoni", + "peppers", + "raclette", + }, + sauce = { + "aioli", + "algerian", + "andalousian", + "barbecue", + "bechamel", + "burger", + "cheese", + "curry", + "fish", + "harissa", + "mayonnaise", + "moroccan", + "mustard", + "tartare", + "tunisian", + "samurai", + }, + sauce_verb = { + "bathed in #sauce# sauce", + "dripping with #sauce# sauce", + "drizzled with a #sauce# sauce", + "in a #sauce# sauce", + "soaked in a #sauce# sauce", + "swimming in #sauce# sauce", + }, + origin = { + "Here! A #m_size# #meat# tacos with #topping# #sauce_verb#!", + "Here! A #l_size# #meat# and #meat# tacos with #topping# and #topping# " .. + "#sauce_verb#!", + "Here! A #xl_size# tacos with #meat#, #meat#, #meat#, #topping# " .. + "#sauce_verb#!", + "Here! A #xxl_size# tacos with #meat#, #meat#, #meat#, #topping# and " .. + "#topping# #sauce_verb#!", + "Here! A #m_size# #meat# tacos #sauce_verb#!", + "Here! A #m_size# #meat# tacos with #topping# and #topping#, " .. + "#sauce_verb#!", + "Here! A #l_size# tacos #meat# and #meat# #sauce_verb#!", + "Here! A #l_size# #meat# and #meat# tacos with #topping# #sauce_verb#!", + "Here! A #xl_size# chihuahuacos with #meat#, #meat#, #meat#, " .. + "#topping# and #topping# #sauce_verb#!", + "Here! A #xxl_size# chihuahuacos with #meat#, #meat#, #meat# and " .. + "#meat# #sauce_verb#!", + } +} diff --git a/examples/gordon/commands/tea.lua b/examples/gordon/commands/tea.lua new file mode 100644 index 0000000..362ee0f --- /dev/null +++ b/examples/gordon/commands/tea.lua @@ -0,0 +1,53 @@ +-- See also https://en.wikipedia.org/wiki/Tea +grammar = { + en_tea = { + "Builder's tea", + "Earl Grey", + "English afternoon tea", + "English breakfast", + "Irish breakfast", + "milk tea", + "orange pekoe", + "Prince of Wales", + }, + jp_tea = { + "genmaicha", + "gyokuro", + "hojicha", + "matcha", + "sencha", + }, + tea = { + "Burmese milk tea", + "masala chai", + "Thai tea", + "butter tea", + "kombucha", + "black tea", + "green tea", + "white tea", + }, + -- Tea not derived from Camellia sinensis + herbal_tea = { + "barley tea", + "chamomile tea", + "corn tea", + "ginger tea", + "ginseng tea", + "maté", + "peppermint tea", + "rooibos", + "rose tea", + }, + cup = { + "bowl", + "cup", + "mug", + }, + origin = { + "Here's your cuppa #en_tea#!", + "Here's your cup of #jp_tea#!", + "Here's your #cup# of #tea#!", + "Here's your #cup# of #herbal_tea#!", + } +} diff --git a/examples/gordon/folia.lua b/examples/gordon/folia.lua new file mode 100644 index 0000000..5f4e7b7 --- /dev/null +++ b/examples/gordon/folia.lua @@ -0,0 +1,79 @@ +local util = require("itteutil") + +-- Default settings +local folia = { + foils_dir = "", + debug = false, +} + + +util.docs.get_foils = [[ (directory_str) + Given the full path to a directory of foils, return the foil contents as a + table. + ]] +function folia.get_foils(str) + local foil_list_str = io.popen("ls " .. str) + local foils = {} + if foil_list_str then + local foil_list = util.split_str(foil_list_str:read("*a")) + for i = 1, #foil_list do + local key = string.gsub(foil_list[i], ".lua", "") + local func, err = loadfile(str .. "/" .. foil_list[i]) + if func then + func() + foils[key] = grammar + end + end + -- Unset global variables + func = nil + grammar = nil + end + return foils +end + + +util.docs.output = [[ (key_str) + Given a foil name or foils table key, output a random expanded string. + ]] +function folia.output(key) + local foils = folia.get_foils(folia.foils_dir) + if table.concat(util.table_keys(foils), "") == "" then + util.debug("output", "Error: cannot retrieve foils." .. + " Please make sure the full directory path is correct.", folia.debug) + do return end + elseif not util.has_key(foils, key) then + util.debug("output", "Error: the key `" .. key .. + "` is not in the foils table.", folia.debug) + do return end + elseif not util.has_key(foils[key], "origin") then + util.debug("output", "Error: no origin found in the foil.", folia.debug) + do return end + elseif foils[key]["origin"] == {} then + util.debug("output", "Error: empty origin.", folia.debug) + do return end + end + + local output_str = util.pick(foils[key]["origin"])[1] + local pattern = "#(%w+_*%-*%w+)#" + util.debug("output", "level 1: " .. output_str, folia.debug) + -- Check for expansion objects and replace them until none are found + while string.find(output_str, pattern) ~= nil do + local hash = output_str:sub(string.find(output_str, pattern)) + local obj = hash:sub(2, #hash - 1) + -- Check the object key is in the foil grammar, and replace one instance + -- at a time. + if util.has_key(foils[key], obj) then + local expand_str = util.pick(foils[key][obj])[1] + output_str = string.gsub(output_str, hash, expand_str, 1) + util.debug("output", "level n: " .. output_str, folia.debug) + -- If the object key is not in the grammar, replace references with a + -- placeholder. + else + output_str = string.gsub(output_str, hash, "[" .. obj .. "]") + end + end + return output_str +end + + +return folia diff --git a/examples/gordon/gordon.config.lua b/examples/gordon/gordon.config.lua new file mode 100644 index 0000000..5e8daa9 --- /dev/null +++ b/examples/gordon/gordon.config.lua @@ -0,0 +1,40 @@ +local irc = require("itte") +local folia = require("folia") + +itte_config = { + debug = false, + messages = { + help = "Don't just stand there like a big f—ing muffin! " .. + "Order something! Your Casa's Kitchen commands are: {{codes}}", + quit = "Master Chef under maintenance.", + reload = "Config reloaded.", + }, +} + +itte_handlers = {} + +folia.foils_dir = "/home/mio/bin/itte/examples/gordon/commands" + + +local gordon = {} + + +-- Create handlers for each foil +function gordon.generate_handlers(handlers, foils_dir) + local foils = folia.get_foils(foils_dir) + for key, foil in pairs(foils) do + handlers[key] = function (cxt, msg) + irc.message(cxt, { msg.reply_to }, folia.output(key)) + end + end + + -- Add aliases + if folia.output("coffee") ~= nil then + itte_handlers.cofe = function (cxt, msg) + irc.message(cxt, { msg.reply_to }, folia.output("coffee")) + end + end +end + + +gordon.generate_handlers(itte_handlers, folia.foils_dir) diff --git a/examples/gordon/gordon.lua b/examples/gordon/gordon.lua new file mode 100644 index 0000000..3d5784e --- /dev/null +++ b/examples/gordon/gordon.lua @@ -0,0 +1,4 @@ +local gordon = require("itte") +gordon.confs.prefix = "gordon" + +gordon.run() diff --git a/examples/gordon/gordon.service b/examples/gordon/gordon.service new file mode 100644 index 0000000..5a3e69d --- /dev/null +++ b/examples/gordon/gordon.service @@ -0,0 +1,11 @@ +[Unit] +Description=gordon — a vending machine IRC bot + +[Service] +WorkingDirectory=%h/bin/itte/examples/gordon +ExecStart=/usr/bin/lua ./gordon.lua +Restart=always +RestartSec=300 + +[Install] +WantedBy=default.target diff --git a/examples/hachi/folia.lua b/examples/hachi/folia.lua index d99af35..5f4e7b7 100644 --- a/examples/hachi/folia.lua +++ b/examples/hachi/folia.lua @@ -54,7 +54,7 @@ function folia.output(key) end local output_str = util.pick(foils[key]["origin"])[1] - local pattern = "#(%w+)#" + local pattern = "#(%w+_*%-*%w+)#" util.debug("output", "level 1: " .. output_str, folia.debug) -- Check for expansion objects and replace them until none are found while string.find(output_str, pattern) ~= nil do