Refactor RablRails#render to use standard library
methods. Emulate a render and lookup context like Rails.
This commit is contained in:
parent
c60306eee5
commit
d4c434e6b0
|
@ -6,18 +6,53 @@ module RablRails
|
||||||
mattr_reader :view_path
|
mattr_reader :view_path
|
||||||
@@view_path = 'app/views'
|
@@view_path = 'app/views'
|
||||||
|
|
||||||
|
class LookupContext
|
||||||
|
T = Struct.new(:source)
|
||||||
|
|
||||||
|
def initialize(view_path, format)
|
||||||
|
@view_path = view_path || RablRails::Renderer.view_path
|
||||||
|
@format = format
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Manually find given rabl template file with given format.
|
||||||
|
# View path can be set via options, otherwise default Rails
|
||||||
|
# path is used
|
||||||
|
#
|
||||||
|
def find_template(name, opt, partial = false)
|
||||||
|
path = File.join(@view_path, "#{name}.#{@format}.rabl")
|
||||||
|
File.exists?(path) ? T.new(File.read(path)) : nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Context class to emulate normal rendering view
|
# Context class to emulate normal rendering view
|
||||||
# context
|
# context
|
||||||
#
|
#
|
||||||
class Context
|
class Context
|
||||||
def initialize
|
attr_reader :format
|
||||||
|
attr_accessor :target_object
|
||||||
|
|
||||||
|
def initialize(path, options)
|
||||||
|
@virtual_path = path
|
||||||
|
@format = options.delete(:format) || 'json'
|
||||||
@_assigns = {}
|
@_assigns = {}
|
||||||
|
@options = options
|
||||||
|
|
||||||
|
options[:locals].each { |k, v| @_assigns[k.to_s] = v } if options[:locals]
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigns
|
def assigns
|
||||||
@_assigns
|
@_assigns
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def params
|
||||||
|
{ format: format }
|
||||||
|
end
|
||||||
|
|
||||||
|
def lookup_context
|
||||||
|
@lookup_context ||= LookupContext.new(@options[:view_path], format)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -30,29 +65,14 @@ module RablRails
|
||||||
# an option: { format: 'xml' }
|
# an option: { format: 'xml' }
|
||||||
#
|
#
|
||||||
def render(object, template, options = {})
|
def render(object, template, options = {})
|
||||||
format = options.delete(:format) || 'json'
|
|
||||||
object = options[:locals].delete(:object) if !object && options[:locals]
|
object = options[:locals].delete(:object) if !object && options[:locals]
|
||||||
|
|
||||||
source = find_template(template, format, options.delete(:view_path))
|
c = Context.new(template, options)
|
||||||
compiled_template = Compiler.new.compile_source(source)
|
c.target_object = object
|
||||||
|
|
||||||
c = Context.new
|
t = c.lookup_context.find_template(template, [], false)
|
||||||
c.assigns[compiled_template.data.to_s[1..-1]] = object if compiled_template.data
|
|
||||||
|
|
||||||
Renderers.const_get(format.upcase!).new(c).render(compiled_template)
|
Library.instance.get_rendered_template(t.source, c)
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
#
|
|
||||||
# Manually find given rabl template file with given format.
|
|
||||||
# View path can be set via options, otherwise default Rails
|
|
||||||
# path is used
|
|
||||||
#
|
|
||||||
def find_template(name, format, view_path = nil)
|
|
||||||
view_path ||= self.view_path
|
|
||||||
path = File.join(view_path, "#{name}.#{format}.rabl")
|
|
||||||
File.exists?(path) ? File.read(path) : nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -19,6 +19,7 @@ module RablRails
|
||||||
#
|
#
|
||||||
def render(template)
|
def render(template)
|
||||||
collection_or_resource = instance_variable_get(template.data) if template.data
|
collection_or_resource = instance_variable_get(template.data) if template.data
|
||||||
|
collection_or_resource = @_context.target_object unless collection_or_resource || template.data == false || !@_context.respond_to?(:target_object)
|
||||||
output_hash = collection_or_resource.respond_to?(:each) ? render_collection(collection_or_resource, template.source) :
|
output_hash = collection_or_resource.respond_to?(:each) ? render_collection(collection_or_resource, template.source) :
|
||||||
render_resource(collection_or_resource, template.source)
|
render_resource(collection_or_resource, template.source)
|
||||||
options[:root_name] = template.root_name
|
options[:root_name] = template.root_name
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
require 'test_helper'
|
||||||
|
require 'pathname'
|
||||||
|
require 'tmpdir'
|
||||||
|
|
||||||
|
class RenderTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
|
setup do
|
||||||
|
@user = User.new(1, 'Marty')
|
||||||
|
@user.stub(:respond_to?).with(:each).and_return(false)
|
||||||
|
@tmp_path = Pathname.new(Dir.mktmpdir)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "allow object to be passed as an option" do
|
||||||
|
File.open(@tmp_path + "nil.json.rabl", "w") do |f|
|
||||||
|
f.puts %q{
|
||||||
|
object :@user
|
||||||
|
attributes :name
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal %q({"user":{"name":"Marty"}}), RablRails.render(nil, 'nil', locals: { object: @user }, view_path: @tmp_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "load source from file" do
|
||||||
|
File.open(@tmp_path + "show.json.rabl", "w") do |f|
|
||||||
|
f.puts %q{
|
||||||
|
object :@user
|
||||||
|
attributes :id, :name
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal %q({"user":{"id":1,"name":"Marty"}}), RablRails.render(@user, 'show', view_path: @tmp_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "handle path for extends" do
|
||||||
|
File.open(@tmp_path + "extend.json.rabl", "w") do |f|
|
||||||
|
f.puts %q{
|
||||||
|
object :@user
|
||||||
|
extends 'base'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
File.open(@tmp_path + "base.json.rabl", "w") do |f|
|
||||||
|
f.puts %q{
|
||||||
|
attribute :name, as: :extended_name
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal %q({"user":{"extended_name":"Marty"}}), RablRails.render(@user, 'extend', view_path: @tmp_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in New Issue