あざらし備忘録。

音ゲー好きなウェッブエンジニアがいろいろ思った事やった事を書いていくブログです

npm installでローカルインストールしたライブラリのコマンドを使えるようにする[npm][JavaScript]

npmでライブラリをインストールするときに、-gをつけずにインストールをするとnode_modules下にインストールしたライブラリが入ります。

そのときにライブラリ側が提供しているコマンドを実行しようとした時、例えばwebpackだと

./node_modules/webpack/bin/webpack.js

みたいなところを実行しなくてはいけないのかな〜辛いな〜と思っていたらそんなことなく解消出来たのでメモ。

話は簡単で、実は./node_modules/.bin/というディレクトリ下に実行可能なコマンドは入っているので、そこにパスでも通してあげればグローバルに入れた時と変わらずコマンド実行できるようになりました。

export PATH=$PATH:./node_modules/.bin

とでもすれば解決できました。めでたしめでたし。

Vue.jsに入門してみた[JavaScript][Vue.js]

ちょっときっかけがあってVue.jsを初めてお勉強してみたので勉強メモ。 JS界隈、全体的に疎さがあるので、関連用語の説明も加えつつ書いてみます。

Vue.jsとは

Vue.js はインタラクティブな Web インターフェイスを作るためのライブラリ。 MVVMパターンのViewModelレイヤに注目していて、ViewとModelを双方向バインディングによって接続しています。

特徴

Vue.jsはざっと以下のような特徴があります。

公式ドキュメントも全て日本語化されていて、ありがたやといったところでした。 公式ドキュメントの物量としてもざっと読むだけなら全然1日かからないくらいだったので本当学習コストは低めだなぁと感じました。

MVVMパターンとは

MVVMパターンとは、Model/View/ViewModelの3つの責務にGUIアプリケーションを分割するパターンのことです。

その中でVue.jsはViewModelレイヤを担っていますよっていうところですね。

f:id:shiro_goma:20150801174627p:plain

Vue.js公式からもってきている画像ですが、すごい関係がスッキリまとまっていて良いです。

双方向バインディングとは

双方向データバインディングとは、データの変更があったらUIの表示を更新し、UIの変更があったらデータの更新する、といった処理を自動的に行う機能を指します。

これができているとViewで表示される内容とModel内で処理されている内容が同期がとれて良いですね。

Vue.jsはこの双方向データバインディングをシンプルに行うことに重点を置いています。

インストール

インストール方法は公式ドキュメントにお任せしますmm

jp.vuejs.org

Vue.jsの提供する機能

Vue.jsとしてのまず押さえる必要のある機能は大まかには以下に並べるくらいです。

以下のサンプルに沿って必要知識をまとめようかと思います。

インスタンスプロパティ

基本中の基本としてはeldataが挙げられます。

el

Vueインスタンスが管理する対象のDOM要素です。 View部分の担当です。

data

Vue インスタンスが監視しているデータオブジェクトです。 Model部分の担当です。

f:id:shiro_goma:20150801201046p:plain

ざっくりとした図ですが、赤枠がel関連、青枠がdata関連です。

elで監視対象を指定して、その監視範囲に対してdataを用いてほげほげする感じですね。 このようにhtmlはあくまでフレームとして用いて、実データの方はjsの方に持たせるといった分担が綺麗にできるようになりスッキリしますね。

他にも何種類かインスタンスプロパティは用意されているのでご参考くださいmm

インスタンスプロパティ - vue.js

ディレクティブ

ディレクティブとは、DOM 要素に対して何かを実行することをライブラリに伝達する、マークアップ中の特別なトークンです。

Vue.jsを触るようになるとよくよく目にするようになります。

f:id:shiro_goma:20150801202403p:plain

赤枠がディレクティブ、青枠がそのディレクティブが対象とするdata等が入ってきます。

青枠のところは用いるディレクティブによって色々変わってきます。

例えば、 v-onディレクティブはclick:から始まりますが、これはv-onディレクトリ固有のものになっていたりします。

APIリファレンスをよく読んで正しく使うようにしましょう。

ディレクティブは、大きく以下の4種類に分類されます。

  • リアクティブディレクティブ
  • リテラルディレクティブ
  • エンプティディレクティブ
  • カスタムディレクティブ

リアクティブディレクティブ

リアクティブディレクティブは、それ自身を Vue インスタンスのプロパティやインスタンスの文脈の中で評価される表現にバインドすることができます。 配下のプロパティや表現の値が変更されたら、それらのディレクティブの update() 関数が同期的に呼ばれます。

