Tag Archives: Rails

.irbrcでirbを便利に

~/.irbrcに、irbを起動したときに読み込むスクリプトを記述できる。さらにこの設定はRailsのscript/consoleでも有効になる。詳しくはirbとscript/consoleの超便利なTipsなどを参照。

というわけで、自分の今の設定をメモしておく。

require 'rubygems'
require 'wirble'
require 'pp'

Wirble.init
Wirble.colorize

# Log to STDOUT if in Rails
if ENV.include?('RAILS_ENV') && !Object.const_defined?('RAILS_DEFAULT_LOGGER')
 require 'logger'
 RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
end

モジュールの特異メソッドをincludeして使えるようにする

次のようなFooモジュールの特異メソッドbarをBazモジュールに特異メソッドとして使えるようにしたい場合、BazでFooをincludeするだけでは不十分。これは、includeによって追加されるのが、Fooのインスタンスメソッドのみだから。

module Foo
  def bar
    puts "bar"
  end
end

module Baz
  include Foo
end

なので、次のように細工をしてやる。

module Foo
  # Module#extendのためにインスタンスメソッドにする
  def bar
    puts "bar"
  end

  # self(この場合はFoo)が他のモジュール(仮引数mod == Baz)にincludeされた際に呼ばれる
  def self.included(mod)
    # modにself(この場合はFoo)のインスタンスメソッドを特異メソッドとして追加する。
    # mod == Bazだから、つまりBazにクラスメソッドを追加することになる
    mod.extend self
  end
end

module Baz
  include Foo
end

このように、Module.includedというフックメソッドを用いて、includeされた際にModule.extendでインスタンスメソッドを特異メソッドとして追加してやればよい。

このようなやり方は、ActiveRecord::Validations::ClassMethodsをActiveRecord::Baseから利用できるようにする際などに利用されている。

追記1 2009-10-17

上記の方法だと、Baz#bar(Bazのインスタンスメソッド)とBaz.bar(クラスメソッド)の両方が定義される。Bazをモジュールではなくクラスとして作成した場合には注意が必要となる。

一応、以下のようにすることでBaz#barを未定義にできる。

module Baz
  include Foo
  # Fooのメソッドを直接指定して未定義とする
  # 直接指定なあたりがちょっとかっこわるい
  undef_method :bar

  # 当然ながら(?)このあとにbarを再定義すれば、そちらが利用される
  # まぁ再定義するぐらいならundef_methodの必要がない気もするけど。
  def bar
    puts "hello"
  end

undef_methodだとスーパークラスでの定義さえもみなくなってしまうので、できればremove_methodがいいんだけど、それだとBaz#barが定義されていないというエラーが出た。

追記2 2009-10-18

先のBaz#barとBaz.barについて、includeしたせいで両方定義されてしまうというのは、extendだけ行えば済むことかとやっと気づいた。つまり、

module Foo
  def bar
    puts "bar"
  end
end

module Baz
  extend Foo
end

ActiveRecord::ValidationsだけでなくActiveRecord::Validations::ClassMethodがあるのは、includeとextendで別個に分けるためだったのか…。

追記3

恐ろしく分かりにくい記事なので、書き直した

参考資料


named_scopeの引数による条件分岐

named_scopeに引数を渡した場合、その型によって設定するSQLを動的に変更したいことがある。 こういうときにはlambdaに渡しているのブロック中で条件分岐すれば良い。


named_scope :member, lambda { |m|
  case m
  when Member
    { :conditions => { :member_id => m.id } }
  when Integer
    { :conditions => { :member_id => m } }
  else
    {}
  end
}

要するに、lambdaに渡したブロックの処理の結果、findに渡すHashパラメータが返ればそれでok、という感じなんじゃないかと。


install rspec

いつも忘れるのでメモ:

$ ruby script/plugin install git://github.com/dchelimsky/rspec.git -r 'refs/tags/1.2.8'
$ ruby script/plugin install git://github.com/dchelimsky/rspec-rails.git -r 'refs/tags/1.2.7.1'
$ ruby script/generate rspec

追記

environment.rbでconfig.gemを設定してrake gems:installのが確実か。


config.gem "rspec", :lib => false, :version => "1.2.7"
config.gem "rspec-rails", :lib => false, :version => "1.2.7.1"

Growlでautospecの結果を表示

Growlの準備

  • Growlをインストール
  • インストーラと一緒に入っているExtra/growlnotify/install.shを実行する
  • autotest + growl で楽々テストを参考に、Growlが「受信される通知を聞く」、「リモートアプリケーション登録を許可」するように環境設定パネルから設定する。

gem類の準備

バージョンも併記した。

まずはgemの準備。

$sudo gem install ZenTest # 4.1.1
$sudo gem install redgreen # 1.2.2, autospecの結果をコンソールで赤と緑で塗り分けてくれる。Growlだけなら不要
$sudo gem install ruby-growl # 1.0.1

RSpecとRSpec on Railsのインストール。

ruby script/plugin install git://github.com/dchelimsky/rspec.git -r 'refs/tags/1.2.7' # 1.2.7
ruby script/plugin install git://github.com/dchelimsky/rspec-rails.git -r 'refs/tags/1.2.7.1' # 1.2.7.1
ruby script/generate rspec

画像を拝借

