標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

任意の map[string]~ のキーを全部配列( []string )化してソート

map のキーは文字列限定だが、値については任意の型 Ok

import (
    "reflect"
    "sort"
)

// SortedKeys makes sorted strings' array from keys of the given map whose key's type is string.
func SortedKeys(mapInt interface{}) []string {
    values := reflect.ValueOf(mapInt).MapKeys()
    result := make([]string, len(values))
    for i, value1 := range values {
        result[i] = value1.String()
    }
    sort.Strings(result)
    return result
}

こんな感じで使う

 for _, key := range texts.SortedKeys(BoolOptions) {
        val := BoolOptions[key]

reflect を使ってるから、たぶんすごく遅いんだろうなぁ

GENESTUB という汎用スタブモジュールを公開しました。

昔作った子プロセスが想定どおり呼ばれているかテストするためのスタブモジュールを MIT ライセンスで公開します。 Windows用ですが、.NET Framework 4.0 以降が必要です。

zetamatta/genestub: Stub module to test the child-process is called as expected.

実行すると、GUIのタブで起動コマンドライン環境変数を表示したり、標準出力やエラー出力、ERRORLEVELを設定できます。

f:id:zetamatta:20180623180543p:plain

f:id:zetamatta:20180623180554p:plain

f:id:zetamatta:20180623180618p:plain

受託開発では、責任範囲の切り分けのために、担当する機能単位で、実行ファイルを分けることも多いんですよね。そういった時に他のモジュールをちゃんと想定通り呼び出せているかをログを足さずにチェックするツールがあれば便利だと、会社でこっそり作りました。

ずっと、自分の bin ファイルに置いておいたものですが、結構、一般向けに使えるかと思いましたので、会社にあるモジュールへの依存コードの履歴を塗りつぶして(おいおい)、公開することにしました。

利用する際は、GENESTUB.exe という名前そのままではなく、呼ばれる子プロセスのモジュール名にリネームしてご利用ください。

以上です。

内蔵Luaで実行する際、@ で始まる行を無視するよう修正した

nyagos 4.3 で、バッチファイルに Lua を組み込んで実行する際、内蔵Lua が 5.3 から 5.1 になったため、ラベルの文法がなくなって

@setlocal & set "ARGS=%*" & nyagos.exe --norc  -e "_,_,b=io.input([[%~f0]]):read('*l','*l','*a');assert(loadstring('\n'..b,[[%~f0]]))()"
@endlocal & exit /b %ERRORLEVEL%

とかヘッダに書かなくてはいけなくなって、たいへんになった…とに書いた。 でも、ホストアプリケーションを自分で書いているんだから、このくらい何とか出来そうなもんだ。

ということで、何とかした:

@nyagos --norc --lua-file "%~f0" %*
@exit /b %ERRORLEVEL%

for key,val in pairs(arg) do
    print(key,val)
end

単に読み出す時に @ で始まる行をカットするようにしただけ。 これを実現するのが以下の関数

func DoFileExceptForAtmarkLines(L *lua.LState, fname string) error {
    fd, err := os.Open(fname)
    if err != nil {
        return err
    }
    reader, writer := io.Pipe()
    go func() {
        scan := bufio.NewScanner(fd)
        for scan.Scan() {
            line := scan.Text()
            if len(line) > 0 && line[0] == '@' {
                line = ""
            }
            fmt.Fprintln(writer, line)
        }
        writer.Close()
        fd.Close()
    }()
    f, err := L.Load(reader, fname)
    reader.Close()
    if err != nil {
        return err
    }
    L.Push(f)
    return L.PCall(0, 0, nil)
}

GopherLua には文字列を実行する LoadString , ファイルを実行する LoadFile の他に、io.Reader を取る Load があるので、それに ioPipe のパイプラインの Reader 側を渡しているわけだ。こんなカジュアルに goroutine を作ってもいいのかなぁとつい考えてしまうが、全部を読みだして、string.Builder で文字列化してから、string.Reader を渡すよりはマシか。もっとコスト低い方法はないかな…

nyagos 内蔵 Lua 組み込みバッチファイルの雛型

nyagos内蔵Lua が 5.1 になったので前の 5.3 向けの方法が使えなくなった

donyagos.cmd

@setlocal & set "ARGS=%*" & nyagos.exe --norc  -e "_,_,b=io.input([[%~f0]]):read('*l','*l','*a');assert(loadstring('\n'..b,[[%~f0]]))()"
@endlocal & exit /b %ERRORLEVEL%

print(nyagos.env.args)

自分のマシンの IP アドレスを列挙するコマンドを作った

自分の IP アドレスを表示するだけのコマンド。Go の net ライブラリを使った。

  • IPv4 アドレス
  • UP している
  • loopback でない
  • キーワードが指定されている時は、そのキーワードがインターフェイス名に含まれたものとする

マシンのブート時に以下のようなコマンドを含むバッチファイルを実行して、IP アドレスを OneDrive 上のファイルに出力させる (相対パスを使っているので分かりにくいのは勘弁)

"%~dp0..\bin64\localhosts.exe" -o "%~dp0\..\etc\%COMPUTERNAME%" ローカル

これを拾い上げて、自宅から会社にリモートログインする際の宛先とするのだ。 固定IP なら、こんな苦労はなかったんだけどねぇ…

nyagos豆知識!(じゃじゃーん)- 「cd -h」

「cd -h」とすると、それまでたどったディレクトリが一覧で出るよ。もし「-2 C:\Users\hymko」とか表示されたら「cd -2」でそこへ移動できるよ!

<DESKTOP-LGGUCRA:~/go/src/github.com>
$ cd -h
-3 C:\Users\hymko
-2 C:\Users\hymko\go\src\github.com\zetamatta\nyagos
-1 C:\Users\hymko\go\src\github.com\zetamatta
<DESKTOP-LGGUCRA:~/go/src/github.com>
$ cd -2
<DESKTOP-LGGUCRA:~/go/src/github.com/zetamatta/nyagos>
$

静的型付け言語に慣れた開発者が AutoLISP でやったアレコレ

(2018.06.02)
「静的型付け言語に慣れた開発者が貧弱なCAD用 Lispでやったアレコレ」からタイトル変更しました

静的型付け言語になれた身としては、欲しい機能がいろいろなくて、つらたにえん。せめて、CommonLisp だったら、もうちょっと楽なんだろうなぁ(使ったことないけど)

(let) がない

ローカル変数は使えるが、宣言できる場所が (defun) の直後だけというのはつらい。もっと使う場所の近くで、狭い有効範囲をきって使いたい。普通は(let)を使うところだが、CAD系Lispには(let)がない。仕方ないので((lambda (/ 変数リスト) … )) で代用するようにした(というのが下記の記事)

early-return がない

他の言語だと、エラーの場合早々に return するのがよいとされているが、CAD用Lispには return 文的なものがない。結果、関数の頭で、エラーチェックをたくさんする時、以下のような問題がある。

  • (if) でエラーチェックすると、正常系のコードが else句の奥底のすごく深いインデントになってしまう
  • (quit) でアプリケーションを終了すると、finally 的処理が呼ばれない(エラートラップ等でひと工夫すればできなくもないが、仕組みが大層)

(cond) を使うようにすれば、エラーケースがたくさんあっても、あまりインデントは深くならない(ただ、エラー条件が複雑になると、うまく書けない時も多い)

(cond
  ((エラー条件1)
   エラー処理1
  )
  ((エラー条件2)
    エラー処理2
  )
  ; 中略
  ((エラー条件N)
    エラー処理N)
  (T
     正常系処理
  )

グローバル変数をうっかり壊してしまう

Perl でいうところの use strict が欲しい。なければ作ればよいのだ。

ソースファイルをS式として読み込んで、(defun)の中身を解析し、未使用の変数や、逆に宣言漏れがあったら、コマンドラインにリポートする。

名前空間がない

いろいろ (load) していると関数名が被ることが懸念される。といっても名前空間がないので、

  • グローバルな名前には接頭語をつける(ありがち)
    • foo.lsp ならば (defun foo-xxxx …)
  • 関数内関数で済むなら、それですませる(その関数名はローカルで)

といった方向で誤魔化す。

以上