neatjson 0.9 → 0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 993364bb8a9a2afda35c7a298954472e96bb3e0d
4
- data.tar.gz: 781ace75559493a25110d01b51471bfee5304cca
2
+ SHA256:
3
+ metadata.gz: d2820b11ac77b92de38f28231d4826cd1e77ad0f9140da5b9e41eaf995dee5ce
4
+ data.tar.gz: b5cdc8378b227f574f8de0d517e7964ca6cfe96e40ff30873d6a412cda5844f4
5
5
  SHA512:
6
- metadata.gz: f65b6adc2a60f76b2ab0b18824d9f5586cf411db7efe2a59004df1848168af390f3572e35bcc41b4df276e35d970591860eeb7b5f3f9f62ccbdc0f92e6edb15c
7
- data.tar.gz: e3de0825b58bbf313414e64508df9113c174ca5cfd9c9f9e73b5dc007eba0429b222d82c18ec7d6f53c248e0ac96a3e8c92ced94de1884605b5337ae418a2a8d
6
+ metadata.gz: 1681f5edb27ec6075e5bfd1d9c8a9e806b3ee4d2f76dea65d97a45d5b22fa4feefa20b2507ff060dd424cca346b4bee6ebdcd05735543dde71170f4ad2d55125
7
+ data.tar.gz: 14a3138ab4eb40fce7f9052e250f7c1ca7394c460b3d3f4cc8ccd87d8b91bed870d395719c3c3a0343990284af37589ef5e3abc86bd0f58c2b40ed946197c8ba
data/LICENSE.txt CHANGED
@@ -1,7 +1,7 @@
1
- Copyright (c) 2015-2018 Gavin Kistner
1
+ Copyright (c) 2015-2019 Gavin Kistner
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
5
5
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
6
 