cd ~
curl http://blog.internautdesign.com/files/rails_fail.png > .rails_fail.png
curl http://blog.internautdesign.com/files/rails_ok.png > .rails_ok.png

moroさんが勉強会で使ってたチェックとバツマークのが欲しいんだけど、どこにあるんだろう?

~/.autotestの編集

ZenTestをインストールしたときについてくる設定ファイルのひな形をコピー。 x.x.xはインストールしたZenTestのバージョンで、ここでは4.1.1。

$ cp /Library/Ruby/Gems/1.8/gems/ZenTest-x.x.x/example_dot_autotest.rb ~/.autotest
$ chmod 644 ~/.autotest

以下のように設定する


# -*- ruby -*-

# require 'autotest/autoupdate'
# require 'autotest/once'
# require 'autotest/rcov'
# require 'autotest/restart'
# require 'autotest/timestamp'

# Autotest::AutoUpdate.sleep_time = o
# Autotest::AutoUpdate.update_cmd = o
# Autotest::RCov.command = o
# Autotest::RCov.pattern = o

ok_img = "~/.rails_ok.png"
ng_img = "~/.rails_fail.png"

module Autotest::Growl
  def self.growl title, msg, img=ok_image, pri=0, sticky=""
    msg += " at #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
    # autotestは使わないので、-nで指定するアプリケーション名はautospecで良いと思う
    # -Hで通知先のGrowlのあるホスト名を指定する
    system "growlnotify -n autospec -H localhost --image #{img} -p #{pri} -m #{msg.inspect} #{title} #{sticky}"
  end

  Autotest.add_hook :ran_command do |at|
    results = at.results.last
    examples = results[/(\d+)\s+examples?/].to_i  # テストの総数
    failures = results[/(\d+)\s+failures?/].to_i  # 失敗の数
    errors = results[/(\d+)\s+errors?/].to_i # エラーの数
    if examples >= 0
      if failures > 0 || errors > 0
        growl "Tests Failed", "#{examples} examples, #{failures} failures, and #{errors} errors", ng_img, 2
      else
        growl "Tests Passed", "#{examples} examples, #{failures} failures, and #{errors} errors", ok_img, -2
      end
    else
      growl "Tests Errored", "errors", ng_img, 2
    end
  end
end

実行

$ cd RAILS_ROOT
$ autospec

備考

いくつかサイトを巡って試行錯誤を繰り返したけど、とりあえず以上の作業のみで動作している。結構古い情報もあるみたいだし、autotestとautospecでは~/.autotestでテストの結果を拾う処理に差異があるのでご注意を。

ところでgrowlnotifyでは-Hオプションで通知先のGrowlのホスト名を指定しているけど、うまくやれば,別サーバ上で作業しているときのテスト結果をローカルのGrowlに通知なんてこともできるのかな?ちょっと余裕があるときにでも試してみたい。

参考サイト

変更履歴

2009-08-19

  • 30行目の行末からカンマ(,)を削除。
  • RSpec/Rspec on Railsのインストール時にバージョン指定を追記(これがないとtrunkをインストールしてしまう)。

2010-02-13

  • 成功.失敗時の画像ファイル名を変数で指定するように修正

rake db:createでキャラクタセット関連っぽいエラー

MacPortsでインストールしたMySQL5を使用。

rake db:createで次のようなエラーが出た。

Couldn’t create database for {“reconnect”=>false, “encoding”=>”utf8″, “username”=>***, “adapter”=>”mysql”, “database”=>”TestApp_development”, “host”=>”localhost”, “pool”=>5, “password”=>***, “socket”=>”/opt/local/var/run/mysql5/mysqld.sock”}, charset: utf8, collation: utf8_general_ci (if you set the charset manually, make sure you have a matching collation)

stick stackの記事BACCASS Labsの記事を参考に、/etc/my.cnfを作成してデフォルトの文字セットを設定:

sudo cp /opt/local/share/mysql5/mysql/my-medium.cnf /etc/my.cnf
sudo mate /etc/my.cnf
[client]
default-character-set = utf8

[mysqld]
default-character-set = utf8
collation-server=utf8_general_ci
character-set-server=utf8

[mysqldump]
default-character-set = utf8

[mysql]
default-character-set = utf8

追記 @ 6/15

上を実行してもrake db:createに失敗してた。というかそもそもmysqldが走ってなかった!かといってsudo launchctl start org.macports.mysql5を実行しても、”なにそれ?”的なエラーが返ってきた。

仕方が無いので、MySQLを再インストール:

$ sudo port uninstall -f mysql5
$ sudo port clean mysql5
$ sudo port install mysql5 +server
$ sudo launchctl load -w /Library/LaunchDaemons/org.macports.mysql5.plist
$ sudo -u mysql mysql_install_db5
$ sudo launchctl start org.macports.mysql5 

ps ax | grep myしてみると、どうやらプロセスは走ってるみたい。でもrake db:createには同様のエラー。

やんばるくいなの記事を参考に、上記のものに加えてmy.cnfにさらに次を追加:

[mysqld]
skip-character-set-client-handshake
init-connect = SET NAMES utf8

そしてmysqldを再起動:

$ sudo launchctl stop org.macports.mysql5
$ sudo launchctl start org.macports.mysql5

これでやっとrake db:createに成功!

ついでにエンジンをInnoDBに変更した:

[mysqld]
default-storage-engine = InnoDB
#そしてinno_から始まる行をuncomment