mirror of
https://github.com/pkulchenko/serpent.git
synced 2024-11-21 23:24:24 +00:00
Added load
function to deserialize; updated documentation (closes #9).
This commit is contained in:
parent
b290a5d522
commit
4e4a19df1d
14
README.md
14
README.md
@ -37,6 +37,10 @@ print(serpent.block(a)) -- multi-line indented, no self-ref section
|
|||||||
local fun, err = loadstring(serpent.dump(a))
|
local fun, err = loadstring(serpent.dump(a))
|
||||||
if err then error(err) end
|
if err then error(err) end
|
||||||
local copy = fun()
|
local copy = fun()
|
||||||
|
|
||||||
|
-- or using serpent.load:
|
||||||
|
local ok, copy = serpent.load(serpent.dump(a))
|
||||||
|
print(ok and copy[3] == a[3])
|
||||||
```
|
```
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
@ -51,6 +55,12 @@ internal function, but set different options by default:
|
|||||||
Note that `line` and `block` functions return pretty-printed data structures and if you want to deserialize them, you need to add `return` before running them through `loadstring`.
|
Note that `line` and `block` functions return pretty-printed data structures and if you want to deserialize them, you need to add `return` before running them through `loadstring`.
|
||||||
For example: `loadstring('return '..require('mobdebug').line("foo"))() == "foo"`.
|
For example: `loadstring('return '..require('mobdebug').line("foo"))() == "foo"`.
|
||||||
|
|
||||||
|
While you can use `loadstring` or `load` functions to load serialized fragments, Serpent also provides `load` function that adds safety checks and reports an error if there is any executable code in the fragment.
|
||||||
|
|
||||||
|
* `ok, res = load(str[, {safe = true}])` -- loads serialized fragment; you need to pass `{safe = false}` as the second value if you want to turn safety checks off.
|
||||||
|
|
||||||
|
Similar to `pcall` and `loadstring` calls, `load` returns status as the first value and the result or the error message as the second value.
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
* indent (string) -- indentation; triggers long multi-line output
|
* indent (string) -- indentation; triggers long multi-line output
|
||||||
@ -167,6 +177,10 @@ See LICENSE file.
|
|||||||
|
|
||||||
## History
|
## History
|
||||||
|
|
||||||
|
### v0.26 (Nov 05 2013)
|
||||||
|
- Added `load` function that (safely) loads serialized/pretty-printed values.
|
||||||
|
- Updated documentation.
|
||||||
|
|
||||||
### v0.25 (Sep 29 2013)
|
### v0.25 (Sep 29 2013)
|
||||||
- Added `maxnum` option to limit the number of elements in tables.
|
- Added `maxnum` option to limit the number of elements in tables.
|
||||||
- Optimized processing of tables with numeric indexes.
|
- Optimized processing of tables with numeric indexes.
|
||||||
|
25
misc/serpent-0.26-1.rockspec
Normal file
25
misc/serpent-0.26-1.rockspec
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package = "serpent"
|
||||||
|
version = "0.26-1"
|
||||||
|
source = {
|
||||||
|
url = "git://github.com/pkulchenko/serpent.git",
|
||||||
|
tag = "0.26"
|
||||||
|
}
|
||||||
|
|
||||||
|
description = {
|
||||||
|
summary = "Lua serializer and pretty printer",
|
||||||
|
homepage = "https://github.com/pkulchenko/serpent",
|
||||||
|
maintainer = "Paul Kulchenko <paul@kulchenko.com>",
|
||||||
|
license = "MIT",
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1, < 5.3",
|
||||||
|
}
|
||||||
|
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = {
|
||||||
|
["serpent"] = "src/serpent.lua",
|
||||||
|
},
|
||||||
|
copy_directories = { "t" },
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
local n, v = "serpent", 0.25 -- (C) 2012-13 Paul Kulchenko; MIT License
|
local n, v = "serpent", 0.26 -- (C) 2012-13 Paul Kulchenko; MIT License
|
||||||
local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
|
local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
|
||||||
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
|
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
|
||||||
local badtype = {thread = true, userdata = true, cdata = true}
|
local badtype = {thread = true, userdata = true, cdata = true}
|
||||||
@ -103,8 +103,26 @@ local function s(t, opts)
|
|||||||
return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end"
|
return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function deserialize(data, opts)
|
||||||
|
local f, res = (loadstring or load)('return '..data)
|
||||||
|
if not f then f, res = (loadstring or load)(data) end
|
||||||
|
if not f then return f, res end
|
||||||
|
if opts and opts.safe == false then return pcall(f) end
|
||||||
|
|
||||||
|
local count, thread = 0, coroutine.running()
|
||||||
|
local h, m, c = debug.gethook(thread)
|
||||||
|
debug.sethook(function (e, l) count = count + 1
|
||||||
|
if count >= 3 then error("cannot call functions") end
|
||||||
|
end, "c")
|
||||||
|
local res = {pcall(f)}
|
||||||
|
count = 0 -- set again, otherwise it's tripped on the next sethook
|
||||||
|
debug.sethook(thread, h, m, c)
|
||||||
|
return (table.unpack or unpack)(res)
|
||||||
|
end
|
||||||
|
|
||||||
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
|
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
|
||||||
return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
|
return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
|
||||||
|
load = deserialize,
|
||||||
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
|
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
|
||||||
line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
|
line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
|
||||||
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end }
|
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end }
|
||||||
|
31
t/test.lua
31
t/test.lua
@ -261,8 +261,35 @@ do
|
|||||||
assert(called == false, "sorting is not called on numeric-only tables with maxnum: failed")
|
assert(called == false, "sorting is not called on numeric-only tables with maxnum: failed")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- test serializing large numeric-only tables
|
|
||||||
do
|
do
|
||||||
|
local ok, res = serpent.load(serpent.line(10))
|
||||||
|
assert(ok and res == 10, "deserialization of simple number values: failed")
|
||||||
|
|
||||||
|
local ok, res = serpent.load(serpent.line(true))
|
||||||
|
assert(ok and res == true, "deserialization of simple boolean values: failed")
|
||||||
|
|
||||||
|
local ok, res = serpent.load(serpent.line({3,4}))
|
||||||
|
assert(ok and #res == 2 and res[1] == 3 and res[2] == 4,
|
||||||
|
"deserialization of pretty-printed tables: failed")
|
||||||
|
|
||||||
|
local ok, res = serpent.load(serpent.dump({3,4}))
|
||||||
|
assert(ok and #res == 2 and res[1] == 3 and res[2] == 4,
|
||||||
|
"deserialization of serialized tables: failed")
|
||||||
|
|
||||||
|
local ok, res = serpent.load('{a = math.random()}')
|
||||||
|
assert(not ok and res:find("cannot call functions"),
|
||||||
|
"deserialization of unsafe values: failed")
|
||||||
|
|
||||||
|
local ok, res = serpent.load('{a = math.random()}', {safe = false})
|
||||||
|
assert(ok and res and res.a > 0,
|
||||||
|
"deserialization of unsafe values disabled: failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
print("All tests passed.")
|
||||||
|
|
||||||
|
do
|
||||||
|
print("\nSerializing large numeric-only tables:")
|
||||||
|
|
||||||
local a, str = {}
|
local a, str = {}
|
||||||
for i = 1, 100000 do a[i] = i end
|
for i = 1, 100000 do a[i] = i end
|
||||||
|
|
||||||
@ -278,5 +305,3 @@ do
|
|||||||
str = serpent.dump(a, {sparse = false})
|
str = serpent.dump(a, {sparse = false})
|
||||||
print("dump/sparse=false: "..(os.clock() - start), #str)
|
print("dump/sparse=false: "..(os.clock() - start), #str)
|
||||||
end
|
end
|
||||||
|
|
||||||
print("All tests passed.")
|
|
||||||
|
Loading…
Reference in New Issue
Block a user