Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Breadcrumbs, OO version
# typed: false
# frozen_string_literal: true
require 'json'
module PublicLaw
# Represents a breadcrumb trail on a page.
class Breadcrumbs
include ActionView::Helpers
extend T::Sig
JSON_PREFIX = "<script type=\"application/ld+json\">\n"
JSON_SUFFIX = "\n</script>\n"
HTML_PREFIX = "<nav aria-label=\"breadcrumb\">\n<ol class=\"breadcrumb\">"
HTML_SUFFIX = "</ol>\n</nav>"
Links = T.type_alias { T::Array[T::Hash[Symbol, String]] }
sig {params(title: String, location: String).returns(Breadcrumbs)}
def initialize(title:, location:)
raise 'Title is blank' if title.blank?
raise 'Location is blank' if location.blank?
@all_but_last_item = T.let([], Links)
@last_item = T.let({ title: sanitize(title), location: location }, T::Hash[Symbol, String])
self
end
sig {params(title: String, location: String).returns(Breadcrumbs)}
def add(title:, location:)
raise 'Title is blank' if title.blank?
raise 'Location is blank' if location.blank?
@all_but_last_item << @last_item
@last_item = { title: sanitize(title), location: location }
self
end
sig {returns(String)}
def to_s
to_html
end
private
sig {returns(String)}
def to_html
(microdata_json + "\n" + html_list).html_safe
end
sig {returns(String)}
def microdata_json
microdata = {
'@context' => 'http://schema.org',
'@type' => 'BreadcrumbList',
'itemListElement' => list_elements(@all_but_last_item + [@last_item]),
}
JSON_PREFIX + microdata.to_json + JSON_SUFFIX
end
sig {returns(String)}
def html_list
HTML_PREFIX + "\n" + list_items_html + HTML_SUFFIX + "\n"
end
sig {returns(String)}
def list_items_html
' ' + list_items.join("\n ") + "\n"
end
#
# Create HTML <li> elements from the Links. All but
# the last should be hyperlinks.
#
sig {returns(T::Array[String])}
def list_items
@all_but_last_item
.map { |l| "<li class=\"breadcrumb-item\"><a href=\"#{l[:location]}\">#{l[:title]}</a></li>" }
.push(final_list_item)
end
sig {returns(String)}
def final_list_item
"<li class=\"breadcrumb-item active\" aria-current=\"page\">#{@last_item.fetch(:title)}</li>"
end
sig {params(links: Links).returns(T::Array[T::Hash[String, T.untyped]])}
def list_elements(links)
list_elements = []
links.each_index do |index|
list_elements << {
'@type' => 'ListItem',
'position' => index + 1,
'item' => {
'@id' => links[index].fetch(:location),
'name' => links[index].fetch(:title),
},
}
end
list_elements
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.