コーヒー飲みながら仕事したい

仕事で使う技術的なことの備忘録とか

Visual Studio 2017 で欠かせないプラグイン 4+1つ

個人的にこれは欠かせないっていう Visual Studioプラグインを備忘録として残しておきます。

Format document on Save

Ctrl + S で保存時、自動整形を実行してから保存してくれるプラグインです。
Visual Studio 自体にもプラグインの機能があるのですが、わざわざ Ctrl + K, Ctrl + D と2回も実行しないといけないし、明示的な操作をしないとソースファイルに反映されないので、このプラグインを使うことで使い勝手が格段に向上します。

marketplace.visualstudio.com

Git Diff Margin

かなり有名なプラグインですが、やはりこれは便利です。
git 管理が前提となりますが、ソースファイルを開いていたらプラグインが自動で git diff を実行してソース上にコミット前との変更箇所が視覚的に表示されます。
なんといっても、変更前と変更後のソースを直感的に確認できるのは便利です。

marketplace.visualstudio.com

VSColorOutput

出力ウィンドウ(ビルド実行時とかにビルドログとかが表示されるところ)の文字に色を付けてくれます。
エラーだったら赤色とか、正常ビルドできたら緑色とか、地味に便利です。

marketplace.visualstudio.com

Shrink Empty Lines

このプラグインを導入すると、文字や数値を含まない行の縦幅が 25% 縮小されます。ちょっとだけですが、見通しが良くなります。

marketplace.visualstudio.com

ForceUTF8 (with BOM)

ちょっとマニアックですが、保存時の文字コードを UTF8 に自動変換してくれます。
Visual Studio のデフォルト文字コードが UTF8 なので、基本的には恩恵を受けることはないのですが、私の環境で以前 Visual Studio が自動生成したコードが Shift-JIS だったことがありました。そのせいでコンパイルが通らなくなり、その理由もなかなか判明せずにハマったので、それ以降保険として適用しています。

marketplace.visualstudio.com

Visual Studio でビルド時に「のプロジェクト情報が見つかりません。これは、プロジェクト参照がないことを示している可能性があります。」でエラーになったときの対処法

(備考:もしかしたら .NET Standard のみの事象かもしれません)

事象

主題の通り、
Visual Studio でビルド実行時に、以下のようなエラーになりました。
xxx.csproj はソリューション内で参照しているプロジェクト)

'xxx.csproj' のプロジェクト情報が見つかりません。これは、プロジェクト参照がないことを示している可能性があります。

また、出力ウィンドウには以下のようなエラーが表示されました。

4>C:\Program Files (x86)\dotnet\sdk\2.0.0\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.Sdk.targets(114,5): error : 'xxx.csproj' のプロジェクト情報が見つかりません。これは、プロジェクト参照がないことを示している可能性があります。
4>プロジェクト "zzz.csproj" のビルドが終了しました -- 失敗。

対策

どうやら、参照しているプロジェクトが本当は小文字なのに、sln ファイル内では大文字として記述してあったのが原因のようでした。
上記の場合だと、 xxx.csproj のファイル名を、 XXX.csproj (つまり大文字)に修正したら治りました。

Windows は大文字と小文字を区別しないので、適当に変更したことがダメだったようです。

日本語でググってもなかなかエラーを特定できなかったので備忘録として残しておきます。

英語でググったら出てきた解決策が以下です。

VS 2017 RC error: Cannot find project info for... This can indicate a missing project reference · Issue #5144 · dotnet/cli · GitHub

単体テスト<C#> async な moq をセットアップするときにハマったこと

C#単体テストで moq を使用した場合のお話です。
備忘録として残しておきます。

以下のようなインターフェイスがあったとします。

public interface IHoge
{
    Task SomethingAsync(int x);
}

これを moq でセットアップする場合、以下のように書く必要があります。

Mock<IHoge> hogeMock= new Mock<IHoge>();

hogeMock.Setup(m => m.SomethingAsync(It.IsAny<int>())).Callback<int>((value) =>
    {
         // Assert.Equal 等の何かしらの処理をここに記述
    }).Returns(Task.CompletedTask);

