From b11175372ea10c9c8a3bb6f7e26da3cc4cc9c12f Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Thu, 5 Oct 2023 11:53:05 -0500 Subject: [PATCH 1/2] Remove TruffleRuby from CI There is currently a bug in TruffleRuby ([truffleruby#3285][]) wherein `Kernel#binding` does not capture a given anonymous block, which breaks `yield` calls evaluated using that binding. This bug is preventing us from extending our rendering API. Furthermore, this bug was caught by a test unit for said API extension, but our views themselves aren't tested by CI. So if such a `yield` call were added to a view, CI would still pass but the `sdoc` command would be broken when using TruffleRuby. Also, Rails itself does not officially support TruffleRuby. Considering all of the above, this commit removes TruffleRuby from CI. [truffleruby#3285]: https://github.com/oracle/truffleruby/issues/3285 --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 482e4d44..21c7ef8e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,6 @@ jobs: - '3.1' - '3.2' - 'ruby-head' - - 'truffleruby-head' steps: - uses: actions/checkout@v1 From 3f81fde9fb1623ae70967812641b480ed917b42a Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Fri, 15 Sep 2023 21:33:43 -0500 Subject: [PATCH 2/2] Add SDoc::Renderer#inline `SDoc::Renderer#inline` renders a template to the current output buffer instead of as a separate string. It also allows a block to be specified so that the template can `yield` to perform interleaved rendering. For example: ```erb <% inline "_partial.erb" do %> content <% end %> ``` ```erb <%# _partial.erb %>
<% yield %>
``` Renders: ```html
content
``` --- lib/rdoc/generator/template/rails/class.rhtml | 6 +-- lib/rdoc/generator/template/rails/file.rhtml | 6 +-- lib/rdoc/generator/template/rails/index.rhtml | 6 +-- lib/sdoc/renderer.rb | 15 +++++- spec/renderer_spec.rb | 51 +++++++++++++++++++ 5 files changed, 73 insertions(+), 11 deletions(-) diff --git a/lib/rdoc/generator/template/rails/class.rhtml b/lib/rdoc/generator/template/rails/class.rhtml index 205c5e2a..18d4b1bf 100644 --- a/lib/rdoc/generator/template/rails/class.rhtml +++ b/lib/rdoc/generator/template/rails/class.rhtml @@ -4,7 +4,7 @@ <%= page_title @context.full_name %> - <%= render "_head.rhtml", { :tree_keys => @context.full_name.split('::') } %> + <% inline "_head.rhtml", { :tree_keys => @context.full_name.split('::') } %> @@ -13,14 +13,14 @@ Skip to Content Skip to Search - <%= render "_panel.rhtml" %> + <% inline "_panel.rhtml" %>

<%= @context.type %> <%= module_breadcrumbs @context %>

- <%= render "_context.rhtml" %> + <% inline "_context.rhtml" %>
Definition files
<%= more_less_ul @context.in_files.map { |file| link_to file }, 5..9 %> diff --git a/lib/rdoc/generator/template/rails/file.rhtml b/lib/rdoc/generator/template/rails/file.rhtml index c2a5637b..e0802e37 100644 --- a/lib/rdoc/generator/template/rails/file.rhtml +++ b/lib/rdoc/generator/template/rails/file.rhtml @@ -4,7 +4,7 @@ <%= page_title @context.name %> - <%= render "_head.rhtml", { :tree_keys => [] } %> + <% inline "_head.rhtml", { :tree_keys => [] } %> @@ -13,7 +13,7 @@ Skip to Content Skip to Search - <%= render "_panel.rhtml" %> + <% inline "_panel.rhtml" %>
@@ -26,7 +26,7 @@ <% end %> - <%= render "_context.rhtml" %> + <% inline "_context.rhtml" %>
diff --git a/lib/rdoc/generator/template/rails/index.rhtml b/lib/rdoc/generator/template/rails/index.rhtml index 88ac6c42..e17b1008 100644 --- a/lib/rdoc/generator/template/rails/index.rhtml +++ b/lib/rdoc/generator/template/rails/index.rhtml @@ -4,17 +4,17 @@ <%= page_title %> - <%= render "_head.rhtml", {tree_keys: []} %> + <% inline "_head.rhtml", {tree_keys: []} %> Skip to Content Skip to Search - <%= render "_panel.rhtml" %> + <% inline "_panel.rhtml" %>
- <%= render "_context.rhtml" %> + <% inline "_context.rhtml" %>
diff --git a/lib/sdoc/renderer.rb b/lib/sdoc/renderer.rb index 774df17c..da4cf3b8 100644 --- a/lib/sdoc/renderer.rb +++ b/lib/sdoc/renderer.rb @@ -7,18 +7,29 @@ class SDoc::Renderer def self.compile_erb(path) @compiled_erb ||= {} @compiled_erb[path] ||= begin - erb = ERB.new(File.read(path), trim_mode: "<>") + erb = ERB.new(File.read(path), trim_mode: "<>", eoutvar: "self.buffer") erb.filename = path erb end end + attr_reader :buffer + def buffer=(*); end # Ignore buffer reset from ERB itself. + def initialize(context, rdoc_options) @context = context @options = rdoc_options + @buffer = nil + end + + def render(...) + original_buffer, @buffer = @buffer, +"" + inline(...) + ensure + @buffer = original_buffer end - def render(template_path, local_assigns = {}) + def inline(template_path, local_assigns = {}) template_path = File.expand_path(template_path, @options.template_dir) _binding = binding local_assigns.each { |name, value| _binding.local_variable_set(name, value) } diff --git a/spec/renderer_spec.rb b/spec/renderer_spec.rb index 3e417f1f..2b3dcc7c 100644 --- a/spec/renderer_spec.rb +++ b/spec/renderer_spec.rb @@ -51,5 +51,56 @@ def create_template(name, erb) _(SDoc::Renderer.new(nil, @rdoc_options).render("foo.erb")). must_equal "foo & bar" end + + it "is reentrant" do + create_template "foo.erb", %(1 + 1 = <%= render "two.erb" %>) + create_template "two.erb", %(<%= 1 + 1 %>) + + _(SDoc::Renderer.new(nil, @rdoc_options).render("foo.erb")). + must_equal "1 + 1 = 2" + end + end + + describe "#inline" do + it "supports isolated local variables" do + create_template "outer.erb", %(<%= foo %> <% inline "inner.erb", bar: "BAR" %> <%= foo %>) + create_template "inner.erb", %(<%= foo = bar %>) + + _(SDoc::Renderer.new(nil, @rdoc_options).render("outer.erb", { foo: "FOO" })). + must_equal "FOO BAR FOO" + end + + it "provides access to the same non-local values as #render" do + create_template "outer.erb", %(<% inline "inner.erb" %>) + create_template "inner.erb", %(<%= h @context[:foobar] %>) + + _(SDoc::Renderer.new({ foobar: "foo & bar" }, @rdoc_options).render("outer.erb")). + must_equal "foo & bar" + end + + it "supports yield" do + create_template "outer.erb", '1 <% inline("inner.erb") { 3 } %> 5' + create_template "inner.erb", %(2 <%= yield %> 4) + + _(SDoc::Renderer.new(nil, @rdoc_options).render("outer.erb")). + must_equal "1 2 3 4 5" + end + + it "supports interleaved rendering" do + create_template "outer.erb", '1 <% inline("inner.erb") do %>3<% end %> 5' + create_template "inner.erb", %(2 <% yield %> 4) + + _(SDoc::Renderer.new(nil, @rdoc_options).render("outer.erb")). + must_equal "1 2 3 4 5" + end + + it "supports interleaved rendering with nested #inline calls" do + create_template "outer.erb", '1 <% inline("middle.erb") { inline("inner.erb") } %> 5' + create_template "middle.erb", %(2 <% yield %> 4) + create_template "inner.erb", %(3) + + _(SDoc::Renderer.new(nil, @rdoc_options).render("outer.erb")). + must_equal "1 2 3 4 5" + end end end