[ruby-list:50069] Re: メソッドが無い「ふり」をする方法
From:
whiteleaf <2nd.leaf@...>
Date:
2015-01-21 12:57:37 UTC
List:
ruby-list #50069
やられたいこととは違うかもしれませんが。
module M
refine String do
def to_html
"call #to_html"
end
end
end
def with_to_html
yield
end
using M
with_to_html do
p "hoge".to_html
end
# => call #to_html
require_relative "tt" # 他の場所でも with_to_html を使おうとすると undefined method
`#to_html`
refine 使えば using を使ったところでのみ String の拡張を制限出来ますね。
2015年1月21日 21:02 KISHIMOTO, Makoto <ksmakoto@dd.iij4u.or.jp>:
> きしもとです
>
> 内部(埋め込み)DSLなどで、Stringなど組込みクラスにモンキーパッチ的な
> ことをしたいが、他の部分に影響を与えたくない、とします。
>
> ブロックを使って yield の前後でメソッド定義を追加したり削除したりして、
> 以下のように書けると思うわけですが、目的のコンテキスト以外の場合を
> スルーするために、カレントスレッドオブジェクトを使ってチェックする
> ことにしました。
> # この方法についての議論もありそうですが、ここでの本題ではありません。
>
> 本題ですが、こういった場合に、メソッドが無い「ふり」をする方法の
> ベストプラクティスとしては、このように method_missing を呼ぶ、
> という方法で良いでしょうか。もっと良い方法があるでしょうか? と
> いうのが質問です。
>
> def with_to_yaml
> cur_th = Thread.current
>
> String.__send__(:define_method, :to_yaml){
> unless Thread.current.equal? cur_th then
> method_missing :to_yaml
> end
>
> return self
> }
>
> yield
>
> String.__send__(:remove_method, :to_yaml)
> end
>
> with_to_yaml {
> p "hoge".to_yaml
> }
>
> # remove_method は ensure 節で実行するようにしたほうが
> # 良いですね...