Skip to content

Commit d4b6216

Browse files
bf4shishirmk
authored andcommitted
Make our own fast MultiToJson
1 parent b717ffe commit d4b6216

2 files changed

Lines changed: 92 additions & 1 deletion

File tree

lib/fast_jsonapi/multi_to_json.rb

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Usage:
2+
# class Movie
3+
# def to_json(payload)
4+
# FastJsonapi::MultiToJson.to_json(payload)
5+
# end
6+
# end
7+
module FastJsonapi
8+
module MultiToJson
9+
# Result object pattern is from https://johnnunemaker.com/resilience-in-ruby/
10+
# e.g. https://github.com/github/github-ds/blob/fbda5389711edfb4c10b6c6bad19311dfcb1bac1/lib/github/result.rb
11+
class Result
12+
def initialize(*rescued_exceptions)
13+
rescued_exceptions = [StandardError] if rescued_exceptions.empty?
14+
@value = yield
15+
@error = nil
16+
rescue *rescued_exceptions => e
17+
@error = e
18+
end
19+
20+
def ok?
21+
@error.nil?
22+
end
23+
24+
def value!
25+
if ok?
26+
@value
27+
else
28+
raise @error
29+
end
30+
end
31+
32+
def rescue
33+
return self if ok?
34+
Result.new { yield(@error) }
35+
end
36+
end
37+
38+
def self.logger(device=nil)
39+
return @logger = Logger.new(device) if device
40+
@logger ||= Logger.new(IO::NULL)
41+
end
42+
43+
# Encoder-compatible with default MultiJSON adapters and defaults
44+
def self.to_json_method
45+
encode_method = String.new(%(def _fast_to_json(object)\n ))
46+
encode_method << Result.new(LoadError) {
47+
require 'oj'
48+
%(::Oj.dump(object, mode: :compat, time_format: :ruby, use_to_json: true))
49+
}.rescue {
50+
require 'yajl'
51+
%(::Yajl::Encoder.encode(object))
52+
}.rescue {
53+
require 'jrjackson' unless defined?(::JrJackson)
54+
%(::JrJackson::Json.dump(object))
55+
}.rescue {
56+
require 'json'
57+
%(JSON.fast_generate(object, create_additions: false, quirks_mode: true))
58+
}.rescue {
59+
require 'gson'
60+
%(::Gson::Encoder.new({}).encode(object))
61+
}.rescue {
62+
require 'active_support/json/encoding'
63+
%(::ActiveSupport::JSON.encode(object))
64+
}.rescue {
65+
warn "No JSON encoder found. Falling back to `object.to_json`"
66+
%(object.to_json)
67+
}.value!
68+
encode_method << "\nend"
69+
end
70+
71+
def self.to_json(object)
72+
_fast_to_json(object)
73+
rescue NameError
74+
define_to_json(FastJsonapi::MultiToJson)
75+
_fast_to_json(object)
76+
end
77+
78+
def self.define_to_json(receiver)
79+
cl = caller_locations[0]
80+
method_body = to_json_method
81+
logger.debug { "Defining #{receiver}._fast_to_json as #{method_body.inspect}" }
82+
receiver.instance_eval method_body, cl.absolute_path, cl.lineno
83+
end
84+
85+
def self.reset_to_json!
86+
undef :_fast_to_json if method_defined?(:_fast_to_json)
87+
logger.debug { "Undefining #{receiver}._fast_to_json" }
88+
end
89+
end
90+
end

lib/fast_jsonapi/serialization_core.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'active_support/concern'
2+
require 'fast_jsonapi/multi_to_json'
23

34
module FastJsonapi
45
module SerializationCore
@@ -67,7 +68,7 @@ def record_hash(record)
6768

6869
# Override #to_json for alternative implementation
6970
def to_json(payload)
70-
JSON.fast_generate(payload) if payload.present?
71+
FastJsonapi::MultiToJson.to_json(payload) if payload.present?
7172
end
7273

7374
# includes handler

0 commit comments

Comments
 (0)