Class: Jsonify::Builder

Inherits:
BlankSlate show all
Defined in:
lib/jsonify/builder.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BlankSlate

find_hidden_method, hide, reveal

Constructor Details

#initialize(options = {}) ⇒ Builder

Initializes a new builder. The Jsonify::Builder works by keeping a stack of JsonValues.

Parameters:

  • options (Hash) (defaults to: {})

    the options to create with

Options Hash (options):

  • :verify (boolean)

    Builder will verify that the compiled JSON string is parseable; this option does incur a performance penalty and generally should only be used in development

  • :format (symbol)

    Format for the resultant JSON string; `:pretty`, the JSON string will be output in a prettier format with new lines and indentation; this option does incur a performance penalty and generally should only be used in development `:plain`, no formatting (compact one-line JSON – best for production)



38
39
40
41
42
# File 'lib/jsonify/builder.rb', line 38

def initialize(options={})
  @verify = options[:verify].nil? ? false : options[:verify] 
  @pretty = options[:format].to_s == 'pretty' ? true : false 
  reset!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, args = nil, &block) ⇒ Object

Adds a new JsonPair to the builder where the key of the pair is set to the method name (`sym`). When passed a block, the value of the pair is set to the result of that block; otherwise, the value is set to the argument(s) (`args`).

If a block is given and an argument is passed, the argument it is assumed to be an Array (more specifically, an object that responds to `each`). The argument is iterated over and each item is yielded to the block. The result of the block becomes an array item of the JsonArray.

Examples:

Create an object literal

json.person do
  json.first_name @person.given_name
  json.last_name @person.surname
end

compiles to something like …

"person": {
  "first_name": "George",
  "last_name": "Burdell"
}

Map an of array of links to an array of JSON objects

json.links(@links) do |link|
  json.rel link.first
  json.href link.last
end

compiles to something like …

"links": [
   {
     "rel": "self",
     "href": "http://example.com/people/123"
   },
   {
     "rel": "school",
     "href": "http://gatech.edu"
   }
]

Parameters:

  • *args (Array)

    iterates over the given array yielding each array item to the block; the result of which is added to a JsonArray



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/jsonify/builder.rb', line 192

def method_missing(sym, args=nil, &block)
  
  # When no block given, simply add the symbol and arg as key - value for a JsonPair to current
  return __store( sym, args ) unless block

  # In a block; create a JSON pair (with no value) and add it to the current object
  pair = Generate.pair_value(sym)
  __store pair

  # Now process the block
  @level += 1

  if args.nil?
    block.call
  else
    array!(args, &block)
  end

  # Set the value on the pair to the object at the top of the stack
  pair.value = @stack[@level]

  # Pop current off the top of the stack; we are done with it at this point
  @stack.pop

  @level -= 1
end

Class Method Details

.compile(options = {}) {|builder| ... } ⇒ Object

Compiles the given block into a JSON string without having to instantiate a Builder.

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :verify (boolean)

    Builder will verify that the compiled JSON string is parseable; this option does incur a performance penalty and generally should only be used in development

  • :format (symbol)

    Format for the resultant JSON string; `:pretty`, the JSON string will be output in a prettier format with new lines and indentation; this option does incur a performance penalty and generally should only be used in development `:plain`, no formatting (compact one-line JSON – best for production)

Yields:

  • (builder)


13
14
15
16
17
# File 'lib/jsonify/builder.rb', line 13

def compile( options={} )
  builder = self.new options
  yield builder
  builder.compile!
end

.plain(&block) ⇒ Object

Compiles the given block into a plain (e.g. no newlines and whitespace) JSON string without having to instantiate a Builder.



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

def plain(&block)
  compile( :format => :plain, &block )
end

.pretty(&block) ⇒ Object

Compiles the given block into a pretty JSON string without having to instantiate a Builder.



20
21
22
# File 'lib/jsonify/builder.rb', line 20

def pretty(&block)
  compile( :format => :pretty, &block )
end

Instance Method Details

#<<(val) ⇒ Object

Append – pushes the given object on the end of a JsonArray.



95
96
97
98
99
# File 'lib/jsonify/builder.rb', line 95

def <<(val)
  __array
  @stack[@level].add val
  self
end

#append!(*args) ⇒ Object

