move author logic to its own drop

This commit is contained in:
Ben Balter 2017-08-23 11:07:52 -04:00
parent f5dbc6c36f
commit 891d621899
No known key found for this signature in database
GPG Key ID: DBB67C246AD356C4
5 changed files with 106 additions and 58 deletions

View File

@ -1,6 +1,4 @@
source "https://rubygems.org"
require "json"
require "open-uri"
gemspec

View File

@ -3,7 +3,8 @@ require "jekyll-seo-tag/version"
module Jekyll
class SeoTag < Liquid::Tag
autoload :JSONLD, "jekyll-seo-tag/json_ld"
autoload :JSONLD, "jekyll-seo-tag/json_ld"
autoload :AuthorDrop, "jekyll-seo-tag/author_drop"
autoload :Drop, "jekyll-seo-tag/drop"
autoload :Filters, "jekyll-seo-tag/filters"

View File

@ -0,0 +1,88 @@
module Jekyll
class SeoTag
class AuthorDrop < Jekyll::Drops::Drop
# A drop representing the current page's author
#
# Author name will be pulled from:
#
# 1. The page's `author` key
# 2. The first author in the page's `authors` key
# 3. The `author` key in the site config
#
# If the result from the name search is a string, we'll also check
# for additional author metadata in `site.data.authors`
def initialize(page: nil, site: nil)
raise ArugementError unless page && site
@mutations = {}
@page = page
@site = site
end
# Public methods to delegate to keys of the author hash
# Ensures keys will be present when `to_h` is called, even with nil values
DELEGATED_METHODS = %i[name picture].freeze
DELEGATED_METHODS.each do |meth|
define_method meth do
author_hash[meth.to_s]
end
end
# AuthorDrop#to_s should return name, allowing the author drop to safely
# replace `page.author`, if necessary, and remain backwards compatible
alias_method :to_s, :name
def twitter
return @twitter if defined? @twitter
twitter = author_hash["twitter"] || author_hash["name"]
@twitter = twitter.is_a?(String) ? twitter.sub(%r!^@!, "") : nil
end
private
attr_reader :page
attr_reader :site
# Finds the page author in the page.author, page.authors, or site.author
#
# Returns a string or hash representing the author
def resolved_author
return @resolved_author if defined? @resolved_author
sources = [page["author"]]
sources << page["authors"].first if page["authors"].is_a?(Array)
sources << site["author"]
@resolved_author = sources.find { |s| !s.to_s.empty? }
end
# If resolved_author is a string, attempts to find coresponding author
# metadata in `site.data.authors`
#
# Returns a hash representing additional metadata or an empty hash
def site_data_hash
@site_data_hash ||= begin
return {} unless resolved_author.is_a?(String)
return {} unless site.data["authors"].is_a?(Hash)
author_hash = site.data["authors"][resolved_author]
author_hash.is_a?(Hash) ? author_hash : {}
end
end
# Returns the normalized author hash representing the page author,
# including site-wide metadata if the author is provided as a string,
# or an empty hash, if the author cannot be resolved
def author_hash
if resolved_author.is_a? Hash
resolved_author
elsif resolved_author.is_a? String
{ "name" => resolved_author }.merge(site_data_hash)
else
{}
end
end
# Since author_hash is aliased to fallback_data, any values in the hash
# will be exposed via the drop, allowing support for arbitrary metadata
alias_method :fallback_data, :author_hash
end
end
end

View File

@ -72,29 +72,9 @@ module Jekyll
end
end
# Returns a nil or a hash representing the author
# Author name will be pulled from:
#
# 1. The `author` key, if the key is a string
# 2. The first author in the `authors` key
# 3. The `author` key in the site config
#
# If the result from the name search is a string, we'll also check
# to see if the author exists in `site.data.authors`
# A drop representing the page author
def author
@author ||= begin
return if author_string_or_hash.to_s.empty?
author = if author_string_or_hash.is_a?(String)
author_hash(author_string_or_hash)
else
author_string_or_hash
end
author["twitter"] ||= author["name"]
author["twitter"].delete! "@" if author["twitter"]
author.to_liquid
end
@author ||= AuthorDrop.new(:page => page, :site => site)
end
def date_modified
@ -231,35 +211,6 @@ module Jekyll
string unless string.empty?
end
def author_string_or_hash
@author_string_or_hash ||= begin
author = page["author"]
author = page["authors"][0] if author.to_s.empty? && page["authors"]
author = site["author"] if author.to_s.empty?
author
end
end
# Given a string representing the current document's author, return
# a normalized hash representing that author. Will try to pull from
# site.authors if present and in the proper format.
def author_hash(author_string)
site_author_hash(author_string) || { "name" => author_string }
end
# Given a string representing the current document's author, attempt
# to retrieve additional metadata from site.data.authors, if present
#
# Returns the author hash
def site_author_hash(author_string)
return unless site.data["authors"] && site.data["authors"].is_a?(Hash)
author_hash = site.data["authors"][author_string]
return unless author_hash.is_a?(Hash)
author_hash["name"] ||= author_string
author_hash["twitter"] ||= author_string
author_hash
end
def seo_name
@seo_name ||= format_string(page_seo["name"]) if page_seo["name"]
end

View File

@ -223,6 +223,16 @@ RSpec.describe Jekyll::SeoTag::Drop do
end
context "author" do
let(:name) { "foo" }
let(:twitter) { "foo" }
let(:picture) { nil }
let(:expected_hash) do
{
"name" => name,
"twitter" => twitter,
"picture" => picture,
}
end
let(:data) { {} }
let(:config) { { "author" => "site_author" } }
let(:site) do
@ -236,7 +246,7 @@ RSpec.describe Jekyll::SeoTag::Drop do
let(:page_meta) { { "author" => "foo" } }
it "doesn't error" do
expect(subject.author).to eql({ "name" => "foo", "twitter" => "foo" })
expect(subject.author.to_h).to eql(expected_hash)
end
end
@ -245,7 +255,7 @@ RSpec.describe Jekyll::SeoTag::Drop do
let(:page_meta) { { "author" => "foo" } }
it "doesn't error" do
expect(subject.author).to eql({ "name" => "foo", "twitter" => "foo" })
expect(subject.author.to_h).to eql(expected_hash)
end
end
@ -279,8 +289,8 @@ RSpec.describe Jekyll::SeoTag::Drop do
"#{author_type}_author".sub("nil_", "site_").sub("empty_string_", "site_")
end
it "returns a hash" do
expect(subject.author).to be_a(Hash)
it "returns a Drop" do
expect(subject.author).to be_a(Jekyll::SeoTag::AuthorDrop)
end
it "returns the name" do