Updates in the Athenaverse - tab completion, progress bars, oh my!

Updates in the Athenaverse

This update is a bit unique in that there is no grandiose refactor that architecturally moves the framework forward, but is instead more focused on polishing/improving upon what is already there. There is however a major focus on the Console Component, with many exciting new features being introduced.

Demo Application

The Skeleton repository was introduced in the last update as a way to get started with the framework more quickly. I’m pleased to announce the introduction of the new Demo Application that expands on the idea of the skeleton, but with a fully runnable example application. The demo application is a simple blog REST API application that can be used as reference to see what an Athena Framework application, including tests, looks like. It also serves as a good somewhat real world example that can be used to play test proposed changes.

Console

The console component had quite a lot of development as of late. Both in regards to new features, as well as fixing some bugs. Let’s dive right in!

Native Tab Completion

One of the more exciting features is the console component now supports native tab completion for both built-in and user-defined commands. It is also fully integrated into the commands provided by the framework component.

NOTE: For performance reasons, this feature is currently limited to real compiled binaries only. This may possibly change when/if the interpreter becomes more robust.

Using the demo application as an example, which provides a bin/console binary out of the box (if you want to follow along it can be built via shards build). We first will want to generate and source the completion helper script:

$ ./bin/console completion > completion.sh
$ source completion.bash

The completion script will detect your shell based on $SHELL and generate the proper file for your shell (bash, zsh, or fish). This file can then be sourced directly, or moved to a location where it would be sourced automatically for all new shells going forward. Run ./bin/console completion --help for more information on this aspect.

And that’s it! The console binary will now tab complete command names, option names, and option/argument values if possible as we can see here:

out

Plus, because this is native tab completion, performance is very speedy and is able to handle large amounts of data, so no need to do any filtering within your command itself.

Progress Bars and Indicators

While it’s hard to follow tab completion, another feature I’m elated to announce is the ability to render progress bars and progress indicators. These are a great way to keep the user informed of the progress of the currently running task. Or in the case of indicators, at least let the user know progress is still being made, even if it is not known when it will finish.

Progress Bars

Progress bars can be nearly fully customized. In the following example we customize the format to leverage some emojis, span multiple lines, what the characters that make up the bar should be, and various messages to show as things progress.

Progress Bar

Code
bar = ACON::Helper::ProgressBar.new output, 15
bar.format = %(<fg=cyan> %title:-37s% </>\n %current%/%max% %bar% %percent:3s%%\n 🏁  %remaining:-10s% %memory:24s%)
bar.bar_character = "<fg=green>▓</>"
bar.empty_bar_character = "<fg=red>░</>"
bar.progress_character = ""

bar.set_message "Starting the demo... fingers crossed", "title"
bar.start

15.times do
  bar.advance

  case bar.progress
  when  6 then bar.set_message "Looks good to me...", "title"
  when 15 then bar.set_message "Thanks, bye", "title"
  end

  sleep 0.2
end

bar.finish

Custom formats and placeholders may also be defined as needed. The built-in Athena Style also exposes an API to use a progress bar in the Athena suggested style.

Progress Indicators

Progress indicators on the other hand, are a lot simpler. They simply spin showing that progress is not stalled, without any progress information.

img

The characters used for the animation can be controlled, as can the format.

Output Sections Max Height

Output sections are a neat little feature that’s been around for a while that enables having creating sections that can be written to and cleared independently of one another. This can be useful to display multiple progress bars for example.

Output sections now have a feature in which their maximum height can be limited, causing the contents to scroll, for example with a height of 3:

img

The height can be changed at any time, and even removed which causes the scrolled text to display all at once.

Bug Fixes

Various bugs, mainly related to incorrect display alignment/formatting have also been squashed in the latest release. See the release notes for more information.

Framework

While most of the work has been focused on the console component, the framework component has also seen some nice new features/fixes.

Trailing Slashes

A common gotcha for those new to Athena Framework has been in how trailing slashes in routes are handled. Defining a route such as /user/{id} IS different than /user/{id}/ and as such would cause a 404 if your route has a trailing slash but the request does not, or vice versa. This scenario is now more gracefully handled by redirecting GET and HEAD requests with a trailing slash to the route without one if it exists, and vice versa. The best practice is still pick one way and be consistent, given other HTTP methods do not have this same treatment.

Multiple Route Annotations

It is now possible for a single controller action to have more than one routing annotation:

class MultipleRoutesSingleMethod < ATH::Controller
  @[ARTA::Get("/multiple-routes")]
  @[ARTA::Post("/multiple-routes")]
  @[ARTA::Route("/multiple-routes", methods: "PATCH")]
  def action : Nil; end
end

This can be useful in certain cases, tho it is still a best practice to have a more 1:1 relationships between routes and methods.

Clock

Last but not least, a new component has been introduced and already integrated into the other components as needed. The Athena::Clock component decouples an application from the system clock, making testing time-sensitive logic much easier. It also provides the ability for different types of clocks to be used depending no the use case, while not having the change anything in the underlying implementation.

class ExpirationChecker
  def initialize(@clock : Athena::Clock::Interface); end

  def expired?(valid_until : Time) : Bool
    @clock.now > valid_until
  end
end

clock = ACLK::Spec::MockClock.new Time.utc 2023, 9, 16, 15, 20
expiration_checker = ExpirationChecker.new clock
valid_until = Time.utc 2023, 9, 16, 15, 25

# valid_until is in the future, so not expired
expiration_checker.expired?(valid_until).should be_false

# Sleep for 10 minutes, so time is now 2023-09-16 15:30:00,
# time is instantly changes as if 10 minutes really passed
clock.sleep 10.minutes

expiration_checker.expired?(valid_until).should be_true

# Time can also be shifted, either into the future or past
clock.shift minutes: -20

# valid_until is in the future again, so not expired
expiration_checker.expired?(valid_until).should be_false

Administrative

Taking a step back from the code, the Athena ecosystem now includes CONTRIBUTING.md and UPGRADING.md files as applicable. For example, for information on how to upgrade to this newest version of the console component, checkout it’s UPGRADING.md. Or for more general information on how Athena handles versioning, checkout the monorepo’s UPGRADING.md. This text will be hidden

18 Likes

Huge! :clap: :clap: :clap:

1 Like

As a reminder, Athena components are all independent from one another. Totally could use the clock, or console, etc in your project even if you’re using another framework, or no framework at all. It is not a requirement to use the entire framework just so you can use one piece of it. But of everything works the best when used together.

4 Likes