tidy_json 0.1.1
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 +7 -0
- data/.yardopts +1 -0
- data/Gemfile +7 -0
- data/LICENSE +21 -0
- data/README.md +68 -0
- data/Rakefile +14 -0
- data/lib/tidy_json/dedication.rb +11 -0
- data/lib/tidy_json/version.rb +3 -0
- data/lib/tidy_json.rb +384 -0
- data/test/test_tidy_json.rb +49 -0
- data/tidy_json.gemspec +26 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5c8377fc4c17ae11f718b6cadd5a0bbf5a806c1706f8184370e036dbeb714d73
|
4
|
+
data.tar.gz: dd9dcac5f8b3294f1edbd7a05762ad89277e6b593b0610d79d501e3d68e62fea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 62b421c64ac5ecbd6fcc54a9e43f57d1e04ae52b6b6ab21c5eb65d65b4a267e44a28dde2ee67cf80167c5d0857c242c246e3881d510f00493e44b835fb17b52a
|
7
|
+
data.tar.gz: 0b7534efee7f35486f1bc8f60dab7031f762aa6fdc69a7eb83d603b2cfae25583aa702e4009ff8dba284a0e1b3136e0c4bafe39f43e235951d7bc93a767eca1a
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--private lib/*.rb lib/tidy_json/version.rb - README.md LICENSE
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Robert Di Pardo
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# TidyJson
|
2
|
+
|
3
|
+
[](https://travis-ci.com/rdipardo/tidy_json)
|
4
|
+
|
5
|
+
A mixin providing (recursive) JSON serialization and pretty printing.
|
6
|
+
|
7
|
+
### Installation
|
8
|
+
|
9
|
+
#### Minimal
|
10
|
+
|
11
|
+
```bash
|
12
|
+
$ gem install tidy_json
|
13
|
+
```
|
14
|
+
|
15
|
+
#### Development (tests, YARD docs)
|
16
|
+
|
17
|
+
```bash
|
18
|
+
$ gem install --development tidy_json
|
19
|
+
```
|
20
|
+
|
21
|
+
Or, with `bundler`:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
source 'https://rubygems.org'
|
25
|
+
# ...
|
26
|
+
gem 'tidy_json'
|
27
|
+
# ...
|
28
|
+
```
|
29
|
+
|
30
|
+
### Example
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
require 'tidy_json'
|
34
|
+
|
35
|
+
JSON.parse [].stringify
|
36
|
+
# => {"class"=>"Array"}
|
37
|
+
|
38
|
+
complex_object = { :a => 1, :b => ['two', 3, '<abbr title="four">IV</abbr>'] }
|
39
|
+
# => {:a=>1, :b=>["two", 3, "<abbr title=\"four\">IV</abbr>"]}
|
40
|
+
|
41
|
+
puts complex_object.to_tidy_json
|
42
|
+
# {
|
43
|
+
# "a": 1,
|
44
|
+
# "b":
|
45
|
+
# [
|
46
|
+
# "two",
|
47
|
+
# 3,
|
48
|
+
# "<abbr title=\"four\">IV</abbr>"
|
49
|
+
# ]
|
50
|
+
# }
|
51
|
+
# => nil
|
52
|
+
```
|
53
|
+
|
54
|
+
### Dependencies
|
55
|
+
|
56
|
+
#### Runtime
|
57
|
+
- [json](https://rubygems.org/gems/json) ~> 2.2
|
58
|
+
|
59
|
+
#### Building
|
60
|
+
- [bundler](https://rubygems.org/gems/bundler) ~> 2.1
|
61
|
+
- [minitest](https://rubygems.org/gems/minitest) ~> 5.0
|
62
|
+
- [yard](https://rubygems.org/gems/yard) ~> 0.9
|
63
|
+
|
64
|
+
### License
|
65
|
+
[MIT](https://opensource.org/licenses/MIT)
|
66
|
+
|
67
|
+
### Author
|
68
|
+
[Robert Di Pardo](mailto:rdipardo0520@conestogac.on.ca)
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'yard'
|
4
|
+
|
5
|
+
Rake::TestTask.new(:test) do |t|
|
6
|
+
t.libs << 'test'
|
7
|
+
t.libs << 'lib'
|
8
|
+
t.test_files = FileList['test/**/test_*.rb']
|
9
|
+
end
|
10
|
+
|
11
|
+
YARD::Rake::YardocTask.new
|
12
|
+
|
13
|
+
desc 'Run tests'
|
14
|
+
task default: :test
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module TidyJson # :nodoc:
|
2
|
+
DEDICATION = "#{'.' * 50}\n#{'.' * 20} tidy_json #{'.' * 19}\n" \
|
3
|
+
"#{'.' * 12} (c) 2019 Robert Di Pardo #{'.' * 12}\n" \
|
4
|
+
"#{'.' * 50}\n#{'.' * 19} IN MEMORIAM #{'.' * 18}\n" \
|
5
|
+
"#{'.' * 16} Michael Di Pardo #{'.' * 16}\n" \
|
6
|
+
"#{'.' * 19} 1950 - 2019 #{'.' * 18}\n#{'.' * 50}\n" \
|
7
|
+
"#{'.' * 12} Please consider supporting #{'.' * 11}\n" \
|
8
|
+
"#{'.' * 13} the MS Society of Canada #{'.' * 11}\n" \
|
9
|
+
"#{'.' * 8} https://mssociety.ca/get-involved #{'.' * 7}\n" \
|
10
|
+
"#{'.' * 50}\n"
|
11
|
+
end
|
data/lib/tidy_json.rb
ADDED
@@ -0,0 +1,384 @@
|
|
1
|
+
require 'json'
|
2
|
+
require_relative 'tidy_json/version'
|
3
|
+
|
4
|
+
##
|
5
|
+
# A mixin providing (recursive) JSON serialization and pretty printing.
|
6
|
+
#
|
7
|
+
module TidyJson
|
8
|
+
##
|
9
|
+
# Emits a pretty-printed JSON representation of the given +obj+.
|
10
|
+
#
|
11
|
+
# @param obj [Object] A Ruby object that can be parsed as JSON.
|
12
|
+
# @return [String] A pretty-printed JSON string.
|
13
|
+
def self.tidy(obj = {})
|
14
|
+
str = ''
|
15
|
+
|
16
|
+
if obj.instance_of?(Hash)
|
17
|
+
str << "{\n"
|
18
|
+
|
19
|
+
obj.each do |k, v|
|
20
|
+
str << "\"#{k}\": "
|
21
|
+
str << Serializer.format_node(v, obj)
|
22
|
+
end
|
23
|
+
|
24
|
+
str << "}\n"
|
25
|
+
|
26
|
+
elsif obj.instance_of?(Array)
|
27
|
+
str << "[\n"
|
28
|
+
|
29
|
+
obj.each do |v|
|
30
|
+
str << Serializer.format_node(v, obj)
|
31
|
+
end
|
32
|
+
|
33
|
+
str << "]\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
str
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Like +TidyJson::tidy+, but callable by the sender object with the option *not* to pretty-print.
|
41
|
+
#
|
42
|
+
# @param pretty [Boolean] Whether or not the returned string should be pretty-printed.
|
43
|
+
# @return [String] A pretty-printed JSON string.
|
44
|
+
def to_tidy_json(pretty = true)
|
45
|
+
if !instance_variables.empty?
|
46
|
+
if pretty then TidyJson.tidy(JSON.parse(stringify))
|
47
|
+
else stringify
|
48
|
+
end
|
49
|
+
else
|
50
|
+
if pretty then TidyJson.tidy(self)
|
51
|
+
else to_json
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Emits a JSON representation of the sender object's visible attributes.
|
58
|
+
#
|
59
|
+
# @return [String] A raw JSON string.
|
60
|
+
def stringify
|
61
|
+
json_hash = {}
|
62
|
+
|
63
|
+
begin
|
64
|
+
json_hash = Serializer.serialize(self, class: self.class.name)
|
65
|
+
rescue JSON::JSONError => e
|
66
|
+
warn "#{__FILE__}.#{__LINE__}: #{e.message}"
|
67
|
+
end
|
68
|
+
|
69
|
+
json_hash.to_json
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Writes a pretty-printed JSON representation of the sender object to the file specified by +out+.
|
74
|
+
#
|
75
|
+
# @param pretty [Boolean] Whether or not the output should be pretty-printed.
|
76
|
+
# @param out [String] The destination filename. Defaults to <tt><obj_class_name>_<current_UNIX_time></tt>.json
|
77
|
+
# @return [String, nil] The path to the written output file, if successful.
|
78
|
+
def write_json(pretty = true, out = "#{self.class.name}_#{Time.now.to_i}")
|
79
|
+
path = nil
|
80
|
+
|
81
|
+
File.open("#{out}.json", 'w') do |f|
|
82
|
+
path = f << to_tidy_json(pretty)
|
83
|
+
end
|
84
|
+
|
85
|
+
path.path
|
86
|
+
rescue IOError, RuntimeError, NoMethodError => e
|
87
|
+
warn "#{__FILE__}.#{__LINE__}: #{e.message}"
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# A purpose-built JSON generator.
|
92
|
+
#
|
93
|
+
# @api private
|
94
|
+
class Serializer
|
95
|
+
##
|
96
|
+
# The number of times to reduce the left margin of a nested array's opening
|
97
|
+
# bracket
|
98
|
+
@margins_to_backspace = 0
|
99
|
+
|
100
|
+
##
|
101
|
+
# True if printing a nested array
|
102
|
+
@should_backspace = false
|
103
|
+
|
104
|
+
##
|
105
|
+
# Searches +obj+ to a *maximum* depth of 2 for readable attributes,
|
106
|
+
# storing them as key-value pairs in +json_hash+.
|
107
|
+
#
|
108
|
+
# @param obj [Object] A Ruby object that can be parsed as JSON.
|
109
|
+
# @param json_hash [{String,Symbol => #to_s}] Accumulator.
|
110
|
+
# @return [{String => #to_s}] A hash mapping of +obj+'s visible attributes.
|
111
|
+
def self.serialize(obj, json_hash)
|
112
|
+
obj.instance_variables.each do |m|
|
113
|
+
key = m.to_s[/[^\@]\w*/].to_sym
|
114
|
+
|
115
|
+
next unless key && !key.eql?('')
|
116
|
+
|
117
|
+
begin
|
118
|
+
val = obj.send(key) # assuming readable attributes . . .
|
119
|
+
rescue NoMethodError # . . . which may not be always be the case !
|
120
|
+
json_hash[key] = nil
|
121
|
+
end
|
122
|
+
|
123
|
+
begin
|
124
|
+
# process class members of Hash type
|
125
|
+
if val.instance_of?(Hash)
|
126
|
+
nested_key = ''
|
127
|
+
nested = nil
|
128
|
+
|
129
|
+
val.each.any? do |k, v|
|
130
|
+
if v.instance_variables.first
|
131
|
+
nested_key = k
|
132
|
+
nested = v
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
json_hash[key] = val
|
137
|
+
|
138
|
+
if nested
|
139
|
+
pos = val.keys.select { |k| k === nested_key }.first.to_sym
|
140
|
+
nested.instance_variables.each do
|
141
|
+
json_hash[key][pos] = serialize(nested, class: nested.class.name)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# process class members of Array type
|
146
|
+
elsif val.instance_of?(Array)
|
147
|
+
json_hash[key] = []
|
148
|
+
|
149
|
+
val.each do |elem|
|
150
|
+
i = val.index(elem)
|
151
|
+
|
152
|
+
# multi-dimensional array
|
153
|
+
if elem.instance_of?(Array)
|
154
|
+
nested = []
|
155
|
+
elem.each do |e|
|
156
|
+
j = elem.index(e)
|
157
|
+
|
158
|
+
# nested array element is a class object
|
159
|
+
if e.instance_variables.first
|
160
|
+
json_hash[key][j] = { class: e.class.name }
|
161
|
+
|
162
|
+
# recur over the contained object
|
163
|
+
serialize(e, json_hash[key][j])
|
164
|
+
else
|
165
|
+
# some kind of collection?
|
166
|
+
if e.respond_to? :each
|
167
|
+
temp = []
|
168
|
+
e.each { |el| temp << el }
|
169
|
+
nested << temp
|
170
|
+
else nested << e
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
# ~iteration of nested array elements
|
175
|
+
|
176
|
+
json_hash[key] << nested
|
177
|
+
|
178
|
+
else
|
179
|
+
# 1-D array of class objects
|
180
|
+
if elem.instance_variables.first
|
181
|
+
json_hash[key] << { class: elem.class.name }
|
182
|
+
serialize(elem, json_hash[key][i])
|
183
|
+
else
|
184
|
+
# element of primitive type (or Array, or Hash):
|
185
|
+
# leverage 1:1 mapping of Hash:object
|
186
|
+
if elem.instance_of?(Hash) then json_hash[key] = val
|
187
|
+
else
|
188
|
+
# some kind of collection
|
189
|
+
if elem.respond_to? :each
|
190
|
+
temp = []
|
191
|
+
elem.each { |e| temp << e }
|
192
|
+
json_hash[key] << temp
|
193
|
+
else json_hash[key] << elem
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
# ~iteration of top-level array elements
|
200
|
+
|
201
|
+
# process any nested class members, i.e., handle a recursive call
|
202
|
+
# to Serializer.serialize
|
203
|
+
elsif obj.index(val) || json_hash.key?(key)
|
204
|
+
if val.instance_variables.first
|
205
|
+
class_elem = { class: val.class.name }
|
206
|
+
json_hash[key] << class_elem
|
207
|
+
k = json_hash[key].index(class_elem)
|
208
|
+
serialize(val, json_hash[key][k])
|
209
|
+
else
|
210
|
+
json_hash[key] << val
|
211
|
+
end
|
212
|
+
|
213
|
+
# process uncollected data members
|
214
|
+
else
|
215
|
+
# member a class object
|
216
|
+
if val.instance_variables.first
|
217
|
+
json_hash[key] = { class: val.class.name }
|
218
|
+
serialize(val, json_hash[key])
|
219
|
+
else
|
220
|
+
# member a hash element
|
221
|
+
if json_hash.key?(key) && \
|
222
|
+
!json_hash[key].has_val?(val) && \
|
223
|
+
json_hash[key].instance_of?(Hash)
|
224
|
+
|
225
|
+
json_hash[key][key] = val
|
226
|
+
else
|
227
|
+
json_hash[key] = val
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
rescue NoMethodError
|
232
|
+
# we expected an array to behave like a hash, or vice-versa
|
233
|
+
json_hash.store(key, val) # a shallow copy is better than nothing
|
234
|
+
end
|
235
|
+
end
|
236
|
+
# ~iteration of instance variables
|
237
|
+
|
238
|
+
json_hash
|
239
|
+
end
|
240
|
+
# ~Serializer.serialize
|
241
|
+
|
242
|
+
##
|
243
|
+
# Returns the given +node+ as pretty-printed JSON.
|
244
|
+
#
|
245
|
+
# @param node [#to_s] A visible attribute of +obj+.
|
246
|
+
# @param obj [{Object => Object}, <Object>] The enumerable object containing +node+.
|
247
|
+
# @return [String] A formatted string representation of +node+.
|
248
|
+
def self.format_node(node, obj)
|
249
|
+
str = ''
|
250
|
+
|
251
|
+
if node.instance_of?(Array)
|
252
|
+
str << "\n\t[\n"
|
253
|
+
|
254
|
+
node.each do |elem|
|
255
|
+
if elem.instance_of?(Hash)
|
256
|
+
str << "\t\t{\n"
|
257
|
+
|
258
|
+
elem.each_with_index do |inner_h, h_idx|
|
259
|
+
str << "\t\t\t\"#{inner_h.first}\":"
|
260
|
+
str << node_to_str(inner_h.last)
|
261
|
+
str << ', ' unless h_idx == (elem.to_a.length - 1)
|
262
|
+
str << "\n"
|
263
|
+
end
|
264
|
+
|
265
|
+
str << "\t\t}"
|
266
|
+
str << ',' unless node.index(elem) == (node.length - 1)
|
267
|
+
str << "\n" unless node.index(elem) == (node.length - 1)
|
268
|
+
|
269
|
+
else
|
270
|
+
|
271
|
+
if elem.instance_of?(Array) && elem.any? { |e| e.instance_of?(Array) }
|
272
|
+
@margins_to_backspace = elem.take_while { |e| e.instance_of?(Array) }.size
|
273
|
+
end
|
274
|
+
|
275
|
+
str << "\t\t"
|
276
|
+
str << node_to_str(elem)
|
277
|
+
str << ",\n" unless node.index(elem) == (node.length - 1)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
str << "\n\t]\n"
|
282
|
+
|
283
|
+
elsif node.instance_of?(Hash)
|
284
|
+
str << "\n\t{\n"
|
285
|
+
|
286
|
+
node.each_with_index do |h, idx|
|
287
|
+
if h.last.instance_of?(Hash)
|
288
|
+
key = if h.first.eql? ''
|
289
|
+
"\t\t\"<##{h.last.class.name.downcase}>\":"
|
290
|
+
else
|
291
|
+
"\t\t\"#{h.first}\":"
|
292
|
+
end
|
293
|
+
str << key
|
294
|
+
str << "\n\t\t\t{\n"
|
295
|
+
|
296
|
+
h.last.each_with_index do |inner_h, inner_h_idx|
|
297
|
+
str << "\t\t\t\t\"#{inner_h.first}\":"
|
298
|
+
str << node_to_str(inner_h.last, 4)
|
299
|
+
str << ",\n" unless inner_h_idx == (h.last.to_a.length - 1)
|
300
|
+
end
|
301
|
+
|
302
|
+
str << "\n\t\t\t}"
|
303
|
+
else
|
304
|
+
str << "\t\t\"#{h.first}\": "
|
305
|
+
str << node_to_str(h.last)
|
306
|
+
end
|
307
|
+
|
308
|
+
str << ",\n" unless idx == (node.to_a.length - 1)
|
309
|
+
end
|
310
|
+
|
311
|
+
str << "\n\t}"
|
312
|
+
str << ', ' unless (obj.length <= 1) || \
|
313
|
+
((obj.length > 1) && \
|
314
|
+
(obj.instance_of?(Hash) && \
|
315
|
+
(obj.key(obj.values.last) === obj.key(node))) || \
|
316
|
+
(obj.instance_of?(Array) && (obj.last == node)))
|
317
|
+
str << "\n"
|
318
|
+
|
319
|
+
else
|
320
|
+
str << node_to_str(node)
|
321
|
+
str << ', ' unless (obj.length <= 1) || \
|
322
|
+
((obj.length > 1) && \
|
323
|
+
(obj.instance_of?(Hash) && \
|
324
|
+
(obj.key(obj.values.last) === obj.key(node))) || \
|
325
|
+
(obj.instance_of?(Array) && (obj.last === node)))
|
326
|
+
str << "\n"
|
327
|
+
end
|
328
|
+
|
329
|
+
str.gsub(/\t+[\n\r]+/, '').gsub(/\}\,+/, '},').gsub(/\]\,+/, '],')
|
330
|
+
end
|
331
|
+
# ~Serializer.format_node
|
332
|
+
|
333
|
+
##
|
334
|
+
# Returns a JSON-appropriate string representation of +node+.
|
335
|
+
#
|
336
|
+
# @param node [#to_s] A visible attribute of a Ruby object.
|
337
|
+
# @param tabs [Fixnum] Tab width at which to start printing this node.
|
338
|
+
# @return [String] A formatted string representation of +node+.
|
339
|
+
def self.node_to_str(node, tabs = 0)
|
340
|
+
graft = ''
|
341
|
+
|
342
|
+
tabs += 2 if tabs.zero?
|
343
|
+
if @should_backspace
|
344
|
+
tabs -= 1
|
345
|
+
@margins_to_backspace -= 1
|
346
|
+
end
|
347
|
+
|
348
|
+
if node.nil? then graft << 'null'
|
349
|
+
elsif node.instance_of?(Hash)
|
350
|
+
|
351
|
+
format_node(node, node).scan(/.*$/) do |n|
|
352
|
+
graft << "\n" << ("\t" * tabs).to_s << n
|
353
|
+
end
|
354
|
+
|
355
|
+
elsif node.instance_of?(Array)
|
356
|
+
@should_backspace = @margins_to_backspace.positive?
|
357
|
+
|
358
|
+
format_node(node, {}).scan(/.*$/) do |n|
|
359
|
+
graft << "\n" << ("\t" * tabs).to_s << n
|
360
|
+
end
|
361
|
+
|
362
|
+
elsif !node.instance_of?(String) then graft << node.to_s
|
363
|
+
else graft << "\"#{node.gsub(/\"/, '\\"')}\""
|
364
|
+
end
|
365
|
+
|
366
|
+
graft.rstrip
|
367
|
+
end
|
368
|
+
# ~Serializer.node_to_str
|
369
|
+
end
|
370
|
+
# ~Serializer
|
371
|
+
|
372
|
+
private_constant :Serializer
|
373
|
+
end
|
374
|
+
# ~TidyJson
|
375
|
+
|
376
|
+
##
|
377
|
+
# Exposes the +TidyJson+ mixin to all Ruby objects.
|
378
|
+
# ====
|
379
|
+
# class Object
|
380
|
+
# include TidyJson
|
381
|
+
# end
|
382
|
+
class Object
|
383
|
+
include TidyJson
|
384
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'tidy_json'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Tests.
|
6
|
+
#
|
7
|
+
class JsonableObject
|
8
|
+
attr_reader(:h, :a)
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@h = { one: 'uno', two: 'dos', three: %w[eine zwei drei], cuatro: ['I', 'II', 'III', ['i.', 'ii.', 'iii.', 'iv.']] }
|
12
|
+
@a = ['k', 'l', %w[M N O P], 'q', 'r', 's', [10, 456, ['<abbr title="Reel 2, Dialog Track 2">R2D2</abbr>', 'R', 2, 'D', ['two']]], 'u', 'v', 'x', 'y', %w[Z AB]]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TidyJsonTest < Minitest::Test
|
17
|
+
@@t = JsonableObject.new
|
18
|
+
@@t2 = JsonableObject.new
|
19
|
+
@@t3 = JsonableObject.new
|
20
|
+
@@t.h[:cinque] = { 'ichi' => "\u{4e00}", 'ni' => "\u{4e8c}", 'san' => "\u{4e09}", 'yon' => "\u{56db}" }
|
21
|
+
@@t.h[:sei] = @@t2
|
22
|
+
@@t2.h[:five] = @@t3
|
23
|
+
@@t.a.unshift([@@t2, 13, 14, 15, 5.6])
|
24
|
+
|
25
|
+
def test_version_number
|
26
|
+
refute_nil ::TidyJson::VERSION
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_tidy_static
|
30
|
+
assert_equal(TidyJson.tidy(a: 'one', A: 'ONE', b: nil), "{\n\"a\": \"one\", \n\"A\": \"ONE\", \n\"b\": null\n}\n")
|
31
|
+
assert_equal(TidyJson.tidy({}).length, 4)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_tidy_instance
|
35
|
+
assert_equal({}.to_tidy_json, "{\n}\n")
|
36
|
+
assert_equal(JsonableObject.new.to_tidy_json.length, 568)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_stringify_instance
|
40
|
+
assert_equal(@@t.stringify, "{\"class\":\"JsonableObject\",\"h\":{\"one\":\"uno\",\"two\":\"dos\",\"three\":[\"eine\",\"zwei\",\"drei\"],\"cuatro\":[\"I\",\"II\",\"III\",[\"i.\",\"ii.\",\"iii.\",\"iv.\"]],\"cinque\":{\"ichi\":\"\u{4e00}\",\"ni\":\"\u{4e8c}\",\"san\":\"\u{4e09}\",\"yon\":\"\u{56db}\"},\"sei\":{\"class\":\"JsonableObject\",\"h\":{\"one\":\"uno\",\"two\":\"dos\",\"three\":[\"eine\",\"zwei\",\"drei\"],\"cuatro\":[\"I\",\"II\",\"III\",[\"i.\",\"ii.\",\"iii.\",\"iv.\"]],\"five\":{\"class\":\"JsonableObject\",\"h\":{\"one\":\"uno\",\"two\":\"dos\",\"three\":[\"eine\",\"zwei\",\"drei\"],\"cuatro\":[\"I\",\"II\",\"III\",[\"i.\",\"ii.\",\"iii.\",\"iv.\"]]},\"a\":[\"k\",\"l\",[\"M\",\"N\",\"O\",\"P\"],\"q\",\"r\",\"s\",[10,456,[\"<abbr title=\\\"Reel 2, Dialog Track 2\\\">R2D2</abbr>\",\"R\",2,\"D\",[\"two\"]]],\"u\",\"v\",\"x\",\"y\",[\"Z\",\"AB\"]]}},\"a\":[\"k\",\"l\",[\"M\",\"N\",\"O\",\"P\"],\"q\",\"r\",\"s\",[10,456,[\"<abbr title=\\\"Reel 2, Dialog Track 2\\\">R2D2</abbr>\",\"R\",2,\"D\",[\"two\"]]],\"u\",\"v\",\"x\",\"y\",[\"Z\",\"AB\"]]}},\"a\":[{\"class\":\"JsonableObject\",\"h\":{\"one\":\"uno\",\"two\":\"dos\",\"three\":[\"eine\",\"zwei\",\"drei\"],\"cuatro\":[\"I\",\"II\",\"III\",[\"i.\",\"ii.\",\"iii.\",\"iv.\"]],\"five\":{\"class\":\"JsonableObject\",\"h\":{\"one\":\"uno\",\"two\":\"dos\",\"three\":[\"eine\",\"zwei\",\"drei\"],\"cuatro\":[\"I\",\"II\",\"III\",[\"i.\",\"ii.\",\"iii.\",\"iv.\"]]},\"a\":[\"k\",\"l\",[\"M\",\"N\",\"O\",\"P\"],\"q\",\"r\",\"s\",[10,456,[\"<abbr title=\\\"Reel 2, Dialog Track 2\\\">R2D2</abbr>\",\"R\",2,\"D\",[\"two\"]]],\"u\",\"v\",\"x\",\"y\",[\"Z\",\"AB\"]]}},\"a\":[\"k\",\"l\",[\"M\",\"N\",\"O\",\"P\"],\"q\",\"r\",\"s\",[10,456,[\"<abbr title=\\\"Reel 2, Dialog Track 2\\\">R2D2</abbr>\",\"R\",2,\"D\",[\"two\"]]],\"u\",\"v\",\"x\",\"y\",[\"Z\",\"AB\"]]},[13,14,15,5.6],\"k\",\"l\",[\"M\",\"N\",\"O\",\"P\"],\"q\",\"r\",\"s\",[10,456,[\"<abbr title=\\\"Reel 2, Dialog Track 2\\\">R2D2</abbr>\",\"R\",2,\"D\",[\"two\"]]],\"u\",\"v\",\"x\",\"y\",[\"Z\",\"AB\"]]}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_writers
|
44
|
+
output = @@t.write_json(false)
|
45
|
+
assert(File.exist?(output))
|
46
|
+
pretty_output = @@t.write_json(true, 'prettified')
|
47
|
+
assert(File.exist?(pretty_output))
|
48
|
+
end
|
49
|
+
end
|
data/tidy_json.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative 'lib/tidy_json/version'
|
2
|
+
require_relative 'lib/tidy_json/dedication'
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = 'tidy_json'
|
6
|
+
spec.version = TidyJson::VERSION
|
7
|
+
spec.date = Time.now.to_s[0..9].to_s
|
8
|
+
spec.summary = 'Serialize any Ruby object as readable JSON'
|
9
|
+
spec.description = 'A mixin providing (recursive) JSON serialization and pretty printing.'
|
10
|
+
spec.authors = ['Robert Di Pardo']
|
11
|
+
spec.email = 'rdipardo0520@conestogac.on.ca'
|
12
|
+
spec.homepage = 'https://github.com/rdipardo/tidy_json'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
15
|
+
['.yardopts'].concat(`git ls-files -z`.split("\x0").reject { |f| f.match(/^(\.[\w+\.]+|test|spec|features)/) })
|
16
|
+
end
|
17
|
+
spec.test_files = Dir['test/*']
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
20
|
+
spec.add_runtime_dependency 'json', '~> 2.2'
|
21
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
22
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
23
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
24
|
+
spec.rdoc_options = ['-x test/*']
|
25
|
+
spec.post_install_message = TidyJson::DEDICATION
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tidy_json
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert Di Pardo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-12-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.9'
|
69
|
+
description: A mixin providing (recursive) JSON serialization and pretty printing.
|
70
|
+
email: rdipardo0520@conestogac.on.ca
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- ".yardopts"
|
76
|
+
- Gemfile
|
77
|
+
- LICENSE
|
78
|
+
- README.md
|
79
|
+
- Rakefile
|
80
|
+
- lib/tidy_json.rb
|
81
|
+
- lib/tidy_json/dedication.rb
|
82
|
+
- lib/tidy_json/version.rb
|
83
|
+
- test/test_tidy_json.rb
|
84
|
+
- tidy_json.gemspec
|
85
|
+
homepage: https://github.com/rdipardo/tidy_json
|
86
|
+
licenses:
|
87
|
+
- MIT
|
88
|
+
metadata: {}
|
89
|
+
post_install_message: |
|
90
|
+
..................................................
|
91
|
+
.................... tidy_json ...................
|
92
|
+
............ (c) 2019 Robert Di Pardo ............
|
93
|
+
..................................................
|
94
|
+
................... IN MEMORIAM ..................
|
95
|
+
................ Michael Di Pardo ................
|
96
|
+
................... 1950 - 2019 ..................
|
97
|
+
..................................................
|
98
|
+
............ Please consider supporting ...........
|
99
|
+
............. the MS Society of Canada ...........
|
100
|
+
........ https://mssociety.ca/get-involved .......
|
101
|
+
..................................................
|
102
|
+
rdoc_options:
|
103
|
+
- "-x test/*"
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 2.3.0
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubygems_version: 3.1.1
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: Serialize any Ruby object as readable JSON
|
121
|
+
test_files:
|
122
|
+
- test/test_tidy_json.rb
|