Anyone playing with higher order messaging in ruby?

For example, something that I often want to do is:

array.each { |entry| entry.do_something(1, "a") }

If you know you're doing things like this a lot, there is an obvious shortcut:

class Array

   class Forwarder
     def initialize(array)
       @array = array
     end
     def method_missing(symbol, *args)
       @array.each { |entry| entry.__send__(symbol, *args) }
     end
   end

   def each_do
     Forwarder.new(self)
   end

end

Now you can do:

array.each_do.do_something(1, "a")

In a more generalized case, you want to use a block to act as a class.

module Trampolines
   class Trampoline
     def initialize(block)
       @block = block
     end
     def method_missing(symbol, *args, &block)
       args << block if block
       @block.call(symbol, *args)
     end
   end
end

def trampoline(&block)
   raise "Missing block" unless block
   Trampolines::Trampoline.new(block)
end

Here we could define

class Array
   def each_do2
     trampoline { |symbol, *args| each { |o| o.__send__(symbol, *args) } }
   end
end

Which would work the same way as the previous code.

But you could also do things like

def wait(time)
   trampoline do |method, *args|
    # queue_event executes the block after time seconds
     queue_event(time) { self.__send__(method, *args) }
   end
end

And write code like:

wait(5).shutdown("Shutdown in seconds")
wait(10).shutdown("Shutdown in 5 seconds")
wait(15).shutdown_now

Instead of wrapping it in blocks.

Other people must have played around with this.

I'd like to learn more about using these methods, so are there any links and sites people could share with me?

/Christoffer

This code adds methods to all enumerables.

module Enumerable
   %w(each collect select reject).each do |method|
     class_eval "def #{method}_do; trampoline { |m, b, *a| #{method} { |o| o.__send__(m, *a, &b) } }; end"
   end
end

For example

["a", "b", "c"].reject_do[/a/] # => ["b", "c"]
["a", "b", "c"].collect_do.capitalize #=> ["A", "B", "C"]

···

On Mar 14, 2007, at 20:04 , Christoffer Lernö wrote:

In a more generalized case, you want to use a block to act as a class.

module Trampolines
  class Trampoline
    def initialize(block)
      @block = block
    end
    def method_missing(symbol, *args, &block)
      args << block if block
      @block.call(symbol, *args)
    end
  end
end

def trampoline(&block)
  raise "Missing block" unless block
  Trampolines::Trampoline.new(block)
end

I've not really liked that style specifically, but it reminds me of a
quick *hack* I put together a while ago:

def it
  itify = lambda {|proc|
    class << proc; self end.class_eval do
      instance_methods.each {|m| undef_method m unless m =~ /^__/}
      define_method :__itify__, &itify
      def method_missing(*a, &b)
        __itify__(Proc.new {|x|
Proc.instance_method(:call).bind(self).call(x).send(*a, &b)})
      end
    end
    proc
  }
  if block_given?
    itify[Proc.new]
  else
    itify[Proc.new {|x| x}]
  end
end

Of course, it isn't perfect (only spent about 15 min on it)... it was
just meant to be a 100% self contained method (my original had cleaner
code but had a named sub-class of Proc, removing the need for the odd
__itify__ method). The reason for the style is that I dropped this in
my .irbrc file for quick manipulations that Symbol#to_proc doesn't
handle:

[1,2,3].map &it + 2 #=> [3, 4, 5]
['1', 2.0, 3].map &it.to_i.to_s(2) #=> ['1', '10', '11']
# or pass it around :wink:
to_constant = it.split('::').inject(Object) {|m,x| m.const_get(x)}
['Object', 'Date::Format', 'Math::PI'].map &to_constant

If anyone wants, I can see if I can fish around for the original code
if anyone wants something that qualifies as less of a hack.

Brian.

···

On 3/14/07, Christoffer Lernö <lerno@dragonascendant.com> wrote:

For example, something that I often want to do is:

array.each { |entry| entry.do_something(1, "a") }

If you know you're doing things like this a lot, there is an obvious
shortcut:

class Array

   class Forwarder
     def initialize(array)
       @array = array
     end
     def method_missing(symbol, *args)
       @array.each { |entry| entry.__send__(symbol, *args) }
     end
   end

   def each_do
     Forwarder.new(self)
   end

end

Now you can do:

array.each_do.do_something(1, "a")

In a more generalized case, you want to use a block to act as a class.

module Trampolines
   class Trampoline
     def initialize(block)
       @block = block
     end
     def method_missing(symbol, *args, &block)
       args << block if block
       @block.call(symbol, *args)
     end
   end