リテラルディレクティブ

リテラルディレクティブは、データバインディングを生成せず、単に文字列リテラルを属性値として取ります。 その要素の値を素の文字列として取り扱い、何ともバインドしようとしません。 このディレクティブが行うのは、文字列の値を bind() 関数に渡して実行することだけです。 リテラルディレクティブはその値の中で Mustache 表現を使用できますが、それらの表現は最初のコンパイルの際に一度だけ評価され、データの変更に対して反応しません。

エンプティディレクティブ

エンプティディレクティブは、属性値すら期待せず、単純にその要素に何かを一度きり行います。

このように色々なディレクティブがあるので、詳細は以下のAPIリファレンスをご参照の事。 恐らくこのリファレンスに頻繁にお世話になりながらコードを書いていく感じになるのかなと思います。

jp.vuejs.org

カスタムディレクティブ

カスタムディレクティブは、データの変更に伴い DOM がどのように変更されるかを定義することができる仕組みです。 有り物だけではちょっとつらいみたいな状態になった時に拡張出来る仕組みです。

jp.vuejs.org

Mustacheスタイルのバインディング

{{ }} これですw

mustache は口ひげの意で、{が口ひげっぽいかららしいですね。

mustache.jsというテンプレートエンジンと同様の構文ですね。

ざっくりいうと変数展開ができます。

f:id:shiro_goma:20150801204413p:plain

フィルタ

フィルタは、本質的には「値を取り、加工し、加工した値を返す」関数です。マークアップ内ではパイプ(|)で表され 、一つ以上の引数を続けることができます。

View を更新する前の生の値を処理するために使われる関数です。

変数に対してある処理を行ってから反映をさせることができるようになります。

f:id:shiro_goma:20150801204734p:plain

デフォルトでは以下のフィルタが用意されています。

  • capitalize
    • 先頭文字を大文字にする
  • uppercase
    • 全部大文字にする
  • lowercase
    • 全部小文字にする
  • currency
    • 引数に好きな通貨単位を取る(ex. $)
  • pluralize
    • 引数に取った値を複数表記にする(ex. item => items)
  • json
    • 引数にインデント幅を取ってjson表記にする
  • key
    • v-onディレクティブとセットで使える
    • 「エンターキーが押されたとき」みたいなのを表現できる
  • filterBy
    • v-repeatディレクティブとセットで使える
    • 引数にフィルタリング条件を取って元配列の内容をフィルタリング出来る
  • orderBy
    • v-repeatディレクティブとセットで使える
    • 引数にソート条件を取って元配列の内容をソート出来る

カスタムフィルタ

コレ以外にもフィルタ欲しい...ってなった時にはカスタムフィルタを定義することも可能です。

Vue.filter('reverse', function (value) {
  return value.split('').reverse().join('')
})

のような感じで定義可能です。

その他

他にも色々用意されてます!

本当に最小限といった形で入門記事を書いてみましたが、今回出した例の範疇を越えて行くと色々な機能も他にもあります。

あたりは今回は触れなかったので追々触れられたらいいな〜と思ってます。

でもこの辺りまでしっかり見ていったとしても、大して学習は時間はかからなさそうだなぁという感想なので、本当に軽めな良いフレームワークだなぁというのが所感です。

良い感じの例も公式で準備してくれてます:)

jp.vuejs.org

ここに置いてあるソースとかを眺めてみても勉強になるかなと思います!

基本は公式をみてれば良さそう

公式ドキュメントがしっかりしているので、公式ドキュメントと仲良くなればおおかた作っていけるかなぁという感触があります。

jp.vuejs.org

自分もしっかり読んで使っていこうと思います!

第一印象としてはすごく使い始めやすそうだなぁという感じだったので、引き続きちょっと触って行きたいと思います!

DoctrineCacheBundleでMemcachedを使おうとした時にハマった話[Symfony2][DoctrineCacheBundle][Memcached]

Symfony2プロダクトでMemcachedを使おうとした時には、DoctrineCacheBundleが使えます。

github.com

基本的にはカジュアルにコンテナから取り出せて便利〜って感じだったのですが、ElastiCacheを使おう〜って思った時にガンハマりしたので備忘録として。

どうハマったか

