Bug #7262
closedmodule extension (#include/#prepend) in refinements
Description
refinementの中でモジュールのincludeやprependがしたい(かつ、そのスコープの範囲内だけで有効にしたい)なんて思ったんですが、きっと困難ですよね。
「無理」と思ったら遠慮なくrejectしてください。
module Experiment
refine String do
include Enumerable
def foo; p :foo; end
end
end
using Experiment
"foo".foo
"foo".each(&:p)
Matz.
Updated by shugo (Shugo Maeda) about 12 years ago
matz (Yukihiro Matsumoto) wrote:
refinementの中でモジュールのincludeやprependがしたい(かつ、そのスコープの範囲内だけで有効にしたい)なんて思ったんですが、きっと困難ですよね。
「無理」と思ったら遠慮なくrejectしてください。module Experiment
refine String do
include Enumerable
def foo; p :foo; end
end
endusing Experiment
"foo".foo
"foo".each(&:p)
以下では"refinement"はrefineのブロック中のselfになる匿名モジュールを指します。¶
Enumerableにはeachは定義されていないので、以下のようにしたいということでしょうか。
module Experiment
refine String do
include Enumerable
def foo; p :foo; end
def each; each_line; end
end
end
using Experiment
"foo".foo
p "foo\nbar".map { |i| i.upcase }
実はinclude自体は使えるのですが、上のコードは今の仕様ではエラーになります。
$ ruby /tmp/t.rb
:foo
/tmp/t.rb:11:in map': undefined method
each' for "foo\nbar":String (NoMethodError)
from /tmp/t.rb:11:in `'
Enumerableのmap自体はrefinementが有効なスコープで呼べるのですが、
mapの中でeachを呼ぶ時にEnumerable#mapの中ではrefinementが有効で
ないためeachが見つかりません。
まとめると、refinementに対してモジュールをincludeすることはできるが、
そのモジュールでTemplate Methodパターンを使用している場合、テンプレート
メソッドがrefinementで定義されていてもincludeしたモジュールからは呼び
出すことができません。
これを許すようにしようと思うと、local rebindingが必要になってしまうと
思いますが、どうでしょうか。
Updated by Anonymous about 12 years ago
まつもと ゆきひろです
In message "Re: [ruby-dev:46351] [ruby-trunk - Bug #7262] module extension (#include/#prepend) in refinements"
on Fri, 2 Nov 2012 12:04:27 +0900, "shugo (Shugo Maeda)" redmine@ruby-lang.org writes:
|まとめると、refinementに対してモジュールをincludeすることはできるが、
|そのモジュールでTemplate Methodパターンを使用している場合、テンプレート
|メソッドがrefinementで定義されていてもincludeしたモジュールからは呼び
|出すことができません。
|
|これを許すようにしようと思うと、local rebindingが必要になってしまうと
|思いますが、どうでしょうか。
ローカルリバインディングは採用しないというのは大前提として決
めたことなので、この点は取り下げます。テンプレートメソッドパ
ターンを含むものを例題にしたのは失敗でしたね。
ということは、通常のメソッドを追加するだけであればrefinement
内でのinclude/prependは、現状のままで有効であるという理解で
正しいでしょうか。正しければ、この提案はcloseしてください。
まつもと ゆきひろ /:|)
Updated by shugo (Shugo Maeda) about 12 years ago
匿名ユーザ wrote:
ということは、通常のメソッドを追加するだけであればrefinement
内でのinclude/prependは、現状のままで有効であるという理解で
正しいでしょうか。正しければ、この提案はcloseしてください。
prependの方はちょっと変な挙動になっているようなので少し考えさせてください。
class C
def foo
[:C]
end
end
module M1
def foo
super << :M1
end
end
module M2
def foo
super << :M2
end
end
module M3
refine C do
include M1
prepend M2
def foo
super << :M3
end
end
end
using M3
p C.new.foo #=> [:C, :M1, :M3, :M2, :M3]
Updated by shugo (Shugo Maeda) about 12 years ago
- Status changed from Open to Assigned
Updated by shugo (Shugo Maeda) about 12 years ago
- Status changed from Assigned to Closed
r38298とr38328で対応したのでcloseします。
期待と違う動作だったらreopenしてください。 > まつもとさん