Skip to content

Commit

Permalink
Support pipe in Serbea 2.0, add new pure Ruby template syntax (WIP) (
Browse files Browse the repository at this point in the history
…#817)

* Support `pipe` in Serbea 2.0, add new pure Ruby template syntax

* Refactor HTMLinRuby template syntax

* Ensure `pipe` is available to components

* Support MARKDOWN in cop

* Arrive at final syntax

* fix test on Ruby 3.2

* Skip Ruby template test on v2.7.2

* Update how the text string helpers works

* Pull in new Streamlined dependency

* Streamlined tweaks; components now automatically support syntax

* Support Ruby 3.3 for Nokolexbor

* Streamline (heh) Streamlined integration

* Syntax improvements based on updated Streamlined

* Add slick "Ruby front matter" DSL to Roda routes

- also update cookies config

* Fix test with cookies

* back out of secure default
  • Loading branch information
jaredcwhite authored Apr 12, 2024
1 parent 6e0751a commit 54e56ef
Show file tree
Hide file tree
Showing 24 changed files with 221 additions and 98 deletions.
26 changes: 15 additions & 11 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ PATH
rake (>= 13.0)
roda (~> 3.46)
rouge (>= 3.0, < 5.0)
serbea (~> 1.0)
serbea (~> 2.1)
signalize (~> 1.3)
streamlined (>= 0.5.2)
serbea (~> 1.0)
thor (~> 1.1)
tilt (~> 2.0)
zeitwerk (~> 2.5)
Expand Down Expand Up @@ -76,7 +78,7 @@ GEM
colorator (1.1.0)
concurrent-ruby (1.2.3)
connection_pool (2.4.1)
csv (3.2.8)
csv (3.3.0)
diff-lcs (1.5.1)
docile (1.4.0)
drb (2.2.1)
Expand All @@ -94,7 +96,7 @@ GEM
i18n (1.14.4)
concurrent-ruby (~> 1.0)
jaro_winkler (1.5.6)
json (2.7.1)
json (2.7.2)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
Expand Down Expand Up @@ -133,13 +135,13 @@ GEM
parser (3.3.0.5)
ast (~> 2.4.1)
racc
public_suffix (5.0.4)
public_suffix (5.0.5)
racc (1.7.3)
rack (3.0.9.1)
rack (3.0.10)
rack-test (2.1.0)
rack (>= 1.3)
rainbow (3.1.1)
rake (13.1.0)
rake (13.2.1)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
Expand All @@ -150,7 +152,7 @@ GEM
rexml (3.2.6)
roda (3.78.0)
rack
rouge (4.2.0)
rouge (4.2.1)
rspec-mocks (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
Expand All @@ -171,12 +173,11 @@ GEM
rubocop-bridgetown (0.4.1)
rubocop (~> 1.23)
rubocop-performance (~> 1.12)
rubocop-performance (1.20.2)
rubocop-performance (1.21.0)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.30.0, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (1.13.0)
serbea (1.0.1)
activesupport (>= 6.0)
serbea (2.1.0)
erubi (>= 1.10)
tilt (~> 2.0)
shoulda (4.0.0)
Expand Down Expand Up @@ -209,6 +210,9 @@ GEM
thor (~> 1.0)
tilt (~> 2.0)
yard (~> 0.9, >= 0.9.24)
streamlined (0.5.2)
serbea (>= 2.1)
zeitwerk (~> 2.5)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
thor (1.3.1)
Expand Down
2 changes: 1 addition & 1 deletion bridgetown-builder/lib/bridgetown-builder/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 0 additions & 21 deletions bridgetown-builder/test/test_hooks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion bridgetown-core/bridgetown-core.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ 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", "< 5.0"])
s.add_runtime_dependency("serbea", "~> 1.0")
s.add_runtime_dependency("serbea", "~> 2.1")
s.add_runtime_dependency("signalize", "~> 1.3")
s.add_runtime_dependency("streamlined", ">= 0.5.2")
s.add_runtime_dependency("thor", "~> 1.1")
s.add_runtime_dependency("tilt", "~> 2.0")
s.add_runtime_dependency("zeitwerk", "~> 2.5")
Expand Down
2 changes: 2 additions & 0 deletions bridgetown-core/lib/bridgetown-core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,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
Expand Down
1 change: 1 addition & 0 deletions bridgetown-core/lib/bridgetown-core/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

module Bridgetown
class Component
include Bridgetown::Streamlined
extend Forwardable

def_delegators :@view_context, :liquid_render, :partial
Expand Down
1 change: 1 addition & 0 deletions bridgetown-core/lib/bridgetown-core/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def run_initializers!(context:) # rubocop:todo Metrics/AbcSize, Metrics/Cyclomat
dsl = ConfigurationDSL.new(scope: self, data: self)
dsl.instance_variable_set(:@context, context)
dsl.instance_exec(dsl, &init_init.block)
dsl._run_builtins!
self.url = cached_url if cached_url # restore local development URL if need be

setup_load_paths! appending: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ def _setup_initializer(name:, require_gem:, require_initializer:)
def _in_require_denylist?(name)
REQUIRE_DENYLIST.include?(name.to_sym)
end

# Initializers that are part of the Bridgetown boot sequence. Site owners can override
# defaults by running any of these manually…init is no-op if the initializer was already run.
def _run_builtins!
init :streamlined
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ def capture(*args)
end

class ERBView < RubyTemplateView
include ERBCapture

def h(input)
Erubi.h(input)
end
Expand Down
59 changes: 56 additions & 3 deletions bridgetown-core/lib/bridgetown-core/converters/ruby_templates.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,69 @@
# frozen_string_literal: true

require "streamlined/renderable"

module Bridgetown
class PureRubyView < ERBView
def render(item = nil, **options, &block) # rubocop:disable Metrics
return @_erbout if !block && options.empty? && item.nil?

if item.is_a?(Proc) || (block && item.nil?)
result = item.is_a?(Proc) ? item.() : 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&.to_s&.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
Expand Down
46 changes: 6 additions & 40 deletions bridgetown-core/lib/bridgetown-core/helpers.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# frozen_string_literal: true

require "streamlined/helpers"
require "active_support/html_safe_translation"

module Bridgetown
class RubyTemplateView
class Helpers
include Bridgetown::Filters
include Bridgetown::Filters::FromLiquid
include ::Streamlined::Helpers

# @return [Bridgetown::RubyTemplateView]
attr_reader :view
Expand Down Expand Up @@ -114,28 +116,13 @@ def link_to(text, relative_path = nil, options = {}, &block)
elsif relative_path.nil?
raise ArgumentError, "You must provide a relative path"
end
segments = attributes_from_options({ href: url_for(relative_path) }.merge(options))
segments = html_attributes({ href: url_for(relative_path) }.merge(options))

safe("<a #{segments}>#{text}</a>")
end

# Create a set of attributes from a hash.
#
# @param options [Hash] key-value pairs of HTML attributes
# @return [String]
def attributes_from_options(options)
segments = []
options.each do |attr, option|
attr = dashed(attr)
if option.is_a?(Hash)
option = option.transform_keys { |key| "#{attr}-#{dashed(key)}" }
segments << attributes_from_options(option)
else
segments << attribute_segment(attr, option)
end
end
safe(segments.join(" "))
end
# Provide backwards compatibility via Streamlined helper
alias_method :attributes_from_options, :html_attributes

# Delegates to <tt>I18n#translate</tt> but also performs two additional
# functions.
Expand Down Expand Up @@ -294,30 +281,9 @@ def dsd_style

style_tag.html_safe
end

# TODO: docu
def bypass_tracking(...) = Signalize.untracked(...)

private

# Covert an underscored value into a dashed string.
#
# @example "foo_bar_baz" => "foo-bar-baz"
#
# @param value [String|Symbol]
# @return [String]
def dashed(value)
value.to_s.tr("_", "-")
end

# Create an attribute segment for a tag.
#
# @param attr [String] the HTML attribute name
# @param value [String] the attribute value
# @return [String]
def attribute_segment(attr, value)
"#{attr}=\"#{Utils.xml_escape(value)}\""
end
end
end
end
18 changes: 18 additions & 0 deletions bridgetown-core/lib/bridgetown-core/ruby_template_view.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
# frozen_string_literal: true

require "digest"
require "serbea/pipeline"
require "streamlined/helpers"
require "streamlined/renderable"

module Bridgetown
module Streamlined
include ::Streamlined::Renderable
include Serbea::Pipeline::Helper
include ERBCapture

def helper(name, &helper_block)
self.class.define_method(name) do |*args, **kwargs, &block|
helper_block.call(*args, **kwargs, &block)
end
end
alias_method :macro, :helper
end

class RubyTemplateView
require "bridgetown-core/helpers"

include Bridgetown::Streamlined

attr_reader :layout, :resource, :paginator, :site, :content
alias_method :page, :resource

Expand Down
2 changes: 1 addition & 1 deletion bridgetown-core/lib/roda/plugins/bridgetown_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def self.load_dependencies(app) # rubocop:disable Metrics
app.plugin :json
app.plugin :json_parser
app.plugin :indifferent_params
app.plugin :cookies
app.plugin :cookies, path: "/"
app.plugin :public, root: Bridgetown::Current.preloaded_configuration.destination
app.plugin :not_found do
output_folder = Bridgetown::Current.preloaded_configuration.destination
Expand Down
2 changes: 1 addition & 1 deletion bridgetown-core/lib/site_template/Gemfile.erb
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ gem "puma", "< 7"
# gem "nokogiri", "~> 1.13"

# Or for faster parsing of HTML-only resources via Inspectors, use Nokolexbor:
# gem "nokolexbor", "~> 0.4"
# gem "nokolexbor", "~> 0.5"
17 changes: 17 additions & 0 deletions bridgetown-core/test/resources/src/_components/ruby_html_text.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class RubyHtmlText < Bridgetown::Component
def template
# blub = ->(input, str, replace_str) { input.sub(str, replace_str) }

macro :flub do |input, str, replace_str|
input.sub str, replace_str
end

html -> {
<<~HTML
<p>This is #{text -> { "<b>escaped!</b>" }}</p>
#{html "piping <i>bad</i>", -> { text | concat(" <b>good</b>") | markdownify }}
#{text "_yipee_", -> { markdownify | flub("yipee", "yay") | html_safe }}
HTML
}
end
end
Loading

0 comments on commit 54e56ef

Please sign in to comment.