Append – pushes the given variable list objects on to the end of the JsonArray



102
103
104
105
106
107
108
# File 'lib/jsonify/builder.rb', line 102

def append!(*args)
  __array
  args.each do |arg| 
    @stack[@level].add arg
  end
  self
end

#array!(args) ⇒ Object

Creates array of json objects in current element from array passed to this method. Accepts block which yields each array element.

Examples:

Create array in root JSON element

json.array!(@links) do |link|
  json.rel link.first
  json.href link.last
end

compiles to something like …

[
   {
     "rel": "self",
     "href": "http://example.com/people/123"
   },
   {
     "rel": "school",
     "href": "http://gatech.edu"
   }
]


131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/jsonify/builder.rb', line 131

def array!(args)
  __array
  args.each do |arg|
    @level += 1
    yield arg
    @level -= 1
            
    value = @stack.pop
  
    # If the object created was an array with a single value
    # assume that just the value should be added
    if (JsonArray === value && value.values.length <= 1)
      value = value.values.first
    end
  
    @stack[@level].add value
  end
end

#attributes!(object, *attrs) ⇒ Object

Adds a new JsonPair for each attribute in attrs by taking attr as key and value of that attribute in object.

Parameters:

  • object (Object)

    Object to take values from

  • *attrs (Array<Symbol>)

    Array of attributes for JsonPair keys



63
64
65
66
67
# File 'lib/jsonify/builder.rb', line 63

def attributes!(object, *attrs)
  attrs.each do |attr|
    method_missing attr, object.send(attr)
  end
end

#compile!Object

Compiles the JSON objects into a string representation. If initialized with :verify => true, the compiled result will be verified by attempting to re-parse it using MultiJson.load. If initialized with +:format => :pretty+, the compiled result will be parsed and encoded via MultiJson.dump(<json>, :pretty => true) This method can be called without any side effects. You can call compile! at any time, and multiple times if desired.

Raises:

  • (TypeError)

    only if :verify is set to true

  • (JSON::ParseError)

    only if :verify is set to true



76
77
78
79
80
81
# File 'lib/jsonify/builder.rb', line 76

def compile!
  result = (@stack[0] || {}).encode_as_json
  MultiJson.load(result) if @verify
  result = MultiJson.dump(MultiJson.load(result), :pretty => true) if @pretty
  result
end

#ingest!(json_string) ⇒ Object

Ingest a full JSON representation (either an oject or array) into the builder. The value is parsed, objectified, and added to the current value at the top of the stack.

Parameters:

  • json_string (String)

    a full JSON string (e.g. from a rendered partial)



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/jsonify/builder.rb', line 224

def ingest!(json_string)
  return if json_string.empty?
  res = Jsonify::Generate.value(MultiJson.load(json_string))
  current = @stack[@level]
  if current.nil?
    @stack[@level] = res
  elsif JsonObject === current
    if JsonObject === res
      @stack[@level].merge res
    else 
      raise ArgumentError.new("Cannot add JSON array to JSON Object")
    end
  else # current is JsonArray
    @stack[@level].add res
  end
end

#reset!Object

Clears the builder data



45
46
47
48
# File 'lib/jsonify/builder.rb', line 45

def reset!
  @level = 0
  @stack = []
end

#store!(key, value = nil) ⇒ Object Also known as: []=

Stores the key and value into a JSON object

Parameters:

  • key

    the key for the pair

  • value (defaults to: nil)

    the value for the pair

Returns:

  • self to allow for chaining



87
88
89
90
# File 'lib/jsonify/builder.rb', line 87

def store!(key, value=nil)
  (@stack[@level] ||= JsonObject.new).add(key,value)
  self
end

#tag!(sym, args = nil, &block) ⇒ Object

Adds a new JsonPair to the builder. Use this method if the pair “key” has spaces or other characters that prohibit creation via method_missing.

Parameters:

  • sym (String)

    the key for the pair

  • *args (arguments)

    If a block is passed, the first argument will be iterated over and the subsequent result will be added to a JSON array; otherwise, the arguments set value for the `JsonPair`

  • &block

    a code block the result of which will be used to populate the value for the JSON pair



55
56
57
# File 'lib/jsonify/builder.rb', line 55

def tag!(sym, args=nil, &block)
  method_missing(sym, *args, &block)
end