access super from yield block?

Q

Quintus

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 15.09.2010 20:59, schrieb Gene Angelo:
Is there a way to access super from a yield block?

None I'm aware of. However, with a heavy bit of metaprogramming,
everything's possible in Ruby:

- -------------------------------------
class A

def foo
puts "foo in A"
end

end

class B < A

def foo(&block)
puts "foo in B"
if block_given?
super_method = A.instance_method:)foo)
instance_exec(super_method, &block)
end
end

end

x = B.new
x.foo do |super_method|
m = super_method.bind(self)
m.call
end
x.foo
- -------------------------------------

Outputs:

foo in B
foo in A
foo in B

ruby -v: ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]

Note that I'd NEVER use such a construct in production code. But it's
fun to try what's possible in Ruby. ;-)

Vale,
Marvin
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkyRJeMACgkQDYShvwAbcNlfDwCfTBjFhdahiK3gsZWsIP6vmI1w
vaIAn07uvcYdXVjnDw39Az+X7cYCuwQR
=yDm7
-----END PGP SIGNATURE-----
 
G

Gene Angelo

What exactly are trying to achieve?

I have class A that derives from class B

A#parse and A#parse! override members of the same name in B

A#parse and A#parse! both call A#do_parse to retrieve arguments from the
command line in a loop. A yield in A#do_parse returns the arguments
(argv). I want to call 'super argv' from both A#parse and A#parse! but
super is not set to A#super.

# simplified...
class A < B
...

def parse
do_parse {|a| super a}
end

def parse!
do_parse {|a| super a}
def

def do_parse
argv = gets.strip.to_a
return ['-x'] if argv.index '-x'
return ['-h'] if argv.empty?
yield argv
end
protected :do_parse

...
end
 
J

John W Higgins

[Note: parts of this message were removed to make it a legal post.]

Afternoon,

I have class A that derives from class B

A#parse and A#parse! override members of the same name in B

A#parse and A#parse! both call A#do_parse to retrieve arguments from the
command line in a loop. A yield in A#do_parse returns the arguments
(argv). I want to call 'super argv' from both A#parse and A#parse! but
super is not set to A#super.

How about something like this - a little hokey but it works

class A
def x(parm)
puts "Hi from A - #{parm}"
end
end

class B < A
alias :super_x :x

def x(parm)
puts "Hi from B - #{parm}"
do_something { |z| super_x(z) }
end

def do_something
yield "Hello"
end
end

The alias will in essence give you the super method so you can use it inside
the block.

John
 
J

Joel VanderWerf

What exactly are trying to achieve?

I have class A that derives from class B

A#parse and A#parse! override members of the same name in B

A#parse and A#parse! both call A#do_parse to retrieve arguments from the
command line in a loop. A yield in A#do_parse returns the arguments
(argv). I want to call 'super argv' from both A#parse and A#parse! but
super is not set to A#super.

# simplified...
class A< B
...

def parse
do_parse {|a| super a}
end

def parse!
do_parse {|a| super a}
def

def do_parse
argv = gets.strip.to_a
return ['-x'] if argv.index '-x'
return ['-h'] if argv.empty?
yield argv
end
protected :do_parse

...
end

That should work. Can you isolate the problem in a small piece of code
you can post here?

Here's a working example:

class A
def foo a
"A#foo: #{a}"
end
end

class B < A
def do_something
yield 3
end

def foo
s = do_something {|a| super a}
"B#foo: " + s
end
end

p B.new.foo # ==> "B#foo: A#foo: 3"
 
B

Brian Candler

Gene said:
I have class A that derives from class B

A#parse and A#parse! override members of the same name in B

A#parse and A#parse! both call A#do_parse to retrieve arguments from the
command line in a loop. A yield in A#do_parse returns the arguments
(argv). I want to call 'super argv' from both A#parse and A#parse! but
super is not set to A#super.

There is no such method as A#super. super means "call the same named
method in the superclass".

I tried to make your example into a standalone one, but I don't know if
this is a legitimate demonstration of what you're trying to do:

----- 8< -----------------------------
class B
def parse(*args)
puts "parse in B(#{args.inspect})"
end
end

class A < B
def parse
do_parse { |a|
puts "Before super"
super a
puts "After super"
}
end

def do_parse
yield [1,2,3]
end
end

A.new.parse
----- 8< -----------------------------

This prints:

Before super
parse in B([[1, 2, 3]])
After super

which is what I expect. I'm using ruby 1.8.7 (2010-01-10 patchlevel 249)
[x86_64-linux]

What do you want it to do instead?
 
R

Robert Klemme

I have class A that derives from class B

A#parse and A#parse! override members of the same name in B

A#parse and A#parse! both call A#do_parse to retrieve arguments from the
command line in a loop. A yield in A#do_parse returns the arguments
(argv). I want to call 'super argv' from both A#parse and A#parse! but
super is not set to A#super.

What should "super argv" do? Your description is completele technical
but you don't tell what the problem is that you are trying to solve here.
# simplified...
class A< B
..

def parse
do_parse {|a| super a}
end

def parse!
do_parse {|a| super a}
def

Where's the difference between #parse and #parse!? Also, why do you
want to call the superclass method from the block? This will result in
parsing input twice, since B#parse will also call do_parse. This does
not seem to make much sense

And, btw. reading from stdin from within method #do_parse is not very
modular. It might turn out that you want to read input from a file and
then you need to break this up anyway.
def do_parse
argv = gets.strip.to_a

This will create an Array with a single element. Is this really what
you want?
return ['-x'] if argv.index '-x'
return ['-h'] if argv.empty?
yield argv
end
protected :do_parse

..
end

And: what does the whole picture look like? Why do you want several
classes that somehow must behave differently but apparently share the
same argument parsing code? I would have expected different classes to
have different needs for arguments to be parsed and consequently not
share parsing code. With OptionParser you could do:

class B
def parse(argv)
OptionParser.new do |opts|
fill opts
end.parse argv
end

def parse!(argv)
OptionParser.new do |opts|
fill opts
end.parse! argv
end

protected
def fill(opts)
opts.on '-x' do |...| end
opts.on '-y' do |...| end
end
end

class A < B
def fill(opts)
super
opts.on '-z' do |...| end
end
end

Cheers

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,145
Messages
2,570,826
Members
47,371
Latest member
Brkaa

Latest Threads

Top