Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fold private methods into the :render method as local variables #327

Merged
merged 3 commits into from
Dec 16, 2021

Conversation

ashmaroli
Copy link
Member

Since the meta tag contents doesn't depend on page-specific metadata, the resulting markup is essentially the same for all pages / documents in a site:

def attributes
{
:type => "application/atom+xml",
:rel => "alternate",
:href => absolute_url(path),
:title => title,
}.keep_if { |_, v| v }
end
def path
config.dig("feed", "path") || "feed.xml"
end
def title
config["title"] || config["name"]
end

Therefore in theory, the result can be safely memoized to avoid generating arrays for every page / document..

@ashmaroli ashmaroli requested review from parkr and a team October 4, 2020 11:08
@ashmaroli
Copy link
Member Author

/cc @parkr to verify that this doesn't interfere with the jekyll-github-metadata plugin..

%(#{k}=#{v.encode(:xml => :attr)})
end
"<link #{attrs.join(" ")} />"
@context ||= context
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since context could theoretically change (and therefore the code should reflect this), I'd feel more comfortable with an approach using the context's hash (the number Ruby assigns to each unique object):

def render(context)
  link_tag(context)
end

def link_tag(context)
  @link_tags[context.hash] ||= "<link #{xml_encoded_attributes(context).join(" ")} />"
end

etc.

In this model, we always pass context down through the methods, making them pure functions, instead of relying on @context being set (and therefore acting more like Object methods relying on state). What do you think about an approach like this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the source-code on master, the only place @context is ever used in this Liquid tag instance is to get the site config:

def config
@config ||= @context.registers[:site].config
end

Since the site config shouldn't be changing once site.render phase starts, memoizing with a hash-store therefore seems wasteful to me...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@context is required to be set for Jekyll::Filters::URLFilters to work.
So the suggested model is not applicable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the site config shouldn't be changing once site.render phase starts, memoizing with a hash-store therefore seems wasteful to me...

The code as it exists today has a render method that takes in a context. That means that render should respond to changes in context. From a strict read of just the method signatures, one would expect that inputting new information into context and passing it to render would yield a different result. I think the only way to fix this that can use an object-method approach is to do MetaTag.new(context).render and update everything accordingly. The problem stems from the programmer's expectation that f(input) should always take input into account rather than just the input to the first call to f(). This hybrid it's-a-function-but-we-treat-it-like-an-object relies on implicit understanding of the implementation, which could change. The function signatures should reflect this and move fully into an object approach, or use a pure function approach instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay @parkr.

To avoid further bike-shedding, I've decided to not memoize at all..
(since this tag is typically used once per page and hence the context.hash is never constant)

I have refactored the whole implementation to not call private methods at all.

Is the current diff acceptable to you?

@ashmaroli ashmaroli changed the title Memoize feed tag markup string Fold private methods into the :render method as local variables Oct 5, 2020
Copy link

@hugoglezcon hugoglezcon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gracias pero necesario ver el conte

@parkr
Copy link
Member

parkr commented Dec 16, 2021

@jekyllbot: merge +bug

@jekyllbot jekyllbot merged commit 982a532 into jekyll:master Dec 16, 2021
jekyllbot added a commit that referenced this pull request Dec 16, 2021
@ashmaroli ashmaroli deleted the memoize-feed-tag-markup branch December 16, 2021 09:06
@jekyll jekyll locked and limited conversation to collaborators Dec 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants