[ Skill ] load 函數優化,識別相對路徑
在 cds.lib 文件中定義庫的路徑,為了規範庫定義的管理,經常這樣做:
.
|-- cds.lib ------------------- cat --> 1| INCLUDE ./common/cds.lib
`-- common
|-- cds.lib --------------- cat --> 1| INCLUDE ./project/cds.lib
| 2| INCLUDE ./project/cds.lib
|-- project
| |-- cds.lib ----------- cat --> 1| INCLUDE ./project/cds.lib
| | 2| INCLUDE ./project/cds.lib
| | 3| INCLUDE ./project/cds.lib
| |-- layout
| | `-- cds.lib ------- cat --> 1| DEFINE layout_lib1 ./layout_lib1
| | 2| DEFINE layout_lib2 ./layout_lib2
| | 3| 略 ...
| |-- sch
| | `-- cds.lib ------- cat --> 1| 略略 ...
| `-- 略略略 ...
`-- 略略略略 ...
可以看到,對於每一個 cds.lib 文件自身來說,裡面用的都是相對路徑。
同樣的用法在 Skill 中使用 load() / loadi() 函數卻不能支援相對路徑:
在上一篇隨筆 文件讀寫 & IO 句柄 整理的內容中,發現內置的句柄 piport 可以獲取當前文件的路徑這一特性,於是有了這一篇。
幾個函數
__FILE__
在 Perl 中 __FILE__ 用來獲取當前文件的路徑,這裡模仿一個。
procedure(__FILE__()
get_filename(piport)
); __FILE__
-
運行:
printf("Current path: %s\n" (__FILE__)) ; Current path: /home/yeung/tmp/load.il
__DIR__
正則處理,從 __FILE__ 結果中提取父目錄的路徑。
需要注意的是,如果是在 CIW 中執行的 __FILE__,它的返回值會是 *ciwInPort*,這種情況直接返回當前路徑 getWorkingDir 。
procedure(__DIR__(\@optional path((__FILE__)) "t")
if(pcreMatchp("^\\*.+\\*$" path)
getWorkingDir()
pcreReplace(pcreCompile("(?<=/)[^/]+/*$") path "" 0)
)
); __DIR__
-
運行:
printf("Current directory: %s\n" (__DIR__)) ; Current directory: /home/yeung/tmp/
ycReadRelPath
這個函數用來將 相對路徑 轉為 絕對路徑 。
當路徑為 ~ 或者 / 開頭是,說明已經是絕對路徑了,這種情況直接原封不動返回。
procedure(ycReadRelPath(\@optional file("") "t")
let((path)
path = if(pcreMatchp("^[~/]" file)
file
sprintf(nil "%s/%s" (__DIR__) file)
)
simplifyFilename(path t)
); let
); ycReadRelPath
-
運行:
printf("Target path: %s\n" ycReadRelPath("./init/load.il")) ; Target path: /home/yeung/tmp/dir/test.il
ycLoad
優化 load 函數。
預留一個 ignores 參數用來優化 loadi 函數。
procedure(ycLoad(file \@optional ignore "tg")
let((path)
path = ycReadRelPath(file)
unless(isFile(path)
error("ycLoad: not a valid file - %A" path)
)
unless(isReadable(path)
error("ycLoad: can't access file - %A" path)
)
if(ignore loadi(path) load(path))
)
); ycLoad
ycLoadi
優化 loadi 函數。
同樣可以忽略 load 過程中遇到的錯誤,列印錯誤消息,然後繼續 load 。
procedure(ycLoadi(file "t")
ycLoad(file t)
); ycLoadi
效果
-
沒有
ycLoad之前let((home wind sync) home = "/home/yeung/script/skill/tools/" wind = list("hiForm.il" "windCtrl.il") sync = list("syncView.il" "support3rd.il") foreach(x wind load(strcat(home "src/wind/" x)) ) foreach(x sync load(strcat(home "/src/sync/" x)) ) ); let非常啰嗦。
其次如果父文件夾改了名,或者移動了位置,還得一個個文件打開檢查路徑並修改,還要增加無意義的版本。
copy 給別人也不能傻瓜式操作,直接 load 報個錯:*Error* load: can't access" 唉 你 這 腳 本 有 問 題 啊 ? " -
有了
ycLoad之後ycLoad("src/wind/hiForm.il") ycLoad("src/wind/windCtrl.il") ycLoad("src/sync/syncView.il") ycLoad("src/sync/support3rd.il")"優雅地" load 完所有文件。

繼續優化可以再識別 Shell 環境中的變數。


