Dynamicaly define a method which body can contain yield

Hello,

So i try to define a methode by providing a bloc which can contain a
yield.

I got a error 'no block given (yield)' on yield execution

Here is my test code :
class B
    def p1 ; puts "p1"; end
    def p2 ; puts "p2 1" ; yield ; puts "p2 2" ; end
    def self.add_tag(name,&blk)
      puts "defined #{name}..."
      define_method(name) do
         instance_eval(&blk)
      end
    end
    def self.add_tag2(name,str_bloc)
      puts "defined2 #{name}..."
      module_eval %{
         def #{name}()
        #{str_bloc}
         end
  }
     end
end

add_tag2 work well, but is not pretty :

B.add_tag2 "p4" "puts 'p4 '; p1 ; p2 { puts 'inp2' } ; yield"

defined2 p4...
=> nil

b.p4 { puts 'in p4' }

p4
p1
p2 1
inp2
p2 2
in p4
=> nil

add_tag give a Exception if bloc contain a yield:

B.add_tag("p5") { puts 'p5 '; yield }

defined p5...
=> #<Proc:0x027edcd4@./essai.rb:6>

b.p5 { puts 'in p5' }

p5
LocalJumpError: no block given
        from (irb):14
        from ./essai.rb:7:in `instance_eval'
        from ./essai.rb:7:in `p5'
        from (irb):15

Is there a solution ?
Thank you!

Attachments:
http://www.ruby-forum.com/attachment/4772/essai.rb

···

from :0

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

This is known as the single biggest PITA of Ruby1.8, well by me.
If you can, use Ruby1.9 and you can do such wonderful things as
define_method :alpha do |beta, &gamma|
  . .
  gamma[...]
  ..
end

in 1.8. you have to do some nasty tricks with converting methods to
blocks or use simply "eval" or "module_eval" with a string.

HTH
R.

···

On Thu, Jun 3, 2010 at 3:28 PM, Regis d'Aubarede <regis.aubarede@gmail.com> wrote:

Hello,

So i try to define a methode by providing a bloc which can contain a
yield.

Robert Dober wrote:

in 1.8. you have to do some nasty tricks with converting methods to
blocks or use simply "eval" or "module_eval" with a string.

I try actualy with 1.9, but no solution by the way ...

···

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

Robert Dober wrote:

in 1.8. you have to do some nasty tricks with converting methods to
blocks or use simply "eval" or "module_eval" with a string.

I try actualy with 1.9, but no solution by the way ...
--

ok my bad, you call yield in the "client" block, that cannot work, let
us look at what yield really is

def implicit
  yield # invoke the block provided by the client
end

def explicit &blk
  blk # or blk.call, here it is clearer
end

now on the client side

implicit{ yield } # what shall be invoked here???

obviously
  explicit{ blk }
cannot work as blk is the block you provide here, right.

Does this make your problem clearer?

HTH
R.

now if you call ex

···

On Thu, Jun 3, 2010 at 6:22 PM, Regis d'Aubarede <regis.aubarede@gmail.com> wrote:

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

--
The best way to predict the future is to invent it.
-- Alan Kay

Here a (partial) solution :

class B
def p1 ; puts "p1"; end

def self.add_tag(name,&blk)
   define_method(name) do |*args,&blocs|
      instance_eval { blk.call(*args,&blocs) }
   end
end

end

b=B.new
b.instance_eval {
B.add_tag("p5") { |*a,&bb| p1 ; bb.call(*a) ; p1 }
}

b.p5(1,2,3) {|*a| puts "in bloc p5 : #{a.inspect}" }

p1
in bloc p5 : [1, 2, 3]
p1

'b.instance_eval' seem necessary for that p1() call in add_tag() bloc
bind
to 'b' instance

Thank you ,

···

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