From: Trans Date: 2005-08-02T07:36:04+09:00 Subject: Re: Selective mixins; who can improve on this? Kirk Haines wrote: > So, on #ruby-lang an hour ago, Daniel Berger asked for ideas to make some > non-working code of his work. He's trying to come up with a way to > selectively mixin methods from a module into a class. > > After some tinkering, I came up with this working, but ugly and definitely > improveable code to do it: > > class Module > def use(mod, *methods) > c = Class.new > # Make a singleton that mixes everything in, so that we can cherrypick. > eval("class << c; include #{mod}; end") > > methods.each do |m| > # There has to be a more elegant way to do this. > m_sym = m.to_sym > mc_sym = m.to_s.upcase.to_sym > um = c.method(m_sym) > self.const_set(mc_sym,um) > self.class_eval("def #{m.to_s}; #{mc_sym.to_s}.call; end") > end > end > end > > > module Foo > def a; 'abc'; end > def z; 'xyz'; end > end > > class Bing > use(Foo, :a, 'z') > end > > x = Bing.new > p x.a > p x.z > > > There has to be a more elegant way to do this. What is it? > I'm afraid that is not doing what you expect it too. Try: def a; p self; end and you will see that self is not a Bing. There is no _simple_ solution to this. Ruby is picky about where its methods come from and where they can thus go to. Try playing with #method, Class#instance_method and #bind and you'll see what I mean. BUT I have done what you ask, as I have/am considering using something like this for Ruby Facets. Off the top of my head (so forgive any little bugs) like: class Module METHINDEX = {} def index_def( msym, &mdef ) METHINDEX[[self,:"#{msym}"]] = mdef end def use(mod, *methods) methods.each { |msym| self.class_eval &METHINDEX[[mod,:"#{msym}"]] } end end module Foo index_def( :a ) { def a; p self ; end } index_def( :z ) { def z; p "z" ; end } end class Bing use Foo, :a, 'z' end The block is needed to protect the method defintion from binding to an unusable location. Am interested in other people's solutions too. T.