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

On Mar 14, 2007, at 20:04 , 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

For example

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

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ö [email protected] wrote:

 def initialize(array)

class Trampoline
def trampoline(&block)
trampoline { |symbol, *args| each { |o| o.send(symbol,
trampoline do |method, *args|

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?

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 14 Mar 2007, at 19:57, Jason R. 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:

On Mar 14, 2007, at 23:48 , Benjohn B. wrote:

I don’t really see that it makes for an especially more concise
No, you’re right, I am getting old :wink:
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 3/14/07, Benjohn B. [email protected] wrote:

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?”

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.

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


Rick DeNatale

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

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

On 15.03.2007 21:28, Rick DeNatale wrote:

       wants.js

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.

Agreed. :wink:

Kind regards

robert

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

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

  @array.each { |entry| entry.__send__(symbol, *args) }

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 Mar 16, 2007, at 07:25 , Brian C. wrote:

  @array.each { |entry| entry.__send__(symbol, *args) }

array.each_do(:do_something, 1, “a”)

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

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 14, 2007, at 23:48 , Benjohn B. wrote:

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.

/Christoffer

On 3/16/07, Christoffer Lernö [email protected] wrote:

in, and it’s readable too!

message = “Hello”

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 Mar 16, 2007, at 13:21 , Robert D. wrote:

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

On Mar 16, 2007, at 1:32 PM, Jenda K. 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.

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

Christoffer Lernö wrote:

On Mar 14, 2007, at 20:04 , 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 3/16/07, Christoffer Lernö [email protected] wrote:

With normal each:

instance is created or each iterator call in #each_do.broadcast,

No, each_do will only create BroadcastChatPacket once.

/Christoffer

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/14/07, Christoffer Lernö [email protected] wrote:

/Christoffer

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/16/07, Rick DeNatale [email protected] wrote:

On 3/15/07, Robert D. [email protected] wrote:

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!”
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.
    no
    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/15/07, Robert D. [email protected] wrote:

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!”


Rick DeNatale

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