Allow conditionnal blocks within template

This commit is contained in:
ccocchi 2012-09-05 18:11:23 +02:00
parent cf39a3f748
commit 3999737daf
6 changed files with 65 additions and 17 deletions

View File

@ -5,6 +5,7 @@ require 'active_support/core_ext/class/attribute_accessors'
require 'rabl-rails/version' require 'rabl-rails/version'
require 'rabl-rails/template' require 'rabl-rails/template'
require 'rabl-rails/condition'
require 'rabl-rails/compiler' require 'rabl-rails/compiler'
require 'rabl-rails/renderer' require 'rabl-rails/renderer'
@ -17,10 +18,10 @@ require 'multi_json'
module RablRails module RablRails
extend Renderer extend Renderer
mattr_accessor :cache_templates mattr_accessor :cache_templates
@@cache_templates = true @@cache_templates = true
mattr_accessor :include_json_root mattr_accessor :include_json_root
@@include_json_root = true @@include_json_root = true
@ -30,18 +31,18 @@ module RablRails
def self.configure def self.configure
yield self yield self
end end
def self.json_engine=(name) def self.json_engine=(name)
MultiJson.engine = name MultiJson.engine = name
@@json_engine = name @@json_engine = name
rescue LoadError rescue LoadError
Rails.logger.warn %Q(WARNING: rabl-rails could not load "#{self.json_engine}" as JSON engine, fallback to default) Rails.logger.warn %Q(WARNING: rabl-rails could not load "#{self.json_engine}" as JSON engine, fallback to default)
end end
def self.cache_templates? def self.cache_templates?
ActionController::Base.perform_caching && @@cache_templates ActionController::Base.perform_caching && @@cache_templates
end end
def self.load_default_engines! def self.load_default_engines!
self.json_engine = :yajl self.json_engine = :yajl
end end

View File

@ -5,7 +5,7 @@ module RablRails
# #
class Compiler class Compiler
def initialize def initialize
@glue_count = 0 @i = 0
end end
# #
@ -76,8 +76,8 @@ module RablRails
# #
def glue(data) def glue(data)
return unless block_given? return unless block_given?
name = :"_glue#{@glue_count}" name = :"_glue#{@i}"
@glue_count += 1 @i += 1
@template[name] = sub_compile(data) { yield } @template[name] = sub_compile(data) { yield }
end end
@ -114,6 +114,20 @@ module RablRails
@template.merge!(t.source) @template.merge!(t.source)
end end
#
# Provide a conditionnal block
#
# condition(->(u) { u.is_a?(Admin) }) do
# attributes :secret
# end
#
def condition(proc)
return unless block_given?
name = :"_if#{@i}"
@i += 1
@template[name] = Condition.new(proc, sub_compile(nil) { yield })
end
protected protected
# #
@ -133,12 +147,12 @@ module RablRails
name_or_data name_or_data
end end
end end
def sub_compile(data) def sub_compile(data)
return {} unless block_given? return {} unless block_given?
old_template, @template = @template, {} old_template, @template = @template, {}
yield yield
@template.merge!(:_data => data) data ? @template.merge!(:_data => data) : @template
ensure ensure
@template = old_template @template = old_template
end end

View File

@ -0,0 +1,10 @@
module RablRails
class Condition
attr_reader :proc, :source
def initialize(proc, source)
@proc = proc
@source = source
end
end
end

View File

@ -65,6 +65,11 @@ module RablRails
else # child else # child
object.respond_to?(:each) ? render_collection(object, current_value) : render_resource(object, current_value) object.respond_to?(:each) ? render_collection(object, current_value) : render_resource(object, current_value)
end end
when Condition
if instance_exec data, &(value.proc)
output.merge!(render_resource(data, value.source))
end
next output
end end
output[key] = out output[key] = out
output output

View File

@ -42,7 +42,7 @@ class CompilerTest < ActiveSupport::TestCase
assert_equal :@user, t.data assert_equal :@user, t.data
assert_equal :users, t.root_name assert_equal :users, t.root_name
end end
test "root can be set to false via options" do test "root can be set to false via options" do
t = @compiler.compile_source(%( object :@user, root: false)) t = @compiler.compile_source(%( object :@user, root: false))
assert_equal false, t.root_name assert_equal false, t.root_name
@ -143,6 +143,12 @@ class CompilerTest < ActiveSupport::TestCase
assert_equal 2, t.source[:foo].size assert_equal 2, t.source[:foo].size
end end
test "conditionnal block compile nicely" do
t = @compiler.compile_source(%{ condition(->(u) {}) do attributes :secret end })
assert_instance_of RablRails::Condition, t.source[:_if0]
assert_equal({ :secret => :secret }, t.source[:_if0].source)
end
test "compile with no object" do test "compile with no object" do
t = @compiler.compile_source(%{ t = @compiler.compile_source(%{
object false object false
@ -154,7 +160,7 @@ class CompilerTest < ActiveSupport::TestCase
assert_equal({ :user => { :_data => :@user, :id => :id } }, t.source) assert_equal({ :user => { :_data => :@user, :id => :id } }, t.source)
assert_equal false, t.data assert_equal false, t.data
end end
test "name extraction from argument" do test "name extraction from argument" do
assert_equal [:@users, 'users'], @compiler.send(:extract_data_and_name, :@users) assert_equal [:@users, 'users'], @compiler.send(:extract_data_and_name, :@users)
assert_equal [:users, :users], @compiler.send(:extract_data_and_name, :users) assert_equal [:users, :users], @compiler.send(:extract_data_and_name, :users)

View File

@ -75,7 +75,7 @@ class TestJsonRenderer < ActiveSupport::TestCase
@template.source = { :name => [condition, proc] } @template.source = { :name => [condition, proc] }
assert_equal %q({}), render_json_output assert_equal %q({}), render_json_output
end end
test "node with context method call" do test "node with context method call" do
@context.stub(:respond_to?).with(:context_method).and_return(true) @context.stub(:respond_to?).with(:context_method).and_return(true)
@context.stub(:context_method).and_return('marty') @context.stub(:context_method).and_return('marty')
@ -114,17 +114,29 @@ class TestJsonRenderer < ActiveSupport::TestCase
assert_equal %q({"users":[]}), render_json_output assert_equal %q({"users":[]}), render_json_output
end end
test "condition blocks are transparent if the condition passed" do
c = RablRails::Condition.new(->(u) { true }, { :name => :name })
@template.source = { :_if0 => c }
assert_equal %q({"name":"foobar"}), render_json_output
end
test "condition blocks are ignored if the condition is not met" do
c = RablRails::Condition.new(->(u) { false }, { :name => :name })
@template.source = { :_if0 => c }
assert_equal %q({}), render_json_output
end
test "render object with root node" do test "render object with root node" do
@template.root_name = :author @template.root_name = :author
@template.source = { :id => :id, :name => :name } @template.source = { :id => :id, :name => :name }
assert_equal %q({"author":{"id":1,"name":"foobar"}}), render_json_output assert_equal %q({"author":{"id":1,"name":"foobar"}}), render_json_output
end end
test "render object with root options set to false" do test "render object with root options set to false" do
RablRails.include_json_root = false RablRails.include_json_root = false
@template.root_name = :author @template.root_name = :author
@template.source = { :id => :id, :name => :name } @template.source = { :id => :id, :name => :name }
assert_equal %q({"id":1,"name":"foobar"}), render_json_output assert_equal %q({"id":1,"name":"foobar"}), render_json_output
end end
end end