tableの値をdumpする+α

facebookでリクエストがあったので晒しておきます。
tableの値をdump出力したり、それを実機でコピペ可能状態なテキストフィールドにトレースしたりするクラスです。
ソースが長いので[ココ]
(https://dl.dropbox.com/u/67505768/qiita/corona/log.zip)にzipで固めておきます。


```lua:log.lua

module(..., package.seeall)

local DEBUG = 1;
local INFO  = 2;
local WARN  = 4;
local ERROR = 8;
local RELEASE = 16;

--しきい値設定
local logLevel = DEBUG;		

--デバッグディスプレイのボタンサイズ
local buttonsize = 30;


--Debug Display------------------------------------------------------------------------

--実機検証用

local displayObject = display.newGroup();
local disp;
local dispButton;
local delButton;
local displayEnable = false;


local function visibleDisplay( event )
	disp.isVisible = not( disp.isVisible );
end;

local function deleteDisplay( event )
	disp.text = "";
end;


-- 実機検証用のディスプレイを表示
-- colorObj		{ r ,g ,b ,a }	ディスプレイの文字色設定（各0〜255）、設定があれば背景は透明/nil時は背景白、文字黒

function showDisplay( colorObj )
	print( "showDisplay!!!!!" );
	displayEnable = true;

	dispButton = display.newRect(display.screenOriginX,display.screenOriginY,buttonsize,buttonsize);
	dispButton.strokeWidth = 3;
	dispButton:setFillColor(255, 0, 0);
	dispButton:addEventListener( "tap" , visibleDisplay );
	
	delButton = display.newRect(display.screenOriginX,display.screenOriginY+buttonsize+10,buttonsize,buttonsize);
	delButton.strokeWidth = 3;
	delButton:setFillColor(0, 0, 255);
	delButton:addEventListener( "tap" , deleteDisplay );
	
	disp = native.newTextBox( buttonsize, 0, display.contentWidth-buttonsize, display.contentHeight );
	disp.font = native.newFont( native.systemFont , 12 );
	disp.isVisible = false;
	if colorObj and #colorObj==4 then
		disp:setTextColor( colorObj[1], colorObj[2], colorObj[3], colorObj[4] );
		disp.hasBackground = false;
	end;
	
	displayObject:insert( dispButton );
	displayObject:insert( delButton );
	displayObject:insert( disp );
end;



-- データのダンプ、ダンプした文字列を返す------------------------------------------------------------------------
-- (UserDataと循環参照を持つオブジェクトは入れてはいけません)
-- data				ダンプするデータ
-- return			ダンプした文字列
local function dump_data( data )

	if type( data ) ~= "table" then
		return tostring(data);
	end;

	dump_table = function( t, indent )
		local str = "{\n";
		for k, v in pairs( t ) do
			if type( v ) == "table" then
				str = string.format("%s%s%s%s = %s,\n", str, indent, "\t", tostring( k ),dump_table( v, indent .. "\t" ) );
			elseif type( v ) == "string" then
				str = string.format("%s%s%s%s = %q,\n", str, indent, "\t", tostring( k ), v );
			else
				str = string.format("%s%s%s%s = %s,\n", str, indent, "\t", tostring( k ), tostring( v ) );
			end;
		end;
		str = str .. indent .. "}";
		return str;
	end;
	
	return dump_table( data, "" );
end



-- NEW------------------------------------------------------------------------
-- _path			接頭でprintされる文字列、クラスパスを入れておくと便利

function new( _path )
	local this = {};
	
	if logLevel == RELEASE then
		this = {
				debug = function( value ) end;
				info  = function( value ) end;
				warn  = function( value ) end;
				error = function( value ) end;
				showDisplay = function( value ) end;
				log_display = display.newGroup();
		};		
	else
		this = {
			path = _path;
			debug = function( value )
				if  logLevel <= DEBUG then
					local debug_text = ( "[debug][".. _path .."] " .. dump_data( value ) );
					if displayEnable then disp.text = disp.text .. "\n" .. debug_text; end;
					print( debug_text );
				end
			end;
			info = function( value )
				if  logLevel <= INFO then
					local debug_text = ( "\t[info][".. _path .."] " .. dump_data( value ) );
					if displayEnable then disp.text = disp.text .. "\n" .. debug_text; end;
					print( debug_text );
				end
			end;
			warn = function( value )
				if  logLevel <= WARN then
					local debug_text = ( "\t\t[warn][".. _path .."] " .. dump_data( value ) );
					if displayEnable then disp.text = disp.text .. "\n" .. debug_text; end;
					print( debug_text );
				end
			end;
			error = function( value )
				if  logLevel <= ERROR then
					local debug_text = ( "\t\t\t[error][".. _path .."] " .. dump_data( value ) );
					if displayEnable then disp.text = disp.text .. "\n" .. debug_text; end;
					print( debug_text );
				end
			end;
			showDisplay = function( colorObj ) showDisplay( colorObj ); end;
			log_display = displayObject;
		};
	end;

	return this;
end;



-- 初回トレース ------------------------------------------------------------------------

local startLog = new( "log" );
startLog.error	("\n\n\n\n\n\n\n\n------------------------------ DEBUG START at " .. os.date( "%c" ) .." ------------------------------\n\n");
startLog.debug	( "this is debug." );
startLog.info	( "this is info." );
startLog.warn	( "this is warn." );
startLog.error	( "this is error.\n\n" );

```


## 使用サンプル
で、以下が使用サンプルです。




```lua:main.lua
local log = ( require "log" ).new( "main" );

--実機検証用にディスプレイを表示する場合に一回だけ実行
log.showDisplay();
--displayList最前面とかにする場合は以下な感じで
--container:insert( log.log_display );

--トレースサンプル
local dump_reference = { hoge="hoge" };
local obj = {
	dump_string = "STRING";
	dump_number = 65536;
	dump_boolean = true;
	dump_array = { 50 , 80+2.56 , "THREE" , false , dump_reference };
	dump_function = function() end;
	dump_nan = 0/0;
	--dump_ng = display.newGroup(); --これは駄目よ
};

log.debug( obj.dump_string );
log.info ( obj.dump_number );
log.warn ( obj.dump_boolean );
log.error( obj.dump_array );
log.debug( obj );
```

出力結果はこんな感じ。

> [debug][main] STRING
> 　　　　[info][main] 65536
> 　　　　　　　　[warn][main] true
> 　　　　　　　　　　　　[error][main] {
> 　　1 = 50,
> 　　2 = 82.56,
> 　　3 = "THREE",
> 　　4 = false,
> 　　5 = {
> 　　　　hoge = "hoge",
> 　　},
> }
> [debug][main] {
> 　　dump_string = "STRING",
> 　　dump_array = {
> 　　　　1 = 50,
> 　　　　2 = 82.56,
> 　　　　3 = "THREE",
> 　　　　4 = false,
> 　　　　5 = {
> 　　　　　　hoge = "hoge",
> 　　　　},
> 　　},
> 　　dump_nan = nan,
> 　　dump_number = 65536,
> 　　dump_function = function: 0x115f4d7a0,
> 　　dump_boolean = true,
> }

## つかいかた

* 読み込み

こんな感じでrequireしインスタンスを生成します。newの引数はログに接頭で付くので、クラス名をパッケージフルパスで入れておくと便利です。

```lua:
local log = ( require "log" ).new( "main" );
```

* ログの出力

ログの出力はレベルに応じて4種設定され、それぞれ1つずつタブインデントが付いて出力されます。
循環参照やuserdataはオーバーフローするので入れないようにしてください。

```lua:
log.debug( value );	--なんとなく見たい値とか
log.info( value );	--フロー追いかけ用とか
log.warn( value );	--ちょっとおっかない箇所の出力
log.error( value );	--エラー時用の出力
```

* ログレベルの振り分け

ログの出力レベルは、log.luaのlogLevelで変更出来ます。DEBUG/INFO/WARN/ERROR/RELEASEの5段階あり、しきい値以下のレベルは出力されなくなります。
RELEASEに設定すると、一切出力されません。（リリースビルド向け）

```lua:log.lua11行目
--しきい値設定
local logLevel = DEBUG;
```

* ログディスプレイ表示

実機でしか確認出来ない事項用（GameCenterとかStore関連等）向けに、テキストフィールドにログを出力します。
log.showDisplay()を実行すると、画面の左上に赤と青のボタンが並びます。
・赤ボタン - テキストフィールドの表示ON/OFF
・青ボタン - テキストフィールドの内容を消去（ログが溜まってくると重くなるので、そんな時に）

```lua:
log.showDisplay();	--引数設定でカラー変化。詳しくはコード見て

--displayList最前面とかにする場合は以下な感じで
--group:insert( log.log_display );
```


Corona始めて一番最初に書いたコードなので、ちょっと汚いかもしれませんです。