2015年01月

Gemfile を編集せずに任意の gem を追加して開発する方法 - Gemfile.local

以前、Gemfile を編集せずに任意の gem を追加していじる2つの方法について書いたがその3つ目。

Gemfile.local メソッドと呼ぶ(ことにする)

Gemfile に以下のようなコードを追加する。

local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
if File.exist?(local_gemfile)
  puts "Loading Gemfile.local ..." if $DEBUG # `ruby -d` or `bundle -v`
  instance_eval File.read(local_gemfile)
end

.gitignore に Gemfile.local を追加してコミットされないようにする。これだけ。

Gemfile.local


あとは Gemfile.local に好きな gem を追加して開発することができるようになる。例えばこんなん。

# Gemfile.local
gem 'byebug'


プロダクトがこの仕組みをサポートしていないと使えないので、導入の敷居は高い。
実際にやっているプロダクトには tDiary とか redmine とかがある。

Fluentd にも取り入れた → Support Gemfile.local by sonots Pull Request #538 fluent/fluentd

[Ruby] Exception の error_message は触れない

ruby の Exception クラスでは、コンストラクタにメッセージを渡すことができる。

e = Exception.new('foo')
puts e.to_s # foo
puts e.message # foo

このメッセージを #instance_variable_get で取得しようとしたのだが取れない。#instance_variables で空配列が返って来る.

e.instance_variables #=> []

C の実装を見てみると、どうやらこれは、rb_iv_set の使い方によるもののようだ。

[1] pry(main)> show-source StandardError#initialize

From: error.c (C Method):
Owner: Exception
Visibility: private
Number of lines: 11

static VALUE
exc_initialize(int argc, VALUE *argv, VALUE exc)
{
    VALUE arg;

    rb_scan_args(argc, argv, "01", &arg);
    rb_iv_set(exc, "mesg", arg);
    rb_iv_set(exc, "bt", Qnil);

    return exc;
}

rb_iv_set(exc, "@mesg", arg); ではなく、rb_iv_set(exc, "mesg", arg); になっている。@がないと Ruby からは触れない。残念。

ちなみになぜ、エラーメッセージに触りたかったのかというと、子クラスで Exception#to_s メソッドをオーバーライドしたかったからである。

[3] pry(main)> show-source StandardError#to_s

From: error.c (C Method):
Owner: Exception
Visibility: public
Number of lines: 8

static VALUE
exc_to_s(VALUE exc)
{
    VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));

    if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc));
    return rb_String(mesg);
}

これを少しカスタマイズした以下のような関数を定義したかったのだが、無理でした.という話。Berkshelf に投げたこの pull request に関連する。

def to_s
  if @message
    @message
  else
    "Awesome Error Message"
  end
end

FYI: なお、CRuby のコードは pry-doc gem を入れて追った。

A Ruby and Fluentd committer working at DeNA. 記事本文および記事中のコード片は引用および特記あるものを除いてすべて修正BSDライセンスとします。 #ruby #fluentd #growthforecast #haikanko #yohoushi #specinfra #serverspec #focuslight
はてぶ人気エントリー