猫と一緒にガジェットライフ♪ムチャ(@mutoj_rdm821)です。
今回は、Rubyで開発をしていてはまった小ネタをご紹介します。お役に立てば幸いです。
erbを使ってerb形式のファイルを出力する
Rubyに標準添付されているテンプレートライブラリとしてERBという物があります。詳しい紹介は以下のページにあります。
→Rubyist Magazine - 標準添付ライブラリ紹介 【第 10 回】 ERB
簡単に説明すると、<%~%>で囲まれた部分にRubyスクリプトを記述したテンプレートに対して、ちょっとしたおまじないを書いてやると動的に文字列を埋め込んだりした結果が得られます。
require 'erb' str = "hoge" erb = ERB.new("value = <%= str %>") puts erb.result(binding)
出力結果
value = hoge
あまり使用する局面はないかもしれませんが、ERBを使ってerbファイルを出力したいという状況がありました。出力結果に<%~%>といったerbの埋め込み構文を残さないといけません。
どうすれば良いかというと、%を2つ並べて書きます。
year = 2014 owner = "Junichi Muto" # テンプレートは以下のような感じ "<%%# Copyright <%= year %> <%= owner %> %>"
こうすると、結果は以下のようになります。
<%# Copyright 2014 Jnichi Muto %>
文字列に文字を追加していく
文字列を結合するには+でできますが、追加していく場合は以下のようにも書けます。但し最初の変数には初期値が必要です(nilだとダメ)
content = "abc" content << "def"
ランダムな文字列を生成する
例えば数値と英字小文字大文字による長さ5のランダムな文字列が欲しい場合は以下で得られます。
((0..9).to_a + ("a".."z").to_a + ("A".."Z").to_a).sample(5).join
シンボルで"-"を使いたい
RubyにはSymboleというクラスがあり、文字列の前に:(コロン)を付けて表します。シンボルで表した文字列は唯一のオブジェクトなり、必ず同じものを指します。ここがJavaとちょっと違う所。
ハッシュを定義するときには、通常「キー => 値」の形式で書きますが、ハッシュのキーにシンボルを使う場合は「シンボル: 値」という書き方ができます(Ruby1.9から)。
シンボルで"-"を使いたいとき、そのままだとエラーになってしまいますが、ダブルクォートでくくってやれば大丈夫です。しかし、このとき「シンボル: 値」の記述は使えません。
# シンボル :test # ハイフンを入れたシンボル :"test-hyphen" # ハッシュの定義 { :a => "A", :b => "B", :c => "C" } { a:"A", b:"B", c:"C" } #シンボルの場合 # 以下はエラー #{ "test-hyphen": "value" } # 従来の記述法ならOK { :"test-hyphen" => "value" }
JSON#parseでキーをシンボルにしたい
JSON#parseはJSON文字列からHashを生成するメソッドです。普通に変換するとHashのキーは文字列となりますが、RubyでHash生成する場合はキーをシンボルにすることが多いと思います。
これらをマージすると文字列とシンボルは別の扱いになってしまうので結果がおかしな事になったりします。(さらにJSON#generateで戻すと、シンボルも文字列の扱いになってしまい、同じ文字列だと片方が上書きされたりします。)
JSON#parseでキーをシンボルにしたい場合、第2引数でsymbolize_names: trueを渡してやります。
result = JSON.parse(json_str, symbolize_names: true)
Rails・マルチスレッド環境で「RuntimeError: Circular dependency detected while autoloading constant xxxx」が発生する
がらっと変わりますが(;´∀`)
Railsにはオートロードという機能があります。以下のようにソースコードがあるディレクトリを予め登録しておくと、個々のソースコードでrequireをしなくても、初めて発見したクラスをディレクトリから探して自動的に読み込んでくれます。
require 'active_support/dependencies.rb' ActiveSupport::Dependencies.autoload_paths << 'src'
しかし、マルチスレッド環境で問題が起こることがありました。
通常、この機能で一度読み込んだコードはキャッシュされるので再び読むことはありません。しかし、2つのスレッドが同時に知らないクラスを発見した場合、タイミングによっては読み込み済みかのチェックを通過してしまい、片方のスレッドは読み込みに成功するのですが、もう片方のスレッドでは「既に読み込んでいる!」となって上記エラーが発生します。
複数のクラスから使われるヘルパーのようなクラスは、オートロードから除外して予めロードしてしまうと解決します。対象のソースコードは別ディレクトリに移してautoload_pathsから外し、以下のようにしてロードしてしまいます。
ActiveSupport::Dependencies.require_or_load(file)
タイミングによっては起こらないので、原因を探るのが大変でした(;´∀`)
オートロードを使っている時にGuardでテストしていると、ソースコードの保存を検知してくれない
rspecを使ってテストする際にGuardというツールでテストを行っていました。これはコードを保存するとそれを検知して該当するspecファイルのテストコードを実行してくれるのですが、あるとき(バージョンが変わったせいか)この検知が働かなくなりました。
Guardfileで以下のようにするとうまくいきました。上記のオートロードがいけなかったようです。
Spork.each_run do ActiveSupport::Dependencies.clear end
まとめ
初心者ながらいろいろ苦労して解決した問題です。同じように困っている方のお役に立てれば幸いです。
それではみなさま良きガジェットライフを(´∀`)ノ