From d4c434e6b0c0345046d7b00a0d4a5f17892d0757 Mon Sep 17 00:00:00 2001 From: ccocchi Date: Thu, 26 Jul 2012 02:21:33 +0200 Subject: [PATCH] Refactor RablRails#render to use standard library methods. Emulate a render and lookup context like Rails. --- lib/rabl-rails/renderer.rb | 62 +++++++++++++++++++++----------- lib/rabl-rails/renderers/base.rb | 1 + test/render_test.rb | 52 +++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 test/render_test.rb diff --git a/lib/rabl-rails/renderer.rb b/lib/rabl-rails/renderer.rb index 5f2c081..6fb6efe 100644 --- a/lib/rabl-rails/renderer.rb +++ b/lib/rabl-rails/renderer.rb @@ -5,19 +5,54 @@ module RablRails module Renderer 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 rendering view # 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 = {} + @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 # @@ -30,29 +65,14 @@ module RablRails # an option: { format: 'xml' } # def render(object, template, options = {}) - format = options.delete(:format) || 'json' object = options[:locals].delete(:object) if !object && options[:locals] - source = find_template(template, format, options.delete(:view_path)) - compiled_template = Compiler.new.compile_source(source) + c = Context.new(template, options) + c.target_object = object - c = Context.new - c.assigns[compiled_template.data.to_s[1..-1]] = object if compiled_template.data + t = c.lookup_context.find_template(template, [], false) - Renderers.const_get(format.upcase!).new(c).render(compiled_template) - 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 + Library.instance.get_rendered_template(t.source, c) 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 e053a19..b8b3316 100644 --- a/lib/rabl-rails/renderers/base.rb +++ b/lib/rabl-rails/renderers/base.rb @@ -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 diff --git a/test/render_test.rb b/test/render_test.rb new file mode 100644 index 0000000..f0b543e --- /dev/null +++ b/test/render_test.rb @@ -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 \ No newline at end of file