Add PageDrop to provide Liquid templates with data (#7992)
Merge pull request 7992
This commit is contained in:
		
							parent
							
								
									a011579fe4
								
							
						
					
					
						commit
						b84ba5accc
					
				|  | @ -34,3 +34,38 @@ If you have a lot of pages, you can organize them into subfolders. The same subf | |||
| ## Changing the output URL | ||||
| 
 | ||||
| You might want to have a particular folder structure for your source files that changes for the built site. With [permalinks](/docs/permalinks) you have full control of the output URL. | ||||
| 
 | ||||
| ## Liquid Representation | ||||
| 
 | ||||
| From Jekyll 4.1 onwards, there is a minor change in how instances of `Jekyll::Page` are exposed to layouts and other Liquid | ||||
| templates. `Jekyll::Page` instances now use a `Liquid::Drop` instead of a `Hash`. This change results in greater performance | ||||
| for a site with numerous *standlone pages not within a collection*. | ||||
| 
 | ||||
| ### For plugin developers | ||||
| 
 | ||||
| While end-users do not need to take any extra action due to this change, plugin authors depending on the existing behavior *may* | ||||
| need to make minor changes to their plugins. | ||||
| 
 | ||||
| If a `Jekyll::Page` subclass' `to_liquid` method calls `super`, it will have to be slightly modified. | ||||
| ```ruby | ||||
| class Foo::BarPage < Jekyll::Page | ||||
|   def to_liquid(*) | ||||
|     payload = super        # This needs to be changed to `super.to_h` | ||||
|                            # to obtain a Hash as in v4.0.0. | ||||
| 
 | ||||
|     do_something(payload)  # Logic specific to `Foo::BarPage` objects | ||||
|   end | ||||
| end | ||||
| ``` | ||||
| 
 | ||||
| `Jekyll::Page` subclasses won't inherit the optimization automatically until the next major version. However, plugin authors | ||||
| can opt-in to the optimization in their subclasses by wrapping the temporary `liquid_drop` method if the subclass doesn't | ||||
| override the superclass method: | ||||
| ```ruby | ||||
| class Foo::BarPage < Jekyll::Page | ||||
|   def to_liquid(*) | ||||
|     liquid_drop    # Returns an instance of `Jekyll::Drops::PageDrop`. | ||||
|                    # Will be removed in Jekyll 5.0. | ||||
|   end | ||||
| end | ||||
| ``` | ||||
|  |  | |||
|  | @ -0,0 +1,14 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Jekyll | ||||
|   module Drops | ||||
|     class PageDrop < Drop | ||||
|       extend Forwardable | ||||
| 
 | ||||
|       mutable false | ||||
| 
 | ||||
|       def_delegators :@obj, :content, :dir, :name, :path, :url | ||||
|       private def_delegator :@obj, :data, :fallback_data | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -70,6 +70,38 @@ module Jekyll | |||
|       end | ||||
|     end | ||||
| 
 | ||||
|     # For backwards-compatibility in subclasses that do not redefine | ||||
|     # the `:to_liquid` method, stash existing definition under a new name | ||||
|     # | ||||
|     # TODO: Remove in Jekyll 5.0 | ||||
|     alias_method :legacy_to_liquid, :to_liquid | ||||
|     private :legacy_to_liquid | ||||
| 
 | ||||
|     # Private | ||||
|     # Subclasses can choose to optimize their `:to_liquid` method by wrapping | ||||
|     # it around this definition. | ||||
|     # | ||||
|     # TODO: Remove in Jekyll 5.0 | ||||
|     def liquid_drop | ||||
|       @liquid_drop ||= begin | ||||
|         defaults = site.frontmatter_defaults.all(relative_path, type) | ||||
|         unless defaults.empty? | ||||
|           Utils.deep_merge_hashes!(data, Utils.deep_merge_hashes!(defaults, data)) | ||||
|         end | ||||
|         Drops::PageDrop.new(self) | ||||
|       end | ||||
|     end | ||||
|     private :liquid_drop | ||||
| 
 | ||||
|     # Public | ||||
|     # | ||||
|     # Liquid representation of current page | ||||
|     # | ||||
|     # TODO: Remove optional parameter in Jekyll 5.0 | ||||
|     def to_liquid(attrs = nil) | ||||
|       self.class == Jekyll::Page ? liquid_drop : legacy_to_liquid(attrs) | ||||
|     end | ||||
| 
 | ||||
|     # The full path and filename of the post. Defined in the YAML of the post | ||||
|     # body. | ||||
|     # | ||||
|  |  | |||
|  | @ -50,6 +50,42 @@ class TestPage < JekyllUnitTest | |||
|         assert_equal "/+/%25%23%20+.html", @page.url | ||||
|       end | ||||
| 
 | ||||
|       should "be exposed to Liquid as a Liquid::Drop subclass" do | ||||
|         page = setup_page("properties.html") | ||||
|         liquid_rep = page.to_liquid | ||||
|         refute_equal Hash, liquid_rep.class | ||||
|         assert_equal true, liquid_rep.is_a?(Liquid::Drop) | ||||
|         assert_equal Jekyll::Drops::PageDrop, liquid_rep.class | ||||
|       end | ||||
| 
 | ||||
|       should "make attributes accessible for use in Liquid templates" do | ||||
|         page = setup_page("/contacts", "index.html") | ||||
|         template = Liquid::Template.parse(<<~TEXT) | ||||
|           Name: {{ page.name }} | ||||
|           Path: {{ page.path }} | ||||
|           URL:  {{ page.url }} | ||||
|         TEXT | ||||
|         expected = <<~TEXT | ||||
|           Name: index.html | ||||
|           Path: contacts/index.html | ||||
|           URL:  /contacts/ | ||||
|         TEXT | ||||
|         assert_equal(expected, template.render!("page" => page.to_liquid)) | ||||
|       end | ||||
| 
 | ||||
|       should "make front matter data accessible for use in Liquid templates" do | ||||
|         page = setup_page("properties.html") | ||||
|         template = Liquid::Template.parse(<<~TEXT) | ||||
|           TITLE: {{ page.title }} | ||||
|           FOO:   {{ page.foo }} | ||||
|         TEXT | ||||
|         expected = <<~TEXT | ||||
|           TITLE: Properties Page | ||||
|           FOO:   bar | ||||
|         TEXT | ||||
|         assert_equal expected, template.render!("page" => page.to_liquid) | ||||
|       end | ||||
| 
 | ||||
|       context "in a directory hierarchy" do | ||||
|         should "create URL based on filename" do | ||||
|           @page = setup_page("/contacts", "bar.html") | ||||
|  |  | |||
|  | @ -76,6 +76,12 @@ class TestPageWithoutAFile < JekyllUnitTest | |||
|           end | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       should "be exposed to Liquid as a Hash" do | ||||
|         liquid_rep = @page.to_liquid | ||||
|         refute_equal Jekyll::Drops::PageDrop, liquid_rep.class | ||||
|         assert_equal Hash, liquid_rep.class | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "with site-wide permalink configuration" do | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue