It may be worthwhile looking at Shen (a similar lisp-like langauge) which targets translation to JS. I haven't checked in on their progress in a while, but it seems the largest implementation hurdle is tail recursion.
This "lisp in x lines of y" tradition started with the original Lisp paper back in 1960, which defined lisp in a few lines of lisp. Which, when you think about it, is an extraordinarily lispy thing to do.
I find it quite entertaining to see how specific language features allow for differing patterns. It is much more apparent with such Lisp implementations than with your typical Hello, World app or hidden by some library or framework.
That is begging the question. The argument was supposed to prove that Lisp is "awesome;" if you have to assume that Lisp is a "nice language" for the argument to work, the argument hasn't proven anything.
Why not? [:eq, 42, :a] isn't native syntax in any Lisp I've ever seen. This is Lisp-like data structures and evaluation of native Ruby types, not a whole Lisp compiler or even the reader. It doesn't seem like it'd be any harder to get Ruby-like data structures and evaluation of native Lisp types. What's the core of Ruby? class, def, and :send, perhaps? SICP 3.1.1 does pretty much just that.
I'm not sure it even makes sense to talk about a core of Ruby in the same sense. The semantic core of Ruby is very light, but while a small Lisp is recognizable Lisp, a "small Ruby" without the weight of the Ruby syntax and a whole slew of runtime libraries, is not really likely to be recognizable as Ruby.
What makes Ruby is all the sugar.
E.g. MRI 1.8.x has a parser alone that is about 6000 lines of Yacc with C actions and workarounds for Yacc limitations.
Your best bet for a semantic core of Ruby would probably seem closer to Smalltalk than to Ruby...
Ruby has a lot of special cases (the Proc versus block dichotomy, implicit conversions, etc). Scheme has shockingly clean semantics in comparison.
Implementing Lisp in a language without first class functions is quite easy. Closure conversion is a simple process:
1) Find every variable in the parent lambda that is both accessed in a child lambda and assigned-to outside the child lambda; demote those variables to heap-allocated cells and rewrite references to those variables to indirect through the cell.
2) Note every free variable in the child lambda, and rewrite all references to those variables to indirect through an environment vector passed in through a hidden argument.
3) Generate each lambda as a top-level function, and generate each lambda expression as the allocation of a callable object referencing the top-level function and a heap-allocated environment vector; at each allocation site, generate code to copy the free variables into the environment vector.
This is literally the entire algorithm. It can be implemented in a couple of hundred lines of C.
Whilst not supporting first class functions, C is pretty easy on you in that respect. I reckon there are suitably small lisp implementations in C (less than 100 lines). It all really depends if your lisp implementation uses the language's VM or a VM layer over the top.
In general, how do you write functions that return functions without some form of anonymous function? For instance, how do you write a function that takes an int a and returns a function that takes an int parameter and returns non-zero if and only if that parameter is greater than a?
If macros are needed for the definition of a lisp, then you'll eliminate some important Lisps. If you want macros in the one at the link (ulithp), then you only need to write that feature into an evaluator (dare I say, meta-circular) written in ulithp much like what is done in my other Lisp Lithp.
Link  looks very nice and IMO would be a much more interesting topic than the trivial ruby implementation.
I apologize for the dismissive rudeness of my first comment... I am tired of the many "I saved a function and its arguments into a list, and then wrote a method to evaluate that list" implementations which seem to be so exciting. Although I guess this isn't a new trend (see lisp in awk ).
I understand that (label second '(...)) makes second evaluate to that in the future, statefully, but, the lambda symbol doesn't even appear to have a definition; furthermore, if you try to use it in a way that would work with a real lambda, it doesn't work.
It's triggered when the `fn` is not callable, i.e. when we pass in lambda:
[:lambda, [:x], [:car, [:cdr, :x]]]
The code ignores the `:lambda` symbol (that would be `@env[fn]`).
It evals the third element of the list (the lambda body) in a new context that combines `@env` and the binding of lambda's args to the symbols in the lambda's definition -- that's what the `Hash` mumbo jumbo creates.