重要なのが .Returns(Task.CompletedTask) の部分で、 Task async で実装されるメソッドにはこれをしないとセットアップする必要があります。
でないと、メソッドをコールしても NullReferenceException の例外が投げられてしまいます。
なんとも不親切な例外なので、かなりハマりました・・・

C言語の JSON シリアライザー parson について

parson の紹介

C言語JSONシリアライズすることができないか探していると、 parson なるものを見つけました。

速度はわかりませんが、特徴としては以下のようです。

下記の参考ページに、サンプルなどが載っているので参考になります。

↓文字列を使用することなくパースする、実践的なやり方が公開されています。
かなり参考になります。

kikd.hatenablog.com

↓サンプルを公開されているサイト

mattn.kaoriya.net

↓公式サイトです。
シリアライズとデシリアライズのサンプルがあります。

kgabis.github.io

<おまけ>言語別 JSON parser 一覧

ちなみに、C言語JSONシリアライズ/デシリアライズするのは結構あるみたいです。(こちら参照)

特に気になるのを列挙しておきます。

cJSON

mattn.kaoriya.net

jansson

mattn.kaoriya.net

npm で fatal: unable to connect to github.com: と怒られるとき

npm コマンドを使ってインストールを行うとき、fatal: unable to connect to github.com: と怒られました。
その解決方法です。

条件

ファイアウォールの問題らしいです。
恐らく社内等のネットワーク環境とかが考えられます。

対策

以下を実行します。

git config --global url."https://".insteadOf git://

要は、git://~ というプロトコルがダメらしく、それならば http://~ でアクセスしてやる、というやり方みたいです。

参照

github.com


今回、 gitbook のインストールを試していて、gitbbok-plugin-uml をインストールしようとしたら上記症状が発生しました。

ProtocolBuffers の C# 版の Timestamp について

前に ProtocolBuffers の C# 版の導入をやってみたのですが、

tassi-yuzukko.hatenablog.com

このときに proto ファイル import google/protobuf/timestamp.proto が読込めないせいで以下のようにクラスファイル変換のコンパイルに失敗していました。(このときはこの行自体をコメントアウトしてやり過ごしていましたが・・・)

> protoc -I=./ --csharp_out=./ ./addressbook.proto
google/protobuf/timestamp.proto: File not found.
addressbook.proto: Import "google/protobuf/timestamp.proto" was not found or had errors.
addressbook.proto:49:3: "google.protobuf.Timestamp" is not defined.

今回、ちょっとこの Timestamp という型を使ってみたくなったので、解決策を模索しました。

コンパイル時にパスを指定する

結論から言うと、以下の issue に書かれている通りです。

github.com

以下のように --proto_path オプションを使用してコンパイルします。 (ここでは $(NuGetPackageRoot)C:\Users\<ユーザー名>\.nuget\packages とします)

> protoc -I=./  --proto_path=`$(NuGetPackageRoot)/google.protobuf.tools/3.5.1/tools` --csharp_out=./ ./addressbook.proto

$(NuGetPackageRoot)/google.protobuf.tools/3.5.1/tools 内に、くだんの google/protobuf/timestamp.proto が存在するからです。
要は、 proto ファイルでの import は、コンパイル時に外部の定義先を指定することが必須のようですね。

Timestamp 型とはそもそも何モノ?

proto ファイル上では、以下のように定義されています。

