Access super from yield block?

Is there a way to access super from a yield block?

···

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

What exactly are trying to achieve?

  robert

···

On 15.09.2010 20:59, Gene Angelo wrote:

Is there a way to access super from a yield block?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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. :wink:

Vale,
Marvin

···

Am 15.09.2010 20:59, schrieb Gene Angelo:

Is there a way to access super from a yield block?

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

···

--
Posted via http://www.ruby-forum.com/\.

Afternoon,

> 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.

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

···

On Wed, Sep 15, 2010 at 1:12 PM, Gene Angelo <web.gma@gmail.com> wrote:

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"

···

On 09/15/2010 01:12 PM, Gene Angelo wrote:

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

Gene Angelo wrote:

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.

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?

···

--
Posted via http://www.ruby-forum.com/\.

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.

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

···

On 15.09.2010 22:12, Gene Angelo wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/