端的にいうと、「yaml記法で書かれた設定ファイルのホスト名がよしなに書き換えられてしまう」せいで、ElastiCacheにつながらない、という問題に直面して、苦労したお話です。

原因がわからず詰まっていた

どう書き換えられたか

github.com

このREADMEの

# app/config/doctrine_cache.yml

doctrine_cache:
    providers:
        my_memcached_cache:
            memcached:
                servers:
                    memcached01.ss: 11211
                    memcached02.ss:
                        port: 11211

を参考にして、設定ファイルを以下の様に書いていました。

# app/config/doctrine_cache.yml

doctrine_cache:
    providers:
        my_memcached_cache:
            memcached:
                servers:
                    hoge-fuga-01.abcdef.0001.apne1.cache.amazonaws.com: 11211
                    hoge-fuga-02.abcdef.0001.apne1.cache.amazonaws.com: 11211

的な感じで。

これがなんと、コンテナから取り出した時にはホスト名がそれぞれ

hoge_fuga_01.abcdef.0001.apne1.cache.amazonaws.com
hoge_fuga_02.abcdef.0001.apne1.cache.amazonaws.com

に自動的に書き換えられた状態でセットされてしまう、というものでした。 yamlの仕様かYmlParserの仕様かDoctrineCacheBundleの仕様かContainer周りの仕様か追いきれてないですが、とりあえずこうなってしまうようですorz

どう解決したか

READMEのxmlの例を見て推測しつつ、次のようにやってみたら出来ましたw

# app/config/doctrine_cache.yml

doctrine_cache:
    providers:
        my_memcached_cache:
            memcached:
                servers:
                    server1:
                        host: hoge-fuga-01.abcdef.0001.apne1.cache.amazonaws.com
                        port: 11211
                    server2:
                        host: hoge-fuga-02.abcdef.0001.apne1.cache.amazonaws.com
                        port: 11211

この様にするとホスト名を文字列的に明示してかけるのでよしなに書き換えられる事なく無事つなげることができました。

原因がわかってみれば大したことはなかったのですが、なかなか問題の切り分けがしづらく苦戦しました...

ということで、DoctrineCacheBundleを使ってMemcachedを扱うときは、「ホスト名やポート名は明示するようにしましょう」という備忘録でした。

2.7から始めるSymfony2[PHP][Symfony]

Symfony2のLTSである、Symfony2.7がちょっと前にリリースされました。

LTSということで、Symfony2.7は3年間はサポートするよ!っていうなかなか安定感のあるバージョンになっています。

The Release Process (Contributing to Symfony)

サポート期間が長いのでギョーミーな部分にもSymfony2を導入するハードルも下がるしSymfony2を新規で導入することも増えるんじゃないかなぁと思います。

ということで今回は「これからSymfony2を始めるには」といったところの記事を書こうかなと思います!

「今まで使ったことないけど、試してみようかな?」的なところの助けになれば幸いです。

今回はSymfony2の導入から簡単な構造の説明までをできたらと思います。

インストーラーの導入

Symfony2は、2015/03/26から、新しいインストーラーが導入されて、以前よりも簡単に便利にSymfony2をインストールできるようになりました。

なのでこれからはこのインストーラーを使ってサクサクSymfony2プロダクトを始めるのが良いでしょう!

まず以下の様にしてインストーラーを入れます。

LinuxMac OS Xだったら

sudo curl -LsS http://symfony.com/installer -o /usr/local/bin/symfony
sudo chmod a+x /usr/local/bin/symfony

Windowsだったら

c:\> php -r "readfile('http://symfony.com/installer');" > symfony

このようにするだけです:)

なお、ちょっとWindowsが手元にないのでここからはLinux/Mac OS Xベースで書いていきますmm

プロジェクトの作成

インストーラーがサクッとインストールできたので、次は早速プロジェクトを作成しましょう。

symfony new <プロジェクト名> 2.7

この様にコマンドを実行すると、よしなにSymfony2.7で動くプロジェクトを作成してくれます:) なお、2.7 の部分はお察しの通りSymfony2のバージョンを表していて、任意のバージョンのSymfony2をインストール可能です。2.6でも、2.5でも、好きなように入れることができます。

また、上記の例ではSymfony2.7の中でも最新バージョンを入れてくれますが、2.7.1 のように詳細までバージョン指定することでその指定したバージョンを入れることもできます。

逆にバージョン指定をしないでコマンド実行をするとその時の最新バージョンで動くプロジェクトが作成できます。

