rabl-rails 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +9 -0
- data/Gemfile +3 -0
- data/README.md +22 -3
- data/lib/rabl-rails/compiler.rb +24 -8
- data/lib/rabl-rails/library.rb +6 -4
- data/lib/rabl-rails/renderer.rb +1 -1
- data/lib/rabl-rails/renderers/base.rb +10 -4
- data/lib/rabl-rails/template.rb +5 -0
- data/lib/rabl-rails/version.rb +1 -1
- data/test/cache_templates_test.rb +4 -3
- data/test/compiler_test.rb +23 -1
- data/test/render_test.rb +13 -0
- data/test/renderers/json_renderer_test.rb +15 -0
- data/test/test_helper.rb +1 -1
- metadata +3 -3
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 0.3.2 (unreleased)
|
4
|
+
|
5
|
+
## 0.3.1
|
6
|
+
* Add `merge` keywork
|
7
|
+
* Format can be passed as a string or a symbol
|
8
|
+
* Avoid to unexpectedly change cached templates (johnbintz)
|
9
|
+
* Add full template stack support to `glue` (fnordfish)
|
10
|
+
* Allow format to be a symbol (lloydmeta)
|
11
|
+
|
3
12
|
## 0.3.0
|
4
13
|
* Travis integration
|
5
14
|
* Add test for keywords used as variable names
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -165,7 +165,8 @@ attributes title: :foo, to_s: :bar
|
|
165
165
|
|
166
166
|
### Child nodes
|
167
167
|
|
168
|
-
You can include
|
168
|
+
You can include informations from data associated with the parent model or arbitrary data. These informations can be grouped under a node or directly merged into current node.
|
169
|
+
|
169
170
|
For example if you have a `Post` model that belongs to a `User`
|
170
171
|
|
171
172
|
```ruby
|
@@ -183,9 +184,19 @@ child(:@users) do
|
|
183
184
|
end
|
184
185
|
```
|
185
186
|
|
187
|
+
If you want to merge directly into current node, you can use the `glue` keywork
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
attribute :title
|
191
|
+
glue(:user) do
|
192
|
+
attributes :name => :author_name
|
193
|
+
end
|
194
|
+
# => { "post" : { "title" : "Foo", "author_name" : "John D." } }
|
195
|
+
```
|
196
|
+
|
186
197
|
### Custom nodes
|
187
198
|
|
188
|
-
You can create custom node in your response, based on the result of the given block
|
199
|
+
You can create custom node in your response, based on the result of the given block.
|
189
200
|
|
190
201
|
```ruby
|
191
202
|
object :@user
|
@@ -193,7 +204,7 @@ node(:full_name) { |u| u.first_name + " " + u.last_name }
|
|
193
204
|
# => { "user" : { "full_name" : "John Doe" } }
|
194
205
|
```
|
195
206
|
|
196
|
-
You can add
|
207
|
+
You can add condition on your custom nodes (if the condition is evaluated to false, the node will not be included).
|
197
208
|
|
198
209
|
```ruby
|
199
210
|
node(:email, if: -> { |u| u.valid_email? }) do |u|
|
@@ -207,6 +218,14 @@ Nodes are evaluated at the rendering time, so you can use any instance variables
|
|
207
218
|
node(:url) { |post| post_url(post) }
|
208
219
|
```
|
209
220
|
|
221
|
+
If you want to include directly the result into the current node, use the `merge` keyword (result returned from the block should be a hash)
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
object :@user
|
225
|
+
merge { |u| { name: u.first_name + " " + u.last_name } }
|
226
|
+
# => { "user" : { "name" : "John Doe" } }
|
227
|
+
```
|
228
|
+
|
210
229
|
Custom nodes are really usefull to create flexible representations of your resources.
|
211
230
|
|
212
231
|
### Extends & Partials
|
data/lib/rabl-rails/compiler.rb
CHANGED
@@ -5,7 +5,7 @@ module RablRails
|
|
5
5
|
#
|
6
6
|
class Compiler
|
7
7
|
def initialize
|
8
|
-
@i =
|
8
|
+
@i = -1
|
9
9
|
end
|
10
10
|
|
11
11
|
#
|
@@ -80,9 +80,7 @@ module RablRails
|
|
80
80
|
#
|
81
81
|
def glue(data)
|
82
82
|
return unless block_given?
|
83
|
-
|
84
|
-
@i += 1
|
85
|
-
@template[name] = sub_compile(data) { yield }
|
83
|
+
@template[sequence('glue')] = sub_compile(data) { yield }
|
86
84
|
end
|
87
85
|
|
88
86
|
#
|
@@ -93,7 +91,8 @@ module RablRails
|
|
93
91
|
# node(:name) { |user| user.first_name + user.last_name }
|
94
92
|
# node(:role, if: ->(u) { !u.admin? }) { |u| u.role }
|
95
93
|
#
|
96
|
-
def node(name, options = {}, &block)
|
94
|
+
def node(name = nil, options = {}, &block)
|
95
|
+
name ||= sequence('merge')
|
97
96
|
condition = options[:if]
|
98
97
|
|
99
98
|
if condition
|
@@ -108,6 +107,17 @@ module RablRails
|
|
108
107
|
end
|
109
108
|
alias_method :code, :node
|
110
109
|
|
110
|
+
#
|
111
|
+
# Merge arbitrary data into json output. Given block should
|
112
|
+
# return a hash.
|
113
|
+
# Example:
|
114
|
+
# merge { |item| partial("specific/#{item.to_s}", object: item) }
|
115
|
+
#
|
116
|
+
def merge(&block)
|
117
|
+
return unless block_given?
|
118
|
+
node(sequence('merge'), &block)
|
119
|
+
end
|
120
|
+
|
111
121
|
#
|
112
122
|
# Extends an existing rabl template
|
113
123
|
# Example:
|
@@ -127,13 +137,19 @@ module RablRails
|
|
127
137
|
#
|
128
138
|
def condition(proc)
|
129
139
|
return unless block_given?
|
130
|
-
|
131
|
-
@i += 1
|
132
|
-
@template[name] = Condition.new(proc, sub_compile(nil) { yield })
|
140
|
+
@template[sequence('if')] = Condition.new(proc, sub_compile(nil) { yield })
|
133
141
|
end
|
134
142
|
|
135
143
|
protected
|
136
144
|
|
145
|
+
#
|
146
|
+
# Return unique symbol starting with given name
|
147
|
+
#
|
148
|
+
def sequence(name)
|
149
|
+
@i += 1
|
150
|
+
:"_#{name}#{@i}"
|
151
|
+
end
|
152
|
+
|
137
153
|
#
|
138
154
|
# Extract data root_name and root name
|
139
155
|
# Example:
|
data/lib/rabl-rails/library.rb
CHANGED
@@ -14,21 +14,23 @@ module RablRails
|
|
14
14
|
|
15
15
|
compiled_template = compile_template_from_source(source, path)
|
16
16
|
|
17
|
-
format = context.params[:format]
|
18
|
-
|
17
|
+
format = context.params[:format] ? context.params[:format].to_s : 'json'
|
18
|
+
format.upcase!
|
19
|
+
Renderers.const_get(format).new(context, locals).render(compiled_template)
|
19
20
|
end
|
20
21
|
|
21
22
|
def compile_template_from_source(source, path = nil)
|
22
23
|
if path && RablRails.cache_templates?
|
23
24
|
@cached_templates[path] ||= Compiler.new.compile_source(source)
|
25
|
+
@cached_templates[path].dup
|
24
26
|
else
|
25
27
|
Compiler.new.compile_source(source)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
def compile_template_from_path(path)
|
30
|
-
|
31
|
-
|
32
|
+
return @cached_templates[path].dup if @cached_templates.has_key?(path)
|
33
|
+
|
32
34
|
t = @lookup_context.find_template(path, [], false)
|
33
35
|
compile_template_from_source(t.source, path)
|
34
36
|
end
|
data/lib/rabl-rails/renderer.rb
CHANGED
@@ -54,7 +54,15 @@ module RablRails
|
|
54
54
|
when Symbol
|
55
55
|
data.send(value) # attributes
|
56
56
|
when Proc
|
57
|
-
instance_exec data, &value
|
57
|
+
result = instance_exec data, &value
|
58
|
+
|
59
|
+
if key.to_s.start_with?('_') # merge
|
60
|
+
raise PartialError, '`merge` block should return a hash' unless result.is_a?(Hash)
|
61
|
+
output.merge!(result)
|
62
|
+
next output
|
63
|
+
else # node
|
64
|
+
result
|
65
|
+
end
|
58
66
|
when Array # node with condition
|
59
67
|
next output if !instance_exec data, &(value.first)
|
60
68
|
instance_exec data, &(value.last)
|
@@ -70,9 +78,7 @@ module RablRails
|
|
70
78
|
end
|
71
79
|
|
72
80
|
if key.to_s.start_with?('_') # glue
|
73
|
-
|
74
|
-
output[k] = object.send(v)
|
75
|
-
}
|
81
|
+
output.merge!(render_resource(object, current_value))
|
76
82
|
next output
|
77
83
|
else # child
|
78
84
|
object.respond_to?(:each) ? render_collection(object, current_value) : render_resource(object, current_value)
|
data/lib/rabl-rails/template.rb
CHANGED
data/lib/rabl-rails/version.rb
CHANGED
@@ -18,10 +18,11 @@ class CacheTemplatesTest < ActiveSupport::TestCase
|
|
18
18
|
|
19
19
|
test "cached templates should not be modifiable in place" do
|
20
20
|
ActionController::Base.stub(:perform_caching).and_return(true)
|
21
|
-
@library.compile_template_from_source('', 'some/path')
|
22
|
-
t = @library.compile_template_from_source("attribute :id", 'some/path')
|
21
|
+
t = @library.compile_template_from_source('', 'some/path')
|
23
22
|
|
24
|
-
|
23
|
+
t.merge!(:_data => :foo)
|
24
|
+
|
25
|
+
assert_equal({}, @library.compile_template_from_path('some/path').source)
|
25
26
|
end
|
26
27
|
|
27
28
|
test "don't cache templates cache_templates is enabled but perform_caching is not active" do
|
data/test/compiler_test.rb
CHANGED
@@ -112,7 +112,7 @@ class CompilerTest < ActiveSupport::TestCase
|
|
112
112
|
RablRails::Library.instance.stub(:compile_template_from_path).with('users/base').and_return(mock_template)
|
113
113
|
|
114
114
|
t = @compiler.compile_source(%{child(:user, :partial => 'users/base') })
|
115
|
-
assert_equal(
|
115
|
+
assert_equal({:user => { :_data => :user, :id => :id } }, t.source)
|
116
116
|
end
|
117
117
|
|
118
118
|
test "glue is compiled as a child but with anonymous name" do
|
@@ -132,6 +132,18 @@ class CompilerTest < ActiveSupport::TestCase
|
|
132
132
|
}, t.source)
|
133
133
|
end
|
134
134
|
|
135
|
+
test "glue accepts all dsl in its body" do
|
136
|
+
t = @compiler.compile_source(%{
|
137
|
+
glue :@user do node(:foo) { |u| u.name } end
|
138
|
+
})
|
139
|
+
|
140
|
+
assert_not_nil(t.source[:_glue0])
|
141
|
+
s = t.source[:_glue0]
|
142
|
+
|
143
|
+
assert_equal(:@user, s[:_data])
|
144
|
+
assert_instance_of(Proc, s[:foo])
|
145
|
+
end
|
146
|
+
|
135
147
|
test "extends use other template source as itself" do
|
136
148
|
template = mock('template', :source => { :id => :id })
|
137
149
|
RablRails::Library.reset_instance
|
@@ -153,6 +165,16 @@ class CompilerTest < ActiveSupport::TestCase
|
|
153
165
|
assert_equal 2, t.source[:foo].size
|
154
166
|
end
|
155
167
|
|
168
|
+
test "node can take no arguments and behave like a merge" do
|
169
|
+
t = @compiler.compile_source(%{ node do |m| m.foo end })
|
170
|
+
assert_instance_of Proc, t.source[:_merge0]
|
171
|
+
end
|
172
|
+
|
173
|
+
test "merge compile like a node but with a reserved keyword as name" do
|
174
|
+
t = @compiler.compile_source(%{ merge do |m| m.foo end })
|
175
|
+
assert_instance_of Proc, t.source[:_merge0]
|
176
|
+
end
|
177
|
+
|
156
178
|
test "conditionnal block compile nicely" do
|
157
179
|
t = @compiler.compile_source(%{ condition(->(u) {}) do attributes :secret end })
|
158
180
|
assert_instance_of RablRails::Condition, t.source[:_if0]
|
data/test/render_test.rb
CHANGED
@@ -60,4 +60,17 @@ class RenderTest < ActiveSupport::TestCase
|
|
60
60
|
assert_equal %q({"user":{"extended_name":"Marty"}}), RablRails.render(@user, 'extend', view_path: @tmp_path)
|
61
61
|
end
|
62
62
|
|
63
|
+
test "format can be passed as symbol or a string" do
|
64
|
+
File.open(@tmp_path + "show.json.rabl", "w") do |f|
|
65
|
+
f.puts %q{
|
66
|
+
object :@user
|
67
|
+
attributes :id, :name
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
assert_equal %q({"user":{"id":1,"name":"Marty"}}), RablRails.render(@user, 'show', view_path: @tmp_path, format: :json)
|
72
|
+
assert_equal %q({"user":{"id":1,"name":"Marty"}}), RablRails.render(@user, 'show', view_path: @tmp_path, format: 'json')
|
73
|
+
assert_equal %q({"user":{"id":1,"name":"Marty"}}), RablRails.render(@user, 'show', view_path: @tmp_path, format: 'JSON')
|
74
|
+
end
|
75
|
+
|
63
76
|
end
|
@@ -61,6 +61,11 @@ class TestJsonRenderer < ActiveSupport::TestCase
|
|
61
61
|
assert_equal %q({"name":"foobar"}), render_json_output
|
62
62
|
end
|
63
63
|
|
64
|
+
test "render glued node" do
|
65
|
+
@template.source = { :_glue0 => { :_data => :@data, :foo => lambda { |u| u.name } } }
|
66
|
+
assert_equal(%q({"foo":"foobar"}), render_json_output)
|
67
|
+
end
|
68
|
+
|
64
69
|
test "render collection with attributes" do
|
65
70
|
@data = [User.new(1, 'foo', 'male'), User.new(2, 'bar', 'female')]
|
66
71
|
@context.assigns['data'] = @data
|
@@ -152,4 +157,14 @@ class TestJsonRenderer < ActiveSupport::TestCase
|
|
152
157
|
@template.source = { :id => :id, :name => :name }
|
153
158
|
assert_equal %q({"id":1,"name":"foobar"}), render_json_output
|
154
159
|
end
|
160
|
+
|
161
|
+
test "merge should raise is return from given block is not a hash" do
|
162
|
+
@template.source = { :_merge0 => ->(c) { 'foo' } }
|
163
|
+
assert_raises(RablRails::Renderers::PartialError) { render_json_output }
|
164
|
+
end
|
165
|
+
|
166
|
+
test "result from merge is merge inside current response" do
|
167
|
+
@template.source = { :_merge0 => ->(c) { { :custom => c.name } } }
|
168
|
+
assert_equal %q({"custom":"foobar"}), render_json_output
|
169
|
+
end
|
155
170
|
end
|
data/test/test_helper.rb
CHANGED
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.3.
|
4
|
+
version: 0.3.1
|
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:
|
12
|
+
date: 2013-03-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -119,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
119
|
version: '0'
|
120
120
|
requirements: []
|
121
121
|
rubyforge_project:
|
122
|
-
rubygems_version: 1.8.
|
122
|
+
rubygems_version: 1.8.24
|
123
123
|
signing_key:
|
124
124
|
specification_version: 3
|
125
125
|
summary: Fast Rails 3+ templating system with JSON and XML support
|