本ブログではアイフィリエイトによる収益を得ています。

[Ruby]ちょっとはまった小ネタ

2014年4月17日木曜日

Ruby 開発

t f B! P L C

2013-10-21 20.28.59

猫と一緒にガジェットライフ♪ムチャ(@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


まとめ

初心者ながらいろいろ苦労して解決した問題です。同じように困っている方のお役に立てれば幸いです。

それではみなさま良きガジェットライフを(´∀`)ノ



▼ブログを気に入っていただけたらRSS登録をお願いします!
▼ブログランキング参加中!応援よろしくお願いします。

ブログ内検索

自己紹介

猫とガジェットが好きなJava屋さんです。うつ病で休職後退職し、1年半の休養後に社会復帰。・・・が、いろいろあって再び退職。さらに1年休職の後に復帰して、なんとかSE続けてます。茶トラのすずと一緒に生活していましたが、2014年9月4日に亡くなって1人に。

より詳細なプロフィールはこちら↓

↓更新情報を受け取るにはフォローをお願いします!

Instagramでフォロー

※ヘッダー及びアイコンで使用しているドロイド君は、googleが作成、提供しているコンテンツをベースに複製したものです。

▼ココナラでメンターサービスを販売しています。招待コード「C3VG3」で1000ポイントもらえます。
▼欲しい物リスト

ブログ アーカイブ

QooQ