My OSS work in March was a bit of a grind, but I made progress nonetheless. I worked mostly on relocating and refactoring the Hanami action and view integration code.
For some context, it was back in May 2020 that I first write the action/view integration code for Hanami 2.0. Back then, there were a couple of key motivators:
Hanami::Viewwithin a slice would give you a view class fully integrated with the Hanami application.
Since then, we’ve learnt a few things:
Once I finished my work on the concrete slice classes last month, I decided that now was the time to address these concerns, to bring the action and view class integrations back into the hanami gem, and to take a different approach to activating the integration code.
The work in progress is over in this PR, and thankfully, it’s nearly done!
The impact within Hanami 2 applications will be fairly minimal: the biggest change is that your base action and view classes will now inherit from application variants:
# slices/main/lib/action/base.rb require "hanami/application/action" module Main module Action class Base < Hanami::Application::Action # Previously, this inherited from Hanami::Action end end end
By using this explicit application superclass for actions and views, we hopefully make it easier for our users to understand and distinguish between the integrated and standalone variants of these classes. This distinct superclass should also provide us a clear place to hang extra API documentation relating to the integrated behavior of actions and views.
More importantly for the overall experience,
Hanami::Application::View are both now kept within the core hanami gem. While the framework heads into this final stretch of work before 2.0 final, this will allow us to keep together the aspects of the integration that tend to change together, giving us our best chance at providing a tested, reliable, streamlined actions and views experience.
This is a pragmatic move above all else — we’re a team with little time, so the more we can do to give ourselves confidence in this integrated experience working properly, like having all the code and tests together in one place, the quicker we should be able to get to the 2.0 release. Longer term, we’ll want to provide a first-class integration story for third party components, and I believe we can lead the way in how we deliver that via our actions and views, but that’s now firmly a post-2.0 concern in my mind.
In the meantime, I did take this opportunity to rethink and provide some better hooks for classes like
Hanami::Application::View to integrate with the rest of the framework, chiefly via a new
Hanami::SliceConfigurable module. You can see how it works by checking out the code for
# frozen_string_literal: true require "hanami/view" require_relative "../slice_configurable" require_relative "view/slice_configured_view" module Hanami class Application class View < Hanami::View extend Hanami::SliceConfigurable def self.configure_for_slice(slice) extend SliceConfiguredView.new(slice) end end end end
Any class that extends
Hanami::SliceConfigurable will have its own
.configure_for_slice(slice) method called whenever it is sublcassed within a module namespace that happens to match the namespace managed by an Hanami slice. Using the
slice object passed to that hook, that class can then read any slice- or application-level config to set itself up to integrate with the application.
In the example above, we extend a slice-specific instance of
SliceConfiguredView, which will copy across application level view configs, as well configure the view’s part namespaces to match the slice’s namespace. The reason we build a module instance here (this module builder pattern is a whole technique that I’ll gladly go into one day, but it’s a little out of scope for these monthly updates) is so that we don’t have to keep any trace of the
slice as state on the class after we’re done using it for configuration, making it so the resulting class is as standalone as possible, and not offering any way for its users to inadvertently couple themselves to the whole slice instance.
Overall, this change is feeling quite settled now. All the code has been moved in and refactored, and all that’s left is a final polishing pass before merge, which I hope I can get done this week! A huge thank you to Sean Collins for his original work in proposing an adjustment to our action integration code. It was Sean’s feedback and exploratory work here that got me off the fence here, and made it so easy to get started with these changes!
That’s it for me for now. See you all again next month, hopefully with some more continued core framework polishing.