end

def trampoline(&block)
   raise "Missing block" unless block
   Trampolines::Trampoline.new(block)
end

Here we could define

class Array
   def each_do2
     trampoline { |symbol, *args| each { |o| o.__send__(symbol,
*args) } }
   end
end

Which would work the same way as the previous code.

But you could also do things like

def wait(time)
   trampoline do |method, *args|
    # queue_event executes the block after time seconds
     queue_event(time) { self.__send__(method, *args) }
   end
end

And write code like:

wait(5).shutdown("Shutdown in seconds")
wait(10).shutdown("Shutdown in 5 seconds")
wait(15).shutdown_now

Instead of wrapping it in blocks.

Other people must have played around with this.

I'd like to learn more about using these methods, so are there any
links and sites people could share with me?

For example, something that I often want to do is:

array.each { |entry| entry.do_something(1, "a") }

If do_something doesn't take any arguments then there's the hack which
allows

   array.each(&:do_something)

See http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html

If you know you're doing things like this a lot, there is an obvious
shortcut:

class Array

  class Forwarder
    def initialize(array)
      @array = array
    end
    def method_missing(symbol, *args)
      @array.each { |entry| entry.__send__(symbol, *args) }
    end
  end

  def each_do
    Forwarder.new(self)
  end

end

Now you can do:

array.each_do.do_something(1, "a")

or just:

module Enumberable
  def each_do(meth, *args, &blk)
    each { |item| item.send(meth, *args, &blk) }
  end
end

array.each_do(:do_something, 1, "a")

which has the advantage that do_something can take a block too, if you wish.

B.

···

On Thu, Mar 15, 2007 at 04:04:01AM +0900, Christoffer Lern? wrote:

I wrote this some time ago:

class Message
  def initialize(message, *args)
    @message, @args = message, args
  end

  def call(x, *args)
    x.send @message, *(@args + args)
  end

  def to_proc
    lambda { |*args| call(*args) }
  end
end

Now you can do:

  puts [*0..100].select(&Message.new(:>, 50)).inspect
  puts [*0..100].inject(&Message.new(:+))
  puts %w(Once upon a time).map(&Message.new(:upcase)).inspect
  puts Message.new(:index, /[aeiou]/, -3).call("hello")
  puts %w(1 2 3 4 5).map(&Message.new(:to_i)).map(&Message.new(:class)).inspect

The &Message.new syntax is a bit verbose, so you could alias it:

def _(msg, *args)
  Message.new(msg, *args)
end

And then it runs smooth:

  puts [*0..100].select(&_(:>, 50)).inspect

I don't know if this helps. It does do away with the need for
method_missing or changing core classes or stuff like that. I don't
know how useful it is, because I've never used it for anything
serious. If it was to be really useful, it should've been incorporated
into the language and standard libraries.

···

On 3/14/07, Christoffer Lernö <lerno@dragonascendant.com> wrote:

For example, something that I often want to do is:

array.each { |entry| entry.do_something(1, "a") }

[...]

Other people must have played around with this.

I'd like to learn more about using these methods, so are there any
links and sites people could share with me?

/Christoffer

--
- Simen

I haven't personally messed with this kind of stuff but code like this just
makes me love Ruby even more. These types of, well DSL is really the best
way to describe it, in such little code, makes Ruby such a blast to program
in, and it's readable too!

Jason

···

On 3/14/07, Christoffer Lernö <lerno@dragonascendant.com> wrote:

On Mar 14, 2007, at 20:04 , Christoffer Lernö wrote:

> In a more generalized case, you want to use a block to act as a class.
>
> module Trampolines
> class Trampoline
> def initialize(block)
> @block = block
> end
> def method_missing(symbol, *args, &block)
> args << block if block
> @block.call(symbol, *args)
> end
> end
> end
>
> def trampoline(&block)
> raise "Missing block" unless block
> Trampolines::Trampoline.new(block)
> end

This code adds methods to all enumerables.

module Enumerable
   %w(each collect select reject).each do |method|
     class_eval "def #{method}_do; trampoline { |m, b, *a| #{method}
{ |o| o.__send__(m, *a, &b) } }; end"
   end
end

For example

["a", "b", "c"].reject_do[/a/] # => ["b", "c"]
["a", "b", "c"].collect_do.capitalize #=> ["A", "B", "C"]

Well, actually you might want to pass around the result of each_do to something else, this is why I believe that in most cases the former version is preferable.

