From 5fb9fe1c67a070d1e83497c44b7b7364da9f1975 Mon Sep 17 00:00:00 2001 From: Mark Pulford Date: Fri, 13 Jan 2012 07:17:48 +1030 Subject: Move cjson-misc and scripts to "lua" directory --- lua/cjson-misc.lua | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lua/json2lua.lua | 14 +++ lua/lua2json.lua | 20 ++++ 3 files changed, 311 insertions(+) create mode 100644 lua/cjson-misc.lua create mode 100755 lua/json2lua.lua create mode 100755 lua/lua2json.lua (limited to 'lua') diff --git a/lua/cjson-misc.lua b/lua/cjson-misc.lua new file mode 100644 index 0000000..2142464 --- /dev/null +++ b/lua/cjson-misc.lua @@ -0,0 +1,277 @@ +local json = require "cjson" + +-- Various common routines used by the Lua CJSON package +-- +-- Mark Pulford + +-- Determine with a Lua table can be treated as an array. +-- Explicitly returns "not an array" for very sparse arrays. +-- Returns: +-- -1 Not an array +-- 0 Empty table +-- >0 Highest index in the array +local function is_array(table) + local max = 0 + local count = 0 + for k, v in pairs(table) do + if type(k) == "number" then + if k > max then max = k end + count = count + 1 + else + return -1 + end + end + if max > count * 2 then + return -1 + end + + return max +end + +local serialise_value + +local function serialise_table(value, indent, depth) + local spacing, spacing2, indent2 + if indent then + spacing = "\n" .. indent + spacing2 = spacing .. " " + indent2 = indent .. " " + else + spacing, spacing2, indent2 = " ", " ", false + end + depth = depth + 1 + if depth > 50 then + return "Cannot serialise any further: too many nested tables" + end + + local max = is_array(value) + + local comma = false + local fragment = { "{" .. spacing2 } + if max > 0 then + -- Serialise array + for i = 1, max do + if comma then + table.insert(fragment, "," .. spacing2) + end + table.insert(fragment, serialise_value(value[i], indent2, depth)) + comma = true + end + elseif max < 0 then + -- Serialise table + for k, v in pairs(value) do + if comma then + table.insert(fragment, "," .. spacing2) + end + table.insert(fragment, string.format( + "[%s] = %s", serialise_value(k, indent2, depth), + serialise_value(v, indent2, depth)) + ) + comma = true + end + end + table.insert(fragment, spacing .. "}") + + return table.concat(fragment) +end + +function serialise_value(value, indent, depth) + if indent == nil then indent = "" end + if depth == nil then depth = 0 end + + if value == json.null then + return "json.null" + elseif type(value) == "string" then + return string.format("%q", value) + elseif type(value) == "nil" or type(value) == "number" or + type(value) == "boolean" then + return tostring(value) + elseif type(value) == "table" then + return serialise_table(value, indent, depth) + else + return "\"<" .. type(value) .. ">\"" + end +end + +local function file_load(filename) + local file + if filename == nil then + file = io.stdin + else + local err + file, err = io.open(filename) + if file == nil then + error(string.format("Unable to read '%s': %s", filename, err)) + end + end + local data = file:read("*a") + + if filename ~= nil then + file:close() + end + + if data == nil then + error("Failed to read " .. filename) + end + + return data +end + +local function file_save(filename, data) + local file + if filename == nil then + file = io.stdout + else + local err + file, err = io.open(filename, "w") + if file == nil then + error(string.format("Unable to write '%s': %s", filename, err)) + end + end + file:write(data) + if filename ~= nil then + file:close() + end +end + +local function compare_values(val1, val2) + local type1 = type(val1) + local type2 = type(val2) + if type1 ~= type2 then + return false + end + + -- Check for NaN + if type1 == "number" and val1 ~= val1 and val2 ~= val2 then + return true + end + + if type1 ~= "table" then + return val1 == val2 + end + + -- check_keys stores all the keys that must be checked in val2 + local check_keys = {} + for k, _ in pairs(val1) do + check_keys[k] = true + end + + for k, v in pairs(val2) do + if not check_keys[k] then + return false + end + + if not compare_values(val1[k], val2[k]) then + return false + end + + check_keys[k] = nil + end + for k, _ in pairs(check_keys) do + -- Not the same if any keys from val1 were not found in val2 + return false + end + return true +end + +local test_count_pass = 0 +local test_count_total = 0 + +local function run_test_summary() + return test_count_pass, test_count_total +end + +local function run_test(testname, func, input, should_work, output) + local function status_line(name, status, value) + local statusmap = { [true] = ":success", [false] = ":error" } + if status ~= nil then + name = name .. statusmap[status] + end + print(string.format("[%s] %s", name, serialise_value(value, false))) + end + + local result = { pcall(func, unpack(input)) } + local success = table.remove(result, 1) + + local correct = false + if success == should_work and compare_values(result, output) then + correct = true + test_count_pass = test_count_pass + 1 + end + test_count_total = test_count_total + 1 + + local teststatus = { [true] = "PASS", [false] = "FAIL" } + print(string.format("==> Test[%d] / %s: %s", + test_count_total, testname, teststatus[correct])) + + status_line("Input", nil, input) + if not correct then + status_line("Expected", should_work, output) + end + status_line("Received", success, result) + print() + + return correct, result +end + +local function run_test_group(testgroup, tests) + local function run_config(configname, func) + local success, msg = pcall(func) + if msg then + print(string.format("==> Config %s: %s", configname, msg)) + end + print() + end + + local function test_id(group, id) + return string.format("%s[%d]", group, id) + end + + for k, v in ipairs(tests) do + if type(v) == "function" then + -- Useful for changing configuration during a batch + run_config(test_id(testgroup, k), v) + elseif type(v) == "table" then + run_test(test_id(testgroup, k), unpack(v)) + else + error("Testgroup can only contain functions and tables") + end + end +end + +-- Run a Lua script in a separate environment +local function run_script(script, env) + local env = env or {} + local func + + -- Use setfenv() if it exists, otherwise assume Lua 5.2 load() exists + if _G.setfenv then + func = loadstring(script) + if func then + setfenv(func, env) + end + else + func = load(script, nil, nil, env) + end + + if func == nil then + error("Invalid syntax.") + end + func() + + return env +end + +-- Export functions +return { + serialise_value = serialise_value, + file_load = file_load, + file_save = file_save, + compare_values = compare_values, + run_test_summary = run_test_summary, + run_test = run_test, + run_test_group = run_test_group, + run_script = run_script +} + +-- vi:ai et sw=4 ts=4: diff --git a/lua/json2lua.lua b/lua/json2lua.lua new file mode 100755 index 0000000..050b89d --- /dev/null +++ b/lua/json2lua.lua @@ -0,0 +1,14 @@ +#!/usr/bin/env lua + +-- usage: json2lua.lua [json_file] +-- +-- Eg: +-- echo '[ "testing" ]' | ./json2lua.lua +-- ./json2lua.lua test.json + +local json = require "cjson" +local misc = require "cjson-misc" + +local json_text = misc.file_load(arg[1]) +local t = json.decode(json_text) +print(misc.serialise_value(t)) diff --git a/lua/lua2json.lua b/lua/lua2json.lua new file mode 100755 index 0000000..2a9ddf9 --- /dev/null +++ b/lua/lua2json.lua @@ -0,0 +1,20 @@ +#!/usr/bin/env lua + +-- usage: lua2json.lua [lua_file] +-- +-- Eg: +-- echo '{ "testing" }' | ./lua2json.lua +-- ./lua2json.lua test.lua + +local json = require "cjson" +local misc = require "cjson-misc" + +local env = { + json = { null = json.null }, + null = json.null +} + +local t = misc.run_script("data = " .. misc.file_load(arg[1]), env) +print(json.encode(t.data)) + +-- vi:ai et sw=4 ts=4: -- cgit v1.2.3-55-g6feb