外部化は警告メッセージの表示などを回避できるメリットがある一方で、エラーメッセージも表示されないという特徴もあります。
意図的に隠したい場合は、それもメリットになりますが、プログラム作成や改良の段階ではエラーメッセージが表示されないとデバッグに必要な情報が得られず、意図しないエラーの存在に気付くのが遅れて作業が捗りません。
デバッグ用に、エラーに関する情報を取得するためのメソッドを作成しました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
汎用スクリプト = function(){ | |
// 一時的なスクリプトファイルを作成して処理を外部化する場合、 | |
// 汎用スクリプトファイルのPathではなく関数を埋め込む方が良さそう。 | |
外部スクリプトファイル=function(){ | |
var returnObj = { | |
作成:function(メイン関数){ | |
var path一時的 = AXO.fs.pathTMP+'/'+getTime()+'_外部スクリプト.js' | |
var str出力 = [ | |
'main = '+メイン関数, | |
'汎用スクリプト = '+汎用スクリプト, | |
'汎用スクリプト()', | |
'!'+function(){ | |
var arg = WScript.Arguments | |
var path = arg[LEN] ? arg(0) : '' | |
var 引数 | |
eval('引数 = ' + AXO.fs.Read(path)+'.引数') | |
var returnValue = main(引数) | |
if(path){ AXO.fs.Write(path, toJSON({returnValue:returnValue, 正常終了:true})) } | |
}+'()' | |
].join('\r\n') | |
AXO.fs.Write(path一時的, str出力) | |
return path一時的 | |
}, | |
実行:function(path, 引数, intWindowStyle, func完了後){ | |
// デフォルトでは非同期モードで実行する。 | |
// func完了後が渡されている場合は、外部スクリプトが終了するまで呼び出し元は待機する。 | |
var sw同期 = func完了後 ? true : false | |
var path引数受け渡しファイル = 引数と戻り値の受け渡しファイルを作成(引数) | |
var func後始末=function(sw打ち切り){ | |
var objRV | |
eval('objRV = '+AXO.fs.Read(path引数受け渡しファイル)) | |
var flagエラー | |
if(sw同期 && !objRV.正常終了){ | |
// 同期モードで実行しない場合は、外部スクリプトの終了を待たずに後始末が始まるので | |
// 正常終了の結果を取得することはできない。だからsw同期がtrueの場合のみ、正常終了したか否かをチェックする。 | |
// 外部スクリプトで何らかのエラーが発生し、引数受け渡しファイルが更新されていないと思われる。 | |
flagエラー = true | |
} | |
AXO.fs().DeleteFile(path引数受け渡しファイル) | |
if(flagエラー){ return -1 } | |
if(func完了後){ return func完了後(objRV.returnValue) } | |
} | |
AXO.shell().run('cmd /C cscript "'+path+'" "'+path引数受け渡しファイル+'"', intWindowStyle, sw同期) | |
return func後始末() | |
}, | |
削除:function(path){ AXO.fs().DeleteFile(path) }, | |
デバッグ用:function(func, 引数){ | |
// 外部スクリプトファイルにすると論理エラー等があっても | |
// エラーメッセージは基本的に表示されない。デバッグが大変なので | |
// 外部化する部分に論理エラー等があるかテストするのが、このメソッド。 | |
// エラー箇所があったら、その行番号に対応する行テキストも出力する。 | |
// 「実行」で使用している「WScript.Shell」の「Run」メソッドではエラーの詳細が取得できないが | |
// 「Exec」メソッドには以下の特徴があり、一長一短の関係。 | |
// ・呼び出し先の完了を待つことが出来ない … StdOut.ReadAll()を使えば一応待てる。 | |
// ・intWindowStyleが選べない。 | |
var path外部スクリプト = this.作成(func) | |
var path引数受け渡しファイル = 引数と戻り値の受け渡しファイルを作成(引数) | |
var cmd = 'cscript //Nologo "'+path外部スクリプト+'" "'+path引数受け渡しファイル+'"' | |
var objExec = AXO.shell().exec(cmd) | |
var returnObj = { | |
StdOut : objExec.StdOut.ReadAll(), | |
StdErr : objExec.StdErr.ReadAll() | |
} | |
// エラーがある場合「C:\ … \外部スクリプト.js(3, 3) Microsoft JScript 実行時エラー …」のような文字列が出力される。 | |
// 一つ目の数字がエラー発生行 | |
if(returnObj.StdErr.match(/^[^\n]+\((\d+),/)){ | |
returnObj.エラー行 = AXO.fs.RAS(path外部スクリプト)[RegExp.$1-1].replace(/^\s+/g,'') | |
} | |
this.削除(path外部スクリプト) | |
this.削除(path引数受け渡しファイル) | |
return returnObj | |
}, | |
デバッグ方法のサンプル:function(){ | |
var funcエラー=function(引数){ | |
// Aは宣言されていない、というエラーが出る筈 | |
WScript.Echo(A) | |
} | |
var funcOK=function(引数){ | |
WScript.Echo(123) | |
} | |
var 引数 = 1 | |
// 「デバッグ用」ではエラーが発生した場合、発生行やエラーの内容などが取得できる。 | |
WScript.Echo(toJSON(外部スクリプトファイル.デバッグ用(funcエラー,引数))) // 戻り値:{StdOut:'', StdErr:'C:\\…\\外部スクリプト.js(3, 6) …', エラー行:'WScript.Echo(A)'} | |
WScript.Echo(toJSON(外部スクリプトファイル.デバッグ用(funcOK ,引数))) // 戻り値:{StdOut:'123\r\n', StdErr:''} | |
// 「実行」ではエラーが発生しても「func実行後」を渡していなければ「実行」メソッドは何もreturnしない。 | |
// 「func実行後」を渡していても、returnの中身はエラーがあったことを示す「-1」のみ。 | |
var path = 外部スクリプトファイル.作成(funcエラー) | |
WScript.Echo(外部スクリプトファイル.実行(path, 引数, 1)) // 戻り値:(無し) | |
WScript.Echo(外部スクリプトファイル.実行(path, 引数, 1, funcエラー)) // 戻り値:-1 | |
外部スクリプトファイル.削除(path) | |
var path = 外部スクリプトファイル.作成(funcOK) | |
WScript.Echo(外部スクリプトファイル.実行(path, 引数, 1, funcOK)) // 戻り値:(無し) | |
外部スクリプトファイル.削除(path) | |
} | |
} | |
var 引数と戻り値の受け渡しファイルを作成=function(引数){ | |
var path = AXO.fs.pathTMP+'/'+getTime()+'_外部スクリプト用引数受け渡しファイル.txt' | |
AXO.fs.Write(path, toJSON({引数:引数})) | |
return path | |
} | |
return returnObj | |
}() | |
var ActiveXObject関係=function(){ | |
AXO = function(短縮名, 正式名){ | |
var AXO = new ActiveXObject(正式名) | |
return arguments.callee[短縮名] = function(){ return AXO } | |
} | |
var fso = AXO('fs', 'Scripting.FileSystemObject') | |
var fs = fso() | |
fso.Read = function(p){var r=fs.OpenTextFile(p),v=r.AtEndOfStream?'':r.ReadAll();r.Close();return v} | |
fso.RAS = function(p){return fso.Read(p).split('\r\n')} | |
fso.Write = function(path,v){with(fs.CreateTextFile(path)){Write(v);Close()}} | |
fso.pathTMP = fs.GetSpecialFolder(2) | |
var obj = AXO('shell', 'WScript.Shell') | |
var shell = obj() | |
obj.getDir = function(path,swDir){ | |
var arr=shell.exec('cmd /C dir /A'+(swDir?'':'-')+'D /B "'+path.replace(/[/]/g,'\\')+'"').StdOut.ReadAll().split('\r\n').reverse() | |
!arr[0] && arr.shift() | |
return arr.reverse() | |
} | |
} | |
ActiveXObject関係() | |
LEN='length' | |
for0L = function(arr,fun){for(var i=0,L=arr[LEN],res;i<L;i++){if(res=fun(i,arr[i])){return res}}} | |
forIn = function(obj,fun){var name,res; for(name in obj){if(res=fun(name, obj[name])){return res}}} | |
getTime=function(d){return (d || new Date()).getTime()} | |
toJSON=function(){ | |
var main=function(o){ var t=gt(o); return o===null ? 'null' : objT[t] ? objT[t](o) : objC[gc(o)](o) } | |
var gt=function(o){return typeof(o)}, gc=function(o){return o.constructor}, objT={}, objC={}, fStr, nt='\n\t' | |
var n2nt = function(v){return (v+'').replace(/\n/g,nt)} | |
objT[gt('')] = fStr = function(s){return '"'+(s+'').replace(/\\/g,'\\\\').replace(/\r/g,'\\r').replace(/\n/g,'\\n').replace(/"/g,'\\"')+'"'} | |
objT[gt(0)] = objT[gt(true)] = objT[gt(gt.und)] = objC[gc(/1/)] = function(v){return (''+v).toLowerCase()} | |
objC[gc(new Date())] = function(o){return 'new Date("'+o+'")'} | |
objC[gc(gc)] = function(o){return インデント調整(o)} | |
objC[gc({})] = function(o){ | |
if(循環.名前push(o)){return '"参照の重複"'} | |
var a=[], i=0 | |
forIn(o,function(n,v){ a[i++] = fStr(循環.名前=n)+':'+n2nt(main(v)) }) | |
循環.pop() | |
return '{'+nt+a.join(','+nt)+'\n}' | |
} | |
objC[gc([])] = function(o){ | |
if(循環.名前push(o)){return '"参照の重複"'} | |
var a0=[], s, a1=[], i=0 | |
for0L(o,function(i,v){a0[循環.名前=i]=n2nt(main(v))}), s='['+nt+a0.join(','+nt)+'\n]' | |
forIn(o,function(n,v){ !a0[n] && (a1[i++] = 'a['+fStr(循環.名前=n)+']='+n2nt(main(v))) }) | |
循環.pop() | |
return a1[LEN] ? (インデント調整(function(){ | |
var a=sss | |
aaa111 | |
return a | |
})+'()').replace(/sss/,n2nt(s)).replace(/aaa111/,a1.join(nt)) : s | |
} | |
objC[gc(function(){})] = function(o){ | |
if(循環.名前push(o)){return '"参照の重複"'} | |
var a1=[], i=0 | |
forIn(o,function(n,v){ a1[i++] = 'f['+fStr(循環.名前=n)+']='+n2nt(main(v)) }) | |
循環.pop() | |
return a1[LEN] ? (インデント調整(function(){ | |
var f=sss | |
aaa111 | |
return f | |
})+'()').replace(/sss/,n2nt(o)).replace(/aaa111/,a1.join(nt)) : o | |
} | |
var 循環=function(){ | |
var arr候補, arr確定, key, arr重複候補 | |
var getKey=function(){return key[LEN] ? '['+key.join('][')+']' : ''} | |
return { | |
init:function(){arr候補=[]; arr確定=[]; key=[]; arr重複候補=[], this.名前=''}, | |
名前:'', | |
名前push:function(o){ | |
this.名前 && key.push(fStr(this.名前)) | |
// 追加した名前に対応するoと一致するものがarr候補にあるならtrueを返す | |
var fun=function(i,候補){return o==候補.o && arr確定.push({s:候補.key, d:getKey()}) && key.pop()} | |
if(key[LEN] && (forIn(arr候補,fun) || forIn(arr重複候補,fun))){return true} | |
// 一致するものがなければ候補に追加する | |
arr候補.push({o:o, key:getKey()}) | |
}, | |
pop:function(){key.pop(), arr重複候補.push(arr候補.pop())}, | |
getRes:function(objName){var a=[]; for0L(arr確定,function(i,o){ a.push(objName+o.d+' = '+objName+o.s) }); return a} | |
} | |
}() | |
return function(o){ | |
循環.init() | |
var s=main(o), a=循環.getRes('o') | |
return !a[LEN] ? s : 'function(){\n\tvar o='+s.replace(rNg,nt)+'\n\t'+a.join('\n\t')+'\n\treturn o\n}()' | |
} | |
}() | |
} | |
汎用スクリプト() | |
外部スクリプトファイル.デバッグ方法のサンプル() |
Microsoft Developer Network - WSH Runメソッド
0 件のコメント:
コメントを投稿