Consider a chat server where @clients = [connection1, connection2...]

assuming each connection has a method like "broadcast_chat", the code looks like this:

@clients.each_do.broadcast_chat(incoming_chat)

I like it because it feels clear what is happening and that this is the same as

@clients.each { |c| c.broadcast_chat(incoming_chat) }

Here

@cliente.each_do(:broadcast_chat, incoming_chat)

is not as obvious when it comes to detemining what is the action and what is the data.

···

On Mar 16, 2007, at 07:25 , Brian Candler wrote:

If you know you're doing things like this a lot, there is an obvious
shortcut:

class Array

  class Forwarder
    def initialize(array)
      @array = array
    end
    def method_missing(symbol, *args)
      @array.each { |entry| entry.__send__(symbol, *args) }
    end
  end

  def each_do
    Forwarder.new(self)
  end

end

Now you can do:

array.each_do.do_something(1, "a")

or just:

module Enumberable
  def each_do(meth, *args, &blk)
    each { |item| item.send(meth, *args, &blk) }
  end
end

array.each_do(:do_something, 1, "a")

which has the advantage that do_something can take a block too, if you wish.

Christoffer Lernö wrote:

    end
  end
end

def trampoline(&block)
  raise "Missing block" unless block
  Trampolines::Trampoline.new(block)
end

This code adds methods to all enumerables.

module Enumerable
   %w(each collect select reject).each do |method|
     class_eval "def #{method}_do; trampoline { |m, b, *a| #{method}
{ |o| o.__send__(m, *a, &b) } }; end"
   end
end

Looks to me that it's easier to extend the Forwarder a bit and implement
this like this:

class Forwarder
  def initialize(obj, method)
    @obj = obj
    @method = method
  end
  def method_missing(symbol, *args)
    @obj.__send__( @method) { |entry| entry.__send__(symbol, *args) }
  end
end

module Enumerable
   %w(each collect select reject).each do |method|
     class_eval "def #{method}_do; Forwarder.new(self, :#{method}) end"
   end
end

it's a shame the builtins do not work like this already. And while it's
possible to overwrite the "collect", "select" and "reject" in
Enumerable, to overwrite the "each" you'd (AFAIK) have to touch all the
individual classes.

I should not have to name something I only use once:

list.each { |x| x.whatever() }

Jenda

···

On Mar 14, 2007, at 20:04 , Christoffer Lern� wrote:

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

I think I must be getting too old, or I'm being a spring time Scrouge...

While it's neat, and it's cool Ruby can do that stuff, I've got to ask "Why?".

I've come across this used in DSLs, but I generally think, "I'm sure you're going to get in to trouble down the line. Why don't you just use the regular syntax?"

I don't really see that it makes for an especially more concise program, and really, it just seems to be introducing a different syntax that's kind of crow bared in as an overloading of the current syntax and semantics: as such, it doesn't seem to act in an expected way. Frankly, it all seems reminiscent of some of the c++ template techniques which, while terribly clever, don't generally seem to actually achieve a lot that can't be done more simply in other ways; and introduce so much complexity that even a seriously good coder's complexity budget is nearly all used up with a very small problem.

No, you're right, I am getting old :wink:

···

On 14 Mar 2007, at 19:57, Jason Roelofs wrote:

I haven't personally messed with this kind of stuff but code like this just
makes me love Ruby even more. These types of, well DSL is really the best
way to describe it, in such little code, makes Ruby such a blast to program
in, and it's readable too!

Somewhat related....

