Class: Jbuilder

Inherits:
BasicObject
Defined in:
lib/jbuilder.rb,
lib/jbuilder/blank.rb,
lib/jbuilder/errors.rb,
lib/jbuilder/railtie.rb,
lib/jbuilder/version.rb,
lib/jbuilder/key_formatter.rb,
lib/jbuilder/collection_renderer.rb

Direct Known Subclasses

JbuilderTemplate

Defined Under Namespace

Classes: ArrayError, Blank, CollectionRenderer, DependencyTracker, EnumerableCompat, KeyFormatter, MergeError, NullError, Railtie

Constant Summary collapse

BLANK =
Blank.new
VERSION =
"2.14.1"
@@key_formatter =
nil
@@ignore_nil =
false
@@deep_format_keys =
false

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key_formatter: @@key_formatter, ignore_nil: @@ignore_nil, deep_format_keys: @@deep_format_keys) {|_self| ... } ⇒ Jbuilder

Returns a new instance of Jbuilder.

Yields:

  • (_self)

Yield Parameters:

  • _self (Jbuilder)

    the object that the method was called on



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/jbuilder.rb', line 16

def initialize(
  key_formatter: @@key_formatter,
  ignore_nil: @@ignore_nil,
  deep_format_keys: @@deep_format_keys,
  &block
)
  @attributes = {}
  @key_formatter = key_formatter
  @ignore_nil = ignore_nil
  @deep_format_keys = deep_format_keys

  yield self if block
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missingObject (private)



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/jbuilder.rb', line 277

def set!(key, value = BLANK, *args, &block)
  result = if ::Kernel.block_given?
    if !_blank?(value)
      # json.comments @post.comments { |comment| ... }
      # { "comments": [ { ... }, { ... } ] }
      _scope{ array! value, &block }
    else
      # json.comments { ... }
      # { "comments": ... }
      _merge_block(key){ yield self }
    end
  elsif args.empty?
    if ::Jbuilder === value
      # json.age 32
      # json.person another_jbuilder
      # { "age": 32, "person": { ...  }
      _format_keys(value.attributes!)
    else
      # json.age 32
      # { "age": 32 }
      _format_keys(value)
    end
  elsif _is_collection?(value)
    # json.comments @post.comments, :content, :created_at
    # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
    _scope{ array! value, *args }
  else
    # json.author @post.creator, :name, :email_address
    # { "author": { "name": "David", "email_address": "[email protected]" } }
    _merge_block(key){ _extract value, args }
  end

  _set_value key, result
end

Class Method Details

.deep_format_keys(value = true) ⇒ Object

Same as instance method deep_format_keys! except sets the default.



154
155
156
# File 'lib/jbuilder.rb', line 154

def self.deep_format_keys(value = true)
  @@deep_format_keys = value
end

.encodeObject

Yields a builder and automatically turns the result into a JSON string



31
32
33
# File 'lib/jbuilder.rb', line 31

def self.encode(...)
  new(...).target!
end

.ignore_nil(value = true) ⇒ Object

Same as instance method ignore_nil! except sets the default.



129
130
131
# File 'lib/jbuilder.rb', line 129

def self.ignore_nil(value = true)
  @@ignore_nil = value
end

.key_formatObject

Same as the instance method key_format! except sets the default.



105
106
107
# File 'lib/jbuilder.rb', line 105

def self.key_format(...)
  @@key_formatter = KeyFormatter.new(...)
end

Instance Method Details

#array!(collection = [], *attributes, &block) ⇒ Object

Turns the current element into an array and iterates over the passed collection, adding each iteration as an element of the resulting array.

Example:

json.array!(@people) do |person|
  json.name person.name
  json.age calculate_age(person.birthday)
end

[ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ]

You can use the call syntax instead of an explicit extract! call:

json.(@people) { |person| ... }

It’s generally only needed to use this method for top-level arrays. If you have named arrays, you can do:

json.people(@people) do |person|
  json.name person.name
  json.age calculate_age(person.birthday)
end

{ "people": [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ] }

If you omit the block then you can set the top level array directly:

json.array! [1, 2, 3]

[1,2,3]


209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/jbuilder.rb', line 209

def array!(collection = [], *attributes, &block)
  array = if collection.nil?
    []
  elsif ::Kernel.block_given?
    _map_collection(collection, &block)
  elsif attributes.any?
    _map_collection(collection) { |element| _extract element, attributes }
  else
    _format_keys(collection.to_a)
  end

  @attributes = _merge_values(@attributes, array)
end

#attributes!Object

Returns the attributes of the current builder.



260
261
262
# File 'lib/jbuilder.rb', line 260

def attributes!
  @attributes
end

#call(object, *attributes, &block) ⇒ Object



244
245
246
247
248
249
250
# File 'lib/jbuilder.rb', line 244

