jbuilder 0.4.3 → 0.5.0
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/Gemfile +3 -1
- data/Gemfile.lock +33 -3
- data/jbuilder.gemspec +1 -1
- data/lib/jbuilder.rb +102 -87
- data/lib/jbuilder_template.rb +3 -3
- data/test/jbuilder_template_test.rb +39 -0
- data/test/jbuilder_test.rb +22 -2
- metadata +18 -8
- data/jbuilder-0.4.2.gem +0 -0
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,20 +1,50 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
jbuilder (0.
|
4
|
+
jbuilder (0.4.1)
|
5
5
|
activesupport (>= 3.0.0)
|
6
6
|
blankslate (>= 2.1.2.4)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: http://rubygems.org/
|
10
10
|
specs:
|
11
|
-
|
11
|
+
actionpack (3.2.8)
|
12
|
+
activemodel (= 3.2.8)
|
13
|
+
activesupport (= 3.2.8)
|
14
|
+
builder (~> 3.0.0)
|
15
|
+
erubis (~> 2.7.0)
|
16
|
+
journey (~> 1.0.4)
|
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.8)
|
22
|
+
activesupport (= 3.2.8)
|
23
|
+
builder (~> 3.0.0)
|
24
|
+
activesupport (3.2.8)
|
25
|
+
i18n (~> 0.6)
|
12
26
|
multi_json (~> 1.0)
|
13
27
|
blankslate (2.1.2.4)
|
14
|
-
|
28
|
+
builder (3.0.0)
|
29
|
+
erubis (2.7.0)
|
30
|
+
hike (1.2.1)
|
31
|
+
i18n (0.6.1)
|
32
|
+
journey (1.0.4)
|
33
|
+
multi_json (1.3.6)
|
34
|
+
rack (1.4.1)
|
35
|
+
rack-cache (1.2)
|
36
|
+
rack (>= 0.4)
|
37
|
+
rack-test (0.6.1)
|
38
|
+
rack (>= 1.0)
|
39
|
+
sprockets (2.1.3)
|
40
|
+
hike (~> 1.2)
|
41
|
+
rack (~> 1.0)
|
42
|
+
tilt (~> 1.1, != 1.3.0)
|
43
|
+
tilt (1.3.3)
|
15
44
|
|
16
45
|
PLATFORMS
|
17
46
|
ruby
|
18
47
|
|
19
48
|
DEPENDENCIES
|
49
|
+
actionpack
|
20
50
|
jbuilder!
|
data/jbuilder.gemspec
CHANGED
data/lib/jbuilder.rb
CHANGED
@@ -5,21 +5,50 @@ require 'active_support/core_ext/enumerable'
|
|
5
5
|
require 'active_support/json'
|
6
6
|
require 'multi_json'
|
7
7
|
class Jbuilder < BlankSlate
|
8
|
+
class KeyFormatter
|
9
|
+
def initialize(*args)
|
10
|
+
@format = {}
|
11
|
+
@cache = {}
|
12
|
+
|
13
|
+
options = args.extract_options!
|
14
|
+
args.each do |name|
|
15
|
+
@format[name] = []
|
16
|
+
end
|
17
|
+
options.each do |name, paramaters|
|
18
|
+
@format[name] = paramaters
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize_copy(original)
|
23
|
+
@cache = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def format(key)
|
27
|
+
@cache[key] ||= @format.inject(key.to_s) do |result, args|
|
28
|
+
func, args = args
|
29
|
+
if func.is_a? Proc
|
30
|
+
func.call(result, *args)
|
31
|
+
else
|
32
|
+
result.send(func, *args)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
8
38
|
# Yields a builder and automatically turns the result into a JSON string
|
9
39
|
def self.encode
|
10
40
|
new._tap { |jbuilder| yield jbuilder }.target!
|
11
41
|
end
|
12
42
|
|
13
|
-
@@
|
43
|
+
@@key_formatter = KeyFormatter.new
|
14
44
|
|
15
45
|
define_method(:__class__, find_hidden_method(:class))
|
16
46
|
define_method(:_tap, find_hidden_method(:tap))
|
17
|
-
define_method(:_is_a?, find_hidden_method(:is_a?))
|
18
47
|
reveal(:respond_to?)
|
19
48
|
|
20
|
-
def initialize(
|
49
|
+
def initialize(key_formatter = @@key_formatter.clone)
|
21
50
|
@attributes = ActiveSupport::OrderedHash.new
|
22
|
-
@
|
51
|
+
@key_formatter = key_formatter
|
23
52
|
end
|
24
53
|
|
25
54
|
# Dynamically set a key value pair.
|
@@ -42,7 +71,7 @@ class Jbuilder < BlankSlate
|
|
42
71
|
if block_given?
|
43
72
|
_yield_nesting(key) { |jbuilder| yield jbuilder }
|
44
73
|
else
|
45
|
-
|
74
|
+
_set_value(key, value)
|
46
75
|
end
|
47
76
|
end
|
48
77
|
|
@@ -75,12 +104,12 @@ class Jbuilder < BlankSlate
|
|
75
104
|
# { "_first_name": "David" }
|
76
105
|
#
|
77
106
|
def key_format!(*args)
|
78
|
-
|
107
|
+
@key_formatter = KeyFormatter.new(*args)
|
79
108
|
end
|
80
109
|
|
81
110
|
# Same as the instance method key_format! except sets the default.
|
82
111
|
def self.key_format(*args)
|
83
|
-
|
112
|
+
@@key_formatter = KeyFormatter.new(*args)
|
84
113
|
end
|
85
114
|
|
86
115
|
# Turns the current element into an array and yields a builder to add a hash.
|
@@ -129,19 +158,22 @@ class Jbuilder < BlankSlate
|
|
129
158
|
#
|
130
159
|
# { "people": [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ] }
|
131
160
|
def array!(collection)
|
132
|
-
@attributes = []
|
133
|
-
|
134
|
-
|
135
|
-
child! do |child|
|
136
|
-
yield child, element
|
137
|
-
end
|
161
|
+
@attributes = []
|
162
|
+
collection.each do |element| #[] and return if collection.empty?
|
163
|
+
@attributes << _new_instance._tap { |jbuilder| yield jbuilder, element }.attributes!
|
138
164
|
end
|
139
165
|
end
|
140
166
|
|
141
|
-
# Extracts the mentioned attributes from the passed object and turns them into attributes of the JSON.
|
167
|
+
# Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.
|
142
168
|
#
|
143
169
|
# Example:
|
144
170
|
#
|
171
|
+
# @person = Struct.new(:name, :age).new("David", 32)
|
172
|
+
#
|
173
|
+
# or you can utilize a Hash
|
174
|
+
#
|
175
|
+
# @person = {:name => "David", :age => 32}
|
176
|
+
#
|
145
177
|
# json.extract! @person, :name, :age
|
146
178
|
#
|
147
179
|
# { "name": David", "age": 32 }, { "name": Jamie", "age": 31 }
|
@@ -150,18 +182,19 @@ class Jbuilder < BlankSlate
|
|
150
182
|
#
|
151
183
|
# json.(@person, :name, :age)
|
152
184
|
def extract!(object, *attributes)
|
153
|
-
|
154
|
-
|
185
|
+
if object.is_a?(Hash)
|
186
|
+
attributes.each {|attribute| _set_value attribute, object.send(:fetch, attribute)}
|
187
|
+
else
|
188
|
+
attributes.each {|attribute| _set_value attribute, object.send(attribute)}
|
155
189
|
end
|
156
190
|
end
|
157
191
|
|
158
192
|
if RUBY_VERSION > '1.9'
|
159
|
-
def call(*
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
extract!(*args)
|
193
|
+
def call(object = nil, *attributes)
|
194
|
+
if attributes.empty?
|
195
|
+
array!(object) { |json, element| yield json, element }
|
196
|
+
else
|
197
|
+
extract!(object, *attributes)
|
165
198
|
end
|
166
199
|
end
|
167
200
|
end
|
@@ -177,67 +210,71 @@ class Jbuilder < BlankSlate
|
|
177
210
|
end
|
178
211
|
|
179
212
|
|
180
|
-
|
181
|
-
def
|
182
|
-
|
183
|
-
|
184
|
-
# json.person another_jbuilder
|
185
|
-
# { "age": 32, "person": { ... }
|
186
|
-
when args.one? && args.first.respond_to?(:_is_a?) && args.first._is_a?(Jbuilder)
|
187
|
-
set! method, args.first.attributes!
|
188
|
-
|
189
|
-
# json.comments @post.comments { |json, comment| ... }
|
190
|
-
# { "comments": [ { ... }, { ... } ] }
|
191
|
-
when args.one? && block_given?
|
192
|
-
_yield_iteration(method, args.first) { |child, element| yield child, element }
|
193
|
-
|
194
|
-
# json.age 32
|
195
|
-
# { "age": 32 }
|
196
|
-
when args.length == 1
|
197
|
-
set! method, args.first
|
198
|
-
|
199
|
-
# json.comments { |json| ... }
|
200
|
-
# { "comments": ... }
|
201
|
-
when args.empty? && block_given?
|
202
|
-
_yield_nesting(method) { |jbuilder| yield jbuilder }
|
213
|
+
protected
|
214
|
+
def _set_value(key, value)
|
215
|
+
@attributes[@key_formatter.format(key)] = value
|
216
|
+
end
|
203
217
|
|
204
|
-
# json.comments(@post.comments, :content, :created_at)
|
205
|
-
# { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
|
206
|
-
when args.many? && args.first.respond_to?(:each)
|
207
|
-
_inline_nesting method, args.first, args.from(1)
|
208
218
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
219
|
+
private
|
220
|
+
def method_missing(method, value = nil, *args)
|
221
|
+
if block_given?
|
222
|
+
if value
|
223
|
+
# json.comments @post.comments { |json, comment| ... }
|
224
|
+
# { "comments": [ { ... }, { ... } ] }
|
225
|
+
_yield_iteration(method, value) { |child, element| yield child, element }
|
226
|
+
else
|
227
|
+
# json.comments { |json| ... }
|
228
|
+
# { "comments": ... }
|
229
|
+
_yield_nesting(method) { |jbuilder| yield jbuilder }
|
230
|
+
end
|
231
|
+
else
|
232
|
+
if args.empty?
|
233
|
+
if Jbuilder === value
|
234
|
+
# json.age 32
|
235
|
+
# json.person another_jbuilder
|
236
|
+
# { "age": 32, "person": { ... }
|
237
|
+
_set_value method, value.attributes!
|
238
|
+
else
|
239
|
+
# json.age 32
|
240
|
+
# { "age": 32 }
|
241
|
+
_set_value method, value
|
242
|
+
end
|
243
|
+
else
|
244
|
+
if value.respond_to?(:each)
|
245
|
+
# json.comments(@post.comments, :content, :created_at)
|
246
|
+
# { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
|
247
|
+
_inline_nesting method, value, args
|
248
|
+
else
|
249
|
+
# json.author @post.creator, :name, :email_address
|
250
|
+
# { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
|
251
|
+
_inline_extract method, value, args
|
252
|
+
end
|
253
|
+
end
|
213
254
|
end
|
214
255
|
end
|
215
256
|
|
216
257
|
# Overwrite in subclasses if you need to add initialization values
|
217
258
|
def _new_instance
|
218
|
-
__class__.new(@
|
259
|
+
__class__.new(@key_formatter)
|
219
260
|
end
|
220
261
|
|
221
262
|
def _yield_nesting(container)
|
222
|
-
|
263
|
+
_set_value container, _new_instance._tap { |jbuilder| yield jbuilder }.attributes!
|
223
264
|
end
|
224
265
|
|
225
266
|
def _inline_nesting(container, collection, attributes)
|
226
|
-
|
227
|
-
parent.array!(collection)
|
228
|
-
|
229
|
-
|
230
|
-
parent.child! do |child|
|
231
|
-
attributes.each do |attribute|
|
232
|
-
child.__send__ attribute, element.send(attribute)
|
233
|
-
end
|
267
|
+
_yield_nesting(container) do |parent|
|
268
|
+
parent.array!(collection) do |child, element|
|
269
|
+
attributes.each do |attribute|
|
270
|
+
child._set_value attribute, element.send(attribute)
|
234
271
|
end
|
235
272
|
end
|
236
273
|
end
|
237
274
|
end
|
238
275
|
|
239
276
|
def _yield_iteration(container, collection)
|
240
|
-
|
277
|
+
_yield_nesting(container) do |parent|
|
241
278
|
parent.array!(collection) do |child, element|
|
242
279
|
yield child, element
|
243
280
|
end
|
@@ -245,29 +282,7 @@ class Jbuilder < BlankSlate
|
|
245
282
|
end
|
246
283
|
|
247
284
|
def _inline_extract(container, record, attributes)
|
248
|
-
|
249
|
-
end
|
250
|
-
|
251
|
-
# Format the key using the methods described in @key_format
|
252
|
-
def _format_key(key)
|
253
|
-
@key_format.inject(key.to_s) do |result, args|
|
254
|
-
func, args = args
|
255
|
-
if func.is_a? Proc
|
256
|
-
func.call(result, *args)
|
257
|
-
else
|
258
|
-
result.send(func, *args)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
def self.extract_key_format(args, target)
|
264
|
-
options = args.extract_options!
|
265
|
-
args.each do |name|
|
266
|
-
target[name] = []
|
267
|
-
end
|
268
|
-
options.each do |name, paramaters|
|
269
|
-
target[name] = paramaters
|
270
|
-
end
|
285
|
+
_yield_nesting(container) { |parent| parent.extract! record, *attributes }
|
271
286
|
end
|
272
287
|
end
|
273
288
|
|
data/lib/jbuilder_template.rb
CHANGED
@@ -3,9 +3,9 @@ class JbuilderTemplate < Jbuilder
|
|
3
3
|
new(context)._tap { |jbuilder| yield jbuilder }.target!
|
4
4
|
end
|
5
5
|
|
6
|
-
def initialize(context)
|
6
|
+
def initialize(context, *args)
|
7
7
|
@context = context
|
8
|
-
super()
|
8
|
+
super(*args)
|
9
9
|
end
|
10
10
|
|
11
11
|
def partial!(options, locals = {})
|
@@ -21,7 +21,7 @@ class JbuilderTemplate < Jbuilder
|
|
21
21
|
|
22
22
|
private
|
23
23
|
def _new_instance
|
24
|
-
__class__.new(@context)
|
24
|
+
__class__.new(@context, @key_formatter)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'active_support/test_case'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
require 'action_dispatch'
|
5
|
+
require 'action_view'
|
6
|
+
|
7
|
+
require 'jbuilder'
|
8
|
+
require 'jbuilder_template'
|
9
|
+
|
10
|
+
class JbuilderTemplateTest < ActiveSupport::TestCase
|
11
|
+
test "rendering" do
|
12
|
+
json = JbuilderTemplate.encode(binding) do |json|
|
13
|
+
json.content "hello"
|
14
|
+
end
|
15
|
+
|
16
|
+
assert_equal "hello", JSON.parse(json)["content"]
|
17
|
+
end
|
18
|
+
|
19
|
+
test "key_format! with parameter" do
|
20
|
+
json = JbuilderTemplate.new(binding)
|
21
|
+
json.key_format! :camelize => [:lower]
|
22
|
+
json.camel_style "for JS"
|
23
|
+
|
24
|
+
assert_equal ['camelStyle'], json.attributes!.keys
|
25
|
+
end
|
26
|
+
|
27
|
+
test "key_format! propagates to child elements" do
|
28
|
+
json = JbuilderTemplate.new(binding)
|
29
|
+
json.key_format! :upcase
|
30
|
+
json.level1 "one"
|
31
|
+
json.level2 do |json|
|
32
|
+
json.value "two"
|
33
|
+
end
|
34
|
+
|
35
|
+
result = json.attributes!
|
36
|
+
assert_equal "one", result["LEVEL1"]
|
37
|
+
assert_equal "two", result["LEVEL2"]["VALUE"]
|
38
|
+
end
|
39
|
+
end
|
data/test/jbuilder_test.rb
CHANGED
@@ -67,7 +67,20 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
67
67
|
assert_equal 32, parsed["age"]
|
68
68
|
end
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
|
+
test "extracting from hash" do
|
72
|
+
person = {:name => "Jim", :age => 34}
|
73
|
+
|
74
|
+
json = Jbuilder.encode do |json|
|
75
|
+
json.extract! person, :name, :age
|
76
|
+
end
|
77
|
+
|
78
|
+
JSON.parse(json).tap do |parsed|
|
79
|
+
assert_equal "Jim", parsed["name"]
|
80
|
+
assert_equal 34, parsed["age"]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
71
84
|
test "nesting single child with block" do
|
72
85
|
json = Jbuilder.encode do |json|
|
73
86
|
json.author do |json|
|
@@ -356,6 +369,13 @@ class JbuilderTest < ActiveSupport::TestCase
|
|
356
369
|
json.camel_style "for JS"
|
357
370
|
|
358
371
|
assert_equal ['camelStyle'], json.attributes!.keys
|
359
|
-
Jbuilder.class_variable_set("@@
|
372
|
+
Jbuilder.class_variable_set("@@key_formatter", Jbuilder::KeyFormatter.new)
|
373
|
+
end
|
374
|
+
|
375
|
+
test "don't use default key formatter directly" do
|
376
|
+
json = Jbuilder.new
|
377
|
+
json.key "value"
|
378
|
+
|
379
|
+
assert_equal [], Jbuilder.class_variable_get("@@key_formatter").instance_variable_get("@cache").keys
|
360
380
|
end
|
361
381
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jbuilder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: 3.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: blankslate
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,7 +37,12 @@ dependencies:
|
|
32
37
|
version: 2.1.2.4
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.1.2.4
|
36
46
|
description:
|
37
47
|
email: david@37signals.com
|
38
48
|
executables: []
|
@@ -41,12 +51,12 @@ extra_rdoc_files: []
|
|
41
51
|
files:
|
42
52
|
- ./Gemfile
|
43
53
|
- ./Gemfile.lock
|
44
|
-
- ./jbuilder-0.4.2.gem
|
45
54
|
- ./jbuilder.gemspec
|
46
55
|
- ./lib/jbuilder.rb
|
47
56
|
- ./lib/jbuilder_template.rb
|
48
57
|
- ./MIT-LICENSE
|
49
58
|
- ./README.md
|
59
|
+
- ./test/jbuilder_template_test.rb
|
50
60
|
- ./test/jbuilder_test.rb
|
51
61
|
homepage:
|
52
62
|
licenses: []
|
@@ -68,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
78
|
version: '0'
|
69
79
|
requirements: []
|
70
80
|
rubyforge_project:
|
71
|
-
rubygems_version: 1.8.
|
81
|
+
rubygems_version: 1.8.23
|
72
82
|
signing_key:
|
73
83
|
specification_version: 3
|
74
84
|
summary: Create JSON structures via a Builder-style DSL
|
data/jbuilder-0.4.2.gem
DELETED
Binary file
|