jbuilder 2.0.7 → 2.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +8 -0
- data/README.md +5 -1
- data/jbuilder.gemspec +1 -1
- data/lib/jbuilder.rb +42 -86
- data/lib/jbuilder/dependency_tracker.rb +1 -1
- data/lib/jbuilder/errors.rb +10 -0
- data/lib/jbuilder/jbuilder.rb +7 -0
- data/lib/jbuilder/jbuilder_template.rb +41 -34
- data/lib/jbuilder/key_formatter.rb +34 -0
- data/lib/jbuilder/proxy.rb +7 -0
- data/test/jbuilder_template_test.rb +5 -15
- data/test/jbuilder_test.rb +204 -209
- metadata +6 -7
- data/gemfiles/rails_3_0.gemfile.lock +0 -66
- data/gemfiles/rails_3_1.gemfile.lock +0 -76
- data/gemfiles/rails_3_2.gemfile.lock +0 -75
- data/gemfiles/rails_4_0.gemfile.lock +0 -57
- data/gemfiles/rails_4_1.gemfile.lock +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6836a60ee9c7dd9709201026f7a6b472cc2019e
|
4
|
+
data.tar.gz: 4a8069c61889a929e3ffa10b3d46b799399202a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 774ae98b86547a5fd8261a3452e5ceb188924b9e84cf52d7c1f9c6e5f7ebfe6fb93816ef04b9f5f2aeb1f65d2136ed4d13b466957bd0cf65b3ead3a80515856f
|
7
|
+
data.tar.gz: 4aeb49c248572ceedfac7fab0bfc3d763607ead19be5dda7362d93e1bd87ddb0a1ea8b47f846747c61afb13b358c7ddc772e8d22542863ddbb948a0781fc61dd
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
2.0.8
|
4
|
+
-----
|
5
|
+
* [Eliminate circular dependencies](https://github.com/rails/jbuilder/commit/0879484dc74e7be93b695f66e3708ba48cdb1be3)
|
6
|
+
* [Support cache key generation for complex objects](https://github.com/rails/jbuilder/commit/ca9622cca30c1112dd4408fcb2e658849abe1dd5)
|
7
|
+
* [Remove JbuilderProxy class](https://github.com/rails/jbuilder/commit/5877482fc7da3224e42d4f72a1386f7a3a08173b)
|
8
|
+
* [Move KeyFormatter into a separate file](https://github.com/rails/jbuilder/commit/13fee8464ff53ce853030114283c03c135c052b6)
|
9
|
+
* [Move NullError into a separate file](https://github.com/rails/jbuilder/commit/13fee8464ff53ce853030114283c03c135c052b6)
|
10
|
+
|
3
11
|
2.0.7
|
4
12
|
-----
|
5
13
|
* [Add destroy notice to scaffold generator](https://github.com/rails/jbuilder/commit/8448e86f8cdfa0f517bd59576947875775a1d43c)
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Jbuilder
|
2
2
|
|
3
|
-
[![Build Status](
|
3
|
+
[![Build Status](https://api.travis-ci.org/rails/jbuilder.svg)][travis]
|
4
4
|
[![Gem Version](http://img.shields.io/gem/v/jbuilder.svg)][gem]
|
5
5
|
[![Code Climate](http://img.shields.io/codeclimate/github/rails/jbuilder.svg)][codeclimate]
|
6
6
|
[![Dependencies Status](http://img.shields.io/gemnasium/rails/jbuilder.svg)][gemnasium]
|
@@ -205,6 +205,10 @@ json.cache_if! !admin?, ['v1', @person], expires_in: 10.minutes do
|
|
205
205
|
end
|
206
206
|
```
|
207
207
|
|
208
|
+
If you are rendering fragments for a collection of objects, have a look at
|
209
|
+
`jbuilder_cache_multi` gem. It uses fetch_multi (>= Rails 4.1) to fetch
|
210
|
+
multiple keys at once.
|
211
|
+
|
208
212
|
Keys can be auto formatted using `key_format!`, this can be used to convert
|
209
213
|
keynames from the standard ruby_format to camelCase:
|
210
214
|
|
data/jbuilder.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'jbuilder'
|
3
|
-
s.version = '2.0.
|
3
|
+
s.version = '2.0.8'
|
4
4
|
s.authors = ['David Heinemeier Hansson', 'Pavel Pravosud']
|
5
5
|
s.email = ['david@37signals.com', 'pavel@pravosud.com']
|
6
6
|
s.summary = 'Create JSON structures via a Builder-style DSL'
|
data/lib/jbuilder.rb
CHANGED
@@ -1,58 +1,9 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require '
|
1
|
+
require 'jbuilder/jbuilder'
|
2
|
+
require 'jbuilder/key_formatter'
|
3
|
+
require 'jbuilder/errors'
|
4
4
|
require 'multi_json'
|
5
5
|
|
6
|
-
|
7
|
-
require 'active_support/proxy_object'
|
8
|
-
JbuilderProxy = ActiveSupport::ProxyObject
|
9
|
-
rescue LoadError
|
10
|
-
require 'active_support/basic_object'
|
11
|
-
JbuilderProxy = ActiveSupport::BasicObject
|
12
|
-
end
|
13
|
-
|
14
|
-
class Jbuilder < JbuilderProxy
|
15
|
-
class NullError < ::NoMethodError
|
16
|
-
def initialize(key)
|
17
|
-
super "Failed to add #{key.to_s.inspect} property to null object"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class KeyFormatter
|
22
|
-
def initialize(*args)
|
23
|
-
@format = {}
|
24
|
-
@cache = {}
|
25
|
-
|
26
|
-
options = args.extract_options!
|
27
|
-
args.each do |name|
|
28
|
-
@format[name] = []
|
29
|
-
end
|
30
|
-
options.each do |name, paramaters|
|
31
|
-
@format[name] = paramaters
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def initialize_copy(original)
|
36
|
-
@cache = {}
|
37
|
-
end
|
38
|
-
|
39
|
-
def format(key)
|
40
|
-
@cache[key] ||= @format.inject(key.to_s) do |result, args|
|
41
|
-
func, args = args
|
42
|
-
if ::Proc === func
|
43
|
-
func.call result, *args
|
44
|
-
else
|
45
|
-
result.send func, *args
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Yields a builder and automatically turns the result into a JSON string
|
52
|
-
def self.encode(*args, &block)
|
53
|
-
new(*args, &block).target!
|
54
|
-
end
|
55
|
-
|
6
|
+
class Jbuilder
|
56
7
|
@@key_formatter = KeyFormatter.new
|
57
8
|
@@ignore_nil = false
|
58
9
|
|
@@ -61,13 +12,18 @@ class Jbuilder < JbuilderProxy
|
|
61
12
|
|
62
13
|
@key_formatter = options.fetch(:key_formatter){ @@key_formatter.clone }
|
63
14
|
@ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
|
15
|
+
|
64
16
|
yield self if block
|
65
17
|
end
|
66
18
|
|
19
|
+
# Yields a builder and automatically turns the result into a JSON string
|
20
|
+
def self.encode(*args, &block)
|
21
|
+
new(*args, &block).target!
|
22
|
+
end
|
23
|
+
|
67
24
|
BLANK = ::Object.new
|
68
25
|
|
69
26
|
def set!(key, value = BLANK, *args, &block)
|
70
|
-
|
71
27
|
result = if block
|
72
28
|
if BLANK != value
|
73
29
|
# json.comments @post.comments { |comment| ... }
|
@@ -76,7 +32,7 @@ class Jbuilder < JbuilderProxy
|
|
76
32
|
else
|
77
33
|
# json.comments { ... }
|
78
34
|
# { "comments": ... }
|
79
|
-
_scope
|
35
|
+
_scope{ yield self }
|
80
36
|
end
|
81
37
|
elsif args.empty?
|
82
38
|
if ::Jbuilder === value
|
@@ -96,7 +52,7 @@ class Jbuilder < JbuilderProxy
|
|
96
52
|
else
|
97
53
|
# json.author @post.creator, :name, :email_address
|
98
54
|
# { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
|
99
|
-
_scope
|
55
|
+
_scope{ extract! value, *args }
|
100
56
|
end
|
101
57
|
|
102
58
|
_set_value key, result
|
@@ -105,7 +61,6 @@ class Jbuilder < JbuilderProxy
|
|
105
61
|
alias_method :method_missing, :set!
|
106
62
|
private :method_missing
|
107
63
|
|
108
|
-
|
109
64
|
# Specifies formatting to be applied to the key. Passing in a name of a function
|
110
65
|
# will cause that function to be called on the key. So :upcase will upper case
|
111
66
|
# the key. You can also pass in lambdas for more complex transformations.
|
@@ -185,7 +140,7 @@ class Jbuilder < JbuilderProxy
|
|
185
140
|
# end
|
186
141
|
def child!
|
187
142
|
@attributes = [] unless ::Array === @attributes
|
188
|
-
@attributes << _scope
|
143
|
+
@attributes << _scope{ yield self }
|
189
144
|
end
|
190
145
|
|
191
146
|
# Turns the current element into an array and iterates over the passed collection, adding each iteration as
|
@@ -290,41 +245,42 @@ class Jbuilder < JbuilderProxy
|
|
290
245
|
|
291
246
|
private
|
292
247
|
|
293
|
-
|
294
|
-
|
295
|
-
|
248
|
+
def _extract_hash_values(object, *attributes)
|
249
|
+
attributes.each{ |key| _set_value key, object.fetch(key) }
|
250
|
+
end
|
296
251
|
|
297
|
-
|
298
|
-
|
299
|
-
|
252
|
+
def _extract_method_values(object, *attributes)
|
253
|
+
attributes.each{ |key| _set_value key, object.public_send(key) }
|
254
|
+
end
|
300
255
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
@attributes[@key_formatter.format(key)] = value
|
305
|
-
end
|
306
|
-
end
|
256
|
+
def _set_value(key, value)
|
257
|
+
raise NullError.build(key) if @attributes.nil?
|
258
|
+
return if @ignore_nil && value.nil?
|
307
259
|
|
308
|
-
|
309
|
-
|
260
|
+
key = @key_formatter.format(key)
|
261
|
+
@attributes[key] = value
|
262
|
+
end
|
310
263
|
|
311
|
-
|
312
|
-
|
313
|
-
end
|
314
|
-
end
|
264
|
+
def _map_collection(collection)
|
265
|
+
return [] if collection.nil?
|
315
266
|
|
316
|
-
|
317
|
-
|
318
|
-
@attributes = {}
|
319
|
-
yield
|
320
|
-
@attributes
|
321
|
-
ensure
|
322
|
-
@attributes, @key_formatter = parent_attributes, parent_formatter
|
267
|
+
collection.map do |element|
|
268
|
+
_scope{ yield element }
|
323
269
|
end
|
270
|
+
end
|
324
271
|
|
325
|
-
|
326
|
-
|
327
|
-
|
272
|
+
def _scope
|
273
|
+
parent_attributes, parent_formatter = @attributes, @key_formatter
|
274
|
+
@attributes = {}
|
275
|
+
yield
|
276
|
+
@attributes
|
277
|
+
ensure
|
278
|
+
@attributes, @key_formatter = parent_attributes, parent_formatter
|
279
|
+
end
|
280
|
+
|
281
|
+
def _mapable_arguments?(value, *args)
|
282
|
+
value.respond_to?(:map)
|
283
|
+
end
|
328
284
|
end
|
329
285
|
|
330
286
|
require 'jbuilder/jbuilder_template' if defined?(ActionView::Template)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'jbuilder'
|
1
|
+
require 'jbuilder/jbuilder'
|
2
2
|
require 'action_dispatch/http/mime_type'
|
3
3
|
require 'active_support/cache'
|
4
4
|
|
@@ -74,48 +74,55 @@ class JbuilderTemplate < Jbuilder
|
|
74
74
|
end
|
75
75
|
|
76
76
|
protected
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
else
|
77
|
+
|
78
|
+
def _handle_partial_options(options)
|
79
|
+
options.reverse_merge! locals: {}
|
80
|
+
options.reverse_merge! ::JbuilderTemplate.template_lookup_options
|
81
|
+
as = options[:as]
|
82
|
+
|
83
|
+
if as && options.key?(:collection)
|
84
|
+
collection = options.delete(:collection) || []
|
85
|
+
array!(collection) do |member|
|
86
|
+
options[:locals].merge! as => member
|
87
|
+
options[:locals].merge! collection: collection
|
90
88
|
_render_partial options
|
91
89
|
end
|
90
|
+
else
|
91
|
+
_render_partial options
|
92
92
|
end
|
93
|
+
end
|
93
94
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
def _render_partial(options)
|
96
|
+
options[:locals].merge! json: self
|
97
|
+
@context.render options
|
98
|
+
end
|
98
99
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
elsif @context.respond_to?(:fragment_name_with_digest)
|
105
|
-
# Backwards compatibility for period of time when fragment_name_with_digest was made public.
|
106
|
-
@context.fragment_name_with_digest(key)
|
107
|
-
else
|
108
|
-
::ActiveSupport::Cache.expand_cache_key(key.is_a?(::Hash) ? url_for(key).split('://').last : key, :jbuilder)
|
109
|
-
end
|
110
|
-
end
|
100
|
+
def _cache_key(key, options)
|
101
|
+
key = _fragment_name_with_digest(key, options)
|
102
|
+
key = url_for(key).split('://', 2).last if ::Hash === key
|
103
|
+
::ActiveSupport::Cache.expand_cache_key(key, :jbuilder)
|
104
|
+
end
|
111
105
|
|
112
106
|
private
|
113
107
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
108
|
+
def _fragment_name_with_digest(key, options)
|
109
|
+
if @context.respond_to?(:cache_fragment_name)
|
110
|
+
# Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
|
111
|
+
# should be used instead.
|
112
|
+
@context.cache_fragment_name(key, options)
|
113
|
+
elsif @context.respond_to?(:fragment_name_with_digest)
|
114
|
+
# Backwards compatibility for period of time when fragment_name_with_digest was made public.
|
115
|
+
@context.fragment_name_with_digest(key)
|
116
|
+
else
|
117
|
+
key
|
118
118
|
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def _mapable_arguments?(value, *args)
|
122
|
+
return true if super
|
123
|
+
options = args.last
|
124
|
+
::Hash === options && options.key?(:as)
|
125
|
+
end
|
119
126
|
end
|
120
127
|
|
121
128
|
class JbuilderHandler
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'jbuilder/jbuilder'
|
2
|
+
require 'active_support/core_ext/array'
|
3
|
+
|
4
|
+
class Jbuilder
|
5
|
+
class KeyFormatter
|
6
|
+
def initialize(*args)
|
7
|
+
@format = {}
|
8
|
+
@cache = {}
|
9
|
+
|
10
|
+
options = args.extract_options!
|
11
|
+
args.each do |name|
|
12
|
+
@format[name] = []
|
13
|
+
end
|
14
|
+
options.each do |name, paramaters|
|
15
|
+
@format[name] = paramaters
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize_copy(original)
|
20
|
+
@cache = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def format(key)
|
24
|
+
@cache[key] ||= @format.inject(key.to_s) do |result, args|
|
25
|
+
func, args = args
|
26
|
+
if ::Proc === func
|
27
|
+
func.call result, *args
|
28
|
+
else
|
29
|
+
result.send func, *args
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -216,18 +216,18 @@ class JbuilderTemplateTest < ActionView::TestCase
|
|
216
216
|
|
217
217
|
render_jbuilder <<-JBUILDER
|
218
218
|
json.cache! 'cachekey' do
|
219
|
-
json.array! %w
|
219
|
+
json.array! %w[a b c]
|
220
220
|
end
|
221
221
|
JBUILDER
|
222
222
|
|
223
223
|
json = render_jbuilder <<-JBUILDER
|
224
224
|
json.cache! 'cachekey' do
|
225
|
-
json.array! %w
|
225
|
+
json.array! %w[1 2 3]
|
226
226
|
end
|
227
227
|
JBUILDER
|
228
228
|
|
229
229
|
parsed = MultiJson.load(json)
|
230
|
-
assert_equal %w
|
230
|
+
assert_equal %w[a b c], parsed
|
231
231
|
end
|
232
232
|
|
233
233
|
test 'fragment caching works with previous version of cache digests' do
|
@@ -246,6 +246,7 @@ class JbuilderTemplateTest < ActionView::TestCase
|
|
246
246
|
undef_context_methods :fragment_name_with_digest
|
247
247
|
|
248
248
|
@context.expects :cache_fragment_name
|
249
|
+
ActiveSupport::Cache.expects :expand_cache_key
|
249
250
|
|
250
251
|
render_jbuilder <<-JBUILDER
|
251
252
|
json.cache! 'cachekey' do
|
@@ -258,6 +259,7 @@ class JbuilderTemplateTest < ActionView::TestCase
|
|
258
259
|
undef_context_methods :fragment_name_with_digest
|
259
260
|
|
260
261
|
@context.expects(:cache_fragment_name).with('cachekey', skip_digest: true)
|
262
|
+
ActiveSupport::Cache.expects :expand_cache_key
|
261
263
|
|
262
264
|
render_jbuilder <<-JBUILDER
|
263
265
|
json.cache! 'cachekey', skip_digest: true do
|
@@ -277,16 +279,4 @@ class JbuilderTemplateTest < ActionView::TestCase
|
|
277
279
|
assert_equal Rails.cache.inspect[/entries=(\d+)/, 1], '0'
|
278
280
|
end
|
279
281
|
|
280
|
-
test 'fragment caching falls back on ActiveSupport::Cache.expand_cache_key' do
|
281
|
-
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
|
282
|
-
|
283
|
-
ActiveSupport::Cache.expects :expand_cache_key
|
284
|
-
|
285
|
-
render_jbuilder <<-JBUILDER
|
286
|
-
json.cache! 'cachekey' do
|
287
|
-
json.name 'Cache'
|
288
|
-
end
|
289
|
-
JBUILDER
|
290
|
-
end
|
291
|
-
|
292
282
|
end
|