[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Partial append_features?

Ola Bini

8/28/2006 7:01:00 PM

Hi,

I'm looking for a way to copy methods from a Module, or specify more
directly which methods get included in a class. More or less, I would
like to be able to do something like this:

module Foo
def do_one_thing
end
def do_second
end
def do_third
end
end

class Bar
append_from Foo, :do_second, :do_third
end

or
module Baz
append_from Foo, :do_second, :do_third
end

and I would have a module Baz which could be included, without having
do_one_thing included.

Is this possible in Ruby right now? My first approach was to get the
UnboundMethod instance_method from the Module, but I couldn't find a way
to attach these to an unrelated class since UnboundMethod must have a
is_a?-relationship with the binding object.

Regards
--
Ola Bini (http://ola-bini.bl...)
JvYAML, RbYAML, JRuby and Jatha contributor
System Developer, Karolinska Institutet (http:/...)
OLogix Consulting (http://www....)

"Yields falsehood when quined" yields falsehood when quined.


13 Answers

noah.easterly@gmail.com

8/28/2006 7:20:00 PM

0

Hmmmm... maybe you could do some of this with Forwardable [1], at least
for class instantiations. This isn't a perfect fit, since you do need
to specify the delegate object, though.

[1]: http://www.ruby-doc.org/stdlib/libdoc/forwardable/rdoc/...

Ola Bini wrote:
> Hi,
>
> I'm looking for a way to copy methods from a Module, or specify more
> directly which methods get included in a class. More or less, I would
> like to be able to do something like this:
>
> module Foo
> def do_one_thing
> end
> def do_second
> end
> def do_third
> end
> end
>
> class Bar
> append_from Foo, :do_second, :do_third
> end
>
> or
> module Baz
> append_from Foo, :do_second, :do_third
> end
>
> and I would have a module Baz which could be included, without having
> do_one_thing included.
>
> Is this possible in Ruby right now? My first approach was to get the
> UnboundMethod instance_method from the Module, but I couldn't find a way
> to attach these to an unrelated class since UnboundMethod must have a
> is_a?-relationship with the binding object.
>
> Regards
> --
> Ola Bini (http://ola-bini.bl...)
> JvYAML, RbYAML, JRuby and Jatha contributor
> System Developer, Karolinska Institutet (http:/...)
> OLogix Consulting (http://www....)
>
> "Yields falsehood when quined" yields falsehood when quined.

e

8/28/2006 7:33:00 PM

0

Ola Bini wrote:
> Hi,
>
> I'm looking for a way to copy methods from a Module, or specify more
> directly which methods get included in a class. More or less, I would
> like to be able to do something like this:
>
> <snip />
>
> module Baz
> append_from Foo, :do_second, :do_third
> end
>
> and I would have a module Baz which could be included, without having
> do_one_thing included.
>
> Is this possible in Ruby right now? My first approach was to get the
> UnboundMethod instance_method from the Module, but I couldn't find a way
> to attach these to an unrelated class since UnboundMethod must have a
> is_a?-relationship with the binding object.

I think the 'proper' solution is to chop your module into
smaller pieces. Alternatively, Method#to_proc, maybe?

> Regards


--
Posted via http://www.ruby-....

Matthew Johnson

8/28/2006 8:34:00 PM

0

> I'm looking for a way to copy methods from a Module, or specify
> more directly which methods get included in a class. More or less,
> I would like to be able to do something like this:
>
> module Foo
> def do_one_thing
> end
> def do_second
> end
> def do_third
> end
> end
>
> class Bar
> append_from Foo, :do_second, :do_third
> end
>
> or
> module Baz
> append_from Foo, :do_second, :do_third
> end
>
> and I would have a module Baz which could be included, without
> having do_one_thing included.
>
> Is this possible in Ruby right now? My first approach was to get
> the UnboundMethod instance_method from the Module, but I couldn't
> find a way to attach these to an unrelated class since
> UnboundMethod must have a is_a?-relationship with the binding object.

The closest I have seen to this is generating a module on the fly
(with Module.new) that includes the Module and then undefs all the
methods you don't want. That gives you a custom module to include
that will have only the methods you are after.

Matthew


Logan Capaldo

8/28/2006 9:01:00 PM

0


On Aug 28, 2006, at 3:00 PM, Ola Bini wrote:

> Hi,
>
> I'm looking for a way to copy methods from a Module, or specify
> more directly which methods get included in a class. More or less,
> I would like to be able to do something like this:
>
> module Foo
> def do_one_thing
> end
> def do_second
> end
> def do_third
> end
> end
>
> class Bar
> append_from Foo, :do_second, :do_third
> end
>
> or
> module Baz
> append_from Foo, :do_second, :do_third
> end
>
> and I would have a module Baz which could be included, without
> having do_one_thing included.
>
> Is this possible in Ruby right now? My first approach was to get
> the UnboundMethod instance_method from the Module, but I couldn't
> find a way to attach these to an unrelated class since
> UnboundMethod must have a is_a?-relationship with the binding object.
>
> Regards
> --
> Ola Bini (http://ola-bini.bl...)
> JvYAML, RbYAML, JRuby and Jatha contributor
> System Developer, Karolinska Institutet (http:/...)
> OLogix Consulting (http://www....)
>
> "Yields falsehood when quined" yields falsehood when quined.
>
>

% cat Projects/Ruby Experiments/append_from.rb
class Module
def append_from( mod, *methods_to_keep )
methods_to_keep.map! { |m| m.to_s }
methods_to_remove = mod.instance_methods(false) - methods_to_keep
new_mod = Module.new
new_mod.module_eval do
include mod
methods_to_remove.each { |meth| undef_method meth }
end
include new_mod
end
end

module M
def a
puts "a"
end

def b
puts "b"
end
end

class A
append_from M, :b
end

a = A.new
a.b
a.a

% ruby Projects/Ruby Experiments/append_from.rb
b
-:40: undefined method `a' for #<A:0x1e89b4> (NoMethodError)




e

8/28/2006 11:16:00 PM

0

Robert Dober wrote:
> On 8/28/06, Logan Capaldo <logancapaldo@gmail.com> wrote:
>> > module Foo
>> > end
>> > the UnboundMethod instance_method from the Module, but I couldn't
>> > "Yields falsehood when quined" yields falsehood when quined.
>> include mod
>>
>> a.b
>> a.a
>>
>> % ruby Projects/Ruby Experiments/append_from.rb
>> b
>> -:40: undefined method `a' for #<A:0x1e89b4> (NoMethodError)
>>
>>
>>
>>
>>
> unfortunately that approach undefines eralier defined methods in the
> appendee, especially inherited ones :(
> I guess that could be fixed but the code will become rather clumsy.

Heh, take another look:

new_mod = Module.new # Only this anonymous is affected
new_mod.module_eval do
include mod
methods_to_remove.each { |meth| undef_method meth }
end

A rather nice solution.

> Cheers
> Robert



--
Posted via http://www.ruby-....

Nobuyoshi Nakada

8/29/2006 2:26:00 AM

0

Hi,

At Tue, 29 Aug 2006 04:00:39 +0900,
Ola Bini wrote in [ruby-talk:211191]:
> and I would have a module Baz which could be included, without having
> do_one_thing included.

http://www.rubyist.net/~nobu/ruby/a... may help you.

require 'aliasing'

module Foo
def do_one_thing
"one_thing"
end
def do_second
"second"
end
def do_third
"third"
end
end

class Bar
include Foo.only_aliasing(:do_second, :do_third)
end

p Bar.instance_methods.grep(/^do/)
bar = Bar.new
p bar.do_second
p bar.do_third
p (begin bar.do_one_thing; rescue NoMethodError => e; e; end)

--
Nobu Nakada

Trans

8/29/2006 4:53:00 AM

0


Ola Bini wrote:
> Hi,
>
> I'm looking for a way to copy methods from a Module, or specify more
> directly which methods get included in a class. More or less, I would
> like to be able to do something like this:
>
> module Foo
> def do_one_thing
> end
> def do_second
> end
> def do_third
> end
> end
>
> class Bar
> append_from Foo, :do_second, :do_third
> end
>
> or
> module Baz
> append_from Foo, :do_second, :do_third
> end
>
> and I would have a module Baz which could be included, without having
> do_one_thing included.
>
> Is this possible in Ruby right now? My first approach was to get the
> UnboundMethod instance_method from the Module, but I couldn't find a way
> to attach these to an unrelated class since UnboundMethod must have a
> is_a?-relationship with the binding object.

Try Facets' module/integrate.rb Here's the doc:

# Using integrate is just like using include except the
# module included is a reconstruction of the one given
# altered via commands in the block.
#
# Convenient commands available are: #rename, #redef,
# #remove, #nodef and #wrap. But any module method
# can be used.
#
# module W
# def q ; "q" ; end
# def y ; "y" ; end
# end
#
# class X
# integrate W do
# nodef :y
# end
# end
#
# x = X.new
# x.q #=> "q"
# x.y #=> missing method error
#
# This is like #revisal, but #revisal only
# returns the reconstructred module. It does not
# include it.

http://facets.rub...

T.

Ola Bini

8/29/2006 6:27:00 AM

0

Logan Capaldo wrote:
>
> % cat Projects/Ruby Experiments/append_from.rb
> class Module
> def append_from( mod, *methods_to_keep )
> methods_to_keep.map! { |m| m.to_s }
> methods_to_remove = mod.instance_methods(false) - methods_to_keep
> new_mod = Module.new
> new_mod.module_eval do
> include mod
> methods_to_remove.each { |meth| undef_method meth }
> end
> include new_mod
> end
> end
>

Hi,

Thank you for writing it up for me. This was more or less what I had in
mind of writing up myself. This solution is definitely the best for me,
since the methods I want to keep is a small subset compared to how many
to remove, and the ones to remove will grow with time.

Thanks.

--
Ola Bini (http://ola-bini.bl...)
JvYAML, RbYAML, JRuby and Jatha contributor
System Developer, Karolinska Institutet (http:/...)
OLogix Consulting (http://www....)

"Yields falsehood when quined" yields falsehood when quined.


Mauricio Fernández

8/29/2006 8:13:00 AM

0

On Tue, Aug 29, 2006 at 08:15:47AM +0900, Eero Saynatkari wrote:
> Robert Dober wrote:
> > unfortunately that approach undefines eralier defined methods in the
> > appendee, especially inherited ones :(
> > I guess that could be fixed but the code will become rather clumsy.
>
> Heh, take another look:
>
> new_mod = Module.new # Only this anonymous is affected
> new_mod.module_eval do
> include mod
> methods_to_remove.each { |meth| undef_method meth }
> end
>
> A rather nice solution.

I think this is what he meant:

RUBY_VERSION # => "1.8.5"
class X; def foo; "X#foo" end end
class Y < X; end
module M; def foo; "M#foo" end end
N = Module.new
N.module_eval do
include M
undef_method :foo
end

y = Y.new
y.foo # => "X#foo"
class Y; include N end
y.foo # =>
# ~> -:14: undefined method `foo' for #<Y:0xa7e04000> (NoMethodError)


IMO it's better to have the last call to #foo return X#foo.
You can do that by cloning the module then using remove_method on the copy.

--
Mauricio Fernandez - http://eige... - singular Ruby

Mauricio Fernández

8/29/2006 8:26:00 AM

0

On Tue, Aug 29, 2006 at 03:26:58PM +0900, Ola Bini wrote:
> Logan Capaldo wrote:
> >% cat Projects/Ruby Experiments/append_from.rb
> >class Module
> > def append_from( mod, *methods_to_keep )
> > methods_to_keep.map! { |m| m.to_s }
> > methods_to_remove = mod.instance_methods(false) - methods_to_keep
> > new_mod = Module.new
> > new_mod.module_eval do
> > include mod
> > methods_to_remove.each { |meth| undef_method meth }
> > end
> > include new_mod
> > end
> >end
> >
>
> Thank you for writing it up for me. This was more or less what I had in
> mind of writing up myself. This solution is definitely the best for me,
> since the methods I want to keep is a small subset compared to how many
> to remove, and the ones to remove will grow with time.

The above code effectively removes inherited methods too (as well as those
from other modules that were included previously):

class Module
def append_from( mod, *methods_to_keep )
methods_to_keep.map! { |m| m.to_s }
methods_to_remove = mod.instance_methods(false) - methods_to_keep
new_mod = Module.new
new_mod.module_eval do
include mod
methods_to_remove.each { |meth| undef_method meth }
end
include new_mod
end
end

module A; def foo; "A#foo" end end
module B
def foo; "B#foo" end
def bar; "B#bar" end
end
class X; include A end
x = X.new
x.foo # => "A#foo"
class X; append_from B, :bar end
x.bar # => "B#bar"
x.foo # =>

# ~> -:24: undefined method `foo' for #<X:0xa7d72a88> (NoMethodError)

In this example, #undef_method has blocked A#foo too.


Here's another way to do it without clobbering inherited methods; the
key difference is that the original module will not be added to the
inheritance chain:



RUBY_VERSION # => "1.8.5"
RUBY_RELEASE_DATE # => "2006-08-25"
class Module
def append_from(mod, *methods)
methods.map!{|x| x.to_s}
m = mod.clone
m.module_eval do
(instance_methods(false) - methods).each{|x| remove_method x }
end
include m
end
end

module A; def foo; "A#foo" end end
module B
def foo; "B#foo" end
def bar; "B#bar" end
end
class X; include A end
x = X.new
x.foo # => "A#foo"
class X; append_from B, :bar end
x.bar # => "B#bar"
x.foo # => "A#foo"
X.ancestors # => [X, #<Module:0xa7d94214>, A, Object, Kernel]
====================
B(') is missing in
the inheritance chain

--
Mauricio Fernandez - http://eige... - singular Ruby