Class: Jbuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/jbuilder.rb,
lib/jbuilder/blank.rb,
lib/jbuilder/errors.rb,
lib/jbuilder/railtie.rb,
lib/jbuilder/key_formatter.rb,
lib/jbuilder/dependency_tracker.rb,
lib/jbuilder/collection_renderer.rb

Direct Known Subclasses

JbuilderTemplate

Defined Under Namespace

Modules: CollectionRenderable, DependencyTrackerMethods Classes: ArrayError, Blank, CollectionRenderer, KeyFormatter, MergeError, NullError, Railtie

Constant Summary collapse

BLANK =
Blank.new
NON_ENUMERABLES =
[ ::Struct, ::OpenStruct ].to_set
DependencyTracker =
Class.new(dependency_tracker::ERBTracker)
@@key_formatter =
nil
@@ignore_nil =
false
@@deep_format_keys =
false

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) {|_self| ... } ⇒ Jbuilder

Returns a new instance of Jbuilder.

Yields:

  • (_self)

Yield Parameters:

  • _self (Jbuilder)

    the object that the method was called on


15
16
17
18
19
20
21
22
23
# File 'lib/jbuilder.rb', line 15

def initialize(options = {})
  @attributes = {}

  @key_formatter = options.fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil}
  @ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
  @deep_format_keys = options.fetch(:deep_format_keys, @@deep_format_keys)

  yield self if ::Kernel.block_given?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(*args, &block) ⇒ Object


68
69
70
71
72
73
74
# File 'lib/jbuilder.rb', line 68

def method_missing(*args, &block)
  if ::Kernel.block_given?
    set!(*args, &block)
  else
    set!(*args)
  end
end

Class Method Details

.deep_format_keys(value = true) ⇒ Object

Same as instance method deep_format_keys! except sets the default.


158
159
160
# File 'lib/jbuilder.rb', line 158

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

.encode(*args, &block) ⇒ Object

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


26
27
28
# File 'lib/jbuilder.rb', line 26

def self.encode(*args, &block)
  new(*args, &block).target!
end

.ignore_nil(value = true) ⇒ Object

Same as instance method ignore_nil! except sets the default.


133
134
135
# File 'lib/jbuilder.rb', line 133

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

.key_format(*args) ⇒ Object

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


109
110
111
# File 'lib/jbuilder.rb', line 109

def self.key_format(*args)
  @@key_formatter = KeyFormatter.new(*args)
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]

213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/jbuilder.rb', line 213

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.


268
269
270
# File 'lib/jbuilder.rb', line 268

def attributes!
  @attributes
end

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


252
253
254
255
256
257
258
# File 'lib/jbuilder.rb', line 252

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

178
179
180
181
# File 'lib/jbuilder.rb', line 178

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" }}

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

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)

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

def extract!(object, *attributes)
  if ::Hash === object
    _extract_hash_values(object, attributes)
  else
    _extract_method_values(object, attributes)
  end
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

{}

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

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

#key_format!(*args) ⇒ 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" }

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

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

#merge!(object) ⇒ Object

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


273
274
275
276
# File 'lib/jbuilder.rb', line 273

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.


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

def nil!
  @attributes = nil
end

#set!(key, value = BLANK, *args, &block) ⇒ Object


33
34
35
36
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
# File 'lib/jbuilder.rb', line 33

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.


279
280
281
# File 'lib/jbuilder.rb', line 279

def target!
  @attributes.to_json
end