-
Rubyの名前空間に苦しむ。そしてちょっと勉強。 2007-10-20 00:00:00
作ったあるメソッドを使うとき、 attr_accessor みたいな書き方をしたかったのだけど、Rubyの名前空間にちょっとハマってしまった。復習しておこうっと。
それはともかく、attr_accessor はどうやって定義されているのかと思ってちょっと調べてみると、Moduleクラスのプライベートインスタンスメソッドとして定義されていた。ClassクラスはModuleクラスのサブクラスだからか。なので、同じようにやってみる。
test.rbclass Module private def set_special_url(args) define_method :special_url do args end end endとして、こいつをrequireしてやると
#!/usr/bin/ruby require 'test' class Lesson set_special_url :controller => 'test', :action => 'login' def index puts special_url[:controller] puts special_url[:action] end end Lesson.new.index実行結果は、
test login
となった。なるほど。
次にRailsでやってみる。
ジャンプ先のURLを一度設定しておけば、どこでもそれが使えるという機能と、ステートを保持するセッションを持ち、それをインスタンス変数としてアクセスできる機能を持つpluginを作ってみる。module Spoon private def say @word ||= session[:word] || "I'm thinking nothing" end def mind=(word) session[:word] = word @word = word end def thinking(word) self.mind = word end class ::Module private def set_jump_url(args) define_method :jump_url do args end end end endこんな感じ。
Moduleクラスをオーバライドしているのは前述のとおり。::をModuleの頭につけてあげないと、Spoon::Moduleクラスの定義になってしまうので注意。
sayメソッドとmindメソッドは、それぞれ@wordへのアクセサになっている。sessionを使っているのは、アクセスされるたびにインスタンスが生成されるので、@workがそのたびに異なるものになってしまうため。だったらセッションだけでもいい気もするけど、こっちのほうがシンプルだと思う。
thinkingメソッドは、mindメソッドを確実に呼ぶために定義した。selfレシーバをつけてあげないと、mindがメソッドなのかローカル変数なのか、区別がつきにくい(というかコントローラのアクションの中ではローカル変数と判断される)のだ。このあたりは、acts_as_authenticatedをもろに参考にしました。
で、ApplicationControllerでは
class ApplicationController < ActionController::Base include Spoon set_jump_url :controller => 'test', :action => 'index' end
こうしてやる。これで、どのコントローラでも、redirect_to jump_url みたいな感じで、設定したジャンプ先のURLが使えるようになる。
それからふたつのコントローラをclass TestController < ApplicationController def index render :text => say end def set_mind thinking "I'm hungry..." redirect_to jump_url end endclass KaeruController < ApplicationController def index redirect_to jump_url end endこんな感じで定義する。
もしjump_urlをtestコントローラだけで使いたいときは、set_jump_urlをtestコントローラだけで使えばいい。そうすれば、kaeruコントローラではjump_urlが使えない(未定義でエラーになる)。

コメント(
リンク元(203)