From e14b27b1047577eaf21775cc60528e1fea651d9a Mon Sep 17 00:00:00 2001 From: Jared White Date: Mon, 9 Oct 2023 20:34:15 -0700 Subject: [PATCH] Support `pipe` in Serbea 2.0, add new pure Ruby template syntax --- Gemfile.lock | 4 +- .../lib/bridgetown-builder/plugin.rb | 2 +- bridgetown-builder/test/test_hooks.rb | 21 ------ bridgetown-core/bridgetown-core.gemspec | 2 +- bridgetown-core/lib/bridgetown-core.rb | 10 +++ .../converters/erb_templates.rb | 2 + .../converters/ruby_templates.rb | 66 ++++++++++++++++++- .../src/_events/2020-12-25-christmas.html | 2 +- .../test/resources/src/_pages/i-am-ruby.rb | 26 +++++++- .../resources/src/_partials/_a_partial.rb | 3 + .../src/_partials/_an_erb_partial.erb | 1 + bridgetown-core/test/test_resource.rb | 15 ++++- bridgetown-website/Gemfile.lock | 4 +- 13 files changed, 123 insertions(+), 35 deletions(-) create mode 100644 bridgetown-core/test/resources/src/_partials/_a_partial.rb create mode 100644 bridgetown-core/test/resources/src/_partials/_an_erb_partial.erb diff --git a/Gemfile.lock b/Gemfile.lock index 0432e6034..3811b583e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -25,7 +25,7 @@ PATH rake (>= 13.0) roda (~> 3.46) rouge (~> 3.0) - serbea (~> 1.0) + serbea (~> 2.0) thor (~> 1.1) tilt (~> 2.0) zeitwerk (~> 2.5) @@ -199,7 +199,7 @@ GEM rubocop-ast (>= 0.4.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) - serbea (1.0.1) + serbea (2.0.0) activesupport (>= 6.0) erubi (>= 1.10) tilt (~> 2.0) diff --git a/bridgetown-builder/lib/bridgetown-builder/plugin.rb b/bridgetown-builder/lib/bridgetown-builder/plugin.rb index 456d98e52..c1e2656b0 100644 --- a/bridgetown-builder/lib/bridgetown-builder/plugin.rb +++ b/bridgetown-builder/lib/bridgetown-builder/plugin.rb @@ -57,7 +57,7 @@ def initialize(name = nil, current_site = nil) def doc(*) raise Bridgetown::Errors::FatalException, - "The `doc' method has been removed. Please use the `new_resource' builder DSL instead" + "The `doc' method has been removed. Please use the `add_resource' builder DSL instead" end end end diff --git a/bridgetown-builder/test/test_hooks.rb b/bridgetown-builder/test/test_hooks.rb index 58e10ce9f..253086e21 100644 --- a/bridgetown-builder/test/test_hooks.rb +++ b/bridgetown-builder/test/test_hooks.rb @@ -11,15 +11,6 @@ def build hook :site, :pre_read do site.config[:pre_read_hook_ran] = true end - - hook :site, :post_read do - if site.data[:languages] - doc "#{site.data[:languages][1]}.md" do - title "Ruby" - date "2020-05-17" - end - end - end end end @@ -48,18 +39,6 @@ class TestHooks < BridgetownUnitTest assert @site.config[:after_reset_hook_ran] assert @site.config[:pre_read_hook_ran] end - - # TODO: get working with Resource - # should "work alongside Document Builder" do - # @site.reset - # @site.setup - # @site.read - # @generator = Builders::DocumentsGenerator.new(@site.config) - # @generator.generate(@site) - - # post = @site.posts.docs.find { |doc| doc.data[:title] == "Ruby" } - # assert_includes post.destination(""), "/dest/2020/05/17/ruby.html" - # end end context "SiteBuilder" do diff --git a/bridgetown-core/bridgetown-core.gemspec b/bridgetown-core/bridgetown-core.gemspec index 1aaa7ab33..6c9e02b30 100644 --- a/bridgetown-core/bridgetown-core.gemspec +++ b/bridgetown-core/bridgetown-core.gemspec @@ -48,7 +48,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency("rake", ">= 13.0") s.add_runtime_dependency("roda", "~> 3.46") s.add_runtime_dependency("rouge", "~> 3.0") - s.add_runtime_dependency("serbea", "~> 1.0") + s.add_runtime_dependency("serbea", "~> 2.0") s.add_runtime_dependency("thor", "~> 1.1") s.add_runtime_dependency("tilt", "~> 2.0") s.add_runtime_dependency("zeitwerk", "~> 2.5") diff --git a/bridgetown-core/lib/bridgetown-core.rb b/bridgetown-core/lib/bridgetown-core.rb index 130fde455..efd652a35 100644 --- a/bridgetown-core/lib/bridgetown-core.rb +++ b/bridgetown-core/lib/bridgetown-core.rb @@ -60,6 +60,8 @@ def require_all(path) # Ensure we can set up fallbacks so the default locale gets used I18n::Backend::Simple.include I18n::Backend::Fallbacks +# Monkey patches: + module HashWithDotAccess class Hash # :nodoc: def to_liquid @@ -68,6 +70,14 @@ def to_liquid end end +class Enumerator + def html_map(&block) + results = map.each(&block) + + results.join.html_safe + end +end + # Create our little String subclass for Ruby Front Matter class Rb < String; end diff --git a/bridgetown-core/lib/bridgetown-core/converters/erb_templates.rb b/bridgetown-core/lib/bridgetown-core/converters/erb_templates.rb index 552fc9efe..e4b0208df 100644 --- a/bridgetown-core/lib/bridgetown-core/converters/erb_templates.rb +++ b/bridgetown-core/lib/bridgetown-core/converters/erb_templates.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "tilt/erubi" +require "serbea/pipeline" module Bridgetown class OutputBuffer < ActiveSupport::SafeBuffer @@ -74,6 +75,7 @@ def capture(*args) class ERBView < RubyTemplateView include ERBCapture + include Serbea::Pipeline::Helper def h(input) Erubi.h(input) diff --git a/bridgetown-core/lib/bridgetown-core/converters/ruby_templates.rb b/bridgetown-core/lib/bridgetown-core/converters/ruby_templates.rb index 649ff43a6..da4eba087 100644 --- a/bridgetown-core/lib/bridgetown-core/converters/ruby_templates.rb +++ b/bridgetown-core/lib/bridgetown-core/converters/ruby_templates.rb @@ -1,16 +1,76 @@ # frozen_string_literal: true module Bridgetown + class PureRubyView < ERBView + # @yield a block which should be HTML escaped + def text(input, &blk) + if blk + h(pipe(input, &blk)) + else + h(input) + end + end + + def render(item = nil, **options, &block) # rubocop:disable Metrics + return @_erbout if !block && item.nil? && !options.key?(:html) + + if options.key?(:html) || (block && item.nil?) + result = options.key?(:html) ? options[:html].presence : yield + return result if result.is_a?(OutputBuffer) + + @_erbout ||= OutputBuffer.new + @_erbout << result.to_s.html_safe + + return @_erbout + end + + if item.respond_to?(:render_in) + result = item.render_in(self, &block) + result&.html_safe + else + partial(item, **options, &block)&.html_safe + end + end + + def _render_partial(partial_name, options) + partial_path = _partial_path(partial_name, "rb") + return super unless File.exist?(partial_path) + + (@_locals_stack ||= []).push(options) + (@_buffer_stack ||= []).push(@_erbout) + @_erbout = OutputBuffer.new + + tmpl = site.tmp_cache["partial-tmpl:#{partial_path}"] ||= + options.keys.map do |k| + "#{k}=locals[:#{k}];" + end.push(File.read(partial_path)).join + + instance_eval(tmpl).to_s.tap do + @_locals_stack.pop + @_erbout = @_buffer_stack.pop + end + end + + def _output_buffer + @_erbout # might be nil + end + + def locals + @_locals_stack&.last || {} + end + end + module Converters class RubyTemplates < Converter priority :highest input :rb def convert(content, convertible) - erb_view = Bridgetown::ERBView.new(convertible) - erb_view.instance_eval( + rb_view = Bridgetown::PureRubyView.new(convertible) + results = rb_view.instance_eval( content, convertible.path.to_s, line_start(convertible) - ).to_s + ) + rb_view._output_buffer || results.to_s end end end diff --git a/bridgetown-core/test/resources/src/_events/2020-12-25-christmas.html b/bridgetown-core/test/resources/src/_events/2020-12-25-christmas.html index d1c472b37..da8e5abfc 100644 --- a/bridgetown-core/test/resources/src/_events/2020-12-25-christmas.html +++ b/bridgetown-core/test/resources/src/_events/2020-12-25-christmas.html @@ -6,4 +6,4 @@ end %>--- -Fa <%= 8.times.map { "la" }.join(" ") %>! \ No newline at end of file +Fa <%= pipe(8) { times | map(->(_) { "la" }) | join(" ") | concat("!") } %> \ No newline at end of file diff --git a/bridgetown-core/test/resources/src/_pages/i-am-ruby.rb b/bridgetown-core/test/resources/src/_pages/i-am-ruby.rb index 5ef5b3805..7fda84b9b 100644 --- a/bridgetown-core/test/resources/src/_pages/i-am-ruby.rb +++ b/bridgetown-core/test/resources/src/_pages/i-am-ruby.rb @@ -2,11 +2,31 @@ front_matter do layout :default title "I am Ruby. Here me roar!" + include_markdown true end ### -markdownify <<~MARKDOWN +render html: <<-HTML +