message Timestamp {

  // Represents seconds of UTC time since Unix epoch
  // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
  // 9999-12-31T23:59:59Z inclusive.
  int64 seconds = 1;

  // Non-negative fractions of a second at nanosecond resolution. Negative
  // second values with fractions must still have non-negative nanos values
  // that count forward in time. Must be from 0 to 999,999,999
  // inclusive.
  int32 nanos = 2;
  • seconds フィールド
    • UNIX 時間」とか「 POSIX 時間」とか呼ばれている、1970年1月1日0時0分0秒(UTC)からの経過秒数
    • C言語でいう time() 関数の戻り値である time_t 型のそれ(参考)
  • nonos フィールド
    • XXXミリ秒YYYマイクロ秒ZZZナノ秒を、 XXX,YYY,ZZZ の9桁の整数として表すもの

つまり、なんてことない、結構プリミティブ型に近いような拡張型ですね。

C# での使い方( DateTime 型との互換)

C# での時間は DateTime 型が良く使われると思います。
この互換については、Timestamp クラスに静的メソッドとして以下が用意されているので、双方簡単に変換ができます。

  • Timestamp型を返す FromDateTime(DateTime dateTime)
  • DateTime型を返す ToDateTime()

詳細は、以下を参照してください。
Google.Protobuf.WellKnownTypes.Timestamp Class Reference  |  Protocol Buffers  |  Google Developers

ハマったこと・・・

ProtocolBuffers はバイナリにシリアライズする規格です。しかし、誤って文字列にシリアライズしてしまっていました。
たまたまかもしれませんが、プリミティブ型を文字列にシリアライズしても、正常にデシリアライズできていました。そこで Timestamp 型を文字列にシリアライズすると例外も出ずに失敗してしまい、「なぜ Timestamp 型を使用するとシリアライズできなくなるのか・・・」とハマってしまったので備忘録として残しておきます・・・。

Pandoc で PlantUML を出力

pandoc は、当然ですがデフォルトでは plantuml に対応していません。
しかし、 markdown でドキュメントを書く際は、 plantuml をよく使用するので、 plantuml の画像を出力できるようにします。

前提

お約束の前提ですが、以下の環境とします。

また、あらかじめ以下もインストール済みとします。

  • graphviz (plantuml を扱うのに必要)
  • python3 (pandoc のフィルターに使用)
    • 結果的に python は使用しませんでした
  • node.js (npm を使用するのに必要)

plantuml とは

plantuml がどんなもので、plantuml そのものをどうやってインストールするかは省略します。
詳しくは↓サイトに紹介されています。

qiita.com

pandoc の plantuml 用フィルターを利用

Windows 環境下で pandoc の plantuml フィルターの用意が非常に大変でした。ネットの日本語情報も少なく、その情報も自分の環境ではうまくいかないものばかりだったので、備忘録として経緯も載せます。

pandoc バージョンの注意

私の環境では最初、 pandoc のバージョンが 1.7 でした。そのバージョンではどうやら -F XXX.py という感じで python ファイルのフィルターが使用できないみたいでした。
バージョンを 2.1.2 にすると解決しました。

(すみません、参考サイトは失念しました。どこかの github の issue だった気がします)

plantuml-filter.py を使用する方法 その1(結果失敗です)

これは結果的に失敗したので、読み飛ばしてもらってOKです。

以下にある情報をもとにやってみました。

mickey-happygolucky.hatenablog.com

https://raw.githubusercontent.com/matthiasbeyer/pandoc-paper-template/master/scripts/plantuml-filter.pyにあるものをフィルターとして使用する方法です。

これはどうやら Windows 環境ではうまくいかないようで、実行すると以下のようなエラーが出ました。

> pandoc test.md -o test.html --self-contained -t html5 -F .\plantuml-filter.py
        [PLTUML] plantuml-images/8428a0c71ace69322a85c178b192bb8cdaa0bd20.png
Traceback (most recent call last):
  File ".\plantuml-filter.py", line 64, in <module>
    toJSONFilter(graphviz)
(中略)
  File "C:\Users\XXX\AppData\Local\Programs\Python\Python35-32\lib\subprocess.py", line 873, in __init__
    "close_fds is not supported on Windows platforms"
ValueError: close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr
Error running filter .\plantuml-filter.py:
Filter returned error status 1

どうやら pythonスクリプトの中身が Windows に対応していないみたいです。(close_fdsWindows では使えないっぽい?) python 自体わかっていない人間なので、いったんここで断念します。

python をちゃんと理解していたらチョコっと手を加えたら解決する可能性があります。

plantuml-filter.py を使用する方法 その2(結果失敗です)

これも結果的に失敗したので、読み飛ばしてもらってOKです。

以下にある情報をもとにやってみました。

takec.hatenablog.jp

これは inkscape とかの連動をしているので、そのまま流用することはできないのですが、ここでは「その1」であった python スクリプトWindows 用に書き換えて使用する例が載っていました。
が、しかし実行すると以下のエラーが出てうまくいきませんでした。(念のため inkscape に関連する箇所はコメントアウトしたんですが、駄目でした)

> pandoc test.md -o test.html --self-contained -t html5  -F .\plantuml-filter.py
Traceback (most recent call last):
  File ".\plantuml-filter.py", line 64, in <module>
    toJSONFilter(graphviz)
(中略)
  File ".\plantuml-filter.py", line 47, in graphviz
    data, err = pipe(["java", "-jar", "C:\plantuml.jar", "-pipe", "-Tsvg", "-charset", "UTF-8"], code)
  File ".\plantuml-filter.py", line 22, in pipe
    p = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  File "C:\Users\XXX\AppData\Local\Programs\Python\Python35-32\lib\subprocess.py", line 950, in __init__
    restore_signals, start_new_session)
  File "C:\Users\XXX\AppData\Local\Programs\Python\Python35-32\lib\subprocess.py", line 1220, in _execute_child
    startupinfo)
FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。
Error running filter .\plantuml-filter.py:
Filter returned error status 1

このエラーはよくわかりませんでした。一応 plantuml,jar のファイルのパス等を確認したのですが、ファイルが見つかりませんと言われます。
まあよくわかりもせずに、他の人のスクリプトを使うなということです・・・。

pandoc-plantuml-filter.cmd を使用する方法(成功しました)

以下の github 上に公開されているリポジトリを参照させてもらいました。

github.com

pandoc-plantuml-filterの取得

Readme.md には npm -g でグローバルにインストールするように書かれていますが、私の環境ではグローバルインストールではうまくいきませんでした。以下のように、markdown → html 変換するディレクトリにに配置します。

> npm install pandoc-plantuml-filter

実行

Readme に書いてある通り、以下の通り実行します。

> pandoc test.md -o test.html --self-contained -t html5 -F pandoc-plantuml-filter.cmd
[WARNING] This document format requires a nonempty <title> element.
  Please specify either 'title' or 'pagetitle' in the metadata.
  Falling back to 'test'

なんか警告が出ていますが・・・ --metadata pagetitle=<ページタイトル> を付加すると消えます。どうやら、ブラウザ上に表示されるタイトルの設定のようですが、はっきり言って勝手に html の名称を割り当ててくれたらいいのに・・・と思いますので、別途バッチファイルとか作ったほうが便利かもしれません。
(ちなみに、これは pandoc 側の仕様らしい?です。 issueでも同じ不満を言っている人がいますw)

追記

以下のバッチファイルを作ってみました。

# pandoc_markdown2html.bat

@echo off

rem param1: markdownファイル名
rem param2: cssファイル名

if "%1"=="" (
  echo ERROR : Needs Filename.
  exit /b 1
)

if not "%2"=="" (
  rem 第2引数はcssだけ許可
  if not "%~x2"==".css" (
    echo ERROR : Arg2 is neet to css filename.
    exit /b 1
  )
  set CSS=-c %2
)

rem ファイル名から拡張子を取り除く
for /f %%i in ('echo %1') do set FILE=%%~ni

pandoc %1 -o %FILE%.html --self-contained -t html5 %CSS% -F pandoc-plantuml-filter.cmd --metadata pagetitle="%FILE%"

使用例:

> pandoc_markdown2html.bat test.md test.css

plantuml を svg 形式で出力

pandoc-plantuml-filter のデフォルトのままでは、出力形式は png 固定です。
ちょこっといじって svg で出力するようにしました。

node_modules\pandoc-plantuml-filter\plantuml-filter.js の以下の部分を書き換えます。

- var res = execSync(util.format("java -splash:no -jar \"%s\" -charset UTF-8 -pipe", plantumlPath), { input: umlText });
+ var res = execSync(util.format("java -splash:no -jar \"%s\" -charset UTF-8 -pipe -Tsvg", plantumlPath), { input: umlText });
- var fileName = util.format("%d.png", imgCounter++);
+ var fileName = util.format("%d.svg", imgCounter++);

とりあえず、これで晴れて目的を達成できました。最終的には gitlab にプッシュしたら、 gitlab runner が走って markdown を html に自動変換するっていうのを実現したいです。