From f606d8e7c312222234c7f3409a2f601d78d25be8 Mon Sep 17 00:00:00 2001 From: Denis Defreyne Date: Mon, 8 Oct 2018 21:23:47 +0200 Subject: [PATCH 1/2] Ensure breadcrumb trail always ends in item itself --- nanoc/lib/nanoc/helpers/breadcrumbs.rb | 7 +++--- nanoc/spec/nanoc/helpers/breadcrumbs_spec.rb | 23 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/nanoc/lib/nanoc/helpers/breadcrumbs.rb b/nanoc/lib/nanoc/helpers/breadcrumbs.rb index 058dd953c9..0a633af3eb 100644 --- a/nanoc/lib/nanoc/helpers/breadcrumbs.rb +++ b/nanoc/lib/nanoc/helpers/breadcrumbs.rb @@ -40,9 +40,9 @@ def breadcrumbs_trail if @item.identifier.legacy? prefixes.map { |pr| @items[Nanoc::Identifier.new('/' + pr, type: :legacy)] } else - prefixes - .reject { |pr| pr =~ /^\/index\./ } - .map do |pr| + ancestral_prefixes = prefixes.reject { |pr| pr =~ /^\/index\./ }[0..-2] + ancestral_items = + ancestral_prefixes.map do |pr| if pr == '' @items['/index.*'] else @@ -50,6 +50,7 @@ def breadcrumbs_trail prefix_patterns.lazy.map { |pat| @items[pat] }.find(&:itself) end end + ancestral_items + [item] end end end diff --git a/nanoc/spec/nanoc/helpers/breadcrumbs_spec.rb b/nanoc/spec/nanoc/helpers/breadcrumbs_spec.rb index f6e8a32ee4..1764177da8 100644 --- a/nanoc/spec/nanoc/helpers/breadcrumbs_spec.rb +++ b/nanoc/spec/nanoc/helpers/breadcrumbs_spec.rb @@ -176,6 +176,29 @@ ) end end + + context 'child with multiple extensions' do + before do + ctx.create_item('grandchild1', {}, Nanoc::Identifier.new('/foo/stuff.zip')) + ctx.create_item('grandchild2', {}, Nanoc::Identifier.new('/foo/stuff.md')) + ctx.create_item('grandchild3', {}, Nanoc::Identifier.new('/foo/stuff.png')) + ctx.create_item('child', {}, Nanoc::Identifier.new('/foo.md')) + ctx.create_item('root', {}, Nanoc::Identifier.new('/index.md')) + + ctx.item = ctx.items['/foo/stuff.md'] + end + + it 'picks the best parent' do + expect(subject) + .to eql( + [ + ctx.items['/index.md'], + ctx.items['/foo.md'], + ctx.items['/foo/stuff.md'], + ], + ) + end + end end end end From 34e42ebc49148363afa5f1c35be14f61b9c2d7ea Mon Sep 17 00:00:00 2001 From: Denis Defreyne Date: Mon, 8 Oct 2018 21:48:41 +0200 Subject: [PATCH 2/2] Explain design rationale of breadcrumbs_trail --- nanoc/lib/nanoc/helpers/breadcrumbs.rb | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/nanoc/lib/nanoc/helpers/breadcrumbs.rb b/nanoc/lib/nanoc/helpers/breadcrumbs.rb index 0a633af3eb..e0f67adf3e 100644 --- a/nanoc/lib/nanoc/helpers/breadcrumbs.rb +++ b/nanoc/lib/nanoc/helpers/breadcrumbs.rb @@ -33,6 +33,34 @@ def self.patterns_for_prefix(prefix) # @return [Array] def breadcrumbs_trail + # The design of this function is a little complicated. + # + # We can’t use #parent_of from the ChildParent helper, because the + # breadcrumb trail can have gaps. For example, the breadcrumbs trail for + # /software/oink.md might be /index.md -> nil -> /software/oink.md if + # there is no item matching /software.* or /software/index.*. + # + # What this function does instead is something more complicated: + # + # 1. It creates an ordered prefix list, based on the identifier of the + # item to create a breadcrumbs trail for. For example, + # /software/oink.md might have the prefix list + # ['', '/software', '/software/oink.md']. + # + # 2. For each of the elements in that list, it will create a list of + # patterns could match zero or more items. For example, the element + # '/software' would correspond to the pattern '/software.*'. + # + # 3. For each of the elements in that list, and for each pattern for that + # element, it will find any matching element. For example, the + # pattern '/software.*' (coming from the prefix /software) would match + # the item /software.md. + # + # 4. Return the list of items, with the last element replaced by the item + # for which the breadcrumb is generated for -- while ancestral items + # in the breadcrumbs trail can have a bit of ambiguity, the item for + # which to generate the breadcrumbs trail is fixed. + # e.g. ['', '/foo', '/foo/bar'] components = item.identifier.components prefixes = components.inject(['']) { |acc, elem| acc + [acc.last + '/' + elem] }