direnvで、使用するdocker-machineを指定する
.env
にこんな風に書けるようにします。
# .env
use docker-machine my-rails-app
ディレクトリに移動すると、自動的にdocker-machineを(まだ起動していないなら)起動し、docker-machine env
で環境変数をセットします。
$ cd ~/Documents/my-project direnv: loading ~/.direnvrc direnv: loading .envrc direnv: using docker-machine my-rails-app Starting "my-rails-app"... Machine "my-rails-app" is already running. direnv: export +DOCKER_CERT_PATH +DOCKER_HOST +DOCKER_MACHINE_NAME +DOCKER_TLS_VERIFY $ docker ps # my-rails-app のコンテナ一覧が表示される
インストール
git clone git@github.com:doloopwhile/direnv_use_docker-machine.git ~/direnv_use_docker-machine echo '. ~/direnv_use_docker-machine/direnv_use_docker-machine.sh' >> ~/.direnvrc
使用目的
docker-machineではdefaultホスト1個しか立ち上げていない人が多いと思います。
docker-composeなどを使えば、コンテナ名が被らないようにできるので、 それで困ってないのかもしれません。
しかし、プロジェクト毎にDockerホストを立ちあげると便利なことも。
- ポート番号がかぶらない(複数のWEBアプリを同時に
docker-compose up
させておける) - ホストごとにDocker Engineの設定を変えられる
docker ps
などのリストがスッキリする- 混乱した時は
docker rm -f $(docker ps -a -q)
してリセットできる。
反面、イメージをホスト毎にインストールする手間などもあります。
Docker開発はまだ試行錯誤が多いのですが、この方法も案外便利かもしれませんよ。
Yggdroot/indentLineのせいでmarkdownの表示がおかしくなった
markdown編集中に"*hogehoge"が"hogehoge"のように変換されて表示されてしまう。この表示の仕方はVimのmarkdownモードの機能の1つで、set conceallevel=2
が設定されているとこう表示する。
問題はset conceallevel=2
などした覚えが無いということで、調べるとどうやら"Yggdroot/indentLine"が内部でset conceallevel=2
をしているようだ。勝手なことをするなよな。
Ruby初心者(つまり昨日の僕)に伝えたいRubyの7つのハマり所
書くのが楽しいプログラミング言語であるRubyですが、それでも「落とし穴」がいくつも存在します。
その中から私が最近ハマった落とし穴を7つ紹介します。
シンボルと文字列は異なる
Rubyには「文字列(String)」("a"
とか 'Hello world!'
)の他に、文字列に似た「シンボル(Symbol)」(:a
とか:hello_world
とか)があります。*1。両者は異なる型なので、例えば 'a' != :a
となります。
そのため、キーがシンボルであるハッシュ(Hash)から、文字列を使って値を取り出そうとするとnil
が返されます。
h = { :ja => '日本語', :en => '英語', :fr => 'フランス語' } p h['ja'] # => nil p h[:ja] # => "日本語"
ちなみに、シンボルはハッシュのキーとしてよく使われるため、=>
を使わない短縮記法があります。
# これは・・・ h = { :ja => '日本語', :en => '英語', :fr => 'フランス語' } # こうも書ける h = { ja: '日本語', en: '英語', fr: 'フランス語' }
シンボルと文字列は異なる
Rubyには文字列(String)の他に、文字列に似たシンボル(Symbol)があります。*2。両者は異なる型なので、例えば 'a' != :a
となります。
ハッシュのキーにはシンボルがよく使われますが、例えばRailsのparams
(HTTPのクエリパラメータ)のキーは文字列です。
したがって、文字列を使ってparams
から値を取り出そうとするとnil
が返されます。
class XYZController def search params[:lang] # => nil end end
なお、Railsはハッシュのキーをシンボルに変換するHash#symbolize_keys
等の一連のメソッドを追加します。
また、JSON.parse
にはJSONのキーをシンボルに変換するsymbolize_names
パラメータがあります。
シンボルと文字列は異なる
Rubyには文字列(String)の他に、文字列に似たシンボル(Symbol)があります。*3。両者は異なる型なので、例えば 'a' != :a
となります。
そのため、シンボルを文字列と連結したり、文字列のメソッドを呼びだそうとするとエラーになります。
a = 'hello' b = :world a + b # => TypeError: no implicit conversion of Symbol into String b.tr 'o', 'x' # => NoMethodError: undefined method `tr' for :world:Symbol
このような時は.to_s
や.to_sym
で、文字列とシンボルを相互に変換します。
また、文字列連結の代わりに式展開を使うこともできます。 式展開はシンボルだけでなく数値や他の型つかえますし、文字列連結を使うよりも可読性が高くなります。 そのため、Rubyでは文字列連結を使う機会はあまり多くありません。
# これよりも a + ' ' + b # こうするべき "#{a} #{b}"
シンボルと文字列は異なる
Rubyには文字列(String)の他に、文字列に似たシンボル(Symbol)が・・・すみません、これで最後にします。
method_missingの引数はシンボルです。実際のところ、シンボルに文字列操作を施す機会はメタプログラミング以外はあまりありません。
なので、method_missingでこんなコードを書くとエラーになります。
def method_missing(name, *args) # エラーになるコード if name.end_with?('!') # ... end super(name, *args) end
privateメソッドをクラス外から呼び出すとmethod_missingが呼ばれる
黒魔術だなんだと言われつつ使わざるをえないmethod_missing
について。実はmethod_missing
が呼ばれるのはメソッドが無い場合だけではないとことです。
呼ぼうとしたメソッドがprotected
やprivate
であった場合もmethod_missing
は呼ばれます。
class Foo def method_missing(name) p name end private def greeting p 'hello' end end foo = Foo.new foo.greeting # => :greeting
だから、method_missing
は黒魔術なのであって、method_missing
なんて使うのは止めましょう。
Module#define_method が作るメソッドはpublicになるとは限らない
黒魔術でもうひとつ。メソッドを動的に定義するdefine_method
は、private
の後ではprivateなメソッドを定義します。
class FooController def index # 普通のメソッド end private # あとから foo_params を追加! def foo_params #... end %w(name email age).each do |name| define_method "show_#{name}".to_sym do # ... end end
なので、「ゴチャゴチャした処理は後ろに書こう」とクラスの後ろでdefine_method
を書いていて、
途中にprivateなメソッドを追加したりすると、思わぬ動作になります。
ちなみに「private
の後ではprivateになる」のはattr_reader
なども同様です。
Structはキーワード引数を取らない
最後に、真面目に罠だと思うことを。
たまに便利なStruct
は、実はコンストラクタにキーワード引数を使えないことです。
間違ってキーワード引数を使うと、それらは1個のハッシュを渡したかのように扱われます。
Dog = Struct.new(:name, :age) # => Struct::Dog # キーワード引数は使えない Dog.new(name: 'ポチ', age: 1) # => #<struct Struct::Dog name={:name=>"ポチ", :age=>1}, age=nil> # ハッシュを渡したかのように扱われる。 Dog.new({name: 'ポチ', age: 1}) # => #<struct Struct::Dog name={:name=>"ポチ", :age=>1}, age=nil> # なのでStructでは通常の呼び出しをするしかない Dog.new('ポチ', 1) # => #<struct Struct::Dog name="ポチ", age=1>
正直な所、これは仕様のバグだと思います。後方互換性が失われるので直しにくいと思いますが。
*1:文字列とは別にシンボルがある理由として、シンボルは内部的に整数として扱われるため文字列よりも速度的に有利なことが挙げられることがあります。「性能を目指して実装してない」くせに何言ってやがる、と思わなくもありません。とにかくRubyにはシンボルがあります。
*2:文字列とは別にシンボルがある理由として、シンボルは内部的に整数として扱われるため文字列よりも速度的に有利なことが挙げられることがあります。「性能を目指して実装してない」くせに何言ってやがる、と思わなくもありません。とにかくRubyにはシンボルがあります。
*3:文字列とは別にシンボルがある理由として、シンボルは内部的に整数として扱われるため文字列よりも速度的に有利なことが挙げられることがあります。「性能を目指して実装してない」くせに何言ってやがる、と思わなくもありません。とにかくRubyにはシンボルがあります。
rbenv環境で特定バージョンのコマンドを実行する(特にrubocop)
RBENV_VERSION
環境変数を指定すればいい。
#!/bin/bash RBENV_VERSION=2.2.3 rbenv exec rubocop "$@"
背景
イマドキ、プロジェクトで使うRubyのバージョンを.ruby-version
やGemfile
で指定していない人はいないと思いますが、その時困るのはgem install hoge
して使うRuby製のツール。
ツールは新しいRuby 2.2.xにインストールしたが、プロジェクトでは2.0.xを使っている、といった場合、rbenv は冷徹にエラーを出力します。
rbenv: rubocop: command not found The `rubocop' command exists in these Ruby versions: 2.2.2 2.2.3
そういった場合、最初の例のような内容のラッパースクリプトを書けばよござんす。
(どうでもいいが「書けばよい」を丁寧語でどう言えばいいのだろう)
Ruby初心者と忘れっぽい僕のための10の必須リンク先
部分集合が含まれているのは仕様です。
1. リファレンスマニュアル
寝るときに枕の下に敷くこと。 なお、リファレンスマニュアルは各バージョンごとにあるので、最新版(今は2.2.0)を見ましょう。
オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル (Ruby 2.2.0)
2. リファレンスマニュアル - 組み込みライブラリと標準ライブラリ
ostructに(;´Д`)ハァハァしましょう。
3. リファレンスマニュアル - 基本コレクション
Enumerable#each_cons かわいいよ、 Enumerable#each_sliceも。
- module Enumerable (Ruby 2.2.0)
- class Hash (Ruby 2.2.0)
- class Array (Ruby 2.2.0)
- class String (Ruby 2.2.0)
4. リファレンスマニュアル - %記法
しれっと、%i
なんかが追加されてたりするからタマラナイ。
5. ワンライナー向けオプションまとめ
{sed,awk,grep,perl,...}が許されるのは(ry maeharin.hatenablog.com
6. Railsが拡張したObjectのAPI
ライスとカレーライスの区別は重要です。 http://api.rubyonrails.org/classes/Object.htmlapi.rubyonrails.org
7. Rake
コンパイルとかバックアップはRakefileにしとくと便利。
なお、一番大事なことはページの最後に書いてある。
8. 必須開発ツール
迷ったらgem install pry rubocop
迷う前にgem install pry rubocop
9. 「関数型Ruby」という病
処女地じゃない。雑草が再び生い茂ったというだけだ。 yuroyoro.hatenablog.com
&:symbol
は好き。
10. Rubyから外部プログラムを起動
このブログの記事。大したことない記事だと思うのですが、なぜかアクセスが多いので、書いておきます。 doloopwhile.hatenablog.com
Goライブラリもウルトラ簡単に作れる!
RubyGemはめっちゃ簡単に作れる! - 酒と泪とRubyとRailsとでRubyライブラリの公開方法が紹介されていました。
Goライブラリも知らないとハードル高そうに見えますが、実はかなり簡単につくれます。 これから積極的にGoライブラリを作ってOSSの世界に貢献していきたいので簡単な作り方をまとめました。
1. ファイルを用意する
今回はテスト的にHello World!と出力するようにします。hello.goを以下のように作成します。
package hello func Greet() { println("Hello World!")}
2. 公開する
# gitのリモートリポジトリを設定 git remote add origin git@github.com:doloopwhile/hello.git # add & commit & push git add . -A && git commit -m 'first commit' && git push
ライブラリはgo get github.com/doloopwhile/hello
でダウンロードできるようになります。