さて、コマンドを実行すると以下のように表示されるかと思います。

 Downloading Symfony...

    4.95 MB/4.95 MB ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓  100%

 Preparing project...

 ✔  Symfony 2.7.1 was successfully installed. Now you can:

    * Change your current directory to /Users/g-nakanishi/hogehoge_symfony

    * Configure your application in app/config/parameters.yml file.

    * Run your application:
        1. Execute the php app/console server:run command.
        2. Browse to the http://localhost:8000 URL.

    * Read the documentation at http://symfony.com/doc

これでプロジェクト作成は完了です。いやはや簡単。

また、Symfony2にはその環境でちゃんとSymfony2が動作するかどうかのチェックスクリプトが同梱されていて、そのスクリプトを実行すれば簡単に動作をするかも確認できます。

php <プロジェクト名>/app/check.php

こちらを実行するとphp.iniを見つつ動作チェックを行ってくれます。

プロジェクトの動作確認

もう実はバッチリSymfony2は動くようになってくれています!

確認してみましょう。

プロジェクトに入って、サーバーを起動してみます。

cd <プロジェクト名>
php app/console server:run

Server running on http://127.0.0.1:8000                                                         
Quit the server with CONTROL-C.         

サーバー起動まで行えたら、ブラウザでhttp://127.0.0.1:8000/app/exampleにアクセスしてみます。

これでHomepage.のように画面上に表示されていればSymfony2はしっかり仕事をしてくれています。

プロジェクトの構造

Symfony2プロジェクトは、以下の様な構成になっています。

├─ app/
│  ├─ console
│  ├─ cache/
│  ├─ config/
│  ├─ logs/
│  └─ Resources/
├─ bin/
├─ src/
│  └─ AppBundle/
├─ vendor/
└─ web/

app

アプリケーション固有の設定や、アプリケーションの核になるファイル、キャッシュやログの格納されるディレクトリなどが詰まったディレクトリです。

console

Symfony2が提供しているコマンド群を実行するためのスクリプトです。

先ほど実行したphp app/console server:runのようにして使用します。

また、自作したコマンドをこのconsole経由で実行可能にすることもできます。

cache

キャッシュディレクトリです。Symfony2は色々な部分でキャッシュを行って高速化を行っていますが、そのキャッシュ群はこのディレクトリに格納されます。

config

アプリケーション固有の設定は、このconfigディレクトリ下に格納されます。 データベースの設定であったり、ロガーの設定であったり、ルーティングの設定であったり、各種様々な設定は軒並みこちらのディレクトリに集まります。

logs

ログが集まるディレクトリです。(特になんも言えなかった)

Resources

主にアプリケーション全体に共通となるhtml等を置くディレクトリです。

bin

実行可能な便利コマンド群を置くディレクトリです。 シンボリックリンクを置いておいたりもできます。

src

ソースコードが置かれる部分です。

Symfony2は全てがBundleという単位で管理されているため、そのBundle群がこのsrc下に集まっています。

Bundleというのはプラグインに近いような概念で、自分たちで書いていくアプリケーションコードに関してもBundleという形で作成していきます。

web

俗に言うpublicなディレクトリで、ここにはブラウザ等からアクセス可能なものが配置されます。

vendor

外部ベンダーの作成したライブラリ等が格納されます。

git等のバージョン管理時にはignoreしておいたら良いかと思います。

終わりに

今回はとりあえず「これくらいカジュアルに始められるよ!」というのを伝えたくて本当に導入部だけ書いてみました。

Symfony2、PHPでアプリを書くなら一択くらいには気に入っているので、ぜひ使う人口が増えるとうれしいです。

次やる気がでれば導入後の入門記事とかも書きたいな〜

AASMライクなPHP用StateMachine 1.1.0 released!![PHP][Doctrine]

以前このブログでも紹介した、

shiro-goma.hatenablog.com

PHP用のステートマシンライブラリのv1.1.0を公開しました!

Rubyの有名なステートマシンgemであるaasm/aasm · GitHubぽいカジュアルに使えるステートマシンが欲しくて開発しています。

