One of the biggest goals of Tourmaline since its inception has been to make things easier on the bot developer, while also limiting the possibility of runtime exceptions that cause the bot to go down. Those are both reasons why I chose Crystal as the language to build this framework on, as it's both easy to use with a beauitful syntax, and compiled with a strong type system which keeps you (for the most part) from making mistakes that could prove fatal during runtime. Well today I'm happy to announce a couple changes to the framework itself that should also serve to make life easier on you, the bot developer.
Bye Bye Filters
This most recent update, v0.20.0 removes the concept of the
Filter. As announced in the release notes, the main issue with them was trying to allow a developer to receive information about the update being filtered. I tried to solve this using
Update#context, but it was majorly limited and pretty messy. As I was working on my other Telegram related project Proton, which I've tried to structure in a very similar way to Tourmaline, I figured out a way to do make handlers work in a much less messy way than before.
You see, prior to introducing filters several releases back, we had handlers. They worked for the most part, but had a couple issues. The main, overarching issue was that the original handler implementation wasn't very extendable.
EventHandler, which was the base handler class, was a normal class that was in charge of all annotations and made handlers themselved kind of messy. So how is this time around different?
First of all,
EventHandler is now abstract and does two things. First of all it has an abstract definition
call(update : Update) which extending handlers need to implement. It also still, in a way, handles all annotations, but it does it in a much more abstract fassion. Let's take a look at some code:
This is a module included within the
EventHandler class and included by
Client and it's responsible for one thing: finding subclasses of
EventHandler and calling the
self.annotate method on those classes. This allows handlers to manage their own annotations! The Current list of implemented handlers is as follows:
InlineQueryHandler, and the standard
Most handlers also include their own
Context struct which holds all the data that normally would've been passed to the
UpdateContext by a filter. I like this approach better because it allows handlers to control what data they pass to their calbacks.
One of the most common tasks for any bot developer is creating menus using
InlineKeyboardMarkup, and it can get pretty difficult when those menus include multiple levels, back buttons, etc. For those types of situations I have created the
RoutedMenu helper class. Let's start with a usage example:
If I succeeded in my goal, which is making an easy to use and easy to understand DSL for menu creation, it should be extremely obvious what the above code does. First we build a menu using the
RoutedMenu.build DSL. Think of each
route call as creating a page, because that's literally what it does. The
route call exposes another DSL that allows you to build the page using the
buttons methods, etc etc.
RoutedMenu also adds a new set of methods for sending those menus including
And that's about it. There is also
PagedKeyboard which was introduced a couple updates back, webhook support without Kemal has been improved, and speed has been increased, but those are all secondary.
Thanks for using Tourmaline!