-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Delegate properly to custom Resolver instances #1580
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Static template named 'foo.html' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Static template named 'bar.html' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
require 'rails_helper' | ||
|
||
RSpec.describe "template rendering", :type => :controller do | ||
context "without render_views" do | ||
context "with the standard renderers" do | ||
controller do | ||
def index | ||
render :template => 'foo', :layout => false | ||
end | ||
end | ||
|
||
it "renders the 'foo' template" do | ||
get :index | ||
|
||
expect(response).to render_template(:foo) | ||
end | ||
|
||
it "renders an empty string" do | ||
get :index | ||
|
||
expect(response.body).to eq("") | ||
end | ||
end | ||
|
||
context "with a String path prepended to the view path" do | ||
controller do | ||
def index | ||
prepend_view_path('app/views/some_templates') | ||
|
||
render :template => 'bar', :layout => false | ||
end | ||
end | ||
|
||
it "renders the 'bar' template" do | ||
get :index | ||
|
||
expect(response).to render_template(:bar) | ||
end | ||
|
||
it "renders an empty string" do | ||
get :index | ||
|
||
expect(response.body).to eq("") | ||
end | ||
end | ||
|
||
context "with a custom renderer prepended to the view path" do | ||
controller do | ||
def index | ||
prepend_view_path(MyResolver.new) | ||
|
||
render :template => 'baz', :layout => false | ||
end | ||
end | ||
|
||
it "renders the 'baz' template" do | ||
get :index | ||
|
||
expect(response).to render_template(:baz) | ||
end | ||
|
||
it "renders an empty string" do | ||
get :index | ||
|
||
expect(response.body).to eq("") | ||
end | ||
end | ||
end | ||
|
||
context "with render_views enabled" do | ||
render_views | ||
|
||
context "with the standard renderers" do | ||
controller do | ||
def index | ||
render :template => 'foo', :layout => false | ||
end | ||
end | ||
|
||
it "renders the 'foo' template" do | ||
get :index | ||
|
||
expect(response).to render_template(:foo) | ||
end | ||
|
||
it "renders the contents of the template" do | ||
get :index | ||
|
||
expect(response.body).to include("Static template named 'foo.html'") | ||
end | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great start, we just need to check that the views are empty (as |
||
|
||
context "with a String path prepended to the view path" do | ||
controller do | ||
def index | ||
prepend_view_path('app/views/some_templates') | ||
|
||
render :template => 'bar', :layout => false | ||
end | ||
end | ||
|
||
it "renders the 'bar' template" do | ||
get :index | ||
|
||
expect(response).to render_template(:bar) | ||
end | ||
|
||
it "renders the contents of the template" do | ||
get :index | ||
|
||
expect(response.body).to include("Static template named 'bar.html'") | ||
end | ||
end | ||
|
||
context "with a custom renderer prepended to the view path" do | ||
controller do | ||
def index | ||
prepend_view_path(MyResolver.new) | ||
|
||
render :template => 'baz', :layout => false | ||
end | ||
end | ||
|
||
it "renders the 'baz' template" do | ||
get :index | ||
|
||
expect(response).to render_template(:baz) | ||
end | ||
|
||
it "renders the contents of the template" do | ||
get :index | ||
|
||
expect(response.body).to eq("Dynamic template with path '/baz'") | ||
end | ||
end | ||
end | ||
|
||
class MyResolver < ActionView::Resolver | ||
private | ||
|
||
def find_templates(name, prefix = nil, partial = false, details = {}, key = nil, locals = []) | ||
name.prepend("_") if partial | ||
path = [prefix, name].join("/") | ||
template = find_template(name, path) | ||
|
||
[template] | ||
end | ||
|
||
def find_template(name, path) | ||
ActionView::Template.new( | ||
"", | ||
name, | ||
lambda { |_template| %("Dynamic template with path '#{_template.virtual_path}'") }, | ||
:virtual_path => path, | ||
:format => :html | ||
) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,15 +39,18 @@ def render_views? | |
self.class.render_views? || !controller.class.respond_to?(:view_paths) | ||
end | ||
|
||
# Delegates find_all to the submitted path set and then returns templates | ||
# with modified source | ||
# | ||
# @private | ||
class EmptyTemplateResolver < ::ActionView::FileSystemResolver | ||
private | ||
class EmptyTemplateResolver | ||
def self.build(path) | ||
if path.is_a?(::ActionView::Resolver) | ||
ResolverDecorator.new(path) | ||
else | ||
FileSystemResolver.new(path) | ||
end | ||
end | ||
|
||
def find_templates(*args) | ||
super.map do |template| | ||
def self.nullify_template_rendering(templates) | ||
templates.map do |template| | ||
::ActionView::Template.new( | ||
"", | ||
template.identifier, | ||
|
@@ -57,6 +60,44 @@ def find_templates(*args) | |
) | ||
end | ||
end | ||
|
||
# Delegates all methods to the submitted resolver and for all methods | ||
# that return a collection of `ActionView::Template` instances, return | ||
# templates with modified source | ||
# | ||
# @private | ||
class ResolverDecorator | ||
def initialize(resolver) | ||
@resolver = resolver | ||
end | ||
|
||
def method_missing(name, *args, &block) | ||
result = @resolver.send(name, *args, &block) | ||
nullify_templates(result) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realize that inspecting return values’ type isn't particularly good design. The alternative is to override |
||
end | ||
|
||
private | ||
|
||
def nullify_templates(collection) | ||
return collection unless collection.is_a?(Enumerable) | ||
return collection unless collection.all? { |element| element.is_a?(::ActionView::Template) } | ||
|
||
EmptyTemplateResolver.nullify_template_rendering(collection) | ||
end | ||
end | ||
|
||
# Delegates find_templates to the submitted path set and then returns | ||
# templates with modified source | ||
# | ||
# @private | ||
class FileSystemResolver < ::ActionView::FileSystemResolver | ||
private | ||
|
||
def find_templates(*args) | ||
templates = super | ||
EmptyTemplateResolver.nullify_template_rendering(templates) | ||
end | ||
end | ||
end | ||
|
||
# @private | ||
|
@@ -81,13 +122,13 @@ def append_view_path(new_path) | |
private | ||
|
||
def _path_decorator(*paths) | ||
paths.map { |path| EmptyTemplateResolver.new(path) } | ||
paths.map { |path| EmptyTemplateResolver.build(path) } | ||
end | ||
end | ||
|
||
# @private | ||
RESOLVER_CACHE = Hash.new do |hash, path| | ||
hash[path] = EmptyTemplateResolver.new(path) | ||
hash[path] = EmptyTemplateResolver.build(path) | ||
end | ||
|
||
included do | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://travis-ci.org/rspec/rspec-rails/builds/118239747 failed to bundle because v2.6.4 of
mail
is out, which allows bundling withmime-types < 4
instead of, as earlier,mime-types < 3
.