From 4b61edad644e66d9bfa0b83f0e40e3c0c3c6c717 Mon Sep 17 00:00:00 2001 From: ccocchi Date: Thu, 13 Sep 2012 15:57:05 +0200 Subject: [PATCH] Locals are now passed to the renderer object. Allow to skip object or collection definition when using `respond_to` block --- lib/rabl-rails/handler.rb | 2 +- lib/rabl-rails/library.rb | 4 ++-- lib/rabl-rails/renderer.rb | 14 ++++++-------- lib/rabl-rails/renderers/base.rb | 11 ++++++++--- test/render_test.rb | 9 ++++----- test/renderers/json_renderer_test.rb | 1 + 6 files changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/rabl-rails/handler.rb b/lib/rabl-rails/handler.rb index 8cc028e..6b1d9ab 100644 --- a/lib/rabl-rails/handler.rb +++ b/lib/rabl-rails/handler.rb @@ -7,7 +7,7 @@ module RablRails def self.call(template) %{ RablRails::Library.instance. - get_rendered_template(#{template.source.inspect}, self) + get_rendered_template(#{template.source.inspect}, self, local_assigns) } end end diff --git a/lib/rabl-rails/library.rb b/lib/rabl-rails/library.rb index 0324369..e53bc4a 100644 --- a/lib/rabl-rails/library.rb +++ b/lib/rabl-rails/library.rb @@ -8,14 +8,14 @@ module RablRails @cached_templates = {} end - def get_rendered_template(source, context) + def get_rendered_template(source, context, locals = nil) path = context.instance_variable_get(:@virtual_path) @lookup_context = context.lookup_context compiled_template = compile_template_from_source(source, path) format = context.params[:format] || 'json' - Renderers.const_get(format.upcase!).new(context).render(compiled_template) + Renderers.const_get(format.upcase!).new(context, locals).render(compiled_template) end def compile_template_from_source(source, path = nil) diff --git a/lib/rabl-rails/renderer.rb b/lib/rabl-rails/renderer.rb index 168b409..b74d3d0 100644 --- a/lib/rabl-rails/renderer.rb +++ b/lib/rabl-rails/renderer.rb @@ -4,7 +4,7 @@ require 'rabl-rails/renderers/json' module RablRails module Renderer class TemplateNotFound < StandardError; end - + mattr_reader :view_path @@view_path = 'app/views' @@ -33,7 +33,6 @@ module RablRails # class Context attr_reader :format - attr_accessor :target_object def initialize(path, options) @virtual_path = path @@ -56,17 +55,17 @@ module RablRails @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 + # 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: @@ -80,12 +79,11 @@ module RablRails 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) + Library.instance.get_rendered_template(t.source, c, resource: object) end end end \ No newline at end of file diff --git a/lib/rabl-rails/renderers/base.rb b/lib/rabl-rails/renderers/base.rb index 2f09f30..c336de3 100644 --- a/lib/rabl-rails/renderers/base.rb +++ b/lib/rabl-rails/renderers/base.rb @@ -5,9 +5,10 @@ module RablRails class Base attr_accessor :_options - def initialize(context) # :nodoc: + def initialize(context, locals = nil) # :nodoc: @_context = context @_options = {} + @_resource = locals[:resource] if locals setup_render_context end @@ -19,9 +20,13 @@ module RablRails # def render(template) collection_or_resource = if template.data - template.data.to_s.start_with?('@') ? instance_variable_get(template.data) : @_context.send(template.data) + if @_context.respond_to?(template.data) + @_context.send(template.data) + else + instance_variable_get(template.data) + end end - collection_or_resource = @_context.target_object unless collection_or_resource || template.data == false || !@_context.respond_to?(:target_object) + collection_or_resource ||= @_resource 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 diff --git a/test/render_test.rb b/test/render_test.rb index 8108f7c..9b4b26d 100644 --- a/test/render_test.rb +++ b/test/render_test.rb @@ -6,7 +6,6 @@ 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 @@ -29,16 +28,16 @@ class RenderTest < ActiveSupport::TestCase 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 } + node(:username) { |_| @user.name } } end assert_equal %q({"username":"Marty"}), RablRails.render(nil, 'instance', view_path: @tmp_path, locals: { user: @user }) @@ -51,7 +50,7 @@ class RenderTest < ActiveSupport::TestCase extends 'base' } end - + File.open(@tmp_path + "base.json.rabl", "w") do |f| f.puts %q{ attribute :name, as: :extended_name diff --git a/test/renderers/json_renderer_test.rb b/test/renderers/json_renderer_test.rb index b2ab458..93d3ab0 100644 --- a/test/renderers/json_renderer_test.rb +++ b/test/renderers/json_renderer_test.rb @@ -89,6 +89,7 @@ class TestJsonRenderer < ActiveSupport::TestCase end test "node with context method call" do + @context.stub(:respond_to?).with(:@data).and_return(false) @context.stub(:respond_to?).with(:context_method).and_return(true) @context.stub(:context_method).and_return('marty') proc = lambda { |object| context_method }