forked from soveran/cuba
-
Notifications
You must be signed in to change notification settings - Fork 139
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add part plugin, with a simpler (and better performing when using :as…
…sume_fixed_locals) method for rendering with locals This adds a part method, which only supports locals and no other render options: # Render plugin API: render(:template, locals: {foo: 'bar'}) # Same, but simpler, and potentially faster part(:template, foo: 'bar')
- Loading branch information
1 parent
1328205
commit 67fc63f
Showing
4 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# frozen-string-literal: true | ||
|
||
# | ||
class Roda | ||
module RodaPlugins | ||
# The part plugin adds a part method, which is an optimized | ||
# render method that only supports locals. | ||
# | ||
# # Can replace this: | ||
# render(:template, locals: {foo: 'bar'}) | ||
# | ||
# # With this: | ||
# part(:template, foo: 'bar') | ||
# | ||
# On Ruby 2.7+, the part method takes a keyword splat, so you | ||
# must pass keywords and not a positional hash for the locals. | ||
# | ||
# If you are using the :assume_fixed_locals render plugin option, | ||
# template caching is enabled, and you are using Ruby 3+, in | ||
# addition to providing a simpler API, this also provides a | ||
# significant performance improvement (more significant on Ruby | ||
# 3.4+). | ||
module Part | ||
def self.load_dependencies(app) | ||
app.plugin :render | ||
end | ||
|
||
def self.configure(app) | ||
if app.render_opts[:assume_fixed_locals] && !app.render_opts[:check_template_mtime] | ||
app.send(:include, AssumeFixedLocalsInstanceMethods) | ||
end | ||
end | ||
|
||
module InstanceMethods | ||
if RUBY_VERSION >= '2.7' | ||
class_eval(<<-RUBY, __FILE__, __LINE__ + 1) | ||
def part(template, **locals, &block) | ||
render(template, :locals=>locals, &block) | ||
end | ||
RUBY | ||
# :nocov: | ||
else | ||
def part(template, locals=OPTS, &block) | ||
render(template, :locals=>locals, &block) | ||
end | ||
end | ||
# :nocov: | ||
end | ||
|
||
module AssumeFixedLocalsInstanceMethods | ||
# :nocov: | ||
if RUBY_VERSION >= '3.0' | ||
# :nocov: | ||
class_eval(<<-RUBY, __FILE__, __LINE__ + 1) | ||
def part(template, ...) | ||
if optimized_method = _optimized_render_method_for_locals(template, OPTS) | ||
send(optimized_method[0], ...) | ||
else | ||
super | ||
end | ||
end | ||
RUBY | ||
end | ||
end | ||
end | ||
|
||
register_plugin(:part, Part) | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
require_relative "../spec_helper" | ||
|
||
begin | ||
require 'tilt' | ||
require 'tilt/erb' | ||
require 'tilt/string' | ||
require_relative '../../lib/roda/plugins/render' | ||
rescue LoadError | ||
warn "tilt not installed, skipping part plugin test" | ||
else | ||
describe "part plugin" do | ||
before do | ||
app(:bare) do | ||
plugin :render, :views=>"./spec/views", :check_paths=>true | ||
plugin :part | ||
|
||
route do |r| | ||
r.on "home" do | ||
part('layout', :title=>"Home"){part("home", :name => "Agent Smith", :title => "Home")} | ||
end | ||
|
||
r.on "about" do | ||
part("about", :title => "About Roda") | ||
end | ||
|
||
r.on "inline" do | ||
part({:inline=>"Hello <%= name %>"}, :name => "Agent Smith") | ||
end | ||
|
||
r.on "path" do | ||
part({:path=>"./spec/views/about.erb"}, :title => "Path") | ||
end | ||
|
||
r.on "render-block" do | ||
part('layout', :title=>"Home"){part("about", :title => "About Roda")} | ||
end | ||
end | ||
end | ||
end | ||
|
||
it "default actions" do | ||
body("/about").strip.must_equal "<h1>About Roda</h1>" | ||
body("/home").strip.must_equal "<title>Roda: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>" | ||
body("/inline").strip.must_equal "Hello Agent Smith" | ||
body("/path").strip.must_equal "<h1>Path</h1>" | ||
body("/render-block").strip.must_equal "<title>Roda: Home</title>\n<h1>About Roda</h1>" | ||
end | ||
|
||
it "with str as engine" do | ||
app.plugin :render, :engine => "str" | ||
body("/about").strip.must_equal "<h1>About Roda</h1>" | ||
body("/home").strip.must_equal "<title>Roda: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>" | ||
body("/inline").strip.must_equal "Hello <%= name %>" | ||
end | ||
|
||
if Roda::RodaPlugins::Render::FIXED_LOCALS_COMPILED_METHOD_SUPPORT | ||
[true, false].each do |cache_plugin_option| | ||
multiplier = cache_plugin_option ? 1 : 2 | ||
|
||
it "support fixed locals in layout templates with plugin option :cache=>#{cache_plugin_option}" do | ||
template = "comp_test" | ||
|
||
app(:bare) do | ||
plugin :render, :views=>'spec/views/fixed', :cache=>cache_plugin_option, :template_opts=>{:extract_fixed_locals=>true} | ||
plugin :part | ||
route do | ||
part("layout", title: "Home"){part(template)} | ||
end | ||
end | ||
|
||
layout_key = [:_render_locals, "layout"] | ||
template_key = [:_render_locals, template] | ||
app.render_opts[:template_method_cache][template_key].must_be_nil | ||
app.render_opts[:template_method_cache][layout_key].must_be_nil | ||
body.strip.must_equal "<title>Roda: Home</title>\nct" | ||
app.render_opts[:template_method_cache][template_key].must_be_kind_of(Array) | ||
app.render_opts[:template_method_cache][layout_key].must_be_kind_of(Array) | ||
body.strip.must_equal "<title>Roda: Home</title>\nct" | ||
app.render_opts[:template_method_cache][template_key].must_be_kind_of(Array) | ||
app.render_opts[:template_method_cache][layout_key].must_be_kind_of(Array) | ||
body.strip.must_equal "<title>Roda: Home</title>\nct" | ||
app.render_opts[:template_method_cache][template_key].must_be_kind_of(Array) | ||
app.render_opts[:template_method_cache][layout_key].must_be_kind_of(Array) | ||
app::RodaCompiledTemplates.private_instance_methods.length.must_equal(multiplier * 2) | ||
end | ||
|
||
it "support fixed locals in render templates with plugin option :cache=>#{cache_plugin_option}" do | ||
template = "local_test" | ||
|
||
app(:bare) do | ||
plugin :render, :views=>'spec/views/fixed', :cache=>cache_plugin_option, :template_opts=>{:extract_fixed_locals=>true} | ||
plugin :part | ||
route do | ||
part(template, title: 'ct') | ||
end | ||
end | ||
|
||
key = [:_render_locals, template] | ||
app.render_opts[:template_method_cache][key].must_be_nil | ||
body.strip.must_equal "ct" | ||
app.render_opts[:template_method_cache][key].must_be_kind_of(Array) | ||
body.strip.must_equal "ct" | ||
app.render_opts[:template_method_cache][key].must_be_kind_of(Array) | ||
body.strip.must_equal "ct" | ||
app.render_opts[:template_method_cache][key].must_be_kind_of(Array) | ||
app::RodaCompiledTemplates.private_instance_methods.length.must_equal multiplier | ||
end | ||
|
||
[true, false].each do |assume_fixed_locals_option| | ||
it "caches expectedly for cache: #{cache_plugin_option}, assume_fixed_locals: #{assume_fixed_locals_option} options" do | ||
template = "opt_local_test" | ||
|
||
app(:bare) do | ||
plugin :render, :views=>'spec/views/fixed', :cache=>cache_plugin_option, :template_opts=>{:extract_fixed_locals=>true}, :assume_fixed_locals=>assume_fixed_locals_option | ||
plugin :part | ||
route do |r| | ||
r.is 'a' do | ||
render(template) | ||
end | ||
part(template, title: 'ct') | ||
end | ||
end | ||
|
||
cache_size = 1 | ||
key = if assume_fixed_locals_option | ||
template | ||
else | ||
[:_render_locals, template] | ||
end | ||
cache = app.render_opts[:template_method_cache] | ||
cache[key].must_be_nil | ||
body.strip.must_equal "ct" | ||
cache[key].must_be_kind_of(Array) | ||
cache.instance_variable_get(:@hash).length.must_equal cache_size | ||
body.strip.must_equal "ct" | ||
cache[key].must_be_kind_of(Array) | ||
cache.instance_variable_get(:@hash).length.must_equal cache_size | ||
body.strip.must_equal "ct" | ||
cache[key].must_be_kind_of(Array) | ||
cache.instance_variable_get(:@hash).length.must_equal cache_size | ||
app::RodaCompiledTemplates.private_instance_methods.length.must_equal multiplier | ||
|
||
cache_size = 2 unless assume_fixed_locals_option | ||
key = template | ||
body('/a').strip.must_equal "ct" | ||
cache[key].must_be_kind_of(Array) | ||
cache.instance_variable_get(:@hash).length.must_equal cache_size | ||
body('/a').strip.must_equal "ct" | ||
cache[key].must_be_kind_of(Array) | ||
cache.instance_variable_get(:@hash).length.must_equal cache_size | ||
body('/a').strip.must_equal "ct" | ||
cache[key].must_be_kind_of(Array) | ||
cache.instance_variable_get(:@hash).length.must_equal cache_size | ||
app::RodaCompiledTemplates.private_instance_methods.length.must_equal(multiplier * cache_size) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters