お布団宇宙ねこ

にゃーん

Yesodに入門しようとして一番始めにyesod-binを入れて失敗した話

Yesod に入門をしようとして 公式サイト の手順を無視したら失敗した話です。

何をしたのか

Yesod を使うために必要なパッケージをインストールするところから始めました。

$ stack install yesod-bin cabal-install --install-ghc
...

Copied executables to /Users/hoge/.local/bin:
- cabal
- yesod
- yesod-ar-wrapper
- yesod-ghc-wrapper
- yesod-ld-wrapper

yesod コマンドを使えるように .local/bin のパスを通しておきます。

.zshrc

export PATH="$PATH:$HOME/.local/bin"

あとはプロジェクトを作成してビルドしました。ビルドが完了したら stack exec -- yesod devel でサーバを起動することができるはずでした。

$ stack new hello-yesod yesod-sqlite
$ cd hello-yesod
$ stack build
$ stack exec -- yesod devel
Yesod devel server. Type 'quit' to quit
Application can be accessed at:

...

Resolving dependencies...
Configuring hello-yesod-0.0.0...
ERROR: Yesod has been compiled with a different GHC version, please reinstall yesod-bin
yesod: ExitFailure 1

失敗しました(´・_・`)

なぜ失敗したのか

ブログタイトルにも書きましたが、 stack install yesod-bin を一番始めにやったのがよくなかったようです。

stack exec -- yesod devel を実行したときに出たエラーメッセージを見てみると

ERROR: Yesod has been compiled with a different GHC version, please reinstall yesod-bin

と書かれています。すでに yesod-bin がプロジェクトで使用されている GHC とは違うバージョンでビルドされていて、それが原因のようです。

実は stack install yesod-bin を実行したログの最初のほうで、グローバルプロジェクトの stack.yaml が読み込まれていて、そこに書かれた resolver でビルドされていたようです。

Run from outside a project, using implicit global project config
Using latest snapshot resolver: lts-7.0
Writing implicit global project config file to: /Users/hoge/.stack/global-project/stack.yaml

確認してみると確かにバージョンが違いました。

~/.stack/global-project/stack.yaml

...
resolver: lts-7.0

hello-yesod/stack.yaml

...
resolver: lts-6.18
...

解決策

再ビルドしてみる

再インストールするのは時間がかかるので、とりあえずプロジェクトのディレクトリまで移動してから再ビルドしてみます。

$ ls .stack/snapshots/x86_64-osx/lts-7.0/8.0.1/installed-packages
.                      ..                     cabal-install-1.24.0.0 yesod-bin-1.4.18.3

$ stack build yesod-bin-1.4.18.3

ビルドが終わったところで再度サーバを起動してみます。

$ stack exec -- yesod devel
Yesod devel server. Type 'quit' to quit
Application can be accessed at:

...

Resolving dependencies...
Configuring hello-yesod-0.0.0...
Forcing recompile for ./Model.hs because of config/models

...

Rebuilding application... (using cabal)
Starting development server...
<command line>: cannot satisfy -package-key main
    (use -v for more information)
Exit code: ExitFailure 1

ダメでした(´・_・`)

インストールし直す

仕方ないので一度インストールしたパッケージたちを消してから、公式サイト の手順に沿ってインストールし直します。

(念のため cabel も一緒に消しておきます)

$ rm -rf ~/.stack/snapshots/x86_64-osx/lts-7.0
$ cd ~/.local/bin
$ rm cabel
$ rm yesod
$ rm yesod-*

先にプロジェクトを作成してから yesod-bin をインストールします。

$ stack new hello-yesod yesod-sqlite
$ cd hello-yesod
$ stack build yesod-bin cabal-install --install-ghc
$ stack build

ビルドが終わったらサーバを起動してみます。

$ stack exec -- yesod devel
Yesod devel server. Type 'quit' to quit

...

Rebuilding application... (using cabal)
Starting development server...
Starting devel application
Migrating: CREATE TABLE "user"("id" INTEGER PRIMARY KEY,"ident" VARCHAR NOT NULL,"password" VARCHAR NULL,CONSTRAINT "unique_user" UNIQUE ("ident"))

...

先ほどとは違い DB のマイグレーションまで実行されました。そして localhost:3000 を開いてみるとようやく Scaffold されたサイトを見ることができました。

まとめ