def call(object, *attributes, &block)
  if ::Kernel.block_given?
    array! object, &block
  else
    _extract object, attributes
  end
end

#child!Object

Turns the current element into an array and yields a builder to add a hash.

Example:

json.comments do
  json.child! { json.content "hello" }
  json.child! { json.content "world" }
end

{ "comments": [ { "content": "hello" }, { "content": "world" } ]}

More commonly, you’d use the combined iterator, though:

json.comments(@post.comments) do |comment|
  json.content comment.formatted_content
end


174
175
176
177
# File 'lib/jbuilder.rb', line 174

def child!
  @attributes = [] unless ::Array === @attributes
  @attributes << _scope{ yield self }
end

#deep_format_keys!(value = true) ⇒ Object

Deeply apply key format to nested hashes and arrays passed to methods like set!, merge! or array!.

Example:

json.key_format! camelize: :lower
json.settings({some_value: "abc"})

{ "settings": { "some_value": "abc" }}

json.key_format! camelize: :lower
json.deep_format_keys!
json.settings({some_value: "abc"})

{ "settings": { "someValue": "abc" }}


149
150
151
# File 'lib/jbuilder.rb', line 149

def deep_format_keys!(value = true)
  @deep_format_keys = value
end

#extract!(object, *attributes) ⇒ Object

Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.

Example:

@person = Struct.new(:name, :age).new('David', 32)

or you can utilize a Hash

@person = { name: 'David', age: 32 }

json.extract! @person, :name, :age

{ "name": David", "age": 32 }, { "name": Jamie", "age": 31 }

You can also use the call syntax instead of an explicit extract! call:

json.(@person, :name, :age)


240
241
242
# File 'lib/jbuilder.rb', line 240

def extract!(object, *attributes)
  _extract object, attributes
end

#ignore_nil!(value = true) ⇒ Object

If you want to skip adding nil values to your JSON hash. This is useful for JSON clients that don’t deal well with nil values, and would prefer not to receive keys which have null values.

Example:

json.ignore_nil! false
json.id User.new.id

{ "id": null }

json.ignore_nil!
json.id User.new.id

{}


124
125
126
# File 'lib/jbuilder.rb', line 124

def ignore_nil!(value = true)
  @ignore_nil = value
end

#key_format!Object

Specifies formatting to be applied to the key. Passing in a name of a function will cause that function to be called on the key. So :upcase will upper case the key. You can also pass in lambdas for more complex transformations.

Example:

json.key_format! :upcase
json.author do
  json.name "David"
  json.age 32
end

{ "AUTHOR": { "NAME": "David", "AGE": 32 } }

You can pass parameters to the method using a hash pair.

json.key_format! camelize: :lower
json.first_name "David"

{ "firstName": "David" }

Lambdas can also be used.

json.key_format! ->(key){ "_" + key }
json.first_name "David"

{ "_first_name": "David" }


100
101
102
# File 'lib/jbuilder.rb', line 100

def key_format!(...)
  @key_formatter = KeyFormatter.new(...)
end

#merge!(object) ⇒ Object

Merges hash, array, or Jbuilder instance into current builder.



265
266
267
268
# File 'lib/jbuilder.rb', line 265

def merge!(object)
  hash_or_array = ::Jbuilder === object ? object.attributes! : object
  @attributes = _merge_values(@attributes, _format_keys(hash_or_array))
end

#nil!Object Also known as: null!

Returns the nil JSON.



253
254
255
# File 'lib/jbuilder.rb', line 253

def nil!
  @attributes = nil
end

#set!(key, value = BLANK, *args, &block) ⇒ Object Also known as: method_missing



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/jbuilder.rb', line 37

def set!(key, value = BLANK, *args, &block)
  result = if ::Kernel.block_given?
    if !_blank?(value)
      # json.comments @post.comments { |comment| ... }
      # { "comments": [ { ... }, { ... } ] }
      _scope{ array! value, &block }
    else
      # json.comments { ... }
      # { "comments": ... }
      _merge_block(key){ yield self }
    end
  elsif args.empty?
    if ::Jbuilder === value
      # json.age 32
      # json.person another_jbuilder
      # { "age": 32, "person": { ...  }
      _format_keys(value.attributes!)
    else
      # json.age 32
      # { "age": 32 }
      _format_keys(value)
    end
  elsif _is_collection?(value)
    # json.comments @post.comments, :content, :created_at
    # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
    _scope{ array! value, *args }
  else
    # json.author @post.creator, :name, :email_address
    # { "author": { "name": "David", "email_address": "[email protected]" } }
    _merge_block(key){ _extract value, args }
  end

  _set_value key, result
end

#target!Object

Encodes the current builder as JSON.



271
272
273
# File 'lib/jbuilder.rb', line 271

def target!
  @attributes.to_json
end