Module: Rufus::Json

Defined in:
lib/rufus/json.rb

Defined Under Namespace

Classes: ParserError

Constant Summary collapse

VERSION =
'1.0.6'
JSON =

The JSON / JSON pure decoder

{
  :encode => lambda { |o, opts|
    opts[:max_nesting] = false unless opts.has_key?(:max_nesting)
    if o.is_a?(Hash) or o.is_a?(Array)
      ::JSON.generate(o, opts)
    else
      ::JSON.generate([ o ], opts).strip[1..-2]
    end
  },
  :pretty_encode => lambda { |o|
    encode(
      o,
      :indent => '  ', :object_nl => "\n", :array_nl => "\n", :space => ' ')
  },
  :decode => lambda { |s|
    ::JSON.parse(
      "[#{s}]",
      :max_nesting => nil,
      :create_additions => false
    ).first },
  :error => lambda {
    ::JSON::ParserError }
}
ACTIVE_SUPPORT =

The Rails ActiveSupport::JSON decoder

{
  :encode => lambda { |o, opts|
    ActiveSupport::JSON.encode(o, opts) },
  :pretty_encode => lambda { |o|
    ActiveSupport::JSON.encode(o) },
  :decode => lambda { |s|
    decode_e(s) || ActiveSupport::JSON.decode(s) },
  :error => lambda {
    RuntimeError }
}
ACTIVE =
ACTIVE_SUPPORT
YAJL =
{
  :encode => lambda { |o, opts|
    Yajl::Encoder.encode(o, opts) },
  :pretty_encode => lambda { |o|
    Yajl::Encoder.encode(o, :pretty => true, :indent => '  ') },
  :decode => lambda { |s|
    Yajl::Parser.parse(s) },
  :error => lambda {
    ::Yajl::ParseError }
}
OJ =
{
  :encode => lambda { |o, opts|
    Oj.dump(syms_to_s(o), opts.merge(:symbol_keys => false)) },
  :pretty_encode => lambda { |o|
    Oj.dump(syms_to_s(o), :indent => 2) },
  :decode => lambda { |s|
    Oj.load(s, :strict => true) },
  :error => lambda {
    ::Oj::ParseError }
}
JRJACKSON =
{
    :encode => lambda { |o, opts|
      fix_raw_value(::JrJackson::Json.dump(syms_to_s(o))) },
    :pretty_encode => lambda { |o|
      fix_raw_value(::JrJackson::Json.dump(syms_to_s(o))) },
    :decode => lambda { |s|
      ::JrJackson::Json.load(s) },
    :error => lambda {
      ::JrJackson::ParseError }
}
NONE =

The "raise an exception because there's no backend" backend

{
  :encode => lambda { |o, opts| raise 'no JSON backend found' },
  :pretty_encode => lambda { |o| raise 'no JSON backend found' },
  :decode => lambda { |s| raise 'no JSON backend found' },
  :error => lambda { raise 'no JSON backend found' }
}
E_REGEX =
/^\d+(\.\d+)?[eE][+-]?\d+$/

Class Method Summary collapse

Class Method Details

.backend ⇒ Object

Returns :yajl|:json|:active|:none (an identifier for the current backend)



179
180
181
182
183
184
# File 'lib/rufus/json.rb', line 179

def self.backend

  %w[ yajl json active oj jrjackson none ].find { |b|
    Rufus::Json.const_get(b.upcase) == @backend
  }.to_sym
end

.backend=(b) ⇒ Object

Forces a decoder JSON/ACTIVE_SUPPORT or any lambda pair that knows how to deal with JSON.

It's OK to pass a symbol as well, :yajl, :json, :active (or :none).



191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/rufus/json.rb', line 191

def self.backend=(b)

  b =
    {
      'yajl' => YAJL, 'yajl-ruby' => YAJL,
      'json' => JSON, 'json-pure' => JSON,
      'active' => ACTIVE, 'active-support' => ACTIVE,
      'oj' => OJ, 'jrjackson' => JRJACKSON, 'none' => NONE
    }[b.to_s.gsub(/[_\/]/, '-')] if b.is_a?(String) or b.is_a?(Symbol)

  @backend = b