v1.0.0ではステートマシンとしての最小限の機能である状態遷移を管理する機能のみを提供していましたが、v1.1.0では以下のような機能を追加しました。

  • 間違った遷移をしようとした時に例外を投げるのではなくfalseを返すようにするオプションの実装(WhinyTransitions)
  • 直接代入による状態遷移を向こうにするオプションの実装(NoDirectAssignment)
  • コールバックメソッドの有効化(Callbacks)
    • イベント開始前(beforeEvent)
    • 旧状態退出前(beforeExit)
    • 旧状態退出時(exit)
    • 新状態入場前(beforeEnter)
    • 新状態入場時(enter)
    • 遷移後(afterTransition)
    • 旧状態退出後(afterExit)
    • 新状態入場後(afterEnter)
    • イベント終了後(afterEvent)
  • 引数を伴うコールバックメソッドへの対応
  • 状態名取得メソッドの実装

これで色々なフックポイントでコールバックメソッドを実行できるようになったので、痒いところに手が届きやすくなったかなーと思っています!

また、状態名を取得するメソッドも用意出来たので、これで定数などで状態名を保持するような二重管理っぽい状況も打破できそうです:)

リポジトリは以下です。

github.com

設定ファイル不要でアノテーションだけで状態管理できるようになるのでお手軽ですよー! また、Symfony2でお馴染みのDoctrineが提供しているアノテーション機能を用いて作成していますが、Symfony2で無くてもプレーンなPHPに対して使用可能になっているのでぜひどうぞ。

せっかく作ったライブラリなので普通に使えるようにしっかり育て続けていきたいと思います!

Macの環境構築を通じて0からAnsibleに触れる[Ansible][Mac]

こんにちは。

今回は、以前@t-wadaさんが書かれていた

t-wada.hatenablog.jp

を読んで「めっちゃ良いじゃないですか」と思ったので実際に自環境もやってみました。

上記エントリをはじめ、リンクとして書かれていた@hnakamurさんやmawatariさんのブログも参考にさせて頂きましたmm

ありがとうございますmm

AnsibleでHomebrew, Cask, Atomエディターのパッケージを管理する - Qiita

HomebrewとAnsibleでMacの開発環境構築を自動化する | mawatari.jp

Ansibleも触ったことがないのでちょうどいいやということで。 また、今までHomebrew Caskも使ってみた事がなかったのでちょうどいいやということで。

なのでそのあたりの説明等も自分なりに書きつつまとめたいと思います。

基本は@t-wadaさんのブログを見ながら進めてみるということで、以下作業メモ程度に残しておきます。

Ansibleの構成

Ansibleは構成管理ツールであるということはわかっているのですがなんせ初心者なので、まずはAnsibleの構成から。

Ansibleは以下の3つによって主に構成されています。

  • インベントリ(hosts)
    • 作業対象のホストを記述します。
    • 今回はローカル環境で動かすだけなのでlocalhostとなります。
  • モジュール
    • 実際の具体的な実行内容を記述します。
    • 例えばファイルをコピーしたり、コマンドを実行したり、と言った部分です。
  • playbook
    • 前述のモジュール群を用いた処理を記述します。
    • このplaybookがプロビジョニングの内容となっていきます。

モジュールは標準で用意されてるものや、その他公開されているもので足りればそれらを用いれば良く、なければ自作すれば良い、といった感じですね。

サーバーで実行可能なのであればモジュールの言語自体は問わないようです。(てっきりPythonで書かなきゃいけないもんだと思っていた)

また、playbookを用意しなくてもansibleコマンドで実行も可能なようですが、今回はおそらく入れる物量も多くなりますしplaybookをサッと書こうと思います。

playbookを用いたプロビジョニングの実行は以下のコマンドになります。

ansible-playbook <playbook.yml>

これでざっくり概要のまとめは完了したので、プロビジョニングの準備を行っていきます。

プロビジョニング準備

t-wadaさんのブログに習って進めて行きます。

ディレクトリ作成

作業用のディレクトリを掘る。

mkdir .macbook-provisioning
cd .macbook-provisioning

ansibleのために必要な物を用意

先に述べた

  • インベントリ(hosts)
  • モジュール
  • playbook

を準備していく。

インベントリ(hosts)の用意

今回はローカルの環境構築のみなのでlocalhostとだけ。

echo 'localhost' > hosts

モジュールの用意

いい感じのがあったら使う、なければ作る、といったところですが、今回は

があるので、こちらを使いました。

playbookの用意

@t-wadaさんの記事を存分に参考にさせていただきつつ、記述していたものの意味をまとめてみました。

他にも色々と設定もできるようですが、まずは第一歩ということで...

