URLからトラッキングのアレを削除するやつ書いた
モチベーションは Neat URL がだいぶ前から動かなくなっていた*1から。
似たようなアドオンも軒並み死んでいるように思うので自分で作りました。
とりあえず単純なトラッキングタグ(って言うのかな?)は削除できるようにしてあり、最終的な目標としては Neat URL と同等の機能を持たせてあげたい。
グリモンスクリプトなので、 Edge, Firefox, Chrome, Safari 等のグリモン系アドオンがあり
'URL' in window && 'URLSearchParams' in window
が真となる環境であれば問題なく使えるはずです。
なんなら Firefox for Android であればスマートフォンでも使えます*2。
npm scripts で OS ごとに処理を分ける
npm scriptsに clean
ってコマンドを登録しようとしたんですよ。
普通なら rimraf を使うところなんですが、 cleanの過程で node_modules
ディレクトリも削除して綺麗にしたい。
かと言って npm i -g rimraf
など、環境依存になるので以ての外。
rm
コマンドは *NIX 環境に依存してしまう。
rd
コマンドは Windows環境に依存してしまう。
さて困った。
そこで閃きました。
"scripts": { "clean": "node -e \"process.exit(process.platform === 'win32' ^ 1)\" && rd /s /q node_modules || rm -rf node_modules" }
こうします。
これならば、process.platform
を評価して win32
だった場合とそれ以外で処理を分けることができます。
※ true ^ 1 // ==> 0
false ^ 1 // ==> 1
となり、シェルはこれをエラーコードと見るため、 &&
や ||
で繋げることによって処理が分かれます。
git stash の tips
git stash
、使ってますか?
作業中の内容を一旦別に追いやることで他のコマンドを阻害しなくなる便利なコマンドです。
git stash
の詳細については、Qiitaやら各種ブログやらで説明していらっしゃる先人がたくさんおりますので、そちらにお譲りします。
tl;dr
git stash <subcommand> stash@{<n>}
を省略して git stash <subcommand> <n>
と書ける。
本文
みなさんご存じの通り、Gitの各種コマンドには様々なサブコマンドがあり、この git stash
も例外ではありません。
この内、
git stash show
git stash apply
git stash pop
git stash drop
git stash branch
は何も引数を与えず実行すると、暗黙的に stash@{0}
が採用されたものと見做されます1。
で、引数を与える場合、特にstashの番号を与える場合は stash@{2}
とか stash@{3}
とか、 stash@{n}
のフォーマットで書きます。
これ、数タイプではありますが結構面倒くさいですよね。typoの可能性だって出て来ます。
GitはコミットをSHA1のハッシュで管理しています。
多くのGitコマンドはコミットの指定にハッシュ値の入力を要求しますが2、このハッシュ値は現在のリポジトリの中で一意に特定さえできれば、最低4文字まで省略できることになっています。
例えば、リポジトリに caf1234...
というコミットがあり、 他に caf1
で始まる他のコミットがなければ、
git checkout caf1
でこのコミットにチェックアウトすることができます。
caf10...
というコミットが他にあれば caf1
では候補が2つあることになってしまうので、
一文字追加して git checkout caf12
でチェックアウトできますね3。
で、私思いました。ハッシュ値が省略できるなら、もしかしたらstashの指定も省略できるのではないかと。
何気なく git stash drop 1
と入力して実行してみたら、何と、通りました。
ドキュメントを読んでみるとこんな記述があります。
The latest stash you created is stored in
refs/stash
; older stashes are found in the reflog of this reference and can be named using the usual reflog syntax (e.g.stash@{0}
is the most recently created stash,stash@{1}
is the one before it,stash@{2.hours.ago}
is also possible). Stashes may also be referenced by specifying just the stash index (e.g. the integern
is equivalent tostash@{n}
).
太字部分を雑に訳すと「インデックスだけを指定して参照することもできます(例えば n
は stash@{n}
と等価です)」といった感じでしょうか。
恥ずかしながら、今までこの略記を知りませんでした。
いろいろな git stash
に言及している記事を読んでもこの略記について触れているものは私の観測範囲にはありませんでした。
意外と知られていないのかな、と思ってこのエントリを書きました。
ちなみに HEAD
も @
という略記がありますが、これは結構有名ですよね。
Visual Studio Code for Windows の Integrated Terminal に MSYS2 の fish を使う
fish、便利です。
当方は未だにWindows 8.1 UpdateなのでWSL1は使えません。
なので Git for Windows SDK をインストールして簡易的なシェル環境を構築してます。
これが pacman があるのでなかなか快適なんですね。
nodeもこれで入れられるのでchocolateyもほぼ不要になります。
Git for Windows の本来のシェルは Git Bash ですが、他のシェルも pacman 経由でインストールできるため、私は fish をインストールしてこれをデフォルトにしています。
本題です。
慣れたシェルを使っていると、あらゆる場面で導入したくなるもので、VSCode の Integrated Terminal にも fish を導入したくなりました。
で、おもむろに Ctrl + ,
で設定画面出しますね。
{ "terminal.integrated.shell.windows": "C:/git-sdk-64/usr/bin/fish.exe", "terminal.integrated.shellArgs.windows": [ "-i", "--login", ], }
と入力します。2
Ctrl + @
でターミナルを表示するとどうでしょう、エラーの嵐になります。
いろいろ調べた結果、 $PATH
がほとんど空っぽになっていることが分かりました。
"C:/git-sdk-64/usr/bin/fish.exe"
の代わりに "C:/git-sdk-64/usr/bin/bash.exe"
と書いた場合は何の問題もなく起動し、パスも普通に通ってしまうので謎です。
ちなみに bash でうまく行くからと言って
{ "terminal.integrated.shell.windows": "C:/git-sdk-64/usr/bin/bash.exe", "terminal.integrated.shellArgs.windows": [ "-c", "/usr/bin/fish", ], }
としても無駄です。
盛大にエラります。
結構な時間を試行錯誤でアレコレし、
{ "terminal.integrated.shell.windows": "C:/git-sdk-64/usr/bin/fish.exe", "terminal.integrated.shellArgs.windows": [ "-c", "eval 'set -x PATH ~/bin /mingw64/bin /usr/bin $PATH; and /usr/bin/fish'", ], }
と書くことでひとまず解決しました。
fish では変数にスペース区切りで値を与えると配列として格納されます。
$PATH
も配列で持っているので、その先頭に強引にパスを与えてしまいます。
fish.exe をコールしている段階では $PATH
は無事のようなので、ここで set -x PATH ...
としてしまいました。3
VSCode には、シェルに与える環境変数をオーバーライドする terminal.integrated.env.windows
という設定値もあるのですが、ここだと ~
や $PATH
が展開されない為、已む無くコマンド評価で与えています。
正直言ってワークアラウンド的でスマートさに欠けるので、もっといい方法があれば是非教えていただきたいですね。
あとなぜ $PATH
が消え去るのかの原因も分かる方いらっしゃれば…。
式途中に null として評価されてしまうケースの回避方法
F# の話題です。
let x = A().B.C.D
とあるとき、もしA().B
が null
だったら?
F# で定義した型は AllowNullLiteralAttribute
属性を付与するか Unchecked.defaultof<'a>
を使用しない限り、たとえ参照型だろうが null
になることはありません。
でもCLRのクラスは null
の可能性があります。
.NET Framework の資産を使う以上、 NullReferenceException
と付き合っていく必要はどうしてもあります。
一番愚直な方法は、いわゆる nullチェックです。
let x = match A() with | null -> null | x -> match x.B with | null -> null | x -> match x.C with | null -> null | x -> x.D
…ツラすぎる。
次、Maybeモナドみたいなコンピュテーション式を使う方法。
[<AutoOpen>] module Maybe = type MaybeBuilder() = member __.Bind (x, f) = if x = null then null else f x member __.Return x = x let maybe = MaybeBuilder() let x = maybe { let! x = A() let! x = x.B let! x = x.C return x.D }
さっきよりは大分マシになりましたね。
まぁこれでいいんですが、もう一歩やってみました。
クッソ長いんですが、要は評価したい式を引用式として与えることで、途中で null
を検出したら全体を null
とするってことです。
null
を None
、非 null
を Some x
として見れば、まさにMaybeモナドがやっていることとニアリーイコールの結果を得られるわけです。
Gist のコメントに書いたやつのコピペですが、
open System open QuotationUtility let nullUri : Uri = null let result1 = Quotation.evaluate <@ "not null value" @> let result2 = Quotation.evaluate <@ (Uri("http://example.com/")).AbsoluteUri @> let result3 = Quotation.evaluate <@ (null : Uri).AbsoluteUri @> let result4 = Quotation.evaluate <@ nullUri.AbsoluteUri @> printfn "1 : [%A] / 2 : [%A] / 3 : [%A] / 4 : [%A]" result1 result2 result3 result4 (* 1 : ["not null value"] / 2 : ["http://example.com/"] / 3 : [<null>] / 4 : [<null>] *)
大体こんな感じになります。
なんとなーく動いてるように見えますね?
上の例で言えば let result = Quotation.evaluate <@ A().B.C.D @>
とすることで、仮に A().B
が null
だったとしても result
には null
が束縛されるだけです。もちろん D
まで正しく評価できれば D
の値が束縛されます。
たぶんバグあるので複雑な式を与えるとエラると思いますが、少なくとも単純な式なら null
を検出できているようです。
これを使えばスマートに nullチェックできるんじゃないでしょうか。
リフレクションなので、評価回数が増えてくると速度低下に繋がるところがネックですね。
ところで、F#のシンタックスハイライト、なんか毒々しいですね。