From 3999737dafe2176863e15a192d596ab1a478d8d9 Mon Sep 17 00:00:00 2001 From: ccocchi Date: Wed, 5 Sep 2012 18:11:23 +0200 Subject: [PATCH] Allow conditionnal blocks within template --- lib/rabl-rails.rb | 11 ++++++----- lib/rabl-rails/compiler.rb | 24 +++++++++++++++++++----- lib/rabl-rails/condition.rb | 10 ++++++++++ lib/rabl-rails/renderers/base.rb | 5 +++++ test/compiler_test.rb | 10 ++++++++-- test/renderers/json_renderer_test.rb | 22 +++++++++++++++++----- 6 files changed, 65 insertions(+), 17 deletions(-) create mode 100644 lib/rabl-rails/condition.rb diff --git a/lib/rabl-rails.rb b/lib/rabl-rails.rb index 7426b84..18f6b04 100644 --- a/lib/rabl-rails.rb +++ b/lib/rabl-rails.rb @@ -5,6 +5,7 @@ require 'active_support/core_ext/class/attribute_accessors' require 'rabl-rails/version' require 'rabl-rails/template' +require 'rabl-rails/condition' require 'rabl-rails/compiler' require 'rabl-rails/renderer' @@ -17,10 +18,10 @@ require 'multi_json' module RablRails extend Renderer - + mattr_accessor :cache_templates @@cache_templates = true - + mattr_accessor :include_json_root @@include_json_root = true @@ -30,18 +31,18 @@ module RablRails def self.configure yield self end - + def self.json_engine=(name) MultiJson.engine = name @@json_engine = name rescue LoadError Rails.logger.warn %Q(WARNING: rabl-rails could not load "#{self.json_engine}" as JSON engine, fallback to default) end - + def self.cache_templates? ActionController::Base.perform_caching && @@cache_templates end - + def self.load_default_engines! self.json_engine = :yajl end diff --git a/lib/rabl-rails/compiler.rb b/lib/rabl-rails/compiler.rb index 7e78ea2..8ac8042 100644 --- a/lib/rabl-rails/compiler.rb +++ b/lib/rabl-rails/compiler.rb @@ -5,7 +5,7 @@ module RablRails # class Compiler def initialize - @glue_count = 0 + @i = 0 end # @@ -76,8 +76,8 @@ module RablRails # def glue(data) return unless block_given? - name = :"_glue#{@glue_count}" - @glue_count += 1 + name = :"_glue#{@i}" + @i += 1 @template[name] = sub_compile(data) { yield } end @@ -114,6 +114,20 @@ module RablRails @template.merge!(t.source) 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 # @@ -133,12 +147,12 @@ module RablRails name_or_data end end - + def sub_compile(data) return {} unless block_given? old_template, @template = @template, {} yield - @template.merge!(:_data => data) + data ? @template.merge!(:_data => data) : @template ensure @template = old_template end diff --git a/lib/rabl-rails/condition.rb b/lib/rabl-rails/condition.rb new file mode 100644 index 0000000..68cc5b3 --- /dev/null +++ b/lib/rabl-rails/condition.rb @@ -0,0 +1,10 @@ +module RablRails + class Condition + attr_reader :proc, :source + + def initialize(proc, source) + @proc = proc + @source = source + 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 cb9bcac..07c0796 100644 --- a/lib/rabl-rails/renderers/base.rb +++ b/lib/rabl-rails/renderers/base.rb @@ -65,6 +65,11 @@ module RablRails else # child object.respond_to?(:each) ? render_collection(object, current_value) : render_resource(object, current_value) end + when Condition + if instance_exec data, &(value.proc) + output.merge!(render_resource(data, value.source)) + end + next output end output[key] = out output diff --git a/test/compiler_test.rb b/test/compiler_test.rb index b9f8fcc..399e048 100644 --- a/test/compiler_test.rb +++ b/test/compiler_test.rb @@ -42,7 +42,7 @@ class CompilerTest < ActiveSupport::TestCase assert_equal :@user, t.data assert_equal :users, t.root_name end - + test "root can be set to false via options" do t = @compiler.compile_source(%( object :@user, root: false)) assert_equal false, t.root_name @@ -143,6 +143,12 @@ class CompilerTest < ActiveSupport::TestCase assert_equal 2, t.source[:foo].size 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 t = @compiler.compile_source(%{ object false @@ -154,7 +160,7 @@ class CompilerTest < ActiveSupport::TestCase assert_equal({ :user => { :_data => :@user, :id => :id } }, t.source) assert_equal false, t.data end - + 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) diff --git a/test/renderers/json_renderer_test.rb b/test/renderers/json_renderer_test.rb index c04052d..8e430c8 100644 --- a/test/renderers/json_renderer_test.rb +++ b/test/renderers/json_renderer_test.rb @@ -75,7 +75,7 @@ class TestJsonRenderer < ActiveSupport::TestCase @template.source = { :name => [condition, proc] } assert_equal %q({}), render_json_output end - + test "node with context method call" do @context.stub(:respond_to?).with(:context_method).and_return(true) @context.stub(:context_method).and_return('marty') @@ -114,17 +114,29 @@ class TestJsonRenderer < ActiveSupport::TestCase assert_equal %q({"users":[]}), render_json_output 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 @template.root_name = :author @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 - + test "render object with root options set to false" do RablRails.include_json_root = false @template.root_name = :author @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 \ No newline at end of file