- 投稿日:
Prettier の次期 Major release である v3 がそろそろ出そうなので、今回含まれる大きな変更の一つについての記事です。
内容としてはMarkdown文書の全角文字と半角英数の間にスペースが挿入されなくなります。個人的にこれは相当賛否が分かれると思うので、v3が出た後の対処方法も併せて書いておきます。
変更点
以下は漢字Alphabetsひらがな12345カタカナ67890
という文字列が渡された時の変化例です。
v3 より前 | v3 以降 |
---|---|
漢字 Alphabets ひらがな 12345 カタカナ 67890 |
漢字Alphabetsひらがな12345カタカナ67890 |
多分スペースが空いたときのほうが好みといった人が一定数居ると思います。個人的には検索性が破滅的に低下するためこの機能には否定的でしたが、今回のアップデートで遂にスペースが入らなくなったので、割と喜んでいます。ぶっちゃけこのブログの過去記事ににある余計なスペースも現在全て除去する作業をしてるくらいです。
発端としては次のIssueにあり、これをずっと追っていた人もきっといると思います。私もそのうちの一人です。
この問題は次のPullRequestで対応され、現在v3 用のブランチに取り込まれています。
- [Markdown[next branch]: Do not insert spaces between Chinese/Japanese & latin letters #11597](https://github.com/prettier/prettier/pull/11597)
この機能を試したい場合、以下のようにインストールすることで試すことが出来ます。
npm i -D https://github.com/prettier/prettier.git#next
なお、PullRequestにある通り既にあるものには影響しないので、既にあるスペースを詰めることは出来ません。
これまで通りスペースを入れたい場合
引き続き漢字Alphabetsひらがな12345カタカナ67890
を漢字 Alphabets ひらがな 12345 カタカナ 67890
にしたいケース
前述のPullRequestの中でも言及されていますが、textlintを利用することで対応できます。ただPrettierと併用するのは難しいと思います。
導入方法
textlintにtextlint-rule-preset-ja-spacingを組み合わせて対応します。
npm i -D textlint textlint-rule-preset-ja-spacing
使用方法
まず.textlintrc
を作成し、次の設定を追加します。
{
"rules": {
"preset-ja-spacing": {
"ja-space-between-half-and-full-width": {
"space": "always"
}
}
}
}
CLIを用いて修正する場合
npx textlint --fix <path>
VSCodeを用いる場合、vscode-textlintをインストールし、settings.json
に以下の設定を追加することで利用することが出来ます。Prettierと併用する場合、Prettierと競合し、textlintが負けるため、Markdownの整形に関してはtextlintに任せるのが無難だと思います。
{
"textlint.autoFixOnSave": true
}
一応Custom Local Formattersを使えば近いことは出来なくもないのですが、ファイルへの書き込み同期がズレてるのか上手く動かない気がします。一応以下の設定で動くことには動きますが、あんま期待しないほうがいいかも…。拡張からコマンドを蹴ること自体セキュリティ的に微妙な気がするので、この方法は使わないのが無難な気がします。
{
"[markdown]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "jkillian.custom-local-formatters"
},
"customLocalFormatters.formatters": [
{
"command": "npx prettier ${file} | npx textlint --stdin --stdin-filename ${file} --fix --format fixed-result",
"languages": ["markdown"]
}
]
}
これはPrettierとtextlintを呼ぶ時点で二重処理になって重いので、Markdownのフォーマットはどっちか片方にやらせたほうが良いでしょう。ただtextlintはデフォルトだと表の整形とかいい感じにしてくれないようなのが困りものです。textlintにmarkdownプラグインを入れると改善されるかもしれませんが試してないです。
これまでのスペースを消したい場合
既にある漢字 Alphabets ひらがな 12345 カタカナ 67890
を漢字Alphabetsひらがな12345カタカナ67890
にしたいケース
前項の「これまで通りスペースを入れたい場合」で紹介した環境を導入し、.textlintrc
を以下のように作成すればある程度は対応できます。但し完全には除去しきれません。
{
"rules": {
"preset-ja-spacing": {
"ja-space-between-half-and-full-width": {
"space": "never"
}
}
}
}
この設定によるtextlintの整形結果は以下のとおりです。記号の前後の半角スペースや見出しやリンク文章にある半角スペースは除去しきれないようです。
## 123 あああ abc
-ユーザー ID は Slack アプリから
+ユーザー IDはSlackアプリから
やよいの ○ 色申告
[Web サイトの example](https://example.com)
余談
多分大抵の人はPrettierをv3にしてからこの事に気が付くと思います。当然です。一々 OSSのアップデートを追っている人は恐らくメンテナか物好きだからです。
現在Prettierのリポジトリでは似たような議論として、デフォルトでインデントにスペースを使っているところをタブに置き換えようという動きがあります。幸いv3では採用に至っていませんが、今後採用される可能性があり、メンテナであるSosuke Suzuki氏もこの事について以下の記事で憂慮されています。
ある日突然インデントのスペースがタブに変われば、苦情が出るのは明白です。設定一つ直すだけとは言え、影響は大きいでしょう。CIで全体にPrettierを掛けていないプロジェクトでは一時的にタブインデントのファイルとスペースインデントのファイルが混在するケースもあると思います。空白文字の差分表示や検出を無効化していると気づかないまま、そのような状態になるケースもあると思います。
個人的にはMarkdownに落とした時にどの環境でも同じように見えるという理由でスペースインデントが好みですが、A11yの観点からタブにせよという考えも理解は出来ます。でもブラウザで.md
ファイル見たときとかに見づらいんですよね…。Python や PHP、YAML の様に標準がスペースインデントの言語もありますし、個人的には標準はスペースで構わないのではと思ったりもします。(その上で必要に応じてタブを使うという選択肢は出来ると思います。Google JavaScript Style Guideでも、これが標準です。Prettierは代表的なフォーマッタで事実上のコーディング標準であるとも言えるため、社会的責務でそうする必要があるかもしれませんが、個人的な思いとしては標準はスペースのままであってほしいなぁと思います。どうしても標準が変わると、世間はそこに引きずられざれ得ないと思いますから。
多分今回の変更も、上記のuseTab
同様に一部で非難が上がる気がしていて、余り大事にならなければいいなぁ…とか考えています。(タブと比べると影響範囲が狭いので、ひょっとしたら今回はあまり何も起きないかもですが…)
- 投稿日:
Bioサイトを作っていた時にimgタグの下に謎の隙間ができることに気がついたので、その対処録。
問題
画像の下に謎の隙間があり、DevToolsで見るとaタグがはみ出ているように見える。margin
やpadding
を0
にしても効果なし。
aタグを外して、imgタグ単体にしても起きる。
再現コード例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>lycolia.info</title>
</head>
<body>
<a href="https://example.com">
<img src="example.png" width="200" height="40" alt="example">
</a>
</body>
</html>
原因
imgタグはinline要素なので vertical-align の既定値が baseline になっている関係で、文字の下端と画像の下端が合う状態になっているために、隙間が生まれていることが確認できる。
解決策
imgタグに対してvertical-align
にbottom
ないしtop
を指定すれば解消する。
勿論この状態で横に文字を並べると、その文字は当然浮くが、今回はこの解決方法は扱わない。
参考コード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>lycolia.info</title>
</head>
<body>
<a href="https://example.com">
<img style="vertical-align: bottom;" src="example.png" width="200" height="40" alt="example">
</a>
</body>
</html>
- 投稿日:
Windows向けのツールを作ろうというので、昔よく使っていたC#.NETで開発をすることにしたのですが結構苦労があったのでその話を書いていこうと思います。Unit testingを書くのは一旦断念しましたが、暇があれば挑戦したいとは思ってます。
事のいきさつ
WindowsのVSCodeでRemote Development拡張を使うことが多いのですが、リモートエクスプローラーにアイテムが増えてくると移動したいフォルダを探すのが大変になってくるのと、ここに出てないフォルダを開くのが結構手間という問題があり、これを解決できないかということを考えていました。
そこで考えついたのがWSLやSSHのネットワークパス上でExplorerの右クリックメニューを開いたらVSCodeがリモートモードで起動できると良いのでは?という所でした。Windows向けでexeからバイナリ起動するならC#で書くのが楽だろうと考え、C#での開発に着手しました。
疎結合な実装でUnit testingもできたらいいなーと漠然と考えながら開発していたのですが、最後にC#を書いたのは3年ほど前で、C#でモダンな実装をした経験もなかったので結構苦労しました。よく考えたらTypeScriptかJavaScriptくらいでしかまともにやったことがないし、UT自体他言語でもGolangかPHPでしか書いたことがなかったので、C#でこれをやるのは自分の実装技術に対する一種の挑戦みたいなところがありました。結論としてはあっけなく破れたわけですが…。
ツールの要件
- Explorerの右クリックメニューから起動する
- 開いたパスに応じてWindowsローカル、SSH、WSLを判定し、適切なモードでVSCodeを起動する
- パス解決には設定ファイルを用いる
- Explorerから渡されるパスはリモート環境のパスと差異があるので、そこを解決するためのものです
ツールの設計
やることは設定ファイルを読み込み、コマンドライン引数から値を取得し、それらをいい感じに変換してVSCodeに渡すだけです
大まかなフロー
実行形式
- コマンドライン引数
this.exe <dir path>
-
設定ファイル形式
```json5
{
"CodePath": "VSCodeのexeパス",
// リモートホスト定義。辞書形式
"Remote": {
"リモートホスト名": {
"ExplorerPrefix": "explorerのパスから除外する文字列",
"AppendPrefix": "explorerのパスに追加する文字列"
},
}
}
```
ツールの実装
まずはTDD的にやろうとしてInterfaceを作成し、Classで実装し、ロジック自体は好調に組み上がっていき、テストもすべて通るようになりました。但し実際にexeを蹴ると動かず、テストは通るが動かないゴミが出来上がっていました。(途中で動作確認をしなかったのか?と思うかもしれませんが、実際は完全に動くものを作ってからテスト可能な形に書き換えるという流れで作っていたのでこうなっています)
動かなかった理由は設定ファイルにJSONを採用していて、デシリアライザにSystem.Text.Json.JsonSerializer
を使っていたためです。このデシリアライザは標準ではInterfaceに対してJSONをデシリアライズできません(考えてみれば当然ですが)。しかし、テストをするためにはモックをDIしたいので、Interfaceが必要です。
以下は実際に設定を読み込むために実装したClassですが、メンバが全部Interfaceになっているので、標準の状態ではデシリアライズに失敗します。ならばデシリアライザを自作すればいいという話が出てくるのですが、高々設定ファイルを読み込む処理にそこまで情熱を込めるか…?と言うことになり、諦めました。
public class ConfigBase : IConfigBase {
private IFileInfo? _CodePath;
private IDictionary<string, IConfigRemote>? _Remote;
public IFileInfo CodePath {
get {
if (this._CodePath == null) {
throw new Exception("Config Error: Missing CodePath.");
} else if (this._CodePath == null) {
throw new Exception("Config Error: CodePath is empty. Set the code.exe path in this field.");
} else if (!this._CodePath.Exists) {
throw new Exception("Config Error: CodePath is Not exists.");
} else {
return this._CodePath;
}
}
set { this._CodePath = value; }
}
public IDictionary<string, IConfigRemote> Remote {
get {
if (this._Remote == null) {
throw new Exception("Config Error: Missing Remote.");
} else if (this._Remote.Count == 0) {
throw new Exception("Config Error: Remote is empty. Set the remote infomation in this field.");
} else {
return this._Remote;
}
}
set { this._Remote = value; }
}
}
そもそもこのツールは「設定ファイルを読み込み、コマンドライン引数から値を取得し、それらをいい感じに変換してVSCodeに渡すだけ」のツールです。たったそれだけのツールに入れる仕組みにしては大げさすぎると感じました。
テストをするためにInterfaceを作ったり、本実装とモック用のClassを作る程度まではまだ容認できるのですが、カスタムデシリアライザを作ると、今度はそれのテストも必要になってきます。どう考えてもしんどい。
因みにこのコード、仮にInterfaceをやめても文字列をFileInfo
に組み替えるためのカスタムデシリアライザの実装が必要で結構頭が痛くなります…。多分そこはFile.exists
をラップしたクラスをDIしてやるのが無難な気がしますね。
この辺はTypeScriptだとimport
の中身をJestで書き換えたら終わりなのであんま考えなくていいのは楽ですが、C#だと厳しいなと感じました。
C#でテストを書いていて思ったこと
クラスベースで実装していくとメソッド単位でのテストがしづらく、テストがコケても原因が把握しづらいというのを一つ課題感として覚えました。TSでなんちゃって関数型開発をしていれば関数のUTを書けば関数の挙動を把握できますが、Classではそうも行きません。
仮に1つのpublic methodが5つのprivate methodを呼び出していて、private methodの裏ではprivate propertyが複雑な依存を持っていたとしたらどうでしょうか?
正直デバッグをかけないとどこで何がコケたか特定できないと思います。そんな実装にするのが悪いといえばそうですが、でもクラスってそういうものじゃないですっけ…?お互いに関連性がなくていいならもうそれ関数で良くないですか?って思いました。
勿論、全部静的メソッドにしてClassそのものは単なるエンティティにするのも選択肢の一つだとは思います。しかしC#でそこまでやるか…?という疑念が個人的にあるのと、処理を繋げたテストをUTとして書く方法がなくなると思います。例えばインスタンスメソッドならモックをDIすることでメソッドが呼ばれた事や、戻り値に対する分岐を確認できますが、静的メソッドでこれをやるのは難しいと思います。
Classの単体テストは関数と状態が密結合したテストになってしまうので、いまいち微妙だなと思ったのが今回思ったことでした。
- 投稿日:
runas
では上手く出来ないっぽいのでPowerShellを呼んで実行する。管理者実行したいコマンドを分けたい時に活用できる。
確認環境
Env | Ver |
---|---|
Windows 11 Pro | 22621.1413 |
サンプルコード
powershell start-process <ここにコマンド> -verb runas
備考
PowerShellのリファレンスに沿って書くなら大文字小文字を書き分ける方がより正しいが、基本的に大文字と小文字を区別しないため、どっちでも動く。
powershell Start-Process <ここにコマンド> -Verb runAs
- 投稿日:
TypeScriptやJavaScriptだとコマンド一発で見れるコードカバレッジですが、C#.NETの開発ではちょっと手こずったので導入方法を記録しておく。
確認環境
Env | Ver |
---|---|
Visual Studio 2022 Community | Version 17.5.1 |
.NET Framework | 6.0 |
導入手順
- C#.NETで開発用のプロジェクトを作成
- 作成したプロジェクトのソリューションにxUnitテストプロジェクトを追加
- 何かしらの実装と、それに対するテスト実装を作成
- Fine Code CoverageをVisual Studioにインストール
- ソリューションエクスプローラからxUnitテストプロジェクトを右クリックしてテストの実行
- 下部トレイにあるFine Code Coverageタブを選択
- 表示されていない場合は表示 → その他のウィンドウ → Fine Code Coverageで表示出来る
- 表示されていない場合は表示 → その他のウィンドウ → Fine Code Coverageで表示出来る
- コードカバレッジが表示される
疑問
Visual Studio 2022にもなって標準でコードカバレッジも取れないの?
今どきそんな事あるか?思って調べてみたところ、どうやらEnterpriseであればコードカバレッジを取る機能がついている模様。
まぁ無料版だから仕方ないねということで諦めるしかないでしょう。Professional版にもないけど…w。VisualStudioの便利機能は以前から有料機能に組み込まれる傾向があるので仕方がない気もしますが、取り敢えず今回は有志が便利なツールを作っていてくれて助かりました。
因みにコードカバレッジ自体は無料版でも取れます。ただこれはXMLのカバレッジレポートを吐くだけなので、可視化するには別途ここからHTMLを生成する必要があり面倒なので、なんかもっと楽な方法はないかなと思って見つけたのが今回のFine Code Coverageでした。
しかしFine Code Coverage便利なのにそこまで利用されているように見えないのは、やはりテストに関心がある人が少ないのか、公式にあるカバレッジHTMLを吐く方法で納得しているのか、その辺りが気になりました。自前でFine Code Coverageの様な物を作っている人もいるでしょうが、それは少数派だと思いますし。
この方法で取れるカバレッジは正しいものか?
GitHubのREADMEを読む限り、組み込みのカバレッジレポーターのAPIを叩いて取ってきたものを表示しているだけに見えるので、恐らく正しいデータが出ているのではないかと思います。
少なくとも単純なコードのUnit testingを書いた感じではテストケースを増減することでカバレッジも連動して増減していたのと、組み込みのレポーターがそのくらいはやってくれている筈で、これはその内容を表示しているだけなので恐らく大丈夫なのではないかと考えています。