end

.decode(s) ⇒ Object

Decodes the given JSON string.



227
228
229
230
231
232
233
# File 'lib/rufus/json.rb', line 227

def self.decode(s)

  @backend[:decode][s]

rescue @backend[:error][] => e
  raise ParserError.new(e.message)
end

.decode_e(s) ⇒ Object

Let's ActiveSupport do the E number notation.



259
260
261
262
# File 'lib/rufus/json.rb', line 259

def self.decode_e(s)

  s.match(E_REGEX) ? eval(s) : false
end

.detect_backend ⇒ Object

[Re-]Attempts to detect a JSON backend



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/rufus/json.rb', line 149

def self.detect_backend

  @backend =
    if defined?(::JrJackson)
      JRJACKSON
    elsif defined?(::Oj)
      OJ
    elsif defined?(::Yajl)
      YAJL
    elsif defined?(::JSON)
      JSON
    elsif defined?(ActiveSupport::JSON)
      ACTIVE_SUPPORT
    else
      NONE
    end
end

.dump(o, opts = {}) ⇒ Object

An alias for .encode



220
221
222
223
# File 'lib/rufus/json.rb', line 220

def self.dump(o, opts={})

  encode(o, opts)
end

.dup(o) ⇒ Object

Duplicates an object by turning it into JSON and back.

Don't laugh, yajl-ruby makes that faster than a Marshal copy.



246
247
248
249
250
251
252
253
# File 'lib/rufus/json.rb', line 246

def self.dup(o)

  if @backend == NONE
    syms_to_s(Marshal.load(Marshal.dump(o)))
  else
    decode(encode(o))
  end
end

.encode(o, opts = {}) ⇒ Object

Encodes the given object to a JSON string.



206
207
208
209
# File 'lib/rufus/json.rb', line 206

def self.encode(o, opts={})

  @backend[:encode][o, opts]
end

.fix_raw_value(o) ⇒ Object

Used to handle parsers that do not support raw value encoding (i.e. JrJackson)



277
278
279
280
281
282
283
284
285
286
287
# File 'lib/rufus/json.rb', line 277

def self.fix_raw_value(o)

  case o
    when FalseClass, TrueClass, Fixnum, Float
      o.to_s
    when NilClass
      'null'
    else
      o
  end
end

.has_backend? ⇒ Boolean

Returns true if there is a backend set for parsing/encoding JSON

Returns:

  • (Boolean)


172
173
174
175
# File 'lib/rufus/json.rb', line 172

def self.has_backend?

  (@backend != NONE)
end

.load(s) ⇒ Object

An alias for .decode



237
238
239
240
# File 'lib/rufus/json.rb', line 237

def self.load(s)

  decode(s)
end

.load_backend(*order) ⇒ Object

In the given order, attempts to load a json lib and sets it as the backend of rufus-json.

Returns the name of lib found if sucessful.

Returns nil if no lib could be set.

The default order / list of backends is yajl, active_support, json, json/pure. When specifying a custom order/list, unspecified backends won't be tried for.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/rufus/json.rb', line 130

def self.load_backend(*order)

  order =
    %w[ yajl oj jrjackson active_support json json/pure ] if order.empty?

  order.each do |lib|
    begin
      require(lib)
      Rufus::Json.backend = lib
      return lib
    rescue LoadError => le
    end
  end

  nil
end

.pretty_encode(o) ⇒ Object

Pretty encoding



213
214
215
216
# File 'lib/rufus/json.rb', line 213

def self.pretty_encode(o)

  @backend[:pretty_encode][o]
end

.syms_to_s(o) ⇒ Object

Used to get a uniform behaviour among encoders.



266
267
268
269
270
271
272
# File 'lib/rufus/json.rb', line 266

def self.syms_to_s(o)

  return o.to_s if o.is_a?(Symbol)
  return o unless o.is_a?(Hash)

  o.inject({}) { |h, (k, v)| h[k.to_s] = syms_to_s(v); h }
end