Send() with a block?

Why don't the ruby docs say that send() can take a block?

Kernel.send(:define_method, :my_meth) do |x|
  puts x
end

my_meth(10)

--output:--
10

At the following link there is nothing saying that send() will accept a
block:

http://www.ruby-doc.org/core/classes/Object.html#M000999

Whereas, for example, at the following link it states that grep() will
take a block:

http://www.ruby-doc.org/core/classes/Enumerable.html#M001482

···

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

It's not the send() that's consuming the block - it's the define_method().

Regards,
Sean

···

On Sat, Mar 12, 2011 at 8:45 PM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

Why don't the ruby docs say that send() can take a block?

Kernel.send(:define_method, :my_meth) do |x|
puts x
end

From the pickaxe:

obj.send( symbol ⟨ , args ⟩∗ ⟨ , &block ⟩ ) → other_obj

···

On Mar 12, 2011, at 12:45 , 7stud -- wrote:

Why don't the ruby docs say that send() can take a block?

ALL methods take a block, they just don't have to do anything with it

One of the best replies. And beautifully signifies the flexible approach
taken by Ruby.

Blocks rule.

···

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

It says "Invokes the method identified by symbol, passing it any arguments
specified." A block is an argument, it just gets set into an implicit
location by default, or you can make it explicit, putting it into a Proc
object, by putting &varname on the end of your params list.

I've had difficulty following the code examples in this thread. Here is the
one I think is relevant:

def meth(first, second=12 , *rest, &block)
  [first , second , rest , block]
end

send :meth , 1 # => [1, 12, , nil]
send :meth , 1 , 2 # => [1, 2, , nil]
send :meth , 1 , 2 , 3 # => [1, 2, [3], nil]
send :meth , 1 , 2 , 3 do end # => [1, 2, [3], #<Proc:0x00000100868340@-:8>]

You can see, it passes on ordinal arguments, args with default values,
variable lengthed arguments, and yes, also blocks.

···

On Sat, Mar 12, 2011 at 2:45 PM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

Why don't the ruby docs say that send() can take a block?

Kernel.send(:define_method, :my_meth) do |x|
puts x
end

my_meth(10)

--output:--
10

At the following link there is nothing saying that send() will accept a
block:

class Object - RDoc Documentation

Whereas, for example, at the following link it states that grep() will
take a block:

module Enumerable - RDoc Documentation

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

Thanks for all the responses. This may be true:

···

--
The actual method "send" can take a block, and it passes it to the
method being invoked. If it didn't, it would be impossible to pass a
block to a method when invoking it using send.
--

...but why should a beginner have to figure that out? You shouldn't
have to be a meta-programming guru to figure out the docs. Wouldn't it
be better if beginners posted: "I really think the docs are great."
rather than "beginner: the docs are confusing; expert-response: they are
clear if you are smart."

Why doesn't this work:

def my_meth(*args)
  yield
  p args
end

my_proc = Proc.new {puts 'hello'}
my_meth(1, 2, 3, &my_proc ) #=>'hello' [1, 2, 3]

obj = Object.new
m = obj.method(my_meth)
m.call([10, 20, 30], &my_proc) #LocalJumpError at yield line

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

But send() still bothers to pass the block around. Consider the following code:

---8<---8<---
def my_method
   p block_given?
end

def my_send # imitating send
   my_method
end

my_send # => false
---8<---8<---

···

On Sun, 13 Mar 2011 06:01:31 +0900, Sean O'Halpin wrote:

On Sat, Mar 12, 2011 at 8:45 PM, 7stud -- <bbxx789_05ss@yahoo.com> > wrote:

Why don't the ruby docs say that send() can take a block?

Kernel.send(:define_method, :my_meth) do |x|
puts x
end

It's not the send() that's consuming the block - it's the define_method().

--
   WBR, Peter Zotov.

Correct, a block IS an argument, but of a rather unusual type in that
it may or may not be explicit in the definition of a method that uses
it.

HOWEVER, if a method (call it method bar or baz) passes any block it
receives on to yet another method (call it method foo), it is best
that the documents include this fact.

AN EXAMPLE:
## Method foo() may or may not be given a block...
def foo(*args)
  puts "foo(#{args.inspect}) called with" + (block_given? ? '' :
'out') + " a block included."
  yield *args if block_given?
end

