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

Refactor front matter handling and extract behavior into loaders #778

Merged
merged 4 commits into from
Feb 17, 2024

Conversation

michaelherold
Copy link
Contributor

This is a 🙋 feature or enhancement.

Summary

This change reorganizes the front matter-related code so it is fully contained within the Bridgetown::FrontMatter module. That makes it easier to find the functionality and standardizes the way that Bridgetown refers to front matter.

It also adds deprecated constant proxies for backwards-compatibility. It's unclear whether the moved modules were public API or not so the proxies make it so updating will not break anyone's site without warning.

This change also refactors the loading of front matter into a series of classes. This is a first step toward making front matter loaders pluggable to allow, for example, TOML- or KDL-based front matter.

Context

This accomplishes much of the "open to extension" goal in #777.

Copy link
Contributor Author

@michaelherold michaelherold left a comment

Choose a reason for hiding this comment

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

This is a high-level review of things that I thought of while working on this. It's been several months in the making and I wanted to get it up for review before working through it anymore.

Comment on lines +113 to +120
FrontmatterDefaults = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
"FrontmatterDefaults",
"Bridgetown::FrontMatter::Defaults"
)

FrontMatterImporter = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
"FrontMatterImporter",
"Bridgetown::FrontMatter::Importer"
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment: I kept these to honor the move fast but try not to break things principle.

question: These don't use the Bridgetown::Deprecator. Do we want to refactor to use it?

autoload :Ruby, "bridgetown-core/front_matter/loaders/ruby"
autoload :YAML, "bridgetown-core/front_matter/loaders/yaml"

Result = Struct.new(:content, :front_matter, :line_count, keyword_init: true)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment: This should likely be marked private. I believe it should be a temporary thing.

Comment on lines +28 to +41
# Registers a new type of front matter loader
#
# @param loader_class [Loader::Base]
# @return [void]
def self.register(loader_class)
registry.push(loader_class)
end

private_class_method def self.registry
@registry ||= []
end

register YAML
register Ruby
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment: This is at MVP stage and it's what I'm least excited about. If you notice, I register YAML before Ruby. This is because it needs to be higher precedence to maintain the original business logic of the read_from_matter method.

I didn't want to overengineer here, but I think having both (1) symbol-based registration and (2) a priority level would be useful here. That way people can override by type and give higher precedence to a loader if needed.

Thoughts?

class Base
# @param origin_or_layout [Bridgetown::Model::RepoOrigin, Bridgetown::Layout]
def initialize(origin_or_layout)
@origin_or_layout = origin_or_layout
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment: I don't know if there's a higher-level concept that these things both have in common. Is there?

@@ -69,7 +69,7 @@ def read_directories(dir = "")
file_path = @site.in_source_dir(base, entry)
if File.directory?(file_path)
entries_dirs << entry
elsif Utils.has_yaml_header?(file_path) || Utils.has_rbfm_header?(file_path)
elsif FrontMatter::Loaders.front_matter?(file_path)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

question: Would it be worth exposing this method on FrontMatter instead?

@@ -16,7 +16,7 @@ class TestGeneratedSite < BridgetownUnitTest
end

should "ensure post count is as expected" do
assert_equal 51, @site.collections.posts.resources.size
assert_equal 52, @site.collections.posts.resources.size
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment: This test is fragile. Should we remove it?

@@ -21,7 +21,7 @@ def setup
end

should "return accept objects which respond to url" do
assert_equal "<a href=\"/2020/09/10/further-nested/\">Label</a>", @helpers.link_to("Label", @site.collections.posts.resources.first)
assert_equal "<a href=\"/2023/06/30/ruby-front-matter/\">Label</a>", @helpers.link_to("Label", @site.collections.posts.resources.first)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment: This test is fragile as well. Does it pay for itself?

@@ -387,20 +387,26 @@ class TestUtils < BridgetownUnitTest
end

context "The `Utils.has_yaml_header?` method" do
should "accept files with YAML front matter" do
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment: These tests move into the YAML loader tests.

@@ -30,7 +30,7 @@ def eval_route_file(file, file_slug, app) # rubocop:disable Lint/UnusedMethodArg

code = File.read(file)
code_postmatch = nil
ruby_content = code.match(Bridgetown::FrontMatterImporter::RUBY_BLOCK)
ruby_content = code.match(Bridgetown::FrontMatter::Loaders::Ruby::BLOCK)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

comment: This appears to be dealing with front matter without really stating that fact. Perhaps we should refactor it?

Comment on lines +12 to +13
1. `HEADER` matches the opening line of the front matter
2. `BLOCK` matches the contents of the front matter block with the first capturing group being the content and the regular expression consuming the ending delimiter
Copy link
Contributor Author

Choose a reason for hiding this comment

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

question: Is this worth mentioning?

@jaredcwhite
Copy link
Member

Apologies I haven't had a chance to dig into this @michaelherold, hope to soon. Thanks for working on this as it's an idea that's come up before. In fact, I could foresee relocating all of the front matter logic out to a separate gem (which then is a dependency of core), but probably it's fine to keep it in house for now (though more standalone).

@michaelherold
Copy link
Contributor Author

As I was working on this, I imagined having a gem that Bridgetown would use, so we're thinking along the same lines!

This change refactors the loading of front matter into a series of
classes. This is a first step toward making front matter loaders
pluggable to allow, for example, [TOML][1]- or [KDL][2]-based front
matter.

[1]: https://toml.io
[2]: https://kdl.dev/
These were developed prior to FrontMatterImporter and are no longer used.
This change reorganizes the front matter-related code so it is fully
contained within the Bridgetown::FrontMatter module. That makes it
easier to find the functionality and standardizes the way that
Bridgetown refers to front matter.

It also adds deprecated constant proxies for backwards-compatibility.
It's unclear whether the moved modules were public API or not so the
proxies make it so updating will not break anyone's site without
warning.
This is already done by the include of the importer so isn't necessary
at this point.
@michaelherold
Copy link
Contributor Author

michaelherold commented Aug 22, 2023

Rebased for the green checkmarks (and hit a flaky test).

@jaredcwhite jaredcwhite added this to the 1.4 milestone Aug 22, 2023
@jaredcwhite jaredcwhite removed this from the 1.4 milestone Oct 10, 2023
@jaredcwhite
Copy link
Member

@michaelherold Better late than never! This PR looks really good, so I'm going to go ahead and merge with the expectation to release in Bridgetown v2.0. If there were any more details you wanted to go over, just let me know in a follow-up issue/PR. Thanks!

@jaredcwhite jaredcwhite merged commit b22ddfe into bridgetownrb:main Feb 17, 2024
1 of 4 checks passed
jaredcwhite added a commit that referenced this pull request Mar 16, 2024
@jaredcwhite
Copy link
Member

@michaelherold don't worry, I didn't revert this for 2.0, just for the latest 1.3.3 point release (because I needed other stuff that was also in main). Still excited to get this in!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants