boolean_accessorというGemを書いてRubyGems.orgに公開した

boolean_accessor

たとえば、

class Item
  attr_reader :active

  def initialize
    @active = true
  end
end

のような場合、

item = Item.new
item.active  # => true

となりますが、activeという属性がbooleanだということをもっとわかりやすくしたいところです。

かといって、is_activeという名前にするのもrubyっぽくなくてイマイチ。 ここは、

item.active?  # => NoMethodError: undefined method `active?'...

で、trueが返ってきてほしいところです。

alias_method :active?, :active

とすれば、item.active?とできるようになりますが、複数属性がある場合にひとつひとつ書くのは面倒ですし、booleanの属性にこういった動作をしてほしい場合は多々あるので、gemにしてみました。

boolean_accessor

使い方はREADME.mdに書いてある通りですが、今回の例であれば、

class Item
  battr_reader :active

  def initialize
    @active = true
  end
end

item = Item.new
item.active?  # => true

のようになります。

RubyGems.orgへの公開

今回はじめてrubygems.orgに公開してみましたので、手順を書いておきます。
gemを作るのはbundlerを使うと簡単です。

bundle gem boolean_accessor

以下のようなファイルが作成され、gitの準備もしてくれます。

      create  boolean_accessor/Gemfile
      create  boolean_accessor/Rakefile
      create  boolean_accessor/LICENSE.txt
      create  boolean_accessor/README.md
      create  boolean_accessor/.gitignore
      create  boolean_accessor/boolean_accessor.gemspec
      create  boolean_accessor/lib/boolean_accessor.rb
      create  boolean_accessor/lib/boolean_accessor/version.rb
Initializating git repo in /path/to/dir/boolean_accessor

libの中に実際のコードを書いていくわけですが、今回はとても小さなgemなので、テスト以外のコードとしては、

boolean_accessor/lib/boolean_accessor.rb

書いただけです。

動作を確認する場合は、作成されたディレクトリに移動(cd boolean_accessor)した上で、

bundle console

とすれば、gemの内容が読み込まれ、コンソール上で動作が確認できます。

あとは boolean_accessor.gemspec のTODOや必要事項を埋めたり、README.mdなどを編集すれば、今回は完成です。

gemspecは必ず確認するので問題ないと思いますが、LICENSE.txtにも自動で名前が入っているので、必要があれば修正します。(最初は~/.gitconfigのuser nameが入るみたいです。)

公開するgemなのでテストも書いておきます。specディレクトリを作成し、RSpecで書きました。

公開する前に、まずローカルでgemをbuildし、インストールしてみます。
rake -T でrakeタスク一覧を見ることができます。
rake installをすればインストールできるはずですが、権限の関係かうまくいかなかったので、

rake build

でgemを作成し、作成されたgemを、

sudo gem install pkg/boolean_accessor-0.0.1.gem

でインストールしました。

RubyGems.orgへの公開は、まずサイトにサインアップしておいた上で、

git push pkg/boolean_accessor-0.0.1.gem

のようにして、聞かれるEmailやPasswordを入力すれば、公開できました。

一度リリースすると、~/.gem/credentialsファイルが生成されるようで、これが作成されると今後はrake -Tで一覧表示されたrake releaseでリリースできるようになるのだと思います。

参考

Basic RubyGem Development - Tech.Pro
はじめてbundlerでruby gem作ってgithubとrubygemsに上げてみた - shoprevのブログ
Ruby: Boolean attribute naming convention and use - Stack Overflow

Solr 4用のMuninプラグインを書いた

Solr 3までは solrmulticore というプラグインを使っていたのですが、Solr 4.0以降動かなくなっていたので、Muninプラグインの書き方を調べて自分で書いてみました。

munin-solr4-multicore

Rubyで書いたのですが、書き方自体は別エントリで書くことにして、このプラグインの使い方を書いておきます。

インストール

cd /usr/share/munin/plugins/
sudo wget https://raw.github.com/hiroki23/munin-solr4-multicore/master/solr4_multicore_
sudo chmod 755 solr4_multicore_

先頭のrubyパス (#!/usr/local/bin/ruby) は、環境に合わせて修正してください。

sudo vi solr4_multicore_

Rubyのパスは、which rubyで確認できますね。)

シンボリックリンクを作成します。

sudo ln -s /usr/share/munin/plugins/solr4_multicore_ /etc/munin/plugins/solr4_multicore_999thPcRequestTime

munin-nodeをrestartします。

sudo /etc/init.d/munin-node restart

この例では、99.9%番目のリクエスト時間のグラフが生成されます。

取得できる値

同じようにシンボリックリンクを作ることで、以下のような値が取れます。

  • avgRequestsPerSecond
  • 5minRateReqsPerSecond
  • 15minRateReqsPerSecond
  • avgTimePerRequest
  • medianRequestTime
  • 75thPcRequestTime
  • 95thPcRequestTime
  • 99thPcRequestTime
  • 999thPcRequestTime
  • errors
  • timeouts

など。

sudo ln -s /usr/share/munin/plugins/solr4_multicore_ /etc/munin/plugins/solr4_multicore_{取りたい値}

Solr4.1までは、req/sec、time/reqは、avgRequestsPerSecondやavgTimePerRequestしか取れなかったのですが、Solr4.2以降は5分ごと、15分ごとのreq/sec、平均time/req、75%、95%、99%、99.9%番目のtime/reqが取得できるようになって、ますます便利になりました。

同様にシンボリックリンクを作成することで、以下のキャッシュのキャッシュヒット率も取ることができます。

  • queryResultCache
  • documentCache
  • fieldValueCache
  • filterCache

画面キャプチャ

設定がうまくいけば、以下のようなグラフが生成されます。

5minRateReqsPerSecond
f:id:hiroki23:20130529003800p:plain

99thPcRequestTime
f:id:hiroki23:20130529003803p:plain

documentCache
f:id:hiroki23:20130529004321p:plain

RSpecをpryで試す

RSpecではいつの間にかshouldではなくexpectが推奨されるようになっていました。

やはり実際に手を動かして覚えたいので、公式ページを見ながら pry(またはirb)で試してみます。
rspec-expectations

rspecをインストール

sudo gem install rspec

pry起動

pry

こんなふうに試せます。

require 'rspec' 
# => true

include RSpec::Matchers
# => Object

expect(1).to eq(1) 
# => true
expect(1).to be > 2
# => エラー

shouldのほうが書きやすいと思っていましたが、書いてみると意外と悪くない感じ。

エラーの検証は、

expect{ raise }.to raise_error
# => true

範囲系は以下のような感じで書けます。
(ただし、includeはモジュールの読み込みと重なってしまうので単純には書けません。)

expect([1,2,3]).to start_with(1)
expect([1,2,3]).to start_with(1,2)
expect([1,2,3]).to end_with(3)
expect([1,2,3]).to end_with(2,3)
expect("this string").to start_with("this")
expect("this string").to end_with("ring")
# => すべてtrue