tidy_json 0.2.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/Gemfile +7 -0
- data/LICENSE +1 -1
- data/README.md +84 -38
- data/bin/jtidy +143 -0
- data/bin/jtidy_info.rb +34 -0
- data/lib/tidy_json/dedication.rb +8 -2
- data/lib/tidy_json/formatter.rb +238 -0
- data/lib/tidy_json/serializer.rb +118 -0
- data/lib/tidy_json/version.rb +1 -1
- data/lib/tidy_json.rb +28 -376
- data/test/JsonableObject.json +1 -0
- data/test/codecov_runner.rb +16 -0
- data/test/test_tidy_json.rb +61 -31
- data/tidy_json.gemspec +8 -4
- metadata +28 -12
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TidyJson
|
4
|
+
##
|
5
|
+
# A purpose-built JSON generator.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Serializer
|
9
|
+
##
|
10
|
+
# Searches +obj+ to a maximum depth of 2 for readable attributes, storing
|
11
|
+
# them as key-value pairs in +json_hash+.
|
12
|
+
#
|
13
|
+
# @param obj [Object] A Ruby object that can be parsed as JSON.
|
14
|
+
# @param json_hash [{String,Symbol => #to_s}] Accumulator.
|
15
|
+
# @return [{String => #to_s}] A hash mapping of +obj+'s visible attributes.
|
16
|
+
def self.serialize(obj, json_hash)
|
17
|
+
obj.instance_variables.each do |m|
|
18
|
+
key = m.to_s[/[^\@]\w*/].to_sym
|
19
|
+
|
20
|
+
next unless key && !key.eql?('')
|
21
|
+
|
22
|
+
begin
|
23
|
+
val = obj.send(key) # assuming readable attributes . . .
|
24
|
+
rescue NoMethodError # . . . which may not be always be the case !
|
25
|
+
json_hash[key] = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
# process class members of Hash type
|
30
|
+
if val.instance_of?(Hash)
|
31
|
+
nested_key = ''
|
32
|
+
nested = nil
|
33
|
+
|
34
|
+
val.each.any? do |k, v|
|
35
|
+
unless v.instance_variables.empty?
|
36
|
+
nested_key = k
|
37
|
+
nested = v
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
json_hash[key] = val
|
42
|
+
|
43
|
+
if nested
|
44
|
+
pos = val.keys.select { |k| k === nested_key }.first.to_sym
|
45
|
+
nested.instance_variables.each do
|
46
|
+
json_hash[key][pos] = serialize(nested,
|
47
|
+
class: nested.class.name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# process class members of Array type
|
52
|
+
elsif val.instance_of?(Array)
|
53
|
+
json_hash[key] = []
|
54
|
+
|
55
|
+
val.each do |elem|
|
56
|
+
i = val.index(elem)
|
57
|
+
|
58
|
+
# member is a multi-dimensional collection
|
59
|
+
if elem.respond_to?(:each)
|
60
|
+
nested = []
|
61
|
+
elem.each do |e|
|
62
|
+
j = if elem.respond_to?(:key)
|
63
|
+
elem.key(e)
|
64
|
+
else elem.index(e)
|
65
|
+
end
|
66
|
+
|
67
|
+
# nested element is a class object
|
68
|
+
if !e.instance_variables.empty?
|
69
|
+
json_hash[key][j] = { class: e.class.name }
|
70
|
+
|
71
|
+
# recur over the contained object
|
72
|
+
serialize(e, json_hash[key][j])
|
73
|
+
|
74
|
+
# some kind of collection?
|
75
|
+
elsif e.respond_to?(:each)
|
76
|
+
temp = []
|
77
|
+
e.each do |el|
|
78
|
+
temp << if el.instance_variables.empty? then el
|
79
|
+
else JSON.parse(el.stringify)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
nested << temp
|
84
|
+
|
85
|
+
# scalar type
|
86
|
+
else nested << e
|
87
|
+
end
|
88
|
+
end
|
89
|
+
# ~iteration of nested array elements
|
90
|
+
|
91
|
+
json_hash[key] << nested
|
92
|
+
|
93
|
+
# member is a flat array
|
94
|
+
elsif !elem.instance_variables.empty? # class object?
|
95
|
+
json_hash[key] << { class: elem.class.name }
|
96
|
+
serialize(elem, json_hash[key][i])
|
97
|
+
|
98
|
+
# scalar type
|
99
|
+
else json_hash[key] << elem
|
100
|
+
end
|
101
|
+
end
|
102
|
+
# ~iteration of top-level array elements
|
103
|
+
|
104
|
+
end
|
105
|
+
rescue NoMethodError
|
106
|
+
# we expected an array to behave like a hash, or vice-versa
|
107
|
+
json_hash.store(key, val) # a shallow copy is better than nothing
|
108
|
+
end
|
109
|
+
end
|
110
|
+
# ~iteration of instance variables
|
111
|
+
|
112
|
+
json_hash
|
113
|
+
end
|
114
|
+
# ~Serializer.serialize
|
115
|
+
end
|
116
|
+
|
117
|
+
private_constant :Serializer
|
118
|
+
end
|
data/lib/tidy_json/version.rb
CHANGED
data/lib/tidy_json.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
3
|
require 'json'
|
4
|
+
require_relative 'tidy_json/serializer'
|
5
|
+
require_relative 'tidy_json/formatter'
|
4
6
|
require_relative 'tidy_json/version'
|
5
7
|
|
6
8
|
##
|
@@ -16,36 +18,32 @@ module TidyJson
|
|
16
18
|
# @return [String] A pretty-printed JSON string.
|
17
19
|
def self.tidy(obj = {}, opts = {})
|
18
20
|
formatter = Formatter.new(opts)
|
19
|
-
|
20
|
-
str = ''
|
21
|
+
json = ''
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
str
|
28
|
-
|
29
|
-
|
30
|
-
str << "}\n"
|
23
|
+
begin
|
24
|
+
if obj.instance_variables.empty?
|
25
|
+
obj = sort_keys(obj) if formatter.format[:sorted]
|
26
|
+
json = JSON.generate(obj, formatter.format)
|
27
|
+
else
|
28
|
+
str = "{\n"
|
29
|
+
obj = JSON.parse(obj.stringify)
|
30
|
+
obj = sort_keys(obj) if formatter.format[:sorted]
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
obj.each do |k, v|
|
33
|
+
str << formatter.format[:indent] << "\"#{k}\": "
|
34
|
+
str << formatter.format_node(v, obj)
|
35
|
+
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
str << formatter.format_node(v, obj)
|
37
|
+
str << "}\n"
|
38
|
+
json = JSON.generate(JSON.parse(formatter.trim(str)), formatter.format)
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
extra_comma[:trail].slice(1, str.length.pred))
|
41
|
+
json.gsub(/[\n\r]{2,}/, "\n")
|
42
|
+
.gsub(/\[\s+\]/, '[]')
|
43
|
+
.gsub(/{\s+}/, '{}') << "\n"
|
44
|
+
rescue JSON::JSONError => e
|
45
|
+
warn "#{__FILE__}.#{__LINE__}: #{e.message}"
|
46
46
|
end
|
47
|
-
|
48
|
-
str
|
49
47
|
end
|
50
48
|
|
51
49
|
##
|
@@ -85,7 +83,7 @@ module TidyJson
|
|
85
83
|
temp[idx] = sorter.call(h, {})
|
86
84
|
end
|
87
85
|
|
88
|
-
temp.
|
86
|
+
temp.each_key { |k| sorted << temp[k] }
|
89
87
|
else
|
90
88
|
sorted = sorter.call(obj, {})
|
91
89
|
end
|
@@ -100,11 +98,7 @@ module TidyJson
|
|
100
98
|
# @option (see Formatter#initialize)
|
101
99
|
# @return [String] A pretty-printed JSON string.
|
102
100
|
def to_tidy_json(opts = {})
|
103
|
-
|
104
|
-
TidyJson.tidy(JSON.parse(stringify), opts)
|
105
|
-
else
|
106
|
-
TidyJson.tidy(self, opts)
|
107
|
-
end
|
101
|
+
TidyJson.tidy(self, opts)
|
108
102
|
end
|
109
103
|
|
110
104
|
##
|
@@ -139,359 +133,17 @@ module TidyJson
|
|
139
133
|
|
140
134
|
File.open("#{out}.json", 'w') do |f|
|
141
135
|
path =
|
142
|
-
f << if
|
143
|
-
|
144
|
-
|
145
|
-
end
|
146
|
-
else
|
147
|
-
if opts[:tidy] then to_tidy_json(opts)
|
148
|
-
else to_json
|
149
|
-
end
|
136
|
+
f << if opts[:tidy] then to_tidy_json(opts)
|
137
|
+
elsif instance_variables.empty? then to_json
|
138
|
+
else stringify
|
150
139
|
end
|
151
140
|
end
|
152
141
|
|
153
142
|
path&.path
|
154
|
-
rescue IOError, RuntimeError, NoMethodError => e
|
143
|
+
rescue Errno::ENOENT, Errno::EACCES, IOError, RuntimeError, NoMethodError => e
|
155
144
|
warn "#{__FILE__}.#{__LINE__}: #{e.message}"
|
156
145
|
end
|
157
|
-
|
158
|
-
##
|
159
|
-
# A purpose-built JSON generator.
|
160
|
-
#
|
161
|
-
# @api private
|
162
|
-
class Serializer
|
163
|
-
##
|
164
|
-
# Searches +obj+ to a maximum depth of 2 for readable attributes, storing
|
165
|
-
# them as key-value pairs in +json_hash+.
|
166
|
-
#
|
167
|
-
# @param obj [Object] A Ruby object that can be parsed as JSON.
|
168
|
-
# @param json_hash [{String,Symbol => #to_s}] Accumulator.
|
169
|
-
# @return [{String => #to_s}] A hash mapping of +obj+'s visible attributes.
|
170
|
-
def self.serialize(obj, json_hash)
|
171
|
-
obj.instance_variables.each do |m|
|
172
|
-
key = m.to_s[/[^\@]\w*/].to_sym
|
173
|
-
|
174
|
-
next unless key && !key.eql?('')
|
175
|
-
|
176
|
-
begin
|
177
|
-
val = obj.send(key) # assuming readable attributes . . .
|
178
|
-
rescue NoMethodError # . . . which may not be always be the case !
|
179
|
-
json_hash[key] = nil
|
180
|
-
end
|
181
|
-
|
182
|
-
begin
|
183
|
-
# process class members of Hash type
|
184
|
-
if val.instance_of?(Hash)
|
185
|
-
nested_key = ''
|
186
|
-
nested = nil
|
187
|
-
|
188
|
-
val.each.any? do |k, v|
|
189
|
-
unless v.instance_variables.empty?
|
190
|
-
nested_key = k
|
191
|
-
nested = v
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
json_hash[key] = val
|
196
|
-
|
197
|
-
if nested
|
198
|
-
pos = val.keys.select { |k| k === nested_key }.first.to_sym
|
199
|
-
nested.instance_variables.each do
|
200
|
-
json_hash[key][pos] = serialize(nested,
|
201
|
-
class: nested.class.name)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
# process class members of Array type
|
206
|
-
elsif val.instance_of?(Array)
|
207
|
-
json_hash[key] = []
|
208
|
-
|
209
|
-
val.each do |elem|
|
210
|
-
i = val.index(elem)
|
211
|
-
|
212
|
-
# member is a multi-dimensional array
|
213
|
-
if elem.instance_of?(Array)
|
214
|
-
nested = []
|
215
|
-
elem.each do |e|
|
216
|
-
j = elem.index(e)
|
217
|
-
|
218
|
-
# nested array element is a class object
|
219
|
-
if !e.instance_variables.empty?
|
220
|
-
json_hash[key][j] = { class: e.class.name }
|
221
|
-
|
222
|
-
# recur over the contained object
|
223
|
-
serialize(e, json_hash[key][j])
|
224
|
-
|
225
|
-
# some kind of collection?
|
226
|
-
elsif e.respond_to?(:each)
|
227
|
-
temp = []
|
228
|
-
e.each { |el| temp << el }
|
229
|
-
nested << temp
|
230
|
-
|
231
|
-
# primitive type
|
232
|
-
else nested << e
|
233
|
-
end
|
234
|
-
end
|
235
|
-
# ~iteration of nested array elements
|
236
|
-
|
237
|
-
json_hash[key] << nested
|
238
|
-
|
239
|
-
# member is a flat array
|
240
|
-
else
|
241
|
-
# class object?
|
242
|
-
if !elem.instance_variables.empty?
|
243
|
-
json_hash[key] << { class: elem.class.name }
|
244
|
-
serialize(elem, json_hash[key][i])
|
245
|
-
|
246
|
-
# leverage 1:1 mapping of Hash:object
|
247
|
-
elsif elem.instance_of?(Hash)
|
248
|
-
json_hash[key] = val
|
249
|
-
|
250
|
-
# some kind of collection
|
251
|
-
elsif elem.respond_to?(:each)
|
252
|
-
temp = []
|
253
|
-
elem.each { |e| temp << e }
|
254
|
-
json_hash[key] << temp
|
255
|
-
|
256
|
-
# primitive type
|
257
|
-
else json_hash[key] << elem
|
258
|
-
end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
# ~iteration of top-level array elements
|
262
|
-
|
263
|
-
# process any nested class members, i.e., handle a recursive call
|
264
|
-
# to Serializer.serialize
|
265
|
-
elsif obj.index(val) || json_hash.key?(key)
|
266
|
-
if !val.instance_variables.empty?
|
267
|
-
class_elem = { class: val.class.name }
|
268
|
-
json_hash[key] << class_elem
|
269
|
-
k = json_hash[key].index(class_elem)
|
270
|
-
serialize(val, json_hash[key][k])
|
271
|
-
else
|
272
|
-
json_hash[key] << val
|
273
|
-
end
|
274
|
-
|
275
|
-
# process uncollected class members
|
276
|
-
else
|
277
|
-
# member is a class object
|
278
|
-
if !val.instance_variables.empty?
|
279
|
-
json_hash[key] = { class: val.class.name }
|
280
|
-
serialize(val, json_hash[key])
|
281
|
-
|
282
|
-
# member belongs to a contained object
|
283
|
-
elsif json_hash.key?(key) &&
|
284
|
-
!json_hash[key].has_val?(val) &&
|
285
|
-
json_hash[key].instance_of?(Hash)
|
286
|
-
|
287
|
-
json_hash[key][key] = val
|
288
|
-
|
289
|
-
# primitive member
|
290
|
-
else json_hash[key] = val
|
291
|
-
end
|
292
|
-
end
|
293
|
-
rescue NoMethodError
|
294
|
-
# we expected an array to behave like a hash, or vice-versa
|
295
|
-
json_hash.store(key, val) # a shallow copy is better than nothing
|
296
|
-
end
|
297
|
-
end
|
298
|
-
# ~iteration of instance variables
|
299
|
-
|
300
|
-
json_hash
|
301
|
-
end
|
302
|
-
# ~Serializer.serialize
|
303
|
-
end
|
304
|
-
# ~Serializer
|
305
|
-
|
306
|
-
##
|
307
|
-
# A purpose-built JSON formatter.
|
308
|
-
#
|
309
|
-
# @api private
|
310
|
-
class Formatter
|
311
|
-
attr_reader :indent, :sorted
|
312
|
-
# @!attribute indent
|
313
|
-
# @return [String] the string of white space used by this +Formatter+ to
|
314
|
-
# indent object members.
|
315
|
-
|
316
|
-
# @!attribute sorted
|
317
|
-
# @return [Boolean] whether or not this +Formatter+ will sort object
|
318
|
-
# members by key name.
|
319
|
-
|
320
|
-
##
|
321
|
-
# @param opts [Hash] Formatting options.
|
322
|
-
# @option opts [[2,4,6,8,10,12]] :indent (2) An even number of white spaces
|
323
|
-
# to indent each object member.
|
324
|
-
# @option opts [Boolean] :sort (false) Whether or not object members should
|
325
|
-
# be sorted by key.
|
326
|
-
def initialize(opts = {})
|
327
|
-
# The number of times to reduce the left indent of a nested array's
|
328
|
-
# opening bracket
|
329
|
-
@left_bracket_offset = 0
|
330
|
-
|
331
|
-
# True if printing a nested array
|
332
|
-
@need_offset = false
|
333
|
-
|
334
|
-
# don't test for the more explicit :integer? method because it's defined
|
335
|
-
# for floating point numbers also
|
336
|
-
valid_width = opts[:indent].positive? \
|
337
|
-
if opts[:indent].respond_to?(:times) &&
|
338
|
-
(2..12).step(2).include?(opts[:indent])
|
339
|
-
@indent = "\s" * (valid_width ? opts[:indent] : 2)
|
340
|
-
@sorted = opts[:sort] || false
|
341
|
-
end
|
342
|
-
# ~Formatter#initialize
|
343
|
-
|
344
|
-
##
|
345
|
-
# Returns the given +node+ as pretty-printed JSON.
|
346
|
-
#
|
347
|
-
# @param node [#to_s] A visible attribute of +obj+.
|
348
|
-
# @param obj [{Object => #to_s}, <#to_s>] The enumerable object
|
349
|
-
# containing +node+.
|
350
|
-
# @return [String] A formatted string representation of +node+.
|
351
|
-
def format_node(node, obj)
|
352
|
-
str = ''
|
353
|
-
indent = @indent
|
354
|
-
|
355
|
-
# BUG: arrays containing repeated elements may produce a trailing comma
|
356
|
-
# since Array#index returns the first occurance; in this case the last
|
357
|
-
# element can't be detected by index; a temporary hack in TidyJson::tidy
|
358
|
-
# attempts to correct for this
|
359
|
-
is_last = (obj.length <= 1) ||
|
360
|
-
(obj.length > 1 &&
|
361
|
-
(obj.instance_of?(Hash) &&
|
362
|
-
(obj.key(obj.values.last) === obj.key(node))) ||
|
363
|
-
(obj.instance_of?(Array) && obj.size.pred == obj.index(node)))
|
364
|
-
|
365
|
-
if node.instance_of?(Array)
|
366
|
-
str << "[\n"
|
367
|
-
|
368
|
-
# format array elements
|
369
|
-
node.each do |elem|
|
370
|
-
if elem.instance_of?(Hash)
|
371
|
-
str << "#{(indent * 2)}{\n"
|
372
|
-
|
373
|
-
elem.each_with_index do |inner_h, h_idx|
|
374
|
-
str << "#{(indent * 3)}\"#{inner_h.first}\": "
|
375
|
-
str << node_to_str(inner_h.last, 4)
|
376
|
-
str << ', ' unless h_idx == elem.to_a.length.pred
|
377
|
-
str << "\n"
|
378
|
-
end
|
379
|
-
|
380
|
-
str << "#{(indent * 2)}}"
|
381
|
-
str << ',' unless node.index(elem) == node.length.pred
|
382
|
-
str << "\n" unless node.index(elem) == node.length.pred
|
383
|
-
|
384
|
-
# element a primitive, or a nested array
|
385
|
-
else
|
386
|
-
is_nested_array = elem.instance_of?(Array) &&
|
387
|
-
elem.any? { |e| e.instance_of?(Array) }
|
388
|
-
if is_nested_array
|
389
|
-
@left_bracket_offset = \
|
390
|
-
elem.take_while { |e| e.instance_of?(Array) }.size
|
391
|
-
end
|
392
|
-
|
393
|
-
str << (indent * 2) << node_to_str(elem)
|
394
|
-
str << ",\n" unless node.index(elem) == node.length.pred
|
395
|
-
end
|
396
|
-
end
|
397
|
-
|
398
|
-
str << "\n#{indent}]\n"
|
399
|
-
|
400
|
-
elsif node.instance_of?(Hash)
|
401
|
-
str << "{\n"
|
402
|
-
|
403
|
-
# format elements as key-value pairs
|
404
|
-
node.each_with_index do |h, idx|
|
405
|
-
# format values which are hashes themselves
|
406
|
-
if h.last.instance_of?(Hash)
|
407
|
-
key = if h.first.eql? ''
|
408
|
-
"#{indent * 2}\"<##{h.last.class.name.downcase}>\": "
|
409
|
-
else
|
410
|
-
"#{indent * 2}\"#{h.first}\": "
|
411
|
-
end
|
412
|
-
|
413
|
-
str << key << "{\n"
|
414
|
-
|
415
|
-
h.last.each_with_index do |inner_h, inner_h_idx|
|
416
|
-
str << "#{indent * 3}\"#{inner_h.first}\": "
|
417
|
-
str << node_to_str(inner_h.last, 4)
|
418
|
-
str << ",\n" unless inner_h_idx == h.last.to_a.length.pred
|
419
|
-
end
|
420
|
-
|
421
|
-
str << "\n#{indent * 2}}"
|
422
|
-
|
423
|
-
# format plain values
|
424
|
-
else
|
425
|
-
str << "#{indent * 2}\"#{h.first}\": " << node_to_str(h.last)
|
426
|
-
end
|
427
|
-
|
428
|
-
str << ",\n" unless idx == node.to_a.length.pred
|
429
|
-
end
|
430
|
-
|
431
|
-
str << "\n#{indent}}"
|
432
|
-
str << ', ' unless is_last
|
433
|
-
str << "\n"
|
434
|
-
|
435
|
-
# format primitive types
|
436
|
-
else
|
437
|
-
str << node_to_str(node)
|
438
|
-
str << ', ' unless is_last
|
439
|
-
str << "\n"
|
440
|
-
end
|
441
|
-
|
442
|
-
str.gsub(/(#{indent})+[\n\r]+/, '')
|
443
|
-
.gsub(/\}\,+/, '},')
|
444
|
-
.gsub(/\]\,+/, '],')
|
445
|
-
end
|
446
|
-
# ~Formatter#format_node
|
447
|
-
|
448
|
-
##
|
449
|
-
# Returns a JSON-appropriate string representation of +node+.
|
450
|
-
#
|
451
|
-
# @param node [#to_s] A visible attribute of a Ruby object.
|
452
|
-
# @param tabs [Integer] Tab width at which to start printing this node.
|
453
|
-
# @return [String] A formatted string representation of +node+.
|
454
|
-
def node_to_str(node, tabs = 0)
|
455
|
-
graft = ''
|
456
|
-
tabs += 2 if tabs.zero?
|
457
|
-
|
458
|
-
if @need_offset
|
459
|
-
tabs -= 1
|
460
|
-
@left_bracket_offset -= 1
|
461
|
-
end
|
462
|
-
|
463
|
-
indent = @indent * (tabs / 2)
|
464
|
-
|
465
|
-
if node.nil? then graft << 'null'
|
466
|
-
|
467
|
-
elsif node.instance_of?(Hash)
|
468
|
-
|
469
|
-
format_node(node, node).scan(/.*$/) do |n|
|
470
|
-
graft << "\n" << indent << n
|
471
|
-
end
|
472
|
-
|
473
|
-
elsif node.instance_of?(Array)
|
474
|
-
@need_offset = @left_bracket_offset.positive?
|
475
|
-
|
476
|
-
format_node(node, {}).scan(/.*$/) do |n|
|
477
|
-
graft << "\n" << indent << n
|
478
|
-
end
|
479
|
-
|
480
|
-
elsif !node.instance_of?(String) then graft << node.to_s
|
481
|
-
|
482
|
-
else graft << "\"#{node.gsub(/\"/, '\\"')}\""
|
483
|
-
end
|
484
|
-
|
485
|
-
graft.strip
|
486
|
-
end
|
487
|
-
# ~Formatter#node_to_str
|
488
|
-
end
|
489
|
-
# ~Formatter
|
490
|
-
|
491
|
-
private_constant :Serializer
|
492
|
-
private_constant :Formatter
|
493
146
|
end
|
494
|
-
# ~TidyJson
|
495
147
|
|
496
148
|
##
|
497
149
|
# Includes +TidyJson+ in every Ruby class.
|