In Ruby 1.9 iterating methods (I couldn't think of a better term) such
as each, map, and so on return an Enumerator object if a block isn't
provided. This makes it easier to add the magic dot behavior:

class Enumerable::Enumerator
   def method_missing(*args, &block)
     each { |x| x.send(*args, &block ) }
   end
end

[1,-2,3,-4].map.abs # [1,2,3,4]
[1,-2,3,-4].map.abs.map.succ # [2,3,4,5]
%w{mon tue wed}.map.capitalize # ["Mon", "Tue", "Wed"]`

This works because Enumerable::Enumerator#each returns the original
collection (instead of the iterator) when a block is provided.

[1,2].each.class # Enumerator
[1,2].each.each.class # Enumerator
[1,2].each.each {}.class # Array

Gary Wright

···

On Mar 16, 2007, at 1:32 PM, Jenda Krynicky wrote:

it's a shame the builtins do not work like this already. And while it's
possible to overwrite the "collect", "select" and "reject" in
Enumerable, to overwrite the "each" you'd (AFAIK) have to touch all the
individual classes.

For code like this:

subscribers.send_message(:chat, @current_user, chat_text)

Instead of

subscribers.each { |s| s.add_to_queue(:send_message, [:chat, @current_user, chat_text]) }

It is also useful for transactions, where you can define a trampoline like this (writing this code in my mail program, it probably has bugs):

def transaction
  queue =
  $exec = trampoline { |method, *args| @queue << [method, args] }
  yield
  queue.each do |method, args|
    __send__(method, *args)
  end
end

def exec
  $exec
end
  
Now you write code like this

transaction do
  do_something
  exec.start_system1
  do_something_else
  raise "Some error" if (something_failed)
  exec.start_system2
end

If the transaction works, both start_system1 and start_system2 is called. Otherwise neither happens.

It helps making the code straightforward, especially if the start_system calls are IO or similar that is difficult to reverse.

/Christoffer

···

On Mar 14, 2007, at 23:48 , Benjohn Barnes wrote:

On 14 Mar 2007, at 19:57, Jason Roelofs wrote:

I haven't personally messed with this kind of stuff but code like this just
makes me love Ruby even more. These types of, well DSL is really the best
way to describe it, in such little code, makes Ruby such a blast to program
in, and it's readable too!

I think I must be getting too old, or I'm being a spring time Scrouge...

While it's neat, and it's cool Ruby can do that stuff, I've got to ask "Why?".

I've come across this used in DSLs, but I generally think, "I'm sure you're going to get in to trouble down the line. Why don't you just use the regular syntax?"

I don't really see that it makes for an especially more concise program, and really, it just seems to be introducing a different syntax that's kind of crow bared in as an overloading of the current syntax and semantics: as such, it doesn't seem to act in an expected way. Frankly, it all seems reminiscent of some of the c++ template techniques which, while terribly clever, don't generally seem to actually achieve a lot that can't be done more simply in other ways; and introduce so much complexity that even a seriously good coder's complexity budget is nearly all used up with a very small problem.

No, you're right, I am getting old :wink:

Yes it's powerful, and it's useful, but it needs to be done with
thought and care. We used to call similar things like this in
Smalltalk "stupid Smalltalk tricks." It's like any other tool, it can
be used for good or evil, it's the workman who determines this.

I just blogged about some of the ramifications of this this morning.
(see my signature for the URL of my blog).

Rails makes use of this and similar techniques a lot. Two examples,
which I've recently encountered reading the rails code:

1) Named routes. Normally you set up routes which represent mappings
between urls and actions and their parameters with the connect method
of an internal class called ActionController::Routing::RouteSet in
code like this, in your config/routs.rb file:

    ActionController::Routing::Routes.draw do | map |
        map.connect ':controller/xyz/:arg1/:arg2'
    end

Routes are used both to map an incoming url to an controller, action
and parameters, and also to map the other way to generate a url.
Routes defined above are anonymous, when asked to generate a url it
picks which route to use itself. But you can also name routes so that
you can explicitly give a particular route to use when generating a
url. Let's say you want to
name that route above xyz. To do this you use the method xyz instead
of connect:

      map.xyz 'controller/xyz/:arg1/:arg1'

which does the same thing as above but also defines a helper method
called xyz_url.

Of course the mechanism used to do this is to catch :xyz with
method_missing and turn it into a call to named_route passing the name
(:xyz) and any other parameters, which in turn invokes connect and
then creates the helper.

2) mime content negotiation

   An action might be able to respond to a request with more than one
mime-type. An HTTP request can give a prioritized lists of mime-types
which the client will accept. The way to handle this negotiation in
an action is to use the respond_to method you might have code in an
action like:

    respond_to do |wants|
            wants.html { redirect_to(person_list_url) }
            wants.js
            wants.xml { render :xml => @person.to_xml(:include => @company) }
      end

What this code says is something like:
     if the requester wants html redirect to the person_list_url
     if the requester wants java script perform the normal rendering
for javascript (such as look for an rjs template with the right name
and render that)
     etc.

It's kind of like a case statement, except what really happens also
depends on which of those alternatives came first in the requests list
of acceptable types.

Now what happens under the covers is that the respond_to method
creates an ActionController::MimeResponds::Responder object which
becomes map in the code above. Then it yields to the block. The html
method adds html to the list of available mime types, along with the
block, or as in the case of the invocation of the js method where no
block is given, a default block. Then once the block given to
respond_to returns, the Responder is asked to respond by executing the
first block found using the list of requested mime-types.