7
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -189,29 +189,33 @@ var json = neatJSON( myValue, { arrayPadding:1, afterComma:1, beforeColonN:2, in
189
189
  local json = neatJSON( myValue, { arrayPadding=1, afterComma=1, beforeColonN=2, indentLast=true } )
190
190
  ~~~
191
191
 
192
- * `wrap` — Maximum line width before wrapping. Use `false` to never wrap, `true` to always wrap. default:`80`
193
- * `indent` — Whitespace used to indent each level when wrapping. default:`" "` (two spaces)
194
- * `indent_last` — Indent the closing bracket/brace for arrays and objects? default:`false`
195
- * `short` — Put opening brackets on the same line as the first value, closing brackets on the same line as the last? default:`false`
192
+ * `wrap` — Maximum line width before wrapping. Use `false` to never wrap, `true` to always wrap. default:`80`
193
+ * `indent` — Whitespace used to indent each level when wrapping. default:`" "` (two spaces)
194
+ * `indent_last` — Indent the closing bracket/brace for arrays and objects? default:`false`
195
+ * `short` — Put opening brackets on the same line as the first value, closing brackets on the same line as the last? default:`false`
196
196
  * _This causes the `indent` and `indent_last` options to be ignored, instead basing indentation on array and object padding._
197
- * `sort` — Sort objects' keys in alphabetical order (`true`), or supply a lambda for custom sorting. default:`false`
197
+ * `sort` — Sort objects' keys in alphabetical order (`true`), or supply a lambda for custom sorting. default:`false`
198
198
  * If you supply a lambda to the `sort` option, it will be passed three values: the (string) name of the key, the associated value, and the object being sorted, e.g. `{ sort:->(key,value,hash){ Float(value) rescue Float::MAX } }`
199
- * `aligned` — When wrapping objects, line up the colons (per object)? default:`false`
200
- * `decimals` — Decimal precision for non-integer numbers; use `false` to keep values precise. default:`false`
201
- * `array_padding` Number of spaces to put inside brackets for arrays. default:`0`
202
- * `object_padding` Number of spaces to put inside braces for objects. default:`0`
203
- * `padding` Shorthand to set both `array_padding` and `object_padding`. default:`0`
204
- * `before_comma` — Number of spaces to put before commas (for both arrays and objects). default:`0`
205
- * `after_comma` — Number of spaces to put after commas (for both arrays and objects). default:`0`
206
- * `around_comma` Shorthand to set both `before_comma` and `after_comma`. default:`0`
207
- * `before_colon_1` Number of spaces before a colon when the object is on one line. default:`0`
208
- * `after_colon_1` — Number of spaces after a colon when the object is on one line. default:`0`
209
- * `before_colon_n` — Number of spaces before a colon when the object is on multiple lines. default:`0`
210
- * `after_colon_n` Number of spaces after a colon when the object is on multiple lines. default:`0`
211
- * `before_colon` Shorthand to set both `before_colon_1` and `before_colon_n`. default:`0`
212
- * `after_colon` Shorthand to set both `after_colon_1` and `after_colon_n`. default:`0`
213
- * `around_colon` Shorthand to set both `before_colon` and `after_colon`. default:`0`
214
- * `lua` (Lua only) Output a Lua table literal instead of JSON? default:`false`
199
+ * `aligned` — When wrapping objects, line up the colons (per object)? default:`false`
200
+ * `decimals` — Decimal precision for non-integer numbers; use `false` to keep values precise. default:`false`
201
+ * `trim_trailing_zeros` Remove extra zeros at the end of floats, e.g. `1.2000` becomes `1.2`. default:`false`
202
+ * `force_floats` Force every integer value written to the file to be a float, e.g. `12` becomes `12.0`. default:`false`
203
+ * `force_floats_in` Specify an array of object key names under which all integer values are treated as floats.
204
+ For example, serializing `{a:[1, 2, {a:3, b:4}], c:{a:5, d:6}` with `force_floats_in:['a']` would produce `{"a":[1.0, 2.0, {"a":3.0, "b":4}], "c":{"a":5.0, "d":6}}`.
205
+ * `array_padding` — Number of spaces to put inside brackets for arrays. default:`0`
206
+ * `object_padding` Number of spaces to put inside braces for objects. default:`0`
207
+ * `padding` Shorthand to set both `array_padding` and `object_padding`. default:`0`
208
+ * `before_comma` — Number of spaces to put before commas (for both arrays and objects). default:`0`
209
+ * `after_comma` — Number of spaces to put after commas (for both arrays and objects). default:`0`
210
+ * `around_comma` Shorthand to set both `before_comma` and `after_comma`. default:`0`
211
+ * `before_colon_1` Number of spaces before a colon when the object is on one line. default:`0`
212
+ * `after_colon_1` Number of spaces after a colon when the object is on one line. default:`0`
213
+ * `before_colon_n` Number of spaces before a colon when the object is on multiple lines. default:`0`
214
+ * `after_colon_n` Number of spaces after a colon when the object is on multiple lines. default:`0`
215
+ * `before_colon` — Shorthand to set both `before_colon_1` and `before_colon_n`. default:`0`
216
+ * `after_colon` — Shorthand to set both `after_colon_1` and `after_colon_n`. default:`0`
217
+ * `around_colon` — Shorthand to set both `before_colon` and `after_colon`. default:`0`
218
+ * `lua` — (Lua only) Output a Lua table literal instead of JSON? default:`false`
215
219
  * `emptyTablesAreObjects` — (Lua only) Should `{}` in Lua become a JSON object (`{}`) or JSON array (`[]`)? default:`false` (array)
216
220
 
217
221
  You may omit the 'value' and/or 'object' parameters in your `sort` lambda if desired. For example:
@@ -257,7 +261,7 @@ _Note that the JavaScript and Lua versions of NeatJSON do not provide a mechanis
257
261
 
258
262
  ## License & Contact
259
263
 
260
- NeatJSON is copyright ©2015–2019 by Gavin Kistner and is released under
264
+ NeatJSON is copyright ©2015–2022 by Gavin Kistner and is released under
261
265
  the [MIT License](http://www.opensource.org/licenses/mit-license.php).
262
266
  See the LICENSE.txt file for more details.
263
267
 
@@ -274,6 +278,11 @@ For other communication you can [email the author directly](mailto:!@phrogz.net?
274
278
 
275
279
  ## HISTORY
276
280
 
281
+ * **v0.10** — August 29, 2022
282
+ * Add `force_floats` and `force_floats_in` to support serialization for non-standard parsers that differentiate between integers and floats.
283
+ * Add `trim_trailing_zeros` option to convert the `decimals` output from e.g. `5.40000` to `5.4`.
284
+ * Convert JavaScript version to require ECMAScript 6 for performance.
285
+
277
286
  * **v0.9** — July 29, 2019
278
287
  * Add Lua version, serializing to both JSON and Lua table literals
279
288
  * All languages serialize Infinity/-Infinity to JSON as `9e9999` and `-9e9999`
data/lib/neatjson.rb CHANGED
@@ -6,13 +6,16 @@ module JSON
6
6
  # @author Gavin Kistner <!@phrogz.net>
7
7
  # @param object [Object] the object to serialize
8
8
  # @param opts [Hash] the formatting options
9
- # @option opts [Integer] :wrap (80) The maximum line width before wrapping. Use `false` to never wrap, or `true` to always wrap.
10
- # @option opts [String] :indent (" ") Whitespace used to indent each level when wrapping (without the :short option).
11
- # @option opts [Boolean] :indent_last (false) Indent the closing bracket for arrays and objects (without the :short option).
12
- # @option opts [Boolean] :short (false) Keep the output 'short' when wrapping, putting opening brackets on the same line as the first value, and closing brackets on the same line as the last item.
13
- # @option opts [Boolean] :sort (false) Sort the keys for objects to be in alphabetical order (`true`), or supply a lambda to determine ordering.
14
- # @option opts [Boolean] :aligned (false) When wrapping objects, align the colons (only per object).
15
- # @option opts [Integer] :decimals (null) Decimal precision to use for floats; omit to keep numberic values precise.
9
+ # @option opts [Integer] :wrap (80) The maximum line width before wrapping. Use `false` to never wrap, or `true` to always wrap.
10
+ # @option opts [String] :indent (" ") Whitespace used to indent each level when wrapping (without the :short option).
11
+ # @option opts [Boolean] :indent_last (false) Indent the closing bracket for arrays and objects (without the :short option).
12
+ # @option opts [Boolean] :short (false) Keep the output 'short' when wrapping, putting opening brackets on the same line as the first value, and closing brackets on the same line as the last item.
13
+ # @option opts [Boolean] :sort (false) Sort the keys for objects to be in alphabetical order (`true`), or supply a lambda to determine ordering.
14
+ # @option opts [Boolean] :aligned (false) When wrapping objects, align the colons (only per object).
15
+ # @option opts [Boolean] :force_floats (false) Ensure that all integer values have `.0` after them.
16
+ # @option opts [Array] :force_floats_in ([]) Array of object key names to force floats inside of.
17
+ # @option opts [Integer] :decimals (null) Decimal precision to use for floats; omit to keep numeric values precise.
18
+ # @option opts [Boolean] :trim_trailing_zeros (false) Remove trailing zeros added by `decimals`` from the ends of floating point numbers.
16
19
  # @option opts [Integer] :padding (0) Number of spaces to put inside brackets/braces for both arrays and objects.
17
20
  # @option opts [Integer] :array_padding (0) Number of spaces to put inside brackets for arrays. Overrides `:padding`.
18
21
  # @option opts [Integer] :object_padding (0) Number of spaces to put inside braces for objects. Overrides `:padding`.
@@ -37,6 +40,7 @@ module JSON
37
40
  opts[:wrap] = 80 unless opts.key?(:wrap)
38
41
  opts[:wrap] = -1 if opts[:wrap]==true
39
42
  opts[:indent] ||= " "
43
+ opts[:force_floats_in]||= []
40
44
  opts[:array_padding] ||= opts[:padding] || 0
41
45
  opts[:object_padding] ||= opts[:padding] || 0
42
46
  opts[:after_comma] ||= opts[:around_comma] || 0
@@ -56,21 +60,27 @@ module JSON
56
60
  colonn= "#{' '*opts[:before_colon_n]}:#{' '*opts[:after_colon_n]}"
57
61
 
58
62
  memoizer = {}
59
- build = ->(o,indent) do
60
- memoizer[[o,indent]] ||= case o
61
- when String,Integer then "#{indent}#{o.inspect}"
63
+ build = ->(o,indent,floats_forced) do
64
+ memoizer[[o,indent,floats_forced]] ||= case o
65
+ when String then "#{indent}#{o.inspect}"
62
66
  when Symbol then "#{indent}#{o.to_s.inspect}"
63
67
  when TrueClass,FalseClass then "#{indent}#{o}"
64
68
  when NilClass then "#{indent}null"
69
+ when Integer
70
+ floats_forced ? build[o.to_f, indent, floats_forced] : "#{indent}#{o.inspect}"
65
71
  when Float
66
72
  if o.infinite?
67
73
  "#{indent}#{o<0 ? "-9e9999" : "9e9999"}"
68
74
  elsif o.nan?
69
75
  "#{indent}\"NaN\""
70
- elsif (o==o.to_i) && (o.to_s !~ /e/)
71
- build[o.to_i,indent]
76
+ elsif !floats_forced && (o==o.to_i) && (o.to_s !~ /e/)
77
+ build[o.to_i, indent, floats_forced]
72
78
  elsif opts[:decimals]
73
- "#{indent}%.#{opts[:decimals]}f" % o
79
+ if opts[:trim_trailing_zeros]
80
+ "#{indent}#{o.round(opts[:decimals])}"
81
+ else
82
+ "#{indent}%.#{opts[:decimals]}f" % o
83
+ end
74
84
  else
75
85
  "#{indent}#{o}"
76
86
  end
@@ -79,19 +89,19 @@ module JSON
79
89
  if o.empty?
80
90
  "#{indent}[]"
81
91
  else
82
- pieces = o.map{ |v| build[v,''] }
92
+ pieces = o.map{ |v| build[v, '', floats_forced] }
83
93
  one_line = "#{indent}[#{apad}#{pieces.join comma}#{apad}]"
84
94
  if !opts[:wrap] || (one_line.length <= opts[:wrap])
85
95
  one_line
86
96
  elsif opts[:short]
87
97
  indent2 = "#{indent} #{apad}"
88
- pieces = o.map{ |v| build[ v,indent2 ] }
98
+ pieces = o.map{ |v| build[v, indent2, floats_forced] }
89
99
  pieces[0] = pieces[0].sub indent2, "#{indent}[#{apad}"
90
100
  pieces[pieces.length-1] = "#{pieces.last}#{apad}]"
91
101
  pieces.join ",\n"
92
102
  else
93
103
  indent2 = "#{indent}#{opts[:indent]}"
94
- "#{indent}[\n#{o.map{ |v| build[ v, indent2 ] }.join ",\n"}\n#{opts[:indent_last] ? indent2 : indent}]"
104
+ "#{indent}[\n#{o.map{ |v| build[v, indent2, floats_forced] }.join ",\n"}\n#{opts[:indent_last] ? indent2 : indent}]"
95
105
  end
96
106
  end
97
107
 
@@ -108,7 +118,8 @@ module JSON
108
118
  when 3 then o.sort_by{ |k,v| sort[k,v,o] }
109
119
  end
110
120
  end
111
- keyvals = o.map{ |k,v| [ k.to_s.inspect, build[v,''] ] }
121
+ keys = o.map{|x| x.first.to_s }
122
+ keyvals = o.map.with_index{ |(k,v),i| [ k.to_s.inspect, build[v, '', opts[:force_floats] || opts[:force_floats_in].include?(keys[i])] ] }
112
123
  keyvals = keyvals.map{ |kv| kv.join(colon1) }.join(comma)
113
124
  one_line = "#{indent}{#{opad}#{keyvals}#{opad}}"
114
125
  if !opts[:wrap] || (one_line.length <= opts[:wrap])
@@ -122,11 +133,12 @@ module JSON
122
133
  formatk = "%-#{longest}s"
123
134
  keyvals.map!{ |k,v| [ formatk % k,v] }
124
135
  end
125
- keyvals.map! do |k,v|
136
+ keyvals.map!.with_index do |(k,v),i|
137
+ floats_forced = opts[:force_floats] || opts[:force_floats_in].include?(keys[i])
126
138
  indent2 = " "*"#{k}#{colonn}".length
127
- one_line = "#{k}#{colonn}#{build[v,'']}"
139
+ one_line = "#{k}#{colonn}#{build[v, '', floats_forced]}"
128
140
  if opts[:wrap] && (one_line.length > opts[:wrap]) && (v.is_a?(Array) || v.is_a?(Hash))
129
- "#{k}#{colonn}#{build[v,indent2].lstrip}"
141
+ "#{k}#{colonn}#{build[v, indent2, floats_forced].lstrip}"
130
142
  else
131
143
  one_line
132
144
  end
@@ -141,9 +153,9 @@ module JSON
141
153
  end
142
154
  indent2 = "#{indent}#{opts[:indent]}"
143
155
  keyvals.map! do |k,v|
144
- one_line = "#{k}#{colonn}#{build[v,'']}"
156
+ one_line = "#{k}#{colonn}#{build[v, '', floats_forced]}"
145
157
  if opts[:wrap] && (one_line.length > opts[:wrap]) && (v.is_a?(Array) || v.is_a?(Hash))
146
- "#{k}#{colonn}#{build[v,indent2].lstrip}"
158
+ "#{k}#{colonn}#{build[v, indent2, floats_forced].lstrip}"
147
159
  else
148
160
  one_line
149
161
  end
@@ -158,6 +170,6 @@ module JSON
158
170
  end
159
171
  end
160
172
 
161
- build[object,'']
173
+ build[object, '', opts[:force_floats]]
162
174
  end
163
175
  end
data/neatjson.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
  require 'date'
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "neatjson"
5
- s.version = "0.9"
5
+ s.version = "0.10"
6
6
  s.date = Date.today.iso8601
7
7
  s.authors = ["Gavin Kistner"]
8
8
  s.email = "gavin@phrogz.net"
@@ -1,83 +1,83 @@
1
- local function dump(v)
2
- local reserved = {["and"]=1,["break"]=1,["do"]=1,["else"]=1,["elseif"]=1,["end"]=1,["false"]=1,["for"]=1,["function"]=1,["goto"]=1,["if"]=1,["in"]=1,["local"]=1,["nil"]=1,["not"]=1,["or"]=1,["repeat"]=1,["return"]=1,["then"]=1,["true"]=1,["until"]=1,["while"]=1}
3
- local t=type(v)
4
- if t=='table' then
5
- local s,r={},{}
6
- for i,v2 in ipairs(v) do s[i]=true table.insert(r,dump(v2)) end
7
- for k,v2 in pairs(v) do
8
- if not s[k] then
9
- if type(k)=='string' and not reserved[k] and string.match(k,'^[%a_][%w_]*$') then
10
- table.insert(r,k..'='..dump(v2))
11
- else
12
- table.insert(r,'['..dump(k)..']='..dump(v2))
13
- end
14
- end
15
- end
16
- return '{'..table.concat(r,', ')..'}'
17
- elseif t=='string' then
18
- return string.format('%q',v)
19
- else
20
- return tostring(v)
21
- end
22
- end
23
-
24
-
25
- package.path = '?.lua;../lua/?.lua'
26
- local tests = require'tests'
27
- local neatJSON = require'neatjson'
28
- local startTime = os.clock()
29
- local count,pass=0,0
30
- for _,valtest in ipairs(tests) do
31
- local value = valtest.value
32
- for _,test in ipairs(valtest.tests) do
33
- local cmd = "neatJSON("..dump(value)..(test.opts and (", "..dump(test.opts)) or '')..")"
34
- local ok,err = pcall(function()
35
- local json, success
36
- if test.opts then
37
- local opts = {}
38
- for k,v in pairs(test.opts) do opts[k]=v end
39
- json = neatJSON(value,opts)
40
- else
41
- json = neatJSON(value)
42
- end
43
-
44
- if type(test.json)=='string' then
45
- success = json==test.json
46
- else
47
- -- If it's not a string, assume it's an array of acceptable string patterns
48
- success = false
49
- for _,testPattern in ipairs(test.json) do
50
- if json:match(testPattern) then
51
- success = true
52
- break
53
- end
54
- end
55
- end
56
-
57
- if success then
58
- pass = pass + 1
59
- else
60
- local expected = type(test.json)=='string' and test.json or table.concat(test.json, ' or ')
61
- print(cmd)
62
- print('EXPECTED')
63
- print(expected)
64
- print('ACTUAL')
65
- print(json==nil and '(nil)' or #json==0 and '(empty string)' or json)
66
- print('')
67
- end
68
- end)
69
- if not ok then
70
- print('Error running '..cmd)
71
- print(err)
72
- print('')
73
- end
74
- count = count + 1
75
- end
76
- end
77
- local elapsed = os.clock()-startTime
78
- print(("%d/%d test%s passed in %.2fms (%.0f tests per second)"):format(
79
- pass, count,
80
- count==1 and '' or 's',
81
- elapsed,
82
- 1000 * count/elapsed
83
- ))
1
+ local function dump(v)
2
+ local reserved = {["and"]=1,["break"]=1,["do"]=1,["else"]=1,["elseif"]=1,["end"]=1,["false"]=1,["for"]=1,["function"]=1,["goto"]=1,["if"]=1,["in"]=1,["local"]=1,["nil"]=1,["not"]=1,["or"]=1,["repeat"]=1,["return"]=1,["then"]=1,["true"]=1,["until"]=1,["while"]=1}
3
+ local t=type(v)
4
+ if t=='table' then
5
+ local s,r={},{}
6
+ for i,v2 in ipairs(v) do s[i]=true table.insert(r,dump(v2)) end
7
+ for k,v2 in pairs(v) do
8
+ if not s[k] then
9
+ if type(k)=='string' and not reserved[k] and string.match(k,'^[%a_][%w_]*$') then
10
+ table.insert(r,k..'='..dump(v2))
11
+ else
12
+ table.insert(r,'['..dump(k)..']='..dump(v2))
13
+ end
14
+ end
15
+ end
16
+ return '{'..table.concat(r,', ')..'}'
17
+ elseif t=='string' then
18
+ return string.format('%q',v)
19
+ else
20
+ return tostring(v)
21
+ end
22
+ end
23
+
24
+
25
+ package.path = '?.lua;../lua/?.lua'
26
+ local tests = require'tests'
27
+ local neatJSON = require'neatjson'
28
+ local startTime = os.clock()
29
+ local count,pass=0,0
30
+ for _,valtest in ipairs(tests) do
31
+ local value = valtest.value
32
+ for _,test in ipairs(valtest.tests) do
33
+ local cmd = "neatJSON("..dump(value)..(test.opts and (", "..dump(test.opts)) or '')..")"
34
+ local ok,err = pcall(function()
35
+ local json, success
36
+ if test.opts then
37
+ local opts = {}
38
+ for k,v in pairs(test.opts) do opts[k]=v end
39
+ json = neatJSON(value,opts)
40
+ else
41
+ json = neatJSON(value)
42
+ end
43
+
44
+ if type(test.json)=='string' then
45
+ success = json==test.json
46
+ else
47
+ -- If it's not a string, assume it's an array of acceptable string patterns
48
+ success = false
49
+ for _,testPattern in ipairs(test.json) do
50
+ if json:match(testPattern) then
51
+ success = true
52
+ break
53
+ end
54
+ end
55
+ end
56
+
57
+ if success then
58
+ pass = pass + 1
59
+ else
60
+ local expected = type(test.json)=='string' and test.json or table.concat(test.json, ' or ')
61
+ print(cmd)
62
+ print('EXPECTED')
63
+ print(expected)
64
+ print('ACTUAL')
65
+ print(json==nil and '(nil)' or #json==0 and '(empty string)' or json)
66
+ print('')
67
+ end
68
+ end)
69
+ if not ok then
70
+ print('Error running '..cmd)
71
+ print(err)
72
+ print('')
73
+ end
74
+ count = count + 1
75
+ end
76
+ end
77
+ local elapsed = os.clock()-startTime
78
+ print(("%d/%d test%s passed in %.2fms (%.0f tests per second)"):format(
79
+ pass, count,
80
+ count==1 and '' or 's',
81
+ elapsed,
82
+ 1000 * count/elapsed
83
+ ))
data/test/tests.js CHANGED
@@ -15,6 +15,9 @@ exports.tests = [
15
15
  {value:5.0001, tests:[
16
16
  {json:"5.0001"},
17
17
  {json:"5.000", opts:{decimals:3}},
18
+ {json:"5", opts:{decimals:3, trimTrailingZeros:true}},
19
+ {json:"5.0", opts:{decimals:3, trimTrailingZeros:true, forceFloats:true}},
20
+ {json:"5.000", opts:{decimals:3, trimTrailingZeros:false, forceFloats:true}},
18
21
  ]},
19
22
  {value:4.2, tests:[
20
23
  {json:"4.2"},
@@ -30,7 +33,6 @@ exports.tests = [
30
33
  {value:-2.4, tests:[{json:"-2", opts:{decimals:0}}]},
31
34
 
32
35
  {value:"foo", tests:[{json:"\"foo\""}]},
33
- // {value: :foo, tests:[{json:"\"foo\""}]},
34
36
  {value:"foo\nbar", tests:[{json:"\"foo\\nbar\""}]},
35
37
 
36
38
  {value:[1,2,3,4,[5,6,7,[8,9,10],11,12]], tests:[
@@ -173,6 +175,33 @@ exports.tests = [
173
175
  { json:'{"inf":9e9999,"nan":"NaN","neginf":-9e9999}', opts:{sort:true} },
174
176
  ]},
175
177
 
178
+ {value:[0, 1, 1.1, 1.555555], tests:[
179
+ { json:'[0,1,1.1,1.555555]', opts:{forceFloats:false} },
180
+ { json:'[0.0,1.0,1.1,1.555555]', opts:{forceFloats:true} },
181
+ { json:'[0.000,1.000,1.100,1.556]', opts:{forceFloats:true, decimals:3} },
182
+ { json:'[0.0,1.0,1.1,1.556]', opts:{forceFloats:true, decimals:3, trimTrailingZeros:true} },
183
+ { json:'[0,1,1.1,1.556]', opts:{forceFloats:false, decimals:3, trimTrailingZeros:true} },
184
+ ]},
185
+
186
+ {value:{floats:[0, 1, 0.1, 1.555555], raw:[0, 1, 0.1, 1.555555]}, tests:[
187
+ { json:'{"floats":[0,1,0.1,1.555555],"raw":[0,1,0.1,1.555555]}', opts:{forceFloats:false} },
188
+ { json:'{"floats":[0.0,1.0,0.1,1.555555],"raw":[0.0,1.0,0.1,1.555555]}', opts:{forceFloats:true} },
189
+ { json:'{"floats":[0.0,1.0,0.1,1.555555],"raw":[0,1,0.1,1.555555]}', opts:{forceFloatsIn:['floats']} },
190
+
191
+ { json:'{"floats":[0,1,0.100,1.556],"raw":[0,1,0.100,1.556]}', opts:{forceFloats:false, decimals:3} },
192
+ { json:'{"floats":[0.000,1.000,0.100,1.556],"raw":[0.000,1.000,0.100,1.556]}', opts:{forceFloats:true, decimals:3} },
193
+ { json:'{"floats":[0.000,1.000,0.100,1.556],"raw":[0,1,0.100,1.556]}', opts:{forceFloatsIn:['floats'], decimals:3} },
194
+
195
+ { json:'{"floats":[0,1,0.1,1.556],"raw":[0,1,0.1,1.556]}', opts:{forceFloats:false, decimals:3, trimTrailingZeros:true} },
196
+ { json:'{"floats":[0.0,1.0,0.1,1.556],"raw":[0.0,1.0,0.1,1.556]}', opts:{forceFloats:true, decimals:3, trimTrailingZeros:true} },
197
+ { json:'{"floats":[0.0,1.0,0.1,1.556],"raw":[0,1,0.1,1.556]}', opts:{forceFloatsIn:['floats'], decimals:3, trimTrailingZeros:true} },
198
+ ]},
199
+
200
+ {value:[1,2,3,{a:[4,5,{a:6, b:7}], b:[8,9,{a:10, b:11}]}], tests:[
201
+ { json:'[1,2,3,{"a":[4,5,{"a":6,"b":7}],"b":[8,9,{"a":10,"b":11}]}]', opts:{} },
202
+ { json:'[1.0,2.0,3.0,{"a":[4.0,5.0,{"a":6.0,"b":7.0}],"b":[8.0,9.0,{"a":10.0,"b":11.0}]}]', opts:{forceFloats:true, wrap:false} },
203
+ { json:'[1,2,3,{"a":[4.0,5.0,{"a":6.0,"b":7}],"b":[8,9,{"a":10.0,"b":11}]}]', opts:{forceFloatsIn:['a'], wrap:false} },
204
+ ]},
176
205
 
177
206
  // {value:Class.new{ def to_json(*a); {a:1}.to_json(*a); end }.new, tests:[
178
207
  // { json:'{ "a":1}' },
data/test/tests.lua CHANGED
@@ -14,6 +14,9 @@ return {
14
14
  {value=5.0001, tests={
15
15
  {json="5.0001"},
16
16
  {json="5.000", opts={decimals=3}},
17
+ {json="5", opts={decimals=3, trimTrailingZeros=true}},
18
+ {json="5.0", opts={decimals=3, trimTrailingZeros=true, forceFloats=true}},
19
+ {json="5.000", opts={decimals=3, trimTrailingZeros=false, forceFloats=true}},
17
20
  }},
18
21
  {value=4.2, tests={
19
22
  {json="4.2"},
@@ -174,11 +177,40 @@ return {
174
177
  }},
175
178
 
176
179
  {value={1,2,3,a=4,['for']=5}, tests={
177
- { json='{[1]=1,[2]=2,[3]=3,a=4,["for"]=5}', opts={lua=true, sort=true} }
180
+ { json='{[1]=1,[2]=2,[3]=3,a=4,["for"]=5}', opts={lua=true, sort=true} },
181
+ { json='{\n [1]=1,\n [2]=2,\n [3]=3,\n a=4,\n ["for"]=5\n}', opts={lua=true, sort=true, wrap=true} },
178
182
  }},
179
183
 
180
184
  {value={inf=1/0, neginf=-1/0, nan=0/0}, tests={
181
185
  { json='{"inf":9e9999,"nan":"NaN","neginf":-9e9999}', opts={sort=true} },
182
186
  { json='{inf=1/0,nan=0/0,neginf=-1/0}', opts={sort=true, lua=true} },
183
- }}
187
+ }},
188
+
189
+ {value={0, 1, 1.1, 1.555555}, tests={
190
+ { json='[0,1,1.1,1.555555]', opts={forceFloats=false} },
191
+ { json='[0.0,1.0,1.1,1.555555]', opts={forceFloats=true} },
192
+ { json='[0.000,1.000,1.100,1.556]', opts={forceFloats=true, decimals=3} },
193
+ { json='[0.0,1.0,1.1,1.556]', opts={forceFloats=true, decimals=3, trimTrailingZeros=true} },
194
+ { json='[0,1,1.1,1.556]', opts={forceFloats=false, decimals=3, trimTrailingZeros=true} },
195
+ }},
196
+
197
+ {value={floats={0, 1, 0.1, 1.555555}, raw={0, 1, 0.1, 1.555555}}, tests={
198
+ { json='{"floats":[0,1,0.1,1.555555],"raw":[0,1,0.1,1.555555]}', opts={forceFloats=false, sort=true} },
199
+ { json='{"floats":[0.0,1.0,0.1,1.555555],"raw":[0.0,1.0,0.1,1.555555]}', opts={forceFloats=true, sort=true} },
200
+ { json='{"floats":[0.0,1.0,0.1,1.555555],"raw":[0,1,0.1,1.555555]}', opts={forceFloatsIn={'floats'}, sort=true} },
201
+
202
+ { json='{"floats":[0,1,0.100,1.556],"raw":[0,1,0.100,1.556]}', opts={forceFloats=false, decimals=3, sort=true} },
203
+ { json='{"floats":[0.000,1.000,0.100,1.556],"raw":[0.000,1.000,0.100,1.556]}', opts={forceFloats=true, decimals=3, sort=true} },
204
+ { json='{"floats":[0.000,1.000,0.100,1.556],"raw":[0,1,0.100,1.556]}', opts={forceFloatsIn={'floats'}, decimals=3, sort=true} },
205
+
206
+ { json='{"floats":[0,1,0.1,1.556],"raw":[0,1,0.1,1.556]}', opts={forceFloats=false, decimals=3, trimTrailingZeros=true, sort=true} },
207
+ { json='{"floats":[0.0,1.0,0.1,1.556],"raw":[0.0,1.0,0.1,1.556]}', opts={forceFloats=true, decimals=3, trimTrailingZeros=true, sort=true} },
208
+ { json='{"floats":[0.0,1.0,0.1,1.556],"raw":[0,1,0.1,1.556]}', opts={forceFloatsIn={'floats'}, decimals=3, trimTrailingZeros=true, sort=true} },
209
+ }},
210
+
211
+ -- {value={1,2,3,{a={4,5,{a=6, b=7}}, b={8,9,{a=10, b=11}}}}, tests={
212
+ -- { json='[1,2,3,{"a":[4,5,{"a":6,"b":7}],"b":[8,9,{"a":10,"b":11}]}]', opts={} },
213
+ -- { json='[1.0,2.0,3.0,{"a":[4.0,5.0,{"a":6.0,"b":7.0}],"b":[8.0,9.0,{"a":10.0,"b":11.0}]}]', opts={forceFloats=true, wrap=false} },
214
+ -- { json='[1,2,3,{"a":[4.0,5.0,{"a":6.0,"b":7}],"b":[8,9,{"a":10.0,"b":11}]}]', opts={forceFloatsIn={'a'}, wrap=false} },
215
+ -- }},
184
216
  }
data/test/tests.rb CHANGED
@@ -13,6 +13,8 @@ TESTS = [
13
13
  {value:5.0001, tests:[
14
14
  {json:"5.0001"},
15
15
  {json:"5.000", opts:{decimals:3}},
16
+ {json:"5.0", opts:{decimals:3, trim_trailing_zeros:true, force_floats:true}},
17
+ {json:"5.000", opts:{decimals:3, trim_trailing_zeros:false, force_floats:true}},
16
18
  ]},
17
19
  {value:4.2, tests:[
18
20
  {json:"4.2"},
@@ -188,5 +190,33 @@ TESTS = [
188
190
  {value:{inf:1.0/0, neginf:-1.0/0, nan:0.0/0}, tests:[
189
191
  { json:'{"inf":9e9999,"nan":"NaN","neginf":-9e9999}', opts:{sort:true} },
190
192
  ]},
193
+
194
+ {value:[0, 1, 1.1, 1.555555], tests:[
195
+ { json:'[0,1,1.1,1.555555]', opts:{force_floats:false} },
196
+ { json:'[0.0,1.0,1.1,1.555555]', opts:{force_floats:true} },
197
+ { json:'[0.000,1.000,1.100,1.556]', opts:{force_floats:true, decimals:3} },
198
+ { json:'[0.0,1.0,1.1,1.556]', opts:{force_floats:true, decimals:3, trim_trailing_zeros:true} },
199
+ { json:'[0,1,1.1,1.556]', opts:{force_floats:false, decimals:3, trim_trailing_zeros:true} },
200
+ ]},
201
+
202
+ {value:{floats:[0, 1, 0.1, 1.555555], raw:[0, 1, 0.1, 1.555555]}, tests:[
203
+ { json:'{"floats":[0,1,0.1,1.555555],"raw":[0,1,0.1,1.555555]}', opts:{force_floats:false} },
204
+ { json:'{"floats":[0.0,1.0,0.1,1.555555],"raw":[0.0,1.0,0.1,1.555555]}', opts:{force_floats:true} },
205
+ { json:'{"floats":[0.0,1.0,0.1,1.555555],"raw":[0,1,0.1,1.555555]}', opts:{force_floats_in:['floats']} },
206
+
207
+ { json:'{"floats":[0,1,0.100,1.556],"raw":[0,1,0.100,1.556]}', opts:{force_floats:false, decimals:3} },
208
+ { json:'{"floats":[0.000,1.000,0.100,1.556],"raw":[0.000,1.000,0.100,1.556]}', opts:{force_floats:true, decimals:3} },
209
+ { json:'{"floats":[0.000,1.000,0.100,1.556],"raw":[0,1,0.100,1.556]}', opts:{force_floats_in:['floats'], decimals:3} },
210
+
211
+ { json:'{"floats":[0,1,0.1,1.556],"raw":[0,1,0.1,1.556]}', opts:{force_floats:false, decimals:3, trim_trailing_zeros:true} },
212
+ { json:'{"floats":[0.0,1.0,0.1,1.556],"raw":[0.0,1.0,0.1,1.556]}', opts:{force_floats:true, decimals:3, trim_trailing_zeros:true} },
213
+ { json:'{"floats":[0.0,1.0,0.1,1.556],"raw":[0,1,0.1,1.556]}', opts:{force_floats_in:['floats'], decimals:3, trim_trailing_zeros:true} },
214
+ ]},
215
+
216
+ {value:[1,2,3,{a:[4,5,{a:6, b:7}], b:[8,9,{a:10, b:11}]}], tests:[
217
+ { json:'[1,2,3,{"a":[4,5,{"a":6,"b":7}],"b":[8,9,{"a":10,"b":11}]}]', opts:{} },
218
+ { json:'[1.0,2.0,3.0,{"a":[4.0,5.0,{"a":6.0,"b":7.0}],"b":[8.0,9.0,{"a":10.0,"b":11.0}]}]', opts:{force_floats:true, wrap:false} },
219
+ { json:'[1,2,3,{"a":[4.0,5.0,{"a":6.0,"b":7}],"b":[8,9,{"a":10.0,"b":11}]}]', opts:{force_floats_in:['a'], wrap:false} },
220
+ ]},
191
221
  ]
192
222
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neatjson
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.9'
4
+ version: '0.10'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gavin Kistner
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-29 00:00:00.000000000 Z
11
+ date: 2022-08-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Generate JSON strings from Ruby objects with flexible formatting options.
14
14
  Key features: keep arrays and objects on a single line when they fit; format floats
@@ -35,7 +35,7 @@ homepage: http://github.com/Phrogz/NeatJSON
35
35
  licenses:
36
36
  - MIT
37
37
  metadata: {}
38
- post_install_message:
38
+ post_install_message:
39
39
  rdoc_options: []
40
40
  require_paths:
41
41
  - lib
@@ -50,9 +50,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
50
  - !ruby/object:Gem::Version
51
51
  version: '0'
52
52
  requirements: []
53
- rubyforge_project:
54
- rubygems_version: 2.5.2
55
- signing_key:
53
+ rubygems_version: 3.2.3
54
+ signing_key:
56
55
  specification_version: 4
57
56
  summary: Pretty, powerful, flexible JSON generation.
58
57
  test_files: []