[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 節で実行するようにしたほうが
> # 良いですね...

In This Thread