# hosts
#
# hostsファイルに記述したホスト情報の中からプロビジョニング対象とするホストを選択する
# hosts: プロビジョニング対象ホスト名
# hosts: host1,host2,host3
# hosts:
#   - host1
#   - host2
#   - host3
- hosts: localhost
  # connection
  #
  # connection: local とすることでlocalhostの場合必要のないSSHをしないようにできる
  # [http://docs.ansible.com/playbooks_delegation.html#local-playbooks]
  connection: local
  # gather_facts
  #
  # 対象サーバーから情報を収集するかどうか
  # noとすれば取得しない。デフォルトはyes
  # 集めた情報は配列形式となっていて、playbook内で使用可能
  gather_facts: no
  # sudo
  #
  # sudoで実行するかどうか
  # noならばしないし、yesならばrootで実行する
  # ユーザ名を指定するとそのユーザで実行する
  sudo: no
  # vars
  #
  # タスク実行の際に必要な変数を定義しておける
  vars:
   # homebrew_taps
   # 
   # brew tapする必要がある場合はこの項目に記述しておく
    homebrew_taps:
      - hoge/hogehoge
    # homebrew_packages
    #
    # brew installでインストールするものをこの項目に記述しておく
    # [http://docs.ansible.com/homebrew_module.html]
    # [http://kiririmode.hatenablog.jp/entry/20150101/1420074034]
    homebrew_packages:
      - foo
      - { name: fuga, state: linked, install_options: force }
    # homebrew_cask_packages
    #
    # brew cask installでインストールするものをこの項目に記述しておく
    # [http://docs.ansible.com/homebrew_cask_module.html]
    homebrew_cask_packages:
      - bar
      - { name: piyo }
  # tasks
  #
  # ここに書いたタスクが上から順番に実行される
  # もし途中から実行したい場合は
  # ansible-playbook localhost.yml --start-at-task="タスク名"
  # ステップ実行したい場合は
  # ansible-playbook localhost.yml --step
  tasks:
   # name:
   # 
   # タスク名を記述
    - name: homebrew の tap リポジトリを追加
      # モジュール名: モジュールのオプション
      # 
      # このタスクでどのモジュールを実行するかとどんなオプションで実行するかを指定
      # with_itemsでforeachっぽく処理して順番にtapしている
      # [http://docs.ansible.com/homebrew_tap_module.html]
      homebrew_tap: tap={{ item }} state=present
      with_items: homebrew_taps
    - name: homebrew をアップデート
      homebrew: update_homebrew=yes

    # brew
    - name: brew パッケージをインストール
      homebrew: >
        name={{ item.name }}
        state={{ item.state | default('latest') }}
        install_options={{
          item.install_options | default() | join(',')
          if item.install_options is not string
          else item.install_options
        }}
      with_items: homebrew_packages
      register: brew_result
    - name: brew パッケージの情報保存先ディレクトリを作成
      file: path=brew_info state=directory
    - name: brew パッケージの情報を保存
      shell: brew info {{ item }} > brew_info/{{ item }}
      with_items: brew_result.results | selectattr('changed') | map(attribute='item') | map(attribute='name') | list

    # cask
    - name: homebrew-cask のインストール
      homebrew: name=brew-cask state=latest
    - name: cask パッケージをインストール
      homebrew_cask: name={{ item.name }} state={{ item.state|default('installed') }}
      with_items: homebrew_cask_packages
      register: cask_result
    - name: cask パッケージの情報保存先ディレクトリを作成
      file: path=cask_info state=directory
    - name: cask パッケージの情報を保存
      shell: brew cask info {{ item }} > cask_info/{{ item }}
      with_items: cask_result.results | selectattr('changed') | map(attribute='item') | map(attribute='name') | list
  # handlers
  #
  # playbookの終了時に実行される
  # 基本はタスクの記述と変わらない
  # サービスの再起動等に用いる事が多い
  # [https://docs.ansible.com/playbooks_intro.html#handlers-running-operations-on-change]
  # タスクにnotify: ハンドラー名 といった形で指定を加えるとそのタスクがトリガーとなってハンドラーが起動する
  handlers:

今回はbrewで入れるものの吟味や記述までは手が回らなかったので、時間を作ってコツコツ進めて行きたいですmm

ざっとですがAnsibleに触れられたので、良い体験になりました。 また、本当に構造がシンプルで書きやすくて良いですね!気に入りました!

次は現状chefで書いていたvagrantのプロビジョニングを試しにAnsibleで書いてみたりするのもいいかなぁ。