Merge pull request #2 from ccocchi/render-method
Add RablRails#render method
This commit is contained in:
commit
d0b023936b
@ -16,6 +16,8 @@ require 'rabl-rails/railtie'
|
||||
require 'multi_json'
|
||||
|
||||
module RablRails
|
||||
extend Renderer
|
||||
|
||||
mattr_accessor :cache_templates
|
||||
@@cache_templates = true
|
||||
|
||||
|
@ -1,2 +1,91 @@
|
||||
require 'rabl-rails/renderers/base'
|
||||
require 'rabl-rails/renderers/json'
|
||||
require 'rabl-rails/renderers/json'
|
||||
|
||||
module RablRails
|
||||
module Renderer
|
||||
class TemplateNotFound < StandardError; end
|
||||
|
||||
mattr_reader :view_path
|
||||
@@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 Rails view
|
||||
# context
|
||||
#
|
||||
class Context
|
||||
attr_reader :format
|
||||
attr_accessor :target_object
|
||||
|
||||
def initialize(path, options)
|
||||
@virtual_path = path
|
||||
@format = options.delete(:format) || 'json'
|
||||
@_assigns = {}
|
||||
@options = options
|
||||
|
||||
options[:locals].each { |k, v| @_assigns[k.to_s] = v } if options[:locals]
|
||||
end
|
||||
|
||||
def assigns
|
||||
@_assigns
|
||||
end
|
||||
|
||||
def params
|
||||
{ format: format }
|
||||
end
|
||||
|
||||
def lookup_context
|
||||
@lookup_context ||= LookupContext.new(@options[:view_path], format)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Renders object with the given rabl template.
|
||||
#
|
||||
# Object can also be passed as an option :
|
||||
# { locals: { object: obj_to_render } }
|
||||
#
|
||||
# Default render format is JSON, but can be changed via
|
||||
# an option: { format: 'xml' }
|
||||
#
|
||||
# If template includes uses of instance variables (usually
|
||||
# defined in the controller), you can passed them as locals
|
||||
# options.
|
||||
# For example, if you have this template:
|
||||
# object :@user
|
||||
# node(:read) { |u| u.has_read?(@post) }
|
||||
#
|
||||
# Your method call should look like this:
|
||||
# RablRails.render(user, 'users/show', locals: { post: Post.new })
|
||||
#
|
||||
def render(object, template, options = {})
|
||||
object = options[:locals].delete(:object) if !object && options[:locals]
|
||||
|
||||
c = Context.new(template, options)
|
||||
c.target_object = object
|
||||
|
||||
t = c.lookup_context.find_template(template, [], false)
|
||||
raise TemplateNotFound unless t
|
||||
|
||||
Library.instance.get_rendered_template(t.source, c)
|
||||
end
|
||||
end
|
||||
end
|
@ -19,6 +19,7 @@ module RablRails
|
||||
#
|
||||
def render(template)
|
||||
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) :
|
||||
render_resource(collection_or_resource, template.source)
|
||||
_options[:root_name] = template.root_name
|
||||
|
64
test/render_test.rb
Normal file
64
test/render_test.rb
Normal file
@ -0,0 +1,64 @@
|
||||
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 "raise error if template is not found" do
|
||||
assert_raises(RablRails::Renderer::TemplateNotFound) { RablRails.render(@user, 'not_found') }
|
||||
end
|
||||
|
||||
test "instance variables can be passed via options[:locals]" do
|
||||
File.open(@tmp_path + "instance.json.rabl", "w") do |f|
|
||||
f.puts %q{
|
||||
object false
|
||||
node(:username) { |_| @user.name }
|
||||
}
|
||||
end
|
||||
assert_equal %q({"username":"Marty"}), RablRails.render(nil, 'instance', view_path: @tmp_path, locals: { user: @user })
|
||||
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
Block a user