About define_method

I want to define a method in kernel using Flattern Scope.

  Kernel.send :define_method, :each_event do
    events.each_pair do |message, condition|
      yield message, condition
    end
  end

so, I think this is equal to:

def Kernel.each_event

    events.each_pair do |message, condition|
      yield message, condition
    end

end

Then I can pass a block to this method, for example:
Kernel.each_event do |message, condition|
  .....
end

However, if I use send define_method method to define each_event, I
would met a exception:
in `each_event': no block given (LocalJumpError)

I do not know why? if I do not use "send", the "yield" work well. Also,
I can define method as follows according to "meta programming ruby"
says:

  Kernel.send :define_method, :each_event do |&block|
    events.each_pair do |message, condition|
      block.call message, condition
    end
  end

please help me to figure out why I can not use the first solution.

···

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

You simply cannot define methods which use block passed to them via
define_method as you have found out. Minimalistic example:

$ ruby -e 'module Kernel;def foo; yield 1 end end; foo {|x| p x}'
1
$ ruby -e 'module Kernel;define_method(foo) { yield 1 };end;foo {|x| p x}'
-e:1:in `<module:Kernel>': undefined local variable or method `foo'
for Kernel:Module (NameError)
        from -e:1:in `<main>'

Another variant is to use class_eval:

$ ruby -e 'Kernel.class_eval "def foo; yield 1 end";foo {|x| p x}'
1

Kind regards

robert

···

On Mon, Oct 15, 2012 at 8:37 AM, li shoubo <lists@ruby-forum.com> wrote:

please help me to figure out why I can not use the first solution.

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

li shoubo wrote in post #1079862:

I want to define a method in kernel using Flattern Scope.

  Kernel.send :define_method, :each_event do
    events.each_pair do |message, condition|
      yield message, condition
    end
  end

. . .

However, if I use send define_method method to define each_event, I
would met a exception:
in `each_event': no block given (LocalJumpError)

I do not know why? if I do not use "send", the "yield" work well. Also,
I can define method as follows according to "meta programming ruby"
says:

  Kernel.send :define_method, :each_event do |&block|
    events.each_pair do |message, condition|
      block.call message, condition
    end
  end

The problem is not the 'send', but rather the 'define_method'. Namely,
'define_method' does not allow you to specify a method body that expects
a blok. If you need to dynamically create a method that accepts a block,
you need to use the 'def method_name; ...; end' and the 'class_eval'
(see: D. Flanagan's & Y. Matsumoto's book 'The Ruby Programming
Language' page:275).

So, your example should look something like the following:

  Kernel.class_eval do
    def each_event(events)
      events.each_pair do |message, condition|
        yield message, condition
      end
    end
  end
  events = { one: 1, two: 2, three: 3 }
  each_event(events) { |x, y| puts "#{x}, #{y}" }

Regards, igor

···

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

I looked at all the posts above again, and realized that both, you li,
and
Robert, have already presented the proper solution to your original
post. In fact you yourself, li, offered the solution at the end of your
first post above. Namely, contrary to the quote in 'The Ruby Programming
Language' book, the following code with 'define_method' works just fine:

  Kernel.send :define_method, :each_event do |events, &block|
    events.each_pair do |message, condition|
      block.call message, condition
    end
  end
  events = { one: 1, two: 2, three: 3 }
  each_event(events) { |m, c| puts "message:#{m}, condition:#{c}" }

···

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

I looked at all the posts again, and realized that both, you li, and
Robert, have already presented the proper solution to your original
post. In fact you yourself, li, offered the solution at the end of your
first post above. Namely, contrary to the quote in 'The Ruby Programming
Language' book, the following code with 'define_method' works just fine:

  Kernel.send :define_method, :each_event do |events, &block|
    events.each_pair do |message, condition|
      block.call message, condition
    end
  end
  events = { one: 1, two: 2, three: 3 }
  each_event(events) { |m, c| puts "message:#{m}, condition:#{c}" }

···

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

thanks, I use your example in irb:

module Kernel

   define_method(:foo) { yield 1}

end

no error, but if I invoke it:

Kernel.foo { 2 }

the error jumps,

LocalJumpError: no block given

however, this is OK

module Kernel

   define_method(:foo) { 1 }

end

It seems I can not use yield in define_method, can you tell me more
details?

Robert Klemme wrote in post #1079864:

···

On Mon, Oct 15, 2012 at 8:37 AM, li shoubo <lists@ruby-forum.com> wrote:

please help me to figure out why I can not use the first solution.

You simply cannot define methods which use block passed to them via
define_method as you have found out. Minimalistic example:

$ ruby -e 'module Kernel;def foo; yield 1 end end; foo {|x| p x}'
1
$ ruby -e 'module Kernel;define_method(foo) { yield 1 };end;foo {|x| p
x}'
-e:1:in `<module:Kernel>': undefined local variable or method `foo'
for Kernel:Module (NameError)
        from -e:1:in `<main>'

Another variant is to use class_eval:

$ ruby -e 'Kernel.class_eval "def foo; yield 1 end";foo {|x| p x}'
1

Kind regards

robert

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

you meant :foo

···

On Oct 15, 2012, at 00:15 , Robert Klemme <shortcutter@googlemail.com> wrote:

$ ruby -e 'module Kernel;define_method(foo) { yield 1 };end;foo {|x| p x}'
-e:1:in `<module:Kernel>': undefined local variable or method `foo'

Yes, of course. Thanks for catching that. Then we get

$ ruby -e 'module Kernel;define_method(:foo) { yield 1 };end;foo {|x| p x}'
-e:1:in `block in <module:Kernel>': no block given (yield) (LocalJumpError)
        from -e:1:in `<main>'

Kind regards

robert

···

On Mon, Oct 15, 2012 at 9:49 AM, Ryan Davis <ryand-ruby@zenspider.com> wrote:

On Oct 15, 2012, at 00:15 , Robert Klemme <shortcutter@googlemail.com> wrote:

$ ruby -e 'module Kernel;define_method(foo) { yield 1 };end;foo {|x| p x}'
-e:1:in `<module:Kernel>': undefined local variable or method `foo'

you meant :foo

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

can you give me more details? Or it is a rule that I can not use yield
in define_method method to define a new one?

Robert Klemme wrote in post #1079874:

···

On Mon, Oct 15, 2012 at 9:49 AM, Ryan Davis <ryand-ruby@zenspider.com> > wrote:

On Oct 15, 2012, at 00:15 , Robert Klemme <shortcutter@googlemail.com> wrote:

$ ruby -e 'module Kernel;define_method(foo) { yield 1 };end;foo {|x| p x}'
-e:1:in `<module:Kernel>': undefined local variable or method `foo'

you meant :foo

Yes, of course. Thanks for catching that. Then we get

$ ruby -e 'module Kernel;define_method(:foo) { yield 1 };end;foo {|x| p
x}'
-e:1:in `block in <module:Kernel>': no block given (yield)
(LocalJumpError)
        from -e:1:in `<main>'

Kind regards

robert

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

You got it. But you can use Proc#call instead:

irb(main):013:0> String.send(:define_method, :foo) {|a, &b| b.call(a +
length())}
=> #<Proc:0x802b6c4c@(irb):12 (lambda)>
irb(main):014:0> s="bar"
=> "bar"
irb(main):015:0> s.foo(10) {|x| p x}
13
=> 13

Kind regards

robert

···

On Mon, Oct 15, 2012 at 1:27 PM, li shoubo <lists@ruby-forum.com> wrote:

can you give me more details? Or it is a rule that I can not use yield
in define_method method to define a new one?

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