# Can you do Lisp-like macros in Ruby?

**URL:** <https://www.ruby-forum.com/t/can-you-do-lisp-like-macros-in-ruby/62379>\
**Category:** Ruby\
**Created:** [June 3, 2006, 2:53pm UTC](https://www.ruby-forum.com/t/can-you-do-lisp-like-macros-in-ruby/62379 "2006-06-03T14:53:17Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [June 3, 2006, 2:53pm UTC](https://www.ruby-forum.com/t/can-you-do-lisp-like-macros-in-ruby/62379/1 "2006-06-03T14:53:17Z")

</div>

I’ve never used lisp before until ~2am last night…and while working  
on the very simple unit testing framework in Practical Common Lisp [1]  
I came up with this macro:

(defun report-result (result form)  
(format t “~:[FAIL~;pass~] … ~a~%” result form))

(defmacro test (test-form)  
(let ((result (gensym)))  
`(let ((,result ,test-form))  
(report-result ,result ',test-form)  
,result)))

Using that macro, I can do:  
CL-USER\> (test (= (+ 1 2) 3))  
pass … (= (+ 1 2) 3)  
T

I really like the syntax of that. How could I do the same thing in  
Ruby? I took a quick shot and missed…it might be super easy and I’m  
just dumb from this apparent insomnia. I really like using Ruby, but  
I would absolutely love it if I could build syntax like I did with  
Lisp.

The Ruby translation of the syntax - not the code that actually makes  
it work - would be like

irb\> test { (1 + 2) == 3 }  
pass … (1 + 2) == 3

Okay here’s what I’ve come up with:

def report\_result(result, &block)  
message = result ? “pass” : “FAIL”  
puts “#{message} … #{block}”  
end

def test(&block)  
result = yield  
report\_result result, &block  
result  
end

irb\> test { (1 + 2) == 3 }  
pass … #Proc:0x00306b58@:55(irb)

So I guess the question is how to make the code show up.

Here’s my change:

def report\_result(result, code)  
message = result ? “pass” : “FAIL”  
puts “#{message} … #{code}”  
end

def test(code)  
result = eval code  
report\_result result, code  
result  
end

irb\> test “(1 + 2) == 3”  
pass … (1 + 2) == 3

I certainly don’t like sticking my code in a string like that. That  
just kind of sucks.

Over all this is kind of a lame example anyway. Just after spending  
some time with Lisp though, I get the feeling that I’ll be able to do  
some really cool stuff with it, stuff that I don’t know how to do in  
Ruby, despite using Ruby for several months now. I don’t know exactly  
what it is, but somehow I know that - at least with the Ruby coding  
style I used above - I won’t be able to do some things with Ruby that  
I would be able to in Lisp. I appreciate any feedback…hopefully you  
guys don’t think I’m out in left field with this.

Pat

[1] [Practical Common Lisp](http://www.gigamonkeys.com/book/)

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [June 3, 2006, 5:22pm UTC](https://www.ruby-forum.com/t/can-you-do-lisp-like-macros-in-ruby/62379/2 "2006-06-03T17:22:01Z")

</div>

On Jun 3, 2006, at 8:52 AM, Pat M. wrote:

> ```
> (report-result ,result ',test-form)
> 
> ```
> 
> I would absolutely love it if I could build syntax like I did with  
> def report\_result(result, &block)  
> irb\> test { (1 + 2) == 3 }
> 
> just kind of sucks.  
> Pat
> 
> [1] [Practical Common Lisp](http://www.gigamonkeys.com/book/)

It seems like just giving a Proc a copy of the code used to create it  
would do this. There might even be a nice way to do it behind the  
scenes that wouldn’t require actually storing a string. But I don’t  
see any way to do this myself right now. Maybe some tricks with  
stack tracing?  
I do agree that Lisp has some neat tricks, but it made my eyes hurt  
trying to figure out where all the parens in that code started and  
stopped…  
-Mat

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [June 3, 2006, 7:54pm UTC](https://www.ruby-forum.com/t/can-you-do-lisp-like-macros-in-ruby/62379/3 "2006-06-03T19:54:37Z")

</div>

> `(let ((,result ,test-form))  
> (report-result ,result ',test-form)  
> ,result)))  
> […]

Just in case you missed this great article, here it is:

```
http://www.artima.com/rubycs/articles/patterns_sexp_dsls3.html

```

and among other things it talks exactly about this: S-Expressions.

Hope it helps,  
Alex

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [June 4, 2006, 7:26am UTC](https://www.ruby-forum.com/t/can-you-do-lisp-like-macros-in-ruby/62379/4 "2006-06-04T07:26:51Z")

</div>

On Jun 3, 2006, at 12:17 PM, Elliot T. wrote:

> On Jun 3, 2006, at 8:19 AM, Mat S. wrote:
> 
> > I do agree that Lisp has some neat tricks, but it made my eyes  
> > hurt trying to figure out where all the parens in that code  
> > started and stopped…  
> > most of the parentheses can be ignored because the whitespace  
> > contains the same information. like in ruby we use whitespace to  
> > read nested do/end blocks.

Yeah, that probably came off stronger than I intended. I’m sure like  
anything else, you get used to it after awhile. I’m just not used to  
it in the least.  
-Mat

---

<div class="post-metadata">

**Author:** ![pergesu](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/22d042/32.png) [@pergesu](https://www.ruby-forum.com/u/pergesu)\
**Post date:** [June 3, 2006, 6:19pm UTC](https://www.ruby-forum.com/t/can-you-do-lisp-like-macros-in-ruby/62379/5 "2006-06-03T18:19:57Z")

</div>

On Jun 3, 2006, at 8:19 AM, Mat S. wrote:

> I do agree that Lisp has some neat tricks, but it made my eyes hurt  
> trying to figure out where all the parens in that code started and  
> stopped…

most of the parentheses can be ignored because the whitespace  
contains the same information. like in ruby we use whitespace to read  
nested do/end blocks.

for the paren that can’t be ignored, the information is necessary to  
prevent ambiguity about grouping things together. all languages have  
to express that information somehow.

ruby does

foo(bar(x,y),z)

and lisp does

(foo (bar x y) z)

Those are almost the same (all the identifiers are in the same order  
(prefix, not infix, for both lisp and ruby)). the lisp version is IMO  
a little nicer. certainly nothing worth hating.

ruby does other things as well, like using dots: “c,b,a”.split  
(“,”).sort.join. maybe that is even nicer. lisp could do that too, if  
you wanted it to.

– Elliot T.

> **[Curiosity Blog – Elliot Temple](https://www.curi.us/blog/)**
>
> A philosophy blog
