jbuilder 1.4.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.travis.yml +8 -3
- data/Gemfile.edge +3 -6
- data/README.md +23 -5
- data/jbuilder.gemspec +1 -1
- data/lib/jbuilder.rb +18 -2
- data/lib/jbuilder/jbuilder_template.rb +50 -12
- data/test/jbuilder_template_test.rb +63 -1
- data/test/jbuilder_test.rb +24 -5
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NGYyYTk2NWM1ZjkxN2Q1YWYxNmM1MWI2YWZhZWFlODY4YWJiNjZjYw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZGM3Mjg1NGYxODFjNGU4NGYwZWRkYmNkNTZmMjJjMmFjMzk3NTUxZA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OGFkMmYzYWM0MjQ5OWM5ZmU4ZjU1ODBhZmVkMzQ3ZjRjNjg0YmE2N2VmY2Rm
|
10
|
+
M2YyNDIwY2FlZTNhMzBmNDk4MDljNGMxNWVkNzMwYTMyOTRiYTEwYzE2Mjc4
|
11
|
+
NjE0ODZlZTU2MjczZjgxMDg5ZTVmZmIxZWQ0OGQ1NTI5M2FhNmQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ODc3OGEwYTkxMGFlNTdhODdmOGEzYWM1YzZiYTEyOTk5MjFmZjM4M2I5ZTU1
|
14
|
+
ZTU4Y2ViYTFhMTA1NzFmZGFlMTc5OTljYTk1OTA2MTk0MDVmOTVhZGYyMzZl
|
15
|
+
Y2Y1ZTlmOWU0OTQ2NTY1MmY1ODQ2YmY2YjdiYTEwYTA2NTYwYmE=
|
data/.travis.yml
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
language: ruby
|
2
|
-
|
3
|
-
- gem install bundler
|
2
|
+
|
4
3
|
rvm:
|
5
4
|
- 1.8.7
|
6
5
|
- 1.9.2
|
@@ -12,12 +11,14 @@ rvm:
|
|
12
11
|
- jruby-19mode
|
13
12
|
- rbx-18mode
|
14
13
|
- rbx-19mode
|
14
|
+
|
15
15
|
gemfile:
|
16
16
|
- Gemfile
|
17
17
|
- Gemfile.edge
|
18
|
+
|
18
19
|
matrix:
|
19
20
|
exclude:
|
20
|
-
# Edge Rails is only compatible with 1.9.3
|
21
|
+
# Edge Rails is only compatible with 1.9.3+
|
21
22
|
- gemfile: Gemfile.edge
|
22
23
|
rvm: 1.8.7
|
23
24
|
- gemfile: Gemfile.edge
|
@@ -28,6 +29,10 @@ matrix:
|
|
28
29
|
rvm: jruby-18mode
|
29
30
|
- gemfile: Gemfile.edge
|
30
31
|
rvm: rbx-18mode
|
32
|
+
allow_failures:
|
33
|
+
- rvm: ruby-head
|
34
|
+
- rvm: rbx-18mode
|
35
|
+
- rvm: rbx-19mode
|
31
36
|
|
32
37
|
notifications:
|
33
38
|
email: false
|
data/Gemfile.edge
CHANGED
@@ -3,9 +3,6 @@ source 'https://rubygems.org'
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
gem 'rake'
|
6
|
-
gem '
|
7
|
-
|
8
|
-
|
9
|
-
gem 'railties', require: 'rails/railtie'
|
10
|
-
gem 'actionpack'
|
11
|
-
end
|
6
|
+
gem 'railties', '~> 4.0.0'
|
7
|
+
gem 'actionpack', '~> 4.0.0'
|
8
|
+
gem 'mocha', require: false
|
data/README.md
CHANGED
@@ -131,12 +131,30 @@ end
|
|
131
131
|
if current_user.admin?
|
132
132
|
json.visitors calculate_visitors(@message)
|
133
133
|
end
|
134
|
+
```
|
135
|
+
|
136
|
+
|
137
|
+
You can use partials as well. The following will render the file
|
138
|
+
`views/comments/_comments.json.jbuilder`, and set a local variable
|
139
|
+
`comments` with all this message's comments, which you can use inside
|
140
|
+
the partial.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
json.partial! 'comments/comments', comments: @message.comments
|
144
|
+
```
|
145
|
+
|
146
|
+
It's also possible to render collections of partials:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
json.array! @posts, partial: 'posts/post', as: :post
|
150
|
+
|
151
|
+
# or
|
152
|
+
|
153
|
+
json.partial! 'posts/post', collection: @posts, as: :post
|
154
|
+
|
155
|
+
# or
|
134
156
|
|
135
|
-
|
136
|
-
# RAILS_ROOT/app/views/api/comments/_comments.json.jbuilder, and set a local variable
|
137
|
-
# 'comments' with all this message's comments, which you can use inside
|
138
|
-
# the partial.
|
139
|
-
json.partial! 'api/comments/comments', comments: @message.comments
|
157
|
+
json.partial! partial: 'posts/post', collection: @posts, as: :post
|
140
158
|
```
|
141
159
|
|
142
160
|
You can explicitly make Jbuilder object return null if you want:
|
data/jbuilder.gemspec
CHANGED
data/lib/jbuilder.rb
CHANGED
@@ -252,9 +252,9 @@ class Jbuilder < JbuilderProxy
|
|
252
252
|
# json.(@person, :name, :age)
|
253
253
|
def extract!(object, *attributes)
|
254
254
|
if ::Hash === object
|
255
|
-
|
255
|
+
_extract_hash_values(object, *attributes)
|
256
256
|
else
|
257
|
-
|
257
|
+
_extract_method_values(object, *attributes)
|
258
258
|
end
|
259
259
|
end
|
260
260
|
|
@@ -285,6 +285,22 @@ class Jbuilder < JbuilderProxy
|
|
285
285
|
|
286
286
|
private
|
287
287
|
|
288
|
+
def _extract_hash_values(object, *attributes)
|
289
|
+
attributes.each{ |key| _set_value key, object.fetch(key) }
|
290
|
+
end
|
291
|
+
|
292
|
+
def _extract_method_values(object, *attributes)
|
293
|
+
attributes.each do |method_name|
|
294
|
+
unless object.respond_to?(method_name)
|
295
|
+
message = "Private method #{method_name.inspect} was used to " +
|
296
|
+
'extract value. This will be an error in future versions of Jbuilder'
|
297
|
+
end
|
298
|
+
|
299
|
+
_set_value method_name, object.send(method_name)
|
300
|
+
::ActiveSupport::Deprecation.warn message if message
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
288
304
|
def _set_value(key, value)
|
289
305
|
raise NullError, key if @attributes.nil?
|
290
306
|
unless @ignore_nil && value.nil?
|
@@ -6,14 +6,29 @@ class JbuilderTemplate < Jbuilder
|
|
6
6
|
super(*args, &block)
|
7
7
|
end
|
8
8
|
|
9
|
-
def partial!(
|
10
|
-
case
|
9
|
+
def partial!(name_or_options, locals = {})
|
10
|
+
case name_or_options
|
11
11
|
when ::Hash
|
12
|
-
|
13
|
-
options
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
# partial! partial: 'name', locals: { foo: 'bar' }
|
13
|
+
options = name_or_options
|
14
|
+
else
|
15
|
+
# partial! 'name', foo: 'bar'
|
16
|
+
options = { :partial => name_or_options, :locals => locals }
|
17
|
+
as = locals.delete(:as)
|
18
|
+
options[:as] = as if as.present?
|
19
|
+
options[:collection] = locals[:collection]
|
20
|
+
end
|
21
|
+
|
22
|
+
_handle_partial_options options
|
23
|
+
end
|
24
|
+
|
25
|
+
def array!(collection, *attributes, &block)
|
26
|
+
options = attributes.extract_options!
|
27
|
+
|
28
|
+
if options.key?(:partial)
|
29
|
+
partial! options[:partial], options.merge(:collection => collection)
|
30
|
+
else
|
31
|
+
super
|
17
32
|
end
|
18
33
|
end
|
19
34
|
|
@@ -26,15 +41,38 @@ class JbuilderTemplate < Jbuilder
|
|
26
41
|
# json.extract! @person, :name, :age
|
27
42
|
# end
|
28
43
|
def cache!(key=nil, options={}, &block)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
44
|
+
if @context.controller.perform_caching
|
45
|
+
value = ::Rails.cache.fetch(_cache_key(key), options) do
|
46
|
+
_scope { yield self }
|
47
|
+
end
|
33
48
|
|
34
|
-
|
49
|
+
_merge(value)
|
50
|
+
else
|
51
|
+
yield
|
52
|
+
end
|
35
53
|
end
|
36
54
|
|
37
55
|
protected
|
56
|
+
def _handle_partial_options(options)
|
57
|
+
options.reverse_merge!(:locals => {}, :handlers => [:jbuilder])
|
58
|
+
collection = options.delete(:collection)
|
59
|
+
as = options[:as]
|
60
|
+
|
61
|
+
if collection && as
|
62
|
+
array!(collection) do |member|
|
63
|
+
options[:locals].merge!(as => member, :collection => collection)
|
64
|
+
_render_partial options
|
65
|
+
end
|
66
|
+
else
|
67
|
+
_render_partial options
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def _render_partial(options)
|
72
|
+
options[:locals].merge!(:json => self)
|
73
|
+
@context.render options
|
74
|
+
end
|
75
|
+
|
38
76
|
def _cache_key(key)
|
39
77
|
if @context.respond_to?(:cache_fragment_name)
|
40
78
|
# Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
|
@@ -5,6 +5,20 @@ require 'action_view/testing/resolvers'
|
|
5
5
|
require 'active_support/cache'
|
6
6
|
require 'jbuilder'
|
7
7
|
|
8
|
+
|
9
|
+
BLOG_POST_PARTIAL = <<-JBUILDER
|
10
|
+
json.extract! blog_post, :id, :body
|
11
|
+
json.author do
|
12
|
+
name = blog_post.author_name.split(nil, 2)
|
13
|
+
json.first_name name[0]
|
14
|
+
json.last_name name[1]
|
15
|
+
end
|
16
|
+
JBUILDER
|
17
|
+
|
18
|
+
BlogPost = Struct.new(:id, :body, :author_name)
|
19
|
+
blog_authors = [ 'David Heinemeier Hansson', 'Pavel Pravosud' ].cycle
|
20
|
+
BLOG_POST_COLLECTION = 10.times.map{ |i| BlogPost.new(i+1, "post body #{i+1}", blog_authors.next) }
|
21
|
+
|
8
22
|
module Rails
|
9
23
|
def self.cache
|
10
24
|
@cache ||= ActiveSupport::Cache::MemoryStore.new
|
@@ -18,7 +32,10 @@ class JbuilderTemplateTest < ActionView::TestCase
|
|
18
32
|
end
|
19
33
|
|
20
34
|
def partials
|
21
|
-
{
|
35
|
+
{
|
36
|
+
'_partial.json.jbuilder' => 'json.content "hello"',
|
37
|
+
'_blog_post.json.jbuilder' => BLOG_POST_PARTIAL
|
38
|
+
}
|
22
39
|
end
|
23
40
|
|
24
41
|
def render_jbuilder(source)
|
@@ -35,6 +52,16 @@ class JbuilderTemplateTest < ActionView::TestCase
|
|
35
52
|
end
|
36
53
|
end
|
37
54
|
|
55
|
+
def assert_collection_rendered(json)
|
56
|
+
result = MultiJson.load(json)
|
57
|
+
|
58
|
+
assert_equal 10, result.length
|
59
|
+
assert_equal Array, result.class
|
60
|
+
assert_equal 'post body 5', result[4]['body']
|
61
|
+
assert_equal 'Heinemeier Hansson', result[2]['author']['last_name']
|
62
|
+
assert_equal 'Pavel', result[5]['author']['first_name']
|
63
|
+
end
|
64
|
+
|
38
65
|
test 'rendering' do
|
39
66
|
json = render_jbuilder <<-JBUILDER
|
40
67
|
json.content 'hello'
|
@@ -74,6 +101,30 @@ class JbuilderTemplateTest < ActionView::TestCase
|
|
74
101
|
assert_equal 'hello', MultiJson.load(json)['content']
|
75
102
|
end
|
76
103
|
|
104
|
+
test 'partial! renders collections' do
|
105
|
+
json = render_jbuilder <<-JBUILDER
|
106
|
+
json.partial! 'blog_post', :collection => BLOG_POST_COLLECTION, :as => :blog_post
|
107
|
+
JBUILDER
|
108
|
+
|
109
|
+
assert_collection_rendered json
|
110
|
+
end
|
111
|
+
|
112
|
+
test 'partial! renders collection (alt. syntax)' do
|
113
|
+
json = render_jbuilder <<-JBUILDER
|
114
|
+
json.partial! :partial => 'blog_post', :collection => BLOG_POST_COLLECTION, :as => :blog_post
|
115
|
+
JBUILDER
|
116
|
+
|
117
|
+
assert_collection_rendered json
|
118
|
+
end
|
119
|
+
|
120
|
+
test 'render array of partials' do
|
121
|
+
json = render_jbuilder <<-JBUILDER
|
122
|
+
json.array! BLOG_POST_COLLECTION, :partial => 'blog_post', :as => :blog_post
|
123
|
+
JBUILDER
|
124
|
+
|
125
|
+
assert_collection_rendered json
|
126
|
+
end
|
127
|
+
|
77
128
|
test 'fragment caching a JSON object' do
|
78
129
|
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
|
79
130
|
|
@@ -136,6 +187,17 @@ class JbuilderTemplateTest < ActionView::TestCase
|
|
136
187
|
JBUILDER
|
137
188
|
end
|
138
189
|
|
190
|
+
test 'does not perform caching when controller.perform_caching is false' do
|
191
|
+
controller.perform_caching = false
|
192
|
+
render_jbuilder <<-JBUILDER
|
193
|
+
json.cache! 'cachekey' do
|
194
|
+
json.name 'Cache'
|
195
|
+
end
|
196
|
+
JBUILDER
|
197
|
+
|
198
|
+
assert_equal Rails.cache.inspect[/entries=(\d+)/, 1], '0'
|
199
|
+
end
|
200
|
+
|
139
201
|
test 'fragment caching falls back on ActiveSupport::Cache.expand_cache_key' do
|
140
202
|
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
|
141
203
|
|
data/test/jbuilder_test.rb
CHANGED
@@ -5,12 +5,14 @@ require 'jbuilder'
|
|
5
5
|
|
6
6
|
Comment = Struct.new(:content, :id)
|
7
7
|
|
8
|
-
|
9
|
-
# Faking Object#instance_eval for 1.8
|
10
|
-
|
11
|
-
|
8
|
+
unless JbuilderProxy.method_defined? :instance_eval
|
9
|
+
# Faking Object#instance_eval for 1.8 and some newer JRubies
|
10
|
+
class JbuilderProxy
|
11
|
+
def instance_eval(code)
|
12
|
+
eval code
|
13
|
+
end
|
12
14
|
end
|
13
|
-
end
|
15
|
+
end
|
14
16
|
|
15
17
|
class NonEnumerable
|
16
18
|
def initialize(collection)
|
@@ -71,6 +73,23 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
71
73
|
assert_equal 32, parsed['age']
|
72
74
|
end
|
73
75
|
|
76
|
+
test 'extracting from object using private method' do
|
77
|
+
person = Struct.new(:name) do
|
78
|
+
private
|
79
|
+
def age
|
80
|
+
32
|
81
|
+
end
|
82
|
+
end.new('David')
|
83
|
+
|
84
|
+
message = 'Private method :age was used to extract value. This will be' +
|
85
|
+
' an error in future versions of Jbuilder'
|
86
|
+
|
87
|
+
::ActiveSupport::Deprecation.expects(:warn).with(message)
|
88
|
+
json = Jbuilder.encode do |json|
|
89
|
+
json.extract! person, :name, :age
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
74
93
|
test 'extracting from object using call style for 1.9' do
|
75
94
|
person = Struct.new(:name, :age).new('David', 32)
|
76
95
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jbuilder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
- - ! '>='
|
17
17
|
- !ruby/object:Gem::Version
|
18
18
|
version: 3.0.0
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
name: activesupport
|
19
22
|
version_requirements: !ruby/object:Gem::Requirement
|
20
23
|
requirements:
|
21
24
|
- - ! '>='
|
22
25
|
- !ruby/object:Gem::Version
|
23
26
|
version: 3.0.0
|
24
|
-
type: :runtime
|
25
|
-
prerelease: false
|
26
|
-
name: activesupport
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 1.2.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
name: multi_json
|
33
36
|
version_requirements: !ruby/object:Gem::Requirement
|
34
37
|
requirements:
|
35
38
|
- - ! '>='
|
36
39
|
- !ruby/object:Gem::Version
|
37
40
|
version: 1.2.0
|
38
|
-
type: :runtime
|
39
|
-
prerelease: false
|
40
|
-
name: multi_json
|
41
41
|
description:
|
42
42
|
email: david@37signals.com
|
43
43
|
executables: []
|
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
84
|
version: '0'
|
85
85
|
requirements: []
|
86
86
|
rubyforge_project:
|
87
|
-
rubygems_version: 2.0.
|
87
|
+
rubygems_version: 2.0.6
|
88
88
|
signing_key:
|
89
89
|
specification_version: 4
|
90
90
|
summary: Create JSON structures via a Builder-style DSL
|