jbuilder 0.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,20 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ jbuilder (0.3)
5
+ activesupport (>= 3.0.0)
6
+ blankslate (>= 2.1.2.4)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ activesupport (3.1.3)
12
+ multi_json (~> 1.0)
13
+ blankslate (2.1.2.4)
14
+ multi_json (1.0.4)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ jbuilder!
data/README.md CHANGED
@@ -3,71 +3,83 @@ Jbuilder
3
3
 
4
4
  Jbuilder gives you a simple DSL for declaring JSON structures that beats massaging giant hash structures. This is particularly helpful when the generation process is fraught with conditionals and loops. Here's a simple example:
5
5
 
6
- Jbuilder.encode do |json|
7
- json.content format_content(@message.content)
8
- json.(@message, :created_at, :updated_at)
9
-
10
- json.author do |json|
11
- json.name @message.creator.name.familiar
12
- json.email_address @message.creator.email_address_with_name
13
- json.url url_for(@message.creator, format: :json)
14
- end
15
-
16
- if current_user.admin?
17
- json.visitors calculate_visitors(@message)
18
- end
6
+ ``` ruby
7
+ Jbuilder.encode do |json|
8
+ json.content format_content(@message.content)
9
+ json.(@message, :created_at, :updated_at)
10
+
11
+ json.author do |json|
12
+ json.name @message.creator.name.familiar
13
+ json.email_address @message.creator.email_address_with_name
14
+ json.url url_for(@message.creator, format: :json)
15
+ end
16
+
17
+ if current_user.admin?
18
+ json.visitors calculate_visitors(@message)
19
+ end
20
+
21
+ json.comments @message.comments, :content, :created_at
19
22
 
20
- json.comments @message.comments, :content, :created_at
21
-
22
- json.attachments @message.attachments do |json, attachment|
23
- json.filename attachment.filename
24
- json.url url_for(attachment)
25
- end
26
- end
23
+ json.attachments @message.attachments do |json, attachment|
24
+ json.filename attachment.filename
25
+ json.url url_for(attachment)
26
+ end
27
+ end
28
+ ```
27
29
 
28
30
  This will build the following structure:
29
31
 