In Rails 1.2, ActionController::MimeResponds:Responder uses
method__missing to support new mime types not 'baked in' to Rails.

These are just two examples from Rails, there are many more.

It's good to read such carefully crafted code and understand the
techniques and the possibilities, but I'd caution about getting too
carried away with such things before you are ready, and most folks
thing they are ready before they really are. <G>

···

On 3/14/07, Benjohn Barnes <benjohn@fysh.org> wrote:

On 14 Mar 2007, at 19:57, Jason Roelofs wrote:

> I haven't personally messed with this kind of stuff but code like
> this just
> makes me love Ruby even more. These types of, well DSL is really
> the best
> way to describe it, in such little code, makes Ruby such a blast to
> program
> in, and it's readable too!

I think I must be getting too old, or I'm being a spring time Scrouge...

While it's neat, and it's cool Ruby can do that stuff, I've got to
ask "Why?".

I've come across this used in DSLs, but I generally think, "I'm sure
you're going to get in to trouble down the line. Why don't you just
use the regular syntax?"

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

And another example:

# A chat server where @clients = [connection1, connection2...]
# message = "Hello"
# sender = "Bob"

# With normal each:
packet = BroadcastChatPacket.new("#{sender} says: #{message}")
@clients.each { |c| c.broadcast(packet) }

# With each_do:
@clients.each_do.broadcast(BroadcastChatPacket.new("#{sender} says: #{message}"))

Eliminating the need for the temporary variable.

/Christoffer

···

On Mar 14, 2007, at 23:48 , Benjohn Barnes wrote:

On 14 Mar 2007, at 19:57, Jason Roelofs wrote:

I haven't personally messed with this kind of stuff but code like this just
makes me love Ruby even more. These types of, well DSL is really the best
way to describe it, in such little code, makes Ruby such a blast to program
in, and it's readable too!

I think I must be getting too old, or I'm being a spring time Scrouge...

While it's neat, and it's cool Ruby can do that stuff, I've got to ask "Why?".

--------------------- 8< ---------------------

module Enumerable
    class MapProxy
        def initialize obj
            @obj = obj
        end #def initialize obj
        def method_missing name, *args, &blk
            @obj.map do
                > ele |
                ele.send name, *args, &blk
            end
        end #def method_missing name, *args, &blk
    end #class MapProxy

    alias_method :aliased_map, :map
    def map *args, &blk
        return MapProxy.new( self ) if args.length.zero? && blk.nil?
        aliased_map *args, &blk
    end #def map *args, &blk
end #module Enumerable

---------------- 8< --------------------

This is from a thread of 2006-09-27 posted the 28th, looks familiar
it was about "for or against the magic dot notation" but the
functionality is the same :slight_smile:

the French say: "Les grands esprits se resemblent", but my modesty
forbids any translations :wink:

Cheers
Robert

2) mime content negotiation

  An action might be able to respond to a request with more than one
mime-type. An HTTP request can give a prioritized lists of mime-types
which the client will accept. The way to handle this negotiation in
an action is to use the respond_to method you might have code in an
action like:

   respond_to do |wants|
           wants.html { redirect_to(person_list_url) }
           wants.js
           wants.xml { render :xml => @person.to_xml(:include => @company) }
     end

What this code says is something like:
    if the requester wants html redirect to the person_list_url
    if the requester wants java script perform the normal rendering
for javascript (such as look for an rjs template with the right name
and render that)
    etc.

It's kind of like a case statement, except what really happens also
depends on which of those alternatives came first in the requests list
of acceptable types.

That is no difference to case statements: with those, order matters as well:

>> x="foo"
=> "foo"
>> case x
>> when /fo/; puts 1
>> when /oo/; puts 2
>> else puts 0
>> end
1
=> nil
>> case x
>> when /oo/; puts 2
>> when /fo/; puts 1
>> else puts 0
>> end
2
=> nil

I think the major difference (apart from syntactical aspects) is the execution time. Of course this could also be mimicked with a case statement by returning a Proc but the Rails version looks much more elegant.

It's good to read such carefully crafted code and understand the
techniques and the possibilities, but I'd caution about getting too
carried away with such things before you are ready, and most folks
thing they are ready before they really are. <G>

Agreed. :wink:

Kind regards

  robert

···

On 15.03.2007 21:28, Rick DeNatale wrote:

