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
|
||||
gem "jquery-rails"
|
||||
gem 'rspec-mocks'
|
||||
|
||||
# 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
|
||||
|
@ -39,7 +39,7 @@ GEM
|
||||
erubis (2.7.0)
|
||||
hike (1.2.1)
|
||||
i18n (0.6.0)
|
||||
journey (1.0.2)
|
||||
journey (1.0.3)
|
||||
jquery-rails (2.0.0)
|
||||
railties (>= 3.2.0.beta, < 5.0)
|
||||
thor (~> 0.14)
|
||||
@ -76,6 +76,7 @@ GEM
|
||||
rake (0.9.2.2)
|
||||
rdoc (3.12)
|
||||
json (~> 1.4)
|
||||
rspec-mocks (2.8.0)
|
||||
sprockets (2.1.2)
|
||||
hike (~> 1.2)
|
||||
rack (~> 1.0)
|
||||
@ -94,4 +95,5 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
jquery-rails
|
||||
rabl-fast-json!
|
||||
rspec-mocks
|
||||
sqlite3
|
||||
|
@ -7,6 +7,7 @@ require 'active_support/core_ext/class/attribute_accessors'
|
||||
require 'rabl-fast-json/version'
|
||||
require 'rabl-fast-json/template'
|
||||
require 'rabl-fast-json/compiler'
|
||||
require 'rabl-fast-json/library'
|
||||
require 'rabl-fast-json/handler'
|
||||
require 'rabl-fast-json/railtie'
|
||||
|
||||
|
@ -1,13 +1,9 @@
|
||||
require 'singleton'
|
||||
|
||||
module RablFastJson
|
||||
class Compiler
|
||||
|
||||
def initialize(context, assigns = nil)
|
||||
def initialize(context = nil, assigns = nil)
|
||||
@context = context
|
||||
@glue_count = 0
|
||||
_get_assigns_from_context(assigns)
|
||||
_get_virtual_path_from_context
|
||||
end
|
||||
|
||||
def compile_source(source)
|
||||
@ -41,6 +37,7 @@ module RablFastJson
|
||||
return unless block_given?
|
||||
name = :"_glue#{@glue_count}"
|
||||
@glue_count += 1
|
||||
Rails.logger.warn "[RABL] glue called with data = #{data.inspect}"
|
||||
_compile_sub_template(name, data, &block)
|
||||
end
|
||||
|
||||
@ -50,7 +47,12 @@ module RablFastJson
|
||||
alias_method :code, :node
|
||||
|
||||
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
|
||||
|
||||
def object(data)
|
||||
@ -58,6 +60,10 @@ module RablFastJson
|
||||
@template.data, @template.root_name = data, name
|
||||
end
|
||||
|
||||
def method_missing(name, *args, &block)
|
||||
@context.respond_to?(name) ? @context.send(name, *args, &block) : super
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def extract_data_and_name(name_or_data)
|
||||
@ -76,16 +82,5 @@ module RablFastJson
|
||||
template = compiler.compile_block(&block)
|
||||
@template[name] = template.merge!(:_data => data)
|
||||
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
|
@ -6,7 +6,8 @@ module RablFastJson
|
||||
|
||||
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
|
||||
|
43
lib/rabl-fast-json/library.rb
Normal file
43
lib/rabl-fast-json/library.rb
Normal file
@ -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
|
||||
class CompiledTemplate
|
||||
|
||||
attr_accessor :source, :data, :root_name
|
||||
attr_accessor :source, :data, :root_name, :context
|
||||
|
||||
delegate :[], :[]=, :to => :source
|
||||
delegate :[], :[]=, :merge!, :to => :source
|
||||
|
||||
def initialize
|
||||
@source = {}
|
||||
end
|
||||
|
||||
#
|
||||
# def render(data = nil)
|
||||
# output = {}
|
||||
# @data = data if data
|
||||
#
|
||||
# return render_collection if @data.respond_to?(:each)
|
||||
#
|
||||
# @template.each_pair { |key, value|
|
||||
# out = case value
|
||||
# when Symbol
|
||||
# @data.send(value)
|
||||
# end
|
||||
# output[key] = out
|
||||
# }
|
||||
# output
|
||||
# end
|
||||
#
|
||||
# def render_collection
|
||||
# output = []
|
||||
# @data.each { |o|
|
||||
# object = {}
|
||||
# @template.each_pair { |key, value|
|
||||
# out = case value
|
||||
# when Symbol
|
||||
# o.send(value)
|
||||
# end
|
||||
# object[key] = out
|
||||
# }
|
||||
# output << object
|
||||
# }
|
||||
# output
|
||||
# end
|
||||
def get_object_from_assigns
|
||||
@object = @context.instance_variable_get(@data)
|
||||
end
|
||||
|
||||
def render
|
||||
get_object_from_assigns
|
||||
@object.respond_to?(:each) ? render_collection : render_resource
|
||||
end
|
||||
|
||||
def render_resource(data = nil, source = nil)
|
||||
output = {}
|
||||
|
||||
data ||= @object
|
||||
source ||= @source
|
||||
|
||||
source.each_pair { |key, value|
|
||||
out = case value
|
||||
when Symbol
|
||||
data.send(value) # attributes
|
||||
when Proc
|
||||
value.call(data) # node
|
||||
when Hash
|
||||
data_symbol = value.delete(:_data)
|
||||
object = data_symbol.to_s.start_with?('@') ? @context.instance_variable_get(data_symbol) : @object.send(data_symbol)
|
||||
if key.to_s.start_with?('_') # glue
|
||||
value.each_pair { |k, v|
|
||||
output[k] = object.send(v)
|
||||
}
|
||||
|
||||
next
|
||||
else # child
|
||||
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
|
@ -1,5 +1,12 @@
|
||||
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
|
@ -1,26 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
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
|
||||
@context = Context.new
|
||||
@ -29,20 +9,6 @@ class CompilerTest < ActiveSupport::TestCase
|
||||
@compiler = RablFastJson::Compiler.new(@context)
|
||||
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
|
||||
assert_instance_of RablFastJson::CompiledTemplate, @compiler.compile_source("")
|
||||
end
|
||||
@ -78,38 +44,56 @@ class CompilerTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test "child with arbitrary source store the data with the template" do
|
||||
t = @compiler.compile_source(%{ child @user => :author do attribute :name end })
|
||||
assert_equal({ :author => { :_data => @user, :name => :name } }, t.source)
|
||||
t = @compiler.compile_source(%{ child :@user => :author do attribute :name end })
|
||||
assert_equal({ :author => { :_data => :@user, :name => :name } }, t.source)
|
||||
end
|
||||
|
||||
test "glue is compiled as a child but with anonymous name" do
|
||||
t = @compiler.compile_source(%{ glue @user do attribute :name end })
|
||||
assert_equal({ :_glue0 => { :_data => @user, :name => :name } }, t.source)
|
||||
t = @compiler.compile_source(%{ glue :@user do attribute :name end })
|
||||
assert_equal({ :_glue0 => { :_data => :@user, :name => :name } }, t.source)
|
||||
end
|
||||
|
||||
test "multiple glue don't come with name collisions" do
|
||||
t = @compiler.compile_source(%{
|
||||
glue @user do attribute :name end
|
||||
glue @user do attribute :foo end
|
||||
glue :@user do attribute :name end
|
||||
glue :@user do attribute :foo end
|
||||
})
|
||||
|
||||
assert_equal({
|
||||
:_glue0 => { :_data => @user, :name => :name},
|
||||
:_glue1 => { :_data => @user, :foo => :foo}
|
||||
:_glue0 => { :_data => :@user, :name => :name},
|
||||
:_glue1 => { :_data => :@user, :foo => :foo}
|
||||
}, t.source)
|
||||
end
|
||||
|
||||
test "object set data for the template" do
|
||||
t = @compiler.compile_source(%{ object @user })
|
||||
assert_equal @user, t.data
|
||||
t = @compiler.compile_source(%{ object :@user })
|
||||
assert_equal :@user, t.data
|
||||
end
|
||||
|
||||
test "object property can define root name" do
|
||||
t = @compiler.compile_source(%{ object @user => :author })
|
||||
assert_equal @user, t.data
|
||||
t = @compiler.compile_source(%{ object :@user => :author })
|
||||
assert_equal :@user, t.data
|
||||
assert_equal :author, t.root_name
|
||||
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
|
||||
t = @compiler.compile_source(%{ node(:foo) { bar } })
|
||||
assert_not_nil t.source[:foo]
|
||||
|
@ -2,6 +2,35 @@
|
||||
ENV["RAILS_ENV"] = "test"
|
||||
$:.unshift File.expand_path('../../lib', __FILE__)
|
||||
|
||||
require 'rspec/mocks'
|
||||
require 'minitest/autorun'
|
||||
require 'active_support/test_case'
|
||||
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
Block a user