diff --git a/Gemfile b/Gemfile
index c9d2029..caef18e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -4,6 +4,7 @@ gemspec
gem 'oj'
gem 'libxml-ruby'
+gem 'plist'
group :test do
gem 'rspec-mocks'
diff --git a/lib/rabl-rails.rb b/lib/rabl-rails.rb
index db3c321..3c2ed94 100644
--- a/lib/rabl-rails.rb
+++ b/lib/rabl-rails.rb
@@ -33,6 +33,12 @@ module RablRails
mattr_accessor :responder_default_template
@@responder_default_template = 'show'
+ mattr_reader :plist_engine
+ @@plist_engine = nil
+
+ mattr_accessor :include_plist_root
+ @@include_plist_root = nil
+
def self.configure
yield self
@@ -59,12 +65,18 @@ module RablRails
ActiveSupport::XmlMini.backend
end
+ def self.plist_engine=(name)
+ raise "Your plist engine does not respond to #dump" unless name.respond_to?(:dump)
+ @@plist_engine = name
+ end
+
def self.cache_templates?
ActionController::Base.perform_caching && @@cache_templates
end
def self.load_default_engines!
- self.json_engine = MultiJson.default_engine
- self.xml_engine = 'LibXML' if defined?(LibXML)
+ self.json_engine = MultiJson.default_engine
+ self.xml_engine = 'LibXML' if defined?(LibXML)
+ self.plist_engine = Plist::Emit if defined?(Plist)
end
end
diff --git a/lib/rabl-rails/renderer.rb b/lib/rabl-rails/renderer.rb
index ad53d88..1cc86c4 100644
--- a/lib/rabl-rails/renderer.rb
+++ b/lib/rabl-rails/renderer.rb
@@ -1,6 +1,7 @@
require 'rabl-rails/renderers/base'
require 'rabl-rails/renderers/json'
require 'rabl-rails/renderers/xml'
+require 'rabl-rails/renderers/plist'
module RablRails
module Renderer
diff --git a/lib/rabl-rails/renderers/plist.rb b/lib/rabl-rails/renderers/plist.rb
new file mode 100644
index 0000000..c7387be
--- /dev/null
+++ b/lib/rabl-rails/renderers/plist.rb
@@ -0,0 +1,11 @@
+module RablRails
+ module Renderers
+ class PLIST < Base
+
+ def format_output(hash)
+ hash = { _options[:root_name] => hash } if _options[:root_name] && RablRails.include_plist_root
+ RablRails.plist_engine.dump(hash)
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/test/renderers/json_renderer_test.rb b/test/renderers/json_renderer_test.rb
index ec0cd80..dd7517a 100644
--- a/test/renderers/json_renderer_test.rb
+++ b/test/renderers/json_renderer_test.rb
@@ -140,6 +140,7 @@ class TestJsonRenderer < ActiveSupport::TestCase
end
test "render object with root node" do
+ RablRails.include_json_root = true
@template.root_name = :author
@template.source = { :id => :id, :name => :name }
assert_equal %q({"author":{"id":1,"name":"foobar"}}), render_json_output
diff --git a/test/renderers/plist_renderer_test.rb b/test/renderers/plist_renderer_test.rb
new file mode 100644
index 0000000..5b17165
--- /dev/null
+++ b/test/renderers/plist_renderer_test.rb
@@ -0,0 +1,138 @@
+require 'test_helper'
+require 'plist'
+
+RablRails.plist_engine = Plist::Emit
+
+class TestPlistRenderer < ActiveSupport::TestCase
+ INDENT_REGEXP = /\n(\s)*/
+ HEADER_REGEXP = /<\?[^>]+>]+>/
+
+ setup do
+ @data = User.new(1, 'foobar', 'male')
+
+ @context = Context.new
+ @context.assigns['data'] = @data
+
+ @template = RablRails::CompiledTemplate.new
+ @template.data = :@data
+ @template.root_name = :user
+ end
+
+ def render_plist_output
+ output = RablRails::Renderers::PLIST.new(@context).render(@template).to_s.gsub!(INDENT_REGEXP, '')
+ output.sub!(HEADER_REGEXP, '').gsub!(%r(?plist[^>]*>), '').sub!(%r(), '').sub(%r(), '')
+ end
+
+ test "plist engine should responsd to #dump" do
+ assert_raises(RuntimeError) { RablRails.plist_engine = Object.new }
+ end
+
+ test "render object wth empty template" do
+ @template.source = {}
+ assert_equal %q(), render_plist_output
+ end
+
+ test "render collection with empty template" do
+ @context.assigns['data'] = [@data]
+ @template.source = {}
+ assert_equal %q(), render_plist_output
+ end
+
+ test "render object with local methods (used by decent_exposure)" do
+ @context.stub(:user).and_return(@data)
+ @template.data = :user
+ @template.source = { :id => :id }
+ assert_equal %q(id1), render_plist_output
+ end
+
+ test "render single object attributes" do
+ @template.source = { :id => :id, :name => :name }
+ assert_equal %q(id1namefoobar), render_plist_output
+ end
+
+ test "render child with object association" do
+ @data.stub(:address).and_return(mock(:city => 'Paris'))
+ @template.source = { :address => { :_data => :address, :city => :city } }
+ assert_equal %q(addresscityParis), render_plist_output
+ end
+
+ test "render child with arbitrary data source" do
+ @template.source = { :author => { :_data => :@data, :name => :name } }
+ assert_equal %q(authornamefoobar), render_plist_output
+ end
+
+ test "render child with local methods (used by decent_exposure)" do
+ @context.stub(:user).and_return(@data)
+ @template.source = { :author => { :_data => :user, :name => :name } }
+ assert_equal %q(authornamefoobar), render_plist_output
+ end
+
+ test "render node property" do
+ proc = lambda { |object| object.name }
+ @template.source = { :name => proc }
+ assert_equal %q(namefoobar), render_plist_output
+ end
+
+ test "render node property with true condition" do
+ condition = lambda { |u| true }
+ proc = lambda { |object| object.name }
+ @template.source = { :name => [condition, proc] }
+ assert_equal %q(namefoobar), render_plist_output
+ end
+
+ test "render node property with false condition" do
+ condition = lambda { |u| false }
+ proc = lambda { |object| object.name }
+ @template.source = { :name => [condition, proc] }
+ assert_equal %q(), render_plist_output
+ 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 }
+ @template.source = { :name => proc }
+ assert_equal %q(namemarty), render_plist_output
+ end
+
+ test "partial with no values should raise an error" do
+ @template.data = false
+ @template.source = { :user => ->(s) { partial('users/base') } }
+
+ assert_raises(RablRails::Renderers::PartialError) { render_plist_output }
+ end
+
+ test "partial with empty values should not raise an error" do
+ @template.data = false
+ @template.source = { :users => ->(s) { partial('users/base', :object => []) } }
+
+ assert_equal %q(users), render_plist_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(namefoobar), render_plist_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_plist_output
+ end
+
+ test "render object with root node" do
+ RablRails.include_plist_root = true
+ @template.root_name = :author
+ @template.source = { :id => :id, :name => :name }
+ assert_equal %q(authorid1namefoobar), render_plist_output
+ end
+
+ test "render object with root options set to false" do
+ RablRails.include_plist_root = false
+ @template.root_name = :author
+ @template.source = { :id => :id, :name => :name }
+ assert_equal %q(id1namefoobar), render_plist_output
+ end
+end
\ No newline at end of file