Le Yogi Tea à la cannelle et aux épices, c’est bien bon. Pour en faire une version maison, je mélange (pour 4 tasses) :
Quelques copeaux ou bâtons de cannelle,
Un cm3 de gingembre frais coupé en petits morceaux,
Trois gousses cardamone fendues,
Deux clous de girofle,
Un peu de poivre.
Faire bouillir le tout pendant 20mn - 1/2h fera un excellent thé de cannelle.
Variante rapide et économique
Si on manque de temps, ou qu’on préfère utiliser des ingrédients plus simples, on peut utiliser des ingrédients en poudre. Pour cela, je mélange (pour une tasse) :
A while ago Daka made a series of great Firewatch wallpapers. Then dynamicwallpaper.clup user Jagoba turned them into a nice macOS dynamic wallpaper for macOS.
However the previous dynamic wallpaper was timed to the clock – and so didn’t account for the current sunrise and sunset time at your location. Which means that during winter, the wallpaper would still be a bright blue while outside the night was already dark.
So I edited the wallpaper metadata, to make them dependant on the sun position rather than the time of the day.
Rather than computing the sun angle and elevation ourselves, an easiest way is to set the time and GPS position of the pictures. Wallpaper-makers can then automatically convert this time+location data into the sun angle and elevation.
First, the location. I chose the wallpapers to be in Shoshone National Forest, for obvious reasons.
Then, the time. The game takes place during summer 1989, so it seems like a good fit. I’ve arbitrarily chosen the 3rd of July 1989, which roughly matches the first days of the game.
Now we need to time the different wallpapers. For the middle of the night, this is easy enough: jut set the time to midnight. But for the various sunrise and sunset pictures, this is harder to define.
Which leaves us with interesting questions. For instance: at what time was the first light of dawn visible in Shoshone Forest on the 3rd of July 1989?
Turns out there are softwares that can tell the light of the day at a given time and location: planetariums. For instance, by using the atmosphere simulation of stellarium-web.org, we can get a rough idea of the time of each picture.
Here are the exact timing used for the wallpapers:
Firewatch 1 : 1989:07:03 22:00:00
Firewatch 2 : 1989:07:03 23:00:00
Firewatch 3 : 1989:07:03 04:50:00
Firewatch 4 : 1989:07:03 05:20:00
Firewatch 5 : 1989:07:03 07:00:00
Firewatch 6 : 1989:07:03 08:00:00
Firewatch 7 : 1989:07:03 19:30:00
Firewatch 8 : 1989:07:03 20:45:00
Firewatch 9 : 1989:07:03 21:10:00
macOS wallpaper engine will then use these informations to display the correct picture to you, depending on the season at your place. A little trickery though: if the middle-of-the-day picture is timed at 12:00, it’s sun elevation will be very high. Which means that during winter, when the sun is low, the wallpaper engine will simply skip this picture. To make sure the middle-of-the-day will be displayed even during winter, I inserted instead two pictures, timed early in the morning and late in the afternoon.
EDIT: I fixed some timing issues, and re-uploaded a new version under the name “Firewatch Sun”. It makes sure the ‘Sunset’ variant doesn’t start displaying too soon in the afternoon, even during winter.
I recently started toying with Gradual typing in Ruby.
Of course, Ruby is already typed: messages are dispatched to objects depending on their type. That’s dynamic typing, enforced at runtime.
But for larger programs, it can be useful to have some static type-checking, that can be enforced by a type-checker without running the whole program.
Enter type annotations. By adding some explicit informations about the expected types in our program, a type-checker will be able to catch some errors using a static analyzer.
What does it look like?
Gradual typing is not standardized in Ruby yet (although some efforts are ongoing). So there are different tools available. Currently, the best way to add gradual typing to Ruby programs seems to be Sorbet.
Here’s a simple Sorbet example, using an existing Ruby function:
defto_hex(i)"%x"%iend
We can add type informations to this function using the sig function decorator:
Granted, the syntax is a bit weird. But it has the merit of being valid Ruby code, which allows it to be accepted by the standard Ruby parser without modifications. And like many syntaxes that seem unusual at first, our eyes quickly get used to it (hi, Objective-C square brackets).
Letting “Gradual” shine
Now, the neat thing with gradual typing is that you don’t have to provide type informations everywhere. This is useful in many ways.
First, you may start adding type checks to an existing codebase. In that case, declaring all types from the start can be a daunting task. Fortunately, in the absence of types, the type-checker will consider that we know what you’re doing. Which means we can start adding a few types here and there, and already have useful type-checks – but the parts of the program which are still type-annotations-free will not results in warnings or errors.
Second, a lot of Ruby elegance and fun comes from its dynamic nature. Sometimes the most elegant way to express some code is to use dynamic method resolution, or other dynamic-oriented constructs which cannot be type-checked. And this is okay! In that case, gradual typing means you have an escape-hatch: as types are not mandatory, they just won’t be type-checked. We can get the benefits of type-checking for 95% of the code, and still use neat dynamic features in the remaining 5%.
And last, at times it can be useful to just experiment and prototype some code quickly, to see how the structure would look. In these cases, you won’t have to fight your way through types: you can just omit type annotations, and quickly let the code flow without thinking too much about production-ready reliability.
Experimenting with a standalone Ruby script
I’ve never used Sorbet before, so I wanted to start small, and get used to the type system.
Fortunately, the Sorbet website provides an online playground: just type in some Ruby code, add some type annotations, and the type checker will start telling you what’s right and wrong with the types you provided. Neat.
When I copy-pasted the script, without adding anything yet, Sorbet immediately told me about two errors: <function> is not available on NilClass (https://srb.help/7003).
Wow: it detected that in two different places, my code was sending a message to a potentially nil object. And gave me an URL to learn more about the issue.
How to fix this? I followed the URL, and a well-written document explained me that I could either:
Add a nil-check before sending a message to the object;
Or wrap the object in T.must(…), to tell the type-checker “Trust me, this will never be nil”.
So the two reported errors were easy to fix. I was quite impressed that Sorbet found two relevant mistakes without even starting to add types. And even more impressed that it not only does nil-checks, but also type propagation (that is, when some code checks if a value is nil, Sorbet considers that after this point the variable can not longer be nil).
Adding types
After this, I started adding type annotations to a single method (a constructor). That was easy enough: just a matter of adding the correct sig {…} incantation.
But right after that, Sorbet told me about a new error: my signature stated that the method argument was a String, but elsewhere I was calling the constructor with a T.Nilable(String) – that is, an object that may be nil. Interesting. Like before, to fix it, I had to add the proper nil check before calling the constructor.
I then gradually added type annotations to more methods, and found it almost fun. I had the feeling that I was strengthening my program, and uncovering the hidden assumptions that had been there before.
All of this went rather smoothly (except having to convert Ruby Structs, unsupported by Sorbet, into T::Structs). The weird syntax quickly became bearable, and eventually even read like being a part of the documentation.
Refactoring
In the end, this even led me to write better code. For instance, consider this function :
It extracts the two components of a semicolon-separated string – like 03:4A2F.
When adding type annotations, Sorbet initially told me “Hey, offset.to_i(16) is not valid on NilClass”. Because of course, it detected that if the input string is badly formatted, offset may be nil.
So I quickly wrapped the value in T.must(…), to silent the warning away. After all, there’s not so much we can do to prevent badly-formatted input; crashing at runtime seems a sensible option.
But wait, there’s better than crashing at runtime: and that’s “crashing at runtime with a meaningful error message”. What if we rely on nil-propagation to write instead:
Nice: a bad input now gives us a readable error message. And we can even remove the T.must checks, because, thanks to nil-propagation, Sorbet is now sure that offset.to_i(16) is not called on nil.
So far
After toying with the Sorbet’ playground, here are my first impressions:
The good
The online Playground
The expressive error messages
Nil-checking and nil-propagation
The quality of the documentation
Questions concerning Sorbet appear easily in search engines
The bad
Needing to rewrite some Ruby code (like Structs)
The ugly
Nothing yet
What’s next
For now I haven’t tried to type-check a program locally, nor to type-check code that relies on external gems.
So my next step is probably to add some minimal type-checking to a small Rails app, and see how Sorbet’s tooling deals with the many dynamic constructs of the framework.