30
- {
31
- "content": "<p>This is <i>serious</i> monkey business",
32
- "created_at": "2011-10-29T20:45:28-05:00",
33
- "updated_at": "2011-10-29T20:45:28-05:00",
34
-
35
- "author": {
36
- "name": "David H.",
37
- "email_address": "'David Heinemeier Hansson' <david@heinemeierhansson.com>",
38
- "url": "http://example.com/users/1-david.json"
39
- },
40
-
41
- "visitors": 15,
42
-
43
- "comments": [
44
- { "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
45
- { "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }
46
- ],
47
-
48
- "attachment": [
49
- { "filename": "forecast.xls", "url": "http://example.com/downloads/forecast.xls" },
50
- { "filename": "presentation.pdf", "url": "http://example.com/downloads/presentation.pdf" }
51
- ]
52
- }
32
+ ``` javascript
33
+ {
34
+ "content": "<p>This is <i>serious</i> monkey business",
35
+ "created_at": "2011-10-29T20:45:28-05:00",
36
+ "updated_at": "2011-10-29T20:45:28-05:00",
37
+
38
+ "author": {
39
+ "name": "David H.",
40
+ "email_address": "'David Heinemeier Hansson' <david@heinemeierhansson.com>",
41
+ "url": "http://example.com/users/1-david.json"
42
+ },
43
+
44
+ "visitors": 15,
45
+
46
+ "comments": [
47
+ { "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
48
+ { "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }
49
+ ],
50
+
51
+ "attachment": [
52
+ { "filename": "forecast.xls", "url": "http://example.com/downloads/forecast.xls" },
53
+ { "filename": "presentation.pdf", "url": "http://example.com/downloads/presentation.pdf" }
54
+ ]
55
+ }
56
+ ```
53
57
 
54
58
  You can either use Jbuilder stand-alone or directly as an ActionView template language. When required in Rails, you can create views ala show.json.jbuilder (the json is already yielded):
55
59
 
56
- # Any helpers available to views are available to the builder
57
- json.content format_content(@message.content)
58
- json.(@message, :created_at, :updated_at)
60
+ ``` ruby
61
+ # Any helpers available to views are available to the builder
62
+ json.content format_content(@message.content)
63
+ json.(@message, :created_at, :updated_at)
64
+
65
+ json.author do |json|
66
+ json.name @message.creator.name.familiar
67
+ json.email_address @message.creator.email_address_with_name
68
+ json.url url_for(@message.creator, format: :json)
69
+ end
59
70
 
60
- json.author do |json|
61
- json.name @message.creator.name.familiar
62
- json.email_address @message.creator.email_address_with_name
63
- json.url url_for(@message.creator, format: :json)
64
- end
71
+ if current_user.admin?
72
+ json.visitors calculate_visitors(@message)
73
+ end
65
74
 
66
- if current_user.admin?
67
- json.visitors calculate_visitors(@message)
68
- end
75
+ # You can use partials as well, just remember to pass in the json instance
76
+ json.partial! "api/comments/comments", @message.comments
77
+ ```
69
78
 
70
- # You can use partials as well, just remember to pass in the json instance
71
- json.partial! "api/comments/comments" @message.comments
79
+ Libraries similar to this in some form or another includes:
72
80
 
73
- Note: Jbuilder is similar to Garrett Bjerkhoel's json_builder, which I discovered after making this, but the DSL has taken a different turn and will retain the explicit yield style (vs json_builder's 3.0's move to instance_eval).
81
+ * RABL: https://github.com/nesquena/rabl
82
+ * JsonBuilder: https://github.com/nov/jsonbuilder
83
+ * JSON Builder: https://github.com/dewski/json_builder
84
+ * Jsonify: https://github.com/bsiggelkow/jsonify
85
+ * RepresentationView: https://github.com/mdub/representative_view
Binary file
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jbuilder'
3
- s.version = '0.3'
3
+ s.version = '0.3.1'
4
4
  s.author = 'David Heinemeier Hansson'
5
5
  s.email = 'david@37signals.com'
6
6
  s.summary = 'Create JSON structures via a Builder-style DSL'
@@ -17,6 +17,11 @@ class Jbuilder < BlankSlate
17
17
  @attributes = ActiveSupport::OrderedHash.new
18
18
  end
19
19
 
20
+ # Dynamically set a key value pair.
21
+ def set!(key, value)
22
+ @attributes[key] = value
23
+ end
24
+
20
25
  # Turns the current element into an array and yields a builder to add a hash.
21
26
  #
22
27
  # Example:
@@ -38,7 +43,8 @@ class Jbuilder < BlankSlate
38
43
  @attributes << _new_instance._tap { |jbuilder| yield jbuilder }.attributes!
39
44
  end
40
45
 
41
- # Iterates over the passed collection and adds each iteration as an element of the resulting array.
46
+ # Turns the current element into an array and iterates over the passed collection, adding each iteration as
47
+ # an element of the resulting array.
42
48
  #
43
49
  # Example:
44
50
  #
@@ -47,7 +53,7 @@ class Jbuilder < BlankSlate
47
53
  # json.age calculate_age(person.birthday)
48
54
  # end
49
55
  #
50
- # [ { "David", 32 }, { "Jamie", 31 } ]
56
+ # [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ]
51
57
  #
52
58
  # If you are using Ruby 1.9+, you can use the call syntax instead of an explicit extract! call:
53
59
  #
@@ -60,8 +66,10 @@ class Jbuilder < BlankSlate
60
66
  # json.age calculate_age(person.birthday)
61
67
  # end
62
68
  #
63
- # { "people": [ { "David", 32 }, { "Jamie", 31 } ] }
69
+ # { "people": [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ] }
64
70
  def array!(collection)
71
+ @attributes = [] and return if collection.empty?
72
+
65
73
  collection.each do |element|
66
74
  child! do |child|
67
75
  yield child, element
@@ -75,7 +83,7 @@ class Jbuilder < BlankSlate
75
83
  #
76
84
  # json.extract! @person, :name, :age
77
85
  #
78
- # { "David", 32 }, { "Jamie", 31 }
86
+ # { "name": David", "age": 32 }, { "name": Jamie", "age": 31 }
79
87
  #
80
88
  # If you are using Ruby 1.9+, you can use the call syntax instead of an explicit extract! call:
81
89
  #
@@ -111,34 +119,46 @@ class Jbuilder < BlankSlate
111
119
  private
112
120
  def method_missing(method, *args)
113
121
  case
122
+ # json.comments @post.comments { |json, comment| ... }
123
+ # { "comments": [ { ... }, { ... } ] }
114
124
  when args.one? && block_given?
115
125
  _yield_iteration(method, args.first) { |child, element| yield child, element }
126
+
127
+ # json.age 32
128
+ # { "age": 32 }
116
129
  when args.one?
117
- _assign method, args.first
130
+ set! method, args.first
131
+
132
+ # json.comments { |json| ... }
133
+ # { "comments": ... }
118
134
  when args.empty? && block_given?
119
135
  _yield_nesting(method) { |jbuilder| yield jbuilder }
136
+
137
+ # json.comments(@post.comments, :content, :created_at)
138
+ # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
120
139
  when args.many? && args.first.is_a?(Enumerable)
121
140
  _inline_nesting method, args.first, args.from(1)
141
+
142
+ # json.author @post.creator, :name, :email_address
143
+ # { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
122
144
  when args.many?
123
145
  _inline_extract method, args.first, args.from(1)
124
146
  end
125
147
  end
126
148
 
127
- def _assign(key, value)
128
- @attributes[key] = value
129
- end
130
-
131
149
  # Overwrite in subclasses if you need to add initialization values
132
150
  def _new_instance
133
151
  __class__.new
134
152
  end
135
153
 
136
154
  def _yield_nesting(container)
137
- @attributes[container] = _new_instance._tap { |jbuilder| yield jbuilder }.attributes!
155
+ set! container, _new_instance._tap { |jbuilder| yield jbuilder }.attributes!
138
156
  end
139
157
 
140
158
  def _inline_nesting(container, collection, attributes)
141
159
  __send__(container) do |parent|
160
+ parent.array!(collection) and return if collection.empty?
161
+
142
162
  collection.each do |element|
143
163
  parent.child! do |child|
144
164
  attributes.each do |attribute|
@@ -9,7 +9,7 @@ class JbuilderTemplate < Jbuilder
9
9
  end
10
10
 
11
11
  def partial!(partial_name, options = {})
12
- @context.render(partial_name, options.merge(json: self))
12
+ @context.render(partial_name, options.merge(:json => self))
13
13
  end
14
14
 
15
15
  private
@@ -111,6 +111,19 @@ class JbuilderTest < ActiveSupport::TestCase
111
111
  end
112
112
  end
113
113
 
114
+ test "nesting multiple children from array when child array is empty" do
115
+ comments = []
116
+
117
+ json = Jbuilder.encode do |json|
118
+ json.name "Parent"
119
+ json.comments comments, :content
120
+ end
121
+
122
+ JSON.parse(json).tap do |parsed|
123
+ assert_equal "Parent", parsed["name"]
124
+ assert_equal [], parsed["comments"]
125
+ end
126
+ end
114
127
 
115
128
  test "nesting multiple children from array with inline loop" do
116
129
  comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
@@ -192,4 +205,24 @@ class JbuilderTest < ActiveSupport::TestCase
192
205
  assert_equal "world", parsed.second["content"]
193
206
  end
194
207
  end
208
+
209
+ test "empty top-level array" do
210
+ comments = []
211
+
212
+ json = Jbuilder.encode do |json|
213
+ json.array!(comments) do |json, comment|
214
+ json.content comment.content
215
+ end
216
+ end
217
+
218
+ assert_equal [], JSON.parse(json)
219
+ end
220
+
221
+ test "dynamically set a key/value" do
222
+ json = Jbuilder.encode do |json|
223
+ json.set!(:each, "stuff")
224
+ end
225
+
226
+ assert_equal "stuff", JSON.parse(json)["each"]
227
+ end
195
228
  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.3'
4
+ version: 0.3.1
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: 2011-11-30 00:00:00.000000000 Z
12
+ date: 2012-01-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &70104549490040 !ruby/object:Gem::Requirement
16
+ requirement: &70354468053200 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70104549490040
24
+ version_requirements: *70354468053200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: blankslate
27
- requirement: &70104549489160 !ruby/object:Gem::Requirement
27
+ requirement: &70354468052720 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,13 +32,16 @@ dependencies:
32
32
  version: 2.1.2.4
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70104549489160
35
+ version_requirements: *70354468052720
36
36
  description:
37
37
  email: david@37signals.com
38
38
  executables: []
39
39
  extensions: []
40
40
  extra_rdoc_files: []
41
41
  files:
42
+ - ./Gemfile
43
+ - ./Gemfile.lock
44
+ - ./jbuilder-0.3.gem
42
45
  - ./jbuilder.gemspec
43
46
  - ./lib/jbuilder.rb
44
47
  - ./lib/jbuilder_template.rb
@@ -65,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
68
  version: '0'
66
69
  requirements: []
67
70
  rubyforge_project:
68
- rubygems_version: 1.8.11
71
+ rubygems_version: 1.8.15
69
72
  signing_key:
70
73
  specification_version: 3
71
74
  summary: Create JSON structures via a Builder-style DSL