• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

kikito/inspect.lua: Human-readable representation of Lua tables

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

kikito/inspect.lua

开源软件地址(OpenSource Url):

https://github.com/kikito/inspect.lua

开源编程语言(OpenSource Language):

Lua 99.0%

开源软件介绍(OpenSource Introduction):

inspect.lua

This library transforms any Lua value into a human-readable representation. It is especially useful for debugging errors in tables.

The objective here is human understanding (i.e. for debugging), not serialization or compactness.

Examples of use

inspect has the following declaration: local str = inspect(value, <options>).

value can be any Lua value.

inspect transforms simple types (like strings or numbers) into strings.

assert(inspect(1) == "1")
assert(inspect("Hello") == '"Hello"')

Tables, on the other hand, are rendered in a way a human can read easily.

"Array-like" tables are rendered horizontally:

assert(inspect({1,2,3,4}) == "{ 1, 2, 3, 4 }")

"Dictionary-like" tables are rendered with one element per line:

assert(inspect({a=1,b=2}) == [[{
  a = 1,
  b = 2
}]])

The keys will be sorted alphanumerically when possible.

"Hybrid" tables will have the array part on the first line, and the dictionary part just below them:

assert(inspect({1,2,3,b=2,a=1}) == [[{ 1, 2, 3,
  a = 1,
  b = 2
}]])

Subtables are indented with two spaces per level.

assert(inspect({a={b=2}}) == [[{
  a = {
    b = 2
  }
}]])

Functions, userdata and any other custom types from Luajit are simply as <function x>, <userdata x>, etc.:

assert(inspect({ f = print, ud = some_user_data, thread = a_thread} ) == [[{
  f = <function 1>,
  u = <userdata 1>,
  thread = <thread 1>
}]])

If the table has a metatable, inspect will include it at the end, in a special field called <metatable>:

assert(inspect(setmetatable({a=1}, {b=2}) == [[{
  a = 1
  <metatable> = {
    b = 2
  }
}]]))

inspect can handle tables with loops inside them. It will print <id> right before the table is printed out the first time, and replace the whole table with <table id> from then on, preventing infinite loops.

local a = {1, 2}
local b = {3, 4, a}
a[3] = b -- a references b, and b references a
assert(inspect(a) == "<1>{ 1, 2, { 3, 4, <table 1> } }")

Notice that since both a appears more than once in the expression, it is prefixed by <1> and replaced by <table 1> every time it appears later on.

options

inspect has a second parameter, called options. It is not mandatory, but when it is provided, it must be a table.

options.depth

options.depth sets the maximum depth that will be printed out. When the max depth is reached, inspect will stop parsing tables and just return {...}:

local t5 = {a = {b = {c = {d = {e = 5}}}}}

assert(inspect(t5, {depth = 4}) == [[{
  a = {
    b = {
      c = {
        d = {...}
      }
    }
  }
}]])

assert(inspect(t5, {depth = 2}) == [[{
  a = {
    b = {...}
  }
}]])

options.depth defaults to infinite (math.huge).

options.newline & options.indent

These are the strings used by inspect to respectively add a newline and indent each level of a table.

By default, options.newline is "\n" and options.indent is " " (two spaces).

local t = {a={b=1}}

assert(inspect(t) == [[{
  a = {
    b = 1
  }
}]])

assert(inspect(t, {newline='@', indent="++"}), "{@++a = {@++++b = 1@++}@}"

options.process

options.process is a function which allow altering the passed object before transforming it into a string. A typical way to use it would be to remove certain values so that they don't appear at all.

options.process has the following signature:

local processed_item = function(item, path)
  • item is either a key or a value on the table, or any of its subtables
  • path is an array-like table built with all the keys that have been used to reach item, from the root.
    • For values, it is just a regular list of keys. For example, to reach the 1 in {a = {b = 1}}, the path will be {'a', 'b'}
    • For keys, the special value inspect.KEY is inserted. For example, to reach the c in {a = {b = {c = 1}}}, the path will be {'a', 'b', 'c', inspect.KEY }
    • For metatables, the special value inspect.METATABLE is inserted. For {a = {b = 1}}}, the path {'a', {b = 1}, inspect.METATABLE} means "the metatable of the table {b = 1}".
  • processed_item is the value returned by options.process. If it is equal to item, then the inspected table will look unchanged. If it is different, then the table will look different; most notably, if it's nil, the item will dissapear on the inspected table.

Examples

Remove a particular metatable from the result:

local t = {1,2,3}
local mt = {b = 2}
setmetatable(t, mt)

local remove_mt = function(item)
  if item ~= mt then return item end
end

-- mt does not appear
assert(inspect(t, {process = remove_mt}) == "{ 1, 2, 3 }")

The previous exaple only works for a particular metatable. If you want to make all metatables, you can use the path parameter to check wether the last element is inspect.METATABLE, and return nil instead of the item:

local t, mt = ... -- (defined as before)

local remove_all_metatables = function(item, path)
  if path[#path] ~= inspect.METATABLE then return item end
end

assert(inspect(t, {process = remove_all_metatables}) == "{ 1, 2, 3 }")

Filter a value:

local anonymize_password = function(item, path)
  if path[#path] == 'password' then return "XXXX" end
  return item
end

local info = {user = 'peter', password = 'secret'}

assert(inspect(info, {process = anonymize_password}) == [[{
  password = "XXXX",
  user     = "peter"
}]])

Gotchas / Warnings

This method is not appropriate for saving/restoring tables. It is meant to be used by the programmer mainly while debugging a program.

Installation

If you are using luarocks, just run

luarocks install inspect

Otherwise, you can just copy the inspect.lua file somewhere in your projects (maybe inside a /lib/ folder) and require it accordingly.

Remember to store the value returned by require somewhere! (I suggest a local variable named inspect, although others might like table.inspect)

local inspect = require 'inspect'
      -- or --
local inspect = require 'lib.inspect'

Also, make sure to read the license; the text of that license file must appear somewhere in your projects' files. For your convenience, it's included at the begining of inspect.lua.

Contributing

This project uses Teal, a typed dialect of Lua (which generates plain lua files too)

If you want to send a pull request to this project, first of all, thank you! You will need to install the. You can install all of them by running:

make dev

When writing your PR, please make your modifications on the inspect.tl file and then generate the inspect.lua file from it. You will probably want to make sure that the tests are still working (github should run them from you, but they should run very fast). You can do both things in one go by just invoking

make

This will generate inspect.lua, check it with luacheck and then launch busted to run the specs.

If you are sending a pull request, you might want to add some specs in the specs folder.

Change log

Read it on the CHANGELOG.md file




鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap