class Jbuilder

Constants

BLANK
NON_ENUMERABLES

Public Class Methods

deep_format_keys(value = true) click to toggle source

Same as instance method deep_format_keys! except sets the default.

# File lib/jbuilder.rb, line 161
def self.deep_format_keys(value = true)
  @@deep_format_keys = value
end
encode(*args, &block) click to toggle source

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

# File lib/jbuilder.rb, line 29
def self.encode(*args, &block)
  new(*args, &block).target!
end
ignore_nil(value = true) click to toggle source

Same as instance method ignore_nil! except sets the default.

# File lib/jbuilder.rb, line 136
def self.ignore_nil(value = true)
  @@ignore_nil = value
end
key_format(*args) click to toggle source

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

# File lib/jbuilder.rb, line 112
def self.key_format(*args)
  @@key_formatter = KeyFormatter.new(*args)
end
new(options = {}) { |self| ... } click to toggle source
# File lib/jbuilder.rb, line 18
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

Public Instance Methods

array!(collection = [], *attributes, &block) click to toggle source

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]
# File lib/jbuilder.rb, line 216
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!() click to toggle source

Returns the attributes of the current builder.

# File lib/jbuilder.rb, line 271
def attributes!
  @attributes
end
call(object, *attributes, &block) click to toggle source
# File lib/jbuilder.rb, line 255
def call(object, *attributes, &block)
  if ::Kernel.block_given?
    array! object, &block
  else
    extract! object, *attributes
  end
end
child!() { |self| ... } click to toggle source

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
# File lib/jbuilder.rb, line 181
def child!
  @attributes = [] unless ::Array === @attributes
  @attributes << _scope{ yield self }
end
deep_format_keys!(value = true) click to toggle source

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" }}
# File lib/jbuilder.rb, line 156
def deep_format_keys!(value = true)
  @deep_format_keys = value
end
extract!(object, *attributes) click to toggle source

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)
# File lib/jbuilder.rb, line 247
def extract!(object, *attributes)
  if ::Hash === object
    _extract_hash_values(object, attributes)
  else
    _extract_method_values(object, attributes)
  end
end
ignore_nil!(value = true) click to toggle source

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

{}
# File lib/jbuilder.rb, line 131
def ignore_nil!(value = true)
  @ignore_nil = value
end
key_format!(*args) click to toggle source

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" }
# File lib/jbuilder.rb, line 107
def key_format!(*args)
  @key_formatter = KeyFormatter.new(*args)
end
merge!(object) click to toggle source

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

# File lib/jbuilder.rb, line 276
def merge!(object)
  hash_or_array = ::Jbuilder === object ? object.attributes! : object
  @attributes = _merge_values(@attributes, _format_keys(hash_or_array))
end
method_missing(*args, &block) click to toggle source
# File lib/jbuilder.rb, line 71
def method_missing(*args, &block)
  if ::Kernel.block_given?
    set!(*args, &block)
  else
    set!(*args)
  end
end
nil!() click to toggle source

Returns the nil JSON.

# File lib/jbuilder.rb, line 264
def nil!
  @attributes = nil
end
Also aliased as: null!
null!()
Alias for: nil!
set!(key, value = BLANK, *args) { |self| ... } click to toggle source
# File lib/jbuilder.rb, line 36
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": "david@loudthinking.com" } }
    _merge_block(key){ extract! value, *args }
  end

  _set_value key, result
end
target!() click to toggle source

Encodes the current builder as JSON.

# File lib/jbuilder.rb, line 282
def target!
  @attributes.to_json
end

Private Instance Methods

_blank?(value=@attributes) click to toggle source
# File lib/jbuilder.rb, line 360
def _blank?(value=@attributes)
  BLANK == value
end
_extract_hash_values(object, attributes) click to toggle source
# File lib/jbuilder.rb, line 288
def _extract_hash_values(object, attributes)
  attributes.each{ |key| _set_value key, _format_keys(object.fetch(key)) }
end
_extract_method_values(object, attributes) click to toggle source
# File lib/jbuilder.rb, line 292
def _extract_method_values(object, attributes)
  attributes.each{ |key| _set_value key, _format_keys(object.public_send(key)) }
end
_format_keys(hash_or_array) click to toggle source
# File lib/jbuilder.rb, line 321
def _format_keys(hash_or_array)
  return hash_or_array unless @deep_format_keys

  if ::Array === hash_or_array
    hash_or_array.map { |value| _format_keys(value) }
  elsif ::Hash === hash_or_array
    ::Hash[hash_or_array.collect { |k, v| [_key(k), _format_keys(v)] }]
  else
    hash_or_array
  end
end
_is_collection?(object) click to toggle source
# File lib/jbuilder.rb, line 356
def _is_collection?(object)
  _object_respond_to?(object, :map, :count) && NON_ENUMERABLES.none?{ |klass| klass === object }
end
_key(key) click to toggle source
# File lib/jbuilder.rb, line 317
def _key(key)
  @key_formatter ? @key_formatter.format(key) : key.to_s
end
_map_collection(collection) { |element| ... } click to toggle source
# File lib/jbuilder.rb, line 341
def _map_collection(collection)
  collection.map do |element|
    _scope{ yield element }
  end - [BLANK]
end
_merge_block(key) { |self| ... } click to toggle source
# File lib/jbuilder.rb, line 296
def _merge_block(key)
  current_value = _blank? ? BLANK : @attributes.fetch(_key(key), BLANK)
  ::Kernel.raise NullError.build(key) if current_value.nil?
  new_value = _scope{ yield self }
  _merge_values(current_value, new_value)
end
_merge_values(current_value, updates) click to toggle source
# File lib/jbuilder.rb, line 303
def _merge_values(current_value, updates)
  if _blank?(updates)
    current_value
  elsif _blank?(current_value) || updates.nil? || current_value.empty? && ::Array === updates
    updates
  elsif ::Array === current_value && ::Array === updates
    current_value + updates
  elsif ::Hash === current_value && ::Hash === updates
    current_value.deep_merge(updates)
  else
    ::Kernel.raise MergeError.build(current_value, updates)
  end
end
_object_respond_to?(object, *methods) click to toggle source
# File lib/jbuilder.rb, line 364
def _object_respond_to?(object, *methods)
  methods.all?{ |m| object.respond_to?(m) }
end
_scope() { || ... } click to toggle source
# File lib/jbuilder.rb, line 347
def _scope
  parent_attributes, parent_formatter, parent_deep_format_keys = @attributes, @key_formatter, @deep_format_keys
  @attributes = BLANK
  yield
  @attributes
ensure
  @attributes, @key_formatter, @deep_format_keys = parent_attributes, parent_formatter, parent_deep_format_keys
end
_set_value(key, value) click to toggle source
# File lib/jbuilder.rb, line 333
def _set_value(key, value)
  ::Kernel.raise NullError.build(key) if @attributes.nil?
  ::Kernel.raise ArrayError.build(key) if ::Array === @attributes
  return if @ignore_nil && value.nil? or _blank?(value)
  @attributes = {} if _blank?
  @attributes[_key(key)] = value
end