Christoffer Lernö
3/15/2007 6:14:00 AM
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 ;-)
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