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

Direct Known Subclasses

JbuilderTemplate

Defined Under Namespace

Modules: DependencyTrackerMethods Classes: ArrayError, Blank, 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


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

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


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

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.


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

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


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

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.


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

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.


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

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]

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

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.


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

def attributes!
  @attributes
end

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


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

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

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

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

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

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)

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

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

{}

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

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

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

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

#merge!(object) ⇒ Object

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


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

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.


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

def nil!
  @attributes = nil
end

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


32
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
# File 'lib/jbuilder.rb', line 32

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.


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

def target!
  @attributes.to_json
end