Skip to content

Commit 5094a47

Browse files
committed
Merge pull request #1580 from bquorning/empty-template-resolver-builder-2
Delegate properly to custom Resolver instances
2 parents 682a120 + c4bc440 commit 5094a47

File tree

8 files changed

+231
-9
lines changed

8 files changed

+231
-9
lines changed

Gemfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ else
2525
gem 'rake', '~> 10.0' # rake 11 requires Ruby 1.9.3 or later
2626
end
2727

28+
# Version 3 of mime-types 3 requires Ruby 2.0
29+
if RUBY_VERSION < '2.0.0'
30+
gem 'mime-types', '< 3'
31+
end
32+
2833
# Capybara versions that support RSpec 3 only support RUBY_VERSION >= 1.9.3
2934
if RUBY_VERSION >= '1.9.3'
3035
gem 'capybara', '~> 2.2.0', :require => false
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Static template named 'foo.html'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Static template named 'bar.html'

example_app_generator/generate_app.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
| gem 'rake', '~> 10.0' # rake 11 requires Ruby 1.9.3 or later
3939
|end
4040
|
41+
|# Version 3 of mime-types 3 requires Ruby 2.0
42+
|if RUBY_VERSION < '2.0.0'
43+
| gem 'mime-types', '< 3'
44+
|end
45+
|
4146
|gem 'rspec-rails',
4247
| :path => '#{rspec_rails_repo_path}',
4348
| :groups => [:development, :test]

example_app_generator/generate_stuff.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ def setup_tasks
1414

1515
def final_tasks
1616
copy_file 'spec/verify_active_record_spec.rb'
17+
copy_file 'app/views/foo.html'
18+
copy_file 'app/views/some_templates/bar.html'
19+
copy_file 'spec/verify_custom_renderers_spec.rb'
1720
copy_file 'spec/verify_fixture_warning_spec.rb'
1821
run('bin/rake db:migrate')
1922
if ::Rails::VERSION::STRING.to_f < 4.1
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
require 'rails_helper'
2+
3+
RSpec.describe "template rendering", :type => :controller do
4+
context "without render_views" do
5+
context "with the standard renderers" do
6+
controller do
7+
def index
8+
render :template => 'foo', :layout => false
9+
end
10+
end
11+
12+
it "renders the 'foo' template" do
13+
get :index
14+
15+
expect(response).to render_template(:foo)
16+
end
17+
18+
it "renders an empty string" do
19+
get :index
20+
21+
expect(response.body).to eq("")
22+
end
23+
end
24+
25+
context "with a String path prepended to the view path" do
26+
controller do
27+
def index
28+
prepend_view_path('app/views/some_templates')
29+
30+
render :template => 'bar', :layout => false
31+
end
32+
end
33+
34+
it "renders the 'bar' template" do
35+
get :index
36+
37+
expect(response).to render_template(:bar)
38+
end
39+
40+
it "renders an empty string" do
41+
get :index
42+
43+
expect(response.body).to eq("")
44+
end
45+
end
46+
47+
context "with a custom renderer prepended to the view path" do
48+
controller do
49+
def index
50+
prepend_view_path(MyResolver.new)
51+
52+
render :template => 'baz', :layout => false
53+
end
54+
end
55+
56+
it "renders the 'baz' template" do
57+
get :index
58+
59+
expect(response).to render_template(:baz)
60+
end
61+
62+
it "renders an empty string" do
63+
get :index
64+
65+
expect(response.body).to eq("")
66+
end
67+
end
68+
end
69+
70+
context "with render_views enabled" do
71+
render_views
72+
73+
context "with the standard renderers" do
74+
controller do
75+
def index
76+
render :template => 'foo', :layout => false
77+
end
78+
end
79+
80+
it "renders the 'foo' template" do
81+
get :index
82+
83+
expect(response).to render_template(:foo)
84+
end
85+
86+
it "renders the contents of the template" do
87+
get :index
88+
89+
expect(response.body).to include("Static template named 'foo.html'")
90+
end
91+
end
92+
93+
context "with a String path prepended to the view path" do
94+
controller do
95+
def index
96+
prepend_view_path('app/views/some_templates')
97+
98+
render :template => 'bar', :layout => false
99+
end
100+
end
101+
102+
it "renders the 'bar' template" do
103+
get :index
104+
105+
expect(response).to render_template(:bar)
106+
end
107+
108+
it "renders the contents of the template" do
109+
get :index
110+
111+
expect(response.body).to include("Static template named 'bar.html'")
112+
end
113+
end
114+
115+
context "with a custom renderer prepended to the view path" do
116+
controller do
117+
def index
118+
prepend_view_path(MyResolver.new)
119+
120+
render :template => 'baz', :layout => false
121+
end
122+
end
123+
124+
it "renders the 'baz' template" do
125+
get :index
126+
127+
expect(response).to render_template(:baz)
128+
end
129+
130+
it "renders the contents of the template" do
131+
get :index
132+
133+
expect(response.body).to eq("Dynamic template with path '/baz'")
134+
end
135+
end
136+
end
137+
138+
class MyResolver < ActionView::Resolver
139+
private
140+
141+
def find_templates(name, prefix = nil, partial = false, details = {}, key = nil, locals = [])
142+
name.prepend("_") if partial
143+
path = [prefix, name].join("/")
144+
template = find_template(name, path)
145+
146+
[template]
147+
end
148+
149+
def find_template(name, path)
150+
ActionView::Template.new(
151+
"",
152+
name,
153+
lambda { |_template| %("Dynamic template with path '#{_template.virtual_path}'") },
154+
:virtual_path => path,
155+
:format => :html
156+
)
157+
end
158+
end
159+
end

