In this post I use several tools to find my way to what I hope to be the answer to an initial question.
There are two repositories of interest:
- A Hyku Repository
- A Hyrax-application
- Hyrax
- A Rails engine
The Hyku Repository mounts the Hyrax Engine; providing much of it’s functionality.
I also use a few command-line tools:
- rg
- “recursively searches directories for a regex pattern while respecting your gitignore”; a super speedy alternative to the venerable
grep
command. (see the source code) - git
- the ubiquitous distributed source control tool
Instead of rg
, you could use ag
(aka the Silver Searcher).
And as always, I’m relying on Emacs 📖 for viewing files. The git-link package helps me quickly select a region of code and generate a remote link (e.g. a link to Github to the current commit of the selected region).
Now, with the preliminaries out of the way, let’s dive into the journey through two code-bases.
The Walk Through
A team member wanted to know in the Hyku repository what items
were available in app/views/hyrax/base/_collections_parent_row.html.erb
(see code here):
<!--<dt> <%#= t(".label", type: type.humanize) %> </dt>-->
<dt>Collection</dt>
<dd>
<% if items.blank? %>
<p><%= t('.empty', type: type.humanize) %></p>
<% else %>
<ul class="tabular">
<% items.each do |item| %>
<li class='attribute attribute-title'>
<%= link_to item.title.first, url_for_document(item) %>
</li>
<% end %>
</ul>
<% end %>
</dd>
First I wanted to know if this was in Hyrax or custom code for the application. I checked the current repository version of Hyrax. It was on v2.9.6.
I ran rg "hyrax \(\d+\.\d+\.\d+\)" Gemfile.lock
to get the Hyrax version.
I didn’t see the above partial in that version of Hyrax, so assumed it was something local.
For completeness, I could check later version of Hyrax, but I chose not to.
In the link sent to me of the above view, I checked the SHA of that file (e.g. 21402d0fcf989dafac315e048e87f2709eeee931
). Locally, I ran git show
with the given SHA. For the commit that introduced the partial, I wanted to see what called that partial:
> git show 21402d0fcf989dafac315e048e87f2709eeee931 | rg collections_parent_row
+<%= render 'collections_parent_rows', presenter: presenter %>
diff --git a/app/views/hyrax/base/_collections_parent_row.html.erb b/app/views/hyrax/base/_collections_parent_row.html.erb
+++ b/app/views/hyrax/base/_collections_parent_row.html.erb
diff --git a/app/views/hyrax/base/_collections_parent_rows.html.erb b/app/views/hyrax/base/_collections_parent_rows.html.erb
+++ b/app/views/hyrax/base/_collections_parent_rows.html.erb
+ <%= render 'collections_parent_row', type: model_name, items: items, presenter: presenter %>
+ <%= render 'collections_parent_row', type: type, items: items, presenter: presenter %>
The above results are a bit ugly but I wanted to see the files and where all it was referenced at the time of the introduced change. In my experience I want to see two things: the state of the code when we introduced something and the current state of the code. I also checked the current state of the repository:
❯ rg collections_parent_row
app/views/hyrax/base/_collections.html.erb
1:<%= render 'collections_parent_rows', presenter: presenter %>
app/views/hyrax/base/_collections_parent_rows.html.erb
3: <%= render 'collections_parent_row', type: model_name, items: items, presenter: presenter %>
9: <%= render 'collections_parent_row', type: type, items: items, presenter: presenter %>
Looking at app/views/hyrax/base/_collections_parent_rows.html.erb
we have the following:
<% presenter.presenter_types.each do |type| %>
<% presenter.grouped_presenters(filtered_by: type).each_pair do |_, items| %>
<%= render 'collections_parent_row', type: type, items: items, presenter: presenter %>
<% end %>
<% end %>
Given that we’re in app/views/hyrax/base/
the presenter
could be a variety of things; works
, collections
, pages
, my
, etc. (I ran ls app/views/hyrax
on the Hyrax repository to see the potential candidates; not all of the results are actual candidates but it is enough to be cautious about making assumptions).
The partial had two methods to go searching for: #presenter_types
and #grouped_presenters
.
Hopping over to Hyrax (checking out v2.9.6), I wanted to find where we defined those methods; namely what is the presenter
object’s class in the above views.
❯ rg "def (self\.)?(presenter_types|grouped_presenters)"
app/presenters/hyrax/work_show_presenter.rb
142: def presenter_types
147: def grouped_presenters(filtered_by: nil, except: nil)
It looks like Hyrax::WorkShowPresenter
; I especially like that it has a named parameter of filtered_by
which corresponds to the above view.
Looking at the definition of #grouped_presenters
(see below), we’re calling #member_of_collection_presenters
.
def grouped_presenters(filtered_by: nil, except: nil)
# TODO: we probably need to retain collection_presenters (as parent_presenters)
# and join this with member_of_collection_presenters
grouped = member_of_collection_presenters.group_by(&:model_name).transform_keys { |key| key.to_s.underscore }
grouped.select! { |obj| obj.downcase == filtered_by } unless filtered_by.nil?
grouped.except!(*except) unless except.nil?
grouped
end
Now let’s look at #member_of_collection_presenters
:
# Get presenters for the collections this work is a member of via the member_of_collections association.
# @return [Array<CollectionPresenter>] presenters
def member_of_collection_presenters
PresenterFactory.build_for(ids: member_of_authorized_parent_collections,
presenter_class: collection_presenter_class,
presenter_args: presenter_factory_arguments)
end
What’s I liked about this is that we’re passing in some ids
of authorized parent collections. This looks really promising!
Let’s look at #member_of_authorized_parent_collections
:
def member_of_authorized_parent_collections
# member_of_collection_ids with current_ability access
@member_of ||= Hyrax::CollectionMemberService.run(solr_document, current_ability).map(&:id)
end
I definitely like the comment: “member_of_collection_ids with current_ability access”. And in this query we have two things:
solr_document
- The SOLR document representation of the current work (after all we’re in the
Hyrax::WorkShowPresenter
). current_ability
- The instance of the Ability for the current user.
With that class we can answer the question: What are the collections authorized for a given work and given current user (by way of current ability)?
At this point, I have enough of to feel comfortable answering the initial question.
Conclusion
I wanted to take the time to walk through one of the many available pathways when exploring a problem. Within an application, I often rely on Language Server Protocol (LSP 📖) (by way of the Eglot package) to jump to definitions. However, when working on two repositories, the jump is often not viable.
I instead use some connective command-line tools to help orient from one repository to the other.