Hello #{text "

world

"}

+ #{ render "a_partial", abc: 123 } + #{ render "an_erb_partial", abc: 456 } +HTML - > Well, _this_ is quite interesting! =) +if data.include_markdown + render do + markdownify <<~MARKDOWN -MARKDOWN + > Well, _this_ is quite interesting! =) + + MARKDOWN + end +end + +render html: <<-HTML + +HTML diff --git a/bridgetown-core/test/resources/src/_partials/_a_partial.rb b/bridgetown-core/test/resources/src/_partials/_a_partial.rb new file mode 100644 index 000000000..10c5ee196 --- /dev/null +++ b/bridgetown-core/test/resources/src/_partials/_a_partial.rb @@ -0,0 +1,3 @@ +render html: <<~HTML + #{text("Does this work?") { upcase | concat(" ") | concat(abc.to_s) }} +HTML \ No newline at end of file diff --git a/bridgetown-core/test/resources/src/_partials/_an_erb_partial.erb b/bridgetown-core/test/resources/src/_partials/_an_erb_partial.erb new file mode 100644 index 000000000..7e4aeaca4 --- /dev/null +++ b/bridgetown-core/test/resources/src/_partials/_an_erb_partial.erb @@ -0,0 +1 @@ +<%= "Does this work? #{abc}" %> \ No newline at end of file diff --git a/bridgetown-core/test/test_resource.rb b/bridgetown-core/test/test_resource.rb index e26486766..2bc141dc8 100644 --- a/bridgetown-core/test/test_resource.rb +++ b/bridgetown-core/test/test_resource.rb @@ -316,14 +316,27 @@ class TestResource < BridgetownUnitTest @site = resources_site @site.process @dest_file = File.read(dest_dir("i-am-ruby/index.html")) + Serbea::Pipeline.raise_on_missing_filters = true + # rubocop:disable Layout/TrailingWhitespace assert_includes @dest_file, <<~HTML +

Hello <p>world</p>

+ DOES THIS WORK? 123 + + Does this work? 456

Well, this is quite interesting! =)

-
+ + HTML + # rubocop:enable Layout/TrailingWhitespace end end diff --git a/bridgetown-website/Gemfile.lock b/bridgetown-website/Gemfile.lock index d5ac51708..327b349fe 100644 --- a/bridgetown-website/Gemfile.lock +++ b/bridgetown-website/Gemfile.lock @@ -25,7 +25,7 @@ PATH rake (>= 13.0) roda (~> 3.46) rouge (~> 3.0) - serbea (~> 1.0) + serbea (~> 2.0) thor (~> 1.1) tilt (~> 2.0) zeitwerk (~> 2.5) @@ -119,7 +119,7 @@ GEM ruby2js (5.1.0) parser regexp_parser (~> 2.1.1) - serbea (1.0.1) + serbea (2.0.0) activesupport (>= 6.0) erubi (>= 1.10) tilt (~> 2.0)