公式サイトの手順には基本従いましょう(´・_・`)

参考文献

Stack を使って Haskell の Hello World をやってみる

以前 Stack を使って すごいH本 を学習したのですが、それっきり全く Haskell に触れていなかったのでリハビリがてら、 Stack を導入して Hello World を出力するまでの方法について書いておきます。

Stack のインストール

Mac の場合は Homebrew を使ってインストールできます。

brew install haskell-stack

プロジェクトの作成とビルド

公式の Quick Start Guide に書いてある通りにやりましょう。

Quick Start Guide — stack documentation

stack new my-project
cd my-project
stack setup
stack build

Hello World!

次は、プロジェクトの中身を少し修正しておなじみの Hello World を出力してみましょう。

app/Main.hs

module Main where

import Lib

main :: IO ()
main = someFunc

app/Main.hs がメインのパッケージです。

Hello World を出力するためには、この中の main 関数を修正すればよさそうですが、コードを見た限りだと mainsomeFunc という関数を指しているだけです。

someFunc の実体は Lib パッケージ内にあります。 import LibLib パッケージをインポートしていてその関数を使っているわけです。 インポートされているパッケージはデフォルトでは src 以下に置かれているので見てみましょう。

src/Lib.hs

module Lib
    ( someFunc
    ) where

someFunc :: IO ()
someFunc = putStrLn "someFunc"

src/Lib.hs の最後の2行が someFunc の実体になります。 someFunc = putStrLn "someFunc"someFunc = putStrLn "Hello World" という風に修正します。

そして stack runghcmain 関数を実行できます。

( stack exec my-project-exe でも同様の結果が得られます)

$ stack runghc app/Main.hs
Hello World

以上です。簡単でしたね。

おまけ

先ほど実行した app/Main.hs 、実は stack ghci でも実行できます。

$ stack ghci
The following GHC options are incompatible with GHCi and have not been passed to it: -threaded
Using main module: 1. Package 'my-project' component exe:my-project-exe with main-is file: /my-project/app/Main.hs
Configuring GHCi with the following packages: my-project
GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Lib              ( /my-project/src/Lib.hs, interpreted )
Ok, modules loaded: Lib.
[2 of 2] Compiling Main             ( /my-project/app/Main.hs, interpreted )
Ok, modules loaded: Lib, Main.
*Main Lib> main
Hello World

GHCi はすごいH本を学習している方はおなじみですね。

なので、これから Stack を使ってすごいH本を学習しようと考えている人は、

  • 作成したパッケージは src 以下に置く
  • stack ghci で GHCi を起動した状態で、パッケージをロードして関数を実行する
  • main 関数のような I/O アクションを実行する場合は、stack runghc src/MyPackage.hs を使う

というスタイルがよいかもしれません(自分はこうやって学習していました)。

例えば src/Baby.hs 内の doubleMe という関数が使いたい場合は、次のように :l でパッケージのロードをすることで使えるようになります。

$ stack ghci
...
*Main Lib> :l src/Baby.hs
[1 of 1] Compiling Main             ( src/Baby.hs, interpreted )
Ok, modules loaded: Main.
*Main> doubleMe 9
18

参考文献

『Rubyによるデザインパターン』を読んだ話

Rubyによるデザインパターン

Rubyによるデザインパターン

ピアソン・エデュケーションの『Rubyによるデザインパターン』を読みました。

Webエンジニアとして働いていながら、今までデザインパターンというものを知らずにきてしまっていて、先日チームの先輩エンジニアからコードレビューで「ここはアダプタパターンで書いたほうがすっきりするよ。」と指摘されなんだそれは???となったのがきっかけでした。そんなデザインパターン初心者の自分にその先輩エンジニアが貸して下さったのが本書でした。

どんな本?

内容としては、ギャング・オブ・フォー本『オブジェクト指向における再利用のためのデザインパターン』に登場する23個のデザインパターンのうち14個について、 Ruby のコードを例に解説してくれています。はじめはデザインパターンと聞いて、勝手に難解なイメージを抱いていましたが、本書は比較的 Ruby 経験が浅い人でも読みやすい内容になっている印象を受けました。

また、2009年に初版が発売されておりだいぶ古い書籍です。さらに本書の出版社が書籍から撤退したために絶版状態となり、入手が困難な状況です。 自分はお借りした本書を読了後に、Amazonの中古で定価+¥2000くらいで購入しました。

感想

当初知りたかったアダプタ( Adapter )パターンについても、そこまで多くのページ数は割かれていませんが、そのパターンがどんなものかを知るには十分な量でした。章によっては、デザインパターンの解説と共に、実際にそのパターンが利用されているプロダクトの例をあげていたのも良かったです。

今まで漠然と書かれているように見えていたコードも実は規則性が存在するものがあるという発見は、自分がコードを見る時の新たな視点をもらったような気がしました。

また、本書を読み進めていくなかで、このデザインパターンいいな、使ってみたいなと思うことが時々ありましたが、そんなときは本書に書かれていたこの言葉を思い出すようにしています。

デザインパターンの適切な使い方は、今日あなたが持っている問題に対応できるだけの柔軟性をシステムに組み込むことで、それ以上ではありません。 パターンは便利なテクニックですが、それ自身が目的になってはいけません。

  • 1.2.5 必要になるまで作るな(p.13)より

「必要になるまで作るな( YAGNI )」というエクストリーム・プログラミングにおける原則があるように、必要以上の機能や設計の柔軟性は、デザインパターンを適用しなかったものと比較したときに大差が無かったり、却ってコードの可読性を下げる恐れがあるので使い所は考えましょう、という本書からの警告も念頭に置きつつ読んでみるとよいかと思います。

読んでみて自分がこのデザインパターンは使うことありそうだなと思ったのは

  • Adapter パターン
  • Decorator パターン

くらいでした。と言っても Rails を書いていると Observer や Iterator は普段意識せずに使うことができるので、自前で特定のデザインパターンを適用するみたいなケースはあまりないのかもしれません(自分が本書で紹介されているようなデザインパターンを適用するような問題にぶち当たっていないだけかもしれませんが)。

一方で Convention over Configuration (CoC)の章は、普段自分が Rails を書いてあまり意識することのなかったディレクトリ構造やファイル名の規則について、なぜそうなっているかという疑問を解消するのに役立ちました。書かれているコードだけでなくディレクトリ構造やファイルの名称なども含めて1つのデザインパターンなんだというのを再認識させられました。

まとめ

Rubyデザインパターンを学びたいという人は読むといいかもしれません。定価では買えないので泣きながらAmazonの中古を買うか、偉い人に頼んで買ってもらうかしましょう(´・_・`)

