jbuilder 0.3 → 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/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