-
Notifications
You must be signed in to change notification settings - Fork 31
Description
So, let me begin by saying that this gem is wonderful. The API is elegant, the code is precise and concise, and the functionality is very helpful. In fact, I have found this gem so wonderful that it has inspired me to build on top of it. I will probably be opening a few Issues as spaces to discuss some feature ideas that I have had and implemented. If it is helpful at all, I have my own, fairly radically altered version of the layout_helper.rb file that I am using in a project where all of the features I have added are implemented. I have made the file a gist. If you think any particular feature is worth bringing into nestive, though, I will work to make an individual PR for just that feature. This is the first such feature idea, and it concerns adding scope/context to the buffer (the @_area_for hash),
One of the best features of the codebase is its simplicity. The core functionality lives in one file, the code paths are clear and direct, and the implementation is immediately understandable. The central implementation detail is the array of instructions in a "buffer" hash under the key name of the area. One limitation that I immediately ran into, however, is that such a hash (only ever one level deep) does not allow for name collisions. So, if I have a complex layout where there are various sections in which some part may conceptually be the "title" for that section, I must name each area with a fully descriptive name (e.g. :section1_title and :section2_title); that is, I have to scope the context in a prefix in the name of the area. To my mind, what would be preferable is to simply nest areas:
<%= area :section1 do %>
<%= area :title, 'Section 1 Title' %>
<% end %>
<%= area :section2 do %>
<%= area :title, 'Section 2, Title' %>
<% end %>The gem currently, given such a layout, would have an @_area_for hash that looked like:
{
:title=>[[:push, "Section 1 Title"], [:push, "Section 2, Title"]],
:section1=>[[:push, "\n Section 1 Title\n"]],
:section2=>[[:push, "\n Section 2, TitleSection 1 Title\n"]]
}So, the first feature I wanted to implement was a context-aware buffer hash. The implementation would be to have an N-level hash of hashes. So, for the dummy example, we would have a hash that looked like this:
{
:section1=>{
:title=>[[:push, "Section 1 Title"]]
},
:section2=>{
:title=>[[:push, "Section 2, Title"]]
}
}This is achieved by keeping a queue and pushing an area on when the method begins and then popping it off right before the method returns. So, if, in the capture(&block), the area method is called again, it's parent area lives in the queue, and the child is pushed onto the queue after it. We then use this queue along with an auto-vivifying hash for the buffer and the new Ruby Hash.dig method to create the buffer (so, in our example, @_buffer.dig(*[:section1, :title]) would eventually get called, where @_buffer is an auto-vivifying hash). We can get into finer-grained implementation details later if this is a path you would be interested in pursuing.
What it provides, IMO, is a more flexible and expressive API for constructing layouts. Now, not only are layouts nestable, but the areas are too. In my gist file, I have implemented this by creating new helpers (section and within) and there are some specific issues for this kind of feature that are addressed in the code for those methods, but if you like the idea, I would try to implement this directly on top of the area API and nothing more.
Let me know what thoughts or questions you have. I know that this is a fairly large feature change that has numerous implications, and I've only briefly sketched out the implementation. But I wanted to start with the basics and see if you'd even be interested in pursuing this feature before really diving in.