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