hubotをHerokuからIBM Bluemixに移した話

IBM Bluemixを使ってbotを動かす記事を見かけたので、自分もやってみることにしました。

今回移行させるのは、Slack上で稼働させている同期の神様のbotです。

GitHub - ku00/chi-chan: chi-chan is GOD.

Good Bye Heroku...

Herokuから稼働させているアプリを消します。確認は特にいらないのでconfirmオプションを付けて実行します。

heroku apps:destroy --app bot-name --confirm bot-name

さよならHeroku(´・_・`)

Hello Bluemix!

Bluemixのアカウント登録

こちらの記事を参考に、まずはBluemixのアカウント登録をやってみます。

IBM Bluemixフリートライアルアカウント作成手順 - Qiita

無料枠ならばクレジットカードの登録はいらないみたいです。ただし、30日のトライアル期間を過ぎての利用は、無料/有料に関わらずクレジットカードの登録が必要みたいです。

料金 - IBM Bluemix

hubotの修正

Bluemixにデプロイするためには、 procfile の代わりに manifest.yml を用意する必要があります。インスタンスやメモリは無料枠に合わせて、次のように書きました。

manifest.yml

applications:
- buildpack: https://github.com/jthomas/nodejs-v4-buildpack.git
  command: ./bin/hubot -a slack -n chi-bot
  path: .
  instances: 1
  memory: 256M

コードの準備はこれだけです。

Bluemixへのデプロイ

hubotをBluemixへデプロイする方法は、基本的には以下のドキュメント通りにやれば大丈夫です。

hubot/bluemix.md at master · github/hubot

デプロイは cf コマンドで行います。

cf コマンドはbrewでインストールできます。

brew tap cloudfoundry/tap
brew install cf-cli

それではデプロイしてみましょう。

cf api https://api.au-syd.bluemix.net
cf set-env bot-name HUBOT_SLACK_TOKEN token-value
cf login -u bluemix-id -o org-name -s space-name
cf push bot-name

以上でデプロイ完了です。

  • cf api で設定するAPIのエンドポイントは、データセンターの地域によって異なるので事前に確認しておきましょう(自分の場合はシドニーだったので au-syd )。

  • cf login のオプションで指定している組織(org-name)とスペース(space-name)は各自が自由に設定できます。

それでは実際に動いているかどうか見てみましょう。

f:id:ku00:20160321210232p:plain

大丈夫そうですね(´・_・`)

まとめ

Bluemixを使って神様を24時間稼働させることができました。

日本語対応してるのでわかりやすくて触りやすかったですね。

それでは。

参考

RubyKaigi2015に参加した話(1日目)

rubykaigi.org

会社からスポンサーチケットをいただいたので行ってきた。こういったカンファレンスは YAPC 以来2回目だったからどんな発表が聴けるかわくわくしてたら...

