rabl-rails 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -7
- data/CHANGELOG.md +5 -0
- data/README.md +30 -6
- data/lib/rabl-rails.rb +14 -7
- data/lib/rabl-rails/railtie.rb +2 -0
- data/lib/rabl-rails/renderer.rb +90 -1
- data/lib/rabl-rails/renderers/base.rb +1 -0
- data/lib/rabl-rails/version.rb +1 -1
- data/test/render_test.rb +64 -0
- metadata +5 -4
- data/Gemfile.lock +0 -67
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 0.1.2
|
4
|
+
* Add RablRails#render method (see README or source code)
|
5
|
+
* Fix fail when JSON engine is not found. Now fallback to MultiJson.default_adapter
|
6
|
+
* Warning message printed on logger when JSON engine fail to load
|
7
|
+
|
3
8
|
## 0.1.1
|
4
9
|
|
5
10
|
* Add CHANGELOG
|
data/README.md
CHANGED
@@ -81,6 +81,20 @@ The same rule applies for view helpers such as `current_user`
|
|
81
81
|
|
82
82
|
After the template is compiled into a hash, Rabl-rails will use a renderer to do the actual output. Actually, only JSON and XML formats are supported.
|
83
83
|
|
84
|
+
## Configuration
|
85
|
+
|
86
|
+
RablRails works out of the box, with default options and fastest engine available (yajl, libxml). But depending on your needs, you might want to change that or how your output looks like. You can set global configuration in your application:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
# config/initializers/rabl_rails.rb
|
90
|
+
RablRails.configure do |config|
|
91
|
+
# These are the default
|
92
|
+
# config.cache_templates = true
|
93
|
+
# config.include_json_root = true
|
94
|
+
# config.json_engine = :yajl
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
84
98
|
## Usage
|
85
99
|
|
86
100
|
### Data declaration
|
@@ -218,6 +232,22 @@ child :posts do
|
|
218
232
|
end
|
219
233
|
```
|
220
234
|
|
235
|
+
### Caching
|
236
|
+
|
237
|
+
Caching is not a part of Rabl-rails. It is already in Rails itself, because caching all view output is the same as action caching (Rails caching is even better because it will also not run your queries).
|
238
|
+
|
239
|
+
Moreover caching each object in a collection can be really not effective with big collections or simple objects. This is also a nightmare with cache expiration.
|
240
|
+
|
241
|
+
### Render object directly
|
242
|
+
|
243
|
+
There are cases when you want to render object outside Rails view context. For instance to render objects in the console or to create message queue payloads. For these situations, you can use `RablRails.render` as show below:
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
Rabl.render(object, template, :view_path => 'app/views', :format => :json) #=> "{...}"
|
247
|
+
```
|
248
|
+
|
249
|
+
You can find more informations about how to use this method in the [wiki](http://github.com/ccocchi/rabl-rails/wiki/Render-object-directly)
|
250
|
+
|
221
251
|
## Performance
|
222
252
|
|
223
253
|
Benchmarks have been made using this [application](http://github.com/ccocchi/rabl-benchmark), with rabl 0.6.14 and rabl-rails 0.1.0
|
@@ -226,12 +256,6 @@ Overall, Rabl-rails is **20% faster and use 10% less memory**.
|
|
226
256
|
|
227
257
|
You can see full tests on test application repository.
|
228
258
|
|
229
|
-
## Caching
|
230
|
-
|
231
|
-
Caching is not a part of Rabl-rails. It is already in Rails itself, because caching all view output is the same as action caching (Rails caching is even better because it will also not run your queries).
|
232
|
-
|
233
|
-
And caching each object in a collection can be really not effective with big collections or simple objects. This is also a nightmare with cache expiration.
|
234
|
-
|
235
259
|
## Authors and contributors
|
236
260
|
|
237
261
|
* [Christopher Cocchi-Perrier](http://github.com/ccocchi) - Creator of the project
|
data/lib/rabl-rails.rb
CHANGED
@@ -16,26 +16,33 @@ require 'rabl-rails/railtie'
|
|
16
16
|
require 'multi_json'
|
17
17
|
|
18
18
|
module RablRails
|
19
|
+
extend Renderer
|
20
|
+
|
19
21
|
mattr_accessor :cache_templates
|
20
22
|
@@cache_templates = true
|
21
23
|
|
22
24
|
mattr_accessor :include_json_root
|
23
25
|
@@include_json_root = true
|
24
26
|
|
25
|
-
|
27
|
+
mattr_reader :json_engine
|
26
28
|
@@json_engine = :yajl
|
27
29
|
|
28
30
|
def self.configure
|
29
31
|
yield self
|
30
|
-
post_configure
|
31
32
|
end
|
32
|
-
|
33
|
+
|
34
|
+
def self.json_engine=(name)
|
35
|
+
MultiJson.engine = name
|
36
|
+
@@json_engine = name
|
37
|
+
rescue LoadError
|
38
|
+
Rails.logger.warn %Q(WARNING: rabl-rails could not load "#{self.json_engine}" as JSON engine, fallback to default)
|
39
|
+
end
|
40
|
+
|
33
41
|
def self.cache_templates?
|
34
42
|
ActionController::Base.perform_caching && @@cache_templates
|
35
43
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
MultiJson.engine = self.json_engine
|
44
|
+
|
45
|
+
def self.load_default_engines!
|
46
|
+
self.json_engine = :yajl
|
40
47
|
end
|
41
48
|
end
|
data/lib/rabl-rails/railtie.rb
CHANGED
data/lib/rabl-rails/renderer.rb
CHANGED
@@ -1,2 +1,91 @@
|
|
1
1
|
require 'rabl-rails/renderers/base'
|
2
|
-
require 'rabl-rails/renderers/json'
|
2
|
+
require 'rabl-rails/renderers/json'
|
3
|
+
|
4
|
+
module RablRails
|
5
|
+
module Renderer
|
6
|
+
class TemplateNotFound < StandardError; end
|
7
|
+
|
8
|
+
mattr_reader :view_path
|
9
|
+
@@view_path = 'app/views'
|
10
|
+
|
11
|
+
class LookupContext
|
12
|
+
T = Struct.new(:source)
|
13
|
+
|
14
|
+
def initialize(view_path, format)
|
15
|
+
@view_path = view_path || RablRails::Renderer.view_path
|
16
|
+
@format = format
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Manually find given rabl template file with given format.
|
21
|
+
# View path can be set via options, otherwise default Rails
|
22
|
+
# path is used
|
23
|
+
#
|
24
|
+
def find_template(name, opt, partial = false)
|
25
|
+
path = File.join(@view_path, "#{name}.#{@format}.rabl")
|
26
|
+
File.exists?(path) ? T.new(File.read(path)) : nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Context class to emulate normal Rails view
|
32
|
+
# context
|
33
|
+
#
|
34
|
+
class Context
|
35
|
+
attr_reader :format
|
36
|
+
attr_accessor :target_object
|
37
|
+
|
38
|
+
def initialize(path, options)
|
39
|
+
@virtual_path = path
|
40
|
+
@format = options.delete(:format) || 'json'
|
41
|
+
@_assigns = {}
|
42
|
+
@options = options
|
43
|
+
|
44
|
+
options[:locals].each { |k, v| @_assigns[k.to_s] = v } if options[:locals]
|
45
|
+
end
|
46
|
+
|
47
|
+
def assigns
|
48
|
+
@_assigns
|
49
|
+
end
|
50
|
+
|
51
|
+
def params
|
52
|
+
{ format: format }
|
53
|
+
end
|
54
|
+
|
55
|
+
def lookup_context
|
56
|
+
@lookup_context ||= LookupContext.new(@options[:view_path], format)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Renders object with the given rabl template.
|
62
|
+
#
|
63
|
+
# Object can also be passed as an option :
|
64
|
+
# { locals: { object: obj_to_render } }
|
65
|
+
#
|
66
|
+
# Default render format is JSON, but can be changed via
|
67
|
+
# an option: { format: 'xml' }
|
68
|
+
#
|
69
|
+
# If template includes uses of instance variables (usually
|
70
|
+
# defined in the controller), you can passed them as locals
|
71
|
+
# options.
|
72
|
+
# For example, if you have this template:
|
73
|
+
# object :@user
|
74
|
+
# node(:read) { |u| u.has_read?(@post) }
|
75
|
+
#
|
76
|
+
# Your method call should look like this:
|
77
|
+
# RablRails.render(user, 'users/show', locals: { post: Post.new })
|
78
|
+
#
|
79
|
+
def render(object, template, options = {})
|
80
|
+
object = options[:locals].delete(:object) if !object && options[:locals]
|
81
|
+
|
82
|
+
c = Context.new(template, options)
|
83
|
+
c.target_object = object
|
84
|
+
|
85
|
+
t = c.lookup_context.find_template(template, [], false)
|
86
|
+
raise TemplateNotFound unless t
|
87
|
+
|
88
|
+
Library.instance.get_rendered_template(t.source, c)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -19,6 +19,7 @@ module RablRails
|
|
19
19
|
#
|
20
20
|
def render(template)
|
21
21
|
collection_or_resource = instance_variable_get(template.data) if template.data
|
22
|
+
collection_or_resource = @_context.target_object unless collection_or_resource || template.data == false || !@_context.respond_to?(:target_object)
|
22
23
|
output_hash = collection_or_resource.respond_to?(:each) ? render_collection(collection_or_resource, template.source) :
|
23
24
|
render_resource(collection_or_resource, template.source)
|
24
25
|
_options[:root_name] = template.root_name
|
data/lib/rabl-rails/version.rb
CHANGED
data/test/render_test.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pathname'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
class RenderTest < ActiveSupport::TestCase
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@user = User.new(1, 'Marty')
|
9
|
+
@user.stub(:respond_to?).with(:each).and_return(false)
|
10
|
+
@tmp_path = Pathname.new(Dir.mktmpdir)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "allow object to be passed as an option" do
|
14
|
+
File.open(@tmp_path + "nil.json.rabl", "w") do |f|
|
15
|
+
f.puts %q{
|
16
|
+
object :@user
|
17
|
+
attributes :name
|
18
|
+
}
|
19
|
+
end
|
20
|
+
assert_equal %q({"user":{"name":"Marty"}}), RablRails.render(nil, 'nil', locals: { object: @user }, view_path: @tmp_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
test "load source from file" do
|
24
|
+
File.open(@tmp_path + "show.json.rabl", "w") do |f|
|
25
|
+
f.puts %q{
|
26
|
+
object :@user
|
27
|
+
attributes :id, :name
|
28
|
+
}
|
29
|
+
end
|
30
|
+
assert_equal %q({"user":{"id":1,"name":"Marty"}}), RablRails.render(@user, 'show', view_path: @tmp_path)
|
31
|
+
end
|
32
|
+
|
33
|
+
test "raise error if template is not found" do
|
34
|
+
assert_raises(RablRails::Renderer::TemplateNotFound) { RablRails.render(@user, 'not_found') }
|
35
|
+
end
|
36
|
+
|
37
|
+
test "instance variables can be passed via options[:locals]" do
|
38
|
+
File.open(@tmp_path + "instance.json.rabl", "w") do |f|
|
39
|
+
f.puts %q{
|
40
|
+
object false
|
41
|
+
node(:username) { |_| @user.name }
|
42
|
+
}
|
43
|
+
end
|
44
|
+
assert_equal %q({"username":"Marty"}), RablRails.render(nil, 'instance', view_path: @tmp_path, locals: { user: @user })
|
45
|
+
end
|
46
|
+
|
47
|
+
test "handle path for extends" do
|
48
|
+
File.open(@tmp_path + "extend.json.rabl", "w") do |f|
|
49
|
+
f.puts %q{
|
50
|
+
object :@user
|
51
|
+
extends 'base'
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
File.open(@tmp_path + "base.json.rabl", "w") do |f|
|
56
|
+
f.puts %q{
|
57
|
+
attribute :name, as: :extended_name
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
assert_equal %q({"user":{"extended_name":"Marty"}}), RablRails.render(@user, 'extend', view_path: @tmp_path)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rabl-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -69,7 +69,6 @@ files:
|
|
69
69
|
- .gitignore
|
70
70
|
- CHANGELOG.md
|
71
71
|
- Gemfile
|
72
|
-
- Gemfile.lock
|
73
72
|
- MIT-LICENSE
|
74
73
|
- README.md
|
75
74
|
- Rakefile
|
@@ -89,6 +88,7 @@ files:
|
|
89
88
|
- test/compiler_test.rb
|
90
89
|
- test/deep_nesting_test.rb
|
91
90
|
- test/non_restful_response_test.rb
|
91
|
+
- test/render_test.rb
|
92
92
|
- test/renderers/json_renderer_test.rb
|
93
93
|
- test/test_helper.rb
|
94
94
|
homepage: https://github.com/ccocchi/rabl-rails
|
@@ -111,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
111
|
version: '0'
|
112
112
|
requirements: []
|
113
113
|
rubyforge_project:
|
114
|
-
rubygems_version: 1.8.
|
114
|
+
rubygems_version: 1.8.21
|
115
115
|
signing_key:
|
116
116
|
specification_version: 3
|
117
117
|
summary: Fast Rails 3+ templating system with JSON and XML support
|
@@ -120,5 +120,6 @@ test_files:
|
|
120
120
|
- test/compiler_test.rb
|
121
121
|
- test/deep_nesting_test.rb
|
122
122
|
- test/non_restful_response_test.rb
|
123
|
+
- test/render_test.rb
|
123
124
|
- test/renderers/json_renderer_test.rb
|
124
125
|
- test/test_helper.rb
|
data/Gemfile.lock
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
rabl-rails (0.1.0)
|
5
|
-
activesupport (~> 3.0)
|
6
|
-
railties (~> 3.0)
|
7
|
-
|
8
|
-
GEM
|
9
|
-
remote: http://rubygems.org/
|
10
|
-
specs:
|
11
|
-
actionpack (3.2.6)
|
12
|
-
activemodel (= 3.2.6)
|
13
|
-
activesupport (= 3.2.6)
|
14
|
-
builder (~> 3.0.0)
|
15
|
-
erubis (~> 2.7.0)
|
16
|
-
journey (~> 1.0.1)
|
17
|
-
rack (~> 1.4.0)
|
18
|
-
rack-cache (~> 1.2)
|
19
|
-
rack-test (~> 0.6.1)
|
20
|
-
sprockets (~> 2.1.3)
|
21
|
-
activemodel (3.2.6)
|
22
|
-
activesupport (= 3.2.6)
|
23
|
-
builder (~> 3.0.0)
|
24
|
-
activesupport (3.2.6)
|
25
|
-
i18n (~> 0.6)
|
26
|
-
multi_json (~> 1.0)
|
27
|
-
builder (3.0.0)
|
28
|
-
erubis (2.7.0)
|
29
|
-
hike (1.2.1)
|
30
|
-
i18n (0.6.0)
|
31
|
-
journey (1.0.4)
|
32
|
-
json (1.7.3)
|
33
|
-
multi_json (1.3.6)
|
34
|
-
rack (1.4.1)
|
35
|
-
rack-cache (1.2)
|
36
|
-
rack (>= 0.4)
|
37
|
-
rack-ssl (1.3.2)
|
38
|
-
rack
|
39
|
-
rack-test (0.6.1)
|
40
|
-
rack (>= 1.0)
|
41
|
-
railties (3.2.6)
|
42
|
-
actionpack (= 3.2.6)
|
43
|
-
activesupport (= 3.2.6)
|
44
|
-
rack-ssl (~> 1.3.2)
|
45
|
-
rake (>= 0.8.7)
|
46
|
-
rdoc (~> 3.4)
|
47
|
-
thor (>= 0.14.6, < 2.0)
|
48
|
-
rake (0.9.2.2)
|
49
|
-
rdoc (3.12)
|
50
|
-
json (~> 1.4)
|
51
|
-
rspec-mocks (2.11.1)
|
52
|
-
sprockets (2.1.3)
|
53
|
-
hike (~> 1.2)
|
54
|
-
rack (~> 1.0)
|
55
|
-
tilt (~> 1.1, != 1.3.0)
|
56
|
-
thor (0.15.4)
|
57
|
-
tilt (1.3.3)
|
58
|
-
yajl-ruby (1.1.0)
|
59
|
-
|
60
|
-
PLATFORMS
|
61
|
-
ruby
|
62
|
-
|
63
|
-
DEPENDENCIES
|
64
|
-
actionpack (~> 3.0)
|
65
|
-
rabl-rails!
|
66
|
-
rspec-mocks
|
67
|
-
yajl-ruby
|