## Method bar() does NOT explicitly capture block arguments
## and thus does NOT pass any given block on to foo():
def bar(*args)
  puts "bar(#{args.inspect}) called with" + (block_given? ? '' :
'out') + " a block included."
  foo(*args)
end

## Method baz() DOES explicitly capture block arguments
## and DOES pass any given block on to foo():
def baz(*args, &block)
  puts "baz(#{args.inspect}) called with" + (block_given? ? '' :
'out') + " a block included."
  foo(*args, &block)
end

bar("some", :args => "for bar", :without => "a block")
puts
bar("some", :args => "for bar", :with => "a block") { |*a| puts "block
passed to bar(): #{a.inspect}" }
puts "--"
baz("some", :args => "for baz", :without => "a block")
puts
baz("some", :args => "for baz", :with => "a block") { |*a| puts "block
passed to baz(): #{a.inspect}" }

SAMPLE OUTPUT FROM ABOVE EXAMPLE:
bar(["some", {:args=>"for bar", :without=>"a block"}]) called without
a block included.
foo(["some", {:args=>"for bar", :without=>"a block"}]) called without
a block included.

bar(["some", {:args=>"for bar", :with=>"a block"}]) called with a
block included.
foo(["some", {:args=>"for bar", :with=>"a block"}]) called without a
block included.

···

On Sun, Mar 13, 2011 at 8:30 PM, Josh Cheek <josh.cheek@gmail.com> wrote:

It says "Invokes the method identified by symbol, passing it any arguments
specified." A block is an argument...

--
baz(["some", {:args=>"for baz", :without=>"a block"}]) called without
a block included.
foo(["some", {:args=>"for baz", :without=>"a block"}]) called without
a block included.

baz(["some", {:args=>"for baz", :with=>"a block"}]) called with a
block included.
foo(["some", {:args=>"for baz", :with=>"a block"}]) called with a
block included.
block passed to baz(): ["some", {:args=>"for baz", :with=>"a block"}]

THINGS TO NOTE FROM THE EXAMPLE:
* Notice that even though bar() uses the splat to capture and pass
through all supplied arguments, because it does NOT explicitly include
a &block argument, it does NOT automatically pass through any provided
block.=
* Note that baz() DOES explicitly include a &block argument and
explicitly passes it through.

When I read documents and see a method that does NOT explicitly
mention a block, I assume that it will NOT pass any supplied block on
to yet another method.

Hence, I expect that the send() documentation really should mention
that any block passed to it IS passed through to the method specified
as the first argument to send().

Maybe I'm eccentric, but I prefer that documentation for a method
which uses a block, either directly or by passing it through to
another method, whether the block is explicit or implicit in the
method definition, to clearly document what the block is used for or
what is done with it.

Aaron out.

Why doesn't this work:

def my_meth(*args)
yield
p args
end

my_proc = Proc.new {puts 'hello'}
my_meth(1, 2, 3, &my_proc ) #=>'hello' [1, 2, 3]

obj = Object.new
m = obj.method(my_meth)
m.call([10, 20, 30], &my_proc) #LocalJumpError at yield line

Your comment about LocalJumpError should be one line above and it
occurs because you are calling my_meth without a block and are
attempting to yield to the non-existent block. You don't want
to invoke my_meth there, you want to *name* it:

m = obj.method('my_meth')

I think you are adding a confusing difference when you try to invoke
my_method on the last line by packaging up three arguments in an array.
If you want to follow the pattern you used when you called my_meth
directly you should be doing:

m.call(10, 20, 30, &my_proc)

Gary Wright

···

On Mar 14, 2011, at 6:24 PM, 7stud -- wrote:

I'm not sure what you're showing me here. But consider this:

class Foo
  def self.send(*a, &block)
    p block_given?
    super(*a)
  end
end

class Bar
  def self.send(*a)
    p block_given?
    super(*a)
  end
end

Foo.send(:define_method, :my_method) do |x|
  p x
end

block = proc{ |x| p x }
Bar.send(:define_method, :my_method2, &block)

foo = Foo.new
foo.my_method(1)
bar = Bar.new
bar.my_method2(2)

def my_method(x)
  p x
end

my_method(10, &block)

__END__
true
true
1
2
10

Even when you explicitly do /not/ pass on the block (as in the
super(*a) call above), send() does not consume it.
Passing a block using the &block syntax is simply part of ruby's
method calling syntax.
A method does not have to specify that it takes a block for you to
call it with one.

Regards,
Sean

···

On Sat, Mar 12, 2011 at 9:11 PM, Peter Zotov <whitequark@whitequark.org> wrote:

On Sun, 13 Mar 2011 06:01:31 +0900, Sean O'Halpin wrote:

On Sat, Mar 12, 2011 at 8:45 PM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

Why don't the ruby docs say that send() can take a block?

Kernel.send(:define_method, :my_meth) do |x|
puts x
end

It's not the send() that's consuming the block - it's the define_method().

But send() still bothers to pass the block around. Consider the following
code:

---8<---8<---
def my_method
p block_given?
end

def my_send # imitating send
my_method
end

my_send # => false
---8<---8<---

--
WBR, Peter Zotov.

Peter Zotov wrote in post #987115:

define_method().

But send() still bothers to pass the block around. Consider the
following code:

---8<---8<---
def my_method
   p block_given?
end

def my_send # imitating send
   my_method
end

my_send # => false
---8<---8<---

But compare with this:

def my_method
  p block_given?
end

def my_send(&blk) # imitating send
  my_method(&blk)
end

my_send # => false
my_send { :wibble } # => true

···

On Sun, 13 Mar 2011 06:01:31 +0900, Sean O'Halpin wrote:

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

Correct, a block IS an argument, but of a rather unusual type in that
it may or may not be explicit in the definition of a method that uses
it.

There is always a block slot, as Ryan said "ALL methods take a block". What
is explicit is whether or not you wish to assign it to a named object. Even
then, you can turn the implicit block into a Proc object, if you need.

def meth
  proc.call
end

meth { 1 + 1 } # => 2

When I read documents and see a method that does NOT explicitly

mention a block, I assume that it will NOT pass any supplied block on
to yet another method.

Hence, I expect that the send() documentation really should mention
that any block passed to it IS passed through to the method specified
as the first argument to send().

This is really all you needed to say. I think all your code detracted from
this point.

···

On Sun, Mar 13, 2011 at 10:47 PM, Aaron D. Gifford <astounding@gmail.com>wrote:

Gary Wright wrote in post #987429:

···

On Mar 14, 2011, at 6:24 PM, 7stud -- wrote:

obj = Object.new
m = obj.method(my_meth)
m.call([10, 20, 30], &my_proc) #LocalJumpError at yield line

Your comment about LocalJumpError should be one line above and it
occurs because you are calling my_meth without a block and are
attempting to yield to the non-existent block. You don't want
to invoke my_meth there, you want to *name* it:

m = obj.method('my_meth')

Ah, a typo. Thanks.

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

Indeed... Take that statement a step further: ALL methods take a block, they just don't have to do anything with it:

% ruby -e 'p 1.+(2) { p 42 }'
3

···

On Mar 12, 2011, at 13:50 , Sean O'Halpin wrote:

A method does not have to specify that it takes a block for you to
call it with one.

Why don't the ruby docs say that send() can take a block?

Kernel.send(:define_method, :my_meth) do |x|
  puts x
end

It's not the send() that's consuming the block - it's the define_method().

But send() still bothers to pass the block around. Consider the following
code:

---8<---8<---
def my_method
  p block_given?
end

def my_send # imitating send
  my_method
end

my_send # => false
---8<---8<---

--
  WBR, Peter Zotov.

I'm not sure what you're showing me here. But consider this:

class Foo
   def self.send(*a,&block)
     p block_given?
     super(*a)
   end
end

class Bar
   def self.send(*a)
     p block_given?
     super(*a)
   end
end

Foo.send(:define_method, :my_method) do |x|
   p x
end

block = proc{ |x| p x }
Bar.send(:define_method, :my_method2,&block)

foo = Foo.new
foo.my_method(1)
bar = Bar.new
bar.my_method2(2)

def my_method(x)
   p x
end

my_method(10,&block)

__END__
true
1
2
10

Even when you explicitly do /not/ pass on the block (as in the
super(*a) call above), send() does not consume it.

Automatic propagation of the block is not a feature of #send but a feature of "super":

>> class X
>> def a;p block_given? end
>> def b;p block_given?;a end
>> def c;p block_given?;send(:a) end
>> end
=> nil
>> X.new.a {1+2}
true
=> true
>> X.new.b {1+2}
true
false
=> false
>> X.new.c {1+2}
true
false
=> false

>> class A
>> def a;p block_given? end
>> end
=> nil
>> class B < A
>> def a;p block_given?;super end
>> end
=> nil
>> class C < A
>> def a;p block_given?;super() end
>> end
=> nil
>> A.new.a {1+2}
true
=> true
>> B.new.a {1+2}
true
=> true
>> C.new.a {1+2}
true
=> true

Passing a block using the&block syntax is simply part of ruby's
method calling syntax.
A method does not have to specify that it takes a block for you to
call it with one.

Correct.

Kind regards

  robert

···

On 12.03.2011 22:50, Sean O'Halpin wrote:

On Sat, Mar 12, 2011 at 9:11 PM, Peter Zotov<whitequark@whitequark.org> wrote:

On Sun, 13 Mar 2011 06:01:31 +0900, Sean O'Halpin wrote:

On Sat, Mar 12, 2011 at 8:45 PM, 7stud --<bbxx789_05ss@yahoo.com> wrote:

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

That's the whole point of my demonstration. (Maybe I was too concise.)
Any send-like method should to a trick like that to get the block-passing
behavior. It is not implicit.

···

On Sun, 13 Mar 2011 23:26:01 +0900, Brian Candler wrote:

Peter Zotov wrote in post #987115:

On Sun, 13 Mar 2011 06:01:31 +0900, Sean O'Halpin wrote:

define_method().

But send() still bothers to pass the block around. Consider the
following code:

---8<---8<---
def my_method
   p block_given?
end

def my_send # imitating send
   my_method
end

my_send # => false
---8<---8<---

But compare with this:

def my_method
  p block_given?
end

def my_send(&blk) # imitating send
  my_method(&blk)
end

my_send # => false
my_send { :wibble } # => true

--
   WBR, Peter Zotov.

Peter Zotov wrote in post #987115:

define_method().

But send() still bothers to pass the block around. Consider the
following code:

---8<---8<---
def my_method
p block_given?
end

def my_send # imitating send
my_method
end

my_send # => false
---8<---8<---

But compare with this:

def my_method
p block_given?
end

def my_send(&blk) # imitating send
my_method(&blk)
end

my_send # => false
my_send { :wibble } # => true

That's the whole point of my demonstration. (Maybe I was too concise.)

You were so concise you left out the thing you were trying to demonstrate:

def my_send
  p block_given?
end

my_send { p 42 } #=> true

Any send-like method should to a trick like that to get the block-passing
behavior. It is not implicit.

It /is/ implicit and is true for any method call. That's how you can do this:

def my_yield
  yield
end

my_yield { p 42 } #=> 42

You specify the &block parameter when you want to do something with the block.

Regards,
Sean

···

On Sun, Mar 13, 2011 at 2:54 PM, Peter Zotov <whitequark@whitequark.org> wrote:

On Sun, 13 Mar 2011 23:26:01 +0900, Brian Candler wrote:

On Sun, 13 Mar 2011 06:01:31 +0900, Sean O'Halpin wrote:

Peter Zotov wrote in post #987191:

That's the whole point of my demonstration. (Maybe I was too concise.)
Any send-like method should to a trick like that to get the
block-passing
behavior. It is not implicit.

Indeed. And the O.P. was passing a block to send explicitly too.

···

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

Or to put it another way:

def my_method
  p block_given?
end

def my_send # imitating send
  my_method
end

my_send # => false
my_send { :wibble } # => false

def my_send_2
  send :my_method
end

my_send_2 # => false
my_send_2 { :wibble } # => false

It's entirely consistent: false in all four cases.

The actual method "send" can take a block, and it passes it to the
method being invoked. If it didn't, it would be impossible to pass a
block to a method when invoking it using send.

···

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

I agree that the documentation the original post linked to really
should mention that if any block is passed to send, the block is
passed on to the method invoked.

From the linked docs: "Invokes the method identified by symbol,
passing it any arguments specified. You can use send if the name send
clashes with an existing method in obj."

That could use an additional sentence: "If a block is supplied to
send, the block is supplied to the method invoked."

Aaron out.

···

On Sun, Mar 13, 2011 at 11:00 AM, Brian Candler <b.candler@pobox.com> wrote:

The actual method "send" can take a block, and it passes it to the
method being invoked. If it didn't, it would be impossible to pass a
block to a method when invoking it using send.