class Foo
def self.open(*args, &block)
p [args, block]
yield if block_given?
end
end
Foo.open(1) do
puts "hello"
end
open_m = Foo.method 'open'
class Foo
def self.open(*a) p 42 end
end
Foo.open(2) do
puts "hello"
end
(class << Foo; self; end).instance_eval do
define_method(:open, open_m)
end
Foo.open(3) do
puts "bye"
end
__END__
[[1], #<Proc:0x02869018@c:/rubylib/experiments/redefine-class-method.rb:8>]
hello
42
[[3], #<Proc:0x02867728@c:/rubylib/experiments/redefine-class-method.rb:26>]
bye
but as we've seen, it doesn't work in the case of the File(IO)
singleton. To be honest, I'm not clear about exactly what kind of
object the File(IO) singleton is. Anyone offer any enlightenment?
Regards,
Sean
···
On 7/14/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
On Fri, 14 Jul 2006, Sean O'Halpin wrote:
> Hmmm. I'm still getting "singleton method called for a different
> object (TypeError)" for this (ruby 1.8.4 (2005-12-24) [i386-mswin32]).
me too.
harp:~ > cat a.rb
class X # role of IO
class << self
def x(*args,&block) # role of open
block.call(1764) if block
end
end
end
OLD = X.method :x
class Y < X # role of File
class << self
def x; "rubbish"; end
end
end
class Y
class << self
define_method(:x, OLD )
end
end
Y.x{|a| puts a }
harp:~ > ruby a.rb
a.rb:23:in `x': singleton method called for a different object (TypeError)
from a.rb:23
harp:~ > ruby -v && cat /etc/redhat-release && uname -srm
ruby 1.8.4 (2005-12-01) [i686-linux]
Red Hat Enterprise Linux WS release 3 (Taroon Update 7)
Linux 2.4.21-40.EL i686
you robert?
btw. this challenge was not arbitrary: the increase in metaprogramming
popularity means people are doing things like
def class_method
alias '__instance_method__', 'instance_method' # push
define_method 'instance_method' do
# ...
__instance_method__ 42
# ...
end
ensure
alias 'instance_method', '__instance_method__' # pop
end
but this is neither thread safe (easy to fix) or re-entrant (not easy to fix).
what i mean is doing
class Foo
def self.open(*args, &block)
p [args, block]
yield if block_given?
end
end
[...]
(class << Foo; self; end).instance_eval do
define_method(:open, open_m)
end
[...]
but as we've seen, it doesn't work in the case of the File(IO)
singleton. To be honest, I'm not clear about exactly what kind of
object the File(IO) singleton is. Anyone offer any enlightenment?
Open is a singleton method of IO, not File; this is why the call fails (in
1.9, it'd happen earlier, as soon as you try to rebind the method). There's
nothing that special about File itself:
class X
def self.foo; yield + 1 end
end
class Y < X
end
Y.foo{1} # => 2
m = Y.method(:foo)
def Y.foo; 10 end
Y.foo{1} # => 10
class << Y; self end.class_eval{define_method(:foo, m)}
Y.foo{1} # =>
# ~> -:13:in `foo': singleton method bound for a different object (TypeError)
# ~> from -:13
As for the File(IO) notation, it seems to mean that the singleton method
belongs to IO:
class X; def self.foo; yield + 1 end end
class Y < X; end
Y.method(:foo) # => #<Method: Y(X).foo>
X.method(:foo) # => #<Method: X.foo>
Keep in mind that the singleton class of a class is derived from that of its
superclass:
class X; def self.foo; 1 end end
class Y < X; end
X.methods(false) # => ["foo"]
Y.methods(false) # =>
Y.foo # => 1
···
On Sat, Jul 15, 2006 at 10:33:09AM +0900, Sean O'Halpin wrote:
On 7/14/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
>On Fri, 14 Jul 2006, Sean O'Halpin wrote:
I think that certainly fits the description of enlightenment
I can see now that my example was missing the essential aspect of
using a parent's singleton method in a derived class.
And so back to Ara's challenge...
Regards,
Sean
···
On 7/18/06, Mauricio Fernandez <mfp@acm.org> wrote:
On Sat, Jul 15, 2006 at 10:33:09AM +0900, Sean O'Halpin wrote:
> On 7/14/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
> >On Fri, 14 Jul 2006, Sean O'Halpin wrote:
> In most cases, this works:
>
> class Foo
> def self.open(*args, &block)
> p [args, block]
> yield if block_given?
> end
> end
[...]
> (class << Foo; self; end).instance_eval do
> define_method(:open, open_m)
> end
[...]
> but as we've seen, it doesn't work in the case of the File(IO)
> singleton. To be honest, I'm not clear about exactly what kind of
> object the File(IO) singleton is. Anyone offer any enlightenment?
Open is a singleton method of IO, not File; this is why the call fails (in
1.9, it'd happen earlier, as soon as you try to rebind the method). There's
nothing that special about File itself:
class X
def self.foo; yield + 1 end
end
class Y < X
end
Y.foo{1} # => 2
m = Y.method(:foo)
def Y.foo; 10 end
Y.foo{1} # => 10
class << Y; self end.class_eval{define_method(:foo, m)}
Y.foo{1} # =>
# ~> -:13:in `foo': singleton method bound for a different object (TypeError)
# ~> from -:13
As for the File(IO) notation, it seems to mean that the singleton method
belongs to IO:
class X; def self.foo; yield + 1 end end
class Y < X; end
Y.method(:foo) # => #<Method: Y(X).foo>
X.method(:foo) # => #<Method: X.foo>
Keep in mind that the singleton class of a class is derived from that of its
superclass:
class X; def self.foo; 1 end end
class Y < X; end
X.methods(false) # => ["foo"]
Y.methods(false) # =>
Y.foo # => 1
Open is a singleton method of IO, not File; this is why the call fails (in
1.9, it'd happen earlier, as soon as you try to rebind the method). There's
nothing that special about File itself:
(...)
The problem is, if you change the method of the superclass (IO), and then later restore the original version, that you can't call it on the subclass (File):
class X; def self.foo; 1 end end
class Y < X; end
Y.foo # => 1
m = X.method(:foo)
def X.foo; 2 end
Y.foo # => 2
class << X; self end.class_eval{define_method(:foo, m)}
X.foo # => 1
Y.foo # => singleton method called for a different object
Just another thaught about it, what is wrong with my OPEN.call solution, is
it not general enough?
Cheers
Robert
···
On 7/19/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
On Wed, 19 Jul 2006, Sean O'Halpin wrote:
> I think that certainly fits the description of enlightenment
>
> I can see now that my example was missing the essential aspect of using
a
> parent's singleton method in a derived class.
>
> And so back to Ara's challenge...
yeah - i never solved satisfactorily...
good luck!
-a
--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama
--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.
It'd require one constant per method call for Ara's intended use, in the
general case (when several "layers" can be added at any point in time, i.e.
you want it to be reentrant).
···
On Wed, Jul 19, 2006 at 06:22:18PM +0900, Robert Dober wrote:
On 7/19/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
>On Wed, 19 Jul 2006, Sean O'Halpin wrote:
>> I can see now that my example was missing the essential aspect of using a
>> parent's singleton method in a derived class.
>>
>> And so back to Ara's challenge...
>
>yeah - i never solved satisfactorily...
>
Just another thaught about it, what is wrong with my OPEN.call solution, is
it not general enough?
Nothing wrong with it - it's just not an answer to the challenge!
In Ara's second post he notes: "using a const makes it too easy and
will accomplish what i need to do."
The reason it's not so useful to use consts is that it's not
re-entrant (so you can't nest and it's not thread-safe), it pollutes
the constant namespace, it becomes harder to manage the more instances
you have, it's not contained within local scope, etc. so I guess it
wouldn't pass as a general solution. You could probably overcome some
of these issues by using thread-local stacks but then that would
quickly start to get messy and wouldn't address the using out-of-scope
information issue.
However, back in the real world ;), yours is a pragmatic solution that
works as long as you understand its limitations.
Regards,
Sean
···
On 7/19/06, Robert Dober <robert.dober@gmail.com> wrote:
Just another thaught about it, what is wrong with my OPEN.call solution, is
it not general enough?
I guess I fail to understand the challange
Nevertheless the constant is just one way to store a reference to the
original methods, it would be very simple to export references of all
methods into a hash or a delegation object or whatever.
The constant was just part of the original challange.
I also have difficulties to see why
X.some
is any different from
X.method("some").call
concerning Thread Safety or even reentrance.
But anyway I too would prefer to reinstall the original method structure,
which is perfectly possible if the method was not from a superclass. And if
it was from the superclass we do not need to redefine it, so how about
class File
class << self
remove_method :open
define_method( :open, OPEN ) unless respond_to? :open
end
end
Cheers
Robert
···
On 7/19/06, Sean O'Halpin <sean.ohalpin@gmail.com> wrote:
On 7/19/06, Robert Dober <robert.dober@gmail.com> wrote:
> Just another thaught about it, what is wrong with my OPEN.call solution,
is
> it not general enough?
>
> Cheers
> Robert
>
Nothing wrong with it - it's just not an answer to the challenge!
In Ara's second post he notes: "using a const makes it too easy and
will accomplish what i need to do."
The reason it's not so useful to use consts is that it's not
re-entrant (so you can't nest and it's not thread-safe), it pollutes
the constant namespace, it becomes harder to manage the more instances
you have, it's not contained within local scope, etc. so I guess it
wouldn't pass as a general solution. You could probably overcome some
of these issues by using thread-local stacks but then that would
quickly start to get messy and wouldn't address the using out-of-scope
information issue.
However, back in the real world ;), yours is a pragmatic solution that
works as long as you understand its limitations.
Regards,
Sean
--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.