The document describes a talk given by Yusuke Endoh on esoteric and obfuscated programming in Ruby. Some key points:
- Endoh is a committer for MRI Ruby and works on performance improvements at Cookpad.
- He demonstrates programming in Ruby using only symbol characters to produce "Hello, World!" output.
- Endoh also shows code written using only alphabetic characters to produce the same output, by abusing features of Ruby's open classes and control structures.
- The goal is to explore Ruby's power and flexibility by writing very unusual code, inspired by esoteric programming languages like Brainfuck.
3. My contributions for Ruby
• The release manager for 2.0
• Implemented coverage.so,
keyword arguments, etc.
• OptCarrot: A NES emulator
for Ruby3x3 benchmark
• Branch coverage (Ruby 2.5)
↑OptCarrot .
https://eregon.me/blog/2016/11/28/optcarrot.html
http://engineering.appfolio.com/appfolio-engineering/2017/9/22/optcarrot-an-excellent-cpu-benchmark-for-ruby-3x3
4. Today's Topic: Ruby's power
• "Ruby is easy to read and write"?
– Incorrect
• Ruby is just rich and flexible
– Easy to write an easy-to-read code
– Also, easy to write a hard-to-read code
• I show you my bad examples
– (Note: I'll talk about nothing useful)
7. Demo
• "Hello, RubyConf!" program written
using only symbol characters
$ ruby symbols.rb
Hello, RubyConf!
$
8. Spoiler
• If you want to read it yourself…
• Three key techniques
– How to make a number (by only symbols)
– How to make a string (by only symbols)
– How to print a string (by only symbols)
9. Spoiler: How to make a number
• String#=~ returns the beginning index
of matched substring
• Calculation to make a large number
"Hello, RubyConf!" by Symbols
"@" =~ /$/ #=> 1
"@@" =~ /$/ #=> 2
"@@@" =~ /$/ #=> 3
_ = ("@@"=~/$/) # assigns 2 to _
_*_*_*_ #=> 16
10. Spoiler: How to make a string
• String#<< treats an integer as a
codepoint (ASCII code)
"Hello, RubyConf!" by Symbols
"" << 72 << 101 << 108 << 108 << 111
#=> "Hello"
11. Spoiler: How to print a string
• $> is $stdout
• IO#<< writes its argument to the IO
"Hello, RubyConf!" by Symbols
$> << "Hello"
13. Spoiler: More Complex Code?
• Q. Can we write a more complex code
than "Hello, world!"?
• A. Yes! There is a great idiom to call
"eval" by using only symbols
• Exercise: Explain how it works
->(&_){
_["", "eval", "<YOUR RUBY CODE>"]
}[&:"#{ "send" }"]
"Hello, RubyConf!" by Symbols
Replace them by using the previous techniques
14. Question 2: Can you read?
90-line code by only alphabets!
begin begin begin public begin begin def each
clear rescue begin begin begin end end end
concat begin dup ensure concat begin clear
concat concat concat concat concat concat size
concat begin begin begin size end end end
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
begin concat concat size end until hex
concat concat concat concat begin size end
concat concat begin size end rescue upcase
begin concat begin concat size end end
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat begin concat size end unless begin end
begin concat concat concat begin size end end
begin begin concat concat size end end
concat begin concat begin size end end
concat concat begin size end unless begin end
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat concat begin begin size end end
concat concat concat size unless begin end
concat begin concat size end if downcase
begin concat concat size end rescue upcase
concat begin concat size end unless begin end
concat begin begin begin size end end end
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat concat concat concat concat concat size
begin concat concat size end rescue upcase
concat size if downcase rescue upcase
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
begin concat concat begin size end end
begin concat concat size end unless begin end
concat concat begin begin size end end
concat concat begin concat concat size end
begin begin concat size end end if downcase
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
begin concat begin concat size end end
concat concat concat concat concat size
begin concat concat size end rescue upcase
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat concat begin size end if downcase
begin begin concat concat size end end
concat concat concat size rescue upcase
concat concat concat size rescue upcase
begin concat begin size end end rescue upcase
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat concat concat size rescue upcase
concat concat concat begin concat size end
concat begin concat begin size end end
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat concat concat concat concat concat size
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
begin concat begin concat concat size end end
concat concat begin size end unless begin end
concat concat concat size unless begin end
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat concat begin size end rescue upcase
begin begin concat concat concat size end end
concat begin concat size end unless begin end
concat begin concat begin size end end
begin begin concat concat size end end
begin begin concat size end end rescue upcase
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat begin concat size end rescue upcase
concat begin concat begin concat size end end
begin concat concat size end unless begin end
concat concat begin begin concat size end end
begin size end ensure begin clear end end end
begin begin prepend begin chr end end end
concat begin dup ensure concat begin clear
begin concat concat begin size end end
concat begin concat concat concat size end
begin concat concat concat begin size end end
begin concat begin size end end if downcase
begin size end ensure begin clear end end end
puts concat begin dup ensure concat begin clear
concat begin concat concat concat size end
concat begin concat concat concat size end
size ensure clear end end end end end end
for each in begin inspect end do end end end
begin begin begin public begin begin def each
clear rescue begin begin begin end end end
concat begin dup ensure concat begin clear
concat concat concat concat concat concat size
concat begin begin begin size end end end
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
begin concat concat size end until hex
concat concat concat concat begin size end
concat concat begin size end rescue upcase
begin concat begin concat size end end
begin size end ensure begin clear end end end
concat begin dup ensure concat begin clear
concat begin concat size end unless begin end
15. Demo
• "Hello, RubyConf!" program written
using only alphabets
$ ruby alphabets.rb
Hello, RubyConf!
$
16. Spoiler: Basic Structure
"Hello, RubyConf!" by Alphabets
s = inspect #=> "main"
s.clear
s.concat 72 #=> add 'H'
s.concat 105 #=> add 'i'
puts s
Need to remove the periods
17. class String
def foo
self.clear
self.concat 72 #=> add 'H'
self.concat 105 #=> add 'i'
puts self
end
end
inspect.foo
Spoiler: Abuse Open Class
"Hello, RubyConf!" by Alphabets
We can omit "self." !
Need to remove the period
18. class String
def each
clear
concat 72 #=> add 'H'
concat 105 #=> add 'i'
puts self
end
end
for x in inspect do end
Spoiler: Abuse "for"-statement
"Hello, RubyConf!" by Alphabets
Equivalent to
inspect.each {}
Exercise:
Remove the numbers
and the upper-case letter
Got "Hi" program
By only alnums!
19. Frequently Asked Question
• Q. Why do I write such a program?
• A. Because it's there.
– To figure out Ruby's power and its limit
– To stress the interpreter with unusual
code
• Q. What inspired me?
• A. Esoteric programming languages
– Funny joke languages including Brainf*ck
and Chef
20. Brainf*ck
• A language using only eight symbols
– Inspired me to create "Hello by Symbols"
+++++++++[>++++++++>+++++++++++>+++++<<<
]>.>++.+++++++..+++. >-.------------.<++
++++++.---- ----.+++.------.--------.>+.
Hello, world!
in Brainf*ck
Examples of Esolangs
21. Chef (not a provisioning tool)
• A language where programs look like
cooking recipes
Cheese cake in Chef.
Ingredients.
100 g cream cheese
97 g sour cream
*snip*
Method.
Put the cream cheese into the mixing bowl.
Put the sour cream into the mixing bowl.
*snip*
Examples of Esolangs
Data section
Code section
22. [PR] Cookpad
• One of the world's largest
recipe sharing platform
• My Cheesecake recipe is
published at Cookpad
– https://cookpad.com/us/
recipes/3335222
– It is a program in Chef
• Prints "cookpad"
– It can be also used as
a real recipe
• Chef (and some esolangs)
inspired me to create
a funny-shaped Ruby code…
26. Spoiler: Two key techniques
• Quine: self-reproducing program
• ASCII-art programs
– Ruby's %-notation works great for them
27. Spoiler: Quine
• A program that prints its source code
• Basic structure
eval s=%q(
s="eval s=%q(#{s})"
# Do funny thing here!
# e.g., Rotate the globe in the string
puts s
)
Qlobe: A Quine with Spinning Globe
Reconstruct the
original code
as a string
Print it
28. Spoiler: ASCII-art code
• Write a code with no space and backslash
• Wrap it with "eval(%w(" and ").join)"
• You can shape your code as you like
puts"Hello,world!"
eval(%w(puts"Hello,world!").join)
eval(%w(pu
ls "H
el lo
,w or
ld!")*"")#
#=> Hello,world!
30. Quine-relay
• A Ruby code
• that generates Rust code
• that generates Scala code
• …
• that generates REXX code
• that generates the original Ruby code
128 languages
involved
in total
31. Quine-relay
• A Ruby code
• that generates Rust code
• that generates Scala code
• …
• that generates REXX code
• that generates the original Ruby code
128 languages
involved
in total
32. Spoiler: Quine-relay
eval s=%q(
s=%(eval s=%q(#{s}))
# Generate a REXX code that prints it
# …
# Generate a Scala code that prints it
# Generate a Rust code that prints it
puts s
)
33. Monumental Quine
A column object 3D model data
Ruby code
is inscribed
You can buy it at Shapeways!
https://www.shapeways.com/shops/mametter
Execute
the code
3D
printer
34. Spoiler: Monumental Quine
eval s=%q(
s=%(eval s=%q(#{s}))
# Generate 3D model data that
# embeds the string
puts s
)
+TrueType font data
+Font renderer
+Code golf
38. Demo
• You can delete any one character
• It automatically restore itself!
$ ruby broken.rb > rquine2.rb
$ diff –s rquine.rb rquine2.rb
rquine.rb and rquine2.rb are identical
39. Spoiler: Radiation-hardened Quine
• Redundancy-based error-correction
– The longer one is always not broken
• When a letter out of "<YOUR CODE>" is
deleted, what should we do?
x = "<YOUR CODE>"
y = "<YOUR CODE>"
eval [x, y].max_by {|s| s.size }
40. Spoiler: Radiation-hardened Quine
• A style against one-letter deletion
• Even if one letter is deleted, this code
successfully does one of the following:
– Assign the string like "<YOUR CODE>" to a
variable eval
– Call eval to "<YOUR CODE>" and exit
• Note: Cookpad's service is robust, but its
source code is not so bad like this
x = "<YOUR CODE>"
eval=eval=eval="(<YOUR CODE>;exit)#"##"
rewrite
41. More? Buy my book!
• "The World of
Obfuscated,
Esoteric, Artistic
Programming"
– Contains about 40
codes like this talk
– Written in Japanese
42. Related work
• International Obfuscated C Code Contest
(IOCCC)
– A programming contest for hard-to-read
programs written in C language
• Transcendental Ruby Imbroglio Contest
for rubyKaigi (TRICK)
– The judges (including I) held TRICK twice
• https://github.com/tric/trick2013
• https://github.com/tric/trick2015
– TRICK FINAL will be held in RubyKaigi 2018
• Please send your esoteric Ruby code to us!
• https://github.com/tric/trick2018
43. Conclusion
• Ruby is very rich and flexible language
– You can use Ruby with broken keyboards
(only symbols, or only alphabets)
– You can write artistic and super-robust
Quine in Ruby
• One more thing…
44. A Quine that takes five minutes
0;BEGIN{eval(s=%q~s=s.gsub(/¥e¥[¥d+m/,"");eval((%w¥C="0;BEGIN{eval(s=%q#{126.chr+s+126.chr})}";E=""
;Z=32.chr;D=->k,d{c=35;k.scan(/../){c+=1;d.gsub!(c.chr,$&)};d};include(Math);M=D["PPQPQi^heigMk=nis
iJO^L^MjQqiEPQjQn^ikjviKNfihhvLFPOLQOPQoiOijd]igiljkMmihjkiQQNNiQiPjiiilihi","^kNojsdhm.;vA.;/7ciqL
^A;;.vA5k&jjBhohdvPkhd^lNQE(m3:v0:vjlHkhdjGhHN:HjOHj6Bim1HBgn*-INBinJPNvdjnBfnPO3gGhkO%NBhn>INvdlnB
cl@lkldclJij7jjBjm(:PHqdcnBjoN@eLNHOehI+H4hFE3h>H3h+92rhD92jhGbi6Orh?i0oh>H4hQG2f&GHOohJi0rhPD6P'QD
EIv&92'I_K/8P8Q8P818Q8QK,9D1NQNDKKK1KQNGK8DKKKG)QciDkA@9^,G^AmM;Q@/?;OI^=P7FQ/?vM?.%vM?.,9bL%;OI5lh
`,_CI]A]LCGCDCNC@C]MCNCNC5CG]L]ACkk]PD*PF&h6Omhgj<P*?:HOmhgjkArM><'6Pgh6OJ$I)Q:2fhgjP<<(IlhE4hfj$<J
?ihH4hHPI)J$I'2f3<</IghEIgHha@D@N_Bjmm0]35khP?@n0]h]HvOjJ?qLOJ>F7gL>%Jo=@eM<-mLOJ>-mLOfMGoM>7fM(rA5
kAkOdjm7`9)fM5G+IsMf=4L1GgL4if=G+:_D*-I^$-J•i]"].bytes;F=44100;z={};H=->n,l,v{z[[n,l,v]]||=(l=(3e5/
l).round;t=0.0;(0...l).map{|j|k=(j+1000)%l/1000.0;x=j*440*2**(n/12.0)/F*PI;sin(x+2*t=sin(x+t))*v*(k
>4?1:(2-(3-k).abs).abs)/3})};W="MHJEFAFH".bytes.flat_map{|n|H[n-84,6,30]}*29+H[-7,3,30];i=n=v=0;l=6
;(c=M.pop-98;c<0?v=c*5+55:(l=l*12/(2**(c%5)*3**(c/5));d=M.pop-93;d>0&&(j=i;H[n+=d-13,l,v].map{|t|W[
j]+=t;W[j+4e5]+=t;W[ j+8e5]+=t;j+ =1 }); i+ =3e 5/l)) while
(M!=[]);Y=["data",W. size,*W.map{ | n|n +1 28} ].pa c k("A4VC
*");o=IO.popen("apla y"+Z+"-q"+Z+?-, " wb" ); o<<["R IFF",28+Y
.size,"WAVEfmt"+Z,16 ,1,1,F,F,1, 8]. pac k( "A4V A8VvvVVvv
")<<Y.slice!(0,4410 0 *3);L=D["*1 /< 7q 8j 9B 9aA3H CHIH aJ|k@|>EI
GAIJIaiaDDFFFkaq j J ff EJjja|qqEa Gb ppJa H H| |kkbbI IJJaa","J
gGG2i66,Cg2C2i3 ;& Jd e Hde,;Cj&D+A-$?,C;H<=I?DHJA-$@@=F@@kEka8?a<1@=8q=8qa&>=?4A4
$=a @?J@ <<= %? I=a1|f 'a =%EGJAii2c3;7:;JqF@;J?ka?/;Cq7:?'?'a?%<GC2cDI7=6D4iB-lliH4
iCg +i.C5pCB555pCBI): B5ipaB>nm|hh >j):0> j)jB q 4o J:0
c:q| .B>.(0>.( pI> JqB0 (j|+`hhc6J "]. tr (" a -z"
,Z+" #'()+,-./ =@ MTV_" <<92);P=- >s{[q="+ ---+"+ Z *(6 + s.size),"
|:#{s }:SPONS OR S",q]} ;f=40;c= E+R=D["4 =8]?:B . B@C / C<<7_?
<5<8]?66 _9A8;;==BC]_ _:_C??B`> >]A @@ AAB B CC__``]]"
,"$AC-8<C ]: $2 - > <:4@. -1`$]8-1C_` 4)5-7C 74C? 5A5 , 574C9B=C]
99`=<<?5219?(C(2<9C2 19?B86/)'1&_06/)'1&_006(2<9.,:>A_<_<_@<<?'3333;7CA7@6@3
>:CA,`*C%;>7+2%>A:+2 %:A7<,`*C8++@6&*_"];S=[[["EXECUTIVE:ADMINISTRATOR","Abb
y:Phoenix"],["EVENT: PRODUCE R ","Hea ther :Johnson" ],["S
PONSORSHIP:CONSULTAN T","Shirley:B ai les "] ,],[[(t= "PR OGR
AM:")+"CHAIR","Sarah :Mei"],[t+="DIRECTOR" ,"E va n:Phoe n ix"],[t, "Ma rty
:Haught"],],[[t="TRA CKDIRECTOR","Akira:Matsuda"] ,[t ," Corali n e:Ada:Eh mke
"],[t,"Courteney:Ervin"],],[[t,"Derek:Prior"],[t,"N adi a:O du nayo"],[ t," Nic
kolas:Means"],]].map{|a|a.flat_map{|x,y|[E]*5+[x+Z* x.s ize,Z *y.s i ze+ y]}
[5..-1]};S[1,0]=[p,"[[:Program:Committee:]]"];[p,C.gsub(/./){Z==$&?c.slice!(0,1).tr("]_`","##;"):Z}
.lines[11,24],p,'<<-"RubyConf:2017":--:@New_Orleans.->>',p,"[[:Planning:Team:]]",*S,p,P["DIAMOND"],
p,L.scan(/.{92}/)[0,7],p,P["PLATINUM"],p,L[7*92..-1].scan(/.{47}/),p,P["GOLD"],*[["STITCH:FIX","sqr
een"],["Braintree","HEROKU"],["entelo","SENTRY"],["DATADOG","ROOSTIFY"]].map{|a|f=40-f;a.flat_map{|
s|l=Z*f;r=Z*f=40-f;[E,E,l+s+r,l+?=*s.size+r,E,E]}},p,P["BRONZE"]+[E,"BRAKEMANPRO"]+[E]*4+P["OTHER"]
+[E,"covermymeds",E,"Google:Cloud:Platform"],p,"Brought:to:you:by:the:folks:at:Ruby:Central",p,"Rub
yConf:2017",p,[?%*39,u="%%"+Z*35+"%%","%%::::Remember!::This:is:a:Quine!::::%%",u,"%%:This:banner:i
s:a:valid:Ruby:code.:%%",u,?%*39,],p,["The:original:source:code:follows...",E,E,"---8<---"*8],p,C.g
sub(/./){Z==$&?(c=R.slice!(0,1).ord;27.chr+"[#{c-52}m#{Z}"+27.chr+"[0m"):$&}.lines].flat_map{|s|(s)
?(s=[*s];s.map{|l|l.center(99).rstrip}+[E]*[0,(24-s.size)/2].max+[p]):[E]*24}.map{|s|n=(s)?(puts(Z=
=s[0]?s.tr(?:,Z):s);1):92;t=Time.new;o<<Y.slice!(0,4410*n);$$until(t+0.09*n<Time.now)};o<<Y;o.close
;exit;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;¥*"").gsub(/¥e¥[¥d+m/,""))~)}
Demo:
https://www.youtube.com/watch?v=ABuj0XfltpM