読者です 読者をやめる 読者になる 読者になる

VSCode に Integrated terminal という機能が追加されていた

VSCode 1.2.0 で Integrated terminal という機能が追加されていた。

大雑把にいうと、エディタのウィンドウの一部にターミナルを追加させる機能。

mix コマンドをコマンドパレットから実行できるように拡張機能を書こうとしてたんだけれど、Integrated terminal でいいじゃんって感じ。フォーカスを移動させるショートカットがまだわからないけど、拡張機能を書く意欲は下降気味。というか消失。

Visual Studio Code をコマンドラインから起動させる

問題

コマンドラインから Visual Studio Code を起動したいが、どう設定すればいいか不明。

環境

解決

コマンドパレットから shell Command: Install 'code' command in PATH を実行する。アンインストールも同じ感じ。

参考

Running Visual Studio Code on OS X

Ueberauth: (FunctionClauseError) no function clause matching in Keyword.merge/2

問題

phoenixueberauth_identity を組み込もうとしたところ、コンパイル時に (FunctionClauseError) no function clause matching in Keyword.merge/2 というエラーが発生する。

環境

  • Elixir 1.2.6
  • Phoenix 1.1.4
  • ueberauth_identity 0.2.3

解決

config.exs に設定を追加する。

config :ueberauth, Ueberauth,
  providers: [
    identity: {Ueberauth.Strategy.Identity, [
      callback_methods: ["POST"]
    ]}
  ]

感想

エラーメッセージ・スタックトレースからでは原因の予想が全然つかなかった。 ドキュメントには、設定ファイルに追加しろって書いてある。。。

(PHPUnit 5 未満では)データプロバイダでモックオブジェクトを作成しないほうがいい

前提

PHPUnit 5 未満を使用している(問題の確認をしたのは PHPUnit 4.8.21)。

問題

指定したメソッドが一回だけコールされることを確かめるテストで、指定したメソッドが一回も呼ばれていないのにテストが成功してしまう。

モックオブジェクトはデータプロバイダで生成している。

具体的には

以下のコード(some.php)がある。このテストを実行すると失敗するはず。。。

なのだが、PHPUnit を実行すると成功してしまう。

$ ./phpunit-4.8.21.phar some.php
PHPUnit 4.8.21 by Sebastian Bergmann and contributors.

.

Time: 141 ms, Memory: 12.00Mb

OK (1 test, 0 assertions)

解決

  • モックオブジェクトをデータプロバイダではなくテストメソッド内で生成するようにする。

or

  • テストケース内で $mock->__phpunit_verify() を呼ぶ。

前者のほうがお行儀がよさそう。

参考

この修正でデータプロバイダで生成したモックオブジェクトでもテストが期待通り実行されるようになった(issue はデータプロバイダではなく、依存関係の上流のテストケースで生成したモックオブジェクトだけれども)。

PHPUnit 5.1.3 では期待通りの結果。

./phpunit-5.1.3.phar some.php
PHPUnit 5.1.3 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 111 ms, Memory: 10.25Mb

There was 1 failure:

1) SomeTest::testStubWithProvider with data set #0 (Mock_SomeClass_0cfc834a Object (...))
Expectation failed for method name is equal to <string:doSomething> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

はてなブログでElixirのコードにシンタックスハイライトを適用する方法

2015/11/18 時点で、ここを見る限りElixir のシンタックスハイライトは未対応。

でも、大丈夫 Elixir と Ruby は見た目が似ていると言われている。ruby を指定しておけばそれっぽくハイライトされる。

defmodule, defmacro などなど Elixir にしかないキーワードも多いけれど、ないよりかはマシな気がする。

HTTPリクエストからChannelへメッセージを送る

GETやPOSTなどのHTTPリクエストを受け取り、その処理の中でChannelにデータを送信したい場合、以下のように書くことでメッセージを送信できる。

HelloPhoenix.Endpoint.broadcast_from! self(), "rooms:lobby", "new_msg", %{uid: uid, body: body}

http://hexdocs.pm/phoenix/Phoenix.Channel.html の "Broadcasting to an external topic" の箇所に書いてあったのを ここ に合わせて少し変更した。そこの例では channel 側のコードとして書かれているけど、controller 側のコードの中でも使えた(まあ、*.Endpoint モジュールの関数なので当たり前?)。

ちなみに、これで何をしたかったのかというと、fluentd でログを転送して、それをブラウザでリアルタイムで見れるようにしたかった。

こんな感じ。

       +---------+     +---------+
Log -> | fluentd |     | Browser |
       +---------+     +---------+
           |                A
           |                | 
           +-- HTTP(POST)   +-- Websocket
           |                |
           V                |
       +-----------------------+
       |         Phoenix       |
       +-----------------------+

コマンドラインの引数を得る方法

Elixirでコマンドラインツールを書く方法が(自分の観測範囲内では)二通りある。

一つはスクリプトとして実行する方法。もう一つは、escript を使う方法(こっちの方法も名前からするとスクリプトとして実行されてるっぽいけど)。

スクリプトとして実行した場合、System.argv/0 を使えばいつでもコマンドに渡された引数を得ることができるけれど、escript を使った場合は System.argv は nil を返してくる。

ということのメモ。

スクリプトとして実行した場合

ソース

defmodule RunScript do
    def go(argv) do
        IO.inspect argv
        IO.inspect System.argv
    end
end

RunScript.go(System.argv)

実行

$ elixir run_script.exs one two three
["one", "two", "three"]
["one", "two", "three"]

escriptを使った場合

ソース

defmodule RunEscript do
    def main(argv) do
        IO.inspect argv
        IO.inspect System.argv
    end
end

実行

$ ./run_escript one two three
["one", "two", "three"]
nil

参考

escript を使った書き方は以下のページを参考にした。