aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Charbonnier <thibaultcha@me.com>2017-08-05 15:19:43 -0700
committerYichun Zhang (agentzh) <agentzh@gmail.com>2017-11-17 11:46:46 -0800
commitb5e364c7c60167995944ed3a3b9c54d9a377fc1d (patch)
treeb2554317191a34b155aca68be0a54ef364296b58
parent5f9efa4829a72935ddcd40c7da6b1a9e10939b65 (diff)
downloadlua-cjson-2.1.0.6rc1.tar.gz
lua-cjson-2.1.0.6rc1.tar.bz2
lua-cjson-2.1.0.6rc1.zip
feature: set cjson.array_mt on decoded JSON arrays.2.1.0.6rc1
this can be turned on via cjson.decode_array_with_array_mt(true). off by default. Signed-off-by: Yichun Zhang (agentzh) <agentzh@gmail.com>
-rw-r--r--README.md37
-rw-r--r--lua_cjson.c21
-rw-r--r--tests/agentzh.t61
3 files changed, 113 insertions, 6 deletions
diff --git a/README.md b/README.md
index 1cdb53b..83bfd76 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ Table of Contents
14 * [array_mt](#array_mt) 14 * [array_mt](#array_mt)
15 * [empty_array_mt](#empty_array_mt) 15 * [empty_array_mt](#empty_array_mt)
16 * [encode_number_precision](#encode_number_precision) 16 * [encode_number_precision](#encode_number_precision)
17 * [decode_array_with_array_mt](#decode_array_with_array_mt)
17 18
18Description 19Description
19=========== 20===========
@@ -156,3 +157,39 @@ encode_number_precision
156This fork allows encoding of numbers with a `precision` up to 16 decimals (vs. 14 in mpx/lua-cjson). 157This fork allows encoding of numbers with a `precision` up to 16 decimals (vs. 14 in mpx/lua-cjson).
157 158
158[Back to TOC](#table-of-contents) 159[Back to TOC](#table-of-contents)
160
161decode_array_with_array_mt
162--------------------------
163**syntax:** `cjson.decode_array_with_array_mt(enabled)`
164
165**default:** false
166
167If enabled, JSON Arrays decoded by `cjson.decode` will result in Lua
168tables with the [`array_mt`](#array_mt) metatable. This can ensure a 1-to-1
169relationship between arrays upon multiple encoding/decoding of your
170JSON data with this module.
171
172If disabled, JSON Arrays will be decoded to plain Lua tables, without
173the `array_mt` metatable.
174
175The `enabled` argument is a boolean.
176
177Example:
178
179```lua
180local cjson = require "cjson"
181
182-- default behavior
183local my_json = [[{"my_array":[]}]]
184local t = cjson.decode(my_json)
185cjson.encode(t) -- {"my_array":{}} back to an object
186
187-- now, if this behavior is enabled
188cjson.decode_array_with_array_mt(true)
189
190local my_json = [[{"my_array":[]}]]
191local t = cjson.decode(my_json)
192cjson.encode(t) -- {"my_array":[]} properly re-encoded as an array
193```
194
195[Back to TOC](#table-of-contents)
diff --git a/lua_cjson.c b/lua_cjson.c
index 8d6e313..6c7eb4e 100644
--- a/lua_cjson.c
+++ b/lua_cjson.c
@@ -79,6 +79,7 @@
79#define DEFAULT_ENCODE_KEEP_BUFFER 1 79#define DEFAULT_ENCODE_KEEP_BUFFER 1
80#define DEFAULT_ENCODE_NUMBER_PRECISION 14 80#define DEFAULT_ENCODE_NUMBER_PRECISION 14
81#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 1 81#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 1
82#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
82 83
83#ifdef DISABLE_INVALID_NUMBERS 84#ifdef DISABLE_INVALID_NUMBERS
84#undef DEFAULT_DECODE_INVALID_NUMBERS 85#undef DEFAULT_DECODE_INVALID_NUMBERS
@@ -148,6 +149,7 @@ typedef struct {
148 149
149 int decode_invalid_numbers; 150 int decode_invalid_numbers;
150 int decode_max_depth; 151 int decode_max_depth;
152 int decode_array_with_array_mt;
151} json_config_t; 153} json_config_t;
152 154
153typedef struct { 155typedef struct {
@@ -329,6 +331,16 @@ static int json_cfg_encode_empty_table_as_object(lua_State *l)
329 return json_enum_option(l, 1, &cfg->encode_empty_table_as_object, NULL, 1); 331 return json_enum_option(l, 1, &cfg->encode_empty_table_as_object, NULL, 1);
330} 332}
331 333
334/* Configures how to decode arrays */
335static int json_cfg_decode_array_with_array_mt(lua_State *l)
336{
337 json_config_t *cfg = json_arg_init(l, 1);
338
339 json_enum_option(l, 1, &cfg->decode_array_with_array_mt, NULL, 1);
340
341 return 1;
342}
343
332/* Configures JSON encoding buffer persistence */ 344/* Configures JSON encoding buffer persistence */
333static int json_cfg_encode_keep_buffer(lua_State *l) 345static int json_cfg_encode_keep_buffer(lua_State *l)
334{ 346{
@@ -420,6 +432,7 @@ static void json_create_config(lua_State *l)
420 cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; 432 cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER;
421 cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION; 433 cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION;
422 cfg->encode_empty_table_as_object = DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT; 434 cfg->encode_empty_table_as_object = DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT;
435 cfg->decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT;
423 436
424#if DEFAULT_ENCODE_KEEP_BUFFER > 0 437#if DEFAULT_ENCODE_KEEP_BUFFER > 0
425 strbuf_init(&cfg->encode_buf, 0); 438 strbuf_init(&cfg->encode_buf, 0);
@@ -1261,6 +1274,13 @@ static void json_parse_array_context(lua_State *l, json_parse_t *json)
1261 1274
1262 lua_newtable(l); 1275 lua_newtable(l);
1263 1276
1277 /* set array_mt on the table at the top of the stack */
1278 if (json->cfg->decode_array_with_array_mt) {
1279 lua_pushlightuserdata(l, &json_array);
1280 lua_rawget(l, LUA_REGISTRYINDEX);
1281 lua_setmetatable(l, -2);
1282 }
1283
1264 json_next_token(json, &token); 1284 json_next_token(json, &token);
1265 1285
1266 /* Handle empty arrays */ 1286 /* Handle empty arrays */
@@ -1415,6 +1435,7 @@ static int lua_cjson_new(lua_State *l)
1415 { "encode", json_encode }, 1435 { "encode", json_encode },
1416 { "decode", json_decode }, 1436 { "decode", json_decode },
1417 { "encode_empty_table_as_object", json_cfg_encode_empty_table_as_object }, 1437 { "encode_empty_table_as_object", json_cfg_encode_empty_table_as_object },
1438 { "decode_array_with_array_mt", json_cfg_decode_array_with_array_mt },
1418 { "encode_sparse_array", json_cfg_encode_sparse_array }, 1439 { "encode_sparse_array", json_cfg_encode_sparse_array },
1419 { "encode_max_depth", json_cfg_encode_max_depth }, 1440 { "encode_max_depth", json_cfg_encode_max_depth },
1420 { "decode_max_depth", json_cfg_decode_max_depth }, 1441 { "decode_max_depth", json_cfg_decode_max_depth },
diff --git a/tests/agentzh.t b/tests/agentzh.t
index dd70fb8..7967337 100644
--- a/tests/agentzh.t
+++ b/tests/agentzh.t
@@ -153,7 +153,56 @@ print(cjson.encode(data))
153 153
154 154
155 155
156=== TEST 12: array_mt on tables with hash part 156=== TEST 12: decode() by default does not set array_mt on empty arrays
157--- lua
158local cjson = require "cjson"
159local json = [[{"my_array":[]}]]
160local t = cjson.decode(json)
161local has_metatable = getmetatable(t.my_array) == cjson.array_mt
162print("decoded JSON array has metatable: " .. tostring(has_metatable))
163print(cjson.encode(t))
164--- out
165decoded JSON array has metatable: false
166{"my_array":{}}
167
168
169
170=== TEST 13: decode() sets array_mt on non-empty arrays if enabled
171--- lua
172local cjson = require "cjson"
173cjson.decode_array_with_array_mt(true)
174local json = [[{"my_array":["hello","world"]}]]
175local t = cjson.decode(json)
176t.my_array.hash_value = "adding a hash value"
177-- emptying the array part
178t.my_array[1] = nil
179t.my_array[2] = nil
180local has_metatable = getmetatable(t.my_array) == cjson.array_mt
181print("decoded JSON array has metatable: " .. tostring(has_metatable))
182print(cjson.encode(t))
183--- out
184decoded JSON array has metatable: true
185{"my_array":[]}
186
187
188
189=== TEST 14: cfg can enable/disable setting array_mt
190--- lua
191local cjson = require "cjson"
192cjson.decode_array_with_array_mt(true)
193cjson.decode_array_with_array_mt(false)
194local json = [[{"my_array":[]}]]
195local t = cjson.decode(json)
196local has_metatable = getmetatable(t.my_array) == cjson.array_mt
197print("decoded JSON array has metatable: " .. tostring(has_metatable))
198print(cjson.encode(t))
199--- out
200decoded JSON array has metatable: false
201{"my_array":{}}
202
203
204
205=== TEST 15: array_mt on tables with hash part
157--- lua 206--- lua
158local cjson = require "cjson" 207local cjson = require "cjson"
159local data 208local data
@@ -175,7 +224,7 @@ print(cjson.encode(data))
175 224
176 225
177 226
178=== TEST 13: multiple calls to lua_cjson_new (1/3) 227=== TEST 16: multiple calls to lua_cjson_new (1/3)
179--- lua 228--- lua
180local cjson = require "cjson" 229local cjson = require "cjson"
181package.loaded["cjson"] = nil 230package.loaded["cjson"] = nil
@@ -187,7 +236,7 @@ print(cjson.encode(arr))
187 236
188 237
189 238
190=== TEST 14: multiple calls to lua_cjson_new (2/3) 239=== TEST 17: multiple calls to lua_cjson_new (2/3)
191--- lua 240--- lua
192local cjson = require "cjson" 241local cjson = require "cjson"
193package.loaded["cjson"] = nil 242package.loaded["cjson"] = nil
@@ -199,7 +248,7 @@ print(cjson.encode(arr))
199 248
200 249
201 250
202=== TEST 15: multiple calls to lua_cjson_new (3/3) 251=== TEST 18: multiple calls to lua_cjson_new (3/3)
203--- lua 252--- lua
204local cjson = require "cjson.safe" 253local cjson = require "cjson.safe"
205-- load another cjson instance (not in package.loaded) 254-- load another cjson instance (not in package.loaded)
@@ -211,7 +260,7 @@ print(cjson.encode(arr))
211 260
212 261
213 262
214=== TEST 16: & in JSON 263=== TEST 19: & in JSON
215--- lua 264--- lua
216local cjson = require "cjson" 265local cjson = require "cjson"
217local a="[\"a=1&b=2\"]" 266local a="[\"a=1&b=2\"]"
@@ -222,7 +271,7 @@ print(cjson.encode(b))
222 271
223 272
224 273
225=== TEST 17: default and max precision 274=== TEST 20: default and max precision
226--- lua 275--- lua
227local math = require "math" 276local math = require "math"
228local cjson = require "cjson" 277local cjson = require "cjson"