>
>> I haven't personally messed with this kind of stuff but code like
>> this just
>> makes me love Ruby even more. These types of, well DSL is really
>> the best
>> way to describe it, in such little code, makes Ruby such a blast
>> to program
>> in, and it's readable too!
>
> I think I must be getting too old, or I'm being a spring time
> Scrouge...
>
> While it's neat, and it's cool Ruby can do that stuff, I've got to
> ask "Why?".

And another example:

# A chat server where @clients = [connection1, connection2...]
# message = "Hello"
# sender = "Bob"

# With normal each:
packet = BroadcastChatPacket.new("#{sender} says: #{message}")
@clients.each { |c| c.broadcast(packet) }

# With each_do:
@clients.each_do.broadcast(BroadcastChatPacket.new("#{sender} says: #
{message}"))

Eliminating the need for the temporary variable.

Do I understand correctly when I remark that a new BroadcastChatPacket
instance is created or each iterator call in #each_do.broadcast,

If not than it is just the same as
@clients.each{ |c| c.broadcast BCP.new... }

in this context I do not really see the practical interest though I
*obviously* like that style as I have shown above.

Well 6 months is a long time, but no I still like this magic dot notation.

Cheers
Robert

···

On 3/16/07, Christoffer Lernö <lerno@dragonascendant.com> wrote:

On Mar 14, 2007, at 23:48 , Benjohn Barnes wrote:
> On 14 Mar 2007, at 19:57, Jason Roelofs wrote:
/Christoffer

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

No, each_do will only create BroadcastChatPacket once.

/Christoffer

···

On Mar 16, 2007, at 13:21 , Robert Dober wrote:

On 3/16/07, Christoffer Lernö <lerno@dragonascendant.com> wrote:

And another example:

# A chat server where @clients = [connection1, connection2...]
# message = "Hello"
# sender = "Bob"

# With normal each:
packet = BroadcastChatPacket.new("#{sender} says: #{message}")
@clients.each { |c| c.broadcast(packet) }

# With each_do:
@clients.each_do.broadcast(BroadcastChatPacket.new("#{sender} says: #
{message}"))

Eliminating the need for the temporary variable.

Do I understand correctly when I remark that a new BroadcastChatPacket
instance is created or each iterator call in #each_do.broadcast,

Usually rendered in English as "Great minds think alike."

Then again I had a good friend from England some years ago who never
failed to follow that phrase with "or fools fail to differ!" <G>

···

On 3/15/07, Robert Dober <robert.dober@gmail.com> wrote:

the French say: "Les grands esprits se resemblent", but my modesty
forbids any translations :wink:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Sure got confused it is evaluated in method_missing only once, good,
thx for clarifying, I see the practical benefit now too.

Robert

···

On 3/16/07, Christoffer Lernö <lerno@dragonascendant.com> wrote:

On Mar 16, 2007, at 13:21 , Robert Dober wrote:

> On 3/16/07, Christoffer Lernö <lerno@dragonascendant.com> wrote:
>> And another example:
>>
>> # A chat server where @clients = [connection1, connection2...]
>> # message = "Hello"
>> # sender = "Bob"
>>
>> # With normal each:
>> packet = BroadcastChatPacket.new("#{sender} says: #{message}")
>> @clients.each { |c| c.broadcast(packet) }
>>
>> # With each_do:
>> @clients.each_do.broadcast(BroadcastChatPacket.new("#{sender} says: #
>> {message}"))
>>
>> Eliminating the need for the temporary variable.
>>
> Do I understand correctly when I remark that a new BroadcastChatPacket
> instance is created or each iterator call in #each_do.broadcast,

No, each_do will only create BroadcastChatPacket once.

/Christoffer

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

> the French say: "Les grands esprits se resemblent", but my modesty
> forbids any translations :wink:

Usually rendered in English as "Great minds think alike."

Then again I had a good friend from England some years ago who never
failed to follow that phrase with "or fools fail to differ!" <G>

I can still learn from your modesty :))
But sigh Rick you see nobody cares for my code I will have to sell it
to Microsoft :wink:
And as an eventual side remark - after the defeat at Twickenham ARGHHH
- it is good to know that Englishmen can have friends too. <ducking>
no <digging a hole>
but what do I fear? they have the best humor of the world, really,
like e.g. Monthy Ruby's

... ok I guess I need some sleep now.

Robert

···

On 3/16/07, Rick DeNatale <rick.denatale@gmail.com> wrote:

On 3/15/07, Robert Dober <robert.dober@gmail.com> wrote:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw