From: Brian Mitchell Date: 2007-03-15T09:26:22+09:00 Subject: Re: Anyone playing with higher order messaging in ruby? On 3/14/07, Christoffer Lernæ—¦ 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? I've not really liked that style specifically, but it reminds me of aquick *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}] endend Of course, it isn't perfect (only spent about 15 min on it)... it wasjust meant to be a 100% self contained method (my original had cleanercode 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 inmy .irbrc file for quick manipulations that Symbol#to_proc doesn'thandle: [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 ;-)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 codeif anyone wants something that qualifies as less of a hack. Brian.