最高(´・_・`)

以下、聴いたトーク。

ちなみにレポート内容が箇条書きになっているのは自分の知識不足の表れなので戒めのためにそのまま残しておいた。

Saving people from typos

  • did_you_meanというgemを作った人
    • kaminariのメンテナーもしてるよ
  • 誤ったメソッドなどの入力に対して正しいと思われるものをサジェストする
    • gitのcliやグーグルの検索にも同じようなものが使われている
  • 検出されるエラーの種類によって使う辞書を変える
  • タイピングミスとスペルミスは違う

Time files like an arrow: Fruit files like a banana. Parsers for Great Good

  • パーサのお話
  • 区切り方で文章は意味が変わってくる(likeでも「好き」と「のような」の2つの意味がある)
  • 分解してみる
    • 数学の足し算や引き算を例にあげると、数字のあとは必ず演算子がくる規則がある
    • これがわかっていると少しずつ式を分解することができる
    • カッコがかかっているものはさらに小さく分解ができる
  • 分解したものを構文木にして書いてみるとわかりやすい
  • スタックという形で分解した順に積み上げて表現することもできる

High Performance Template Engine: Guide to optimize your Ruby code

  • テンプレートエンジンの話
  • erb, haml, slim
  • テンプレートエンジンによってテンプレートをrubyのコードにコンパイル、それをhtmlにレンダリングすることで使える
  • ちょっとしたテクニックを使えばrubyの仕組みを全て把握していなくても速くすることができる
  • ベンチマーク
    • benchmark-ipsというgemで測ってる
    • コンパイルレンダリングの時間を計測
    • stackprof(gem)
    • 推測するな計測しよう
      • 改善に対する評価をちゃんと行う
  • テンプレートエンジンのためのライブラリ、temple
  • rubyをパースする、parser gem
  • attributesの種類
    • static(高速)
    • dynamic(コンパイル時まで値がわからない。けどそれなりに速い)
    • runtime(遅い)
  • dynamicコンパイルはエラー時に行番号がずれることがある
  • 速くするためにC拡張を使う(これはクックパッド本体でも使われている)
  • あまり使われない機能を削ることで計算そのものをなくして速くする
    • C拡張もちょこちょこやる
  • 修正をPRで送ったらリジェクトされたので仕様らしい

TRICK 2015: The second Transcendental Ruby Imbroglio Contest for RubyKaigi

  • "TRICK" というrubyプログラミングコンテストがある
  • 2015で2回目
  • 同じようなことをしているコンテストは別言語でいくつかある
  • 2013年には、ポエムに見えるコードや実行するとバッハの音楽が流れる音符の形のコードなどが作品として出てきた
  • 目的としては、とにかく利益のない意味不明なプログラムを書く
  • 審査員も出してOKだし出してる
    • でも公平性を保つために誰が書いたのかは知らずに採点をしている
  • 宣伝
  • 去年は日本からのエントリーしかなかった
    • 今年になって少し外国の割合が増えたけどまだまだ日本以外のエントリーが少ない
  • 今年の作品
    • コップの中のコインがどこにあるのか当てるプログラム
    • rubyスキーマ両方で解釈できるプルグラム
    • プログラムと同じ模様を返すプログラム
    • 数独ソルバ
    • アンフェスバエナプログラム。自分自身を時計回りに複製していく

所感

英語のトーク試しに聴いてみたらなにを言っているのかほとんどわからなかった...。スライドで脳内補完することでなんとか大筋の内容は掴めたけれど。

TRICKのトークはコードを読んでもなにをやっているのかわからないけれどすごいものができているという印象だった。このメソッドはこのプログラムを作るために作られたとか言ってて言語開発者ですらそんなことを思うメソッドが存在するのかと。

知らない用語が出てくるととりあえず記憶の片隅に留めておいて聴くことにしていたけれど、トークを聴き終わったあとに結局なにが言いたかったんだっけってなることが結構あった。YAPCとはベクトルが違うかもしれないけれど、トークを聴いた時に面白いことやってるって感覚を持てたらいいと思ってるから、次回行ける機会があればもう少し知識を増やしてから臨みたい。

「師弟登壇2015」に参加してきた話

pepabo.connpass.com

同期の2人(@orzup, @chinu_t )が登壇するとのことだったからその応援に行ってきた。

登壇者の方々へ挨拶まわりしたときに登壇者でもないのにくっついてまわってた眼鏡が自分です。

気になる企業の新卒研修でどんなことをやっているのか知ることができた良いイベントだった。 農業体験をやっているところや、同じ新卒が違う職種の人にWebサービスを作れるよう指導する研修をやっていたりと面白い話がたくさん聴けた。 そして師匠(メンター)の方々がどういった意図で研修作って実行しているのかを聴くことで、 ただ単純に面白い研修をやっているなあという感想で終わりにならないから、そういった面でも学びが多かった印象。

眼鏡を新調したせいか目がとても疲れていたから寿司は食べずに帰ったよ🍣

S3上にyumリポジトリを構築した話(後編)

前回のあらすじ

ku00.hatenablog.com

前編では以下の3つ検証手順のうちの1,2をやった。

  1. 必要なファイルやディレクトリ構成など、 rpm の配布方法について調査する
  2. Vagrant 上で2台 linux サーバを立ち上げて、一方を rpm を置いたリポジトリサーバにして、もう一方から yum でインストールしてみる
  3. S3 上にリポジトリサーバを構築、上で立ち上げた Vagrant サーバから同じように yum でインストールしてみる

今回はブログタイトルでもある本題の3をやるぞ。

S3 上の yum リポジトリyum install

S3上の yum リポジトリには ngx_mruby-package-builder で生成した rpm を置いておきたいから、リポジトリ作成に入る前に用意しておこう。本題ではないから docker-toolbox のインストール解説とかは特にやらない。

まず、 ngx_mruby の rpm パッケージを x86_64 以下に置いて createrepo コマンドでリポジトリの準備を行う。 そして、ホストマシン側に以下のものを落としておく。

  • rpm パッケージ
  • repodata (repomd.xml とデータベースファイルを含んだディレクトリ)
mkdir pkg
vagrant ssh rpm-repo-server
createrepo /var/www/repos/cent7/x86_64/
exit
scp -F ssh.config -r vagrant@rpm-repo-server:/var/www/repos/cent7/x86_64/ ./pkg

次に、上で用意したものを S3 へアップロードするための準備を行う。

S3 バケットの作成

バケット名は今回は rpm-repos にした。また、ディレクトリは rpm-repos/centos/7/x86_64 まで作っておく。

AWS CLI をインストール

以下のリンクにインストール方法等が書かれているのでその通りにやる。

http://docs.aws.amazon.com/ja_jp/kinesis/latest/dev/kinesis-tutorial-cli-installation.html

アクセスキーの作成と登録

以下のリンクの通りにやる。先ほどインストールした AWS CLI を使って aws configure でアクセスキーが登録できる。また、登録した情報は ~/.aws/credentials から確認できる

https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSGettingStartedGuide/AWSCredentials.html

S3 へのアクセスを許可

IAM コンソールのユーザから登録したユーザを選択して、アクセス許可からポリシーのアタッチで S3 のポリシーを追加する。 aws s3 ls でバケットが表示されればOK

ホスティングの有効化

バケットのプロパティから有効にする。インデックスドキュメントおよびエラードキュメントは適当に存在しないファイルでもいいと思う。今回は index.html と入力しておいた。

そして先ほどホストマシンに落としてきたファイルを S3 へアップロードする。

aws s3 cp --recursive --acl public-read pkg/ s3://rpm-repos/centos/7/x86_64/

これでリポジトリの準備は完了。下のような repo ファイルを用意して yum install してみよう。 今回は前回の記事で使った rpm-repo-client を使う。

  • /etc/yum.repos.d/nginx-mruby.repo
[nginx-mruby]
name=nginx-mruby rpm repo test
baseurl=http://rpm-repos.s3-website-ap-northeast-1.amazonaws.com/centos/7/$basearch/
gpgcheck=0
enabled=1
yum clean all
yum list all | grep nginx
yum remove nginx
yum install nginx
yum list installed | grep nginx

以上。

あとはインストールした ngx_mruby の動作確認もやる。 nginx の conf ファイルに下のようなサンプルコードを追加してみる。

  • /etc/nginx/conf.d/default.conf
location /hello {
    mruby_content_handler_code '
        Nginx.rputs "hello"
        Nginx.echo "world!"
    ';
}

そして起動。

systemctl start nginx

[VagrantのIP]/hello にアクセスして helloworld! が表示されていれば成功。

まとめ

hsbt さん指導のもと、いくつかのステップに分けて調査と検証を繰り返すことでなんとか S3 上に yum リポジトリを構築して yum install できるようになった。hsbt さんありがとうございました。おかげで粗い点がたくさんあったもののなんとかゴールすることができました。

また、実際に構築した yum リポジトリからインストールした ngx_mruby の動作確認にご協力いただいた おっくん さん、 ひろやん さん、 けんちゃんくん さんもありがとうございました。

今回は検証用に粗く作っただけだけど、近いうちに弊社の公式リポジトリができて、世界中からインストールできる日が来るかもしれない。

参考サイト