It’s time for another Sous development update, this post’s theme being “better late than never.” Truth be told I’ve been suffering from some wicked burnout since the previous update, and haven’t been left with much energy in my free time to work on the project. That said, I’m now back in the game for the home stretch of the month, with some decent progress to chat about today.
Re-evaluating Goals Link to heading
A bit of housekeeping, first off. Here’s a quick recap of my original goals for the month:
- A reusable core library implementing data structures, conversions, and backend storage.
- A command line frontend for scriptable display and conversion.
- A GUI for everyday browsing and display, with a full-featured editor built-in.
While there is some good progress to show on the former two items, it’s pretty clear at this point that a quality GUI is not in the cards. I likely still won’t be able to achieve the lofty flexibility goals of the core library with the time I have left in the month, but a usable system and a solid base on which to continue development is definitely attainable.
Code Cleanup Link to heading
As I picked back up on the project, I first took some time to clean things up a bit.
The core Sous library and the frontend CLI have been separated into separate Rust modules, with the library further broken into a handful of submodules. While Sous as a whole isn’t large enough yet to warrant separate repositories (or multiple crates glued together by Cargo’s workspace system), this will allow me to make quick work of that task when the time comes.
As a part of separating the library and binary code, I’ve adopted some common
Rust error handling practices. All errors that the library expects are now
wrapped in a SousError
enum, utilizing the well-traveled crate
thiserror. This allows any
function that may result in an error to return a single Result
type, leaving
the client code to decide what to do.
More Structs Link to heading
The core Recipe
struct still only contains three fields, but encodes much
more information.
A Metadata
struct stores the recipe’s name, author, serving count, and
estimated cook time. A source URL and estimated prep time can also optionally
be set.
While the method is still internally stored as a simple Vec<String>
,
ingredients now have their own struct. The only required field is a display
name, with an optional unit and amount included in the render if set.
Markdown Rendering Options Link to heading
A new RenderSettings
struct has been added to control the Markdown output
when rendering a recipe. It currently has options to omit individual sections
and override the default serving yield (which also recalculates ingredient
amounts).
Later on I plan to add options for overriding header text and replacing the pure Markdown title section with front matter appropriate for tools like static site generators or Pandoc.
CLI Trimming and Options Link to heading
Not a lot of excitement on the CLI side of the world aside from adding options
hooked up to the new rendering settings. In fact, the main.rs
has been
trimmed down to less than 50 lines.
As mentioned earlier, I’m paring down expectations for the end of the month. My current goal over the next few days is to implement the concept of a cookbook – a group of recipes that can be acted upon in bulk. From there I aim to support converting an entire cookbook into a format that can be ingested by a different system for prettier rendering (current thoughts are a single PDF via Pandoc, or a static website with Hugo), and scripting the whole process.
My next update (likely sometime late next week) will serve as a postmortem for the month, and with my personal challenge done I’ll be doing any further development out in the open.