Testing version
This commit is contained in:
parent
e24aca780d
commit
bdc5148c42
1
Gemfile
1
Gemfile
|
@ -7,6 +7,7 @@ gemspec
|
||||||
|
|
||||||
# jquery-rails is used by the dummy application
|
# jquery-rails is used by the dummy application
|
||||||
gem "jquery-rails"
|
gem "jquery-rails"
|
||||||
|
gem 'rspec-mocks'
|
||||||
|
|
||||||
# Declare any dependencies that are still in development here instead of in
|
# Declare any dependencies that are still in development here instead of in
|
||||||
# your gemspec. These might include edge Rails or gems from your path or
|
# your gemspec. These might include edge Rails or gems from your path or
|
||||||
|
|
|
@ -39,7 +39,7 @@ GEM
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
hike (1.2.1)
|
hike (1.2.1)
|
||||||
i18n (0.6.0)
|
i18n (0.6.0)
|
||||||
journey (1.0.2)
|
journey (1.0.3)
|
||||||
jquery-rails (2.0.0)
|
jquery-rails (2.0.0)
|
||||||
railties (>= 3.2.0.beta, < 5.0)
|
railties (>= 3.2.0.beta, < 5.0)
|
||||||
thor (~> 0.14)
|
thor (~> 0.14)
|
||||||
|
@ -76,6 +76,7 @@ GEM
|
||||||
rake (0.9.2.2)
|
rake (0.9.2.2)
|
||||||
rdoc (3.12)
|
rdoc (3.12)
|
||||||
json (~> 1.4)
|
json (~> 1.4)
|
||||||
|
rspec-mocks (2.8.0)
|
||||||
sprockets (2.1.2)
|
sprockets (2.1.2)
|
||||||
hike (~> 1.2)
|
hike (~> 1.2)
|
||||||
rack (~> 1.0)
|
rack (~> 1.0)
|
||||||
|
@ -94,4 +95,5 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
jquery-rails
|
jquery-rails
|
||||||
rabl-fast-json!
|
rabl-fast-json!
|
||||||
|
rspec-mocks
|
||||||
sqlite3
|
sqlite3
|
||||||
|
|
|
@ -7,6 +7,7 @@ require 'active_support/core_ext/class/attribute_accessors'
|
||||||
require 'rabl-fast-json/version'
|
require 'rabl-fast-json/version'
|
||||||
require 'rabl-fast-json/template'
|
require 'rabl-fast-json/template'
|
||||||
require 'rabl-fast-json/compiler'
|
require 'rabl-fast-json/compiler'
|
||||||
|
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'
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
require 'singleton'
|
|
||||||
|
|
||||||
module RablFastJson
|
module RablFastJson
|
||||||
class Compiler
|
class Compiler
|
||||||
|
|
||||||
def initialize(context, assigns = nil)
|
def initialize(context = nil, assigns = nil)
|
||||||
@context = context
|
@context = context
|
||||||
@glue_count = 0
|
@glue_count = 0
|
||||||
_get_assigns_from_context(assigns)
|
|
||||||
_get_virtual_path_from_context
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile_source(source)
|
def compile_source(source)
|
||||||
|
@ -41,6 +37,7 @@ module RablFastJson
|
||||||
return unless block_given?
|
return unless block_given?
|
||||||
name = :"_glue#{@glue_count}"
|
name = :"_glue#{@glue_count}"
|
||||||
@glue_count += 1
|
@glue_count += 1
|
||||||
|
Rails.logger.warn "[RABL] glue called with data = #{data.inspect}"
|
||||||
_compile_sub_template(name, data, &block)
|
_compile_sub_template(name, data, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -50,7 +47,12 @@ module RablFastJson
|
||||||
alias_method :code, :node
|
alias_method :code, :node
|
||||||
|
|
||||||
def collection(data, options = {})
|
def collection(data, options = {})
|
||||||
@data = data.to_a if data
|
object(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def extends(path)
|
||||||
|
t = Library.instance.get(path)
|
||||||
|
@template.merge!(t.source)
|
||||||
end
|
end
|
||||||
|
|
||||||
def object(data)
|
def object(data)
|
||||||
|
@ -58,6 +60,10 @@ module RablFastJson
|
||||||
@template.data, @template.root_name = data, name
|
@template.data, @template.root_name = data, name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def method_missing(name, *args, &block)
|
||||||
|
@context.respond_to?(name) ? @context.send(name, *args, &block) : super
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def extract_data_and_name(name_or_data)
|
def extract_data_and_name(name_or_data)
|
||||||
|
@ -76,16 +82,5 @@ module RablFastJson
|
||||||
template = compiler.compile_block(&block)
|
template = compiler.compile_block(&block)
|
||||||
@template[name] = template.merge!(:_data => data)
|
@template[name] = template.merge!(:_data => data)
|
||||||
end
|
end
|
||||||
|
|
||||||
def _get_assigns_from_context(assigns)
|
|
||||||
source = assigns || @context.instance_variable_get(:@_assigns)
|
|
||||||
source.each_pair { |k, v|
|
|
||||||
instance_variable_set("@#{k}", v) unless k.start_with?('_')
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def _get_virtual_path_from_context
|
|
||||||
@virtual_path = @context.instance_variable_get(:@virtual_path)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -6,7 +6,8 @@ module RablFastJson
|
||||||
|
|
||||||
def self.call(template)
|
def self.call(template)
|
||||||
%{
|
%{
|
||||||
RablFastJson::Compiler.instance.compile_source(#{template.source.inspect}, self)
|
RablFastJson::Library.instance.
|
||||||
|
get_rendered_template(#{template.source.inspect}, self)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
require 'singleton'
|
||||||
|
|
||||||
|
module RablFastJson
|
||||||
|
class Library
|
||||||
|
include Singleton
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@cached_templates = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_rendered_template(source, context)
|
||||||
|
path = context.instance_variable_get(:@virtual_path)
|
||||||
|
@view_renderer = context.instance_variable_get(:@view_renderer)
|
||||||
|
start = Time.now
|
||||||
|
compiled_template = get_compiled_template(path, source, context)
|
||||||
|
compiled_time = Time.now
|
||||||
|
compiled_template.context = context
|
||||||
|
r = compiled_template.render
|
||||||
|
render_time = Time.now
|
||||||
|
res = ActiveSupport::JSON.encode(r)
|
||||||
|
final_time = Time.now
|
||||||
|
|
||||||
|
Rails.logger.warn "[BENCHMARK] Compilation:\t#{(compiled_time - start) * 1000.0}ms"
|
||||||
|
Rails.logger.warn "[BENCHMARK] Rendering:\t\t#{(render_time - compiled_time) * 1000.0}ms"
|
||||||
|
Rails.logger.warn "[BENCHMARK] JSON encoding:\t#{(final_time - render_time) * 1000.0}ms"
|
||||||
|
Rails.logger.warn "[BENCHMARK] Total:\t\t#{(final_time - start) * 1000.0}ms"
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_compiled_template(path, source, context)
|
||||||
|
#@cached_templates[path] ||=
|
||||||
|
Compiler.new(context).compile_source(source)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(path)
|
||||||
|
template = @cached_templates[path]
|
||||||
|
return template if !template.nil?
|
||||||
|
t = @view_renderer.lookup_context.find_template(path, [], false)
|
||||||
|
get_compiled_template(path, t.source, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,45 +1,58 @@
|
||||||
module RablFastJson
|
module RablFastJson
|
||||||
class CompiledTemplate
|
class CompiledTemplate
|
||||||
|
|
||||||
attr_accessor :source, :data, :root_name
|
attr_accessor :source, :data, :root_name, :context
|
||||||
|
|
||||||
delegate :[], :[]=, :to => :source
|
delegate :[], :[]=, :merge!, :to => :source
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@source = {}
|
@source = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
def get_object_from_assigns
|
||||||
# def render(data = nil)
|
@object = @context.instance_variable_get(@data)
|
||||||
# output = {}
|
end
|
||||||
# @data = data if data
|
|
||||||
#
|
def render
|
||||||
# return render_collection if @data.respond_to?(:each)
|
get_object_from_assigns
|
||||||
#
|
@object.respond_to?(:each) ? render_collection : render_resource
|
||||||
# @template.each_pair { |key, value|
|
end
|
||||||
# out = case value
|
|
||||||
# when Symbol
|
def render_resource(data = nil, source = nil)
|
||||||
# @data.send(value)
|
output = {}
|
||||||
# end
|
|
||||||
# output[key] = out
|
data ||= @object
|
||||||
# }
|
source ||= @source
|
||||||
# output
|
|
||||||
# end
|
source.each_pair { |key, value|
|
||||||
#
|
out = case value
|
||||||
# def render_collection
|
when Symbol
|
||||||
# output = []
|
data.send(value) # attributes
|
||||||
# @data.each { |o|
|
when Proc
|
||||||
# object = {}
|
value.call(data) # node
|
||||||
# @template.each_pair { |key, value|
|
when Hash
|
||||||
# out = case value
|
data_symbol = value.delete(:_data)
|
||||||
# when Symbol
|
object = data_symbol.to_s.start_with?('@') ? @context.instance_variable_get(data_symbol) : @object.send(data_symbol)
|
||||||
# o.send(value)
|
if key.to_s.start_with?('_') # glue
|
||||||
# end
|
value.each_pair { |k, v|
|
||||||
# object[key] = out
|
output[k] = object.send(v)
|
||||||
# }
|
}
|
||||||
# output << object
|
|
||||||
# }
|
next
|
||||||
# output
|
else # child
|
||||||
# end
|
object.respond_to?(:each) ? render_collection(object, value) : render_resource(object, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
output[key] = out
|
||||||
|
}
|
||||||
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_collection(collection = nil, source = nil)
|
||||||
|
output = []
|
||||||
|
collection ||= @object
|
||||||
|
collection.each { |o| output << render_resource(o, source) }
|
||||||
|
output
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,5 +1,12 @@
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class TestCompiledTemplate
|
class TestCompiledTemplate < ActiveSupport::TestCase
|
||||||
|
|
||||||
|
setup do
|
||||||
|
@context = Context.new
|
||||||
|
@user = User.new
|
||||||
|
@context.set_assign('user', @user)
|
||||||
|
@template = RablFastJson::CompiledTemplate.new
|
||||||
|
@template.context = @context
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -1,26 +1,6 @@
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class CompilerTest < ActiveSupport::TestCase
|
class CompilerTest < ActiveSupport::TestCase
|
||||||
class Context
|
|
||||||
attr_accessor :virtual_path
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@_assigns = {}
|
|
||||||
@virtual_path = '/users'
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_assign(key, value)
|
|
||||||
@_assigns[key] = value
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_assign(key)
|
|
||||||
@_assigns[key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class User
|
|
||||||
attr_accessor :name
|
|
||||||
end
|
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@context = Context.new
|
@context = Context.new
|
||||||
|
@ -29,20 +9,6 @@ class CompilerTest < ActiveSupport::TestCase
|
||||||
@compiler = RablFastJson::Compiler.new(@context)
|
@compiler = RablFastJson::Compiler.new(@context)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "assigns are correctly imported from context" do
|
|
||||||
assert_equal @user, @compiler.instance_variable_get(:@user)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "virtual path is correctly imported from context" do
|
|
||||||
assert_equal '/users', @compiler.instance_variable_get(:@virtual_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "assigns are not imported if already passed to the compiler" do
|
|
||||||
compiler = RablFastJson::Compiler.new(@context, { 'other' => 'foo' })
|
|
||||||
assert_nil compiler.instance_variable_get(:@user)
|
|
||||||
assert_equal 'foo', compiler.instance_variable_get(:@other)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "compiler return a compiled template" do
|
test "compiler return a compiled template" do
|
||||||
assert_instance_of RablFastJson::CompiledTemplate, @compiler.compile_source("")
|
assert_instance_of RablFastJson::CompiledTemplate, @compiler.compile_source("")
|
||||||
end
|
end
|
||||||
|
@ -78,38 +44,56 @@ class CompilerTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
test "child with arbitrary source store the data with the template" do
|
test "child with arbitrary source store the data with the template" do
|
||||||
t = @compiler.compile_source(%{ child @user => :author do attribute :name end })
|
t = @compiler.compile_source(%{ child :@user => :author do attribute :name end })
|
||||||
assert_equal({ :author => { :_data => @user, :name => :name } }, t.source)
|
assert_equal({ :author => { :_data => :@user, :name => :name } }, t.source)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "glue is compiled as a child but with anonymous name" do
|
test "glue is compiled as a child but with anonymous name" do
|
||||||
t = @compiler.compile_source(%{ glue @user do attribute :name end })
|
t = @compiler.compile_source(%{ glue :@user do attribute :name end })
|
||||||
assert_equal({ :_glue0 => { :_data => @user, :name => :name } }, t.source)
|
assert_equal({ :_glue0 => { :_data => :@user, :name => :name } }, t.source)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "multiple glue don't come with name collisions" do
|
test "multiple glue don't come with name collisions" do
|
||||||
t = @compiler.compile_source(%{
|
t = @compiler.compile_source(%{
|
||||||
glue @user do attribute :name end
|
glue :@user do attribute :name end
|
||||||
glue @user do attribute :foo end
|
glue :@user do attribute :foo end
|
||||||
})
|
})
|
||||||
|
|
||||||
assert_equal({
|
assert_equal({
|
||||||
:_glue0 => { :_data => @user, :name => :name},
|
:_glue0 => { :_data => :@user, :name => :name},
|
||||||
:_glue1 => { :_data => @user, :foo => :foo}
|
:_glue1 => { :_data => :@user, :foo => :foo}
|
||||||
}, t.source)
|
}, t.source)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "object set data for the template" do
|
test "object set data for the template" do
|
||||||
t = @compiler.compile_source(%{ object @user })
|
t = @compiler.compile_source(%{ object :@user })
|
||||||
assert_equal @user, t.data
|
assert_equal :@user, t.data
|
||||||
end
|
end
|
||||||
|
|
||||||
test "object property can define root name" do
|
test "object property can define root name" do
|
||||||
t = @compiler.compile_source(%{ object @user => :author })
|
t = @compiler.compile_source(%{ object :@user => :author })
|
||||||
assert_equal @user, t.data
|
assert_equal :@user, t.data
|
||||||
assert_equal :author, t.root_name
|
assert_equal :author, t.root_name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "collection set the data for the template" do
|
||||||
|
t = @compiler.compile_source(%{ collection :@user })
|
||||||
|
assert_equal :@user, t.data
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
test "extends use other template one's active" do
|
||||||
|
template = mock('template', :source => { :id => :id })
|
||||||
|
RablFastJson::Library.stub_chain(:instance, :get).with('users/base').and_return(template)
|
||||||
|
t = @compiler.compile_source(%{ extends 'users/base' })
|
||||||
|
assert_equal({ :id => :id }, t.source)
|
||||||
|
end
|
||||||
|
|
||||||
test "node are compiled without evaluating the block" do
|
test "node are compiled without evaluating the block" do
|
||||||
t = @compiler.compile_source(%{ node(:foo) { bar } })
|
t = @compiler.compile_source(%{ node(:foo) { bar } })
|
||||||
assert_not_nil t.source[:foo]
|
assert_not_nil t.source[:foo]
|
||||||
|
|
|
@ -2,6 +2,35 @@
|
||||||
ENV["RAILS_ENV"] = "test"
|
ENV["RAILS_ENV"] = "test"
|
||||||
$:.unshift File.expand_path('../../lib', __FILE__)
|
$:.unshift File.expand_path('../../lib', __FILE__)
|
||||||
|
|
||||||
|
require 'rspec/mocks'
|
||||||
require 'minitest/autorun'
|
require 'minitest/autorun'
|
||||||
require 'active_support/test_case'
|
require 'active_support/test_case'
|
||||||
require 'rabl-fast-json'
|
require 'rabl-fast-json'
|
||||||
|
|
||||||
|
module ActiveSupport
|
||||||
|
class TestCase
|
||||||
|
RSpec::Mocks::setup(self)
|
||||||
|
include RSpec::Mocks::ExampleMethods
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Context
|
||||||
|
attr_accessor :virtual_path
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@_assigns = {}
|
||||||
|
@virtual_path = '/users'
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_assign(key, value)
|
||||||
|
@_assigns[key] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_assign(key)
|
||||||
|
@_assigns[key]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class User
|
||||||
|
attr_accessor :name
|
||||||
|
end
|
Loading…
Reference in New Issue