ubuntu で install 済みのパッケージリストを表示する
イントロ
yum list installed
的なやつ。
apt-get list
のようなコマンドがあるだろうと思っていたが無かった。
コマンド
dpkg --get-selections
参考
http://www.howtogeek.com/howto/linux/show-the-list-of-installed-packages-on-ubuntu-or-debian/
embulk-filter-eval というフィルタープラグイン書いた
イントロ
まぁ半分ネタも入ってますが、何かちょっとした事を行う程度なら役に立つはず。
これは何が便利?
input
として与えられたカラムに対して、Ruby のコードでちょっとした変換を加える事ができる embulk プラグインです。
embulk
の version 0.5.2
で作りました。
example
github の README に書いてあるサンプルそのままなのですが。(サボってるわけじゃなくて、何かサンプルがあったほうが説明しやすい)
以下のように embulk
コマンドを使って sample を作り、preview できたとします。
$ embulk example $ embulk guess embulk-example/example.yml -o config.yml
preview
すると、以下の様な出力です。
$ embulk preview config.yml +---------+--------------+-------------------------+-------------------------+----------------------------+ | id:long | account:long | time:timestamp | purchase:timestamp | comment:string | +---------+--------------+-------------------------+-------------------------+----------------------------+ | 1 | 32,864 | 2015-01-27 19:23:49 UTC | 2015-01-27 00:00:00 UTC | embulk | | 2 | 14,824 | 2015-01-27 19:01:23 UTC | 2015-01-27 00:00:00 UTC | embulk jruby | | 3 | 27,559 | 2015-01-28 02:20:02 UTC | 2015-01-28 00:00:00 UTC | Embulk "csv" parser plugin | | 4 | 11,270 | 2015-01-29 11:54:36 UTC | 2015-01-29 00:00:00 UTC | NULL | +---------+--------------+-------------------------+-------------------------+----------------------------+
eval_columns
では、例えば全ての id に 1
を足して出力したい、という要望があったとします。
こんな時に filter-eval
では簡単に書くことが出来ます。 config.yml
に以下のように指定するだけ。
filters: - type: eval eval_columns: - id: value + 1
value
には id 列の要素が入ってきます。
なので value + 1
とすると、最初は value =1 なので、 value + 1
が評価されて 2 が返って、次は 3 が返って... というわけです。
$ embulk preview config.yml +---------+--------------+-------------------------+-------------------------+----------------------------+ | id:long | account:long | time:timestamp | purchase:timestamp | comment:string | +---------+--------------+-------------------------+-------------------------+----------------------------+ | 2 | 32,864 | 2015-01-27 19:23:49 UTC | 2015-01-27 00:00:00 UTC | embulk | | 3 | 14,824 | 2015-01-27 19:01:23 UTC | 2015-01-27 00:00:00 UTC | embulk jruby | | 4 | 27,559 | 2015-01-28 02:20:02 UTC | 2015-01-28 00:00:00 UTC | Embulk "csv" parser plugin | | 5 | 11,270 | 2015-01-29 11:54:36 UTC | 2015-01-29 00:00:00 UTC | NULL | +---------+--------------+-------------------------+-------------------------+----------------------------+
実行してみたら、id のカラムが 2, 3, 4, 5
となりました。
out_columns
このプラグインでは出力したいカラムを制御することも可能で、out_columns
という設定で、出力したいカラムを配列で書けば可能です。
filters: - type: eval eval_columns: - id: value + 1 out_columns: - id
これは out_columns
に id
しか指定していないので
$ embulk preview config.yml +---------+ | id:long | +---------+ | 2 | | 3 | | 4 | | 5 | +---------+
こんな感じになります。
まとめ
またゴミのような gem を作ってしまった...
次はもっといいものを考えてます。
rbenv の plugins
イントロ
今使ってる rbenv
の plugin
たち。
rbenv
はこういうエコシステムが便利だから使い続けている。
最近務めている会社では流行りのようなので、私もやってみる。
plugins
% l .rbenv/plugins/ rbenv-ctags rbenv-default-gems rbenv-gemset rbenv-update ruby-build
順に紹介
rbenv-ctags
ruby のコアライブラリにタグファイル(ctags
用)を作ってくれるやつ。
ruby のコアライブラリを追うときに便利。だが、これは vim 用のタグしか吐いてくれない。(作者が vim 使いだから?)
vim 使える人は本家を使えばいいのだけど、私は emacs
しか使えないので、emacs
用のタグを吐くように、fork したものを使ってる。
PR 出すと vim マッチョな作者に殺されそうなのでしていない。
rbenv-default-gems
sstephenson/rbenv-default-gems
rbenv build
を使って ruby を install した時に、自動で gem を install してくれるやつ。
一回入れてしまうと便利。有名。
少し変わったことといえば、mgi166/dotfiles で default-gems
ファイルをバージョン管理していて
rake install default-gems
で ~/.rbenv/default-gems
ディレクトリにシンボリックリンクを貼ってくれるようにしたが、このメソッド、全く流行る気がしない。
% cat ~/.rbenv/default-gems bundler pry pry-byebug pry-stack_explorer ripper-tags
デフォルトの環境汚したくないけど、汚しまくっていて、羞恥心がなくなりつつある今日この頃。
rbenv-gemset
一言で言うと rbenv
版 rvm gemset
gem を管理するやつ。bundler
はプロジェクト単位で管理するけど、これは自在に namespace を作ることができる。
昔は gem 作るたびに gemset
作ってた。Gemfile
作るのめんどいけど、何か作ろうかなーって時に使う。
最近は何かやる際には gem
にするつもりがなくても bundle gem
や bundle init
で頑張る場合が多く、出番が少ない。
あ、でも rails
っていう gemset 作っておくと、rails new
する時楽で好き。
ruby-build
のように、.rbenv-gemsets
ファイルの有無で gemset
が決まるので、bundler
と共存する道はある、と思ってる。
% rbenv gemset list 1.9.3-p545: chef_repo veewee-boxes 2.1.0: d_parallel hipchat_searcher 2.1.2: dangerous_open_uri hipchat_searcher qiita-notify rails s3_utils 2.1.5: rails 2.2.1: rails 2.3.0-dev: rails
rbenv-update
rbenv update
コマンドで、全ての plugin を git pull
してくれるやつ。
これのお陰で ruby の新しいバージョンが出るたびに、毎回
cd ~/.rbenv/plugins/ruby-build
git pull
しなくてよくなった。 コマンド覚えやすいから好き。
ruby-build
rbenv-build
じゃなくて、ruby-build
rbenv
を有名にした MVP
。(と思っている)
説明不要。
まとめ
ネタになると思ったけど、有名どころしか使ってない。
boot2docker 内のコンテナに ssh で接続する
イントロ
最近ようやく docker を触り始めています。
にわか丸出しなので、【翻訳】Dockerコンテナ内でSSHDを実行してはいけない理由 | POSTD のような記事を見かけたのにも関わらず、ssh で接続しようとしています。
理由は serverspec
使ってコンテナのテストしたいと考えたからです。
(ssh
接続しないとできない... はず)
方法
Dockerfile
FROM ubuntu:14.04 RUN apt-get update RUN apt-get install -y openssh-server RUN mkdir /var/run/sshd RUN echo 'root:root' | chpasswd RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config EXPOSE 22 CMD /usr/sbin/sshd -D
build
% docker build -t sshd . % docker port $(docker run -d -P openssh) 22 #=> 0.0.0.0:49155 % docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5d215294c5cf sshd:latest "/bin/sh -c '/usr/sb 17 seconds ago Up 16 seconds 0.0.0.0:49155->22/tcp boring_hodgkin
無事コンテナが作れた。
docker run
に -P
オプションを渡さないと expose
された port が公開されないらしく、若干ハマった。(https://docs.docker.com/reference/run/#expose-incoming-ports)
docker port
コマンド実行結果の port 部分を覚えておく。
接続してみる
-p
の引数は先ほどメモった docker port
コマンド実行結果を渡す。
% ssh root@$(boot2docker ip) -p 49155 The authenticity of host '[192.168.59.103]:49155 ([192.168.59.103]:49155)' can't be established. RSA key fingerprint is 6c:52:de:f7:85:8f:29:69:8c:5c:78:d4:ec:43:3d:69. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '[192.168.59.103]:49155' (RSA) to the list of known hosts. root@192.168.59.103's password: Welcome to Ubuntu 14.04 LTS (GNU/Linux 3.2.0-76-generic x86_64) * Documentation: https://help.ubuntu.com/ The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. root@5d215294c5cf:~#
入れたー
おまけ
boot2docker
で試した理由は、docker
周辺の仕組みを理解したかったからであって、boot2docker
でないといけない理由はありません。
後、観測範囲では、何故か boot2docker
で試した例が見当たらなかったから。
ActiveSupport::Configurable の話
イントロ
よく設定ファイルで見るクラスを簡単に作れる module ActiveSupport::Configurable
の紹介
使い方は、rails/configurable.rb at master · rails/rails のコメント文を読んだほうが早い。
よくあるやつ
具体例を幾つか紹介。
引数が違ったり、ブロック引数有り/無しだったり、メソッド名が違う等の差はあれど、どれも似ている
vagrant
Vagrantfile を拝借
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "centos7" config.vm.network "private_network", ip: "192.168.33.10" .... end
rails
config/environments/development.rb
を拝借
Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false ... end
tapp
esminc/tapp より
Tapp.configure do |config| config.default_printer = :awesome_print config.report_caller = true end
rails_config
RailsConfig.setup do |config| config.const_name = 'AppSettings' config.use_env = true end
他にもあったけど、紙面の関係上省略。
使ってみる
インスタンスを使う
require 'active_support/configurable' class MyConfig include ActiveSupport::Configurable config_accessor :id, :name end c = MyConfig.new c.id = 'aaa' c.id #=> 'aaa' c.name = 'bbb' c.name #=> 'bbb' c.hoge #=> NoMethodError: undefined method `hoge'
config_accessor
でメソッド名を渡すと、(内部でゴニョゴニョしてるが)アクセサが作られるというだけ。
また、config
というインスタンスメソッドが定義されて、それを呼ぶと登録した設定が全て取れる。
c.config
#=> {:id=>"aaa", :name=>"bbb"}
クラスを使う
ActiveSupport::Configurable
を include したクラスでは、ブロックを渡すお馴染みのインターフェイスが提供される。
class MyConfig include ActiveSupport::Configurable config_accessor :id, :name end # みたことあるやつや! MyConfig.configure do |config| config.id = 'aaa' config.name = 'bbb' end MyConfig.id #=> 'aaa' MyConfig.name #=> "bbb" MyConfig.config #=> {:id=>"aaa", :name=>"bbb"}
とはいえ、これだとクラス自体が設定を持っていて、何か気持ち悪い。
応用
例えば以下のようにクラスを書いてみると、しっくりくる。
class MyApp class Config include ActiveSupport::Configurable config_accessor :id, :name end def self.configure(&block) yield config end def self.config @config ||= Config.new end end MyApp.configure do |config| config.id = 'aaa' config.name = 'bbb' end MyApp.config #=> <MyApp::Config:0x007f9b7b9ab870 @_config={:id=>"aaa", :name=>"bbb"}> config = MyApp.config config.id #=> 'aaa' config.name #=> 'bbb'
- 設定を保持するクラス(
MyApp::Config
)にActiveSupport::Configurable
を include させる- 更に
config_accessor
でアクセサを宣言する
- 更に
とするだけで
MyApp.config
とすれば設定インスタンスを参照可能- MyApp を参照できれば、誰でも
config
を知ることができる
- MyApp を参照できれば、誰でも
MyApp::Config
はアクセサを定義しているだけ
みたいな事ができ、馴染みのあるコードになってきた。
けどこれだけだと、config_acessor
の代わりに attr_accessor
でいいんじゃね?ってなる。
オプションを渡す
ところがどっこい config_accessor
にはオプションを渡すことができる。
instance_reader
と instance_writer
だ。
class MyConfig include ActiveSupport::Configurable config_accessor :id config_accessor :name, instance_reader: false end c = MyConfig.new c.id = 'aaa' c.id #=> "aaa" c.name = 'bbb' c.name #=> NoMethodError: undefined method `name'
instance_reader: false
を与えると、MyConfig#name
という reader のメソッドが提供されなくなるので、NoMethodError
になる。
instance_writer: false
はというと、その逆になる。
class MyConfig include ActiveSupport::Configurable config_accessor :id config_accessor :name, instance_writer: false end c = MyConfig.new c.id = 'aaa' c.id #=> "aaa" c.name = 'bbb' #=> NoMethodError: undefined method `name=' c.name #=> nil
今度は MyConfig#name=
というメソッドだけ提供されていないので、writer を呼ぼうとすると NoMethodError
になる。
ブロックを渡す
default 値を定義することもできて、ブロックを渡せば可能。
class MyConfig include ActiveSupport::Configurable config_accessor :id config_accessor :name do 'bbb' end end c = MyConfig.new c.name #=> "bbb"
まとめ
rails/configurable.rb at master · rails/rails
デフォルト値などを考えだすまでは attr_accessor
でいいんじゃないか...? って思いました。
けど使い方次第でしょうねー
React.js で親子関係にある component の更新順序
イントロ
話題の React.js
を去年末ぐらいから、ちょこちょこと触っています。
殆ど Javascript
触ったこと無い状態から、いきなり React
始めて大分修羅の道だったのですが、最近ようやく慣れてきました。
何となくわかってきた React の性質っぽいものを残しておくメモ
これは何か
React.js
で作った component の更新順序を見てみた、というもの。
結論を言ってしまうと、親子関係にあると、必ず 「親 → 子」の順序で更新が行われる
現象
React.js
の基本原則として、this.setState
を呼ぶと、それがトリガーになって render
が呼ばれる、というものがある
(state
とは Ruby でいうインスタンス変数のようなもの。setState
は setter
だと思えばいい)
以下のように、子も親も同時に setState
を呼ぶとどうなるのだろう?という話。
超簡単なサンプルを作ってみた。
var Parent = React.createClass({ getInitialState: function() { return ( { age: 0 } ); }, setAge: function() { var value = this.refs.age.getDOMNode().value; this.setState({ age: Number(value) }); }, increment: function() { this.setState({ age: this.state.age + 1}); }, render: function() { console.log('in parent'); return ( <div id="parent"> <h2>parent</h2> <p>input parent age: {this.state.age}</p> <input type="text" ref="age"/> <button onClick={this.setAge}>submit</button> <h2>child</h2> <Child increment={this.increment} /> </div> ); } }); var Child = React.createClass({ getInitialState: function() { return ( { age: 0 } ); }, increment: function() { this.setState({ age: this.state.age + 1}); this.props.increment(); }, render: function() { console.log('in child'); return ( <div id="child"> <p>parent age: {this.state.age}</p> <button onClick={this.increment}>a year ago</button> </div> ); } }); React.render( <Parent />, document.getElementById('parent') );
最初に親の年齢を入力して、a year ago
ボタンを押すと、子供の年齢も親の年齢も 1 インクリメントするやつ。
ところでこのアプリ、親の年齢を入力しないと、親も子も 0 歳からスタートする。0 歳の親ってどういうこっちゃ。
けど細かいところは気にしない。
サンプルの重要なところは React の render で parent
から child
を作ってるところ。
つまり
- parent - child
のような構造を作っている。
一番下の a year ago
ボタンをクリックすると、console には
in parent in child
と出力される。
これは先に親の render
が呼ばれて、その後に子の render
が呼ばれることを意味している。
で、何がいいたい?
どうしてこういう順序になるのか、わからないです。
直感的には setState
が先に呼ばれた方、でも良い気もするので。
こういうもの、という理解でいいのだろうか?
「親→子」という流れは理解しやすんだけど、それで無理やり理解した気になるのもなんだかなー。
「理性の限界」を読んだ
イントロ
理性の限界――不可能性・不確定性・不完全性 (講談社現代新書)
- 作者: 高橋昌一郎
- 出版社/メーカー: 講談社
- 発売日: 2008/06/17
- メディア: 新書
- 購入: 56人 クリック: 299回
- この商品を含むブログ (176件) を見る
人間の「理性の限界」について、色々な角度からディスカッション形式で話が進んでいく。
途中「ハイゼンベルクの不確定性原理」や「ラプラスの悪魔」といった物理学の面白い話がでてきて、大学が物理学科の私は思わずニンマリ。
本を知ったきっかけ
part16後編のニコニコ市場を見たら、自分の持ってる本が入っててびっくりした。
「理性の限界――不可能性・不確定性・不完全性」は意外な発見があって面白いのでおススメ。特に、アローの不可能性定理は目からウロコでした。
http://t.co/UGvCN7ozKs
— なるしす (@kurodataro) 2014, 9月 14
最近ニコニコ動画の
3つのボタンでカービィボウル
という動画を見てしまった。
動画は勿論面白いんだけど、作者がすごい人だなと思っていて、彼がオススメするならって記憶に残っていた。
個人的な動機
読んでみようと思った理由はそれだけじゃない。
より合理的で、理性的に判断できるようになりたかったから、というのもある。
合理的な判断とはナンゾヤ、という話もあるけど、「今、自分は落ち着いていて、冷静に考えているか」ってこと。
常に意識したいことの一つです。
そういう基準や客観性をどうやって評価するか、維持するか、ということに興味があった。
背景
自分が「こっちのほうが良いんじゃないかなぁ」と考えることが、相手は「あっちのほうが良い」と思うことが、往々にしてある。
日常生活レベルの話なら「個性」と言い換えることができて、結構面白い。
けど合理的な判断を求められる仕事でも起こりえて、こちらは途端に厄介になる。
時に感情的な判断をしがちで、環境によっては到底理性的とは思えない判断をすることがある。不思議なことに。
でも仕事とは限らずに、自分もそういうことはあるし、他人を観察してそう思えることもある。
振り返ると「なんであんなことを」と思うけど、実際そういう時は客観性を失っていて「感情的になっていること」自体に気づかなかったり、あるいは気づかない振りをするものだと思う。
動機の動機
自分は冷静だと考えているけど、相手が感情的になっている場合。人によっては説得しようとすることが逆効果なこともある。
自分の説明が下手なのかな?と思ったけど、なんだか納得してくれているようには見える。でも相手の主張は変わらない。
そんな不思議な体験をした。
きっと自分が感情的になっている事に気づいていないからだろう、と思われる。
そんな時に「相手が自発的に自身の客観性を認識するためには、どうすればよいか」「自分は冷静になっているつもりで、実は論理的な説明ができていないのか?」という悩みを抱える事になった。
難しい。
本を読んで
「理性的とはナンゾヤ」という話にあまり触れず、相対的な議論が展開される。
「◯◯という方法は××という方法より、こういう理由で理性的だ」という感じ。
だから客観性をどうやって評価するか、という疑問の答えにはならなかったけど、ヒントにはなったし、単純に読み物として面白かった。
「神の非存在論」はなるほどなーという感じ。「神は理性では認識不可能」って結論は興味深い。
認識不可能だけど、神様という概念をほとんどの人間が理解していたり、或いは創りだしたりする。
神様 SUGOI
そんな神様を創れる人間はもっと SUGOI
「運と実力の間」を読んだ
イントロ
運と実力の間(あわい)―不完全情報ゲーム(人生・ビジネス・投資)の制し方―
- 作者: 木原直哉
- 出版社/メーカー: 飛鳥新社
- 発売日: 2013/06/08
- メディア: 単行本
- クリック: 2回
- この商品を含むブログ (6件) を見る
年末に読んだ本のうちの一つ。暇だったからブログに書いてみる
私の最近のマイブームが poker で、poker といえば木原直哉氏。
というわけで氏が書いた本を読んでみるか、と極めて安直な理由。
感想
面白い。今の自分が持ってない知見もあった。
内容は木原氏の生い立ちと WSOP 出場に至るまでの経緯、出場経験について語られていた。
元々興味を持って購入したので、その分楽しめた。
エンジニアリングとギャンブルについて
ここからは本の感想ではなく、極めて個人的な意見。
(観察対象があまりに少なすぎると思うけど) プログラムが書くことが得意なプログラマは(私を含む)、こういうギャンブル系が苦手な人が多いと思っている、という話。
言い換えると「確率で考え、実際に行動すること」が不得意な人が多い、ということ。
わかっていても行動できなかったり、そもそもそういう方面に興味が沸かない方が多い。
どうしてそう思うんだろうなーと今まで疑問だったけど、「運と実力の間」を読んでその理由っぽいものを思いついたので書き残します。
勝つまでのプロセスが違う
「勝つまでのプロセスが違う」というのがその有力候補。
当然「勝つ」とは何か、という定義は難しい。人によって違うから。
poker 側の「勝ち」は簡単に言うと「お金が増えること」
プログラム側は仮に、プログラムがどこかでエラーを吐いていて、それをデバッグし、直す作業を考えてみる。
直せたら「勝ち」としよう。直せなくて諦めたら「負け」
poker の話
本の中では以下のように述べられている。
- 負けている時にやり方を変えるな
曰く、負けている時にやり方を変えたら、何が原因で負けているか、わからなくなるからだ。と。
私の拙い経験としても賛成意見。
これは運が絡むゲームにはよくある考え方だと思う。
プログラミングの話
じゃあプログラミングではどうだろうか。
状況にもよるだろうけど
- デバッガを起動し、原因を突き止める
- 設定ファイルを見直す
- ログを追う
等が思い浮かぶ。
共通しているのは、プログラム(またはそれに関連する物)を少しだけ書き換えて、何度も実行する、ということ。
行った修正でエラーが出なくなるか、ちゃんと確かめないといけない。
どんなときも根気強く前に進み、心が折れるのが一番マズい。(経験上)
逆に言えば、プログラムを書き換えないで再実行する意味は無い。(時間に関連するバグなど例外はあるが)
何となく rspec をもう一回叩いてみるか... は時間の無駄だと思う。失敗する時は原因を潰さない限り、何度も失敗する。
だからどこに原因があるか色々考えたり、調べたりして、あらゆる方法を試すのだ。
何が言いたいかというと、負けている時には色々試すのが、プログラミングをする上で良いやり方だと思うってこと。
前提の話
プログラミングと poker では勝てるようになるまでのプロセスが違う、という意見なんだけど、もう一つ重要な考え方がある。
それは人は自身の向き不向きを自覚していて、自然に向いているものに興味を持つ、という考え方。方位磁石が自然と北を向くような感じ。
特に子供の頃はそのような傾向が強く見られるように思える。 これはもう一つ示唆するところがあって、それは「そう簡単に自分の向き不向きが変わらない」という事。
まとめの話
- プログラミングと poker は勝つ方法が違う
- 人は自分に合った興味を持つ
- しかもそれは中々変わらない
という意見から、プログラミングが好きな人はギャンブルに興味を持ちにくく、しかも不得意である可能性が高い。と思うようになった。まる。
言語化すると長い...
で、何が言いたい?
グダグダ書きましたが、全部極論です。
視野が狭いとこうなるので、気をつけねば。
株や投資などには、個人の自己責任でお楽しみください。
binding.pry 使ってる時に、一気にループを抜ける方法
イントロ
みんな大好き pry
の話
何回も binding.pry
が呼ばれる環境下で、毎回 exit
を入力するのめんどいよね、という話。
サンプル
class Test def aaa binding.pry 'aaa' end end
describe '#aaa' do it '1' do expect(test.new.aaa).to eq('1') end it '2' do expect(test.new.aaa).to eq('2') end end
この場合 binding.pry
は 2 回、処理を停止する。
4: def aaa => 5: binding.pry 6: 'aaa' 7: end
exit
叩く。
4: def aaa => 5: binding.pry 6: 'aaa' 7: end
もう一回 exit
叩く。
あるあるですね。
こういう時、一回でプロンプトまで戻りたいわけです。
解決法
!!!
or exit!
or exit-program
を入力する
4: def aaa => 5: binding.pry 6: 'aaa' 7: end >> !!! % # 即座に終了した!
知らなかった...
rails でカスタム generator 作る話
これは何か
好きな generator を作る話。ここで述べる generator
とは
rails generator hoge
のような rails generate
コマンドのこと。
知識整理のために書いてみる
雛形作成
rails には generator を生成する generator があって、以下の様なコマンドを叩けば良い。
rails generate generator <generator名>
試しに test
という generator を作ってみる。
% rails generate generator test create lib/generators/test create lib/generators/test/test_generator.rb create lib/generators/test/USAGE create lib/generators/test/templates invoke test_unit create test/lib/generators/test_generator_test.rb
ファイルが作られた。 作られた generator は以下のように実行できる
rails generate <generator名> (<引数1>, <引数2>, ...)
引数は generator 側の定義で制御する
generator 作成
生成されたファイル
先ほどの rails generate generator test
コマンドで生成されたファイルを順番に見ていく
lib/generators/test/test_generator.rb
class TestGenerator < Rails::Generators::NamedBase source_root File.expand_path('../templates', __FILE__) end
メインの generator ファイル。
Rails::Generators::NamedBase
を継承した {generator名}Generator
というクラスが生成されている。
ここにメソッドを定義していく。
具体例
TestGenerator
に何も生産しないメソッドを作る。
class TestGenerator < Rails::Generators::NamedBase source_root File.expand_path('../templates', __FILE__) def ore puts "俺が" end def dhh puts "DHH、こと" end def da puts "David Heinemeier Hanssonだ!" end end
rails generate
コマンドを叩くと TestGenerator
クラスのインスタンスメソッドが 上から全部実行される
% rails generate test test # test という引数を仮に与えている 俺が DHH、こと David Heinemeier Hanssonだ!
ご覧のとおり上から実行されていることがわかる。
なのでファイルを作りたかったら、そういうメソッドを書けばよい。
ディレクトリを掘りたかったら、そういうメソッドを書けば良い。簡単
lib/generators/test/USAGE
中身は以下の通り。
Description: Explain the generator Example: rails generate test Thing This will create: what/will/it/create
ヘルプコマンドの下の方にそのまま使われる
% rails generate test -h Usage: rails generate test NAME [options] Options: [--skip-namespace], [--no-skip-namespace] # Skip namespace (affects only isolated applications) Runtime options: -f, [--force] # Overwrite files that already exist -p, [--pretend], [--no-pretend] # Run but do not make any changes -q, [--quiet], [--no-quiet] # Suppress status output -s, [--skip], [--no-skip] # Skip files that already exist Description: Explain the generator Example: rails generate test Thing This will create: what/will/it/create
lib/generators/test/templates/
ディレクトリ。現在は空。 erb テンプレートファイルを置いておく用のディレクトリ
test/lib/generators/test_generator_test.rb
require 'test_helper' require 'generators/test/test_generator' class TestGeneratorTest < Rails::Generators::TestCase tests TestGenerator destination Rails.root.join('tmp/generators') setup :prepare_destination # test "generator runs without errors" do # assert_nothing_raised do # run_generator ["arguments"] # end # end end
テストの雛形。rspec 使ってれば rspec で出してくれる。
...と思いきや、rspec の場合はスケルトン作成に失敗する。
(失敗の原因を詳しく追ってない。本当は作られるはず... なのかな)
継承クラス
親クラスは若干注意が必要なので、ここでやりたいことに合わせて分岐する
Rails::Generators::NamedBase
default だとこっち。
rails generate
コマンドの引数として、一つ何かを受け取ることが必須のクラス
cf. Rails::Generators::NamedBase
% rails generate controller Users xxxx
のような馴染みのある generator を作りたい場合はこちらで良い。
Rails::Generators::Base
NamedBase とは異なり rails generate
コマンドの引数を自由に定義できるクラス。
Rails::Generators::NamedBase
は Rails::Generators::Base
を継承している。
こちらのほうが柔軟性があるが、特別な用途がない限りは使わなくても良いかと思います。
便利メソッド
generator なので、テンプレートからファイル生成したり、ディレクトリを掘ったりする用途が主である。
rails はすごいから、そういう簡単なものは既にメソッドが用意してある。
これらのメソッドは全て Thor::Actions
に定義されているので、そっちを見たほうがいい。
というのも Rails::Generators::Base
が Thor::Actions
を include しているから。
もっと言うと Rails::Generators::Base
は Thor::Group
を継承して作られているので、rails の generator は大体 thor でできてると言って良い。
したがって困ったときは thor で検索すると良い
以下は便利メソッドの内、いくつかを紹介
create_file
directory
directory を copy する
template
ERB テンプレートを使って、ファイルを生成
具体例
class TestGenerator < Rails::Generators::NamedBase source_root File.expand_path('../templates', __FILE__) def create_empty_file create_file "aaaa.txt" end end
% rails g test arg1
create aaaa.txt
見たことある出力やー
% rails g test arg1
identical Test.txt
もう一回やると、またまた見たことある出力に。
大体こんな感じでノリで generator 作れてしまいます。すごい簡単です。
まとめ
- 継承するクラスによって、generator に渡せる引数が変わる
Rails::Generators::NamedBase
は 1 つの引数を受け取るRails::Generators::Base
は自在に定義可能
rails generator
の内部は殆どthor
- 詰まったら
thor
で調べると良い thor
を一度触ったことがある人は知見を十分に活かせるthor
はとても素直な実装になっているからthor
の spec はとてもわかり易いので、読むだけで理解できる
- 詰まったら
hook_for
は謎が多いので、使う時は若干注意thor
は「トール」と読むらしい