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

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



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

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

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

  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



65
66
67
68
69
70
71
# File 'lib/jbuilder.rb', line 65

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

Class Method Details

.encode(*args, &block) ⇒ Object

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



23
24
25
# File 'lib/jbuilder.rb', line 23

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.



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

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.



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

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]


185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/jbuilder.rb', line 185

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
    collection.to_a
  end

  merge! array
end

#attributes!Object

Returns the attributes of the current builder.



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

def attributes!
  @attributes
end

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



224
225
226
227
228
229
230
# File 'lib/jbuilder.rb', line 224

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


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

def child!
  @attributes = [] unless ::Array === @attributes
  @attributes << _scope{ yield self }
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)


216
217
218
219
220
221
222
# File 'lib/jbuilder.rb', line 216

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

{}


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

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


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

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

#merge!(hash_or_array) ⇒ Object

Merges hash or array into current builder.



245
246
247
# File 'lib/jbuilder.rb', line 245

def merge!(hash_or_array)
  @attributes = _merge_values(@attributes, hash_or_array)
end

#nil!Object Also known as: null!

Returns the nil JSON.



233
234
235
# File 'lib/jbuilder.rb', line 233

def nil!
  @attributes = nil
end

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



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

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": { ...  }
      value.attributes!
    else
      # json.age 32
      # { "age": 32 }
      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.



250
251
252
# File 'lib/jbuilder.rb', line 250

def target!
  @attributes.to_json
end