lib/rspec/rails/view_rendering.rb

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,18 @@ def render_views?
3939
self.class.render_views? || !controller.class.respond_to?(:view_paths)
4040
end
4141

42-
# Delegates find_all to the submitted path set and then returns templates
43-
# with modified source
44-
#
4542
# @private
46-
class EmptyTemplateResolver < ::ActionView::FileSystemResolver
47-
private
43+
class EmptyTemplateResolver
44+
def self.build(path)
45+
if path.is_a?(::ActionView::Resolver)
46+
ResolverDecorator.new(path)
47+
else
48+
FileSystemResolver.new(path)
49+
end
50+
end
4851

49-
def find_templates(*args)
50-
super.map do |template|
52+
def self.nullify_template_rendering(templates)
53+
templates.map do |template|
5154
::ActionView::Template.new(
5255
"",
5356
template.identifier,
@@ -57,6 +60,44 @@ def find_templates(*args)
5760
)
5861
end
5962
end
63+
64+
# Delegates all methods to the submitted resolver and for all methods
65+
# that return a collection of `ActionView::Template` instances, return
66+
# templates with modified source
67+
#
68+
# @private
69+
class ResolverDecorator
70+
def initialize(resolver)
71+
@resolver = resolver
72+
end
73+
74+
def method_missing(name, *args, &block)
75+
result = @resolver.send(name, *args, &block)
76+
nullify_templates(result)
77+
end
78+
79+
private
80+
81+
def nullify_templates(collection)
82+
return collection unless collection.is_a?(Enumerable)
83+
return collection unless collection.all? { |element| element.is_a?(::ActionView::Template) }
84+
85+
EmptyTemplateResolver.nullify_template_rendering(collection)
86+
end
87+
end
88+
89+
# Delegates find_templates to the submitted path set and then returns
90+
# templates with modified source
91+
#
92+
# @private
93+
class FileSystemResolver < ::ActionView::FileSystemResolver
94+
private
95+
96+
def find_templates(*args)
97+
templates = super
98+
EmptyTemplateResolver.nullify_template_rendering(templates)
99+
end
100+
end
60101
end
61102

62103
# @private
@@ -81,13 +122,13 @@ def append_view_path(new_path)
81122
private
82123

83124
def _path_decorator(*paths)
84-
paths.map { |path| EmptyTemplateResolver.new(path) }
125+
paths.map { |path| EmptyTemplateResolver.build(path) }
85126
end
86127
end
87128

88129
# @private
89130
RESOLVER_CACHE = Hash.new do |hash, path|
90-
hash[path] = EmptyTemplateResolver.new(path)
131+
hash[path] = EmptyTemplateResolver.build(path)
91132
end
92133

93134
included do

spec/rspec/rails/view_rendering_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ def example.controller
139139
expect(controller.view_paths.map(&:to_s)).to match_paths 'app/views', 'app/legacy_views', 'app/others', 'app/more_views'
140140
end
141141

142+
it 'supports manipulating view paths with resolvers' do
143+
expect {
144+
controller.prepend_view_path ActionView::Resolver.new
145+
controller.append_view_path ActionView::Resolver.new
146+
}.to_not raise_error
147+
end
148+
142149
def match_paths(*paths)
143150
eq paths.map { |path| File.expand_path path }
144151
end

0 commit comments

Comments
 (0)