Adding a resolve method to the View module
I've had an issue recently where I've wanted to create "component" classes that are essentially POROs which return an HTML component (say a modal, button or form) using the HtmlBuilder.
Initially we defined them as methods on our view objects, but that didn't allow us to share them across multiple views.
Then we created modules which could be included in the views, but they weren't ideal for two main reasons: 1) we didn't need to explicitly pass in the required variables - they were just available - but it felt wrong to not pass them in too, and 2) we couldn't define private methods that wouldn't leak into the rest of the view and included modules. This was particularly an issue when multiple components of the same type might require the same method, such as fetch_header_text.
Elsewhere in the app we have implemented a similar idea to wrap up common form elements, and we've been able to achieve this nicely because of the resolve method that exists on both FormBuilder and HtmlBuilder in Hanami Helpers. It works something like this:
module Web
module Views
module Users
module Common
module FormDetails
def form_details(context:)
context.resolve do
div class: 'row' do
div class: 'input-field col s12' do
text_field :name
label 'Name', for: :name
end
end
end
end
end
end
end
end
end
And then to call it:
module Web
module Views
module Users
module Common
module NewForm
include Web::Views::Users::Common::FormDetails
def new_form(entity)
form_for :entity, routes.entity_path(entity.id) do
form_details(context: self)
div do
submit 'Create'
end
end
end
end
end
end
end
end
We want to do this but with classes, and from the View module. Without being able to resolve the context it would mean appending all the view methods with context., which is less than ideal. As a test I added the same resolve method to it:
def resolve(&blk)
@context = eval('self', blk.binding, __FILE__, __LINE__)
instance_exec(&blk)
end
This achieved everything we needed. Can we add this into the View module?