Merge pull request #1 from ccocchi/extract-render-from-tempate
Extract render from tempate
This commit is contained in:
commit
7767a708df
@ -5,23 +5,27 @@ require 'active_support/json'
|
|||||||
require 'active_support/core_ext/class/attribute_accessors'
|
require 'active_support/core_ext/class/attribute_accessors'
|
||||||
|
|
||||||
require 'rabl-fast-json/version'
|
require 'rabl-fast-json/version'
|
||||||
require 'rabl-fast-json/helpers'
|
|
||||||
require 'rabl-fast-json/template'
|
require 'rabl-fast-json/template'
|
||||||
require 'rabl-fast-json/compiler'
|
require 'rabl-fast-json/compiler'
|
||||||
|
|
||||||
|
require 'rabl-fast-json/renderer'
|
||||||
|
|
||||||
require 'rabl-fast-json/library'
|
require 'rabl-fast-json/library'
|
||||||
require 'rabl-fast-json/handler'
|
require 'rabl-fast-json/handler'
|
||||||
require 'rabl-fast-json/railtie'
|
require 'rabl-fast-json/railtie'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module RablFastJson
|
module RablFastJson
|
||||||
extend self
|
extend self
|
||||||
|
|
||||||
mattr_accessor :cache_templates
|
mattr_accessor :cache_templates
|
||||||
@@cache_templates = true
|
@@cache_templates = true
|
||||||
|
|
||||||
def configure
|
def configure
|
||||||
yield self
|
yield self
|
||||||
end
|
end
|
||||||
|
|
||||||
def cache_templates?
|
def cache_templates?
|
||||||
ActionController::Base.perform_caching && @@cache_templates
|
ActionController::Base.perform_caching && @@cache_templates
|
||||||
end
|
end
|
||||||
|
@ -4,8 +4,6 @@ module RablFastJson
|
|||||||
# representing data structure
|
# representing data structure
|
||||||
#
|
#
|
||||||
class Compiler
|
class Compiler
|
||||||
include Helpers
|
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@glue_count = 0
|
@glue_count = 0
|
||||||
end
|
end
|
||||||
@ -49,7 +47,7 @@ module RablFastJson
|
|||||||
#
|
#
|
||||||
def collection(data, options = {})
|
def collection(data, options = {})
|
||||||
object(data)
|
object(data)
|
||||||
@template.root_name = options[:root] if root_given?(options)
|
@template.root_name = options[:root] if options[:root]
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -82,8 +80,8 @@ module RablFastJson
|
|||||||
#
|
#
|
||||||
def child(name_or_data, options = {}, &block)
|
def child(name_or_data, options = {}, &block)
|
||||||
data, name = extract_data_and_name(name_or_data)
|
data, name = extract_data_and_name(name_or_data)
|
||||||
name = options[:root] if root_given?(options)
|
name = options[:root] if options[:root]
|
||||||
if partial_given?(options)
|
if options[:partial]
|
||||||
template = Library.instance.get(options[:partial])
|
template = Library.instance.get(options[:partial])
|
||||||
@template[name] = template.merge!(:_data => data)
|
@template[name] = template.merge!(:_data => data)
|
||||||
else
|
else
|
||||||
|
@ -4,7 +4,7 @@ module RablFastJson
|
|||||||
cattr_accessor :default_format
|
cattr_accessor :default_format
|
||||||
self.default_format = 'application/json'
|
self.default_format = 'application/json'
|
||||||
|
|
||||||
def self.call(template)
|
def self.call(template)
|
||||||
%{
|
%{
|
||||||
RablFastJson::Library.instance.
|
RablFastJson::Library.instance.
|
||||||
get_rendered_template(#{template.source.inspect}, self)
|
get_rendered_template(#{template.source.inspect}, self)
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
module RablFastJson
|
|
||||||
module Helpers
|
|
||||||
def root_given?(options) #:nodoc:
|
|
||||||
options[:root].present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def partial_given?(options) #:nodoc:
|
|
||||||
options[:partial].present?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -4,20 +4,18 @@ module RablFastJson
|
|||||||
class Library
|
class Library
|
||||||
include Singleton
|
include Singleton
|
||||||
|
|
||||||
attr_accessor :view_renderer
|
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@cached_templates = {}
|
@cached_templates = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_rendered_template(source, context)
|
def get_rendered_template(source, context)
|
||||||
path = context.instance_variable_get(:@virtual_path)
|
path = context.instance_variable_get(:@virtual_path)
|
||||||
@view_renderer = context.instance_variable_get(:@view_renderer)
|
@lookup_context = context.lookup_context
|
||||||
|
|
||||||
compiled_template = get_compiled_template(path, source)
|
compiled_template = get_compiled_template(path, source)
|
||||||
compiled_template.context = context
|
|
||||||
body = compiled_template.render
|
format = context.params[:format] || 'json'
|
||||||
ActiveSupport::JSON.encode(compiled_template.root_name ? { compiled_template.root_name => body } : body)
|
Renderers.const_get(format.upcase!).new(context).render(compiled_template)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_compiled_template(path, source)
|
def get_compiled_template(path, source)
|
||||||
@ -31,8 +29,8 @@ module RablFastJson
|
|||||||
|
|
||||||
def get(path)
|
def get(path)
|
||||||
template = @cached_templates[path]
|
template = @cached_templates[path]
|
||||||
return template unless template.nil?
|
return template if template
|
||||||
t = @view_renderer.lookup_context.find_template(path, [], false)
|
t = @lookup_context.find_template(path, [], false)
|
||||||
get_compiled_template(path, t.source)
|
get_compiled_template(path, t.source)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
2
lib/rabl-fast-json/renderer.rb
Normal file
2
lib/rabl-fast-json/renderer.rb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
require 'rabl-fast-json/renderers/base'
|
||||||
|
require 'rabl-fast-json/renderers/json'
|
114
lib/rabl-fast-json/renderers/base.rb
Normal file
114
lib/rabl-fast-json/renderers/base.rb
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
module RablFastJson
|
||||||
|
module Renderers
|
||||||
|
class PartialError < StandardError; end
|
||||||
|
|
||||||
|
class Base
|
||||||
|
|
||||||
|
def initialize(context) # :nodoc:
|
||||||
|
@_context = context
|
||||||
|
setup_render_context
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Render a template.
|
||||||
|
# Uses the compiled template source to get a hash with the actual
|
||||||
|
# data and then format the result according to the `format_result`
|
||||||
|
# method defined by the renderer.
|
||||||
|
#
|
||||||
|
def render(template)
|
||||||
|
collection_or_resource = @_context.instance_variable_get(template.data) if template.data
|
||||||
|
output_hash = collection_or_resource.respond_to?(:each) ? render_collection(collection_or_resource, template.source) :
|
||||||
|
render_resource(collection_or_resource, template.source)
|
||||||
|
output_hash = { template.root_name => output_hash } if template.root_name
|
||||||
|
format_output(output_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Format a hash into the desired output.
|
||||||
|
# Renderer subclasses must implement this method
|
||||||
|
#
|
||||||
|
def format_output(hash)
|
||||||
|
raise "Muse be implemented by renderer"
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
#
|
||||||
|
# Render a single resource as a hash, according to the compiled
|
||||||
|
# template source passed.
|
||||||
|
#
|
||||||
|
def render_resource(data, source)
|
||||||
|
source.inject({}) { |output, current|
|
||||||
|
key, value = current
|
||||||
|
|
||||||
|
out = case value
|
||||||
|
when Symbol
|
||||||
|
data.send(value) # attributes
|
||||||
|
when Proc
|
||||||
|
instance_exec data, &value # node
|
||||||
|
when Array # node with condition
|
||||||
|
next output if !instance_exec data, &(value.first)
|
||||||
|
instance_exec data, &(value.last)
|
||||||
|
when Hash
|
||||||
|
current_value = value.dup
|
||||||
|
data_symbol = current_value.delete(:_data)
|
||||||
|
object = data_symbol.nil? ? data : data_symbol.to_s.start_with?('@') ? @_context.instance_variable_get(data_symbol) : data.send(data_symbol)
|
||||||
|
|
||||||
|
if key.to_s.start_with?('_') # glue
|
||||||
|
current_value.each_pair { |k, v|
|
||||||
|
output[k] = object.send(v)
|
||||||
|
}
|
||||||
|
next output
|
||||||
|
else # child
|
||||||
|
object.respond_to?(:each) ? render_collection(object, current_value) : render_resource(object, current_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
output[key] = out
|
||||||
|
output
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Call the render_resource mtehod on each object of the collection
|
||||||
|
# and return an array of the returned values.
|
||||||
|
#
|
||||||
|
def render_collection(collection, source)
|
||||||
|
collection.map { |o| render_resource(o, source) }
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Allow to use partial inside of node blocks (they are evaluated at)
|
||||||
|
# rendering time.
|
||||||
|
#
|
||||||
|
def partial(template_path, options = {})
|
||||||
|
raise PartialError.new("No object was given to partial") unless options[:object]
|
||||||
|
object = options[:object]
|
||||||
|
|
||||||
|
return [] if object.respond_to?(:empty?) && object.empty?
|
||||||
|
|
||||||
|
template = Library.instance.get(template_path)
|
||||||
|
object.respond_to?(:each) ? render_collection(object, template.source) : render_resource(object, template.source)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# If a method is called inside a 'node' property or a 'if' lambda
|
||||||
|
# it will be passed to context if it exists or treated as a standard
|
||||||
|
# missing method.
|
||||||
|
#
|
||||||
|
def method_missing(name, *args, &block)
|
||||||
|
@context.respond_to?(name) ? @context.send(name, *args, &block) : super
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copy assigns from controller's context into this
|
||||||
|
# renderer context to include instances variables when
|
||||||
|
# evaluating 'node' properties.
|
||||||
|
#
|
||||||
|
def setup_render_context
|
||||||
|
@_context.instance_variable_get(:@_assigns).each_pair { |k, v|
|
||||||
|
instance_variable_set("@#{k}", v) unless k.start_with?('_') || k == @data
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
9
lib/rabl-fast-json/renderers/json.rb
Normal file
9
lib/rabl-fast-json/renderers/json.rb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module RablFastJson
|
||||||
|
module Renderers
|
||||||
|
class JSON < Base
|
||||||
|
def format_output(hash)
|
||||||
|
ActiveSupport::JSON.encode(hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,86 +1,11 @@
|
|||||||
module RablFastJson
|
module RablFastJson
|
||||||
class CompiledTemplate
|
class CompiledTemplate
|
||||||
attr_accessor :source, :data, :root_name, :context
|
attr_accessor :source, :data, :root_name
|
||||||
|
|
||||||
delegate :[], :[]=, :merge!, :to => :source
|
delegate :[], :[]=, :merge!, :to => :source
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@source = {}
|
@source = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_root_name?
|
|
||||||
!@root_name.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def render
|
|
||||||
get_object_from_context
|
|
||||||
get_assigns_from_context
|
|
||||||
@object.respond_to?(:each) ? render_collection : render_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_resource(data = nil, source = nil)
|
|
||||||
data ||= @object
|
|
||||||
source ||= @source
|
|
||||||
|
|
||||||
source.inject({}) { |output, current|
|
|
||||||
key, value = current
|
|
||||||
|
|
||||||
out = case value
|
|
||||||
when Symbol
|
|
||||||
data.send(value) # attributes
|
|
||||||
when Proc
|
|
||||||
instance_exec data, &value # node
|
|
||||||
when Array # node with condition
|
|
||||||
next output if !instance_exec data, &(value.first) #value.first.call(data)
|
|
||||||
instance_exec data, &(value.last)
|
|
||||||
when Hash
|
|
||||||
current_value = value.dup
|
|
||||||
data_symbol = current_value.delete(:_data)
|
|
||||||
object = data_symbol.nil? ? data : data_symbol.to_s.start_with?('@') ? @context.instance_variable_get(data_symbol) : data.send(data_symbol)
|
|
||||||
|
|
||||||
if key.to_s.start_with?('_') # glue
|
|
||||||
current_value.each_pair { |k, v|
|
|
||||||
output[k] = object.send(v)
|
|
||||||
}
|
|
||||||
next output
|
|
||||||
else # child
|
|
||||||
object.respond_to?(:each) ? render_collection(object, current_value) : render_resource(object, current_value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
output[key] = out
|
|
||||||
output
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_collection(collection = nil, source = nil)
|
|
||||||
collection ||= @object
|
|
||||||
collection.inject([]) { |output, o| output << render_resource(o, source) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def method_missing(name, *args, &block)
|
|
||||||
@context.respond_to?(name) ? @context.send(name, *args, &block) : super
|
|
||||||
end
|
|
||||||
|
|
||||||
def partial(template_path, options = {})
|
|
||||||
raise "No object was given to partial" if options[:object].nil?
|
|
||||||
object = options[:object]
|
|
||||||
|
|
||||||
return [] if object.respond_to?(:empty?) && object.empty?
|
|
||||||
|
|
||||||
template = Library.instance.get(template_path)
|
|
||||||
object.respond_to?(:each) ? template.render_collection(object) : template.render_resource(object)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def get_object_from_context
|
|
||||||
@object = @context.instance_variable_get(@data) if @data
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_assigns_from_context
|
|
||||||
@context.instance_variable_get(:@_assigns).each_pair { |k, v|
|
|
||||||
instance_variable_set("@#{k}", v) unless k.start_with?('_') || k == @data
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -4,31 +4,31 @@ class CacheTemplatesTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
setup do
|
setup do
|
||||||
RablFastJson::Library.reset_instance
|
RablFastJson::Library.reset_instance
|
||||||
@library = RablFastJson::Library.instance
|
@library = RablFastJson::Library.instance
|
||||||
end
|
|
||||||
|
|
||||||
test "cache templates if perform_caching is active and cache_templates is enabled" do
|
|
||||||
RablFastJson.cache_templates = true
|
RablFastJson.cache_templates = true
|
||||||
ActionController::Base.stub(:perform_caching).and_return(true)
|
end
|
||||||
|
|
||||||
|
test "cache templates if perform_caching is active and cache_templates is enabled" do
|
||||||
|
ActionController::Base.stub(:perform_caching).and_return(true)
|
||||||
@library.get_compiled_template('some/path', "")
|
@library.get_compiled_template('some/path', "")
|
||||||
t = @library.get_compiled_template('some/path', "attribute :id")
|
t = @library.get_compiled_template('some/path', "attribute :id")
|
||||||
|
|
||||||
assert_equal({}, t.source)
|
assert_equal({}, t.source)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "cached templates should not be modifiable in place" do
|
test "cached templates should not be modifiable in place" do
|
||||||
RablFastJson.cache_templates = true
|
|
||||||
ActionController::Base.stub(:perform_caching).and_return(true)
|
ActionController::Base.stub(:perform_caching).and_return(true)
|
||||||
t = @library.get_compiled_template('some/path', "")
|
@library.get_compiled_template('some/path', "")
|
||||||
assert_nil t.context
|
t = @library.get_compiled_template('some/path', "attribute :id")
|
||||||
t.context = "foobar"
|
|
||||||
assert_nil @library.get_compiled_template('some/path', "").context
|
assert_equal({}, t.source)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "don't cache templates cache_templates is enabled but perform_caching is not active" do
|
test "don't cache templates cache_templates is enabled but perform_caching is not active" do
|
||||||
RablFastJson.cache_templates = true
|
ActionController::Base.stub(:perform_caching).and_return(false)
|
||||||
ActionController::Base.stub(:perform_caching).and_return(false)
|
@library.get_compiled_template('some/path', "")
|
||||||
|
t = @library.get_compiled_template('some/path', "attribute :id")
|
||||||
refute_equal @library.get_compiled_template('some/path', ""), @library.get_compiled_template('some/path', "")
|
|
||||||
|
assert_equal({ :id => :id }, t.source)
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -11,6 +11,40 @@ class CompilerTest < ActiveSupport::TestCase
|
|||||||
assert_instance_of RablFastJson::CompiledTemplate, @compiler.compile_source("")
|
assert_instance_of RablFastJson::CompiledTemplate, @compiler.compile_source("")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "object set data for the template" do
|
||||||
|
t = @compiler.compile_source(%{ object :@user })
|
||||||
|
assert_equal :@user, t.data
|
||||||
|
assert_equal({}, t.source)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "object property can define root name" do
|
||||||
|
t = @compiler.compile_source(%{ object :@user => :author })
|
||||||
|
assert_equal :@user, t.data
|
||||||
|
assert_equal :author, t.root_name
|
||||||
|
assert_equal({}, t.source)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "collection set the data for the template" do
|
||||||
|
t = @compiler.compile_source(%{ collection :@user })
|
||||||
|
assert_equal :@user, t.data
|
||||||
|
assert_equal({}, t.source)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "collection property can define root name" do
|
||||||
|
t = @compiler.compile_source(%{ collection :@user => :users })
|
||||||
|
assert_equal :@user, t.data
|
||||||
|
assert_equal :users, t.root_name
|
||||||
|
assert_equal({}, t.source)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "collection property can define root name via options" do
|
||||||
|
t = @compiler.compile_source(%{ collection :@user, :root => :users })
|
||||||
|
assert_equal :@user, t.data
|
||||||
|
assert_equal :users, t.root_name
|
||||||
|
end
|
||||||
|
|
||||||
|
# Compilation
|
||||||
|
|
||||||
test "simple attributes are compiled to hash" do
|
test "simple attributes are compiled to hash" do
|
||||||
t = @compiler.compile_source(%{ attributes :id, :name })
|
t = @compiler.compile_source(%{ attributes :id, :name })
|
||||||
assert_equal({ :id => :id, :name => :name}, t.source)
|
assert_equal({ :id => :id, :name => :name}, t.source)
|
||||||
@ -57,11 +91,10 @@ class CompilerTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "child with succint partial notation" do
|
test "child with succint partial notation" do
|
||||||
@view_renderer = mock()
|
mock_template = RablFastJson::CompiledTemplate.new
|
||||||
@view_renderer.stub_chain(:lookup_context, :find_template).with('users/base', [], false).and_return(
|
mock_template.source = { :id => :id }
|
||||||
mock(:source => %{ attribute :id }))
|
|
||||||
RablFastJson::Library.reset_instance
|
RablFastJson::Library.reset_instance
|
||||||
RablFastJson::Library.instance.view_renderer = @view_renderer
|
RablFastJson::Library.instance.stub(:get).with('users/base').and_return(mock_template)
|
||||||
|
|
||||||
t = @compiler.compile_source(%{child(:user, :partial => 'users/base') })
|
t = @compiler.compile_source(%{child(:user, :partial => 'users/base') })
|
||||||
assert_equal( {:user => { :_data => :user, :id => :id } }, t.source)
|
assert_equal( {:user => { :_data => :user, :id => :id } }, t.source)
|
||||||
@ -84,38 +117,6 @@ class CompilerTest < ActiveSupport::TestCase
|
|||||||
}, t.source)
|
}, t.source)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "object set data for the template" do
|
|
||||||
t = @compiler.compile_source(%{ object :@user })
|
|
||||||
assert_equal :@user, t.data
|
|
||||||
assert_equal({}, t.source)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "object property can define root name" do
|
|
||||||
t = @compiler.compile_source(%{ object :@user => :author })
|
|
||||||
assert_equal :@user, t.data
|
|
||||||
assert_equal :author, t.root_name
|
|
||||||
assert_equal({}, t.source)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "collection set the data for the template" do
|
|
||||||
t = @compiler.compile_source(%{ collection :@user })
|
|
||||||
assert_equal :@user, t.data
|
|
||||||
assert_equal({}, t.source)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "collection property can define root name" do
|
|
||||||
t = @compiler.compile_source(%{ collection :@user => :users })
|
|
||||||
assert_equal :@user, t.data
|
|
||||||
assert_equal :users, t.root_name
|
|
||||||
assert_equal({}, t.source)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "collection property can define root name via options" do
|
|
||||||
t = @compiler.compile_source(%{ collection :@user, :root => :users })
|
|
||||||
assert_equal :@user, t.data
|
|
||||||
assert_equal :users, t.root_name
|
|
||||||
end
|
|
||||||
|
|
||||||
test "extends use other template source as itself" do
|
test "extends use other template source as itself" do
|
||||||
template = mock('template', :source => { :id => :id })
|
template = mock('template', :source => { :id => :id })
|
||||||
RablFastJson::Library.reset_instance
|
RablFastJson::Library.reset_instance
|
||||||
|
@ -21,15 +21,11 @@ class DeepNestingTest < ActiveSupport::TestCase
|
|||||||
@user.stub(:posts).and_return([@post])
|
@user.stub(:posts).and_return([@post])
|
||||||
@user.stub(:respond_to?).with(:each).and_return(false)
|
@user.stub(:respond_to?).with(:each).and_return(false)
|
||||||
|
|
||||||
@view_renderer = mock()
|
|
||||||
@view_renderer.stub_chain(:lookup_context, :find_template).with('comments/show', [], false).and_return(
|
|
||||||
mock(:source => %{ object :@comment\n attribute :content }))
|
|
||||||
|
|
||||||
@context = Context.new
|
@context = Context.new
|
||||||
@context.stub(:instance_variable_get).with(:@user).and_return(@user)
|
@context.stub(:instance_variable_get).with(:@user).and_return(@user)
|
||||||
@context.stub(:instance_variable_get).with(:@view_renderer).and_return(@view_renderer)
|
|
||||||
@context.stub(:instance_variable_get).with(:@virtual_path).and_return('users/show')
|
@context.stub(:instance_variable_get).with(:@virtual_path).and_return('users/show')
|
||||||
@context.stub(:instance_variable_get).with(:@_assigns).and_return({})
|
@context.stub(:instance_variable_get).with(:@_assigns).and_return({})
|
||||||
|
@context.stub(:lookup_context).and_return(mock(:find_template => mock(:source => %{ object :@comment\n attribute :content })))
|
||||||
end
|
end
|
||||||
|
|
||||||
test "compile and render deep nesting template" do
|
test "compile and render deep nesting template" do
|
||||||
|
@ -3,18 +3,18 @@ require 'test_helper'
|
|||||||
class NonRestfulResponseTest < ActiveSupport::TestCase
|
class NonRestfulResponseTest < ActiveSupport::TestCase
|
||||||
setup do
|
setup do
|
||||||
RablFastJson::Library.reset_instance
|
RablFastJson::Library.reset_instance
|
||||||
|
|
||||||
@user = User.new(1, 'foo', 'male')
|
@user = User.new(1, 'foo', 'male')
|
||||||
@user.stub_chain(:posts, :count).and_return(10)
|
@user.stub_chain(:posts, :count).and_return(10)
|
||||||
@user.stub(:respond_to?).with(:each).and_return(false)
|
@user.stub(:respond_to?).with(:each).and_return(false)
|
||||||
|
|
||||||
@context = Context.new
|
@context = Context.new
|
||||||
@context.stub(:instance_variable_get).with(:@user).and_return(@user)
|
@context.stub(:instance_variable_get).with(:@user).and_return(@user)
|
||||||
@context.stub(:instance_variable_get).with(:@view_renderer).and_return(mock())
|
|
||||||
@context.stub(:instance_variable_get).with(:@virtual_path).and_return('user/show')
|
@context.stub(:instance_variable_get).with(:@virtual_path).and_return('user/show')
|
||||||
@context.stub(:instance_variable_get).with(:@_assigns).and_return({'user' => @user})
|
@context.stub(:instance_variable_get).with(:@_assigns).and_return({'user' => @user})
|
||||||
|
@context.stub(:lookup_context)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "compile and render non restful resource" do
|
test "compile and render non restful resource" do
|
||||||
source = %{
|
source = %{
|
||||||
object false
|
object false
|
||||||
@ -23,13 +23,13 @@ class NonRestfulResponseTest < ActiveSupport::TestCase
|
|||||||
attributes :id, :name
|
attributes :id, :name
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_equal(ActiveSupport::JSON.encode({
|
assert_equal(ActiveSupport::JSON.encode({
|
||||||
:post_count => 10,
|
:post_count => 10,
|
||||||
:user => {
|
:user => {
|
||||||
:id => 1,
|
:id => 1,
|
||||||
:name => 'foo'
|
:name => 'foo'
|
||||||
}
|
}
|
||||||
}), RablFastJson::Library.instance.get_rendered_template(source, @context))
|
}), RablFastJson::Library.instance.get_rendered_template(source, @context))
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -1,72 +1,80 @@
|
|||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class TestCompiledTemplate < ActiveSupport::TestCase
|
class TestJsonRenderer < ActiveSupport::TestCase
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@context = Context.new
|
|
||||||
@data = User.new(1, 'foobar', 'male')
|
@data = User.new(1, 'foobar', 'male')
|
||||||
@data.stub(:respond_to?).with(:each).and_return(false)
|
@data.stub(:respond_to?).with(:each).and_return(false)
|
||||||
|
|
||||||
|
@context = Context.new
|
||||||
@context.stub(:instance_variable_get).with(:@data).and_return(@data)
|
@context.stub(:instance_variable_get).with(:@data).and_return(@data)
|
||||||
@context.stub(:instance_variable_get).with(:@_assigns).and_return({})
|
@context.stub(:instance_variable_get).with(:@_assigns).and_return({})
|
||||||
|
|
||||||
@template = RablFastJson::CompiledTemplate.new
|
@template = RablFastJson::CompiledTemplate.new
|
||||||
@template.context = @context
|
|
||||||
@template.data = :@data
|
@template.data = :@data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_json_output
|
||||||
|
RablFastJson::Renderers::JSON.new(@context).render(@template).to_s
|
||||||
|
end
|
||||||
|
|
||||||
test "render object wth empty template" do
|
test "render object wth empty template" do
|
||||||
@template.source = {}
|
@template.source = {}
|
||||||
assert_equal({}, @template.render)
|
assert_equal %q({}), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "render collection with empty template" do
|
test "render collection with empty template" do
|
||||||
@context.stub(:instance_variable_get).with(:@data).and_return([@data])
|
@context.stub(:instance_variable_get).with(:@data).and_return([@data])
|
||||||
@template.source = {}
|
@template.source = {}
|
||||||
assert_equal([{}], @template.render)
|
assert_equal %q([{}]), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "render single object attributes" do
|
test "render single object attributes" do
|
||||||
@template.source = { :id => :id, :name => :name }
|
@template.source = { :id => :id, :name => :name }
|
||||||
assert_equal({ :id => 1, :name => 'foobar'}, @template.render)
|
assert_equal %q({"id":1,"name":"foobar"}), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "render object as a child" do
|
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({"address":{"city":"Paris"}}), render_json_output
|
||||||
|
end
|
||||||
|
|
||||||
|
test "render child with arbitrary data source" do
|
||||||
@template.source = { :author => { :_data => :@data, :name => :name } }
|
@template.source = { :author => { :_data => :@data, :name => :name } }
|
||||||
assert_equal({ :author => { :name => 'foobar' } }, @template.render)
|
assert_equal %q({"author":{"name":"foobar"}}), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "render glued attributes from single object" do
|
test "render glued attributes from single object" do
|
||||||
@template.source = { :_glue0 => { :_data => :@data, :name => :name } }
|
@template.source = { :_glue0 => { :_data => :@data, :name => :name } }
|
||||||
assert_equal({ :name => 'foobar' }, @template.render)
|
assert_equal %q({"name":"foobar"}), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "render collection with attributes" do
|
test "render collection with attributes" do
|
||||||
@data = [User.new(1, 'foo', 'male'), User.new(2, 'bar', 'female')]
|
@data = [User.new(1, 'foo', 'male'), User.new(2, 'bar', 'female')]
|
||||||
@context.stub(:instance_variable_get).with(:@data).and_return(@data)
|
@context.stub(:instance_variable_get).with(:@data).and_return(@data)
|
||||||
@template.source = { :uid => :id, :name => :name, :gender => :sex }
|
@template.source = { :uid => :id, :name => :name, :gender => :sex }
|
||||||
assert_equal([
|
assert_equal %q([{"uid":1,"name":"foo","gender":"male"},{"uid":2,"name":"bar","gender":"female"}]), render_json_output
|
||||||
{ :uid => 1, :name => 'foo', :gender => 'male'},
|
|
||||||
{ :uid => 2, :name => 'bar', :gender => 'female'}
|
|
||||||
], @template.render)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "render node property" do
|
test "render node property" do
|
||||||
proc = lambda { |object| object.sex }
|
proc = lambda { |object| object.name }
|
||||||
@template.source = { :sex => proc }
|
@template.source = { :name => proc }
|
||||||
assert_equal({ :sex => 'male' }, @template.render)
|
assert_equal %q({"name":"foobar"}), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "render node property with true condition" do
|
test "render node property with true condition" do
|
||||||
condition = lambda { |u| true }
|
condition = lambda { |u| true }
|
||||||
proc = lambda { |object| object.name }
|
proc = lambda { |object| object.name }
|
||||||
@template.source = { :name => [condition, proc] }
|
@template.source = { :name => [condition, proc] }
|
||||||
assert_equal({ :name => 'foobar' }, @template.render)
|
assert_equal %q({"name":"foobar"}), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "render node property with false condition" do
|
test "render node property with false condition" do
|
||||||
condition = lambda { |u| false }
|
condition = lambda { |u| false }
|
||||||
proc = lambda { |object| object.name }
|
proc = lambda { |object| object.name }
|
||||||
@template.source = { :name => [condition, proc] }
|
@template.source = { :name => [condition, proc] }
|
||||||
assert_equal({}, @template.render)
|
assert_equal %q({}), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "partial should be evaluated at rendering time" do
|
test "partial should be evaluated at rendering time" do
|
||||||
@ -76,27 +84,27 @@ class TestCompiledTemplate < ActiveSupport::TestCase
|
|||||||
|
|
||||||
# Stub Library#get
|
# Stub Library#get
|
||||||
t = RablFastJson::CompiledTemplate.new
|
t = RablFastJson::CompiledTemplate.new
|
||||||
t.source, t.context = { :name => :name }, @context
|
t.source = { :name => :name }
|
||||||
RablFastJson::Library.reset_instance
|
RablFastJson::Library.reset_instance
|
||||||
RablFastJson::Library.instance.should_receive(:get).with('users/base').and_return(t)
|
RablFastJson::Library.instance.should_receive(:get).with('users/base').and_return(t)
|
||||||
|
|
||||||
@template.data = false
|
@template.data = false
|
||||||
@template.source = { :user => ->(s) { partial('users/base', :object => @user) } }
|
@template.source = { :user => ->(s) { partial('users/base', :object => @user) } }
|
||||||
|
|
||||||
assert_equal({ :user => { :name => 'foobar' } }, @template.render)
|
assert_equal %q({"user":{"name":"foobar"}}), render_json_output
|
||||||
end
|
end
|
||||||
|
|
||||||
test "partial with nil values should raise an error" do
|
test "partial with no values should raise an error" do
|
||||||
@template.data = false
|
@template.data = false
|
||||||
@template.source = { :user => ->(s) { partial('users/base') } }
|
@template.source = { :user => ->(s) { partial('users/base') } }
|
||||||
|
|
||||||
assert_raises(RuntimeError) { @template.render }
|
assert_raises(RablFastJson::Renderers::PartialError) { render_json_output }
|
||||||
end
|
end
|
||||||
|
|
||||||
test "partial with empty values should not raise an error" do
|
test "partial with empty values should not raise an error" do
|
||||||
@template.data = false
|
@template.data = false
|
||||||
@template.source = { :users => ->(s) { partial('users/base', :object => []) } }
|
@template.source = { :users => ->(s) { partial('users/base', :object => []) } }
|
||||||
|
|
||||||
assert_equal({ :users => [] }, @template.render)
|
assert_equal %q({"users":[]}), render_json_output
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -35,16 +35,11 @@ class Context
|
|||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@_assigns = {}
|
@_assigns = {}
|
||||||
@virtual_path = '/users'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_assign(key, value)
|
def params
|
||||||
@_assigns[key] = value
|
{}
|
||||||
end
|
|
||||||
|
|
||||||
def get_assign(key)
|
|
||||||
@_assigns[key]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
User = Struct.new(:id, :name, :sex)
|
User = Struct.new(:id, :name, :sex)
|
Loading…
Reference in New Issue
Block a user