GeistHaus
log in · sign up

https://idiosyncratic-ruby.com/feed.xml

atom
225 posts
Polling state
Status active
Last polled May 18, 2026 21:40 UTC
Next poll May 20, 2026 01:15 UTC
Poll interval 86400s
ETag "66aa07f6-11ae22"
Last-Modified Wed, 31 Jul 2024 09:46:30 GMT

Posts

Ruby TRICKS of 2018
Show full content

Ruby was initially designed to be a successor of the Perl programming language, which also means that it inherited a lot of Perl's expressiveness. To celebrate this, the TRIC¹ contest was invented:

  • Write the most Transcendental, Imbroglio Ruby program!
  • Illustrate some of the subtleties (and design issues) of Ruby!
  • Show the robustness and portability of Ruby interpreters!
  • Stabilize the spec of Ruby by the presence of valuable but unmaintainable code!

The best submissions were awarded at the Japanese Ruby Kaigi conference and also included in the Ruby source, for educational purpose. The winning submissions² of 2018 were:

¹ Transcendental Ruby Imbroglio Contest
² All code is MIT licensed, Copyright (c) 2018, TRICK Winners and Judges

1st Place (Gold): "Most reserved"

By kinaba (remarks)

alias    BEGIN    for      unless   def      class
super    true     or       return   defined? next
break    while    begin    undef    do       end
rescue   then     retry    else     undef    module
nil      ensure   case     if       yield    __LINE__
self     and      redo     elsif    not      __FILE__
alias    END      in       end      when     __ENCODING__
end      until    false    end

The above Ruby program does not output anything, but it is 100% valid code. What is noteworthy: It only consists of reserved keywords and makes use of all of them!

2nd Place (Silver): "Best spiral"

By Yusuke Endoh (remarks)

'';eval(r=%q(->z{r="'';eval(r=\
%q(#{r}))[%q`#{z}`]";i=-040;30.
times{|n|(15+n%2*15-n/2).times{
r<<r[i+=(1.-n&2)*(32-n%2*31)]}}
i=r[524,0]=?\0;eval(r[479..-1])
c['"']}))[%q`GFEDCBA"+"[e\"'"'t
kE*;;\";"  TRICK2018  ";tb,;{{r
2E0$ob[us@*0)[90,336])_#i\n}s#i
0H}>["t]];};o[1,?\n*8];ex"-}eac
1Hl<1[-1]*2*t=n%2];o[14-n,0)mvk
8M$<4,?\n];15.times{|n|;o[35ie2
!Pss.slice!(0,1)+x;sleep(0.0t;0
'W=%q"<<95<<$s<<95;o=->n,x{n.'1
;@[2]}|\e../,%@s="'%trick2018!8
eval$s=%q_eval($s.gsub!(/#{%@`]

Running the above code returns itself, it is a quine. And on top of that, instead of returning the result line by line, it prints itself using a spiral animation!

3rd Place (Bronze): "Best png viewer"

By Tomoya Ishida (remarks)

X=[];class String def-@;replace ?-+self end;def-a;X.reject!{|x|x.
__id__==__id__};a.replace(self+?-+a) end end;at_exit{eval C=(Zlib
.inflate((X*?-).tr(?-,'').tr('q-z','0-9').to_i(26).digits(0x100).
pack'C*'))};def method_missing n;(X<<n.to_s)[-1]end;require'zlib'
fzygtoxyzgntmdmuwvfoffbpmvzojpkhczvjvjdbtscnldwbdoprackddovivvmkz
ponzmosvtjciwkgaslscxxxwudeesmmqpfhislxuxnnypulxstzgobyaekqqhbjcg
mvko------------ddkeys----eivhnccaqyiw---bzyccmt-----------ymtnge
jwhi--------------pjxf------mdarbtumnv---qasda--------------gmwdt
wrtk---qtpzgnce----fsl-------fkgzgtbpp---gwnm----pxkpqkdiw---owga
momz---yjjvpnvar---zeo---v-----duvalwu---nsqt---waofemwakivnyqkjd
fzag---uhvusmkl----kzb---rhc----iutzjr---mqlh---ayijpwativpweaato
xexs--------------rvgv---pjdz-----lkkg---uiaw---lovitupw-----fwmn
kfru------------jvjpgv---jskycf----pal---gbuf---hfdnywog-----iuca
pntn---apmkqroeuzwuwkw---gqnmgof-----b---hlpl---vkkyhfyrqfr--jwrl
kmdb---dhspujhmtgrkccu---uonfummdt-------rqfw----bpiactehwp--fncq
yzvz---gdaxebplhfndran---ytfmviryeh------hqwkl---------------nced
bibu---fnkdthgldhkxxjg---rwnmpudhbqin----gucoyki------------hfura
cqdgqpyzqfzknvdjoxxhpjulwwyebtocxdrvklbuviwwcatlmdosxfvwntzbijguy
iglrvvzlxerflupxvsyujfacuwhrvmnecgtewtqkhtdggcltejiyqcluclkycwvzg
vvxfysvttfbeglvrlngntdngzyhqrmltazwdydxrsvjploembhgxdvfmmhepbschm
brn--iqrcdb--evv----tqp------lg--uein-wzut--mr------wkh------foqz
zsf--srjnjp--ampb--pfio--hgtekx--rrr---fwd--jn--xqkezcz--vsb--nya
khrc--evlr--oioxs--mqce--bqfmag--bwz---xda--qw--jnuzelr--qzi--itx
mdxd--duso--wxbot--nmon--ugnbdpc--a--c--e--hlg--twxndre--tby--rhg
evhbn--zb--dtxmiz--dpia------vie--h--i--t--shh------kfn------owna
ealmt--kb--scxdjy--smvl--dqmgebk--t--s--t--gfd--updcbnc--rh--dwwp
dvpnxb----wpljjdy--kolc--qflyleok---xkv---usbj--jhrawbn--ewx--bgf
eaqwrw----ejwxhet--dice--eoczconm---urz---rqyp--hovvvfc--bskj--el
aocjcts--jtumwxm----mgy------xpaoq-jtwqr-aipay------dhy--iync--hk
sckddmvuvvuhhqstumaykvczaaujrumqbbqsdvdycplyrlkkojlxnkrhbbrmnjxyf
cdtcmpfmjvthwkpzucbblttgumomlxnxwjeypfeagaukfzeokzxjebkpigcvlqnso

Requires gem install chunky_png. This program converts a PNG image into ASCII art! It will turn this image into the following text output:

undef p;X=[];class String def-@;replace ?-+dup end;def-a;X.reject!{|x|x.__id__==__id__};a.replace(self+?-+a) end end;at_exit{eval C=
(Zlib.inflate (X*?-).tr(?-,'').tr('q-z','0-9').to_i(26).digits(256).pack'C*')};def method_missing n;(X<<n.to_s)[-1]end;require'zlib'
gmlztzdculbtzgtjfetuh---k--htf----d-----------------------------------------------------g-b-----s--t-g--------jmuwescmgchftikfjafccs
ivchcveidpvxdabnvwyga-f--v-------xf----------------------------------------------------q-v---l-------q---------liiNeawriayymwooxgxqw
rfosepqsmojseyezmwbhi--------------ew--------------------------------------------------m---k-r-----------vwu--hiotltdmczwyjmlvbyfqwq
uvvykqdjednoqgtcmtfbzs---------f----o--------------------------------------------------t--a------m----x---f-----dldzsakyofetfozfpmrq
geusutariiiNiulkjbwlm-----d------------------------------------------------------------j---------o---------x--j-uitzrgwpupwhvendhyno
uubvnssiywkklwwdufhhi-rw----k---v-------------------------------------------------------sty-----yg---l---c-v----wkffpskpumolqmkeryzg
zrxdaiposwybbzgxdnegh-----g-----ma--n---------------------------------------------------------j----n--b-n-------yqavmscswdogpcgopygt
axiqfswlhzeamvymdnteo---q-q-w--------------------------fhrmj-----------------hkou-----------f-----d----u-o------evcuxxegekfgivzzujan
nslioftsvqvtkeigvfgwr-------------lyco-----------------igyvg-----------------okuk---------m--b-u--d--y------s---dadjrlykfhtermzfyktu
btoxzfpPicxxfligbivvf--------h----yrat---------------------------------------vjwd---------------------d-ki--o--tyqosehopkwttigwwfskp
komzvnyrvkjcjwbmdwdkp----------vxphiNdtawn--xms-saketo--jnld----ezulntdaz----nzna-----vhjwt------h----x--x--o--saxxsrkgktqotaluylbkk
sclegratyaarmgmepheml----------hwgglhlrfcx--znvmpfsgjx-onhju---gtxsmzqprlt---mjzy---frhdk-------------v---mj----dzjujmbgldfwoybgicwu
tfhgnhlzxlwtdtkgzlaca-------------gmex------arlm--------rvmh-ajtgf-----pqal--wcux-zatyi-------------------------xnluwybcugjclmablshn
tnjohqtqzivgmyutrssil-------------lcwq------jrf--------gcaii-maie------------vvnfjfqwo--------------------------filivosyhkxcvuwdibwj
tyxjiopiFqypvwdzoatuq-------------tdln------cnx---------ffuf-ajvq------------tyyypglpzmj------------------------vtqzwewqdsijrbymvpwn
niNffphoehukpvvmzvhyd-------------ahqd------nfr---------jeqk--toap-----mxhyg-tedv---otrwy-----------------------mjxnrktackwxwiajdnuc
kkxhuwbvibpvgvcampadi-------------ebmencqz--obf--------wfprz---qmrotkijiqv---ggfp-----hlzw----------------------kastwdpxiyftmypuxbtu
xetudmwzpomktgnjkcsyc---------------fwpdx---xb----j-----se-k------tllakc-----gjoo-------we------mic---lktk------ubtnrxvrjzuqlrfrsnmf
okdvfvcdbdqkckjialskk---------------------------v---u-------l----------------------------------z--q--qfg--------aaliNbxbjjpxebboneye
kcbkjmdclwnfawtfnwkeq----------------------------------j---y-------------------------------a---jmbyo-sgef--gf---extljbozuoofgyvsilct
xzoqmsqgzjxxpjqwkjkdd------------------------o--------m-------f---------------------------------n--de-ajz-rzv---fhnpbkrwdxoozpxeaxaf
mbcwxuiqdwcmadheiykaa-----------------------q-f------l---i---------------------------------r----zf---k--y---fi--dcnycheytylcgnioauee
yekiNacriqoevtdjerqbp----------------------------w---yy-----my----------------------------ko--mnbpskr--c-----j--ozyqpbfovhbhyoprzgqr
czwtuopxkdbphocfawvbk--------------------------q-s----j--b---------------------------------hd-xsb----bfiNp--w---fmwuvfambdqvxtzldwmh
xysnyrseydlkjcwfbsjnr-------------------------d-d-------------------------------------------f-enpss---qllpwr----almsdidvjwoigvldfqoa
lrpbixjpofxocxlflscpo------------------------------q-fyu--z-------------------------------------kfd-z---n-------bqxurujnxzurrdgcojks
jetyfdkcekckxbyosbfws-------------wdfhgwuvejjmf-----sxjubpvgcsl-------tnmixpv---------eurabjsdvstfv-------------qcyiqhonwoyixqeonfvp
mopPhywsozohitutgmmrb------------zxwtxe--riedeo---mspgpnv--pimlh------jhtzajk--------qqovvq---ldbrh-------------xtooxpayonpcvvtmvpra
vvuyiunpoeagdzqjecsub------------klrw------snrc---rrct------aajom--------nsyk--------peea-------azq-------------iNjefdkfhnagjicqwmsm
mbwwbfgehhbdmvvlflmee---------------------hkejn---jtbo-------jdtje-------jcei---------afyz-----smtc-------------kksvfjyuaqtohxiohhlz
dvfmfrzcmnsfruhqgjuxz------------------dfxdnlk----kkra-------xmmtf-------jwkw----------rdoozxtcho---------------bbwwferxwnnmdzcniicv
mfneisdlyeqwynldjgonj----------------jgrjvc-------uxga-------ghnpr-------sers--------scbknx----gmjo-------------moedtnlbflhtlkjibrqk
gobwqshnpbdcpjmjaeczr--------------iscsxs---------zfpo-------hhfwy-------qbba-------vhlxc-------ntod------------ndwzdomaptumzejiwqbn
snucynymvfpnadyqkzfcv-------------ggze------------kuvfs-----zuhod--------mylo-------jhwyp-----z-pywd------------dqfmpnevmtqcikbrilto
aotyxkipebdkassogpcbl-----------wgackesmvvsrihhd---orzndjndlzpb----------eobf-------kkayixzyotqfafa-w-----------mjjxoomwdglwvccozzut
rthesuszfwycsqqrtxlot-----------ejcqlhriilqbtrys------lwbkzmvp-----------zzwm-------l--qijwfllndzb-ik-----------mmokqomjepdcotnsiNig
nloryyoswwdmefywnnuhph------------------------------------------------------r--r-nd-----h--x--------------------hlgzeqqslwxgtjgghquf
nssngjtiudsrvfuxjzclhjhj----------------------------------------------------------t----------------k-f-mp-------obhyehqebtpjbkeepqzt
ezogzsimfynqmkteaipejo-g-yser-----------------------------------------------e------h-------------i---y----------qpgcqnltivmmsximbbsy
wtjjolwyoselcumgklqwpldkl-ulm-m---------------------------------------------------------------q---u-f--l--------buixfiitufktsqdtnrei
tgrtitcewseetlpeuuujb-osdokjozc------------------------------------------n---d-----f--------g--------q--g-------jyyqtezuzmcxgpcwuwfx
dpPayqmzxrwhbswwalygfurtkruw-u-k---------------------------------------------d---h------i----------c----i-------ulowcddvjbxthqlxjzbe

Every piece of ASCII art generated also contains the full converter program and can be used to transform another PNG image into ASCII!

4th Place: "Best one-liner"

By Colin Fulton (remarks)

# (c) 2018 Colin Fulton. Available for use under the terms of the MIT License.
$🚀=0;def 🤔 🏷,🤔=0,&b;puts ' '*$🚀+(🤔 ?"":"🚫 ")+🏷;$🚀+=4;b&.[];$🚀-=4;end

What we have here is essentially a testing framework in 68 characters! It uses a method named 🤔 as its API. To illustrate its usage, here is an example:

$🚀=0;def 🤔 🏷,🤔=0,&b;puts ' '*$🚀+(🤔 ?"":"🚫 ")+🏷;$🚀+=4;b&.[];$🚀-=4;end

🤔 "Math" do
  🤔 "Addition" do
    🤔 "One plus one equals two.",
      1+1 == 2
    🤔 "One plus one equals eleven. (This should fail.)",
      1+1 == 11
  end

  🤔 "Subtraction" do
    🤔 "One minus one equals zero.",
      1-1 == 0
    🤔 "Ten minus one equal nine.",
      10-1 == 9
  end
end

Test output:

Math
    Addition
        One plus one equals two.
        🚫 One plus one equals eleven. (This should fail.)
    Subtraction
        One minus one equals zero.
        Ten minus one equal nine.
5th Place: "Most three-dimensional"

By Tomoya Ishida (remarks)

                                                    X=[];def self.method_missing n;n.to_s.chars;end
                                               l=[];def l.-a;X<<a=[nil,*a];a;end;def l.+a;self-a;end
                                           class Array;def-@;[]-self;end;def-a;replace [*self,nil,*a
                                 ]end;alias +@ -@;alias + -;end;def gen3d f;yield;b=['solid obj'];w,
                 h=X[0].size,X.size;X<<[];a=->r,z,dr,dz{;r-=w/2.0;z*=2;r2,z2=r+dr,z+dz*2;if r>0||r2>
                 0;r=[0,r].max;r2=[0,r2].max;16.times{|i|m=Math;p=m::PI/8;;c,s=m.cos(t=i*p),m.sin(t)
                 c2,s2=m.cos(t=(i+1)*p),m.sin(t);t-=p/2;[[0,1,2],[0,2,3]].map{|a|b.push [:facet,'n'+
               +                 'ormal',dz*m.cos(t),dz*m.sin(t),-dr]*' ','outer loop',a.map{|i|'v'+
              ++                           "ertex #{[[r*c,r*s,z],[r*c2,r*s2,z],[r2*c2,r2*s2,z2],[r2*
              +c,                              r2*s,z2]][i]*' '}"},:endloop,:endfacet}}end};(0...h).
             map{|                                  y|w.times{|x|[X[y-1][x]||a[x,y,1,0],X[y+1][x]||
           a[x+1,y+
          1,-1,0],X[
         y][x-+1]||a[
        x,y+1,0,-1],X[y
       ][x++1]||a[x+1,y,
       0,1]]if X[y][x]}}
       s=[b,'end'+b[0]]*
        $/;File.write(f,
         s);X.replace(
            []);end

gen3d 'wine_glass.stl' do
  l--ww------------------ww--l
  l--ww------------------ww--l
  l--ww++++++++++++++++++ww--l
  l--ww++++++++++++++++++ww--l
  l--ww++++++++++++++++++ww--l
  l--ww++++++++++++++++++ww--l
  l---ww++++++++++++++++ww---l
  l----www++++++++++++www----l
  l------www++++++++www------l
  l--------wwwwwwwwww--------l
  l-----------wwww-----------l
  l------------ww------------l
  l------------ww------------l
  l------------ww------------l
  l-----------wwww-----------l
  l---------wwwwwwww---------l
  l----wwwwwwwwwwwwwwwwww----l
end

Running the above Ruby program will create an STL file with a 3D description of a wine glass, which you could actually print out using a 3D printer. You can find a preview of the result here. Changing the shape of the glass in the above code will also change the outputted 3D model!

6th Place: "Most reversible" eban award

By Yusuke Endoh (remarks)

a,b=:reverse,:itself;b=b
a=b=:itself;b
 r||=->s,m=a{s.send(m)};a
 puts r[$<.sort_by(&r),b]
 ;r||=->s,m=a{s.send(m)};
  a=b=:reverse;0
  b,a=:reverse,:itself#

This program sorts the file given as an argument. The fun starts, when you apply it on the program itself, because it will generate the following, different program:

  a=b=:reverse;0
  b,a=:reverse,:itself#
 ;r||=->s,m=a{s.send(m)};
 puts r[$<.sort_by(&r),b]
 r||=->s,m=a{s.send(m)};a
a,b=:reverse,:itself;b=b
a=b=:itself;b

This generated program is also a sorting-program, but it sorts the given file by reverse order. The fun continues when you use the program to reverse-order itself! This is the result:

a=b=:itself;b
a,b=:reverse,:itself;b=b
 r||=->s,m=a{s.send(m)};a
 puts r[$<.sort_by(&r),b]
 ;r||=->s,m=a{s.send(m)};
  b,a=:reverse,:itself#
  a=b=:reverse;0

It is even another sorting program, this time it will sort any given file by their last characters on each line. It is a reverse-line sorter! But what if we want to sort by reversed lines in reverse order? No problem, just go one level further and apply the reverse-line sorter program to itself:

  b,a=:reverse,:itself#
  a=b=:reverse;0
 ;r||=->s,m=a{s.send(m)};
 puts r[$<.sort_by(&r),b]
 r||=->s,m=a{s.send(m)};a
a=b=:itself;b
a,b=:reverse,:itself;b=b

The fun ends, when you let this sorter sort itself (again!) which produces the original code:

a,b=:reverse,:itself;b=b
a=b=:itself;b
 r||=->s,m=a{s.send(m)};a
 puts r[$<.sort_by(&r),b]
 ;r||=->s,m=a{s.send(m)};
  a=b=:reverse;0
  b,a=:reverse,:itself#
7th Place: "Best compiler"

By Colin Fulton (remarks)

$l||=__LINE__;eval q=%q[k =";eval q=%q";
# (c) 2018 Colin Fulton  (MIT License) #
;n=([1]);f=->s{[0]*(s.size/40)};$c||=-17
$r=[*$r]+[[]]*(($l-$c)/18);$c=$l;(s="");
;;m=->a,b{8+4*a[b]};$r[ -1]+=f[s]+n;s=%;
;;s&&$r[-1]=f[s]+$r[-1]||(z=44);z=$l=s=z
(y=->{z=puts(z.map &:rstrip)})&&(s="")&&
e=->a,b,c{(a+a)[b+c]+a[b-c]};$r||=$r*42;
;h=[1,*8..10];f=->a,l{a+[0] *(l-a.size)}
(r||=->{f[$r.flat_map{|a|f[a,9]},81]})&&
c=->a,d{h.map{|p|e[a,d,p]}.sum};!nil.!||
g=->a{d=-1;a. map{(m[a,d+=1])[c[a,d]]}};
;x=->{"$l||=__LINE__"+k+91.chr+q+93.chr}
b=->{x[].split(?\n).map{|s|s[$t]}}||!$$;
(v=->i{g[r[]][i]>0?b[]: [" "*40]*18}) &&
w=->i{z ?z.zip(v[i]) .map(&:join):v[i]};
;$t=/\S.{0,39}/;u=->i{z=w[i];i%9>7&&y[]}
;at_exit{b=b&&($z||81.times(&u)&&$z=1)}]

The above code snippet is meant as a building block to build a pattern for a Conway's Game of Life simulation! You have to take this literally and build up the pattern using the above code block! Executing the pattern with Ruby will generate the next generation. Here is the "glider" start pattern. Repeat the script multiple times to see it moving! (zoom out for the best viewing experience)

8th Place: "Most composable" shinh award, leonid award

By Tomoya Ishida (remarks)














































                   (B||=[])<<6;C||=[];C<<%w@0 if@;
             a=?;*2018;C<<%w@2 (e=ARGV[0]);e=File.read@;
          t=->(i,s){s&&a[i.to_i,s.size]=s};C<<%w@25 (e)if@;
         u=->{C.map{|i,s|t[i,s]};eval(a)};C<<%w@30 (/^\.+$@;
        at_exit{_,u=u,->{};_[]};C<<%w@37 /!~e&&File.exist?(@;
       C<<%w@55 e));d='[><+-,.]';i=32.chr;f=0..79;c=(0..7).m@;
       C<<%w@99 ap{|c|b=['C||=[];','a=?;*2018;','t=->(i,s){s@;
      C<<%w@143 &&a[i.to_i,s.size]=s};','u=->{C.map{|i,s|t[i,@;
      C<<%w@188 s]};eval(a)};','at_exit{_,u=u,->{};_[]};'];o=@;
      C<<%w@233 0;f.map{|f|j=(0..67).map{|r|r-=34;s=f-34;m,n=@;
      C<<%w@278 r.abs,s.abs;h=->x{m<25&&n<34&&(x<0||n>17)};q=@;
      C<<%w@323 ->x{n<x+34&&x<n&&n<34};[h[r],q[-r],q[r],n<11|@;
      C<<%w@368 |(m<17&&n<34),n<12,r**4*1.6+16*(s-25)**4<8*17@;
      C<<%w@413 **4||(s>37&&s>17-r&&4*s<173-r),r**4+16*(s-25)@;
      C<<%w@458 **4<8*17**4,h[-r]][c]};r,p=j.index(!!0),j.cou@;
      C<<%w@503 nt(!!0);next(i*68)if(!r);k=f==45?'(B||=[])<<'@;
      C<<%w@548 +c.to_s+?;:'';g=b[0];(k+=b.shift)if(g&&g.size@;
      C<<%w@593 <=p-k.size);l=p-k.size-o.to_s.size-9;s=64.chr@;
      C<<%w@638 ;if(l>0);k+=['C<<%w',s,o,i,a[o,l],s,?;]*'';o+@;
      C<<%w@683 =l;end;(i*r)+k+?;*([p-k.size,0].max)+i*(68-r-@;
      C<<%w@728 p)}};(e.chars-(e.chars-d.chars)).each_slice(8@;
      C<<%w@773 ){|l|puts(f.map{|y|l.map{|r|c[d.index(r)][y]}@;
       C<<%w@818 .*(i*17).rstrip});4.times{puts};};else;x,i=@;
       C<<%w@861 Hash.new{0},0;y=%(while(x[i]!=0);i+=1;i-=1;@;
        C<<%w@904 x[i]+=1;x[i]-=1;x[i]=($<.binmode.getc||0)@;
         C<<%w@945 .ord;$><<(x[i]&0xff).chr;end).split(?;)@;
          C<<%w@984 ;eval(B.map{|a|y[a]}*?;);end;;;;;;;;;@;
             C<<%w@1021 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@;
                   C<<%w@1051 ;;;;;;;;;;;;;;;;;;@;









This is not just another brainfuck compiler. Not only does this piece of code convert a bf source file into an equivalent Ruby source file. It also formats the resulting Ruby code into huge letters representing the original bf code. As a bonus, the compiler gets embedded into the generated Ruby file and is used when it receives another file as a command-line argument. A demo of all the described features in this short video by the author!

9th Place: "Most (un)readable"

By Yutaka Hara

def method_missing(n);$*<<n.to_s.bytesize
n[-1]=="!" and eval$*.map(&:chr).join;end

*自己言及的なプログラム.
これは「自己に言及」したQuineプログラムです.
動かすには普通に無引数で実行してください.
MRIの最新の安定版で動作確認を行っています.
*冒頭の2行が日本語プログラミングのDSLを提供します.
Rubyはピリオドまでの部分がメソッド名であると解釈します.
そのままではNoMethodErrorになります.
それをmethod_missingを使って検知しメソッド名のbytesizeをASCIIコードとして文字にします.
メソッド名が半角の!で終わる場合、記憶した文字たちをjoinしてevalします.
これにより任意のRubyプログラムを日本語により記述することができます.
このプログラムの場合はこのファイルをreadし出力するようになっています.
*Note:文の長さは注意が必要.
UTF_8の日本語は1文字が3bytes.
端数が丁度になるよう英語を入れる.
以上、自己言及的programでした!

The first two lines of this Ruby script enable a "Japanese programming" style. The characters before each . get converted to ASCII on the basis of their byte size. The embedded example program is $><<IO.read($0): The code reads itself to then output itself.

10th Place: "Best double meaning" matz award

By Tomoya Ishida (remarks)

def self.method_missing name, *args
  name.to_s
end

FizzMessage = Fizz()
BuzzMessage = Buzz()

def    fizzbuzz_loop n=100
  n = n.to_i
  return 0 if n == 0
  (1..n).each do |i|
    puts fizzbuzz(i)
  end
  error = get_error_message
  puts error if error
end

def   fizzbuzz n
  set_error 'wrong argument type' if n.nil?
  if n <  0
    n = -n
    retval =  fizzbuzz n
    return       retval
  else
    if mod3(n) == 0 && mod5(n) == 0
      FizzMessage + BuzzMessage
    elsif mod3(n) == 0
      FizzMessage
    elsif mod5(n) == 0
      BuzzMessage
    else
      int2string n
    end
  end
end

def        int2string n
  if n <  0
    n = -n
    tmp =    int2string n
    return  '-' + tmp
  end
  base =  10
  charcode_offset =   0x30
  n =     n.to_i unless n.is_a? Integer
  chars = n.digits(      base   ).map do |n|
    (n + charcode_offset).chr
  end
     chars.reverse.join
end

def       mod3 n
  if n <  0
    n = -n
    tmp  = mod3 n
    return  -tmp
  end
  return +0 if n % 3 == 0
  return +2 if n % 3 == 2 || n % 3 == -1
  return  +1
end

def   mod5 n
  if n <  0
    n = -n
    tmp = mod5 n
    flip =                  -1
    tmp * flip
  else
    n.modulo 5
  end
end

def     set_error msg
  if  !msg
    msg = 'UnknownError'
    retval  = set_error msg
    return  retval
  end
  $ERROR =
           msg
end

def      get_error_message
  $ERROR
end





eval     'n=100;fizzbuzz_loop(n)'

The program printed above is not the original submission, but it looks very similar to the real entry! When run, it will print out the well-known FizzBuzz sequence:

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
…

However, the actual competition entry will print out:

1
2
Ruby
4
Trick
Ruby
7
8
Ruby
Trick
11
Ruby
13
14
RubyTrick
…

The difference: A bunch of invisible Unicode characters sprinkled throughout the code, namely U+00AB (no-break space) and U+200B (zero width space), which drastically change how the code gets interpreted!

11th Place: "Most attractive" eto award

By Tomoya Ishida (remarks)

                           p,i,u,f,v,q    ,h,x=[],
                         Math,->x{i.sin x},->x,y,z{
                       x*=1.2;      r,a,m=(1   -y=y*1.4+0.15)/2+0.1,y+u[3*x+4*y+5*z*=1.2]  /12,x*
                     x+z*z;         l,s,b=     m**0.5,i.atan2(z,x),u[6*a]**2/36+((x*x+z*z)**0.5-r)**
                     2-(1-   a*      a)/2      /500;l-=   (1-y   )/8   *d=  (u[   2*s  +3*3*t   =1-y-
                    l/2]*    u[       3*       s-3*2       *                            t])    **2/(
                     1+i.  exp(       t        *10-   9-  5.5      ));e       =4*l /(   1+(    0.01+
                     (1-a=y-d*    (       1    -y)       /8)**    2)**0.5    -a)*(1-a    *    a+((1-
                      a*a)**2+   0.01   )**    0.5    )** 0.5    ;(i.atan(   (1-0.2*i.         asin(
                      0.98*      u[+   +5.0    *           i.    atan2(y=   3*y-3.4,x         *=3)]
                      ))*(       (0.01+x*x+     y*y      )**    0.5-0.1)    +4*(0.01+z        *z*4
          )**0.5-1)* i.atan(     a*a+e*e-1-10/(1+(40*m)**10+((a+1)*10)**10))-0.01)*b},%w&    MMM##
      TTTQQBKPTVVpQAk5Y7*pgw43v7*pgaor<*"ggau]/~"gau];-~'ga;,,,.'MerryChristmas!&*'',->x    ,y,z,
    s,m{if(m==    1);g=f   [x+=s/2,y+=s/2,z+=s/2];a,  b,c=f[x+d=0.01,y,z]-g,f[x,y+d,z]-    g,f[x,
   y,z+d]           -g;   p<<[x,y,z,a/d=(a*a+b*b+c    *c)**0.5,b/d,c/d];else;(r=0        ...n=[m,4].min).map{|i|r.map{
  |j|a,    b=[f[   x+k    =s*i/n,y+l=s*j/n,z+s],f   [x+k,y+l,z],f[    x,y+k,z+l],f[x+l,y,z+k],f[x+s,y+k,z+l],f[x+l,y++s,
 z+k]].  minmax;return    8.   times    {     |     i|q[x      +          s     *    i     [0],y+s       *i[1]      ,z+s*
i[2],    s,m/2]}if a*b          <0           &&     s/=    2  }}         ;                 end},         0,1    ..  j=128
(0..7)   .each{|i|q[i[    0]    -z=      1.0,i[1    ]-z     ,i[2]    -z,z,64]         ;    $><<   v[2   *i+64     ,2]};;;
sleep    1;loop{  r,s    ,m,    l,d,    w=i.cos(   h+=0.02   ),u[   h],i.cos(  m=    u[    2.3    *h    ]/5),u     [++m],
x.map    {[7]*j},  x.    map    {[7]    *j};;p.    each{|     x,y    ,z,a,b,   e|    x,    z=x    *r    +s*z,z     *r-s*
x;y,z     =m*y+   l*z    ,m       *z    -l*y;x,      y=64*    (x+    1  ),64   *(    1-      y     )       ;x<j    &&y<
 j&&z<            d[x    ][     y]&&   (d[x][y]     ,w       [x][      y]=z    ,(    8*     (1           +(      a*r+b+
  e*s)/2)    /2).floor)};32.times{|i|4.times{|x|w[((u[i**3]+u[h/4+i]/4)*j+x[0])%j][(h/2+u[i*i])%1*j+x[1]]=5}};f=[1,1]
      $><<27.chr+   ?[+f*  ';'+?H+(0..63)     .map{|y|x.map{|x|  v[w[x-=1  ][2*y]*8+w[x][2*y+  1]]}.join}*$/}

Run the code next Christmas for an animated terminal Christmas tree.

12th Place: "Minimum alternative of irb" mame award

By Jan Lelis (remarks), wait, me on that list? Sure, it's no mistake? Unbelievable!

eval      %w?_="";_       _=binding;l
oop(      )do    $><      <">       >\s
"if       $/>     _;p     uts        "=>
\s%p      "%[   __.e      val       (_+
=get      s||exit!)       ,_=""];rescu
e(Ex      cep   tio       n);       put
s""+      "\e    [31      m%p        \e[
0m"%      [$!     ,_=     ""]       if/
d\se      |ee      /!~    "#$!"end?*""

Run the code above to get a fully functional REPL with multi-line support:

>> 21 + 21
=> 42

>> 42.succ
=> 43

>> def announce
puts "TRICK 2018"
end
=> :announce

>> announce
TRICK 2018

For a better usage experience, error messages get displayed in red:

>> 1/0
#<ZeroDivisionError: divided by 0>
13th Place: "Most warned" yhara award

By kinaba (remarks)

def STDOUT.write (s); syswrite s
 end if def $>.write; end
s = Array.new(){}.map{|s|}
s << (-"Trick").grapheme_clusters{}        [0] # frozen_string_literal: Trick
s << ("Ruby".unpack *"ao")                 [0]
s << "#{10**2018 + 1e2018}"                [0]
s << "#{1>2>3 rescue $!.class.trust.class}"[0]
s << "#{true; Kernel.public_class_method}" [0]
s << ($ruby.object_id.coerce +2018)        [0]
result = puts s*""

This program of 10 lines does not output anything special, but as soon you run it with warnings enabled (ruby -w), each line generates two warnings (Ruby 2.5), one at compile-time, and another one at runtime!

kin.rb:1: warning: parentheses after method name is interpreted as an argument list, not a decomposed argument
kin.rb:2: warning: mismatched indentations at 'end' with 'def' at 1
kin.rb:3: warning: shadowing outer local variable - s
kin.rb:4: warning: `frozen_string_literal' is ignored after any tokens
kin.rb:5: warning: `*' interpreted as argument prefix
kin.rb:6: warning: Float 1e2018 out of range
kin.rb:7: warning: comparison '>' after comparison
kin.rb:8: warning: unused literal ignored
kin.rb:9: warning: ambiguous first argument; put parentheses or a space even after `+' operator
kin.rb:10: warning: assigned but unused variable - result
kin.rb:1: warning: method redefined; discarding old write
kin.rb:2: warning: previous definition of write was here
kin.rb:3: warning: given block not used
kin.rb:4: warning: passing a block to String#grapheme_clusters is deprecated
kin.rb:4: warning: character class has duplicated range: /\X/
kin.rb:5: warning: unknown unpack directive 'o' in 'ao'
kin.rb:6: warning: Bignum out of Float range
kin.rb:7: warning: trust is deprecated and its behavior is same as untaint
kin.rb:8: warning: public_class_method with no argument is just ignored
kin.rb:9: warning: global variable `$ruby' not initialized
kin.rb:10: warning: #<IO:<STDOUT>>.write is outdated interface which accepts just one argument
TRICK2018
Honorable Mentions Also See
https://idiosyncratic-ruby.com/75-ruby-tricks-of-2018.html
Super Snakes
Show full content

Have you ever been confused by the __underscores__ required by some of __RUBY__'s features? You can get it right with this overview of all of "super snake" keywords and methods.

There are three different types of underscore-wrapped syntaxes in the Ruby core language:

  • keywords
  • Object methods and
  • Kernel methods.

Let us take a look at each of them, and understand the motivations behind. Or directly jump to:

__FILE____LINE____ENCODING____END____method____callee____dir____id____send__

Keywords (Built into Ruby Syntax)

These are directly translated by the Ruby interpreter: You cannot use meta-programming with these, since they will always return the corresponding value directly:

__FILE__

Returns the current source file's name. Might be special value for unusual invocations:

Context Value File, directly executed path name, can be relative File, required / loaded absolute path IRB "(irb)" eval'd "(eval)" $ ruby -e "-e" Standard Input "-" __LINE__

Returns the line number in the current source file. Also works in IRB and with code executed with $ ruby -e, STDIN or eval.

__ENCODING__

Returns the source file's encoding, as specified per magic comment. The default source file encoding is UTF-8. The important thing to understand is that this value should correspond to the actual encoding of the source file, so to change the source encoding, it is not enough to just change the magic comment, you will also need to convert the source file.

You should also note that this is unrelated to some other global encoding configurations, which serve different purposes:

__END__ (at beginning of line)

A special syntax which will end the source file earlier and create big data.

Underscore-Wrapped Kernel Methods

These special Kernel methods are lowercased to highlight the fact that they are actually just methods and no built-in keywords.

__method__ and __callee__

Both return the current method's name, but they differ in a detail: When using a method alias, __callee__ will return the aliased method name, while __method__ would return the original name:

def example!
  p [__method__, __callee__]
end
alias test! example!

example! # => [:example!, :example!]
test! # => [:example!, :test!]

Two similar and useful methods are Kernel#caller and Kernel#caller_locations, which provide some more context.

__dir__

Returns File.dirname(File.realpath(__FILE__)), which is the absolute path of the directory of the current source file.

While it also works in IRB, it will return nil in eval, $ ruby -e, and STDIN contexts.

Underscore-Wrapped BasicObject Methods

Both of the following methods are so important that every object (even those that inherit from BasicObject directly) should have. This is why they got some underscore companions.

__id__

Returns the object id, just like Object#object_id. It mainly exists for historical reasons, most people use object_id nowadays.

__send__

The __send__ method is an alias of the Object#send, which dynamically calls the method given as a symbol argument. Its purpose is that you should still be able to use the send functionality in case someone redefines the send method. The interpreter will issue a warning¹ should you try to redefine or remove it:

warning: redefining `__send__' may cause serious problems

Nevertheless, it is probably not a good idea either to redefine non-underscore-wrapped send, since a lot of meta-programming relies on it…

¹ This is not true for __id__ - Ruby will not complain if you choose to redefine it. It will complain for object_id though.

Also See

Many thanks to Shannon Skipper for pointing out that the mysterious SUPPORT_JOKE compiler option's __goto__ and __label__ also make use of underscores

https://idiosyncratic-ruby.com/74-super-snakes.html
Unicode Version Mapping
Show full content

The Ruby core team cares a lot about Unicode, and this is why we have pretty good Unicode support in the language.

Even though the Unicode standard evolves constantly - it gets updated at least once a year - Ruby's Unicode support is often only a little bit behind the current version of Unicode. The following tables list which Ruby version supports which version of Unicode / Emoji:

Ruby / Unicode Ruby Version Unicode Version 3.3 15.0.0 3.2 15.0.0 3.1 13.0.0 3.0 12.1.0 2.7 12.1.0 2.6.3+ 12.1.0¹ 2.6.2 12.0.0 2.6.1- 11.0.0 2.5 10.0.0 2.4 9.0.0 2.3 8.0.0 2.2 7.0.0 2.1 6.1.0 2.0 6.1.0 1.9 5.2.0

¹ Unicode 12.1 introduced a single character

Starting with Ruby 2.4, you can find out your Ruby version's Unicode support with:

RbConfig::CONFIG["UNICODE_VERSION"]
Ruby / Emoji Ruby Version Emoji Version 3.3 15.0 3.2 15.0 3.1 13.1 3.0 12.1 2.7 12.1 2.6.2+ 12.0 2.6.1- 11.0 2.5 5.0

Starting with Ruby 2.6, you can find out your Ruby version's Emoji support with:

RbConfig::CONFIG["UNICODE_EMOJI_VERSION"]
Also See
https://idiosyncratic-ruby.com/73-unicode-version-mapping.html
Clear Case of Unclear Casing
Show full content

Recent Ruby versions allow you to choose from a wide-range of uppercase letters - beyond just ASCII - to start a constant / class name:

class Österreich
  # 00D6 ├─ Ö   ├─ LATIN CAPITAL LETTER O WITH DIAERESIS
end
# Syntax OK

However, it is not possible to use just any Unicode character:

class ℻
  # 213B ├─ ℻   ├─ FACSIMILE SIGN
end
# SyntaxError

Only characters of the categories Uppercase_Letter or Titlecase_Letter of your current Ruby's Unicode version are allowed. This can be trickier that you might think at first, as illustrated here:

class 🅆
  # 1F146 ├─ 🅆    ├─ SQUARED LATIN CAPITAL LETTER W
end
# Syntax OK

class 🅏
  # 1F14F ├─ 🅏    ├─ SQUARED WC
end
# SyntaxError

Or consider this case:

class 𐲄
  # 10C84 ├─ 𐲄    ├─ OLD HUNGARIAN CAPITAL LETTER EC
end
# Syntax OK

class 🡓
  # 1F853 ├─ 🡓    ├─ DOWNWARDS SANS-SERIF ARROW
end
# SyntaxError
Start a Class

For reference, this is the list of allowed characters to start a class/constant, as of Ruby 3.0:

Char Codepoint Name A U+0041 LATIN CAPITAL LETTER A B U+0042 LATIN CAPITAL LETTER B C U+0043 LATIN CAPITAL LETTER C D U+0044 LATIN CAPITAL LETTER D E U+0045 LATIN CAPITAL LETTER E F U+0046 LATIN CAPITAL LETTER F G U+0047 LATIN CAPITAL LETTER G H U+0048 LATIN CAPITAL LETTER H I U+0049 LATIN CAPITAL LETTER I J U+004A LATIN CAPITAL LETTER J K U+004B LATIN CAPITAL LETTER K L U+004C LATIN CAPITAL LETTER L M U+004D LATIN CAPITAL LETTER M N U+004E LATIN CAPITAL LETTER N O U+004F LATIN CAPITAL LETTER O P U+0050 LATIN CAPITAL LETTER P Q U+0051 LATIN CAPITAL LETTER Q R U+0052 LATIN CAPITAL LETTER R S U+0053 LATIN CAPITAL LETTER S T U+0054 LATIN CAPITAL LETTER T U U+0055 LATIN CAPITAL LETTER U V U+0056 LATIN CAPITAL LETTER V W U+0057 LATIN CAPITAL LETTER W X U+0058 LATIN CAPITAL LETTER X Y U+0059 LATIN CAPITAL LETTER Y Z U+005A LATIN CAPITAL LETTER Z À U+00C0 LATIN CAPITAL LETTER A WITH GRAVE Á U+00C1 LATIN CAPITAL LETTER A WITH ACUTE  U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX à U+00C3 LATIN CAPITAL LETTER A WITH TILDE Ä U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS Å U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE Æ U+00C6 LATIN CAPITAL LETTER AE Ç U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA È U+00C8 LATIN CAPITAL LETTER E WITH GRAVE É U+00C9 LATIN CAPITAL LETTER E WITH ACUTE Ê U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX Ë U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS Ì U+00CC LATIN CAPITAL LETTER I WITH GRAVE Í U+00CD LATIN CAPITAL LETTER I WITH ACUTE Î U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX Ï U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS Ð U+00D0 LATIN CAPITAL LETTER ETH Ñ U+00D1 LATIN CAPITAL LETTER N WITH TILDE Ò U+00D2 LATIN CAPITAL LETTER O WITH GRAVE Ó U+00D3 LATIN CAPITAL LETTER O WITH ACUTE Ô U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX Õ U+00D5 LATIN CAPITAL LETTER O WITH TILDE Ö U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS Ø U+00D8 LATIN CAPITAL LETTER O WITH STROKE Ù U+00D9 LATIN CAPITAL LETTER U WITH GRAVE Ú U+00DA LATIN CAPITAL LETTER U WITH ACUTE Û U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX Ü U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS Ý U+00DD LATIN CAPITAL LETTER Y WITH ACUTE Þ U+00DE LATIN CAPITAL LETTER THORN Ā U+0100 LATIN CAPITAL LETTER A WITH MACRON Ă U+0102 LATIN CAPITAL LETTER A WITH BREVE Ą U+0104 LATIN CAPITAL LETTER A WITH OGONEK Ć U+0106 LATIN CAPITAL LETTER C WITH ACUTE Ĉ U+0108 LATIN CAPITAL LETTER C WITH CIRCUMFLEX Ċ U+010A LATIN CAPITAL LETTER C WITH DOT ABOVE Č U+010C LATIN CAPITAL LETTER C WITH CARON Ď U+010E LATIN CAPITAL LETTER D WITH CARON Đ U+0110 LATIN CAPITAL LETTER D WITH STROKE Ē U+0112 LATIN CAPITAL LETTER E WITH MACRON Ĕ U+0114 LATIN CAPITAL LETTER E WITH BREVE Ė U+0116 LATIN CAPITAL LETTER E WITH DOT ABOVE Ę U+0118 LATIN CAPITAL LETTER E WITH OGONEK Ě U+011A LATIN CAPITAL LETTER E WITH CARON Ĝ U+011C LATIN CAPITAL LETTER G WITH CIRCUMFLEX Ğ U+011E LATIN CAPITAL LETTER G WITH BREVE Ġ U+0120 LATIN CAPITAL LETTER G WITH DOT ABOVE Ģ U+0122 LATIN CAPITAL LETTER G WITH CEDILLA Ĥ U+0124 LATIN CAPITAL LETTER H WITH CIRCUMFLEX Ħ U+0126 LATIN CAPITAL LETTER H WITH STROKE Ĩ U+0128 LATIN CAPITAL LETTER I WITH TILDE Ī U+012A LATIN CAPITAL LETTER I WITH MACRON Ĭ U+012C LATIN CAPITAL LETTER I WITH BREVE Į U+012E LATIN CAPITAL LETTER I WITH OGONEK İ U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE IJ U+0132 LATIN CAPITAL LIGATURE IJ Ĵ U+0134 LATIN CAPITAL LETTER J WITH CIRCUMFLEX Ķ U+0136 LATIN CAPITAL LETTER K WITH CEDILLA Ĺ U+0139 LATIN CAPITAL LETTER L WITH ACUTE Ļ U+013B LATIN CAPITAL LETTER L WITH CEDILLA Ľ U+013D LATIN CAPITAL LETTER L WITH CARON Ŀ U+013F LATIN CAPITAL LETTER L WITH MIDDLE DOT Ł U+0141 LATIN CAPITAL LETTER L WITH STROKE Ń U+0143 LATIN CAPITAL LETTER N WITH ACUTE Ņ U+0145 LATIN CAPITAL LETTER N WITH CEDILLA Ň U+0147 LATIN CAPITAL LETTER N WITH CARON Ŋ U+014A LATIN CAPITAL LETTER ENG Ō U+014C LATIN CAPITAL LETTER O WITH MACRON Ŏ U+014E LATIN CAPITAL LETTER O WITH BREVE Ő U+0150 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE Œ U+0152 LATIN CAPITAL LIGATURE OE Ŕ U+0154 LATIN CAPITAL LETTER R WITH ACUTE Ŗ U+0156 LATIN CAPITAL LETTER R WITH CEDILLA Ř U+0158 LATIN CAPITAL LETTER R WITH CARON Ś U+015A LATIN CAPITAL LETTER S WITH ACUTE Ŝ U+015C LATIN CAPITAL LETTER S WITH CIRCUMFLEX Ş U+015E LATIN CAPITAL LETTER S WITH CEDILLA Š U+0160 LATIN CAPITAL LETTER S WITH CARON Ţ U+0162 LATIN CAPITAL LETTER T WITH CEDILLA Ť U+0164 LATIN CAPITAL LETTER T WITH CARON Ŧ U+0166 LATIN CAPITAL LETTER T WITH STROKE Ũ U+0168 LATIN CAPITAL LETTER U WITH TILDE Ū U+016A LATIN CAPITAL LETTER U WITH MACRON Ŭ U+016C LATIN CAPITAL LETTER U WITH BREVE Ů U+016E LATIN CAPITAL LETTER U WITH RING ABOVE Ű U+0170 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE Ų U+0172 LATIN CAPITAL LETTER U WITH OGONEK Ŵ U+0174 LATIN CAPITAL LETTER W WITH CIRCUMFLEX Ŷ U+0176 LATIN CAPITAL LETTER Y WITH CIRCUMFLEX Ÿ U+0178 LATIN CAPITAL LETTER Y WITH DIAERESIS Ź U+0179 LATIN CAPITAL LETTER Z WITH ACUTE Ż U+017B LATIN CAPITAL LETTER Z WITH DOT ABOVE Ž U+017D LATIN CAPITAL LETTER Z WITH CARON Ɓ U+0181 LATIN CAPITAL LETTER B WITH HOOK Ƃ U+0182 LATIN CAPITAL LETTER B WITH TOPBAR Ƅ U+0184 LATIN CAPITAL LETTER TONE SIX Ɔ U+0186 LATIN CAPITAL LETTER OPEN O Ƈ U+0187 LATIN CAPITAL LETTER C WITH HOOK Ɖ U+0189 LATIN CAPITAL LETTER AFRICAN D Ɗ U+018A LATIN CAPITAL LETTER D WITH HOOK Ƌ U+018B LATIN CAPITAL LETTER D WITH TOPBAR Ǝ U+018E LATIN CAPITAL LETTER REVERSED E Ə U+018F LATIN CAPITAL LETTER SCHWA Ɛ U+0190 LATIN CAPITAL LETTER OPEN E Ƒ U+0191 LATIN CAPITAL LETTER F WITH HOOK Ɠ U+0193 LATIN CAPITAL LETTER G WITH HOOK Ɣ U+0194 LATIN CAPITAL LETTER GAMMA Ɩ U+0196 LATIN CAPITAL LETTER IOTA Ɨ U+0197 LATIN CAPITAL LETTER I WITH STROKE Ƙ U+0198 LATIN CAPITAL LETTER K WITH HOOK Ɯ U+019C LATIN CAPITAL LETTER TURNED M Ɲ U+019D LATIN CAPITAL LETTER N WITH LEFT HOOK Ɵ U+019F LATIN CAPITAL LETTER O WITH MIDDLE TILDE Ơ U+01A0 LATIN CAPITAL LETTER O WITH HORN Ƣ U+01A2 LATIN CAPITAL LETTER OI Ƥ U+01A4 LATIN CAPITAL LETTER P WITH HOOK Ʀ U+01A6 LATIN LETTER YR Ƨ U+01A7 LATIN CAPITAL LETTER TONE TWO Ʃ U+01A9 LATIN CAPITAL LETTER ESH Ƭ U+01AC LATIN CAPITAL LETTER T WITH HOOK Ʈ U+01AE LATIN CAPITAL LETTER T WITH RETROFLEX HOOK Ư U+01AF LATIN CAPITAL LETTER U WITH HORN Ʊ U+01B1 LATIN CAPITAL LETTER UPSILON Ʋ U+01B2 LATIN CAPITAL LETTER V WITH HOOK Ƴ U+01B3 LATIN CAPITAL LETTER Y WITH HOOK Ƶ U+01B5 LATIN CAPITAL LETTER Z WITH STROKE Ʒ U+01B7 LATIN CAPITAL LETTER EZH Ƹ U+01B8 LATIN CAPITAL LETTER EZH REVERSED Ƽ U+01BC LATIN CAPITAL LETTER TONE FIVE DŽ U+01C4 LATIN CAPITAL LETTER DZ WITH CARON Dž U+01C5 LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON LJ U+01C7 LATIN CAPITAL LETTER LJ Lj U+01C8 LATIN CAPITAL LETTER L WITH SMALL LETTER J NJ U+01CA LATIN CAPITAL LETTER NJ Nj U+01CB LATIN CAPITAL LETTER N WITH SMALL LETTER J Ǎ U+01CD LATIN CAPITAL LETTER A WITH CARON Ǐ U+01CF LATIN CAPITAL LETTER I WITH CARON Ǒ U+01D1 LATIN CAPITAL LETTER O WITH CARON Ǔ U+01D3 LATIN CAPITAL LETTER U WITH CARON Ǖ U+01D5 LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON Ǘ U+01D7 LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE Ǚ U+01D9 LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON Ǜ U+01DB LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE Ǟ U+01DE LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON Ǡ U+01E0 LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON Ǣ U+01E2 LATIN CAPITAL LETTER AE WITH MACRON Ǥ U+01E4 LATIN CAPITAL LETTER G WITH STROKE Ǧ U+01E6 LATIN CAPITAL LETTER G WITH CARON Ǩ U+01E8 LATIN CAPITAL LETTER K WITH CARON Ǫ U+01EA LATIN CAPITAL LETTER O WITH OGONEK Ǭ U+01EC LATIN CAPITAL LETTER O WITH OGONEK AND MACRON Ǯ U+01EE LATIN CAPITAL LETTER EZH WITH CARON DZ U+01F1 LATIN CAPITAL LETTER DZ Dz U+01F2 LATIN CAPITAL LETTER D WITH SMALL LETTER Z Ǵ U+01F4 LATIN CAPITAL LETTER G WITH ACUTE Ƕ U+01F6 LATIN CAPITAL LETTER HWAIR Ƿ U+01F7 LATIN CAPITAL LETTER WYNN Ǹ U+01F8 LATIN CAPITAL LETTER N WITH GRAVE Ǻ U+01FA LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE Ǽ U+01FC LATIN CAPITAL LETTER AE WITH ACUTE Ǿ U+01FE LATIN CAPITAL LETTER O WITH STROKE AND ACUTE Ȁ U+0200 LATIN CAPITAL LETTER A WITH DOUBLE GRAVE Ȃ U+0202 LATIN CAPITAL LETTER A WITH INVERTED BREVE Ȅ U+0204 LATIN CAPITAL LETTER E WITH DOUBLE GRAVE Ȇ U+0206 LATIN CAPITAL LETTER E WITH INVERTED BREVE Ȉ U+0208 LATIN CAPITAL LETTER I WITH DOUBLE GRAVE Ȋ U+020A LATIN CAPITAL LETTER I WITH INVERTED BREVE Ȍ U+020C LATIN CAPITAL LETTER O WITH DOUBLE GRAVE Ȏ U+020E LATIN CAPITAL LETTER O WITH INVERTED BREVE Ȑ U+0210 LATIN CAPITAL LETTER R WITH DOUBLE GRAVE Ȓ U+0212 LATIN CAPITAL LETTER R WITH INVERTED BREVE Ȕ U+0214 LATIN CAPITAL LETTER U WITH DOUBLE GRAVE Ȗ U+0216 LATIN CAPITAL LETTER U WITH INVERTED BREVE Ș U+0218 LATIN CAPITAL LETTER S WITH COMMA BELOW Ț U+021A LATIN CAPITAL LETTER T WITH COMMA BELOW Ȝ U+021C LATIN CAPITAL LETTER YOGH Ȟ U+021E LATIN CAPITAL LETTER H WITH CARON Ƞ U+0220 LATIN CAPITAL LETTER N WITH LONG RIGHT LEG Ȣ U+0222 LATIN CAPITAL LETTER OU Ȥ U+0224 LATIN CAPITAL LETTER Z WITH HOOK Ȧ U+0226 LATIN CAPITAL LETTER A WITH DOT ABOVE Ȩ U+0228 LATIN CAPITAL LETTER E WITH CEDILLA Ȫ U+022A LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON Ȭ U+022C LATIN CAPITAL LETTER O WITH TILDE AND MACRON Ȯ U+022E LATIN CAPITAL LETTER O WITH DOT ABOVE Ȱ U+0230 LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON Ȳ U+0232 LATIN CAPITAL LETTER Y WITH MACRON Ⱥ U+023A LATIN CAPITAL LETTER A WITH STROKE Ȼ U+023B LATIN CAPITAL LETTER C WITH STROKE Ƚ U+023D LATIN CAPITAL LETTER L WITH BAR Ⱦ U+023E LATIN CAPITAL LETTER T WITH DIAGONAL STROKE Ɂ U+0241 LATIN CAPITAL LETTER GLOTTAL STOP Ƀ U+0243 LATIN CAPITAL LETTER B WITH STROKE Ʉ U+0244 LATIN CAPITAL LETTER U BAR Ʌ U+0245 LATIN CAPITAL LETTER TURNED V Ɇ U+0246 LATIN CAPITAL LETTER E WITH STROKE Ɉ U+0248 LATIN CAPITAL LETTER J WITH STROKE Ɋ U+024A LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL Ɍ U+024C LATIN CAPITAL LETTER R WITH STROKE Ɏ U+024E LATIN CAPITAL LETTER Y WITH STROKE Ͱ U+0370 GREEK CAPITAL LETTER HETA Ͳ U+0372 GREEK CAPITAL LETTER ARCHAIC SAMPI Ͷ U+0376 GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA Ϳ U+037F GREEK CAPITAL LETTER YOT Ά U+0386 GREEK CAPITAL LETTER ALPHA WITH TONOS Έ U+0388 GREEK CAPITAL LETTER EPSILON WITH TONOS Ή U+0389 GREEK CAPITAL LETTER ETA WITH TONOS Ί U+038A GREEK CAPITAL LETTER IOTA WITH TONOS Ό U+038C GREEK CAPITAL LETTER OMICRON WITH TONOS Ύ U+038E GREEK CAPITAL LETTER UPSILON WITH TONOS Ώ U+038F GREEK CAPITAL LETTER OMEGA WITH TONOS Α U+0391 GREEK CAPITAL LETTER ALPHA Β U+0392 GREEK CAPITAL LETTER BETA Γ U+0393 GREEK CAPITAL LETTER GAMMA Δ U+0394 GREEK CAPITAL LETTER DELTA Ε U+0395 GREEK CAPITAL LETTER EPSILON Ζ U+0396 GREEK CAPITAL LETTER ZETA Η U+0397 GREEK CAPITAL LETTER ETA Θ U+0398 GREEK CAPITAL LETTER THETA Ι U+0399 GREEK CAPITAL LETTER IOTA Κ U+039A GREEK CAPITAL LETTER KAPPA Λ U+039B GREEK CAPITAL LETTER LAMDA Μ U+039C GREEK CAPITAL LETTER MU Ν U+039D GREEK CAPITAL LETTER NU Ξ U+039E GREEK CAPITAL LETTER XI Ο U+039F GREEK CAPITAL LETTER OMICRON Π U+03A0 GREEK CAPITAL LETTER PI Ρ U+03A1 GREEK CAPITAL LETTER RHO Σ U+03A3 GREEK CAPITAL LETTER SIGMA Τ U+03A4 GREEK CAPITAL LETTER TAU Υ U+03A5 GREEK CAPITAL LETTER UPSILON Φ U+03A6 GREEK CAPITAL LETTER PHI Χ U+03A7 GREEK CAPITAL LETTER CHI Ψ U+03A8 GREEK CAPITAL LETTER PSI Ω U+03A9 GREEK CAPITAL LETTER OMEGA Ϊ U+03AA GREEK CAPITAL LETTER IOTA WITH DIALYTIKA Ϋ U+03AB GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA Ϗ U+03CF GREEK CAPITAL KAI SYMBOL ϒ U+03D2 GREEK UPSILON WITH HOOK SYMBOL ϓ U+03D3 GREEK UPSILON WITH ACUTE AND HOOK SYMBOL ϔ U+03D4 GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL Ϙ U+03D8 GREEK LETTER ARCHAIC KOPPA Ϛ U+03DA GREEK LETTER STIGMA Ϝ U+03DC GREEK LETTER DIGAMMA Ϟ U+03DE GREEK LETTER KOPPA Ϡ U+03E0 GREEK LETTER SAMPI Ϣ U+03E2 COPTIC CAPITAL LETTER SHEI Ϥ U+03E4 COPTIC CAPITAL LETTER FEI Ϧ U+03E6 COPTIC CAPITAL LETTER KHEI Ϩ U+03E8 COPTIC CAPITAL LETTER HORI Ϫ U+03EA COPTIC CAPITAL LETTER GANGIA Ϭ U+03EC COPTIC CAPITAL LETTER SHIMA Ϯ U+03EE COPTIC CAPITAL LETTER DEI ϴ U+03F4 GREEK CAPITAL THETA SYMBOL Ϸ U+03F7 GREEK CAPITAL LETTER SHO Ϲ U+03F9 GREEK CAPITAL LUNATE SIGMA SYMBOL Ϻ U+03FA GREEK CAPITAL LETTER SAN Ͻ U+03FD GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL Ͼ U+03FE GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL Ͽ U+03FF GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL Ѐ U+0400 CYRILLIC CAPITAL LETTER IE WITH GRAVE Ё U+0401 CYRILLIC CAPITAL LETTER IO Ђ U+0402 CYRILLIC CAPITAL LETTER DJE Ѓ U+0403 CYRILLIC CAPITAL LETTER GJE Є U+0404 CYRILLIC CAPITAL LETTER UKRAINIAN IE Ѕ U+0405 CYRILLIC CAPITAL LETTER DZE І U+0406 CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I Ї U+0407 CYRILLIC CAPITAL LETTER YI Ј U+0408 CYRILLIC CAPITAL LETTER JE Љ U+0409 CYRILLIC CAPITAL LETTER LJE Њ U+040A CYRILLIC CAPITAL LETTER NJE Ћ U+040B CYRILLIC CAPITAL LETTER TSHE Ќ U+040C CYRILLIC CAPITAL LETTER KJE Ѝ U+040D CYRILLIC CAPITAL LETTER I WITH GRAVE Ў U+040E CYRILLIC CAPITAL LETTER SHORT U Џ U+040F CYRILLIC CAPITAL LETTER DZHE А U+0410 CYRILLIC CAPITAL LETTER A Б U+0411 CYRILLIC CAPITAL LETTER BE В U+0412 CYRILLIC CAPITAL LETTER VE Г U+0413 CYRILLIC CAPITAL LETTER GHE Д U+0414 CYRILLIC CAPITAL LETTER DE Е U+0415 CYRILLIC CAPITAL LETTER IE Ж U+0416 CYRILLIC CAPITAL LETTER ZHE З U+0417 CYRILLIC CAPITAL LETTER ZE И U+0418 CYRILLIC CAPITAL LETTER I Й U+0419 CYRILLIC CAPITAL LETTER SHORT I К U+041A CYRILLIC CAPITAL LETTER KA Л U+041B CYRILLIC CAPITAL LETTER EL М U+041C CYRILLIC CAPITAL LETTER EM Н U+041D CYRILLIC CAPITAL LETTER EN О U+041E CYRILLIC CAPITAL LETTER O П U+041F CYRILLIC CAPITAL LETTER PE Р U+0420 CYRILLIC CAPITAL LETTER ER С U+0421 CYRILLIC CAPITAL LETTER ES Т U+0422 CYRILLIC CAPITAL LETTER TE У U+0423 CYRILLIC CAPITAL LETTER U Ф U+0424 CYRILLIC CAPITAL LETTER EF Х U+0425 CYRILLIC CAPITAL LETTER HA Ц U+0426 CYRILLIC CAPITAL LETTER TSE Ч U+0427 CYRILLIC CAPITAL LETTER CHE Ш U+0428 CYRILLIC CAPITAL LETTER SHA Щ U+0429 CYRILLIC CAPITAL LETTER SHCHA Ъ U+042A CYRILLIC CAPITAL LETTER HARD SIGN Ы U+042B CYRILLIC CAPITAL LETTER YERU Ь U+042C CYRILLIC CAPITAL LETTER SOFT SIGN Э U+042D CYRILLIC CAPITAL LETTER E Ю U+042E CYRILLIC CAPITAL LETTER YU Я U+042F CYRILLIC CAPITAL LETTER YA Ѡ U+0460 CYRILLIC CAPITAL LETTER OMEGA Ѣ U+0462 CYRILLIC CAPITAL LETTER YAT Ѥ U+0464 CYRILLIC CAPITAL LETTER IOTIFIED E Ѧ U+0466 CYRILLIC CAPITAL LETTER LITTLE YUS Ѩ U+0468 CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS Ѫ U+046A CYRILLIC CAPITAL LETTER BIG YUS Ѭ U+046C CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS Ѯ U+046E CYRILLIC CAPITAL LETTER KSI Ѱ U+0470 CYRILLIC CAPITAL LETTER PSI Ѳ U+0472 CYRILLIC CAPITAL LETTER FITA Ѵ U+0474 CYRILLIC CAPITAL LETTER IZHITSA Ѷ U+0476 CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT Ѹ U+0478 CYRILLIC CAPITAL LETTER UK Ѻ U+047A CYRILLIC CAPITAL LETTER ROUND OMEGA Ѽ U+047C CYRILLIC CAPITAL LETTER OMEGA WITH TITLO Ѿ U+047E CYRILLIC CAPITAL LETTER OT Ҁ U+0480 CYRILLIC CAPITAL LETTER KOPPA Ҋ U+048A CYRILLIC CAPITAL LETTER SHORT I WITH TAIL Ҍ U+048C CYRILLIC CAPITAL LETTER SEMISOFT SIGN Ҏ U+048E CYRILLIC CAPITAL LETTER ER WITH TICK Ґ U+0490 CYRILLIC CAPITAL LETTER GHE WITH UPTURN Ғ U+0492 CYRILLIC CAPITAL LETTER GHE WITH STROKE Ҕ U+0494 CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK Җ U+0496 CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER Ҙ U+0498 CYRILLIC CAPITAL LETTER ZE WITH DESCENDER Қ U+049A CYRILLIC CAPITAL LETTER KA WITH DESCENDER Ҝ U+049C CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE Ҟ U+049E CYRILLIC CAPITAL LETTER KA WITH STROKE Ҡ U+04A0 CYRILLIC CAPITAL LETTER BASHKIR KA Ң U+04A2 CYRILLIC CAPITAL LETTER EN WITH DESCENDER Ҥ U+04A4 CYRILLIC CAPITAL LIGATURE EN GHE Ҧ U+04A6 CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK Ҩ U+04A8 CYRILLIC CAPITAL LETTER ABKHASIAN HA Ҫ U+04AA CYRILLIC CAPITAL LETTER ES WITH DESCENDER Ҭ U+04AC CYRILLIC CAPITAL LETTER TE WITH DESCENDER Ү U+04AE CYRILLIC CAPITAL LETTER STRAIGHT U Ұ U+04B0 CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE Ҳ U+04B2 CYRILLIC CAPITAL LETTER HA WITH DESCENDER Ҵ U+04B4 CYRILLIC CAPITAL LIGATURE TE TSE Ҷ U+04B6 CYRILLIC CAPITAL LETTER CHE WITH DESCENDER Ҹ U+04B8 CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE Һ U+04BA CYRILLIC CAPITAL LETTER SHHA Ҽ U+04BC CYRILLIC CAPITAL LETTER ABKHASIAN CHE Ҿ U+04BE CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER Ӏ U+04C0 CYRILLIC LETTER PALOCHKA Ӂ U+04C1 CYRILLIC CAPITAL LETTER ZHE WITH BREVE Ӄ U+04C3 CYRILLIC CAPITAL LETTER KA WITH HOOK Ӆ U+04C5 CYRILLIC CAPITAL LETTER EL WITH TAIL Ӈ U+04C7 CYRILLIC CAPITAL LETTER EN WITH HOOK Ӊ U+04C9 CYRILLIC CAPITAL LETTER EN WITH TAIL Ӌ U+04CB CYRILLIC CAPITAL LETTER KHAKASSIAN CHE Ӎ U+04CD CYRILLIC CAPITAL LETTER EM WITH TAIL Ӑ U+04D0 CYRILLIC CAPITAL LETTER A WITH BREVE Ӓ U+04D2 CYRILLIC CAPITAL LETTER A WITH DIAERESIS Ӕ U+04D4 CYRILLIC CAPITAL LIGATURE A IE Ӗ U+04D6 CYRILLIC CAPITAL LETTER IE WITH BREVE Ә U+04D8 CYRILLIC CAPITAL LETTER SCHWA Ӛ U+04DA CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS Ӝ U+04DC CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS Ӟ U+04DE CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS Ӡ U+04E0 CYRILLIC CAPITAL LETTER ABKHASIAN DZE Ӣ U+04E2 CYRILLIC CAPITAL LETTER I WITH MACRON Ӥ U+04E4 CYRILLIC CAPITAL LETTER I WITH DIAERESIS Ӧ U+04E6 CYRILLIC CAPITAL LETTER O WITH DIAERESIS Ө U+04E8 CYRILLIC CAPITAL LETTER BARRED O Ӫ U+04EA CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS Ӭ U+04EC CYRILLIC CAPITAL LETTER E WITH DIAERESIS Ӯ U+04EE CYRILLIC CAPITAL LETTER U WITH MACRON Ӱ U+04F0 CYRILLIC CAPITAL LETTER U WITH DIAERESIS Ӳ U+04F2 CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE Ӵ U+04F4 CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS Ӷ U+04F6 CYRILLIC CAPITAL LETTER GHE WITH DESCENDER Ӹ U+04F8 CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS Ӻ U+04FA CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK Ӽ U+04FC CYRILLIC CAPITAL LETTER HA WITH HOOK Ӿ U+04FE CYRILLIC CAPITAL LETTER HA WITH STROKE Ԁ U+0500 CYRILLIC CAPITAL LETTER KOMI DE Ԃ U+0502 CYRILLIC CAPITAL LETTER KOMI DJE Ԅ U+0504 CYRILLIC CAPITAL LETTER KOMI ZJE Ԇ U+0506 CYRILLIC CAPITAL LETTER KOMI DZJE Ԉ U+0508 CYRILLIC CAPITAL LETTER KOMI LJE Ԋ U+050A CYRILLIC CAPITAL LETTER KOMI NJE Ԍ U+050C CYRILLIC CAPITAL LETTER KOMI SJE Ԏ U+050E CYRILLIC CAPITAL LETTER KOMI TJE Ԑ U+0510 CYRILLIC CAPITAL LETTER REVERSED ZE Ԓ U+0512 CYRILLIC CAPITAL LETTER EL WITH HOOK Ԕ U+0514 CYRILLIC CAPITAL LETTER LHA Ԗ U+0516 CYRILLIC CAPITAL LETTER RHA Ԙ U+0518 CYRILLIC CAPITAL LETTER YAE Ԛ U+051A CYRILLIC CAPITAL LETTER QA Ԝ U+051C CYRILLIC CAPITAL LETTER WE Ԟ U+051E CYRILLIC CAPITAL LETTER ALEUT KA Ԡ U+0520 CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK Ԣ U+0522 CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK Ԥ U+0524 CYRILLIC CAPITAL LETTER PE WITH DESCENDER Ԧ U+0526 CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER Ԩ U+0528 CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK Ԫ U+052A CYRILLIC CAPITAL LETTER DZZHE Ԭ U+052C CYRILLIC CAPITAL LETTER DCHE Ԯ U+052E CYRILLIC CAPITAL LETTER EL WITH DESCENDER Ա U+0531 ARMENIAN CAPITAL LETTER AYB Բ U+0532 ARMENIAN CAPITAL LETTER BEN Գ U+0533 ARMENIAN CAPITAL LETTER GIM Դ U+0534 ARMENIAN CAPITAL LETTER DA Ե U+0535 ARMENIAN CAPITAL LETTER ECH Զ U+0536 ARMENIAN CAPITAL LETTER ZA Է U+0537 ARMENIAN CAPITAL LETTER EH Ը U+0538 ARMENIAN CAPITAL LETTER ET Թ U+0539 ARMENIAN CAPITAL LETTER TO Ժ U+053A ARMENIAN CAPITAL LETTER ZHE Ի U+053B ARMENIAN CAPITAL LETTER INI Լ U+053C ARMENIAN CAPITAL LETTER LIWN Խ U+053D ARMENIAN CAPITAL LETTER XEH Ծ U+053E ARMENIAN CAPITAL LETTER CA Կ U+053F ARMENIAN CAPITAL LETTER KEN Հ U+0540 ARMENIAN CAPITAL LETTER HO Ձ U+0541 ARMENIAN CAPITAL LETTER JA Ղ U+0542 ARMENIAN CAPITAL LETTER GHAD Ճ U+0543 ARMENIAN CAPITAL LETTER CHEH Մ U+0544 ARMENIAN CAPITAL LETTER MEN Յ U+0545 ARMENIAN CAPITAL LETTER YI Ն U+0546 ARMENIAN CAPITAL LETTER NOW Շ U+0547 ARMENIAN CAPITAL LETTER SHA Ո U+0548 ARMENIAN CAPITAL LETTER VO Չ U+0549 ARMENIAN CAPITAL LETTER CHA Պ U+054A ARMENIAN CAPITAL LETTER PEH Ջ U+054B ARMENIAN CAPITAL LETTER JHEH Ռ U+054C ARMENIAN CAPITAL LETTER RA Ս U+054D ARMENIAN CAPITAL LETTER SEH Վ U+054E ARMENIAN CAPITAL LETTER VEW Տ U+054F ARMENIAN CAPITAL LETTER TIWN Ր U+0550 ARMENIAN CAPITAL LETTER REH Ց U+0551 ARMENIAN CAPITAL LETTER CO Ւ U+0552 ARMENIAN CAPITAL LETTER YIWN Փ U+0553 ARMENIAN CAPITAL LETTER PIWR Ք U+0554 ARMENIAN CAPITAL LETTER KEH Օ U+0555 ARMENIAN CAPITAL LETTER OH Ֆ U+0556 ARMENIAN CAPITAL LETTER FEH Ⴀ U+10A0 GEORGIAN CAPITAL LETTER AN Ⴁ U+10A1 GEORGIAN CAPITAL LETTER BAN Ⴂ U+10A2 GEORGIAN CAPITAL LETTER GAN Ⴃ U+10A3 GEORGIAN CAPITAL LETTER DON Ⴄ U+10A4 GEORGIAN CAPITAL LETTER EN Ⴅ U+10A5 GEORGIAN CAPITAL LETTER VIN Ⴆ U+10A6 GEORGIAN CAPITAL LETTER ZEN Ⴇ U+10A7 GEORGIAN CAPITAL LETTER TAN Ⴈ U+10A8 GEORGIAN CAPITAL LETTER IN Ⴉ U+10A9 GEORGIAN CAPITAL LETTER KAN Ⴊ U+10AA GEORGIAN CAPITAL LETTER LAS Ⴋ U+10AB GEORGIAN CAPITAL LETTER MAN Ⴌ U+10AC GEORGIAN CAPITAL LETTER NAR Ⴍ U+10AD GEORGIAN CAPITAL LETTER ON Ⴎ U+10AE GEORGIAN CAPITAL LETTER PAR Ⴏ U+10AF GEORGIAN CAPITAL LETTER ZHAR Ⴐ U+10B0 GEORGIAN CAPITAL LETTER RAE Ⴑ U+10B1 GEORGIAN CAPITAL LETTER SAN Ⴒ U+10B2 GEORGIAN CAPITAL LETTER TAR Ⴓ U+10B3 GEORGIAN CAPITAL LETTER UN Ⴔ U+10B4 GEORGIAN CAPITAL LETTER PHAR Ⴕ U+10B5 GEORGIAN CAPITAL LETTER KHAR Ⴖ U+10B6 GEORGIAN CAPITAL LETTER GHAN Ⴗ U+10B7 GEORGIAN CAPITAL LETTER QAR Ⴘ U+10B8 GEORGIAN CAPITAL LETTER SHIN Ⴙ U+10B9 GEORGIAN CAPITAL LETTER CHIN Ⴚ U+10BA GEORGIAN CAPITAL LETTER CAN Ⴛ U+10BB GEORGIAN CAPITAL LETTER JIL Ⴜ U+10BC GEORGIAN CAPITAL LETTER CIL Ⴝ U+10BD GEORGIAN CAPITAL LETTER CHAR Ⴞ U+10BE GEORGIAN CAPITAL LETTER XAN Ⴟ U+10BF GEORGIAN CAPITAL LETTER JHAN Ⴠ U+10C0 GEORGIAN CAPITAL LETTER HAE Ⴡ U+10C1 GEORGIAN CAPITAL LETTER HE Ⴢ U+10C2 GEORGIAN CAPITAL LETTER HIE Ⴣ U+10C3 GEORGIAN CAPITAL LETTER WE Ⴤ U+10C4 GEORGIAN CAPITAL LETTER HAR Ⴥ U+10C5 GEORGIAN CAPITAL LETTER HOE Ⴧ U+10C7 GEORGIAN CAPITAL LETTER YN Ⴭ U+10CD GEORGIAN CAPITAL LETTER AEN Ꭰ U+13A0 CHEROKEE LETTER A Ꭱ U+13A1 CHEROKEE LETTER E Ꭲ U+13A2 CHEROKEE LETTER I Ꭳ U+13A3 CHEROKEE LETTER O Ꭴ U+13A4 CHEROKEE LETTER U Ꭵ U+13A5 CHEROKEE LETTER V Ꭶ U+13A6 CHEROKEE LETTER GA Ꭷ U+13A7 CHEROKEE LETTER KA Ꭸ U+13A8 CHEROKEE LETTER GE Ꭹ U+13A9 CHEROKEE LETTER GI Ꭺ U+13AA CHEROKEE LETTER GO Ꭻ U+13AB CHEROKEE LETTER GU Ꭼ U+13AC CHEROKEE LETTER GV Ꭽ U+13AD CHEROKEE LETTER HA Ꭾ U+13AE CHEROKEE LETTER HE Ꭿ U+13AF CHEROKEE LETTER HI Ꮀ U+13B0 CHEROKEE LETTER HO Ꮁ U+13B1 CHEROKEE LETTER HU Ꮂ U+13B2 CHEROKEE LETTER HV Ꮃ U+13B3 CHEROKEE LETTER LA Ꮄ U+13B4 CHEROKEE LETTER LE Ꮅ U+13B5 CHEROKEE LETTER LI Ꮆ U+13B6 CHEROKEE LETTER LO Ꮇ U+13B7 CHEROKEE LETTER LU Ꮈ U+13B8 CHEROKEE LETTER LV Ꮉ U+13B9 CHEROKEE LETTER MA Ꮊ U+13BA CHEROKEE LETTER ME Ꮋ U+13BB CHEROKEE LETTER MI Ꮌ U+13BC CHEROKEE LETTER MO Ꮍ U+13BD CHEROKEE LETTER MU Ꮎ U+13BE CHEROKEE LETTER NA Ꮏ U+13BF CHEROKEE LETTER HNA Ꮐ U+13C0 CHEROKEE LETTER NAH Ꮑ U+13C1 CHEROKEE LETTER NE Ꮒ U+13C2 CHEROKEE LETTER NI Ꮓ U+13C3 CHEROKEE LETTER NO Ꮔ U+13C4 CHEROKEE LETTER NU Ꮕ U+13C5 CHEROKEE LETTER NV Ꮖ U+13C6 CHEROKEE LETTER QUA Ꮗ U+13C7 CHEROKEE LETTER QUE Ꮘ U+13C8 CHEROKEE LETTER QUI Ꮙ U+13C9 CHEROKEE LETTER QUO Ꮚ U+13CA CHEROKEE LETTER QUU Ꮛ U+13CB CHEROKEE LETTER QUV Ꮜ U+13CC CHEROKEE LETTER SA Ꮝ U+13CD CHEROKEE LETTER S Ꮞ U+13CE CHEROKEE LETTER SE Ꮟ U+13CF CHEROKEE LETTER SI Ꮠ U+13D0 CHEROKEE LETTER SO Ꮡ U+13D1 CHEROKEE LETTER SU Ꮢ U+13D2 CHEROKEE LETTER SV Ꮣ U+13D3 CHEROKEE LETTER DA Ꮤ U+13D4 CHEROKEE LETTER TA Ꮥ U+13D5 CHEROKEE LETTER DE Ꮦ U+13D6 CHEROKEE LETTER TE Ꮧ U+13D7 CHEROKEE LETTER DI Ꮨ U+13D8 CHEROKEE LETTER TI Ꮩ U+13D9 CHEROKEE LETTER DO Ꮪ U+13DA CHEROKEE LETTER DU Ꮫ U+13DB CHEROKEE LETTER DV Ꮬ U+13DC CHEROKEE LETTER DLA Ꮭ U+13DD CHEROKEE LETTER TLA Ꮮ U+13DE CHEROKEE LETTER TLE Ꮯ U+13DF CHEROKEE LETTER TLI Ꮰ U+13E0 CHEROKEE LETTER TLO Ꮱ U+13E1 CHEROKEE LETTER TLU Ꮲ U+13E2 CHEROKEE LETTER TLV Ꮳ U+13E3 CHEROKEE LETTER TSA Ꮴ U+13E4 CHEROKEE LETTER TSE Ꮵ U+13E5 CHEROKEE LETTER TSI Ꮶ U+13E6 CHEROKEE LETTER TSO Ꮷ U+13E7 CHEROKEE LETTER TSU Ꮸ U+13E8 CHEROKEE LETTER TSV Ꮹ U+13E9 CHEROKEE LETTER WA Ꮺ U+13EA CHEROKEE LETTER WE Ꮻ U+13EB CHEROKEE LETTER WI Ꮼ U+13EC CHEROKEE LETTER WO Ꮽ U+13ED CHEROKEE LETTER WU Ꮾ U+13EE CHEROKEE LETTER WV Ꮿ U+13EF CHEROKEE LETTER YA Ᏸ U+13F0 CHEROKEE LETTER YE Ᏹ U+13F1 CHEROKEE LETTER YI Ᏺ U+13F2 CHEROKEE LETTER YO Ᏻ U+13F3 CHEROKEE LETTER YU Ᏼ U+13F4 CHEROKEE LETTER YV Ᏽ U+13F5 CHEROKEE LETTER MV Ა U+1C90 GEORGIAN MTAVRULI CAPITAL LETTER AN Ბ U+1C91 GEORGIAN MTAVRULI CAPITAL LETTER BAN Გ U+1C92 GEORGIAN MTAVRULI CAPITAL LETTER GAN Დ U+1C93 GEORGIAN MTAVRULI CAPITAL LETTER DON Ე U+1C94 GEORGIAN MTAVRULI CAPITAL LETTER EN Ვ U+1C95 GEORGIAN MTAVRULI CAPITAL LETTER VIN Ზ U+1C96 GEORGIAN MTAVRULI CAPITAL LETTER ZEN Თ U+1C97 GEORGIAN MTAVRULI CAPITAL LETTER TAN Ი U+1C98 GEORGIAN MTAVRULI CAPITAL LETTER IN Კ U+1C99 GEORGIAN MTAVRULI CAPITAL LETTER KAN Ლ U+1C9A GEORGIAN MTAVRULI CAPITAL LETTER LAS Მ U+1C9B GEORGIAN MTAVRULI CAPITAL LETTER MAN Ნ U+1C9C GEORGIAN MTAVRULI CAPITAL LETTER NAR Ო U+1C9D GEORGIAN MTAVRULI CAPITAL LETTER ON Პ U+1C9E GEORGIAN MTAVRULI CAPITAL LETTER PAR Ჟ U+1C9F GEORGIAN MTAVRULI CAPITAL LETTER ZHAR Რ U+1CA0 GEORGIAN MTAVRULI CAPITAL LETTER RAE Ს U+1CA1 GEORGIAN MTAVRULI CAPITAL LETTER SAN Ტ U+1CA2 GEORGIAN MTAVRULI CAPITAL LETTER TAR Უ U+1CA3 GEORGIAN MTAVRULI CAPITAL LETTER UN Ფ U+1CA4 GEORGIAN MTAVRULI CAPITAL LETTER PHAR Ქ U+1CA5 GEORGIAN MTAVRULI CAPITAL LETTER KHAR Ღ U+1CA6 GEORGIAN MTAVRULI CAPITAL LETTER GHAN Ყ U+1CA7 GEORGIAN MTAVRULI CAPITAL LETTER QAR Შ U+1CA8 GEORGIAN MTAVRULI CAPITAL LETTER SHIN Ჩ U+1CA9 GEORGIAN MTAVRULI CAPITAL LETTER CHIN Ც U+1CAA GEORGIAN MTAVRULI CAPITAL LETTER CAN Ძ U+1CAB GEORGIAN MTAVRULI CAPITAL LETTER JIL Წ U+1CAC GEORGIAN MTAVRULI CAPITAL LETTER CIL Ჭ U+1CAD GEORGIAN MTAVRULI CAPITAL LETTER CHAR Ხ U+1CAE GEORGIAN MTAVRULI CAPITAL LETTER XAN Ჯ U+1CAF GEORGIAN MTAVRULI CAPITAL LETTER JHAN Ჰ U+1CB0 GEORGIAN MTAVRULI CAPITAL LETTER HAE Ჱ U+1CB1 GEORGIAN MTAVRULI CAPITAL LETTER HE Ჲ U+1CB2 GEORGIAN MTAVRULI CAPITAL LETTER HIE Ჳ U+1CB3 GEORGIAN MTAVRULI CAPITAL LETTER WE Ჴ U+1CB4 GEORGIAN MTAVRULI CAPITAL LETTER HAR Ჵ U+1CB5 GEORGIAN MTAVRULI CAPITAL LETTER HOE Ჶ U+1CB6 GEORGIAN MTAVRULI CAPITAL LETTER FI Ჷ U+1CB7 GEORGIAN MTAVRULI CAPITAL LETTER YN Ჸ U+1CB8 GEORGIAN MTAVRULI CAPITAL LETTER ELIFI Ჹ U+1CB9 GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN Ჺ U+1CBA GEORGIAN MTAVRULI CAPITAL LETTER AIN Ჽ U+1CBD GEORGIAN MTAVRULI CAPITAL LETTER AEN Ჾ U+1CBE GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN Ჿ U+1CBF GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN Ḁ U+1E00 LATIN CAPITAL LETTER A WITH RING BELOW Ḃ U+1E02 LATIN CAPITAL LETTER B WITH DOT ABOVE Ḅ U+1E04 LATIN CAPITAL LETTER B WITH DOT BELOW Ḇ U+1E06 LATIN CAPITAL LETTER B WITH LINE BELOW Ḉ U+1E08 LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE Ḋ U+1E0A LATIN CAPITAL LETTER D WITH DOT ABOVE Ḍ U+1E0C LATIN CAPITAL LETTER D WITH DOT BELOW Ḏ U+1E0E LATIN CAPITAL LETTER D WITH LINE BELOW Ḑ U+1E10 LATIN CAPITAL LETTER D WITH CEDILLA Ḓ U+1E12 LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW Ḕ U+1E14 LATIN CAPITAL LETTER E WITH MACRON AND GRAVE Ḗ U+1E16 LATIN CAPITAL LETTER E WITH MACRON AND ACUTE Ḙ U+1E18 LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW Ḛ U+1E1A LATIN CAPITAL LETTER E WITH TILDE BELOW Ḝ U+1E1C LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE Ḟ U+1E1E LATIN CAPITAL LETTER F WITH DOT ABOVE Ḡ U+1E20 LATIN CAPITAL LETTER G WITH MACRON Ḣ U+1E22 LATIN CAPITAL LETTER H WITH DOT ABOVE Ḥ U+1E24 LATIN CAPITAL LETTER H WITH DOT BELOW Ḧ U+1E26 LATIN CAPITAL LETTER H WITH DIAERESIS Ḩ U+1E28 LATIN CAPITAL LETTER H WITH CEDILLA Ḫ U+1E2A LATIN CAPITAL LETTER H WITH BREVE BELOW Ḭ U+1E2C LATIN CAPITAL LETTER I WITH TILDE BELOW Ḯ U+1E2E LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE Ḱ U+1E30 LATIN CAPITAL LETTER K WITH ACUTE Ḳ U+1E32 LATIN CAPITAL LETTER K WITH DOT BELOW Ḵ U+1E34 LATIN CAPITAL LETTER K WITH LINE BELOW Ḷ U+1E36 LATIN CAPITAL LETTER L WITH DOT BELOW Ḹ U+1E38 LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON Ḻ U+1E3A LATIN CAPITAL LETTER L WITH LINE BELOW Ḽ U+1E3C LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW Ḿ U+1E3E LATIN CAPITAL LETTER M WITH ACUTE Ṁ U+1E40 LATIN CAPITAL LETTER M WITH DOT ABOVE Ṃ U+1E42 LATIN CAPITAL LETTER M WITH DOT BELOW Ṅ U+1E44 LATIN CAPITAL LETTER N WITH DOT ABOVE Ṇ U+1E46 LATIN CAPITAL LETTER N WITH DOT BELOW Ṉ U+1E48 LATIN CAPITAL LETTER N WITH LINE BELOW Ṋ U+1E4A LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW Ṍ U+1E4C LATIN CAPITAL LETTER O WITH TILDE AND ACUTE Ṏ U+1E4E LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS Ṑ U+1E50 LATIN CAPITAL LETTER O WITH MACRON AND GRAVE Ṓ U+1E52 LATIN CAPITAL LETTER O WITH MACRON AND ACUTE Ṕ U+1E54 LATIN CAPITAL LETTER P WITH ACUTE Ṗ U+1E56 LATIN CAPITAL LETTER P WITH DOT ABOVE Ṙ U+1E58 LATIN CAPITAL LETTER R WITH DOT ABOVE Ṛ U+1E5A LATIN CAPITAL LETTER R WITH DOT BELOW Ṝ U+1E5C LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON Ṟ U+1E5E LATIN CAPITAL LETTER R WITH LINE BELOW Ṡ U+1E60 LATIN CAPITAL LETTER S WITH DOT ABOVE Ṣ U+1E62 LATIN CAPITAL LETTER S WITH DOT BELOW Ṥ U+1E64 LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE Ṧ U+1E66 LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE Ṩ U+1E68 LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE Ṫ U+1E6A LATIN CAPITAL LETTER T WITH DOT ABOVE Ṭ U+1E6C LATIN CAPITAL LETTER T WITH DOT BELOW Ṯ U+1E6E LATIN CAPITAL LETTER T WITH LINE BELOW Ṱ U+1E70 LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW Ṳ U+1E72 LATIN CAPITAL LETTER U WITH DIAERESIS BELOW Ṵ U+1E74 LATIN CAPITAL LETTER U WITH TILDE BELOW Ṷ U+1E76 LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW Ṹ U+1E78 LATIN CAPITAL LETTER U WITH TILDE AND ACUTE Ṻ U+1E7A LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS Ṽ U+1E7C LATIN CAPITAL LETTER V WITH TILDE Ṿ U+1E7E LATIN CAPITAL LETTER V WITH DOT BELOW Ẁ U+1E80 LATIN CAPITAL LETTER W WITH GRAVE Ẃ U+1E82 LATIN CAPITAL LETTER W WITH ACUTE Ẅ U+1E84 LATIN CAPITAL LETTER W WITH DIAERESIS Ẇ U+1E86 LATIN CAPITAL LETTER W WITH DOT ABOVE Ẉ U+1E88 LATIN CAPITAL LETTER W WITH DOT BELOW Ẋ U+1E8A LATIN CAPITAL LETTER X WITH DOT ABOVE Ẍ U+1E8C LATIN CAPITAL LETTER X WITH DIAERESIS Ẏ U+1E8E LATIN CAPITAL LETTER Y WITH DOT ABOVE Ẑ U+1E90 LATIN CAPITAL LETTER Z WITH CIRCUMFLEX Ẓ U+1E92 LATIN CAPITAL LETTER Z WITH DOT BELOW Ẕ U+1E94 LATIN CAPITAL LETTER Z WITH LINE BELOW ẞ U+1E9E LATIN CAPITAL LETTER SHARP S Ạ U+1EA0 LATIN CAPITAL LETTER A WITH DOT BELOW Ả U+1EA2 LATIN CAPITAL LETTER A WITH HOOK ABOVE Ấ U+1EA4 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE Ầ U+1EA6 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE Ẩ U+1EA8 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE Ẫ U+1EAA LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE Ậ U+1EAC LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW Ắ U+1EAE LATIN CAPITAL LETTER A WITH BREVE AND ACUTE Ằ U+1EB0 LATIN CAPITAL LETTER A WITH BREVE AND GRAVE Ẳ U+1EB2 LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE Ẵ U+1EB4 LATIN CAPITAL LETTER A WITH BREVE AND TILDE Ặ U+1EB6 LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW Ẹ U+1EB8 LATIN CAPITAL LETTER E WITH DOT BELOW Ẻ U+1EBA LATIN CAPITAL LETTER E WITH HOOK ABOVE Ẽ U+1EBC LATIN CAPITAL LETTER E WITH TILDE Ế U+1EBE LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE Ề U+1EC0 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE Ể U+1EC2 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE Ễ U+1EC4 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE Ệ U+1EC6 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW Ỉ U+1EC8 LATIN CAPITAL LETTER I WITH HOOK ABOVE Ị U+1ECA LATIN CAPITAL LETTER I WITH DOT BELOW Ọ U+1ECC LATIN CAPITAL LETTER O WITH DOT BELOW Ỏ U+1ECE LATIN CAPITAL LETTER O WITH HOOK ABOVE Ố U+1ED0 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE Ồ U+1ED2 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE Ổ U+1ED4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE Ỗ U+1ED6 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE Ộ U+1ED8 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW Ớ U+1EDA LATIN CAPITAL LETTER O WITH HORN AND ACUTE Ờ U+1EDC LATIN CAPITAL LETTER O WITH HORN AND GRAVE Ở U+1EDE LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE Ỡ U+1EE0 LATIN CAPITAL LETTER O WITH HORN AND TILDE Ợ U+1EE2 LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW Ụ U+1EE4 LATIN CAPITAL LETTER U WITH DOT BELOW Ủ U+1EE6 LATIN CAPITAL LETTER U WITH HOOK ABOVE Ứ U+1EE8 LATIN CAPITAL LETTER U WITH HORN AND ACUTE Ừ U+1EEA LATIN CAPITAL LETTER U WITH HORN AND GRAVE Ử U+1EEC LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE Ữ U+1EEE LATIN CAPITAL LETTER U WITH HORN AND TILDE Ự U+1EF0 LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW Ỳ U+1EF2 LATIN CAPITAL LETTER Y WITH GRAVE Ỵ U+1EF4 LATIN CAPITAL LETTER Y WITH DOT BELOW Ỷ U+1EF6 LATIN CAPITAL LETTER Y WITH HOOK ABOVE Ỹ U+1EF8 LATIN CAPITAL LETTER Y WITH TILDE Ỻ U+1EFA LATIN CAPITAL LETTER MIDDLE-WELSH LL Ỽ U+1EFC LATIN CAPITAL LETTER MIDDLE-WELSH V Ỿ U+1EFE LATIN CAPITAL LETTER Y WITH LOOP Ἀ U+1F08 GREEK CAPITAL LETTER ALPHA WITH PSILI Ἁ U+1F09 GREEK CAPITAL LETTER ALPHA WITH DASIA Ἂ U+1F0A GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA Ἃ U+1F0B GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA Ἄ U+1F0C GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA Ἅ U+1F0D GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA Ἆ U+1F0E GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI Ἇ U+1F0F GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI Ἐ U+1F18 GREEK CAPITAL LETTER EPSILON WITH PSILI Ἑ U+1F19 GREEK CAPITAL LETTER EPSILON WITH DASIA Ἒ U+1F1A GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA Ἓ U+1F1B GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA Ἔ U+1F1C GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA Ἕ U+1F1D GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA Ἠ U+1F28 GREEK CAPITAL LETTER ETA WITH PSILI Ἡ U+1F29 GREEK CAPITAL LETTER ETA WITH DASIA Ἢ U+1F2A GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA Ἣ U+1F2B GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA Ἤ U+1F2C GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA Ἥ U+1F2D GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA Ἦ U+1F2E GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI Ἧ U+1F2F GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI Ἰ U+1F38 GREEK CAPITAL LETTER IOTA WITH PSILI Ἱ U+1F39 GREEK CAPITAL LETTER IOTA WITH DASIA Ἲ U+1F3A GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA Ἳ U+1F3B GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA Ἴ U+1F3C GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA Ἵ U+1F3D GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA Ἶ U+1F3E GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI Ἷ U+1F3F GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI Ὀ U+1F48 GREEK CAPITAL LETTER OMICRON WITH PSILI Ὁ U+1F49 GREEK CAPITAL LETTER OMICRON WITH DASIA Ὂ U+1F4A GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA Ὃ U+1F4B GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA Ὄ U+1F4C GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA Ὅ U+1F4D GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA Ὑ U+1F59 GREEK CAPITAL LETTER UPSILON WITH DASIA Ὓ U+1F5B GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA Ὕ U+1F5D GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA Ὗ U+1F5F GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI Ὠ U+1F68 GREEK CAPITAL LETTER OMEGA WITH PSILI Ὡ U+1F69 GREEK CAPITAL LETTER OMEGA WITH DASIA Ὢ U+1F6A GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA Ὣ U+1F6B GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA Ὤ U+1F6C GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA Ὥ U+1F6D GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA Ὦ U+1F6E GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI Ὧ U+1F6F GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI ᾈ U+1F88 GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI ᾉ U+1F89 GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI ᾊ U+1F8A GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI ᾋ U+1F8B GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI ᾌ U+1F8C GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI ᾍ U+1F8D GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI ᾎ U+1F8E GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI ᾏ U+1F8F GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI ᾘ U+1F98 GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI ᾙ U+1F99 GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI ᾚ U+1F9A GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI ᾛ U+1F9B GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI ᾜ U+1F9C GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI ᾝ U+1F9D GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI ᾞ U+1F9E GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI ᾟ U+1F9F GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI ᾨ U+1FA8 GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI ᾩ U+1FA9 GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI ᾪ U+1FAA GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI ᾫ U+1FAB GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI ᾬ U+1FAC GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI ᾭ U+1FAD GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI ᾮ U+1FAE GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI ᾯ U+1FAF GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI Ᾰ U+1FB8 GREEK CAPITAL LETTER ALPHA WITH VRACHY Ᾱ U+1FB9 GREEK CAPITAL LETTER ALPHA WITH MACRON Ὰ U+1FBA GREEK CAPITAL LETTER ALPHA WITH VARIA Ά U+1FBB GREEK CAPITAL LETTER ALPHA WITH OXIA ᾼ U+1FBC GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI Ὲ U+1FC8 GREEK CAPITAL LETTER EPSILON WITH VARIA Έ U+1FC9 GREEK CAPITAL LETTER EPSILON WITH OXIA Ὴ U+1FCA GREEK CAPITAL LETTER ETA WITH VARIA Ή U+1FCB GREEK CAPITAL LETTER ETA WITH OXIA ῌ U+1FCC GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI Ῐ U+1FD8 GREEK CAPITAL LETTER IOTA WITH VRACHY Ῑ U+1FD9 GREEK CAPITAL LETTER IOTA WITH MACRON Ὶ U+1FDA GREEK CAPITAL LETTER IOTA WITH VARIA Ί U+1FDB GREEK CAPITAL LETTER IOTA WITH OXIA Ῠ U+1FE8 GREEK CAPITAL LETTER UPSILON WITH VRACHY Ῡ U+1FE9 GREEK CAPITAL LETTER UPSILON WITH MACRON Ὺ U+1FEA GREEK CAPITAL LETTER UPSILON WITH VARIA Ύ U+1FEB GREEK CAPITAL LETTER UPSILON WITH OXIA Ῥ U+1FEC GREEK CAPITAL LETTER RHO WITH DASIA Ὸ U+1FF8 GREEK CAPITAL LETTER OMICRON WITH VARIA Ό U+1FF9 GREEK CAPITAL LETTER OMICRON WITH OXIA Ὼ U+1FFA GREEK CAPITAL LETTER OMEGA WITH VARIA Ώ U+1FFB GREEK CAPITAL LETTER OMEGA WITH OXIA ῼ U+1FFC GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI ℂ U+2102 DOUBLE-STRUCK CAPITAL C ℇ U+2107 EULER CONSTANT ℋ U+210B SCRIPT CAPITAL H ℌ U+210C BLACK-LETTER CAPITAL H ℍ U+210D DOUBLE-STRUCK CAPITAL H ℐ U+2110 SCRIPT CAPITAL I ℑ U+2111 BLACK-LETTER CAPITAL I ℒ U+2112 SCRIPT CAPITAL L ℕ U+2115 DOUBLE-STRUCK CAPITAL N ℙ U+2119 DOUBLE-STRUCK CAPITAL P ℚ U+211A DOUBLE-STRUCK CAPITAL Q ℛ U+211B SCRIPT CAPITAL R ℜ U+211C BLACK-LETTER CAPITAL R ℝ U+211D DOUBLE-STRUCK CAPITAL R ℤ U+2124 DOUBLE-STRUCK CAPITAL Z Ω U+2126 OHM SIGN ℨ U+2128 BLACK-LETTER CAPITAL Z K U+212A KELVIN SIGN Å U+212B ANGSTROM SIGN ℬ U+212C SCRIPT CAPITAL B ℭ U+212D BLACK-LETTER CAPITAL C ℰ U+2130 SCRIPT CAPITAL E ℱ U+2131 SCRIPT CAPITAL F Ⅎ U+2132 TURNED CAPITAL F ℳ U+2133 SCRIPT CAPITAL M ℾ U+213E DOUBLE-STRUCK CAPITAL GAMMA ℿ U+213F DOUBLE-STRUCK CAPITAL PI ⅅ U+2145 DOUBLE-STRUCK ITALIC CAPITAL D Ⅰ U+2160 ROMAN NUMERAL ONE Ⅱ U+2161 ROMAN NUMERAL TWO Ⅲ U+2162 ROMAN NUMERAL THREE Ⅳ U+2163 ROMAN NUMERAL FOUR Ⅴ U+2164 ROMAN NUMERAL FIVE Ⅵ U+2165 ROMAN NUMERAL SIX Ⅶ U+2166 ROMAN NUMERAL SEVEN Ⅷ U+2167 ROMAN NUMERAL EIGHT Ⅸ U+2168 ROMAN NUMERAL NINE Ⅹ U+2169 ROMAN NUMERAL TEN Ⅺ U+216A ROMAN NUMERAL ELEVEN Ⅻ U+216B ROMAN NUMERAL TWELVE Ⅼ U+216C ROMAN NUMERAL FIFTY Ⅽ U+216D ROMAN NUMERAL ONE HUNDRED Ⅾ U+216E ROMAN NUMERAL FIVE HUNDRED Ⅿ U+216F ROMAN NUMERAL ONE THOUSAND Ↄ U+2183 ROMAN NUMERAL REVERSED ONE HUNDRED Ⓐ U+24B6 CIRCLED LATIN CAPITAL LETTER A Ⓑ U+24B7 CIRCLED LATIN CAPITAL LETTER B Ⓒ U+24B8 CIRCLED LATIN CAPITAL LETTER C Ⓓ U+24B9 CIRCLED LATIN CAPITAL LETTER D Ⓔ U+24BA CIRCLED LATIN CAPITAL LETTER E Ⓕ U+24BB CIRCLED LATIN CAPITAL LETTER F Ⓖ U+24BC CIRCLED LATIN CAPITAL LETTER G Ⓗ U+24BD CIRCLED LATIN CAPITAL LETTER H Ⓘ U+24BE CIRCLED LATIN CAPITAL LETTER I Ⓙ U+24BF CIRCLED LATIN CAPITAL LETTER J Ⓚ U+24C0 CIRCLED LATIN CAPITAL LETTER K Ⓛ U+24C1 CIRCLED LATIN CAPITAL LETTER L Ⓜ U+24C2 CIRCLED LATIN CAPITAL LETTER M Ⓝ U+24C3 CIRCLED LATIN CAPITAL LETTER N Ⓞ U+24C4 CIRCLED LATIN CAPITAL LETTER O Ⓟ U+24C5 CIRCLED LATIN CAPITAL LETTER P Ⓠ U+24C6 CIRCLED LATIN CAPITAL LETTER Q Ⓡ U+24C7 CIRCLED LATIN CAPITAL LETTER R Ⓢ U+24C8 CIRCLED LATIN CAPITAL LETTER S Ⓣ U+24C9 CIRCLED LATIN CAPITAL LETTER T Ⓤ U+24CA CIRCLED LATIN CAPITAL LETTER U Ⓥ U+24CB CIRCLED LATIN CAPITAL LETTER V Ⓦ U+24CC CIRCLED LATIN CAPITAL LETTER W Ⓧ U+24CD CIRCLED LATIN CAPITAL LETTER X Ⓨ U+24CE CIRCLED LATIN CAPITAL LETTER Y Ⓩ U+24CF CIRCLED LATIN CAPITAL LETTER Z Ⰰ U+2C00 GLAGOLITIC CAPITAL LETTER AZU Ⰱ U+2C01 GLAGOLITIC CAPITAL LETTER BUKY Ⰲ U+2C02 GLAGOLITIC CAPITAL LETTER VEDE Ⰳ U+2C03 GLAGOLITIC CAPITAL LETTER GLAGOLI Ⰴ U+2C04 GLAGOLITIC CAPITAL LETTER DOBRO Ⰵ U+2C05 GLAGOLITIC CAPITAL LETTER YESTU Ⰶ U+2C06 GLAGOLITIC CAPITAL LETTER ZHIVETE Ⰷ U+2C07 GLAGOLITIC CAPITAL LETTER DZELO Ⰸ U+2C08 GLAGOLITIC CAPITAL LETTER ZEMLJA Ⰹ U+2C09 GLAGOLITIC CAPITAL LETTER IZHE Ⰺ U+2C0A GLAGOLITIC CAPITAL LETTER INITIAL IZHE Ⰻ U+2C0B GLAGOLITIC CAPITAL LETTER I Ⰼ U+2C0C GLAGOLITIC CAPITAL LETTER DJERVI Ⰽ U+2C0D GLAGOLITIC CAPITAL LETTER KAKO Ⰾ U+2C0E GLAGOLITIC CAPITAL LETTER LJUDIJE Ⰿ U+2C0F GLAGOLITIC CAPITAL LETTER MYSLITE Ⱀ U+2C10 GLAGOLITIC CAPITAL LETTER NASHI Ⱁ U+2C11 GLAGOLITIC CAPITAL LETTER ONU Ⱂ U+2C12 GLAGOLITIC CAPITAL LETTER POKOJI Ⱃ U+2C13 GLAGOLITIC CAPITAL LETTER RITSI Ⱄ U+2C14 GLAGOLITIC CAPITAL LETTER SLOVO Ⱅ U+2C15 GLAGOLITIC CAPITAL LETTER TVRIDO Ⱆ U+2C16 GLAGOLITIC CAPITAL LETTER UKU Ⱇ U+2C17 GLAGOLITIC CAPITAL LETTER FRITU Ⱈ U+2C18 GLAGOLITIC CAPITAL LETTER HERU Ⱉ U+2C19 GLAGOLITIC CAPITAL LETTER OTU Ⱊ U+2C1A GLAGOLITIC CAPITAL LETTER PE Ⱋ U+2C1B GLAGOLITIC CAPITAL LETTER SHTA Ⱌ U+2C1C GLAGOLITIC CAPITAL LETTER TSI Ⱍ U+2C1D GLAGOLITIC CAPITAL LETTER CHRIVI Ⱎ U+2C1E GLAGOLITIC CAPITAL LETTER SHA Ⱏ U+2C1F GLAGOLITIC CAPITAL LETTER YERU Ⱐ U+2C20 GLAGOLITIC CAPITAL LETTER YERI Ⱑ U+2C21 GLAGOLITIC CAPITAL LETTER YATI Ⱒ U+2C22 GLAGOLITIC CAPITAL LETTER SPIDERY HA Ⱓ U+2C23 GLAGOLITIC CAPITAL LETTER YU Ⱔ U+2C24 GLAGOLITIC CAPITAL LETTER SMALL YUS Ⱕ U+2C25 GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL Ⱖ U+2C26 GLAGOLITIC CAPITAL LETTER YO Ⱗ U+2C27 GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS Ⱘ U+2C28 GLAGOLITIC CAPITAL LETTER BIG YUS Ⱙ U+2C29 GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS Ⱚ U+2C2A GLAGOLITIC CAPITAL LETTER FITA Ⱛ U+2C2B GLAGOLITIC CAPITAL LETTER IZHITSA Ⱜ U+2C2C GLAGOLITIC CAPITAL LETTER SHTAPIC Ⱝ U+2C2D GLAGOLITIC CAPITAL LETTER TROKUTASTI A Ⱞ U+2C2E GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE Ⱡ U+2C60 LATIN CAPITAL LETTER L WITH DOUBLE BAR Ɫ U+2C62 LATIN CAPITAL LETTER L WITH MIDDLE TILDE Ᵽ U+2C63 LATIN CAPITAL LETTER P WITH STROKE Ɽ U+2C64 LATIN CAPITAL LETTER R WITH TAIL Ⱨ U+2C67 LATIN CAPITAL LETTER H WITH DESCENDER Ⱪ U+2C69 LATIN CAPITAL LETTER K WITH DESCENDER Ⱬ U+2C6B LATIN CAPITAL LETTER Z WITH DESCENDER Ɑ U+2C6D LATIN CAPITAL LETTER ALPHA Ɱ U+2C6E LATIN CAPITAL LETTER M WITH HOOK Ɐ U+2C6F LATIN CAPITAL LETTER TURNED A Ɒ U+2C70 LATIN CAPITAL LETTER TURNED ALPHA Ⱳ U+2C72 LATIN CAPITAL LETTER W WITH HOOK Ⱶ U+2C75 LATIN CAPITAL LETTER HALF H Ȿ U+2C7E LATIN CAPITAL LETTER S WITH SWASH TAIL Ɀ U+2C7F LATIN CAPITAL LETTER Z WITH SWASH TAIL Ⲁ U+2C80 COPTIC CAPITAL LETTER ALFA Ⲃ U+2C82 COPTIC CAPITAL LETTER VIDA Ⲅ U+2C84 COPTIC CAPITAL LETTER GAMMA Ⲇ U+2C86 COPTIC CAPITAL LETTER DALDA Ⲉ U+2C88 COPTIC CAPITAL LETTER EIE Ⲋ U+2C8A COPTIC CAPITAL LETTER SOU Ⲍ U+2C8C COPTIC CAPITAL LETTER ZATA Ⲏ U+2C8E COPTIC CAPITAL LETTER HATE Ⲑ U+2C90 COPTIC CAPITAL LETTER THETHE Ⲓ U+2C92 COPTIC CAPITAL LETTER IAUDA Ⲕ U+2C94 COPTIC CAPITAL LETTER KAPA Ⲗ U+2C96 COPTIC CAPITAL LETTER LAULA Ⲙ U+2C98 COPTIC CAPITAL LETTER MI Ⲛ U+2C9A COPTIC CAPITAL LETTER NI Ⲝ U+2C9C COPTIC CAPITAL LETTER KSI Ⲟ U+2C9E COPTIC CAPITAL LETTER O Ⲡ U+2CA0 COPTIC CAPITAL LETTER PI Ⲣ U+2CA2 COPTIC CAPITAL LETTER RO Ⲥ U+2CA4 COPTIC CAPITAL LETTER SIMA Ⲧ U+2CA6 COPTIC CAPITAL LETTER TAU Ⲩ U+2CA8 COPTIC CAPITAL LETTER UA Ⲫ U+2CAA COPTIC CAPITAL LETTER FI Ⲭ U+2CAC COPTIC CAPITAL LETTER KHI Ⲯ U+2CAE COPTIC CAPITAL LETTER PSI Ⲱ U+2CB0 COPTIC CAPITAL LETTER OOU Ⲳ U+2CB2 COPTIC CAPITAL LETTER DIALECT-P ALEF Ⲵ U+2CB4 COPTIC CAPITAL LETTER OLD COPTIC AIN Ⲷ U+2CB6 COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE Ⲹ U+2CB8 COPTIC CAPITAL LETTER DIALECT-P KAPA Ⲻ U+2CBA COPTIC CAPITAL LETTER DIALECT-P NI Ⲽ U+2CBC COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI Ⲿ U+2CBE COPTIC CAPITAL LETTER OLD COPTIC OOU Ⳁ U+2CC0 COPTIC CAPITAL LETTER SAMPI Ⳃ U+2CC2 COPTIC CAPITAL LETTER CROSSED SHEI Ⳅ U+2CC4 COPTIC CAPITAL LETTER OLD COPTIC SHEI Ⳇ U+2CC6 COPTIC CAPITAL LETTER OLD COPTIC ESH Ⳉ U+2CC8 COPTIC CAPITAL LETTER AKHMIMIC KHEI Ⳋ U+2CCA COPTIC CAPITAL LETTER DIALECT-P HORI Ⳍ U+2CCC COPTIC CAPITAL LETTER OLD COPTIC HORI Ⳏ U+2CCE COPTIC CAPITAL LETTER OLD COPTIC HA Ⳑ U+2CD0 COPTIC CAPITAL LETTER L-SHAPED HA Ⳓ U+2CD2 COPTIC CAPITAL LETTER OLD COPTIC HEI Ⳕ U+2CD4 COPTIC CAPITAL LETTER OLD COPTIC HAT Ⳗ U+2CD6 COPTIC CAPITAL LETTER OLD COPTIC GANGIA Ⳙ U+2CD8 COPTIC CAPITAL LETTER OLD COPTIC DJA Ⳛ U+2CDA COPTIC CAPITAL LETTER OLD COPTIC SHIMA Ⳝ U+2CDC COPTIC CAPITAL LETTER OLD NUBIAN SHIMA Ⳟ U+2CDE COPTIC CAPITAL LETTER OLD NUBIAN NGI Ⳡ U+2CE0 COPTIC CAPITAL LETTER OLD NUBIAN NYI Ⳣ U+2CE2 COPTIC CAPITAL LETTER OLD NUBIAN WAU Ⳬ U+2CEB COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI Ⳮ U+2CED COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA Ⳳ U+2CF2 COPTIC CAPITAL LETTER BOHAIRIC KHEI Ꙁ U+A640 CYRILLIC CAPITAL LETTER ZEMLYA Ꙃ U+A642 CYRILLIC CAPITAL LETTER DZELO Ꙅ U+A644 CYRILLIC CAPITAL LETTER REVERSED DZE Ꙇ U+A646 CYRILLIC CAPITAL LETTER IOTA Ꙉ U+A648 CYRILLIC CAPITAL LETTER DJERV Ꙋ U+A64A CYRILLIC CAPITAL LETTER MONOGRAPH UK Ꙍ U+A64C CYRILLIC CAPITAL LETTER BROAD OMEGA Ꙏ U+A64E CYRILLIC CAPITAL LETTER NEUTRAL YER Ꙑ U+A650 CYRILLIC CAPITAL LETTER YERU WITH BACK YER Ꙓ U+A652 CYRILLIC CAPITAL LETTER IOTIFIED YAT Ꙕ U+A654 CYRILLIC CAPITAL LETTER REVERSED YU Ꙗ U+A656 CYRILLIC CAPITAL LETTER IOTIFIED A Ꙙ U+A658 CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS Ꙛ U+A65A CYRILLIC CAPITAL LETTER BLENDED YUS Ꙝ U+A65C CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS Ꙟ U+A65E CYRILLIC CAPITAL LETTER YN Ꙡ U+A660 CYRILLIC CAPITAL LETTER REVERSED TSE Ꙣ U+A662 CYRILLIC CAPITAL LETTER SOFT DE Ꙥ U+A664 CYRILLIC CAPITAL LETTER SOFT EL Ꙧ U+A666 CYRILLIC CAPITAL LETTER SOFT EM Ꙩ U+A668 CYRILLIC CAPITAL LETTER MONOCULAR O Ꙫ U+A66A CYRILLIC CAPITAL LETTER BINOCULAR O Ꙭ U+A66C CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O Ꚁ U+A680 CYRILLIC CAPITAL LETTER DWE Ꚃ U+A682 CYRILLIC CAPITAL LETTER DZWE Ꚅ U+A684 CYRILLIC CAPITAL LETTER ZHWE Ꚇ U+A686 CYRILLIC CAPITAL LETTER CCHE Ꚉ U+A688 CYRILLIC CAPITAL LETTER DZZE Ꚋ U+A68A CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK Ꚍ U+A68C CYRILLIC CAPITAL LETTER TWE Ꚏ U+A68E CYRILLIC CAPITAL LETTER TSWE Ꚑ U+A690 CYRILLIC CAPITAL LETTER TSSE Ꚓ U+A692 CYRILLIC CAPITAL LETTER TCHE Ꚕ U+A694 CYRILLIC CAPITAL LETTER HWE Ꚗ U+A696 CYRILLIC CAPITAL LETTER SHWE Ꚙ U+A698 CYRILLIC CAPITAL LETTER DOUBLE O Ꚛ U+A69A CYRILLIC CAPITAL LETTER CROSSED O Ꜣ U+A722 LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF Ꜥ U+A724 LATIN CAPITAL LETTER EGYPTOLOGICAL AIN Ꜧ U+A726 LATIN CAPITAL LETTER HENG Ꜩ U+A728 LATIN CAPITAL LETTER TZ Ꜫ U+A72A LATIN CAPITAL LETTER TRESILLO Ꜭ U+A72C LATIN CAPITAL LETTER CUATRILLO Ꜯ U+A72E LATIN CAPITAL LETTER CUATRILLO WITH COMMA Ꜳ U+A732 LATIN CAPITAL LETTER AA Ꜵ U+A734 LATIN CAPITAL LETTER AO Ꜷ U+A736 LATIN CAPITAL LETTER AU Ꜹ U+A738 LATIN CAPITAL LETTER AV Ꜻ U+A73A LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR Ꜽ U+A73C LATIN CAPITAL LETTER AY Ꜿ U+A73E LATIN CAPITAL LETTER REVERSED C WITH DOT Ꝁ U+A740 LATIN CAPITAL LETTER K WITH STROKE Ꝃ U+A742 LATIN CAPITAL LETTER K WITH DIAGONAL STROKE Ꝅ U+A744 LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE Ꝇ U+A746 LATIN CAPITAL LETTER BROKEN L Ꝉ U+A748 LATIN CAPITAL LETTER L WITH HIGH STROKE Ꝋ U+A74A LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY Ꝍ U+A74C LATIN CAPITAL LETTER O WITH LOOP Ꝏ U+A74E LATIN CAPITAL LETTER OO Ꝑ U+A750 LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER Ꝓ U+A752 LATIN CAPITAL LETTER P WITH FLOURISH Ꝕ U+A754 LATIN CAPITAL LETTER P WITH SQUIRREL TAIL Ꝗ U+A756 LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER Ꝙ U+A758 LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE Ꝛ U+A75A LATIN CAPITAL LETTER R ROTUNDA Ꝝ U+A75C LATIN CAPITAL LETTER RUM ROTUNDA Ꝟ U+A75E LATIN CAPITAL LETTER V WITH DIAGONAL STROKE Ꝡ U+A760 LATIN CAPITAL LETTER VY Ꝣ U+A762 LATIN CAPITAL LETTER VISIGOTHIC Z Ꝥ U+A764 LATIN CAPITAL LETTER THORN WITH STROKE Ꝧ U+A766 LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER Ꝩ U+A768 LATIN CAPITAL LETTER VEND Ꝫ U+A76A LATIN CAPITAL LETTER ET Ꝭ U+A76C LATIN CAPITAL LETTER IS Ꝯ U+A76E LATIN CAPITAL LETTER CON Ꝺ U+A779 LATIN CAPITAL LETTER INSULAR D Ꝼ U+A77B LATIN CAPITAL LETTER INSULAR F Ᵹ U+A77D LATIN CAPITAL LETTER INSULAR G Ꝿ U+A77E LATIN CAPITAL LETTER TURNED INSULAR G Ꞁ U+A780 LATIN CAPITAL LETTER TURNED L Ꞃ U+A782 LATIN CAPITAL LETTER INSULAR R Ꞅ U+A784 LATIN CAPITAL LETTER INSULAR S Ꞇ U+A786 LATIN CAPITAL LETTER INSULAR T Ꞌ U+A78B LATIN CAPITAL LETTER SALTILLO Ɥ U+A78D LATIN CAPITAL LETTER TURNED H Ꞑ U+A790 LATIN CAPITAL LETTER N WITH DESCENDER Ꞓ U+A792 LATIN CAPITAL LETTER C WITH BAR Ꞗ U+A796 LATIN CAPITAL LETTER B WITH FLOURISH Ꞙ U+A798 LATIN CAPITAL LETTER F WITH STROKE Ꞛ U+A79A LATIN CAPITAL LETTER VOLAPUK AE Ꞝ U+A79C LATIN CAPITAL LETTER VOLAPUK OE Ꞟ U+A79E LATIN CAPITAL LETTER VOLAPUK UE Ꞡ U+A7A0 LATIN CAPITAL LETTER G WITH OBLIQUE STROKE Ꞣ U+A7A2 LATIN CAPITAL LETTER K WITH OBLIQUE STROKE Ꞥ U+A7A4 LATIN CAPITAL LETTER N WITH OBLIQUE STROKE Ꞧ U+A7A6 LATIN CAPITAL LETTER R WITH OBLIQUE STROKE Ꞩ U+A7A8 LATIN CAPITAL LETTER S WITH OBLIQUE STROKE Ɦ U+A7AA LATIN CAPITAL LETTER H WITH HOOK Ɜ U+A7AB LATIN CAPITAL LETTER REVERSED OPEN E Ɡ U+A7AC LATIN CAPITAL LETTER SCRIPT G Ɬ U+A7AD LATIN CAPITAL LETTER L WITH BELT Ɪ U+A7AE LATIN CAPITAL LETTER SMALL CAPITAL I Ʞ U+A7B0 LATIN CAPITAL LETTER TURNED K Ʇ U+A7B1 LATIN CAPITAL LETTER TURNED T Ʝ U+A7B2 LATIN CAPITAL LETTER J WITH CROSSED-TAIL Ꭓ U+A7B3 LATIN CAPITAL LETTER CHI Ꞵ U+A7B4 LATIN CAPITAL LETTER BETA Ꞷ U+A7B6 LATIN CAPITAL LETTER OMEGA Ꞹ U+A7B8 LATIN CAPITAL LETTER U WITH STROKE Ꞻ U+A7BA LATIN CAPITAL LETTER GLOTTAL A Ꞽ U+A7BC LATIN CAPITAL LETTER GLOTTAL I Ꞿ U+A7BE LATIN CAPITAL LETTER GLOTTAL U Ꟃ U+A7C2 LATIN CAPITAL LETTER ANGLICANA W Ꞔ U+A7C4 LATIN CAPITAL LETTER C WITH PALATAL HOOK Ʂ U+A7C5 LATIN CAPITAL LETTER S WITH HOOK Ᶎ U+A7C6 LATIN CAPITAL LETTER Z WITH PALATAL HOOK A U+FF21 FULLWIDTH LATIN CAPITAL LETTER A B U+FF22 FULLWIDTH LATIN CAPITAL LETTER B C U+FF23 FULLWIDTH LATIN CAPITAL LETTER C D U+FF24 FULLWIDTH LATIN CAPITAL LETTER D E U+FF25 FULLWIDTH LATIN CAPITAL LETTER E F U+FF26 FULLWIDTH LATIN CAPITAL LETTER F G U+FF27 FULLWIDTH LATIN CAPITAL LETTER G H U+FF28 FULLWIDTH LATIN CAPITAL LETTER H I U+FF29 FULLWIDTH LATIN CAPITAL LETTER I J U+FF2A FULLWIDTH LATIN CAPITAL LETTER J K U+FF2B FULLWIDTH LATIN CAPITAL LETTER K L U+FF2C FULLWIDTH LATIN CAPITAL LETTER L M U+FF2D FULLWIDTH LATIN CAPITAL LETTER M N U+FF2E FULLWIDTH LATIN CAPITAL LETTER N O U+FF2F FULLWIDTH LATIN CAPITAL LETTER O P U+FF30 FULLWIDTH LATIN CAPITAL LETTER P Q U+FF31 FULLWIDTH LATIN CAPITAL LETTER Q R U+FF32 FULLWIDTH LATIN CAPITAL LETTER R S U+FF33 FULLWIDTH LATIN CAPITAL LETTER S T U+FF34 FULLWIDTH LATIN CAPITAL LETTER T U U+FF35 FULLWIDTH LATIN CAPITAL LETTER U V U+FF36 FULLWIDTH LATIN CAPITAL LETTER V W U+FF37 FULLWIDTH LATIN CAPITAL LETTER W X U+FF38 FULLWIDTH LATIN CAPITAL LETTER X Y U+FF39 FULLWIDTH LATIN CAPITAL LETTER Y Z U+FF3A FULLWIDTH LATIN CAPITAL LETTER Z 𐐀 U+10400 DESERET CAPITAL LETTER LONG I 𐐁 U+10401 DESERET CAPITAL LETTER LONG E 𐐂 U+10402 DESERET CAPITAL LETTER LONG A 𐐃 U+10403 DESERET CAPITAL LETTER LONG AH 𐐄 U+10404 DESERET CAPITAL LETTER LONG O 𐐅 U+10405 DESERET CAPITAL LETTER LONG OO 𐐆 U+10406 DESERET CAPITAL LETTER SHORT I 𐐇 U+10407 DESERET CAPITAL LETTER SHORT E 𐐈 U+10408 DESERET CAPITAL LETTER SHORT A 𐐉 U+10409 DESERET CAPITAL LETTER SHORT AH 𐐊 U+1040A DESERET CAPITAL LETTER SHORT O 𐐋 U+1040B DESERET CAPITAL LETTER SHORT OO 𐐌 U+1040C DESERET CAPITAL LETTER AY 𐐍 U+1040D DESERET CAPITAL LETTER OW 𐐎 U+1040E DESERET CAPITAL LETTER WU 𐐏 U+1040F DESERET CAPITAL LETTER YEE 𐐐 U+10410 DESERET CAPITAL LETTER H 𐐑 U+10411 DESERET CAPITAL LETTER PEE 𐐒 U+10412 DESERET CAPITAL LETTER BEE 𐐓 U+10413 DESERET CAPITAL LETTER TEE 𐐔 U+10414 DESERET CAPITAL LETTER DEE 𐐕 U+10415 DESERET CAPITAL LETTER CHEE 𐐖 U+10416 DESERET CAPITAL LETTER JEE 𐐗 U+10417 DESERET CAPITAL LETTER KAY 𐐘 U+10418 DESERET CAPITAL LETTER GAY 𐐙 U+10419 DESERET CAPITAL LETTER EF 𐐚 U+1041A DESERET CAPITAL LETTER VEE 𐐛 U+1041B DESERET CAPITAL LETTER ETH 𐐜 U+1041C DESERET CAPITAL LETTER THEE 𐐝 U+1041D DESERET CAPITAL LETTER ES 𐐞 U+1041E DESERET CAPITAL LETTER ZEE 𐐟 U+1041F DESERET CAPITAL LETTER ESH 𐐠 U+10420 DESERET CAPITAL LETTER ZHEE 𐐡 U+10421 DESERET CAPITAL LETTER ER 𐐢 U+10422 DESERET CAPITAL LETTER EL 𐐣 U+10423 DESERET CAPITAL LETTER EM 𐐤 U+10424 DESERET CAPITAL LETTER EN 𐐥 U+10425 DESERET CAPITAL LETTER ENG 𐐦 U+10426 DESERET CAPITAL LETTER OI 𐐧 U+10427 DESERET CAPITAL LETTER EW 𐒰 U+104B0 OSAGE CAPITAL LETTER A 𐒱 U+104B1 OSAGE CAPITAL LETTER AI 𐒲 U+104B2 OSAGE CAPITAL LETTER AIN 𐒳 U+104B3 OSAGE CAPITAL LETTER AH 𐒴 U+104B4 OSAGE CAPITAL LETTER BRA 𐒵 U+104B5 OSAGE CAPITAL LETTER CHA 𐒶 U+104B6 OSAGE CAPITAL LETTER EHCHA 𐒷 U+104B7 OSAGE CAPITAL LETTER E 𐒸 U+104B8 OSAGE CAPITAL LETTER EIN 𐒹 U+104B9 OSAGE CAPITAL LETTER HA 𐒺 U+104BA OSAGE CAPITAL LETTER HYA 𐒻 U+104BB OSAGE CAPITAL LETTER I 𐒼 U+104BC OSAGE CAPITAL LETTER KA 𐒽 U+104BD OSAGE CAPITAL LETTER EHKA 𐒾 U+104BE OSAGE CAPITAL LETTER KYA 𐒿 U+104BF OSAGE CAPITAL LETTER LA 𐓀 U+104C0 OSAGE CAPITAL LETTER MA 𐓁 U+104C1 OSAGE CAPITAL LETTER NA 𐓂 U+104C2 OSAGE CAPITAL LETTER O 𐓃 U+104C3 OSAGE CAPITAL LETTER OIN 𐓄 U+104C4 OSAGE CAPITAL LETTER PA 𐓅 U+104C5 OSAGE CAPITAL LETTER EHPA 𐓆 U+104C6 OSAGE CAPITAL LETTER SA 𐓇 U+104C7 OSAGE CAPITAL LETTER SHA 𐓈 U+104C8 OSAGE CAPITAL LETTER TA 𐓉 U+104C9 OSAGE CAPITAL LETTER EHTA 𐓊 U+104CA OSAGE CAPITAL LETTER TSA 𐓋 U+104CB OSAGE CAPITAL LETTER EHTSA 𐓌 U+104CC OSAGE CAPITAL LETTER TSHA 𐓍 U+104CD OSAGE CAPITAL LETTER DHA 𐓎 U+104CE OSAGE CAPITAL LETTER U 𐓏 U+104CF OSAGE CAPITAL LETTER WA 𐓐 U+104D0 OSAGE CAPITAL LETTER KHA 𐓑 U+104D1 OSAGE CAPITAL LETTER GHA 𐓒 U+104D2 OSAGE CAPITAL LETTER ZA 𐓓 U+104D3 OSAGE CAPITAL LETTER ZHA 𐲀 U+10C80 OLD HUNGARIAN CAPITAL LETTER A 𐲁 U+10C81 OLD HUNGARIAN CAPITAL LETTER AA 𐲂 U+10C82 OLD HUNGARIAN CAPITAL LETTER EB 𐲃 U+10C83 OLD HUNGARIAN CAPITAL LETTER AMB 𐲄 U+10C84 OLD HUNGARIAN CAPITAL LETTER EC 𐲅 U+10C85 OLD HUNGARIAN CAPITAL LETTER ENC 𐲆 U+10C86 OLD HUNGARIAN CAPITAL LETTER ECS 𐲇 U+10C87 OLD HUNGARIAN CAPITAL LETTER ED 𐲈 U+10C88 OLD HUNGARIAN CAPITAL LETTER AND 𐲉 U+10C89 OLD HUNGARIAN CAPITAL LETTER E 𐲊 U+10C8A OLD HUNGARIAN CAPITAL LETTER CLOSE E 𐲋 U+10C8B OLD HUNGARIAN CAPITAL LETTER EE 𐲌 U+10C8C OLD HUNGARIAN CAPITAL LETTER EF 𐲍 U+10C8D OLD HUNGARIAN CAPITAL LETTER EG 𐲎 U+10C8E OLD HUNGARIAN CAPITAL LETTER EGY 𐲏 U+10C8F OLD HUNGARIAN CAPITAL LETTER EH 𐲐 U+10C90 OLD HUNGARIAN CAPITAL LETTER I 𐲑 U+10C91 OLD HUNGARIAN CAPITAL LETTER II 𐲒 U+10C92 OLD HUNGARIAN CAPITAL LETTER EJ 𐲓 U+10C93 OLD HUNGARIAN CAPITAL LETTER EK 𐲔 U+10C94 OLD HUNGARIAN CAPITAL LETTER AK 𐲕 U+10C95 OLD HUNGARIAN CAPITAL LETTER UNK 𐲖 U+10C96 OLD HUNGARIAN CAPITAL LETTER EL 𐲗 U+10C97 OLD HUNGARIAN CAPITAL LETTER ELY 𐲘 U+10C98 OLD HUNGARIAN CAPITAL LETTER EM 𐲙 U+10C99 OLD HUNGARIAN CAPITAL LETTER EN 𐲚 U+10C9A OLD HUNGARIAN CAPITAL LETTER ENY 𐲛 U+10C9B OLD HUNGARIAN CAPITAL LETTER O 𐲜 U+10C9C OLD HUNGARIAN CAPITAL LETTER OO 𐲝 U+10C9D OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE 𐲞 U+10C9E OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE 𐲟 U+10C9F OLD HUNGARIAN CAPITAL LETTER OEE 𐲠 U+10CA0 OLD HUNGARIAN CAPITAL LETTER EP 𐲡 U+10CA1 OLD HUNGARIAN CAPITAL LETTER EMP 𐲢 U+10CA2 OLD HUNGARIAN CAPITAL LETTER ER 𐲣 U+10CA3 OLD HUNGARIAN CAPITAL LETTER SHORT ER 𐲤 U+10CA4 OLD HUNGARIAN CAPITAL LETTER ES 𐲥 U+10CA5 OLD HUNGARIAN CAPITAL LETTER ESZ 𐲦 U+10CA6 OLD HUNGARIAN CAPITAL LETTER ET 𐲧 U+10CA7 OLD HUNGARIAN CAPITAL LETTER ENT 𐲨 U+10CA8 OLD HUNGARIAN CAPITAL LETTER ETY 𐲩 U+10CA9 OLD HUNGARIAN CAPITAL LETTER ECH 𐲪 U+10CAA OLD HUNGARIAN CAPITAL LETTER U 𐲫 U+10CAB OLD HUNGARIAN CAPITAL LETTER UU 𐲬 U+10CAC OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE 𐲭 U+10CAD OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE 𐲮 U+10CAE OLD HUNGARIAN CAPITAL LETTER EV 𐲯 U+10CAF OLD HUNGARIAN CAPITAL LETTER EZ 𐲰 U+10CB0 OLD HUNGARIAN CAPITAL LETTER EZS 𐲱 U+10CB1 OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN 𐲲 U+10CB2 OLD HUNGARIAN CAPITAL LETTER US 𑢠 U+118A0 WARANG CITI CAPITAL LETTER NGAA 𑢡 U+118A1 WARANG CITI CAPITAL LETTER A 𑢢 U+118A2 WARANG CITI CAPITAL LETTER WI 𑢣 U+118A3 WARANG CITI CAPITAL LETTER YU 𑢤 U+118A4 WARANG CITI CAPITAL LETTER YA 𑢥 U+118A5 WARANG CITI CAPITAL LETTER YO 𑢦 U+118A6 WARANG CITI CAPITAL LETTER II 𑢧 U+118A7 WARANG CITI CAPITAL LETTER UU 𑢨 U+118A8 WARANG CITI CAPITAL LETTER E 𑢩 U+118A9 WARANG CITI CAPITAL LETTER O 𑢪 U+118AA WARANG CITI CAPITAL LETTER ANG 𑢫 U+118AB WARANG CITI CAPITAL LETTER GA 𑢬 U+118AC WARANG CITI CAPITAL LETTER KO 𑢭 U+118AD WARANG CITI CAPITAL LETTER ENY 𑢮 U+118AE WARANG CITI CAPITAL LETTER YUJ 𑢯 U+118AF WARANG CITI CAPITAL LETTER UC 𑢰 U+118B0 WARANG CITI CAPITAL LETTER ENN 𑢱 U+118B1 WARANG CITI CAPITAL LETTER ODD 𑢲 U+118B2 WARANG CITI CAPITAL LETTER TTE 𑢳 U+118B3 WARANG CITI CAPITAL LETTER NUNG 𑢴 U+118B4 WARANG CITI CAPITAL LETTER DA 𑢵 U+118B5 WARANG CITI CAPITAL LETTER AT 𑢶 U+118B6 WARANG CITI CAPITAL LETTER AM 𑢷 U+118B7 WARANG CITI CAPITAL LETTER BU 𑢸 U+118B8 WARANG CITI CAPITAL LETTER PU 𑢹 U+118B9 WARANG CITI CAPITAL LETTER HIYO 𑢺 U+118BA WARANG CITI CAPITAL LETTER HOLO 𑢻 U+118BB WARANG CITI CAPITAL LETTER HORR 𑢼 U+118BC WARANG CITI CAPITAL LETTER HAR 𑢽 U+118BD WARANG CITI CAPITAL LETTER SSUU 𑢾 U+118BE WARANG CITI CAPITAL LETTER SII 𑢿 U+118BF WARANG CITI CAPITAL LETTER VIYO 𖹀 U+16E40 MEDEFAIDRIN CAPITAL LETTER M 𖹁 U+16E41 MEDEFAIDRIN CAPITAL LETTER S 𖹂 U+16E42 MEDEFAIDRIN CAPITAL LETTER V 𖹃 U+16E43 MEDEFAIDRIN CAPITAL LETTER W 𖹄 U+16E44 MEDEFAIDRIN CAPITAL LETTER ATIU 𖹅 U+16E45 MEDEFAIDRIN CAPITAL LETTER Z 𖹆 U+16E46 MEDEFAIDRIN CAPITAL LETTER KP 𖹇 U+16E47 MEDEFAIDRIN CAPITAL LETTER P 𖹈 U+16E48 MEDEFAIDRIN CAPITAL LETTER T 𖹉 U+16E49 MEDEFAIDRIN CAPITAL LETTER G 𖹊 U+16E4A MEDEFAIDRIN CAPITAL LETTER F 𖹋 U+16E4B MEDEFAIDRIN CAPITAL LETTER I 𖹌 U+16E4C MEDEFAIDRIN CAPITAL LETTER K 𖹍 U+16E4D MEDEFAIDRIN CAPITAL LETTER A 𖹎 U+16E4E MEDEFAIDRIN CAPITAL LETTER J 𖹏 U+16E4F MEDEFAIDRIN CAPITAL LETTER E 𖹐 U+16E50 MEDEFAIDRIN CAPITAL LETTER B 𖹑 U+16E51 MEDEFAIDRIN CAPITAL LETTER C 𖹒 U+16E52 MEDEFAIDRIN CAPITAL LETTER U 𖹓 U+16E53 MEDEFAIDRIN CAPITAL LETTER YU 𖹔 U+16E54 MEDEFAIDRIN CAPITAL LETTER L 𖹕 U+16E55 MEDEFAIDRIN CAPITAL LETTER Q 𖹖 U+16E56 MEDEFAIDRIN CAPITAL LETTER HP 𖹗 U+16E57 MEDEFAIDRIN CAPITAL LETTER NY 𖹘 U+16E58 MEDEFAIDRIN CAPITAL LETTER X 𖹙 U+16E59 MEDEFAIDRIN CAPITAL LETTER D 𖹚 U+16E5A MEDEFAIDRIN CAPITAL LETTER OE 𖹛 U+16E5B MEDEFAIDRIN CAPITAL LETTER N 𖹜 U+16E5C MEDEFAIDRIN CAPITAL LETTER R 𖹝 U+16E5D MEDEFAIDRIN CAPITAL LETTER O 𖹞 U+16E5E MEDEFAIDRIN CAPITAL LETTER AI 𖹟 U+16E5F MEDEFAIDRIN CAPITAL LETTER Y 𝐀 U+1D400 MATHEMATICAL BOLD CAPITAL A 𝐁 U+1D401 MATHEMATICAL BOLD CAPITAL B 𝐂 U+1D402 MATHEMATICAL BOLD CAPITAL C 𝐃 U+1D403 MATHEMATICAL BOLD CAPITAL D 𝐄 U+1D404 MATHEMATICAL BOLD CAPITAL E 𝐅 U+1D405 MATHEMATICAL BOLD CAPITAL F 𝐆 U+1D406 MATHEMATICAL BOLD CAPITAL G 𝐇 U+1D407 MATHEMATICAL BOLD CAPITAL H 𝐈 U+1D408 MATHEMATICAL BOLD CAPITAL I 𝐉 U+1D409 MATHEMATICAL BOLD CAPITAL J 𝐊 U+1D40A MATHEMATICAL BOLD CAPITAL K 𝐋 U+1D40B MATHEMATICAL BOLD CAPITAL L 𝐌 U+1D40C MATHEMATICAL BOLD CAPITAL M 𝐍 U+1D40D MATHEMATICAL BOLD CAPITAL N 𝐎 U+1D40E MATHEMATICAL BOLD CAPITAL O 𝐏 U+1D40F MATHEMATICAL BOLD CAPITAL P 𝐐 U+1D410 MATHEMATICAL BOLD CAPITAL Q 𝐑 U+1D411 MATHEMATICAL BOLD CAPITAL R 𝐒 U+1D412 MATHEMATICAL BOLD CAPITAL S 𝐓 U+1D413 MATHEMATICAL BOLD CAPITAL T 𝐔 U+1D414 MATHEMATICAL BOLD CAPITAL U 𝐕 U+1D415 MATHEMATICAL BOLD CAPITAL V 𝐖 U+1D416 MATHEMATICAL BOLD CAPITAL W 𝐗 U+1D417 MATHEMATICAL BOLD CAPITAL X 𝐘 U+1D418 MATHEMATICAL BOLD CAPITAL Y 𝐙 U+1D419 MATHEMATICAL BOLD CAPITAL Z 𝐴 U+1D434 MATHEMATICAL ITALIC CAPITAL A 𝐵 U+1D435 MATHEMATICAL ITALIC CAPITAL B 𝐶 U+1D436 MATHEMATICAL ITALIC CAPITAL C 𝐷 U+1D437 MATHEMATICAL ITALIC CAPITAL D 𝐸 U+1D438 MATHEMATICAL ITALIC CAPITAL E 𝐹 U+1D439 MATHEMATICAL ITALIC CAPITAL F 𝐺 U+1D43A MATHEMATICAL ITALIC CAPITAL G 𝐻 U+1D43B MATHEMATICAL ITALIC CAPITAL H 𝐼 U+1D43C MATHEMATICAL ITALIC CAPITAL I 𝐽 U+1D43D MATHEMATICAL ITALIC CAPITAL J 𝐾 U+1D43E MATHEMATICAL ITALIC CAPITAL K 𝐿 U+1D43F MATHEMATICAL ITALIC CAPITAL L 𝑀 U+1D440 MATHEMATICAL ITALIC CAPITAL M 𝑁 U+1D441 MATHEMATICAL ITALIC CAPITAL N 𝑂 U+1D442 MATHEMATICAL ITALIC CAPITAL O 𝑃 U+1D443 MATHEMATICAL ITALIC CAPITAL P 𝑄 U+1D444 MATHEMATICAL ITALIC CAPITAL Q 𝑅 U+1D445 MATHEMATICAL ITALIC CAPITAL R 𝑆 U+1D446 MATHEMATICAL ITALIC CAPITAL S 𝑇 U+1D447 MATHEMATICAL ITALIC CAPITAL T 𝑈 U+1D448 MATHEMATICAL ITALIC CAPITAL U 𝑉 U+1D449 MATHEMATICAL ITALIC CAPITAL V 𝑊 U+1D44A MATHEMATICAL ITALIC CAPITAL W 𝑋 U+1D44B MATHEMATICAL ITALIC CAPITAL X 𝑌 U+1D44C MATHEMATICAL ITALIC CAPITAL Y 𝑍 U+1D44D MATHEMATICAL ITALIC CAPITAL Z 𝑨 U+1D468 MATHEMATICAL BOLD ITALIC CAPITAL A 𝑩 U+1D469 MATHEMATICAL BOLD ITALIC CAPITAL B 𝑪 U+1D46A MATHEMATICAL BOLD ITALIC CAPITAL C 𝑫 U+1D46B MATHEMATICAL BOLD ITALIC CAPITAL D 𝑬 U+1D46C MATHEMATICAL BOLD ITALIC CAPITAL E 𝑭 U+1D46D MATHEMATICAL BOLD ITALIC CAPITAL F 𝑮 U+1D46E MATHEMATICAL BOLD ITALIC CAPITAL G 𝑯 U+1D46F MATHEMATICAL BOLD ITALIC CAPITAL H 𝑰 U+1D470 MATHEMATICAL BOLD ITALIC CAPITAL I 𝑱 U+1D471 MATHEMATICAL BOLD ITALIC CAPITAL J 𝑲 U+1D472 MATHEMATICAL BOLD ITALIC CAPITAL K 𝑳 U+1D473 MATHEMATICAL BOLD ITALIC CAPITAL L 𝑴 U+1D474 MATHEMATICAL BOLD ITALIC CAPITAL M 𝑵 U+1D475 MATHEMATICAL BOLD ITALIC CAPITAL N 𝑶 U+1D476 MATHEMATICAL BOLD ITALIC CAPITAL O 𝑷 U+1D477 MATHEMATICAL BOLD ITALIC CAPITAL P 𝑸 U+1D478 MATHEMATICAL BOLD ITALIC CAPITAL Q 𝑹 U+1D479 MATHEMATICAL BOLD ITALIC CAPITAL R 𝑺 U+1D47A MATHEMATICAL BOLD ITALIC CAPITAL S 𝑻 U+1D47B MATHEMATICAL BOLD ITALIC CAPITAL T 𝑼 U+1D47C MATHEMATICAL BOLD ITALIC CAPITAL U 𝑽 U+1D47D MATHEMATICAL BOLD ITALIC CAPITAL V 𝑾 U+1D47E MATHEMATICAL BOLD ITALIC CAPITAL W 𝑿 U+1D47F MATHEMATICAL BOLD ITALIC CAPITAL X 𝒀 U+1D480 MATHEMATICAL BOLD ITALIC CAPITAL Y 𝒁 U+1D481 MATHEMATICAL BOLD ITALIC CAPITAL Z 𝒜 U+1D49C MATHEMATICAL SCRIPT CAPITAL A 𝒞 U+1D49E MATHEMATICAL SCRIPT CAPITAL C 𝒟 U+1D49F MATHEMATICAL SCRIPT CAPITAL D 𝒢 U+1D4A2 MATHEMATICAL SCRIPT CAPITAL G 𝒥 U+1D4A5 MATHEMATICAL SCRIPT CAPITAL J 𝒦 U+1D4A6 MATHEMATICAL SCRIPT CAPITAL K 𝒩 U+1D4A9 MATHEMATICAL SCRIPT CAPITAL N 𝒪 U+1D4AA MATHEMATICAL SCRIPT CAPITAL O 𝒫 U+1D4AB MATHEMATICAL SCRIPT CAPITAL P 𝒬 U+1D4AC MATHEMATICAL SCRIPT CAPITAL Q 𝒮 U+1D4AE MATHEMATICAL SCRIPT CAPITAL S 𝒯 U+1D4AF MATHEMATICAL SCRIPT CAPITAL T 𝒰 U+1D4B0 MATHEMATICAL SCRIPT CAPITAL U 𝒱 U+1D4B1 MATHEMATICAL SCRIPT CAPITAL V 𝒲 U+1D4B2 MATHEMATICAL SCRIPT CAPITAL W 𝒳 U+1D4B3 MATHEMATICAL SCRIPT CAPITAL X 𝒴 U+1D4B4 MATHEMATICAL SCRIPT CAPITAL Y 𝒵 U+1D4B5 MATHEMATICAL SCRIPT CAPITAL Z 𝓐 U+1D4D0 MATHEMATICAL BOLD SCRIPT CAPITAL A 𝓑 U+1D4D1 MATHEMATICAL BOLD SCRIPT CAPITAL B 𝓒 U+1D4D2 MATHEMATICAL BOLD SCRIPT CAPITAL C 𝓓 U+1D4D3 MATHEMATICAL BOLD SCRIPT CAPITAL D 𝓔 U+1D4D4 MATHEMATICAL BOLD SCRIPT CAPITAL E 𝓕 U+1D4D5 MATHEMATICAL BOLD SCRIPT CAPITAL F 𝓖 U+1D4D6 MATHEMATICAL BOLD SCRIPT CAPITAL G 𝓗 U+1D4D7 MATHEMATICAL BOLD SCRIPT CAPITAL H 𝓘 U+1D4D8 MATHEMATICAL BOLD SCRIPT CAPITAL I 𝓙 U+1D4D9 MATHEMATICAL BOLD SCRIPT CAPITAL J 𝓚 U+1D4DA MATHEMATICAL BOLD SCRIPT CAPITAL K 𝓛 U+1D4DB MATHEMATICAL BOLD SCRIPT CAPITAL L 𝓜 U+1D4DC MATHEMATICAL BOLD SCRIPT CAPITAL M 𝓝 U+1D4DD MATHEMATICAL BOLD SCRIPT CAPITAL N 𝓞 U+1D4DE MATHEMATICAL BOLD SCRIPT CAPITAL O 𝓟 U+1D4DF MATHEMATICAL BOLD SCRIPT CAPITAL P 𝓠 U+1D4E0 MATHEMATICAL BOLD SCRIPT CAPITAL Q 𝓡 U+1D4E1 MATHEMATICAL BOLD SCRIPT CAPITAL R 𝓢 U+1D4E2 MATHEMATICAL BOLD SCRIPT CAPITAL S 𝓣 U+1D4E3 MATHEMATICAL BOLD SCRIPT CAPITAL T 𝓤 U+1D4E4 MATHEMATICAL BOLD SCRIPT CAPITAL U 𝓥 U+1D4E5 MATHEMATICAL BOLD SCRIPT CAPITAL V 𝓦 U+1D4E6 MATHEMATICAL BOLD SCRIPT CAPITAL W 𝓧 U+1D4E7 MATHEMATICAL BOLD SCRIPT CAPITAL X 𝓨 U+1D4E8 MATHEMATICAL BOLD SCRIPT CAPITAL Y 𝓩 U+1D4E9 MATHEMATICAL BOLD SCRIPT CAPITAL Z 𝔄 U+1D504 MATHEMATICAL FRAKTUR CAPITAL A 𝔅 U+1D505 MATHEMATICAL FRAKTUR CAPITAL B 𝔇 U+1D507 MATHEMATICAL FRAKTUR CAPITAL D 𝔈 U+1D508 MATHEMATICAL FRAKTUR CAPITAL E 𝔉 U+1D509 MATHEMATICAL FRAKTUR CAPITAL F 𝔊 U+1D50A MATHEMATICAL FRAKTUR CAPITAL G 𝔍 U+1D50D MATHEMATICAL FRAKTUR CAPITAL J 𝔎 U+1D50E MATHEMATICAL FRAKTUR CAPITAL K 𝔏 U+1D50F MATHEMATICAL FRAKTUR CAPITAL L 𝔐 U+1D510 MATHEMATICAL FRAKTUR CAPITAL M 𝔑 U+1D511 MATHEMATICAL FRAKTUR CAPITAL N 𝔒 U+1D512 MATHEMATICAL FRAKTUR CAPITAL O 𝔓 U+1D513 MATHEMATICAL FRAKTUR CAPITAL P 𝔔 U+1D514 MATHEMATICAL FRAKTUR CAPITAL Q 𝔖 U+1D516 MATHEMATICAL FRAKTUR CAPITAL S 𝔗 U+1D517 MATHEMATICAL FRAKTUR CAPITAL T 𝔘 U+1D518 MATHEMATICAL FRAKTUR CAPITAL U 𝔙 U+1D519 MATHEMATICAL FRAKTUR CAPITAL V 𝔚 U+1D51A MATHEMATICAL FRAKTUR CAPITAL W 𝔛 U+1D51B MATHEMATICAL FRAKTUR CAPITAL X 𝔜 U+1D51C MATHEMATICAL FRAKTUR CAPITAL Y 𝔸 U+1D538 MATHEMATICAL DOUBLE-STRUCK CAPITAL A 𝔹 U+1D539 MATHEMATICAL DOUBLE-STRUCK CAPITAL B 𝔻 U+1D53B MATHEMATICAL DOUBLE-STRUCK CAPITAL D 𝔼 U+1D53C MATHEMATICAL DOUBLE-STRUCK CAPITAL E 𝔽 U+1D53D MATHEMATICAL DOUBLE-STRUCK CAPITAL F 𝔾 U+1D53E MATHEMATICAL DOUBLE-STRUCK CAPITAL G 𝕀 U+1D540 MATHEMATICAL DOUBLE-STRUCK CAPITAL I 𝕁 U+1D541 MATHEMATICAL DOUBLE-STRUCK CAPITAL J 𝕂 U+1D542 MATHEMATICAL DOUBLE-STRUCK CAPITAL K 𝕃 U+1D543 MATHEMATICAL DOUBLE-STRUCK CAPITAL L 𝕄 U+1D544 MATHEMATICAL DOUBLE-STRUCK CAPITAL M 𝕆 U+1D546 MATHEMATICAL DOUBLE-STRUCK CAPITAL O 𝕊 U+1D54A MATHEMATICAL DOUBLE-STRUCK CAPITAL S 𝕋 U+1D54B MATHEMATICAL DOUBLE-STRUCK CAPITAL T 𝕌 U+1D54C MATHEMATICAL DOUBLE-STRUCK CAPITAL U 𝕍 U+1D54D MATHEMATICAL DOUBLE-STRUCK CAPITAL V 𝕎 U+1D54E MATHEMATICAL DOUBLE-STRUCK CAPITAL W 𝕏 U+1D54F MATHEMATICAL DOUBLE-STRUCK CAPITAL X 𝕐 U+1D550 MATHEMATICAL DOUBLE-STRUCK CAPITAL Y 𝕬 U+1D56C MATHEMATICAL BOLD FRAKTUR CAPITAL A 𝕭 U+1D56D MATHEMATICAL BOLD FRAKTUR CAPITAL B 𝕮 U+1D56E MATHEMATICAL BOLD FRAKTUR CAPITAL C 𝕯 U+1D56F MATHEMATICAL BOLD FRAKTUR CAPITAL D 𝕰 U+1D570 MATHEMATICAL BOLD FRAKTUR CAPITAL E 𝕱 U+1D571 MATHEMATICAL BOLD FRAKTUR CAPITAL F 𝕲 U+1D572 MATHEMATICAL BOLD FRAKTUR CAPITAL G 𝕳 U+1D573 MATHEMATICAL BOLD FRAKTUR CAPITAL H 𝕴 U+1D574 MATHEMATICAL BOLD FRAKTUR CAPITAL I 𝕵 U+1D575 MATHEMATICAL BOLD FRAKTUR CAPITAL J 𝕶 U+1D576 MATHEMATICAL BOLD FRAKTUR CAPITAL K 𝕷 U+1D577 MATHEMATICAL BOLD FRAKTUR CAPITAL L 𝕸 U+1D578 MATHEMATICAL BOLD FRAKTUR CAPITAL M 𝕹 U+1D579 MATHEMATICAL BOLD FRAKTUR CAPITAL N 𝕺 U+1D57A MATHEMATICAL BOLD FRAKTUR CAPITAL O 𝕻 U+1D57B MATHEMATICAL BOLD FRAKTUR CAPITAL P 𝕼 U+1D57C MATHEMATICAL BOLD FRAKTUR CAPITAL Q 𝕽 U+1D57D MATHEMATICAL BOLD FRAKTUR CAPITAL R 𝕾 U+1D57E MATHEMATICAL BOLD FRAKTUR CAPITAL S 𝕿 U+1D57F MATHEMATICAL BOLD FRAKTUR CAPITAL T 𝖀 U+1D580 MATHEMATICAL BOLD FRAKTUR CAPITAL U 𝖁 U+1D581 MATHEMATICAL BOLD FRAKTUR CAPITAL V 𝖂 U+1D582 MATHEMATICAL BOLD FRAKTUR CAPITAL W 𝖃 U+1D583 MATHEMATICAL BOLD FRAKTUR CAPITAL X 𝖄 U+1D584 MATHEMATICAL BOLD FRAKTUR CAPITAL Y 𝖅 U+1D585 MATHEMATICAL BOLD FRAKTUR CAPITAL Z 𝖠 U+1D5A0 MATHEMATICAL SANS-SERIF CAPITAL A 𝖡 U+1D5A1 MATHEMATICAL SANS-SERIF CAPITAL B 𝖢 U+1D5A2 MATHEMATICAL SANS-SERIF CAPITAL C 𝖣 U+1D5A3 MATHEMATICAL SANS-SERIF CAPITAL D 𝖤 U+1D5A4 MATHEMATICAL SANS-SERIF CAPITAL E 𝖥 U+1D5A5 MATHEMATICAL SANS-SERIF CAPITAL F 𝖦 U+1D5A6 MATHEMATICAL SANS-SERIF CAPITAL G 𝖧 U+1D5A7 MATHEMATICAL SANS-SERIF CAPITAL H 𝖨 U+1D5A8 MATHEMATICAL SANS-SERIF CAPITAL I 𝖩 U+1D5A9 MATHEMATICAL SANS-SERIF CAPITAL J 𝖪 U+1D5AA MATHEMATICAL SANS-SERIF CAPITAL K 𝖫 U+1D5AB MATHEMATICAL SANS-SERIF CAPITAL L 𝖬 U+1D5AC MATHEMATICAL SANS-SERIF CAPITAL M 𝖭 U+1D5AD MATHEMATICAL SANS-SERIF CAPITAL N 𝖮 U+1D5AE MATHEMATICAL SANS-SERIF CAPITAL O 𝖯 U+1D5AF MATHEMATICAL SANS-SERIF CAPITAL P 𝖰 U+1D5B0 MATHEMATICAL SANS-SERIF CAPITAL Q 𝖱 U+1D5B1 MATHEMATICAL SANS-SERIF CAPITAL R 𝖲 U+1D5B2 MATHEMATICAL SANS-SERIF CAPITAL S 𝖳 U+1D5B3 MATHEMATICAL SANS-SERIF CAPITAL T 𝖴 U+1D5B4 MATHEMATICAL SANS-SERIF CAPITAL U 𝖵 U+1D5B5 MATHEMATICAL SANS-SERIF CAPITAL V 𝖶 U+1D5B6 MATHEMATICAL SANS-SERIF CAPITAL W 𝖷 U+1D5B7 MATHEMATICAL SANS-SERIF CAPITAL X 𝖸 U+1D5B8 MATHEMATICAL SANS-SERIF CAPITAL Y 𝖹 U+1D5B9 MATHEMATICAL SANS-SERIF CAPITAL Z 𝗔 U+1D5D4 MATHEMATICAL SANS-SERIF BOLD CAPITAL A 𝗕 U+1D5D5 MATHEMATICAL SANS-SERIF BOLD CAPITAL B 𝗖 U+1D5D6 MATHEMATICAL SANS-SERIF BOLD CAPITAL C 𝗗 U+1D5D7 MATHEMATICAL SANS-SERIF BOLD CAPITAL D 𝗘 U+1D5D8 MATHEMATICAL SANS-SERIF BOLD CAPITAL E 𝗙 U+1D5D9 MATHEMATICAL SANS-SERIF BOLD CAPITAL F 𝗚 U+1D5DA MATHEMATICAL SANS-SERIF BOLD CAPITAL G 𝗛 U+1D5DB MATHEMATICAL SANS-SERIF BOLD CAPITAL H 𝗜 U+1D5DC MATHEMATICAL SANS-SERIF BOLD CAPITAL I 𝗝 U+1D5DD MATHEMATICAL SANS-SERIF BOLD CAPITAL J 𝗞 U+1D5DE MATHEMATICAL SANS-SERIF BOLD CAPITAL K 𝗟 U+1D5DF MATHEMATICAL SANS-SERIF BOLD CAPITAL L 𝗠 U+1D5E0 MATHEMATICAL SANS-SERIF BOLD CAPITAL M 𝗡 U+1D5E1 MATHEMATICAL SANS-SERIF BOLD CAPITAL N 𝗢 U+1D5E2 MATHEMATICAL SANS-SERIF BOLD CAPITAL O 𝗣 U+1D5E3 MATHEMATICAL SANS-SERIF BOLD CAPITAL P 𝗤 U+1D5E4 MATHEMATICAL SANS-SERIF BOLD CAPITAL Q 𝗥 U+1D5E5 MATHEMATICAL SANS-SERIF BOLD CAPITAL R 𝗦 U+1D5E6 MATHEMATICAL SANS-SERIF BOLD CAPITAL S 𝗧 U+1D5E7 MATHEMATICAL SANS-SERIF BOLD CAPITAL T 𝗨 U+1D5E8 MATHEMATICAL SANS-SERIF BOLD CAPITAL U 𝗩 U+1D5E9 MATHEMATICAL SANS-SERIF BOLD CAPITAL V 𝗪 U+1D5EA MATHEMATICAL SANS-SERIF BOLD CAPITAL W 𝗫 U+1D5EB MATHEMATICAL SANS-SERIF BOLD CAPITAL X 𝗬 U+1D5EC MATHEMATICAL SANS-SERIF BOLD CAPITAL Y 𝗭 U+1D5ED MATHEMATICAL SANS-SERIF BOLD CAPITAL Z 𝘈 U+1D608 MATHEMATICAL SANS-SERIF ITALIC CAPITAL A 𝘉 U+1D609 MATHEMATICAL SANS-SERIF ITALIC CAPITAL B 𝘊 U+1D60A MATHEMATICAL SANS-SERIF ITALIC CAPITAL C 𝘋 U+1D60B MATHEMATICAL SANS-SERIF ITALIC CAPITAL D 𝘌 U+1D60C MATHEMATICAL SANS-SERIF ITALIC CAPITAL E 𝘍 U+1D60D MATHEMATICAL SANS-SERIF ITALIC CAPITAL F 𝘎 U+1D60E MATHEMATICAL SANS-SERIF ITALIC CAPITAL G 𝘏 U+1D60F MATHEMATICAL SANS-SERIF ITALIC CAPITAL H 𝘐 U+1D610 MATHEMATICAL SANS-SERIF ITALIC CAPITAL I 𝘑 U+1D611 MATHEMATICAL SANS-SERIF ITALIC CAPITAL J 𝘒 U+1D612 MATHEMATICAL SANS-SERIF ITALIC CAPITAL K 𝘓 U+1D613 MATHEMATICAL SANS-SERIF ITALIC CAPITAL L 𝘔 U+1D614 MATHEMATICAL SANS-SERIF ITALIC CAPITAL M 𝘕 U+1D615 MATHEMATICAL SANS-SERIF ITALIC CAPITAL N 𝘖 U+1D616 MATHEMATICAL SANS-SERIF ITALIC CAPITAL O 𝘗 U+1D617 MATHEMATICAL SANS-SERIF ITALIC CAPITAL P 𝘘 U+1D618 MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q 𝘙 U+1D619 MATHEMATICAL SANS-SERIF ITALIC CAPITAL R 𝘚 U+1D61A MATHEMATICAL SANS-SERIF ITALIC CAPITAL S 𝘛 U+1D61B MATHEMATICAL SANS-SERIF ITALIC CAPITAL T 𝘜 U+1D61C MATHEMATICAL SANS-SERIF ITALIC CAPITAL U 𝘝 U+1D61D MATHEMATICAL SANS-SERIF ITALIC CAPITAL V 𝘞 U+1D61E MATHEMATICAL SANS-SERIF ITALIC CAPITAL W 𝘟 U+1D61F MATHEMATICAL SANS-SERIF ITALIC CAPITAL X 𝘠 U+1D620 MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y 𝘡 U+1D621 MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z 𝘼 U+1D63C MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A 𝘽 U+1D63D MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B 𝘾 U+1D63E MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C 𝘿 U+1D63F MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D 𝙀 U+1D640 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E 𝙁 U+1D641 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F 𝙂 U+1D642 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G 𝙃 U+1D643 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H 𝙄 U+1D644 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I 𝙅 U+1D645 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J 𝙆 U+1D646 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K 𝙇 U+1D647 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L 𝙈 U+1D648 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M 𝙉 U+1D649 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N 𝙊 U+1D64A MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O 𝙋 U+1D64B MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P 𝙌 U+1D64C MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q 𝙍 U+1D64D MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R 𝙎 U+1D64E MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S 𝙏 U+1D64F MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T 𝙐 U+1D650 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U 𝙑 U+1D651 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V 𝙒 U+1D652 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W 𝙓 U+1D653 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X 𝙔 U+1D654 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y 𝙕 U+1D655 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z 𝙰 U+1D670 MATHEMATICAL MONOSPACE CAPITAL A 𝙱 U+1D671 MATHEMATICAL MONOSPACE CAPITAL B 𝙲 U+1D672 MATHEMATICAL MONOSPACE CAPITAL C 𝙳 U+1D673 MATHEMATICAL MONOSPACE CAPITAL D 𝙴 U+1D674 MATHEMATICAL MONOSPACE CAPITAL E 𝙵 U+1D675 MATHEMATICAL MONOSPACE CAPITAL F 𝙶 U+1D676 MATHEMATICAL MONOSPACE CAPITAL G 𝙷 U+1D677 MATHEMATICAL MONOSPACE CAPITAL H 𝙸 U+1D678 MATHEMATICAL MONOSPACE CAPITAL I 𝙹 U+1D679 MATHEMATICAL MONOSPACE CAPITAL J 𝙺 U+1D67A MATHEMATICAL MONOSPACE CAPITAL K 𝙻 U+1D67B MATHEMATICAL MONOSPACE CAPITAL L 𝙼 U+1D67C MATHEMATICAL MONOSPACE CAPITAL M 𝙽 U+1D67D MATHEMATICAL MONOSPACE CAPITAL N 𝙾 U+1D67E MATHEMATICAL MONOSPACE CAPITAL O 𝙿 U+1D67F MATHEMATICAL MONOSPACE CAPITAL P 𝚀 U+1D680 MATHEMATICAL MONOSPACE CAPITAL Q 𝚁 U+1D681 MATHEMATICAL MONOSPACE CAPITAL R 𝚂 U+1D682 MATHEMATICAL MONOSPACE CAPITAL S 𝚃 U+1D683 MATHEMATICAL MONOSPACE CAPITAL T 𝚄 U+1D684 MATHEMATICAL MONOSPACE CAPITAL U 𝚅 U+1D685 MATHEMATICAL MONOSPACE CAPITAL V 𝚆 U+1D686 MATHEMATICAL MONOSPACE CAPITAL W 𝚇 U+1D687 MATHEMATICAL MONOSPACE CAPITAL X 𝚈 U+1D688 MATHEMATICAL MONOSPACE CAPITAL Y 𝚉 U+1D689 MATHEMATICAL MONOSPACE CAPITAL Z 𝚨 U+1D6A8 MATHEMATICAL BOLD CAPITAL ALPHA 𝚩 U+1D6A9 MATHEMATICAL BOLD CAPITAL BETA 𝚪 U+1D6AA MATHEMATICAL BOLD CAPITAL GAMMA 𝚫 U+1D6AB MATHEMATICAL BOLD CAPITAL DELTA 𝚬 U+1D6AC MATHEMATICAL BOLD CAPITAL EPSILON 𝚭 U+1D6AD MATHEMATICAL BOLD CAPITAL ZETA 𝚮 U+1D6AE MATHEMATICAL BOLD CAPITAL ETA 𝚯 U+1D6AF MATHEMATICAL BOLD CAPITAL THETA 𝚰 U+1D6B0 MATHEMATICAL BOLD CAPITAL IOTA 𝚱 U+1D6B1 MATHEMATICAL BOLD CAPITAL KAPPA 𝚲 U+1D6B2 MATHEMATICAL BOLD CAPITAL LAMDA 𝚳 U+1D6B3 MATHEMATICAL BOLD CAPITAL MU 𝚴 U+1D6B4 MATHEMATICAL BOLD CAPITAL NU 𝚵 U+1D6B5 MATHEMATICAL BOLD CAPITAL XI 𝚶 U+1D6B6 MATHEMATICAL BOLD CAPITAL OMICRON 𝚷 U+1D6B7 MATHEMATICAL BOLD CAPITAL PI 𝚸 U+1D6B8 MATHEMATICAL BOLD CAPITAL RHO 𝚹 U+1D6B9 MATHEMATICAL BOLD CAPITAL THETA SYMBOL 𝚺 U+1D6BA MATHEMATICAL BOLD CAPITAL SIGMA 𝚻 U+1D6BB MATHEMATICAL BOLD CAPITAL TAU 𝚼 U+1D6BC MATHEMATICAL BOLD CAPITAL UPSILON 𝚽 U+1D6BD MATHEMATICAL BOLD CAPITAL PHI 𝚾 U+1D6BE MATHEMATICAL BOLD CAPITAL CHI 𝚿 U+1D6BF MATHEMATICAL BOLD CAPITAL PSI 𝛀 U+1D6C0 MATHEMATICAL BOLD CAPITAL OMEGA 𝛢 U+1D6E2 MATHEMATICAL ITALIC CAPITAL ALPHA 𝛣 U+1D6E3 MATHEMATICAL ITALIC CAPITAL BETA 𝛤 U+1D6E4 MATHEMATICAL ITALIC CAPITAL GAMMA 𝛥 U+1D6E5 MATHEMATICAL ITALIC CAPITAL DELTA 𝛦 U+1D6E6 MATHEMATICAL ITALIC CAPITAL EPSILON 𝛧 U+1D6E7 MATHEMATICAL ITALIC CAPITAL ZETA 𝛨 U+1D6E8 MATHEMATICAL ITALIC CAPITAL ETA 𝛩 U+1D6E9 MATHEMATICAL ITALIC CAPITAL THETA 𝛪 U+1D6EA MATHEMATICAL ITALIC CAPITAL IOTA 𝛫 U+1D6EB MATHEMATICAL ITALIC CAPITAL KAPPA 𝛬 U+1D6EC MATHEMATICAL ITALIC CAPITAL LAMDA 𝛭 U+1D6ED MATHEMATICAL ITALIC CAPITAL MU 𝛮 U+1D6EE MATHEMATICAL ITALIC CAPITAL NU 𝛯 U+1D6EF MATHEMATICAL ITALIC CAPITAL XI 𝛰 U+1D6F0 MATHEMATICAL ITALIC CAPITAL OMICRON 𝛱 U+1D6F1 MATHEMATICAL ITALIC CAPITAL PI 𝛲 U+1D6F2 MATHEMATICAL ITALIC CAPITAL RHO 𝛳 U+1D6F3 MATHEMATICAL ITALIC CAPITAL THETA SYMBOL 𝛴 U+1D6F4 MATHEMATICAL ITALIC CAPITAL SIGMA 𝛵 U+1D6F5 MATHEMATICAL ITALIC CAPITAL TAU 𝛶 U+1D6F6 MATHEMATICAL ITALIC CAPITAL UPSILON 𝛷 U+1D6F7 MATHEMATICAL ITALIC CAPITAL PHI 𝛸 U+1D6F8 MATHEMATICAL ITALIC CAPITAL CHI 𝛹 U+1D6F9 MATHEMATICAL ITALIC CAPITAL PSI 𝛺 U+1D6FA MATHEMATICAL ITALIC CAPITAL OMEGA 𝜜 U+1D71C MATHEMATICAL BOLD ITALIC CAPITAL ALPHA 𝜝 U+1D71D MATHEMATICAL BOLD ITALIC CAPITAL BETA 𝜞 U+1D71E MATHEMATICAL BOLD ITALIC CAPITAL GAMMA 𝜟 U+1D71F MATHEMATICAL BOLD ITALIC CAPITAL DELTA 𝜠 U+1D720 MATHEMATICAL BOLD ITALIC CAPITAL EPSILON 𝜡 U+1D721 MATHEMATICAL BOLD ITALIC CAPITAL ZETA 𝜢 U+1D722 MATHEMATICAL BOLD ITALIC CAPITAL ETA 𝜣 U+1D723 MATHEMATICAL BOLD ITALIC CAPITAL THETA 𝜤 U+1D724 MATHEMATICAL BOLD ITALIC CAPITAL IOTA 𝜥 U+1D725 MATHEMATICAL BOLD ITALIC CAPITAL KAPPA 𝜦 U+1D726 MATHEMATICAL BOLD ITALIC CAPITAL LAMDA 𝜧 U+1D727 MATHEMATICAL BOLD ITALIC CAPITAL MU 𝜨 U+1D728 MATHEMATICAL BOLD ITALIC CAPITAL NU 𝜩 U+1D729 MATHEMATICAL BOLD ITALIC CAPITAL XI 𝜪 U+1D72A MATHEMATICAL BOLD ITALIC CAPITAL OMICRON 𝜫 U+1D72B MATHEMATICAL BOLD ITALIC CAPITAL PI 𝜬 U+1D72C MATHEMATICAL BOLD ITALIC CAPITAL RHO 𝜭 U+1D72D MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL 𝜮 U+1D72E MATHEMATICAL BOLD ITALIC CAPITAL SIGMA 𝜯 U+1D72F MATHEMATICAL BOLD ITALIC CAPITAL TAU 𝜰 U+1D730 MATHEMATICAL BOLD ITALIC CAPITAL UPSILON 𝜱 U+1D731 MATHEMATICAL BOLD ITALIC CAPITAL PHI 𝜲 U+1D732 MATHEMATICAL BOLD ITALIC CAPITAL CHI 𝜳 U+1D733 MATHEMATICAL BOLD ITALIC CAPITAL PSI 𝜴 U+1D734 MATHEMATICAL BOLD ITALIC CAPITAL OMEGA 𝝖 U+1D756 MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA 𝝗 U+1D757 MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA 𝝘 U+1D758 MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA 𝝙 U+1D759 MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA 𝝚 U+1D75A MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON 𝝛 U+1D75B MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA 𝝜 U+1D75C MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA 𝝝 U+1D75D MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA 𝝞 U+1D75E MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA 𝝟 U+1D75F MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA 𝝠 U+1D760 MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA 𝝡 U+1D761 MATHEMATICAL SANS-SERIF BOLD CAPITAL MU 𝝢 U+1D762 MATHEMATICAL SANS-SERIF BOLD CAPITAL NU 𝝣 U+1D763 MATHEMATICAL SANS-SERIF BOLD CAPITAL XI 𝝤 U+1D764 MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON 𝝥 U+1D765 MATHEMATICAL SANS-SERIF BOLD CAPITAL PI 𝝦 U+1D766 MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO 𝝧 U+1D767 MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL 𝝨 U+1D768 MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA 𝝩 U+1D769 MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU 𝝪 U+1D76A MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON 𝝫 U+1D76B MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI 𝝬 U+1D76C MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI 𝝭 U+1D76D MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI 𝝮 U+1D76E MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA 𝞐 U+1D790 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA 𝞑 U+1D791 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA 𝞒 U+1D792 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA 𝞓 U+1D793 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA 𝞔 U+1D794 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON 𝞕 U+1D795 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA 𝞖 U+1D796 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA 𝞗 U+1D797 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA 𝞘 U+1D798 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA 𝞙 U+1D799 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA 𝞚 U+1D79A MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA 𝞛 U+1D79B MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU 𝞜 U+1D79C MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU 𝞝 U+1D79D MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI 𝞞 U+1D79E MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON 𝞟 U+1D79F MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI 𝞠 U+1D7A0 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO 𝞡 U+1D7A1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL 𝞢 U+1D7A2 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA 𝞣 U+1D7A3 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU 𝞤 U+1D7A4 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON 𝞥 U+1D7A5 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI 𝞦 U+1D7A6 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI 𝞧 U+1D7A7 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI 𝞨 U+1D7A8 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA 𝟊 U+1D7CA MATHEMATICAL BOLD CAPITAL DIGAMMA 𞤀 U+1E900 ADLAM CAPITAL LETTER ALIF 𞤁 U+1E901 ADLAM CAPITAL LETTER DAALI 𞤂 U+1E902 ADLAM CAPITAL LETTER LAAM 𞤃 U+1E903 ADLAM CAPITAL LETTER MIIM 𞤄 U+1E904 ADLAM CAPITAL LETTER BA 𞤅 U+1E905 ADLAM CAPITAL LETTER SINNYIIYHE 𞤆 U+1E906 ADLAM CAPITAL LETTER PE 𞤇 U+1E907 ADLAM CAPITAL LETTER BHE 𞤈 U+1E908 ADLAM CAPITAL LETTER RA 𞤉 U+1E909 ADLAM CAPITAL LETTER E 𞤊 U+1E90A ADLAM CAPITAL LETTER FA 𞤋 U+1E90B ADLAM CAPITAL LETTER I 𞤌 U+1E90C ADLAM CAPITAL LETTER O 𞤍 U+1E90D ADLAM CAPITAL LETTER DHA 𞤎 U+1E90E ADLAM CAPITAL LETTER YHE 𞤏 U+1E90F ADLAM CAPITAL LETTER WAW 𞤐 U+1E910 ADLAM CAPITAL LETTER NUN 𞤑 U+1E911 ADLAM CAPITAL LETTER KAF 𞤒 U+1E912 ADLAM CAPITAL LETTER YA 𞤓 U+1E913 ADLAM CAPITAL LETTER U 𞤔 U+1E914 ADLAM CAPITAL LETTER JIIM 𞤕 U+1E915 ADLAM CAPITAL LETTER CHI 𞤖 U+1E916 ADLAM CAPITAL LETTER HA 𞤗 U+1E917 ADLAM CAPITAL LETTER QAAF 𞤘 U+1E918 ADLAM CAPITAL LETTER GA 𞤙 U+1E919 ADLAM CAPITAL LETTER NYA 𞤚 U+1E91A ADLAM CAPITAL LETTER TU 𞤛 U+1E91B ADLAM CAPITAL LETTER NHA 𞤜 U+1E91C ADLAM CAPITAL LETTER VA 𞤝 U+1E91D ADLAM CAPITAL LETTER KHA 𞤞 U+1E91E ADLAM CAPITAL LETTER GBE 𞤟 U+1E91F ADLAM CAPITAL LETTER ZAL 𞤠 U+1E920 ADLAM CAPITAL LETTER KPO 𞤡 U+1E921 ADLAM CAPITAL LETTER SHA 🄰 U+1F130 SQUARED LATIN CAPITAL LETTER A 🄱 U+1F131 SQUARED LATIN CAPITAL LETTER B 🄲 U+1F132 SQUARED LATIN CAPITAL LETTER C 🄳 U+1F133 SQUARED LATIN CAPITAL LETTER D 🄴 U+1F134 SQUARED LATIN CAPITAL LETTER E 🄵 U+1F135 SQUARED LATIN CAPITAL LETTER F 🄶 U+1F136 SQUARED LATIN CAPITAL LETTER G 🄷 U+1F137 SQUARED LATIN CAPITAL LETTER H 🄸 U+1F138 SQUARED LATIN CAPITAL LETTER I 🄹 U+1F139 SQUARED LATIN CAPITAL LETTER J 🄺 U+1F13A SQUARED LATIN CAPITAL LETTER K 🄻 U+1F13B SQUARED LATIN CAPITAL LETTER L 🄼 U+1F13C SQUARED LATIN CAPITAL LETTER M 🄽 U+1F13D SQUARED LATIN CAPITAL LETTER N 🄾 U+1F13E SQUARED LATIN CAPITAL LETTER O 🄿 U+1F13F SQUARED LATIN CAPITAL LETTER P 🅀 U+1F140 SQUARED LATIN CAPITAL LETTER Q 🅁 U+1F141 SQUARED LATIN CAPITAL LETTER R 🅂 U+1F142 SQUARED LATIN CAPITAL LETTER S 🅃 U+1F143 SQUARED LATIN CAPITAL LETTER T 🅄 U+1F144 SQUARED LATIN CAPITAL LETTER U 🅅 U+1F145 SQUARED LATIN CAPITAL LETTER V 🅆 U+1F146 SQUARED LATIN CAPITAL LETTER W 🅇 U+1F147 SQUARED LATIN CAPITAL LETTER X 🅈 U+1F148 SQUARED LATIN CAPITAL LETTER Y 🅉 U+1F149 SQUARED LATIN CAPITAL LETTER Z 🅐 U+1F150 NEGATIVE CIRCLED LATIN CAPITAL LETTER A 🅑 U+1F151 NEGATIVE CIRCLED LATIN CAPITAL LETTER B 🅒 U+1F152 NEGATIVE CIRCLED LATIN CAPITAL LETTER C 🅓 U+1F153 NEGATIVE CIRCLED LATIN CAPITAL LETTER D 🅔 U+1F154 NEGATIVE CIRCLED LATIN CAPITAL LETTER E 🅕 U+1F155 NEGATIVE CIRCLED LATIN CAPITAL LETTER F 🅖 U+1F156 NEGATIVE CIRCLED LATIN CAPITAL LETTER G 🅗 U+1F157 NEGATIVE CIRCLED LATIN CAPITAL LETTER H 🅘 U+1F158 NEGATIVE CIRCLED LATIN CAPITAL LETTER I 🅙 U+1F159 NEGATIVE CIRCLED LATIN CAPITAL LETTER J 🅚 U+1F15A NEGATIVE CIRCLED LATIN CAPITAL LETTER K 🅛 U+1F15B NEGATIVE CIRCLED LATIN CAPITAL LETTER L 🅜 U+1F15C NEGATIVE CIRCLED LATIN CAPITAL LETTER M 🅝 U+1F15D NEGATIVE CIRCLED LATIN CAPITAL LETTER N 🅞 U+1F15E NEGATIVE CIRCLED LATIN CAPITAL LETTER O 🅟 U+1F15F NEGATIVE CIRCLED LATIN CAPITAL LETTER P 🅠 U+1F160 NEGATIVE CIRCLED LATIN CAPITAL LETTER Q 🅡 U+1F161 NEGATIVE CIRCLED LATIN CAPITAL LETTER R 🅢 U+1F162 NEGATIVE CIRCLED LATIN CAPITAL LETTER S 🅣 U+1F163 NEGATIVE CIRCLED LATIN CAPITAL LETTER T 🅤 U+1F164 NEGATIVE CIRCLED LATIN CAPITAL LETTER U 🅥 U+1F165 NEGATIVE CIRCLED LATIN CAPITAL LETTER V 🅦 U+1F166 NEGATIVE CIRCLED LATIN CAPITAL LETTER W 🅧 U+1F167 NEGATIVE CIRCLED LATIN CAPITAL LETTER X 🅨 U+1F168 NEGATIVE CIRCLED LATIN CAPITAL LETTER Y 🅩 U+1F169 NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 🅰 U+1F170 NEGATIVE SQUARED LATIN CAPITAL LETTER A 🅱 U+1F171 NEGATIVE SQUARED LATIN CAPITAL LETTER B 🅲 U+1F172 NEGATIVE SQUARED LATIN CAPITAL LETTER C 🅳 U+1F173 NEGATIVE SQUARED LATIN CAPITAL LETTER D 🅴 U+1F174 NEGATIVE SQUARED LATIN CAPITAL LETTER E 🅵 U+1F175 NEGATIVE SQUARED LATIN CAPITAL LETTER F 🅶 U+1F176 NEGATIVE SQUARED LATIN CAPITAL LETTER G 🅷 U+1F177 NEGATIVE SQUARED LATIN CAPITAL LETTER H 🅸 U+1F178 NEGATIVE SQUARED LATIN CAPITAL LETTER I 🅹 U+1F179 NEGATIVE SQUARED LATIN CAPITAL LETTER J 🅺 U+1F17A NEGATIVE SQUARED LATIN CAPITAL LETTER K 🅻 U+1F17B NEGATIVE SQUARED LATIN CAPITAL LETTER L 🅼 U+1F17C NEGATIVE SQUARED LATIN CAPITAL LETTER M 🅽 U+1F17D NEGATIVE SQUARED LATIN CAPITAL LETTER N 🅾 U+1F17E NEGATIVE SQUARED LATIN CAPITAL LETTER O 🅿 U+1F17F NEGATIVE SQUARED LATIN CAPITAL LETTER P 🆀 U+1F180 NEGATIVE SQUARED LATIN CAPITAL LETTER Q 🆁 U+1F181 NEGATIVE SQUARED LATIN CAPITAL LETTER R 🆂 U+1F182 NEGATIVE SQUARED LATIN CAPITAL LETTER S 🆃 U+1F183 NEGATIVE SQUARED LATIN CAPITAL LETTER T 🆄 U+1F184 NEGATIVE SQUARED LATIN CAPITAL LETTER U 🆅 U+1F185 NEGATIVE SQUARED LATIN CAPITAL LETTER V 🆆 U+1F186 NEGATIVE SQUARED LATIN CAPITAL LETTER W 🆇 U+1F187 NEGATIVE SQUARED LATIN CAPITAL LETTER X 🆈 U+1F188 NEGATIVE SQUARED LATIN CAPITAL LETTER Y 🆉 U+1F189 NEGATIVE SQUARED LATIN CAPITAL LETTER Z Also See
https://idiosyncratic-ruby.com/72-clear-case-of-unclear-casing.html
Nothing to Disable
Show full content

Ruby's mode of operation can be altered with some --enable-* / --disable-* command-line switches.

By default, all of the following features are activated, except for the frozen strings and the JIT:

Feature CLI Option to Change Description RubyGems --disable-gems RubyGems is the package manager of Ruby, which is required to load 3rd party Ruby libraries¹. RUBYOPT --disable-rubyopt The RUBYOPT ENV variable lets you define default CLI options for Ruby. This switch tells Ruby to ignore RUBYOPT. DidYouMean --disable-did-you-mean² Improves error messages by suggesting auto-corrected method or module names Frozen strings --enable-frozen-string-literal³ Freezes all string literals everywhere. Just-in-time compiler --enable-jit Shortcut to enable is just --jit. New compiler architecture, introduced with Ruby 2.6. See @k0kubun's blog for more details. All of the above --disable-all / --enable-all -

¹ --disable-gems will also prevent did_you_mean from loading, because it is a standard gem
² Variants: --disable-did_you_mean, --disable-did-you_, --disable-did, --disable-d
³ Variants: --enable-frozen_string_literal, --enable-frozen_str, --enable-frozen, …

Also See
https://idiosyncratic-ruby.com/71-nothing-to-disable.html
Nothing to Escape
Show full content

What is your wild guess: How many different ways does Ruby provide for inserting a NULL byte into a double-quoted string?

There are exactly 43 options¹! Here is the list, put together with some ideas from Episode 61: Meta Escape Control:

Directly embedded NULL byte # => "\u0000" "\0" # => "\u0000" "\x00" # => "\u0000" "\x0" # => "\u0000" "\u0000" # => "\u0000" "\u{0000}" # => "\u0000" "\u{000}" # => "\u0000" "\u{00}" # => "\u0000" "\u{0}" # => "\u0000" "\u{00000}" # => "\u0000" "\u{000000}" # => "\u0000" "\000" # => "\u0000" "\00" # => "\u0000" "\C-\0" # => "\u0000" "\C-\x00" # => "\u0000" "\C-\x0" # => "\u0000" "\C-\000" # => "\u0000" "\C-\00" # => "\u0000" "\C-@" # => "\u0000" "\C-\x40" # => "\u0000" "\C-\100" # => "\u0000" "\C-`" # => "\u0000" "\C-\x60" # => "\u0000" "\C-\140" # => "\u0000" "\C- " # => "\u0000" "\C-\s" # => "\u0000" "\C-\x20" # => "\u0000" "\C-\40" # => "\u0000" "\c\0" # => "\u0000" "\c\x00" # => "\u0000" "\c\x0" # => "\u0000" "\c\000" # => "\u0000" "\c\00" # => "\u0000" "\c@" # => "\u0000" "\c\x40" # => "\u0000" "\c\100" # => "\u0000" "\c`" # => "\u0000" "\c\x60" # => "\u0000" "\c\140" # => "\u0000" "\c " # => "\u0000" "\c\s" # => "\u0000" "\c\x20" # => "\u0000" "\c\40" # => "\u0000"

¹ And this is just in the context of double-width strings without interpolation: Another fun NULL byte is 0.chr, as noted by @cremno

Also See
https://idiosyncratic-ruby.com/70-nothing-to-escape.html
Nothing to Compare
Show full content

How does nothing (as in nil, null, or nan) compare to nothing?

Equality Equality == nil 0 0.0 0i 0r NaN¹ nil true false false false false false 0 false true true true true false 0.0 false true true true true false 0i false true true true true false 0r false true true true true false NaN false false false false false false

¹ Get a reference to NaN via Float::NAN or by executing 0.0/0

Take Aways
  • 0 == 0.0 == 0i == 0r
  • NaN != NaN
Fancy Equality === nil 0 0.0 0i 0r NaN nil true false false false false false 0 false true true true true false 0.0 false true true true true false 0i false true true true true false 0r false true true true true false NaN false false false false false false Take Away
  • Same as == for null values
Hash Key Equality .eql? nil 0 0.0 0i 0r NaN nil true false false false false false 0 false true false false false false 0.0 false false true false false false 0i false false false true false false 0r false false false false true false NaN false false false false false false Take Away
  • Different types of 0s do not .eql?
Object Identity .equal? nil 0 0.0 0i 0r NaN nil true false false false false false 0 false true false false false false 0.0 false false true false false false 0i false false false true false false 0r false false false false true false NaN false false false false false true Take Away
  • NaN is the same Object as NaN
Also See
https://idiosyncratic-ruby.com/69-nothing-to-compare.html
Assignments In-Style
Show full content

The introduction of pattern matching in Ruby 2.7 brought us a new style of multi-assigning local variables: The pattern assignment, or, how you could also call it, the assignment in-style.

After you have deactivated the warnings for experimental features, try the following piece of code:

[1, 2, 3, 4] in [first, second, *other]

Think: Put [1, 2, 3, 4] into [first, second, *other]

first # => 1
second # => 2
other # => [3,4]

This is a great addition to the previous two and a half ways of assigning local variables. Let's see some more examples, starting with the most basic one:

0 in a # => nil
a # => 0

When assigning multiple values, be sure to supply exactly the number of expected values:

cities = %w[Berlin Potsdam Magdeburg]
cities in [a,b] # NoMatchingPatternError
cities in [x,y,z]
x #=> Berlin
y #=> Potsdam
z #=> Magdeburg

If your array is of unknown length, use an asterisk, like in the introductory example.

Pattern assignments also have type checks built in:

cities = %w[Berlin Potsdam Magdeburg]
cities in [Integer => c_1, *c_other] # NoMatchingPatternError
cities in [String => c_1, *c_other]
c_other # => ["Potsdam", "Magdeburg"]

Which, of course, also work for single assignments:

0 in Float => a # NoMatchingPatternError
0 in Integer => a

Since hashes are also supported, we can finally have JavaScript-like object destructuring¹:

{
  verb: "CREATE",
  endpoint: "/syntax",
  authed: true,
} in { verb:, endpoint: }

verb #=> "CREATE"
endpoint #=> "/syntax"

¹ Differently from arrays, there is no need to specify all hash keys of the given hash object

Also See
https://idiosyncratic-ruby.com/68-assignments-in-style.html
Warning: The Experiment
Show full content

Ruby's Warning module learned some new tricks in Ruby 2.7:

Support for muting different categories of compile warnings has been introduced. This is a mechanism on top of the warning level reflected by the $VERBOSE variable.

You can now silence deprecation warnings: These are aspects of the language which will be removed or changed in a future version of Ruby. One example is the infamous: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call. Since Ruby 3.0, deprecation warnings are not shown by default, so you will need to explicitly turn them on.

It is also possible to mute experimental features warnings: These are new features of Ruby, which might not have a stable API yet, like the new pattern matching

Per Ruby
Warning[:experimental] = false
Warning[:deprecated] = true
Per CLI
$ ruby -W:no-experimental
$ ruby -W:deprecated
Per ENV Variable
$ RUBYOPT="-W:no-experimental" ruby
$ RUBYOPT="-W:deprecated" ruby
Also See
https://idiosyncratic-ruby.com/67-warning-the-experiment.html
Ruby has Character
Show full content

Ruby comes with good support for Unicode-related features. Read on if you want to learn more about important Unicode fundamentals and how to use them in Ruby…

…or just watch my talk from RubyConf 2017:
⑩ Unicode Characters You Should Know About as a 👩‍💻

Ruby ♡ Unicode var dataCodepointsAssignment = { "name": "Codepoints", "children": [ { "name": "Reserved", "size": 837775 }, { "name": "Assigned", "children": [ { "name": "Standardized", "size": 138869 }, { "name": "Private Use", "size": 137468 } ] } ] } window.renderDiagram = function(data, domId){ var svg = d3.select("#" + domId), width = +svg.attr("width"), height = +svg.attr("height"); var fader = function(color) { return d3.interpolateRgb(color, "#fff")(0.2); }, color = d3.scaleOrdinal(d3.schemeCategory20.map(fader)), format = d3.format(",d"); var treemap = d3.treemap() .tile(d3.treemapResquarify) .size([width, height]) .round(true) .paddingInner(6); var root = d3.hierarchy(data) .eachBefore(function(d) { d.data.id = (d.parent ? d.parent.data.id + "." : "") + d.data.name; }) .sum(sumBySize) .sort(function(b, a) { return b.height - a.height || b.value - a.value; }); treemap(root); var cell = svg.selectAll("g") .data(root.leaves()) .enter().append("g") .attr("transform", function(d) { return "translate(" + d.x0 + "," + d.y0 + ")"; }); cell.append("rect") .attr("id", function(d) { return d.data.id; }) .attr("width", function(d) { return d.x1 - d.x0; }) .attr("height", function(d) { return d.y1 - d.y0; }) .attr("fill", function(d) { return color(d.parent.data.id); }); cell.append("text") .attr("clip-path", function(d) { return "url(#clip-" + d.data.id + ")"; }) .selectAll("tspan") .data(function(d) { return [d.data.name, d.data.size] }) .enter().append("tspan") .attr("x", 8) .attr("y", function(d, i) { return 30 + i * 30; }) .text(function(d) { return d; }); function sumBySize(d) { return d.size; } } Characters in Unicode

Unicode has come a long way and is now available in version 13.0 (core specification). The standard defines a lot of things related to characters, however, it is not always easy to grasp what a character actually is. Is DŽ a single character or not? What about non-Latin languages?

We will need some more fine-grained concepts to distinguish and talk about characters in Unicode:

  • Codepoint: A base unit to construct characters from. Often this maps directly to a single character. Depending on the encoding, a codepoint might require multiple bytes.
  • Grapheme cluster: Smallest linguistic unit, a user-perceived character, constructed out of one or multiple codepoints.
  • Glyph: The actual rendered shape which represents the grapheme cluster
Codepoints & Encodings

Codepoints are the base unit of Unicode: It is a number mapped to some meaning. Often this resolves to a single character:

"\u{41}" # => "A"
"\u{ABCD}" # => "ꯍ"
"\u{1F6A1}" # => "🚡"

There are 1114112 (in hexadecimal: 0x110000) different codepoints. On byte-level, a codepoint can be represented in different ways, which depends on the encoding used. Popular encodings for Unicode are UTF-8, UTF-16, and UTF-32, which all have different mechanisms of representing codepoints:

Codepoint Decimal Glyph Bytes UTF-8 Bytes UTF-16LE Bytes UTF-32LE U+0041 65 A 41 41 00 41 00 00 00 U+ABCD 43981 EA AF 8D CD AB CD AB 00 00 U+1F6A1 128673 🚡 F0 9F 9A A1 3D D8 A1 DE A1 F6 01 00

Here is an overview, without going into too much detail:

  • UTF-8 uses a dynamic number of bytes: While ASCII characters fit into a single byte, it can use up to 4 bytes for higher codepoints.
  • UTF-16 uses 2 bytes, if possible, but has a 4 byte mechanism to represent higher codepoints.
  • UTF-32 is a direct representation of the codepoint and always uses 4 bytes, no logic is involved. It is also a little lavish, because even the largest codepoint U+10FFFF only uses 21 bit of information. As a consequence the last byte is always 00.

You can visualize and learn about encodings on the command-line with the unibits CLI utility.

The rest of this blog post will not deal with encodings and byte representations, but use codepoints as the smallest unit.

Grapheme Clusters

A user-perceived character might be constructed out of multiple codepoints. There are a lot of enclosing characters (like diacritics) which get combined with the previous character to form a new one:

"Ä" = U+0041 "A" + U+0308 "◌̈"

An example from the Thai language:

"กำ" = U+0E01 "ก" + U+0E33 " ำ"

Emoji are another example of grapheme clusters that require multiple codepoints:

"👨🏻‍🍳"¹ = U+1F468 "👨" + U+1F3FB "🏻" + U+0200D "‍" + U+1F373 "🍳"

Ruby 2.5 introduced a convenient way to iterate through all grapheme clusters:

"abกำcd".grapheme_clusters # => ["a", "b", "กำ", "c", "d"]

There is also /\X/², a regex feature that you can use instead of the default /./ to match for grapheme clusters instead of codepoints:

"abกำcd".scan(/./) # => ["a", "b", "ก", "ำ", "c", "d"]
"abกำcd".scan(/\X/) # => ["a", "b", "กำ", "c", "d"]

¹ Depending on the recentness of your rendering software, this is displayed as a single male cook
² This regex matcher was already introduced in earlier versions of Ruby

Normalization

Sometimes, the Unicode standard defines multiple ways to describe the same (or a very similar) glyph. Let us revisit the example from above: the German letter "Ä", which is a "A" with two dots above. It is defined as codepoint U+00C4. At the same time, there is a mechanism to put two dots above just any letter using the combining codepoint U+0308. Combine it with "A" and you get "Ä" - A different representation, although semantically, it is the same character.

However, sometimes you need one canonical representation of a string. This is why the Unicode consortium came up with a normalization algorithm. It is included in Ruby's standard library and required automatically. There are several types of normalization forms:

Form Description NFC Default. The C stands for composed, it uses the composed format for graphemes (if available). NFD The D stands for decomposed, it uses separate codepoints for such graphemes NFKC Like NFC, but uses compatibility mode, instead of canonical mode NFKD Like NFD, but uses compatibility mode, instead of canonical mode

NFC

"Ä".codepoints.map{ |c| "U+%04X"%c } # => ["U+00C4"]
"Ä".unicode_normalize.codepoints.map{|c| "U+%04X"%c }
# => ["U+00C4"]

"Ä".codepoints.map{ |c| "U+%04X"%c } # => ["U+0041", "U+0308"]
"Ä".unicode_normalize.codepoints.map{ |c| "U+%04X"%c }
# => ["U+00C4"]

"A²".codepoints.map{ |c| "U+%04X"%c } # => ["U+0041", "U+00B2"]
"A²".unicode_normalize.codepoints.map{ |c| "U+%04X"%c }
# =>  ["U+0041", "U+00B2"]

NFD

"Ä".codepoints.map{ |c| "U+%04X"%c } # => ["U+00C4"]
"Ä".unicode_normalize(:nfd).codepoints.map{ |c| "U+%04X"%c }
# => ["U+0041", "U+0308"]

"Ä".codepoints.map{ |c| "U+%04X"%c } # => ["U+0041", "U+0308"]
"Ä".unicode_normalize(:nfd).codepoints.map{ |c| "U+%04X"%c }
# => ["U+0041", "U+0308"]

"A²".codepoints.map{ |c| "U+%04X"%c } # => ["U+0041", "U+00B2"]
"A²".unicode_normalize(:nfd).codepoints.map{ |c| "U+%04X"%c }
# =>  ["U+0041", "U+00B2"]

NFKC

"Ä".codepoints.map{ |c| "U+%04X"%c } # => ["U+00C4"]
"Ä".unicode_normalize(:nfkc).codepoints.map{ |c| "U+%04X"%c }
# => ["U+00C4"]

"Ä".codepoints.map{ |c| "U+%04X"%c } # => ["U+0041", "U+0308"]
"Ä".unicode_normalize(:nfkc).codepoints.map{ |c| "U+%04X"%c }
# => ["U+00C4"]

"A²".codepoints.map{ |c| "U+%04X"%c } # => ["U+0041", "U+00B2"]
"A²".unicode_normalize(:nfkc).codepoints.map{ |c| "U+%04X"%c }
# =>  ["U+0041", "U+0032"]

NFKD

"Ä".codepoints.map{ |c| "U+%04X"%c } # => ["U+00C4"]
"Ä".unicode_normalize(:nfkd).codepoints.map{ |c| "U+%04X"%c }
# => ["U+0041", "U+0308"]

"Ä".codepoints.map{ |c| "U+%04X"%c } # => ["U+0041", "U+0308"]
"Ä".unicode_normalize(:nfkd).codepoints.map{ |c| "U+%04X"%c }
# => ["U+0041", "U+0308"]

"A²".codepoints.map{ |c| "U+%04X"%c } # => ["U+0041", "U+00B2"]
"A²".unicode_normalize(:nfkd).codepoints.map{ |c| "U+%04X"%c }
# =>  ["U+0041", "U+0032"]

See the standard and documentation for more details, including the differences between the normalization forms:

Special Case: Visual Confusable Characters

Even in normalization form, there are characters which look very similar (sometimes even identical):

Codepoints A String A String B Codepoints B U+003F + U+003F ?? U+2047 U+0043 C С U+0421 U+0031 1 l U+006C

The record holder is LATIN SMALL LETTER O which is currently linked to 75 other characters that it could be confused with:

ం ಂ ം ං ० ੦ ૦ ௦ ౦ ೦ ൦ ๐ ໐ ၀ ‎٥‎ ۵ o ℴ 𝐨 𝑜 𝒐 𝓸 𝔬 𝕠 𝖔 𝗈 𝗼 𝘰 𝙤 𝚘 ᴏ ᴑ ꬽ ο 𝛐 𝜊 𝝄 𝝾 𝞸 σ 𝛔 𝜎 𝝈 𝞂 𝞼 ⲟ о ჿ օ ‎ס‎ ‎ه‎ ‎𞸤‎ ‎𞹤‎ ‎𞺄‎ ‎ﻫ‎ ‎ﻬ‎ ﻪ‎ ‎ﻩ‎ ‎ھ‎ ‎ﮬ‎ ‎ﮭ‎ ‎ﮫ‎ ‎ﮪ‎ ‎ہ‎ ‎ﮨ‎ ‎ﮩ‎ ‎ﮧ‎ ‎ﮦ‎ ‎ە‎ ഠ ဝ 𐓪 𑣈 𑣗 𐐬

Detecting confusable characters is not built-in, it is possible with some gem support from unicode-confusable:

require "unicode/confusable"
Unicode::Confusable.confusable? "ℜ𝘂ᖯʏ", "Ruby" # => true
Case-Mapping

Another Unicode topic is converting a word from lowercase to uppercase or vice versa. Up until Ruby 2.3, string methods like #upcase,#capitalize, #downcase, or #swapcase would just not work with non-ASCII characters:

"ä".upcase # => "ä" # Ruby 2.3

This has been fixed and more recent versions of Ruby are able to do this out of the box:

"ä".upcase # => "Ä"

The old, ASCII-only behavior can be achieved by passing the :ascii option:

"ä".upcase(:ascii) # => "ä"

This is already much better than before, however, keep in mind that case-mapping is a locale-dependent operation! Not all languages use the same rules for converting between lower- and uppercase. For example, in most languages, the uppercase version of letter i is I:

"i".upcase # => "I"

However, in Turkic languages, it's the letter İ:

"i".upcase(:turkic) # => "İ"

Although Ruby supports special local case mapping rules, as of Ruby 2.5.1, only :turkic is supported. More options might be supported in the future.

Special Case: Case-Folding

There is another special option that you can pass to the String#downcase method: The :fold symbol. It will turn on case-folding, which should be used instead of the default case-mapping behavior if you are interested in comparing/ordering strings. The case-folding algorithm might produce a different output than the case-mapping one. Fer example, the German letter sharp s should be treated like two normal s letters in comparisons:

"ẞ".downcase # => "ß"
"ẞ".downcase(:fold) # => "ss"

There is another String method in Ruby core which makes use of case-folding: String#casecmp?¹ which compares two strings ignoring their case:

 "A".casecmp? "a" # => true
 "ẞ".casecmp? "ss" # => true

¹ You should pay attention that its sister method String#casecmp only uses ASCII, despite the similar naming.

Regex Unicode Property Matching

Ruby's regex engine supports matching of Unicode characteristics, like a characters general purpose (general category), its script, or in which codepoint range it is defined (block):

"String, with: punctuation.".scan(/\p{P}/) # => [",", ":", "."]

See my previous articles for more details:

Special Case: Emoji Matching

Detecting emoji is especially complicated, because there are multiple mechanisms to build up the final emoji glyph. You can use the unicode-emoji gem to find all kinds of emoji:

require "unicode/emoji"
"😴 🛌🏽 🇵🇹 🤾🏽‍♀️".scan(Unicode::Emoji::REGEX) # => ["😴", "🛌🏽", "🇵🇹", "🤾🏽‍♀️"]
Monospace Display-Width

Sometimes, you might find yourself in a situation where you would like to know the width of a character. But this is not easily possible, because the character width is just not defined! This, of course, leads to problems in fixed-width environments like terminals.

If you don't believe me, here are some wide characters for you to checkout:

Codepoint Glyph Name U+1242B 𒐫 CUNEIFORM NUMERIC SIGN NINE SHAR2 U+12219 𒈙 CUNEIFORM SIGN LUGAL OPPOSING LUGAL U+A9C4 ꧄ JAVANESE PADA MADYA U+2E3B ⸻ THREE-EM DASH U+2031 ‱ PER TEN THOUSAND SIGN

To complicate things further, some Asian characters are marked as ambiguous and get displayed wide or narrow, depending on the software displaying them. The unicode-display_width can help:

require "unicode/display_width"

Unicode::DisplayWidth.of("⚀") # => 1
Unicode::DisplayWidth.of("一") # => 2

# Ambiguous example
Unicode::DisplayWidth.of("·", 1) # => 1
Unicode::DisplayWidth.of("·", 2) # => 2
Unicode Special Codepoints

The last section will put the focus on four types of codepoints that require some attention. This is just a selection, there are many more notable codepoints and a good starting point to dig deeper is the Awesome Codepoints list!

Invalid Codepoints

There are two kinds of codepoints which are invalid. If you have these in your data, the data is invalid and String#valid_encoding? will return false. Both of them are encoding-related:

UTF-16 Surrogates

The four byte mechanism that UTF-16 uses to represent codepoints higher than U+FFFF (= 65 535) needs auxiliary codepoints. These are U+D800..U+DFFF and they are strictly forbidden in UTF-8 and UTF-32.

Too Large Codepoints

Any codepoint above U+10FFFF (= 1 114 111) is not allowed. The theoretical UTF-32 maximum is U+FFFFFFFF (= 4 294 967 295) and four byte UTF-8 could represent codepoints upto U+1FFFFF (= 2 097 151).

Ruby does not let you create these from literals:

"\u{D800}" # => SyntaxError: (irb):52: invalid Unicode codepoint
"\u{110000}" # => SyntaxError: (irb):54: invalid Unicode codepoint (too large)

But, if you really need to…, you can use Array#pack:

[0xD800].pack("U") # => "\xED\xA0\x80"
[0x110000].pack("U") # => "\xF4\x90\x80\x80"

Ruby also includes a useful method that removes all invalid bytes, for example, surrogates:

"a\xED\xA0\x80b" # => "a\xED\xA0\x80b"
"a\xED\xA0\x80b".scrub # => "a���b"
"a\xED\xA0\x80b".scrub("") # => "ab"
Unstandardized Codepoints

Another group of codepoints that require extra care are the unstandardized ones. When you look at the following diagram, you will see that a lot of codepoints actually do not have a meaning assigned by the consortium (yet):

Codepoint Distribution as of Unicode 10 Types of Unstandardized Codepoints
  • Private-Use Codepoints: Meant for custom allocations by anyone. You will find vendor logos here, for example, U+F8FF for the Apple logo "" and U+F200 for the ubuntu logo "". Both may only display correctly on the respective operating system with a proper font). Other uses of the private plane include assigning codepoints to fantasy languages like Tengwar by J.R.R. Tolkien.
  • Non-Characters: A handful of codepoints that will never be assigned. Different than invalid codepoints, they are allowed to be used in your data. But they have no meaning.
  • Reserved Codepoints: Will (or might) be assigned in a later version of Unicode
Type Count Codepoints Ruby Regex Private-Use 137 468¹ U+E000..U+F8FF, U+F0000..U+FFFFD, U+100000..U+10FFFD /\p{private use} Non-Characters 66 U+FDD0..U+FDEF and the last two codepoints of each plane: U+XFFFE, U+XFFFF /\p{nchar}/ Reserved 837 775 (not yet assigned) /\p{unassigned}(?<!\p{nchar})/

¹ Two additional private-use codepoints are U+0091 and U+0092, but they are counted as control characters (see next section)

Control Characters

For historical reasons Unicode includes a set of 65 control codepoints. They were not defined by the Unicode Consortium and a lot of them are not universally standardized. However, some of them are extremely common, such as U+0009, the tab-stop character. It also contains the newline characters U+0010 "\n" and U+0013 "\r"; depending on your operating system, use one or both of them for a newline.

Control characters are divided into the two sections C0, covering U+0000..U+001F, and C1, covering U+0080..U+009F. Furthermore, the delete character U+007F ␡ is also considered to be a control character.

In regexes, you can match for control characters with \p{control} or just \p{cc}.

List of C0 Control Codepoints Codepoint Symbol Ruby Escape Name U+0000 ␀ NUL \0 NULL U+0001 ␁ SOH \u{1} START OF HEADING U+0002 ␂ STX \u{2} START OF TEXT U+0003 ␃ ETX \u{3} END OF TEXT U+0004 ␄ EOT \u{4} END OF TRANSMISSION U+0005 ␅ ENQ \u{5} ENQUIRY U+0006 ␆ ACK \u{6} ACKNOWLEDGE U+0007 ␇ BEL \a ALERT U+0008 ␈ BS \b BACKSPACE U+0009 ␉ HT \t CHARACTER TABULATION U+000A ␊ LF \n LINE FEED U+000B ␋ VT \v LINE TABULATION U+000C ␌ FF \f FORM FEED U+000D ␍ CR \r CARRIAGE RETURN U+000E ␎ SS \u{e} SHIFT OUT U+000F ␏ SI \u{f} SHIFT IN U+0010 ␐ DLE \u{10} DATA LINK ESCAPE U+0011 ␑ DC1 \u{11} DEVICE CONTROL ONE U+0012 ␒ DC2 \u{12} DEVICE CONTROL TWO U+0013 ␓ DC3 \u{13} DEVICE CONTROL THREE U+0014 ␔ DC4 \u{14} DEVICE CONTROL FOUR U+0015 ␕ NAK \u{15} NEGATIVE ACKNOWLEDGE U+0016 ␖ SYN \u{16} SYNCHRONOUS IDLE U+0017 ␗ ETB \u{17} END OF TRANSMISSION BLOCK U+0018 ␘ CAN \u{18} CANCEL U+0019 ␙ EM \u{19} END OF MEDIUM U+001A ␚ SUB \u{1a} SUBSTITUTE U+001B ␛ ESC \e ESCAPE U+001C ␜ FS \u{1c} INFORMATION SEPARATOR FOUR U+001D ␝ GS \u{1d} INFORMATION SEPARATOR THREE U+001E ␞ RS \u{1e} INFORMATION SEPARATOR TWO U+001F ␟ US \u{1f} INFORMATION SEPARATOR ONE


List of C1 Control Codepoints Codepoint Symbol Ruby Escape Name U+0080 PAD \u{80} PADDING CHARACTER U+0081 HOP \u{81} HIGH OCTET PRESET U+0082 BPH \u{82} BREAK PERMITTED HERE U+0083 NBH \u{83} NO BREAK HERE U+0084 IND \u{84} INDEX U+0085 NEL¹ \u{85} NEXT LINE¹ U+0086 SSA \u{86} START OF SELECTED AREA U+0087 ESA \u{87} END OF SELECTED AREA U+0088 HTS \u{88} CHARACTER TABULATION SET U+0089 HTJ \u{89} CHARACTER TABULATION WITH JUSTIFICATION U+008A VTS \u{8a} LINE TABULATION SET U+008B PLD \u{8b} PARTIAL LINE FORWARD U+008C PLU \u{8c} PARTIAL LINE BACKWARD U+008D RI \u{8d} REVERSE LINE FEED U+008E SS2 \u{8e} SINGLE SHIFT TWO U+008F SS3 \u{8f} SINGLE SHIFT THREE U+0090 DCS \u{90} DEVICE CONTROL STRING U+0091 PU1 \u{91} PRIVATE USE ONE U+0092 PU2 \u{92} PRIVATE USE TWO U+0093 STS \u{93} SET TRANSMIT STATE U+0094 CCH \u{94} CANCEL CHARACTER U+0095 MW \u{95} MESSAGE WAITING U+0096 SPA \u{96} START OF GUARDED AREA U+0097 EPA \u{97} END OF GUARDED AREA U+0098 SOS \u{98} START OF STRING U+0099 SGC \u{99} SINGLE GRAPHIC CHARACTER INTRODUCER U+009A SCI \u{9a} SINGLE CHARACTER INTRODUCER U+009B CSI \u{9b} CONTROL SEQUENCE INTRODUCER U+009C ST \u{9c} STRING TERMINATOR U+009D OSC \u{9d} OPERATING SYSTEM COMMAND U+009E PM \u{9e} PRIVACY MESSAGE U+009F APC \u{9f} APPLICATION PROGRAM COMMAND

¹ The NEXT LINE control character was introduced to have an universal codepoint for newlines. This goal was not reached. Still, on some systems (for example, my ubuntu machine), it will actually create a newline!

The characteristics gem lets you check if a codepoint belongs to a specific control group:

Characteristics.create("\u{80}").c0? # => false
Characteristics.create("\u{80}").c1? # => true
Ignorable Codepoints

My last example of special codepoints are the so called ignorable codepoints. Their meaning varies, but most of them are invisible and they are often not treated as a whitespace by Unicode. They are ignorable in the sense that if your Unicode rendering engine does not know how to display it, it should just display nothing. The ignorable property is even given to some ranges of unassigned codepoints¹ (which is usually not done).

You can check for ignorable codepoints using the /\p{default ignorable code point}/ (or its shorthand \p{di}) regex.

For example, the following piece of code is made out of tag characters, which resemble all ASCII characters, but as ignorable characters:

eval "󠁰󠁵󠁴󠁳󠀠󠀧󠁉󠁤󠁩󠁯󠁳󠁹󠁮󠁣󠁲󠁡󠁴󠁩󠁣󠀠󠁕󠁮󠁩󠁣󠁯󠁤󠁥󠀧".codepoints.map{ |c| c - 0xE0000 }.pack("U*")

This program will output Idiosyncratic Unicode

¹ The whole range of E0000..E0FFF is ignorable!

CLI Tools for Codepoint Analysis

I hope that you are now ready to closely inspect your own Unicode data! To help you do so, I made a few command-line tools, I hope you like them:

  • uniscribe for codepoint analysis
  • unibits for encoding analysis, also supports a lot of non-Unicode encodings
  • unicopy for converting & copying codepoints
Also See

character.construction

https://idiosyncratic-ruby.com/66-ruby-has-character.html
Warning: The Module
Show full content

Starting with Ruby 2.5¹ it is possible to customize the behavior of Kernel#warn through the Warning module. Here is how:

def Warning.warn(w)
  # super calls the original behavior, which is printing to $stderr
  super "\e[31;1mRUBY WARNING: \e[22m#{w.sub(/warning: /, '')}\e[0m"
end

# # #
# examples

warn "test"
# => RUBY WARNING: test

{ a: 1, a: 2 }
# => RUBY WARNING: (irb):4: key :a is duplicated and overwritten on line 4

$VERBOSE = true # shows level 2 warnings
def a() end
def a() end
# => RUBY WARNING: (irb):8: method redefined; discarding old a
# => RUBY WARNING: (irb):6: previous definition of a was here

You can unlock some more warning features by using Jeremy Evans' warning gem:

require "warning"

Warning.ignore /duplicated and overwritten/
{ a: 1, a: 2 }
# => nothing

$VERBOSE = true
Warning.ignore :method_redefined
def a() end
def a() end
# => nothing

¹ Although the Warning module existed in Ruby 2.4 already, Kernel#warn did not make use of it yet

Further Reading
https://idiosyncratic-ruby.com/65-warning-the-module.html
What the Regex?
Show full content

Regexes, the go-to-mechanism for string matching, must not only be written, but also need to be applied. This episode acts as a reference with some style advice for working with regular expressions in Ruby. If you are looking for resources on writing the actual regexes, take a look at the link collection at the bottom.

What do you Want to Achieve? 1 - Task: Check if Regex Matches 1a) match?

This is the preferred way to check for a match since Ruby 2.4. It only returns true or false, but does not store any match data to get more performance:

"string".match? /1.3/ # => false
"123".match? /1.3/ # => true
1b) =~

This method is baked into Ruby's syntax, although its return value is rather special: It is the codepoint index in the string where the match occurred or nil otherwise. However, it is a wise choice to only use it for its truthy/falsey value and use the more self-explaining String#index method otherwise. Other than with the previous' match? approach, match data is set accordingly (this is the case with all other ways of matching) - see next section "Find First Occurrence" for ways to do so. Here is the example:

"string" =~ /1.3/ # => false
"123" =~ /1.3/ # => true

The match operator's sibling is !~ which negates the match result:

"string" !~ /1.3/ # => true
"123" !~ /1.3/ # => false

More complicated matching can involve capture groups. Depending on the reference style (named or numbered), the way you can access it differs:

Numbered: $1-$9

The Perlish special variables contain the matches:

"String with 42 things" =~ /(\d+) things/
$1 # => "42"
Named: $~

The match data object contains the matches:

"String with 42 things" =~ /(?<thing_count>\d+) things/
$~[:thing_count] # => "42"

Note that regex matching with named captures can implicitly create local variables. This is extremely confusing and you should rather use the above syntax which is clearer, yet still maintains conciseness.

1c) Case Compare

Regex' === operator is also mapped to matching strings (returns true or false). However, although it should not be used directly¹, it allows you to write very expressive and readable case statements²:

case variable = "string or number"
when /\A\d+\z/
  variable.to_i
when /\A\d+\.\d+\z/
  variable.to_f
else
  variable.to_s
end

¹ The reason: It depends on the order of both operands, regex must be first, which is rather unintuitive. String's === operator has a different semantic of just comparing two strings
² For more general documentation about equalness in Ruby, checkout Episode 55: Struggling Four Equality.

2 - Task: Find Single/First Occurrence 2a) String#[]

A very readable way to to return the match result of the string is:

"String with 42 things"[/\d\d/] # => "42"

You can also use capture groups here:

"String with 42 things"[/\d(\d)/, 1] # => "2"
"String with 42 things"[/(?<first>\d)\d/, :first] # => "4"
2b) =~ + $&

If you prefer the =~ syntax, you can retrieve the matched string with the special variable $&:

"String with 42 things" =~ /\d+/
$& # => "42"
2c) String#rindex

Worth mentioning is the special behavior of String.rindex. It will start the match process on the right side of string and return the first index, where a match is possible:

 "String with 42, sorry with 23 things".rindex /\d+/
 $& # => "3"

Note that it does not match "23", but "3". If you want to match an expression in relation to the end of the string you could use a positive-lookahead in combination with \z:

"String with 42, sorry with 23 things" =~ /\d+(?=\D*\z)/
$& # => "23"
3 - Task: Find All Occurrences 3) String#scan

Your friend is the scan method which returns an array of all results:

"String with 42, sorry with 23 things".scan /\d+/ # => ["42", "23"]
4 - Task: Replace

The usual string replacement tool is gsub (global substitution) which replaces all matching occurrences of the regex. Should you only want to replace the first occurrence, use the sub method instead.

4a) String#gsub with String Argument
"String with 42 things".gsub /\d+/, "23" # => "String with 23 things"

You can use back references in the replacement string.

4b) String#gsub with Block
"String with 42 things".gsub /\d+/ do
  $&.to_i + 1
end # => "String with 43 things"

You can use Perl-style regex globals in the replacement block.

Special Task: Split String Into Array

Splitting a string along a separator is the main way of converting it into a useful array:

array = "String with     42\nthings".split(/\s+/)
# => ["String", "with", "42", "things"]
Special Task: Filter Array of Strings

The Enumerable#grep method allows you to do so:

["String", "with", "42", "things"].grep(/\d/) # => ["42"]

Ther is also Enumerable#grep_v which returns all elements that do not match (think #reject):

["String", "with", "42", "things"].grep_v(/\d/) # => ["String", "with", "things"]
Special Task: Partition String

Ruby's String#partition divides a string into an array consisting of three elements:

parts = "String with 42 things".partition(/\d+/)
parts # => ["String with ", "42", " things"]
  • The string before regex match
  • The regex match
  • The string after the regex match

Note that you can get to the same result using the special pre- and post match variables:

"String with 42 things" =~ /\d+/
parts = [$`, $&, $'] # => ["String with ", "42", " things"]
Regex Resources Also See
https://idiosyncratic-ruby.com/64-what-the-regex.html
idiosyncratic_eval
Show full content

When you get farther upwards the steep hill that is Ruby mastery, you will come across some powerful, yet slightly evil methods: instance_eval and class_eval¹. They allow you to execute code and define methods tied to a specific class, at the same time giving you access to outer scope variables through the Ruby block syntax. Their exact behavior varies, depending on the context they are used in. So what is the difference between all the evals?

¹ Also aliased as module_eval

Eval / Method Definition Comparison

In the following tables, you will find all combinations of defining a method and executing it in a different class context:

Class Scope Definition Method No eval class_eval instance_eval def instance instance class define_method instance instance instance def self. class class class define_singleton_method class class class Class-Class Scope (class << self) Definition Method No eval class_eval instance_eval def class class class-class define_method class class class def self. class-class class-class class-class define_singleton_method class-class class-class class-class Observations

While class_eval behaves exactly as if it was in no eval-context at all, instance_eval features a notable difference: def inside instance_eval will define methods one class-level higher. So when instance_eval is executed on instances, def will create instance methods instead of singleton methods. And when it is run on classes, def will create class methods instead of instance methods.

Another difference is that while class_eval is defined on Module, instance_eval lives in BasicObject allowing you to use it on any object, not only modules and classes. However, there is a simple way to use class_eval for instances, too. You can explicitly use the object's singleton class (class << self), which is a module:

o = Object.new # => #<Object:0x000055b6fdabf1f8>
o.singleton_class.class_eval do
  def m
    p self
  end
end

o.m # => #<Object:0x000055b6fdabf1f8>
Best Practice

Overall, the behavior of instance_eval is rather confusing and my recommendation is to avoid it and always use class_eval. If you do not need closure access, consider using no eval at all.

Reference / Examples: Class-Level Scope

For reference, what follows is a list of snippets illustrating each eval-define combination.

Class / def

Defines method on instance-level

class C
  def m
    p self
  end
end

C.new.m # => #<C:0x0000556efd3eb1a8>
Class / class_eval + def

Defines method on instance-level

class C
  class_eval{
    def m
      p self
    end
  }
end

C.new.m # => #<C:0x0000556efd3eb1a8>
Class / instance_eval + def

Defines method on class-level

class C
  instance_eval{
    def m
      p self
    end
  }
end

C.m # => C
Class / define_method

Defines method on instance-level

class C
  define_method(:m){
    p self
  }
end

C.new.m # => #<C:0x0000556efd3eb1a8>
Class / class_eval + define_method

Defines method on instance-level

class C
  class_eval{
    define_method(:m){
      p self
    }
  }
end

C.new.m # => #<C:0x0000556efd3eb1a8>
Class / instance_eval + define_method

Defines method on instance-level

class C
  instance_eval{
    define_method(:m){
      p self
    }
  }
end

C.new.m # => #<C:0x0000556efd3eb1a8>
Class / def self.

Defines method on class-level

class C
  def self.m
    p self
  end
end

C.m # => C
Class / class_eval + def self.

Defines method on class-level

class C
  class_eval{
    def self.m
      p self
    end
  }
end

C.m # => C
Class / instance_eval + def self.

Defines method on class-level

class C
  instance_eval{
    def self.m
      p self
    end
  }
end

C.m # => C
Class / define_singleton_method

Defines method on class-level

class C
  define_singleton_method(:m){
    p self
  }
end

C.m # => C
Class / class_eval + define_singleton_method

Defines method on class-level

class C
  class_eval{
    define_singleton_method(:m){
      p self
    }
  }
end

C.m # => C
Class / instance_eval + define_singleton_method

Defines method on class-level

class C
  instance_eval{
    define_singleton_method(:m){
      p self
    }
  }
end

C.m # => C
Reference / Examples: Class-Class-Level Scope Class-Class / def

Defines method on class-level

class C
  class << self
    def m
      p self
    end
  end
end

C.m # => C
Class-Class / class_eval + def

Defines method on class-level

class C
  class << self
    class_eval{
      def m
        p self
      end
    }
  end
end

C.m # => C
Class-Class / instance_eval + def

Defines method on class-class-level

class C
  class << self
    instance_eval{
      def m
        p self
      end
    }
  end
end

C.singleton_class.m #=> #<Class:C>
Class-Class / define_method

Defines method on class-level

class C
  class << self
    define_method(:m){
      p self
    }
  end
end

C.m # => C
Class-Class / class_eval + define_method

Defines method on class-level

class C
  class << self
    class_eval{
      define_method(:m){
        p self
      }
    }
  end
end

C.m # => C
Class-Class / instance_eval + define_method

Defines method on class-level

class C
  class << self
    instance_eval{
      define_method(:m){
        p self
      }
    }
  end
end

C.m # => C
Class-Class / def self.

Defines method on class-class-level

class C
  class << self
    def self.m
      p self
    end
  end
end

C.singleton_class.m # => C
Class-Class / class_eval + def self.

Defines method on class-class-level

class C
  class << self
    class_eval{
      def self.m
        p self
      end
    end
  }
end

C.singleton_class.m #=> #<Class:C>
Class-Class / instance_eval + def self.

Defines method on class-class-level

class C
  class << self
    instance_eval{
      def self.m
        p self
      end
    }
  end
end

C.singleton_class.m #=> #<Class:C>
Class-Class / define_singleton_method

Defines method on class-class-level

class C
  class << self
    define_singleton_method(:m){
      p self
    }
  end
end

C.singleton_class.m # => C
Class-Class / class_eval + define_singleton_method

Defines method on class-class-level

class C
  class << self
    class_eval{
      define_singleton_method(:m){
        p self
      }
    }
  end
end

C.singleton_class.m #=> #<Class:C>
Class-Class / instance_eval + define_singleton_method

Defines method on class-class-level

class C
  class << self
    instance_eval{
      define_singleton_method(:m){
        p self
      }
    }
  end
end

C.singleton_class.m #=> #<Class:C>
Also See
https://idiosyncratic-ruby.com/63-instance-eval.html
Less Feature-Rich, More Fun
Show full content

Ruby was created in 1993 and has come a long way. The preferred style of coding has changed quite a lot and solid best practice has emerged (though, as always, one size does not fit all). At the same time, Ruby's tool support could be better, the language is still too complex. Maybe, the time has come to remove some features from Ruby.

Which is always hard, because it will break existing code.¹ But it can still be worth it:

  • People new to Ruby start with learning the right thing, instead of having to learnthe best practice later ("avoid for loops")
  • The language gets simpler, which means: better tool support!

What follows are some opinionated examples of what could be removed from Ruby without breaking too much code (hopefully).

Ten Ruby Features which Could Be Removed Without Too Much Trouble (More or Less) 1. for and in Keywords

For loops are rarely used in favor of semantically almost similar alternatives like Array#each or Integer#times. They are even a little slower than calling each directly. Also see: The Evils of the For Loop

2. ? Character Literals

The question mark allows you to create single-letter strings. This was indeed useful when writing code that should work for both, Ruby 1.8 and Ruby 1.9:

"Idiosyncratic"[0] == ?I

While the return value in Ruby 1.9+ is "I" on both sides, in Ruby 1.8 it was 73 on both sides, so it would still return true. Support for Ruby 1.8 ended in 2013, so there is no benefit of the ? syntax anymore.

3. @@ Class Hierarchy Variables

You should not use class variables! They will confuse almost every newcomer and should be removed from the language. Some alternatives:

To be fair: Removing class variables would break more code than any of the other suggestions on this page. Too big to remove.

4. then Keyword

If statements usually separate the condition from the body using a newline or ;:

if true
  p 42
else
  p 43
end

However, you can optionally use the then keyword:

if true then
  p 42
else
  p 43
end

There exist two case where then makes sense. One is one-liners:

if true then p 42 else p 43 end

But even they look better with the ternary operator (?:)

p true ? 42 : 43

The other is single-line when statements:

case
when true  then 42
when false then 43
end

Going with ;, it would still be possible to write single-line whens without then:

case
when true;  42
when false; 43
end

All in all: then is superfluous.

5. TRUE, FALSE, NIL constants

There are keywords for true, false, and nil. They all have a predefined associated constant, which can be redefined: TRUE, FALSE, NIL = nil, true, false. There is no reason to keep them around.

Update: Removed in Ruby 3.0

6. Implicit Creation of Local Variables via Regex Matching

Accessing the last regex match: There is no need for =~ to be able to create local variables, but only if both operands are in the right order. Using $~[:group_name] instead is more explicit and still very concise.

7. and, or, not Keywords

The boolean operators with lower precedence are nice in some situations, for example, using or to raise an exception when an assignment value is nil:

a = dangerous_operation or raise "dangerous operation failed"

But is it a strong enough reason to keep the keywords in the language? They already have created lots of confusion for Ruby learners.

8. Secret CLI Options like -s and -x

When is the last time you used $ ruby -s or $ ruby -x?

9. Symbols

Semantically, symbols and frozen strings are very similar. Symbols should become a shorthand syntax for frozen strings!

10. Flip Flops

This blog covers a lot of Ruby's lesser-known features. It does not even have an episode about Ruby's Flip Flops.

¹ Maybe, we can have strict/quirks modes via a magic comments? More complexity, though.

https://idiosyncratic-ruby.com/62-less-features-more-fun.html
Meta Escape Control
Show full content

Double-quoted strings can not only be used with interpolation, #{}, they also support various escape sequences, which are initiated with \. Escape sequences allow you to embed raw byte and codepoint values. Furthermore, there are shortcuts for common formatting and control characters.

Byte Sequences

There are two basic ways in which you can specify raw bytes to embed: \x00 (hexadecimal) or \000 (octal):

"\x20" # => " " # space
"\xab" # => "\xAB" # byte value 171
"\033" # => "\e" # escape
"\0"   # => "\u0000" # null byte
Meta Escapes

There is a meta escape syntax "\M-x" with x being a byte value. If the byte is below 128 (\x80), it will add 128, otherwise it will return the same value. Differently put: It will return the same byte value with 8th bit set. The x value can be escaped again:

"A".unpack("C")    # => [65]
"\M-A".unpack("C") # => [193]
"\M-\x01" # => "\x81"
"\M-\x81" # => "\x81"
Control Escapes

Another legacy syntax is the control escape syntax: "\C-x" (or "\cx") with x being a byte value. It will return the value of the 5 least significant bits, so the value will also between 0 and 31. The x value can be escaped again, or combined with meta escapes:

"\C-\x01" # => "\u0001"
"\C-!"    # => "\u0001"
"\C-A"    # => "\u0001"
"\M-\C-A" # => "\x81"
"\C-\M-A" # => "\x81"
Unicode Codepoints

Unicode characters are represented by codepoint values. If you know the numerical codepoint value, you can embed it in a double-quoted string using \u. You must use exactly 4 digits of the hexadecimal representation of the value, but casing is not relevant:

"\u0020" # => " " # space
"\u00A0" # => " " # no-break space
"\u203d" # => "‽" # interrobang

The \u syntax supports a more explicit {} flavor:

"\u{9}" # => "\t" # tab
"\u{2602}" # => "☂" # umbrella

The \u{} syntax is required if you want to display codepoints which need more than four hexadecimal digest, for example, U+1F6A1 AERIAL TRAMWAY:

"\u{1F6A1}" # "🚡"

It also allows you to specify multiple characters at once:

"\u{49 64 69 6f 73 79 6e 63 72 e4 74 69 63 20 52 75 62 79}"
# => "Idiosyncrätic Ruby"
Control and Formatting Characters

Some byte values used for common control/formatting characters have escape sequences:

Escape Byte Value Description \a 7 terminal bell \b 8 backspace \t 9 tab \n 10 newline \v 11 vertical tab \f 12 form feed \r 13 carriage return \e 27 start escape sequence \s 32 (space)
https://idiosyncratic-ruby.com/61-meta-escape-control.html
Escape Back Referencing
Show full content

Ruby has more than one way to access additional information about the most recent regex match, like captured groups. One way is using the special variables $`, $&, $', $1 - $9, $+, and also in the MatchData object $~. They become available after using a method that matched a regex, or when the method supports a block, they are already available in the block.

However, there is also a special string processing supported by the string replacement methods String#gsub and String#sub. The replacement string (second parameter) can contain back references, which behave similarly to their corresponding special variable:

"Idiosyncratic Ruby".sub(/(\w+) (\w+)/, '\2 \1') # => "Ruby Idiosyncratic"
Special Regex Variables & Back References Perlish Back-Ref Effect Example $& '\&', '\0'¹ Match "abc".gsub(/.*/, '\&\&') # => "abcabc" $` '\`' Pre Match "abc".gsub(/b/, '\`') # => "aac" $' '\\\'' Post Match "abc".gsub(/b/, '\\\'') # => "acc" $1² '\1' 1st Capture "abc".gsub(/(a)b(c)/, '\1') # => "a" $+ '\+' Last Capture "abc".gsub(/(a)b(c)/, '\+') # => "c" $~[:name] '\k<name>' Named Capture "abc".gsub(/(?<name>a)bc/, '\k<name>') # => "a" Escaping

Ruby is absolutely confusing when it comes to how to escape back references. You have to use one or two backspaces when using single quoted strings. You have to use two (or sometimes three) backspaces when using double quoted strings. Escaping \' needs special attention³:

X '\X' '\\X' '\\\X' "\X" "\\X" "\\\X" "\\\\X" & Match Match "\\&" "&" Match Match "\\&" ` Pre-Match Pre-Match "\\`" "`" Pre-Match Pre-Match "\\`" ' "'" - Post-Match "'" Post-Match Post-Match "\\'" 0¹ Match Match "\\0" "\u0000" Match "\\\u0000" "\\0" 1² 1st Capture 1st Capture "\\1" "\u0001" 1st Capture "\\\u0001" "\\1" + Last Capture Last Capture "\\+" "+" Last Capture Last Capture "\\+" k<name> Named Capture Named Capture "\\k<name>" "k<name>" Named Capture Named Capture "\\k<name>"

¹ Although the global variable $0 is not related to regex matching, \0 is a valid back reference.
² Same for 2-9: Nth Capture
³ If you want to replace ' with \' (backspace quote, no back-ref), the replacement string is: '\\\\\''

https://idiosyncratic-ruby.com/60-escape-back-referencing.html
Big Data Without End
Show full content

Ruby's big DATA constant does more than you might expect!

Everything after the __END__ keyword (at the beginning of the line) is not interpreted as Ruby, but can be retrieved with the big¹ DATA constant.² This is an example big-data.rb script:

p DATA.read
__END__
big data

Big DATA is a File object, which you can read. The example will output "big data". An example of real-world usage is inline templating within the sinatra web framework

¹ Do not confuse with the small Data class, which is a CRuby implementation detail
² Big DATA is not defined, if you have no __END__. Furthermore, it is not available if you did not execute the script directly, but loaded or required it.
³ Actually, not really

Is the Data Section Enough?

Wait a minute! Big DATA is a File object? What file exactly?

p DATA.path
p DATA.lineno
__END__
big data

The output will be "big-data.rb" and 3. The big DATA object points to the source file itself at a specific position! And look, we can alter this:

DATA.rewind
puts DATA.gets("\n__END__")[0..-9]
__END__
big data

It will now read the source code of itself:

DATA.rewind
puts DATA.gets("\n__END__")[0..-9]
Also See
https://idiosyncratic-ruby.com/59-big-data-without-end.html
Magic Instructions
Show full content

Ruby supports magic comments (interpreter instructions) at the top of the source file, mostly known for setting a source files' Encoding. This is the most common use case, but there is more you can do.

Source File Encoding

The default encoding of string literals in a Ruby file is UTF-8:

p "".encoding # => #<Encoding:UTF-8>

You can change it like this

# encoding: big5
p "".encoding # => #<Encoding:Big5>

The magic comment parser is pretty liberal and supports various syntaxes:

# Characters before encoding: ascii or after it will not affect its functionality
p "".encoding # => #<Encoding:US-ASCII>¹

You can mix casing in the encoding name:

# encOding: bInary
p "".encoding # => #<Encoding:ASCII-8BIT>¹

The word coding² is allowed instead of encoding:

# -*- coding: utf-8 -*-
p "".encoding # => #<Encoding:UTF-8>

However, the source encoding must be ASCII compatible:

# encoding: utf-16le
p "".encoding
# UTF-16LE is not ASCII compatible (ArgumentError)

It will also work if you have a UNIX Shebang in the first line:

#!/usr/bin/env ruby
# encoding: windows-1250
p "".encoding # => #<Encoding:Windows-1250>

The encoding can be any you could pass to Encoding.find:

Encoding.name_list # => ["ASCII-8BIT", "UTF-8", "US-ASCII", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE", "UTF-16", "UTF-32", "UTF8-MAC", "EUC-JP", "Windows-31J", "Big5", "Big5-HKSCS", "Big5-UAO", "CESU-8", "CP949", "Emacs-Mule", "EUC-KR", "EUC-TW", "GB18030", "GBK", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "ISO-8859-16", "KOI8-R", "KOI8-U", "Shift_JIS", "Windows-1250", "Windows-1251", "Windows-1252", "Windows-1253", "Windows-1254", "Windows-1257", "BINARY", "IBM437", "CP437", "IBM720", "CP720", "IBM737", "CP737", "IBM775", "CP775", "CP850", "IBM850", "IBM852", "CP852", "IBM855", "CP855", "IBM857", "CP857", "IBM860", "CP860", "IBM861", "CP861", "IBM862", "CP862", "IBM863", "CP863", "IBM864", "CP864", "IBM865", "CP865", "IBM866", "CP866", "IBM869", "CP869", "Windows-1258", "CP1258", "GB1988", "macCentEuro", "macCroatian", "macCyrillic", "macGreek", "macIceland", "macRoman", "macRomania", "macThai", "macTurkish", "macUkraine", "CP950", "Big5-HKSCS:2008", "CP951", "IBM037", "ebcdic-cp-us", "stateless-ISO-2022-JP", "eucJP", "eucJP-ms", "euc-jp-ms", "CP51932", "EUC-JIS-2004", "EUC-JISX0213", "eucKR", "eucTW", "GB2312", "EUC-CN", "eucCN", "GB12345", "CP936", "ISO-2022-JP", "ISO2022-JP", "ISO-2022-JP-2", "ISO2022-JP2", "CP50220", "CP50221", "ISO8859-1", "ISO8859-2", "ISO8859-3", "ISO8859-4", "ISO8859-5", "ISO8859-6", "Windows-1256", "CP1256", "ISO8859-7", "ISO8859-8", "Windows-1255", "CP1255", "ISO8859-9", "ISO8859-10", "ISO8859-11", "TIS-620", "Windows-874", "CP874", "ISO8859-13", "ISO8859-14", "ISO8859-15", "ISO8859-16", "CP878", "MacJapanese", "MacJapan", "ASCII", "ANSI_X3.4-1968", "646", "UTF-7", "CP65000", "CP65001", "UTF-8-MAC", "UTF-8-HFS", "UCS-2BE", "UCS-4BE", "UCS-4LE", "CP932", "csWindows31J", "SJIS", "PCK", "CP1250", "CP1251", "CP1252", "CP1253", "CP1254", "CP1257", "UTF8-DoCoMo", "SJIS-DoCoMo", "UTF8-KDDI", "SJIS-KDDI", "ISO-2022-JP-KDDI", "stateless-ISO-2022-JP-KDDI", "UTF8-SoftBank", "SJIS-SoftBank", "locale", "external", "filesystem", "internal"]

¹ See US-ASCII-8BIT for an explanation of the difference between the both ASCII encodings
² Emacs style

More Comments, More Magic

Besides encoding instructions there are two additional magic comments. Note that when you have multiple comments, you must put the encoding comment first or it will not work!

Frozen Strings

Ruby 2.3 introduced the ability to make all string literals frozen by default:

# encoding: stateless-iso-2022-jp-kddi
# frozen_string_literal: true
p "".frozen? # => true
p "".encoding # => #<Encoding:stateless-ISO-2022-JP-KDDI>

You can also freeze string literals using the --enable-frozen command line option, but the magic comment will always overwrite the behavior of the source file in question.

Indentation Warnings
# warn_indent: true
def method_name
  end

# warning: mismatched indentations at 'end' with 'def' at 2

This warning also appears when running Ruby with the -w command-line option, but the magic comment will always overwrite the behavior of the source file in question.

Auto-Freeze Constants

Introduced in Ruby 3.0

# sharable_constant_value: literal
X = [{foo: []}]
# => same as [{foo: [].freeze}.freeze].freeze

Part of Ruby 3.0 Ractor, this magic comment helps you to create frozen, sharable objects. It can take one these four values:

  • none - No special constant assignments
  • literal - Freezes literals assigned to constants
  • experimental_everywhere - Freezes everything assigned to constants
  • experimental_copy - Freezes everything assigned to constants, "dynamic" objects will be copied so the originally referenced object will not get frozen

Differently from the other comments, it can be placed anywhere in the file. It will affect all subsequent statements within the same module scope.

Documentation.

Also See
https://idiosyncratic-ruby.com/58-magic-instructions.html
What the Time?
Show full content

%a %A %b %B %c %C %d %D %e %F %g %G %h %H %I %j %k %l %L %m %M %n %N %p %P %Q %r %R %s %S %t %T %u %U %v %V %w %W %x %X %y %Y %z %Z %+ %% - _ 0 ^ # :

Date and time formatting is traditionally done with strftime. Not any different in Ruby, which includes a public domain based strftime implementation accessible via Time#strftime. Ruby would not be Ruby if it would not add some confusion: There is a second implementation included in the standard library which is used by Date#strftime and DateTime#strftime. It behaves similarly in most cases, but also differs in some nuances (for example, additional formatting directives like %Q are supported).

Usage

strftime() is called on time objects to convert them to strings:

Time.utc(2016, 05, 24, 15).strftime("%a %b %e %T %Y")
# => "Tue May 24 15:00:00 2016"

Similar to format strings or String.unpack() you have to pass a template string which contains formatting directives (like %Y for year). Many of the directives are combined directives (like %T for time), constructed from multiple base directives ("atoms"). The following tables give an overview, scroll further down for an explanation of every directive.

Atoms Point of Time Atoms (Example) Year %Y (2016)
%C (20)
%y (16) Month %m (05) Day %d (31)
%j (365) Hour/Daytime %H (23)
%I (11)
%P (am) Minute %M (59) Second %S (59) Fraction %N (479254327) English Name Atoms (Example) English Month Name %B (January)
%b (Jan) English Weekday Name %A (Monday)
%a (Mon) Week Based Point of Time Atoms (Example) Year (by Week) %G (2016)
%g (16) Week %W (52)
%U (52)
%V (52) Weekday %u (3)
%w (3) Other Name Atoms (Example) Time Zone %z (+0000)
%Z (UTC) Unix Timestamp %s (1464188400) Unix Timestamp (Milliseconds)¹ %Q (1464188400)

¹ Only available in Date/DateTime's strftime() implementation

Formatting Flags and Padding

Time formatting directives support some basic padding and formatting options via flags that appear between % and the directive type. Padding is the minimum length of the output, if the value is smaller, the remaining space will be filled with spaces or zeros.

Flag Description - Do not apply default padding _ Use spaces for padding 0 Use zeros for padding ^ Upcase # Swap case

Examples:

time = Time.utc(2016, 05, 25, 15) #=> 2016-05-25 15:00:00 UTC

time.strftime("%P") # => "pm"
time.strftime("%^P") # => "PM"
time.strftime("%#P") # => "PM"
time.strftime("%10P") # =>  "        pm"
time.strftime("%010P") # => "00000000pm"
time.strftime("%_10P") # =>  "        pm"

time.strftime("%m") # => "05"
time.strftime("%-m") # => "5"
time.strftime("%10m") #=> "0000000005"
time.strftime("%010m") #=> "0000000005"
time.strftime("%_10m") #=> "         5"
Combined Directives and Aliases Directive Alias/From Atoms %c %a %b %e %T %Y %D %m/%d/%y %e %_d %F %Y-%m-%d %h %b %k %_H %l %_I %L %3N %n "\n" %p %^P %r %I:%M:%S %p %R %H:%M %t "\t" %T %H:%M:%S %v Time#strftime: %e-%^b-%4Y
Date#strftime: %e-%b-%4Y %x %m/%d/%y %X %H:%M:%S %+¹ %a %b %e %H:%M:%S %Z %Y

¹ Only available in Date/DateTime's strftime() implementation

Years Directives %Y | Year, with Century

Will display the time's year with a default padding of 4:

Time.utc(2016).strftime("%Y") # => "2016"
Time.utc(20000).strftime("%Y") # => "20000"
Time.utc(2).strftime("%Y") # => "0002"
Time.utc(2).strftime("%-Y") # => "2"
%y | Year, without Century

Will display the time's year modulo 100 with a default padding of 2:

Time.utc(2016).strftime("%y") # => "16"
Time.utc(20000).strftime("%y") # => "00"
Time.utc(2).strftime("%y") # => "02"
Time.utc(2).strftime("%-y") # => "2"
%C | Century

Will display the time's year divided by 100 with a default padding of 2:

Time.utc(2016).strftime("%C") # => "20"
Time.utc(20000).strftime("%C") # => "000"
Time.utc(2).strftime("%C") # => "00"
Time.utc(2).strftime("%-C") # => "0"
%G | Year (Week based), with Century

Returns the year based on which year the time's week belongs to:

Time.utc(2014, 12, 29).strftime("%G") # => "2015"
Time.utc(2017, 1, 1).strftime("%G") #=> "2016"
%g | Year (Week based), without Century

Returns the year based on which year the time's week belongs to:

Time.utc(2014, 12, 29).strftime("%g") # => "15"
Time.utc(2017, 1, 1).strftime("%g") #=> "16"
Months Directives %m | Month as Number

Number of month, with a default padding of 2:

Time.utc(2016, 5).strftime("%m") # => "05"
Time.utc(2016, 5).strftime("%-m") # => "5"
%B | Month Name

Locale-independent (English) month name:

Time.utc(2016, 1).strftime("%B") # => "January"
%b, %h | Month Name (Abbreviated)

Locale-independent (English) three-letter month name:

Time.utc(2016, 1).strftime("%b") # => "Jan"
Time.utc(2016, 1).strftime("%h") # => "Jan"
Weeks Directives

See ISO 8601 for an explanation of week number construction.

%U | Week Number (Sunday Starts Week) | 00..53

Considers Sunday the first day of the week. Will return 00 if week belongs to last year:

Time.utc(2015, 1, 1).strftime("%U") # => "00" # Thursday
Time.utc(2016, 1, 1).strftime("%U") # => "00" # Friday
Time.utc(2017, 1, 1).strftime("%U") # => "01" # Sunday
%V | Week Number (Week Based Year) | 01..53

Considers Sunday the first day of the week. Will return last years week number if week belongs to last year:

Time.utc(2015, 1, 1).strftime("%V") # => "01" # Thursday
Time.utc(2016, 1, 1).strftime("%V") # => "53" # Friday
Time.utc(2017, 1, 1).strftime("%V") # => "52" # Sunday
%W | Week Number (Monday Starts Weeks) | 00..53

Considers Sunday the last day of the week. Will return 00 if week belongs to last year:

Time.utc(2015, 1, 1).strftime("%W") # => "00" # Thursday
Time.utc(2016, 1, 1).strftime("%W") # => "00" # Friday
Time.utc(2017, 1, 1).strftime("%W") # => "00" # Sunday
Days Directives %j | Day of Year | 001..366

Which day of the year with a default padding of 3:

Time.utc(2016, 5, 24).strftime("%j") # => "145"
Time.utc(2016, 1, 1).strftime("%j") # => "001"
Time.utc(2016, 1, 1).strftime("%-j") # => "1"
%d | Day of Month | 01..31

Which day of the month with a default (zero) padding of 2:

Time.utc(2016, 5, 24).strftime("%d") # => "24"
Time.utc(2016, 1, 1).strftime("%d") # => "01"
Time.utc(2016, 1, 1).strftime("%-d") # => "1"
%e | Day of Month (Space Padded) | 01..31

Which day of the month with a default (space) padding of 2:

Time.utc(2016, 5, 24).strftime("%e") # => "24"
Time.utc(2016, 1, 1).strftime("%e") # => " 1"
Time.utc(2016, 1, 1).strftime("%-e") # => "1"
%u | Weekday as Number (Monday Starts Week) | 1..7

Number of day in the week, value of Sunday is 7:

Time.utc(2016, 5, 22).strftime("%u") # => 7 # Sunday
Time.utc(2016, 5, 23).strftime("%u") # => 1 # Monday
Time.utc(2016, 5, 24).strftime("%u") # => 2 # Tuesday
Time.utc(2016, 5, 25).strftime("%u") # => 3 # Wednesday
Time.utc(2016, 5, 26).strftime("%u") # => 4 # Thursday
Time.utc(2016, 5, 27).strftime("%u") # => 5 # Friday
Time.utc(2016, 5, 28).strftime("%u") # => 6 # Saturday
%w | Weekday as Number (Sunday Starts Week) | 0..6

Number of day in the week, value of Sunday is 0:

Time.utc(2016, 5, 22).strftime("%u") # => 0 # Sunday
Time.utc(2016, 5, 23).strftime("%u") # => 1 # Monday
Time.utc(2016, 5, 24).strftime("%u") # => 2 # Tuesday
Time.utc(2016, 5, 25).strftime("%u") # => 3 # Wednesday
Time.utc(2016, 5, 26).strftime("%u") # => 4 # Thursday
Time.utc(2016, 5, 27).strftime("%u") # => 5 # Friday
Time.utc(2016, 5, 28).strftime("%u") # => 6 # Saturday
%A | Weekday Name

Locale-independent (English) name of weekday:

Time.utc(2016, 5, 22).strftime("%A") # => "Sunday"
Time.utc(2016, 5, 23).strftime("%A") # => "Monday"
Time.utc(2016, 5, 24).strftime("%A") # => "Tuesday"
Time.utc(2016, 5, 25).strftime("%A") # => "Wednesday"
Time.utc(2016, 5, 26).strftime("%A") # => "Thursday"
Time.utc(2016, 5, 27).strftime("%A") # => "Friday"
Time.utc(2016, 5, 28).strftime("%A") # => "Saturday"
%a | Weekday Name (Abbreviated)

Locale-independent (English) three-letter name of weekday:

Time.utc(2016, 5, 22).strftime("%a") # => "Sun"
Time.utc(2016, 5, 23).strftime("%a") # => "Mon"
Time.utc(2016, 5, 24).strftime("%a") # => "Tue"
Time.utc(2016, 5, 25).strftime("%a") # => "Wed"
Time.utc(2016, 5, 26).strftime("%a") # => "Thu"
Time.utc(2016, 5, 27).strftime("%a") # => "Fri"
Time.utc(2016, 5, 28).strftime("%a") # => "Sat"
%D, %x | Date, American

%m/%d/%y

  • Month
  • Day of Month
  • Year without Century
Time.utc(2016, 5, 24).strftime("%D") # => "05/24/16"
Time.utc(2016, 5, 24).strftime("%x") # => "05/24/16"
%F | Date, ISO 8601

%Y-%m-%d

  • Year
  • Month
  • Day of Month
Time.utc(2016, 5, 24).strftime("%F") # => "2016-05-24"
%v | Date, VMS With Time#strftime

%_d-%^b-%Y

  • Space Padded Day of Month
  • Uppercased Month Name
  • Year
Time.utc(2016, 5, 24).strftime("%v") # => "24-MAY-2016"
With Date#strftime and DateTime#strftime

%_d-%b-%Y

  • Space Padded Day of Month
  • Month Name
  • Year
require "date"
Time.utc(2016, 5, 24).to_date.strftime("%v") # => "24-May-2016"
Daytime Directives %P | Meridian Indicator (Lowercase)

Returns "am" for hours between 0 and 11, returns "pm" for hours between 12 and 23:

Time.utc(2016, 5, 24, 15).strftime("%P") # => "pm"
Time.utc(2016, 5, 24, 3).strftime("%P") # => "am"
%p | Meridian Indicator (Uppercase)

Returns "AM" for hours between 0 and 11, returns "PM" for hours between 12 and 23:

Time.utc(2016, 5, 24, 15).strftime("%p") # => "PM"
Time.utc(2016, 5, 24, 3).strftime("%p") # => "AM"
Hours Directives %H | Hour of Day, 24h (Zero Padded) | 0..23

Time's hour on the 24h clock:

Time.utc(2016, 5, 24, 15).strftime("%H") # => "15"
Time.utc(2016, 5, 24, 3).strftime("%H") # => "03"
Time.utc(2016, 5, 24, 3).strftime("%-H") # => "3"
%k | Hour of Day, 24h (Space Padded) | 0..23

Time's hour on the 24h clock:

Time.utc(2016, 5, 24, 15).strftime("%k") # => "15"
Time.utc(2016, 5, 24, 3).strftime("%k") # => " 3"
Time.utc(2016, 5, 24, 3).strftime("%-k") # => "3"
%I | Hour of Day, 12h (Zero Padded) | 0..11

Time's hour on the 12h clock:

Time.utc(2016, 5, 24, 15).strftime("%I") # => "03"
Time.utc(2016, 5, 24, 3).strftime("%I") # => "03"
Time.utc(2016, 5, 24, 3).strftime("%-I") # => "3"
%l | Hour of Day, 12h (Space Padded) | 0..11

Time's hour on the 12h clock:

Time.utc(2016, 5, 24, 15).strftime("%l") # => " 3"
Time.utc(2016, 5, 24, 3).strftime("%l") # => " 3"
Time.utc(2016, 5, 24, 3).strftime("%-l") # => "3"
Minutes Directives %M | Minute of Hour | 00..59

Time's minutes with default padding of 2:

Time.utc(2016, 5, 24, 15, 29).strftime("%M") # => "29"
Time.utc(2016, 5, 24, 15, 1).strftime("%M") # => "01"
Time.utc(2016, 5, 24, 15, 1).strftime("%-M") # => "1"
%R | Time, Hour + Minute

%H:%M

  • Hour (24h)
  • Minute
Time.utc(2016, 5, 24, 15, 29).strftime("%R") # => "15:29"
Seconds Directives %S | Second of Minute | 00..60

Time's seconds with default padding of 2:

Time.utc(2016, 5, 24, 15, 29, 59).strftime("%S") # => "59"
Time.utc(2016, 5, 24, 15, 29, 1).strftime("%S") # => "01"
Time.utc(2016, 5, 24, 15, 29, 1).strftime("%-S") # => "1"
%s | Seconds Since Unix Epoch

Number of seconds since 1970-01-01 00:00:00 UTC. This known as Unix timestamps. It returns the same value (as string) like Time#to_i:

Time.utc(2016, 5, 24, 15, 29, 59).strftime("%s") # => "1464103799"
Time.utc(2016, 5, 24, 15, 29, 59).to_i # => 1464103799
%r | Time, Hour + Minute + Second + Daytime

%I:%M:%S %p

  • Hour (12h)
  • Minute
  • Second
  • Daytime
Time.utc(2016, 5, 24, 15, 29, 59).strftime("%r") # => "03:29:59 PM"
%T, %X | Time, Hour + Minute + Second

%H:%M:%S

  • Hour (24h)
  • Minute
  • Second
Time.utc(2016, 5, 24, 15, 29, 59).strftime("%T") # => "15:29:59"
Time.utc(2016, 5, 24, 15, 29, 59).strftime("%X") # => "15:29:59"
%c | Date, Weekday + Month + Day of Month + Time + Year

%a %b %e %T %Y

  • Weekday (Short)
  • Month (Short)
  • Day of Month
  • Time (24h)
  • Year
Time.utc(2016, 5, 24, 15, 29, 59).strftime("%c") # => "Tue May 24 15:29:59 2016"
%+ | Date, date(1) Style

Only available in Date/DateTime's strftime() implementation

%a %b %e %T %Z %Y

  • Weekday (Short)
  • Month (Short)
  • Day of Month
  • Time (24h)
  • Numerical Time Zone Offset
  • Year
require "date"
Time.utc(2016, 5, 24, 15, 29, 59).to_datetime.strftime("%+")
# => "Tue May 24 15:29:59 +00:00 2016"
Smaller Than Seconds Directives %L | Millisecond | 000..999

Millisecond with default padding of 3. More precise fractions will be truncated:

Time.utc(2016, 5, 24, 15, 29, 0.1239).strftime("%L") # => "123"
%N | Fraction, Default: Nanosecond

Specifies time fractions like milliseconds (precision of 3), microseconds (precision of 6), or nanoseconds (precision of 9). More precise fractions will be truncated. Cannot be combined with padding:

Time.utc(2016, 5, 24, 15, 29, 0.1234567890).strftime("%3N") # => "123"
Time.utc(2016, 5, 24, 15, 29, 0.1234567890).strftime("%6N") # => "123456"
Time.utc(2016, 5, 24, 15, 29, 0.1234567890).strftime("%9N") # => "123456789"
Time.utc(2016, 5, 24, 15, 29, 0.1234567890).strftime("%N") # => "123456789"
%Q | Milliseconds Since Unix Epoch

Only available in Date/DateTime's strftime() implementation

Number of milliseconds since 1970-01-01 00:00:00 UTC:

require "date"
Time.utc(2016, 5, 24, 15, 29, 59.012).to_datetime.strftime("%Q") #=> "1464103799012"
Time Zone Directives %z | Time Zone, Offset from UTC

A numerical time zone identifier in the format of

  • Sign
  • Two-digit Hour
  • Two-digit Minute

which describes the offset from UTC:

Time.utc(2016, 5, 24).strftime("%z") # => "+0000"
Time.local(2016, 5, 24).strftime("%z") # => "+0200"

The output separates hours and minutes when using a single : flag:

Time.local(2016, 5, 24).strftime("%:z") # => "+02:00"

It will also show the seconds offset when using two :: colons:

Time.local(2016, 5, 24).strftime("%::z") # => "+02:00:00"

When using :::, it will only return significant information (no zero minutes or seconds):

Time.local(2016, 5, 24).strftime("%:::z") # => "+02"
%Z | Time Zone, Abbreviated, OS Dependent With Time#strftime

Big %Z displays a platform dependent time zone string:

Time.utc(2016, 5, 24).strftime("%Z") # => "UTC"
Time.local(2016, 5, 24).strftime("%Z") # => "CEST"

Ruby's documentation disencourages %Z, because it has a different result on different platforms and also does not properly identify the time zone:

While all directives are locale independent since Ruby 1.9, %Z is platform dependent. So, the result may differ even if the same format string is used in other systems such as C.

%z is recommended over %Z. %Z doesn’t identify the timezone. For example, "CST" is used at America/Chicago (-06:00), America/Havana (-05:00), Asia/Harbin (+08:00), Australia/Darwin (+09:30) and Australia/Adelaide (+10:30). Also, %Z is highly dependent on the operating system. For example, it may generate a non ASCII string on Japanese Windows. i.e. the result can be different to "JST". So the numeric time zone offset, %z, is recommended.

With Date#strftime and DateTime#strftime

Date's strftime() implementation outputs a numerical offset, similar to %:z:

require "date"
Time.utc(2016, 5, 24).to_datetime.strftime("%Z") # => "+00:00"
Time.local(2016, 5, 24).to_datetime.strftime("%Z") # => "+02:00"
Non Interpolating Directives %n | Newline

Output a newline:

Time.utc(2016).strftime("%n") # => "\n"
%t | Tab

Output a tab:

Time.utc(2016).strftime("%t") # => "\t"
%% | %

A single % needs to be escaped:

Time.utc(2016).strftime("%%") # => "%"
Resources Also See
https://idiosyncratic-ruby.com/57-what-the-time.html
US-ASCII-8BIT
Show full content

How come that Ruby has two ASCII encodings?

Encoding.name_list.grep(/ASCII/)
# => ["ASCII-8BIT", "US-ASCII"]

Which one is the normal one you should use for ASCII?

Aliases ASCII-8BIT US-ASCII BINARY ASCII   ANSI_X3.4-1968   646

So, US-ASCII is aliased to ASCII, but then what is ASCII-8BIT for? Encodings' RDoc has some help:

Encoding::ASCII_8BIT is a special encoding that is usually
used for a byte string, not a character string. But as the name insists,
its characters in the range of ASCII are considered as ASCII characters.
This is useful when you use ASCII-8BIT characters with other ASCII
compatible characters.

So basically, it is not a real encoding, but represents an arbitrary stream of bytes (bytes with a value between 0 and 255). It is used for raw byte stream or if you want to make clear that you do not know about a string's encoding!

The ASCII charset only takes 7 bits, so in strict ASCII, the 8th bit should never be set. The allowed byte value range is from 0 to 127. This is what the US-ASCII encoding is all about: It is used when dealing with ASCII encoded strings. Think: "ASCII-7BIT"

A simple example illustrating the difference:

 out_of_ascii_range = 128.chr # => "\x80"
 out_of_ascii_range.force_encoding("US-ASCII").valid_encoding? # => false
 out_of_ascii_range.force_encoding("ASCII-8BIT").valid_encoding? # => true
https://idiosyncratic-ruby.com/56-us-ascii-8bit.html
Struggling Four Equality
Show full content

Another of Ruby's idiosyncrasies is equalness. It's not too complicated, but naming is an issue here.

Four Concepts of Equalness equal? Object Identity Comparison

This one is easy. Two objects should be considered identical. Think: x.object_id == y.object_id

== Equality Equality

This is the usual method to care about. Two objects should be treated the same. If the class supports the <=> spaceship comparison operator, it is expected that == returns true for the same values, <=> returns 0 for.

eql? Hash Key Equality

Normally, this is the same as ==: "…eql? is usually aliased to the overridden == method"

The most important effect of the result of eql? is to distinguish between hash keys: "Two objects refer to the same hash key when their hash value is identical and the two objects are eql? to each other". A real life example:

1 == 1.0 # => true
1.eql?(1.0) # => false

# this means that the following will be treated as two different keys
{1: "Idiosyncratic", 1.0 "Hash"}

So eql? is a little stricter than ==, because it will return false if two objects are not instances of the same class. A typical implementation looks like this:

def eql?(other)
  instance_of?(other.class) && self == other
end
=== Fancy Equality

Implicitly used for case statements. Usually like ==, but can also mean that something has some kind of relationship, like being some kind of a class.

Equality Implementations for Core Classes Class eql? == === Object Identity (like equal?) Same as eql? Same as == Symbol - - - Numeric Same type, same value Same value, according to spaceship returning 0 - String Same length, same contents If other is a String: eql?, else: other.to_str === self - Regexp If other is a Regexp: Same pattern, same options, same encoding Same as eql? If other is a String: Match against self Array Same length, every element .eql? corresponding other element Same length, every element == corresponding other element. Will implicitly convert other object via .to_ary - Hash Same length, every element == corresponding other element (order not relevant) Same as eql? - Module - - other.is_a?(self) Class - - other.is_a?(self)

Meaning of -: Not defined / Use Object's implementation

Best Practices for Sub Classes
  • Define a meaningful == which returns true if two objects should be considered the same
  • Make eql? return the same value ==, but also limit it to return only true if both object are instances of the same class
  • Don't redefine equal?
  • Be creative with === (On a reasonable level. Other people using your code expect it to be some kind of useful relationship check)
Also See
https://idiosyncratic-ruby.com/55-struggling-four-equality.html
Try Converting
Show full content

Similar to metaprogramming, Ruby's type conversion system has evolved over time. While the result functions, it is also a little inconsistent and suffers from poor naming. Let's put things in perspective:

Implicit and Explicit Conversion

Ruby objects are usually converted to other classes/types using to_* functions. For example, converting the String "42" to a Float is done with to_f:

"42".to_f # => 42.0

This process is called explicit conversion (you want the object converted).

Some classes provide a second way to convert an object: implicit conversion (you expect the object to be of some type).

The following table shows the defined conversion methods of Ruby's important core classes:

Class Explicit Conversion Implicit Conversion Array to_a to_ary Hash to_h to_hash String to_s to_str Integer to_i to_int Float to_f - Complex to_c - Rational to_r - Regexp - to_regexp IO - to_io

In most cases you should just go with the explicit conversion method and you are good.

Expecting a Specific Type

However, things are more complicated in real life. You might, and many of Ruby's core methods do, expect a compatible type that you can deal with. That is where two kinds of indirect conversion methods come into play:

.try_convert Class Methods (Implicit Conversion or nil)

Some of Ruby's core classes have a try_convert class method. Although its not obvious, which classes have one, and which do not have one (Array has one, Integer does not), its semantics are pretty clear: It will convert the object into an instance of the class via the implicit conversion method (e.g. to_ary), or, if no implicit conversion method is defined, will just return nil. It will also return nil, if the result of the conversion is nil, or nil was given as argument:

Array.try_convert(42) # => nil
Array.try_convert(42..43) # => nil
Array.try_convert([42, 43]) # => [42, 43]
Array.try_convert(nil) # => nil

o = Object.new
def o.to_ary() [42] end
Array.try_convert(o) # => [42]
Uppercased Kernel Methods (Special Conversion or TypeError)

Idiosyncratically, there is a third way of converting values: Uppercased Kernel methods, like Array().¹ The objects you pass in will be converted to the corresponding class, following the following rules:

  • If there is a special conversion, apply it. See the table below for details and the exact application order (e.g. Array() does its special conversion after it tried the two steps below).
  • Unless special conversion gets applied, try to convert via the implicit conversion method
  • If it does not exist, try to convert via the explicit conversion method
  • Raise a TypeError² if everything of the above has failed

¹ Although defining uppercased methods for your custom classes to create instances of it looks like an interesting idea at first glance, it is rather confusing. Consider defining class.[] instead, which enables a very similar syntax, but uses the real constant it belongs to. An example of such usage is Set.
² Since Ruby 2.6, you can pass in a exception: false keyword argument to return nil instead of raising an error

Core Classes Conversion Table Class .try_convert Kernel Method Kernel Method w/ nil Kernel Method Special Array Array.try_convert Array() Array(nil) # => [] If :to_ary and :to_a did not return an array, it will create single-element array which contains the given value Hash Hash.try_convert Hash() Hash(nil) # => {} Hash([]) # => {}. Also remember that you can convert arrays to hashes with Hash.[]. String String.try_convert String() String(nil) # => "" - Integer Integer.try_convertInteger() Integer(nil) # TypeError Special behavior for strings: Instead of calling String#to_i, it will be more rigid². Takes a second argument defining the numerical base. Also see ³ Float - Float() Float(nil) # TypeError - ³ Complex - Complex() Complex(nil) # TypeError - Rational - Rational() Rational(nil) # TypeError - Regexp Regexp.try_convert - - - IO IO.try_convert - - -

.

² It will only convert strings that contain exactly an integer. It would not accept "42A", which String#to_i would happily take. It also accepts radix prefixes and numbers that contain underscores, so basically it accepts the same format that is valid for direct integer literals in Ruby. Will raise an ArgumentError if an invalid string is passed in.
³ It will convert to other low-level numerical types (such as integers and floats) directly, so Float(4) will not call 4.to_f
⁴ Added in Ruby 3.1

When to Use What?
  • Prefer explicit conversion: to_* methods
  • Use .try_convert for implicit conversion
  • Use the uppercased Kernel methods for their special effects, like Array() for wrapping single arguments in an arrays, or Integer() for strict integer conversion
https://idiosyncratic-ruby.com/54-try-converting.html
The Constant Tree
Show full content

Generated with Ruby 3.2.2, including RubyGems and DidYouMean:

Object (Class)
├─ARGF (ARGF.class)
├─ARGV (Array)
├─ArgumentError (Class)
├─Array (Class)
├─BasicObject (Class)
│ └─BasicObject → BasicObject
├─Binding (Class)
├─CROSS_COMPILING (NilClass)
├─Class (Class)
├─ClosedQueueError (Class)
├─Comparable (Module)
├─Complex (Class)
│ └─I (Complex)
├─ConditionVariable (Class)
├─Data (Class)
├─DidYouMean (Module)
│ ├─ClassNameChecker (Class)
│ ├─Correctable (Module)
│ ├─Formatter (Class)
│ ├─Jaro (Module)
│ ├─JaroWinkler (Module)
│ │ ├─THRESHOLD (Float)
│ │ └─WEIGHT (Float)
│ ├─KeyErrorChecker (Class)
│ ├─Levenshtein (Module)
│ ├─MethodNameChecker (Class)
│ │ ├─NAMES_TO_EXCLUDE (Hash)
│ │ └─RB_RESERVED_WORDS (Array)
│ ├─NameErrorCheckers (Object)
│ ├─NullChecker (Class)
│ ├─PatternKeyNameChecker (Class)
│ ├─PlainFormatter (Class)
│ ├─RequirePathChecker (Class)
│ ├─SPELL_CHECKERS (DidYouMean::DeprecatedMapping)
│ ├─SpellChecker (Class)
│ ├─TreeSpellChecker (Class)
│ ├─VERSION (String)
│ └─VariableNameChecker (Class)
│   ├─NAMES_TO_EXCLUDE (Hash)
│   └─RB_RESERVED_WORDS (Array)
├─Dir (Class)
├─ENV (Object)
├─EOFError (Class)
├─Encoding (Class)
│ ├─ANSI_X3_4_1968 (Encoding)
│ ├─ASCII (Encoding)
│ ├─ASCII_8BIT (Encoding)
│ ├─BIG5 (Encoding)
│ ├─BIG5_HKSCS (Encoding)
│ ├─BIG5_HKSCS_2008 (Encoding)
│ ├─BIG5_UAO (Encoding)
│ ├─BINARY (Encoding)
│ ├─Big5 (Encoding)
│ ├─Big5_HKSCS (Encoding)
│ ├─Big5_HKSCS_2008 (Encoding)
│ ├─Big5_UAO (Encoding)
│ ├─CESU_8 (Encoding)
│ ├─CP1250 (Encoding)
│ ├─CP1251 (Encoding)
│ ├─CP1252 (Encoding)
│ ├─CP1253 (Encoding)
│ ├─CP1254 (Encoding)
│ ├─CP1255 (Encoding)
│ ├─CP1256 (Encoding)
│ ├─CP1257 (Encoding)
│ ├─CP1258 (Encoding)
│ ├─CP437 (Encoding)
│ ├─CP50220 (Encoding)
│ ├─CP50221 (Encoding)
│ ├─CP51932 (Encoding)
│ ├─CP65000 (Encoding)
│ ├─CP65001 (Encoding)
│ ├─CP720 (Encoding)
│ ├─CP737 (Encoding)
│ ├─CP775 (Encoding)
│ ├─CP850 (Encoding)
│ ├─CP852 (Encoding)
│ ├─CP855 (Encoding)
│ ├─CP857 (Encoding)
│ ├─CP860 (Encoding)
│ ├─CP861 (Encoding)
│ ├─CP862 (Encoding)
│ ├─CP863 (Encoding)
│ ├─CP864 (Encoding)
│ ├─CP865 (Encoding)
│ ├─CP866 (Encoding)
│ ├─CP869 (Encoding)
│ ├─CP874 (Encoding)
│ ├─CP878 (Encoding)
│ ├─CP932 (Encoding)
│ ├─CP936 (Encoding)
│ ├─CP949 (Encoding)
│ ├─CP950 (Encoding)
│ ├─CP951 (Encoding)
│ ├─CSWINDOWS31J (Encoding)
│ ├─CompatibilityError (Class)
│ ├─Converter (Class)
│ │ ├─AFTER_OUTPUT (Integer)
│ │ ├─CRLF_NEWLINE_DECORATOR (Integer)
│ │ ├─CR_NEWLINE_DECORATOR (Integer)
│ │ ├─INVALID_MASK (Integer)
│ │ ├─INVALID_REPLACE (Integer)
│ │ ├─LF_NEWLINE_DECORATOR (Integer)
│ │ ├─PARTIAL_INPUT (Integer)
│ │ ├─UNDEF_HEX_CHARREF (Integer)
│ │ ├─UNDEF_MASK (Integer)
│ │ ├─UNDEF_REPLACE (Integer)
│ │ ├─UNIVERSAL_NEWLINE_DECORATOR (Integer)
│ │ ├─XML_ATTR_CONTENT_DECORATOR (Integer)
│ │ ├─XML_ATTR_QUOTE_DECORATOR (Integer)
│ │ └─XML_TEXT_DECORATOR (Integer)
│ ├─ConverterNotFoundError (Class)
│ ├─CsWindows31J (Encoding)
│ ├─EBCDIC_CP_US (Encoding)
│ ├─EMACS_MULE (Encoding)
│ ├─EUCCN (Encoding)
│ ├─EUCJP (Encoding)
│ ├─EUCJP_MS (Encoding)
│ ├─EUCKR (Encoding)
│ ├─EUCTW (Encoding)
│ ├─EUC_CN (Encoding)
│ ├─EUC_JISX0213 (Encoding)
│ ├─EUC_JIS_2004 (Encoding)
│ ├─EUC_JP (Encoding)
│ ├─EUC_JP_MS (Encoding)
│ ├─EUC_KR (Encoding)
│ ├─EUC_TW (Encoding)
│ ├─Emacs_Mule (Encoding)
│ ├─EucCN (Encoding)
│ ├─EucJP (Encoding)
│ ├─EucJP_ms (Encoding)
│ ├─EucKR (Encoding)
│ ├─EucTW (Encoding)
│ ├─GB12345 (Encoding)
│ ├─GB18030 (Encoding)
│ ├─GB1988 (Encoding)
│ ├─GB2312 (Encoding)
│ ├─GBK (Encoding)
│ ├─IBM037 (Encoding)
│ ├─IBM437 (Encoding)
│ ├─IBM720 (Encoding)
│ ├─IBM737 (Encoding)
│ ├─IBM775 (Encoding)
│ ├─IBM850 (Encoding)
│ ├─IBM852 (Encoding)
│ ├─IBM855 (Encoding)
│ ├─IBM857 (Encoding)
│ ├─IBM860 (Encoding)
│ ├─IBM861 (Encoding)
│ ├─IBM862 (Encoding)
│ ├─IBM863 (Encoding)
│ ├─IBM864 (Encoding)
│ ├─IBM865 (Encoding)
│ ├─IBM866 (Encoding)
│ ├─IBM869 (Encoding)
│ ├─ISO2022_JP (Encoding)
│ ├─ISO2022_JP2 (Encoding)
│ ├─ISO8859_1 (Encoding)
│ ├─ISO8859_10 (Encoding)
│ ├─ISO8859_11 (Encoding)
│ ├─ISO8859_13 (Encoding)
│ ├─ISO8859_14 (Encoding)
│ ├─ISO8859_15 (Encoding)
│ ├─ISO8859_16 (Encoding)
│ ├─ISO8859_2 (Encoding)
│ ├─ISO8859_3 (Encoding)
│ ├─ISO8859_4 (Encoding)
│ ├─ISO8859_5 (Encoding)
│ ├─ISO8859_6 (Encoding)
│ ├─ISO8859_7 (Encoding)
│ ├─ISO8859_8 (Encoding)
│ ├─ISO8859_9 (Encoding)
│ ├─ISO_2022_JP (Encoding)
│ ├─ISO_2022_JP_2 (Encoding)
│ ├─ISO_2022_JP_KDDI (Encoding)
│ ├─ISO_8859_1 (Encoding)
│ ├─ISO_8859_10 (Encoding)
│ ├─ISO_8859_11 (Encoding)
│ ├─ISO_8859_13 (Encoding)
│ ├─ISO_8859_14 (Encoding)
│ ├─ISO_8859_15 (Encoding)
│ ├─ISO_8859_16 (Encoding)
│ ├─ISO_8859_2 (Encoding)
│ ├─ISO_8859_3 (Encoding)
│ ├─ISO_8859_4 (Encoding)
│ ├─ISO_8859_5 (Encoding)
│ ├─ISO_8859_6 (Encoding)
│ ├─ISO_8859_7 (Encoding)
│ ├─ISO_8859_8 (Encoding)
│ ├─ISO_8859_9 (Encoding)
│ ├─InvalidByteSequenceError (Class)
│ ├─KOI8_R (Encoding)
│ ├─KOI8_U (Encoding)
│ ├─MACCENTEURO (Encoding)
│ ├─MACCROATIAN (Encoding)
│ ├─MACCYRILLIC (Encoding)
│ ├─MACGREEK (Encoding)
│ ├─MACICELAND (Encoding)
│ ├─MACJAPAN (Encoding)
│ ├─MACJAPANESE (Encoding)
│ ├─MACROMAN (Encoding)
│ ├─MACROMANIA (Encoding)
│ ├─MACTHAI (Encoding)
│ ├─MACTURKISH (Encoding)
│ ├─MACUKRAINE (Encoding)
│ ├─MacCentEuro (Encoding)
│ ├─MacCroatian (Encoding)
│ ├─MacCyrillic (Encoding)
│ ├─MacGreek (Encoding)
│ ├─MacIceland (Encoding)
│ ├─MacJapan (Encoding)
│ ├─MacJapanese (Encoding)
│ ├─MacRoman (Encoding)
│ ├─MacRomania (Encoding)
│ ├─MacThai (Encoding)
│ ├─MacTurkish (Encoding)
│ ├─MacUkraine (Encoding)
│ ├─PCK (Encoding)
│ ├─SHIFT_JIS (Encoding)
│ ├─SJIS (Encoding)
│ ├─SJIS_DOCOMO (Encoding)
│ ├─SJIS_DoCoMo (Encoding)
│ ├─SJIS_KDDI (Encoding)
│ ├─SJIS_SOFTBANK (Encoding)
│ ├─SJIS_SoftBank (Encoding)
│ ├─STATELESS_ISO_2022_JP (Encoding)
│ ├─STATELESS_ISO_2022_JP_KDDI (Encoding)
│ ├─Shift_JIS (Encoding)
│ ├─Stateless_ISO_2022_JP (Encoding)
│ ├─Stateless_ISO_2022_JP_KDDI (Encoding)
│ ├─TIS_620 (Encoding)
│ ├─UCS_2BE (Encoding)
│ ├─UCS_4BE (Encoding)
│ ├─UCS_4LE (Encoding)
│ ├─US_ASCII (Encoding)
│ ├─UTF8_DOCOMO (Encoding)
│ ├─UTF8_DoCoMo (Encoding)
│ ├─UTF8_KDDI (Encoding)
│ ├─UTF8_MAC (Encoding)
│ ├─UTF8_SOFTBANK (Encoding)
│ ├─UTF8_SoftBank (Encoding)
│ ├─UTF_16 (Encoding)
│ ├─UTF_16BE (Encoding)
│ ├─UTF_16LE (Encoding)
│ ├─UTF_32 (Encoding)
│ ├─UTF_32BE (Encoding)
│ ├─UTF_32LE (Encoding)
│ ├─UTF_7 (Encoding)
│ ├─UTF_8 (Encoding)
│ ├─UTF_8_HFS (Encoding)
│ ├─UTF_8_MAC (Encoding)
│ ├─UndefinedConversionError (Class)
│ ├─WINDOWS_1250 (Encoding)
│ ├─WINDOWS_1251 (Encoding)
│ ├─WINDOWS_1252 (Encoding)
│ ├─WINDOWS_1253 (Encoding)
│ ├─WINDOWS_1254 (Encoding)
│ ├─WINDOWS_1255 (Encoding)
│ ├─WINDOWS_1256 (Encoding)
│ ├─WINDOWS_1257 (Encoding)
│ ├─WINDOWS_1258 (Encoding)
│ ├─WINDOWS_31J (Encoding)
│ ├─WINDOWS_874 (Encoding)
│ ├─Windows_1250 (Encoding)
│ ├─Windows_1251 (Encoding)
│ ├─Windows_1252 (Encoding)
│ ├─Windows_1253 (Encoding)
│ ├─Windows_1254 (Encoding)
│ ├─Windows_1255 (Encoding)
│ ├─Windows_1256 (Encoding)
│ ├─Windows_1257 (Encoding)
│ ├─Windows_1258 (Encoding)
│ ├─Windows_31J (Encoding)
│ └─Windows_874 (Encoding)
├─EncodingError (Class)
├─Enumerable (Module)
├─Enumerator (Class)
│ ├─ArithmeticSequence (Class)
│ ├─Chain (Class)
│ ├─Generator (Class)
│ ├─Lazy (Class)
│ ├─Producer (Class)
│ ├─Product (Class)
│ └─Yielder (Class)
├─Errno (Module)
│ ├─E2BIG (Class)
│ │ └─Errno (Integer)
│ ├─EACCES (Class)
│ │ └─Errno (Integer)
│ ├─EADDRINUSE (Class)
│ │ └─Errno (Integer)
│ ├─EADDRNOTAVAIL (Class)
│ │ └─Errno (Integer)
│ ├─EADV (Class)
│ │ └─Errno (Integer)
│ ├─EAFNOSUPPORT (Class)
│ │ └─Errno (Integer)
│ ├─EAGAIN (Class)
│ │ └─Errno (Integer)
│ ├─EALREADY (Class)
│ │ └─Errno (Integer)
│ ├─EAUTH (Class)
│ │ └─Errno (Integer)
│ ├─EBADARCH (Class)
│ │ └─Errno (Integer)
│ ├─EBADE (Class)
│ │ └─Errno (Integer)
│ ├─EBADEXEC (Class)
│ │ └─Errno (Integer)
│ ├─EBADF (Class)
│ │ └─Errno (Integer)
│ ├─EBADFD (Class)
│ │ └─Errno (Integer)
│ ├─EBADMACHO (Class)
│ │ └─Errno (Integer)
│ ├─EBADMSG (Class)
│ │ └─Errno (Integer)
│ ├─EBADR (Class)
│ │ └─Errno (Integer)
│ ├─EBADRPC (Class)
│ │ └─Errno (Integer)
│ ├─EBADRQC (Class)
│ │ └─Errno (Integer)
│ ├─EBADSLT (Class)
│ │ └─Errno (Integer)
│ ├─EBFONT (Class)
│ │ └─Errno (Integer)
│ ├─EBUSY (Class)
│ │ └─Errno (Integer)
│ ├─ECANCELED (Class)
│ │ └─Errno (Integer)
│ ├─ECAPMODE (Class)
│ │ └─Errno (Integer)
│ ├─ECHILD (Class)
│ │ └─Errno (Integer)
│ ├─ECHRNG (Class)
│ │ └─Errno (Integer)
│ ├─ECOMM (Class)
│ │ └─Errno (Integer)
│ ├─ECONNABORTED (Class)
│ │ └─Errno (Integer)
│ ├─ECONNREFUSED (Class)
│ │ └─Errno (Integer)
│ ├─ECONNRESET (Class)
│ │ └─Errno (Integer)
│ ├─EDEADLK (Class)
│ │ └─Errno (Integer)
│ ├─EDEADLOCK (Class)
│ │ └─Errno (Integer)
│ ├─EDESTADDRREQ (Class)
│ │ └─Errno (Integer)
│ ├─EDEVERR (Class)
│ │ └─Errno (Integer)
│ ├─EDOM (Class)
│ │ └─Errno (Integer)
│ ├─EDOOFUS (Class)
│ │ └─Errno (Integer)
│ ├─EDOTDOT (Class)
│ │ └─Errno (Integer)
│ ├─EDQUOT (Class)
│ │ └─Errno (Integer)
│ ├─EEXIST (Class)
│ │ └─Errno (Integer)
│ ├─EFAULT (Class)
│ │ └─Errno (Integer)
│ ├─EFBIG (Class)
│ │ └─Errno (Integer)
│ ├─EFTYPE (Class)
│ │ └─Errno (Integer)
│ ├─EHOSTDOWN (Class)
│ │ └─Errno (Integer)
│ ├─EHOSTUNREACH (Class)
│ │ └─Errno (Integer)
│ ├─EHWPOISON (Class)
│ │ └─Errno (Integer)
│ ├─EIDRM (Class)
│ │ └─Errno (Integer)
│ ├─EILSEQ (Class)
│ │ └─Errno (Integer)
│ ├─EINPROGRESS (Class)
│ │ └─Errno (Integer)
│ ├─EINTR (Class)
│ │ └─Errno (Integer)
│ ├─EINVAL (Class)
│ │ └─Errno (Integer)
│ ├─EIO (Class)
│ │ └─Errno (Integer)
│ ├─EIPSEC (Class)
│ │ └─Errno (Integer)
│ ├─EISCONN (Class)
│ │ └─Errno (Integer)
│ ├─EISDIR (Class)
│ │ └─Errno (Integer)
│ ├─EISNAM (Class)
│ │ └─Errno (Integer)
│ ├─EKEYEXPIRED (Class)
│ │ └─Errno (Integer)
│ ├─EKEYREJECTED (Class)
│ │ └─Errno (Integer)
│ ├─EKEYREVOKED (Class)
│ │ └─Errno (Integer)
│ ├─EL2HLT (Class)
│ │ └─Errno (Integer)
│ ├─EL2NSYNC (Class)
│ │ └─Errno (Integer)
│ ├─EL3HLT (Class)
│ │ └─Errno (Integer)
│ ├─EL3RST (Class)
│ │ └─Errno (Integer)
│ ├─ELAST (Class)
│ │ └─Errno (Integer)
│ ├─ELIBACC (Class)
│ │ └─Errno (Integer)
│ ├─ELIBBAD (Class)
│ │ └─Errno (Integer)
│ ├─ELIBEXEC (Class)
│ │ └─Errno (Integer)
│ ├─ELIBMAX (Class)
│ │ └─Errno (Integer)
│ ├─ELIBSCN (Class)
│ │ └─Errno (Integer)
│ ├─ELNRNG (Class)
│ │ └─Errno (Integer)
│ ├─ELOOP (Class)
│ │ └─Errno (Integer)
│ ├─EMEDIUMTYPE (Class)
│ │ └─Errno (Integer)
│ ├─EMFILE (Class)
│ │ └─Errno (Integer)
│ ├─EMLINK (Class)
│ │ └─Errno (Integer)
│ ├─EMSGSIZE (Class)
│ │ └─Errno (Integer)
│ ├─EMULTIHOP (Class)
│ │ └─Errno (Integer)
│ ├─ENAMETOOLONG (Class)
│ │ └─Errno (Integer)
│ ├─ENAVAIL (Class)
│ │ └─Errno (Integer)
│ ├─ENEEDAUTH (Class)
│ │ └─Errno (Integer)
│ ├─ENETDOWN (Class)
│ │ └─Errno (Integer)
│ ├─ENETRESET (Class)
│ │ └─Errno (Integer)
│ ├─ENETUNREACH (Class)
│ │ └─Errno (Integer)
│ ├─ENFILE (Class)
│ │ └─Errno (Integer)
│ ├─ENOANO (Class)
│ │ └─Errno (Integer)
│ ├─ENOATTR (Class)
│ │ └─Errno (Integer)
│ ├─ENOBUFS (Class)
│ │ └─Errno (Integer)
│ ├─ENOCSI (Class)
│ │ └─Errno (Integer)
│ ├─ENODATA (Class)
│ │ └─Errno (Integer)
│ ├─ENODEV (Class)
│ │ └─Errno (Integer)
│ ├─ENOENT (Class)
│ │ └─Errno (Integer)
│ ├─ENOEXEC (Class)
│ │ └─Errno (Integer)
│ ├─ENOKEY (Class)
│ │ └─Errno (Integer)
│ ├─ENOLCK (Class)
│ │ └─Errno (Integer)
│ ├─ENOLINK (Class)
│ │ └─Errno (Integer)
│ ├─ENOMEDIUM (Class)
│ │ └─Errno (Integer)
│ ├─ENOMEM (Class)
│ │ └─Errno (Integer)
│ ├─ENOMSG (Class)
│ │ └─Errno (Integer)
│ ├─ENONET (Class)
│ │ └─Errno (Integer)
│ ├─ENOPKG (Class)
│ │ └─Errno (Integer)
│ ├─ENOPOLICY (Class)
│ │ └─Errno (Integer)
│ ├─ENOPROTOOPT (Class)
│ │ └─Errno (Integer)
│ ├─ENOSPC (Class)
│ │ └─Errno (Integer)
│ ├─ENOSR (Class)
│ │ └─Errno (Integer)
│ ├─ENOSTR (Class)
│ │ └─Errno (Integer)
│ ├─ENOSYS (Class)
│ │ └─Errno (Integer)
│ ├─ENOTBLK (Class)
│ │ └─Errno (Integer)
│ ├─ENOTCAPABLE (Class)
│ │ └─Errno (Integer)
│ ├─ENOTCONN (Class)
│ │ └─Errno (Integer)
│ ├─ENOTDIR (Class)
│ │ └─Errno (Integer)
│ ├─ENOTEMPTY (Class)
│ │ └─Errno (Integer)
│ ├─ENOTNAM (Class)
│ │ └─Errno (Integer)
│ ├─ENOTRECOVERABLE (Class)
│ │ └─Errno (Integer)
│ ├─ENOTSOCK (Class)
│ │ └─Errno (Integer)
│ ├─ENOTSUP (Class)
│ │ └─Errno (Integer)
│ ├─ENOTTY (Class)
│ │ └─Errno (Integer)
│ ├─ENOTUNIQ (Class)
│ │ └─Errno (Integer)
│ ├─ENXIO (Class)
│ │ └─Errno (Integer)
│ ├─EOPNOTSUPP (Class)
│ │ └─Errno (Integer)
│ ├─EOVERFLOW (Class)
│ │ └─Errno (Integer)
│ ├─EOWNERDEAD (Class)
│ │ └─Errno (Integer)
│ ├─EPERM (Class)
│ │ └─Errno (Integer)
│ ├─EPFNOSUPPORT (Class)
│ │ └─Errno (Integer)
│ ├─EPIPE (Class)
│ │ └─Errno (Integer)
│ ├─EPROCLIM (Class)
│ │ └─Errno (Integer)
│ ├─EPROCUNAVAIL (Class)
│ │ └─Errno (Integer)
│ ├─EPROGMISMATCH (Class)
│ │ └─Errno (Integer)
│ ├─EPROGUNAVAIL (Class)
│ │ └─Errno (Integer)
│ ├─EPROTO (Class)
│ │ └─Errno (Integer)
│ ├─EPROTONOSUPPORT (Class)
│ │ └─Errno (Integer)
│ ├─EPROTOTYPE (Class)
│ │ └─Errno (Integer)
│ ├─EPWROFF (Class)
│ │ └─Errno (Integer)
│ ├─EQFULL (Class)
│ │ └─Errno (Integer)
│ ├─ERANGE (Class)
│ │ └─Errno (Integer)
│ ├─EREMCHG (Class)
│ │ └─Errno (Integer)
│ ├─EREMOTE (Class)
│ │ └─Errno (Integer)
│ ├─EREMOTEIO (Class)
│ │ └─Errno (Integer)
│ ├─ERESTART (Class)
│ │ └─Errno (Integer)
│ ├─ERFKILL (Class)
│ │ └─Errno (Integer)
│ ├─EROFS (Class)
│ │ └─Errno (Integer)
│ ├─ERPCMISMATCH (Class)
│ │ └─Errno (Integer)
│ ├─ESHLIBVERS (Class)
│ │ └─Errno (Integer)
│ ├─ESHUTDOWN (Class)
│ │ └─Errno (Integer)
│ ├─ESOCKTNOSUPPORT (Class)
│ │ └─Errno (Integer)
│ ├─ESPIPE (Class)
│ │ └─Errno (Integer)
│ ├─ESRCH (Class)
│ │ └─Errno (Integer)
│ ├─ESRMNT (Class)
│ │ └─Errno (Integer)
│ ├─ESTALE (Class)
│ │ └─Errno (Integer)
│ ├─ESTRPIPE (Class)
│ │ └─Errno (Integer)
│ ├─ETIME (Class)
│ │ └─Errno (Integer)
│ ├─ETIMEDOUT (Class)
│ │ └─Errno (Integer)
│ ├─ETOOMANYREFS (Class)
│ │ └─Errno (Integer)
│ ├─ETXTBSY (Class)
│ │ └─Errno (Integer)
│ ├─EUCLEAN (Class)
│ │ └─Errno (Integer)
│ ├─EUNATCH (Class)
│ │ └─Errno (Integer)
│ ├─EUSERS (Class)
│ │ └─Errno (Integer)
│ ├─EWOULDBLOCK (Class)
│ │ └─Errno (Integer)
│ ├─EXDEV (Class)
│ │ └─Errno (Integer)
│ ├─EXFULL (Class)
│ │ └─Errno (Integer)
│ └─NOERROR (Class)
│   └─Errno (Integer)
├─ErrorHighlight (Module)
│ ├─CoreExt (Module)
│ ├─DefaultFormatter (Class)
│ └─VERSION (String)
├─Exception (Class)
├─FalseClass (Class)
├─Fiber (Class)
├─FiberError (Class)
├─File (Class)
│ ├─ALT_SEPARATOR (NilClass)
│ ├─Constants (Module)
│ │ ├─APPEND (Integer)
│ │ ├─BINARY (Integer)
│ │ ├─CREAT (Integer)
│ │ ├─DIRECT (Integer)
│ │ ├─DSYNC (Integer)
│ │ ├─EXCL (Integer)
│ │ ├─FNM_CASEFOLD (Integer)
│ │ ├─FNM_DOTMATCH (Integer)
│ │ ├─FNM_EXTGLOB (Integer)
│ │ ├─FNM_NOESCAPE (Integer)
│ │ ├─FNM_PATHNAME (Integer)
│ │ ├─FNM_SHORTNAME (Integer)
│ │ ├─FNM_SYSCASE (Integer)
│ │ ├─LOCK_EX (Integer)
│ │ ├─LOCK_NB (Integer)
│ │ ├─LOCK_SH (Integer)
│ │ ├─LOCK_UN (Integer)
│ │ ├─NOATIME (Integer)
│ │ ├─NOCTTY (Integer)
│ │ ├─NOFOLLOW (Integer)
│ │ ├─NONBLOCK (Integer)
│ │ ├─NULL (String)
│ │ ├─RDONLY (Integer)
│ │ ├─RDWR (Integer)
│ │ ├─RSYNC (Integer)
│ │ ├─SHARE_DELETE (Integer)
│ │ ├─SYNC (Integer)
│ │ ├─TMPFILE (Integer)
│ │ ├─TRUNC (Integer)
│ │ └─WRONLY (Integer)
│ ├─PATH_SEPARATOR (String)
│ ├─SEPARATOR (String)
│ ├─Separator (String)
│ └─Stat (Class)
├─FileTest (Module)
├─Float (Class)
│ ├─DIG (Integer)
│ ├─EPSILON (Float)
│ ├─INFINITY (Float)
│ ├─MANT_DIG (Integer)
│ ├─MAX (Float)
│ ├─MAX_10_EXP (Integer)
│ ├─MAX_EXP (Integer)
│ ├─MIN (Float)
│ ├─MIN_10_EXP (Integer)
│ ├─MIN_EXP (Integer)
│ ├─NAN (Float)
│ └─RADIX (Integer)
├─FloatDomainError (Class)
├─FrozenError (Class)
├─GC (Module)
│ ├─INTERNAL_CONSTANTS (Hash)
│ ├─OPTS (Array)
│ └─Profiler (Module)
├─Gem (Module)
│ ├─BUNDLED_GEMS (Module)
│ │ ├─ARCHDIR (String)
│ │ ├─DLEXT (Regexp)
│ │ ├─EXACT (Hash)
│ │ ├─LIBDIR (String)
│ │ ├─LIBEXT (Regexp)
│ │ ├─PREFIXED (Hash)
│ │ ├─SINCE (Hash)
│ │ └─WARNED (Hash)
│ ├─BasicSpecification (Class)
│ ├─CIDetector (Module)
│ │ ├─ENV_DESCRIPTORS (Hash)
│ │ └─ENV_INDICATORS (Array)
│ ├─CommandLineError (Class)
│ ├─ConfigFile (Class)
│ │ ├─DEFAULT_BACKTRACE (TrueClass)
│ │ ├─DEFAULT_BULK_THRESHOLD (Integer)
│ │ ├─DEFAULT_CERT_EXPIRATION_LENGTH_DAYS (Integer)
│ │ ├─DEFAULT_CONCURRENT_DOWNLOADS (Integer)
│ │ ├─DEFAULT_IPV4_FALLBACK_ENABLED (FalseClass)
│ │ ├─DEFAULT_UPDATE_SOURCES (TrueClass)
│ │ ├─DEFAULT_VERBOSITY (TrueClass)
│ │ ├─OPERATING_SYSTEM_DEFAULTS (Hash)
│ │ ├─PLATFORM_DEFAULTS (Hash)
│ │ ├─SYSTEM_CONFIG_PATH (String)
│ │ └─SYSTEM_WIDE_CONFIG_FILE (String)
│ ├─ConfigMap (Hash)
│ ├─ConflictError (Class)
│ ├─DEFAULT_HOST (String)
│ ├─Dependency (Class)
│ │ └─TYPES (Array)
│ ├─DependencyError (Class)
│ ├─DependencyList (Class)
│ ├─DependencyRemovalException (Class)
│ ├─DependencyResolutionError (Class)
│ ├─Deprecate (Module)
│ ├─DocumentError (Class)
│ ├─EndOfYAMLException (Class)
│ ├─ErrorReason (Class)
│ ├─Exception (Class)
│ ├─FilePermissionError (Class)
│ ├─FormatException (Class)
│ ├─GEM_DEP_FILES (Array)
│ ├─GemNotFoundException (Class)
│ ├─GemNotInHomeException (Class)
│ ├─ImpossibleDependenciesError (Class)
│ ├─InstallError (Class)
│ ├─Installer (Class)
│ │ ├─ENV_PATHS (Array)
│ │ ├─ExtensionBuildError (Class)
│ │ └─FakePackage (Class)
│ ├─InvalidSpecificationException (Class)
│ ├─LOADED_SPECS_MUTEX (Thread::Mutex)
│ ├─Licenses (Class)
│ │ ├─DEPRECATED_EXCEPTION_IDENTIFIERS (Array)
│ │ ├─DEPRECATED_EXCEPTION_REGEXP (Regexp)
│ │ ├─DEPRECATED_LICENSE_IDENTIFIERS (Array)
│ │ ├─DEPRECATED_LICENSE_REGEXP (Regexp)
│ │ ├─EXCEPTION_IDENTIFIERS (Array)
│ │ ├─LICENSE_IDENTIFIERS (Array)
│ │ ├─LICENSE_REF (String)
│ │ ├─NONSTANDARD (String)
│ │ └─VALID_REGEXP (Regexp)
│ ├─List (Class)
│ ├─LoadError (Class)
│ ├─MARSHAL_SPEC_DIR (String)
│ ├─MissingSpecError (Class)
│ ├─MissingSpecVersionError (Class)
│ ├─NameTuple (Class)
│ ├─OperationNotSupportedError (Class)
│ ├─PathSupport (Class)
│ ├─Platform (Class)
│ │ ├─CURRENT (String)
│ │ └─RUBY (String)
│ ├─PlatformMismatch (Class)
│ ├─REPOSITORY_DEFAULT_GEM_SUBDIRECTORIES (Array)
│ ├─REPOSITORY_SUBDIRECTORIES (Array)
│ ├─RUBYGEMS_DIR (String)
│ ├─RbConfigPriorities (Array)
│ ├─RemoteError (Class)
│ ├─RemoteInstallationCancelled (Class)
│ ├─RemoteInstallationSkipped (Class)
│ ├─RemoteSourceException (Class)
│ ├─RequestSet (Class)
│ │ ├─GemDependencyAPI (Class)
│ │ │ ├─ENGINE_MAP (Hash)
│ │ │ ├─PLATFORM_MAP (Hash)
│ │ │ ├─VERSION_MAP (Hash)
│ │ │ └─WINDOWS (Hash)
│ │ └─Lockfile (Class)
│ │   ├─ParseError (Class)
│ │   ├─Parser (Class)
│ │   └─Tokenizer (Class)
│ │     ├─EOF (Gem::RequestSet::Lockfile::Tokenizer::Token)
│ │     └─Token (Class)
│ ├─Requirement (Class)
│ │ ├─BadRequirementError (Class)
│ │ ├─DefaultPrereleaseRequirement (Array)
│ │ ├─DefaultRequirement (Array)
│ │ ├─OPS (Hash)
│ │ ├─PATTERN (Regexp)
│ │ ├─PATTERN_RAW (String)
│ │ └─SOURCE_SET_REQUIREMENT (#<Class:0x00007fa4ce6f7a00>)
│ ├─Resolver (Class)
│ │ ├─APISet (Class)
│ │ │ └─GemParser (Class)
│ │ ├─APISpecification (Class)
│ │ ├─ActivationRequest (Class)
│ │ ├─BestSet (Class)
│ │ ├─ComposedSet (Class)
│ │ ├─Conflict (Class)
│ │ ├─CurrentSet (Class)
│ │ ├─DEBUG_RESOLVER (FalseClass)
│ │ ├─DependencyRequest (Class)
│ │ ├─GitSet (Class)
│ │ ├─GitSpecification (Class)
│ │ ├─IndexSet (Class)
│ │ ├─IndexSpecification (Class)
│ │ ├─InstalledSpecification (Class)
│ │ ├─InstallerSet (Class)
│ │ ├─LocalSpecification (Class)
│ │ ├─LockSet (Class)
│ │ ├─LockSpecification (Class)
│ │ ├─Molinillo (Module)
│ │ │ ├─CircularDependencyError (Class)
│ │ │ ├─Delegates (Module)
│ │ │ │ ├─ResolutionState (Module)
│ │ │ │ └─SpecificationProvider (Module)
│ │ │ ├─DependencyGraph (Class)
│ │ │ │ ├─Action (Class)
│ │ │ │ ├─AddEdgeNoCircular (Class)
│ │ │ │ ├─AddVertex (Class)
│ │ │ │ ├─DeleteEdge (Class)
│ │ │ │ ├─DetachVertexNamed (Class)
│ │ │ │ ├─Edge (Class)
│ │ │ │ ├─Log (Class)
│ │ │ │ ├─SetPayload (Class)
│ │ │ │ ├─Tag (Class)
│ │ │ │ └─Vertex (Class)
│ │ │ ├─DependencyState (Class)
│ │ │ ├─NoSuchDependencyError (Class)
│ │ │ ├─PossibilityState (Class)
│ │ │ ├─ResolutionState (Class)
│ │ │ ├─Resolver (Class)
│ │ │ │ └─Resolution (Class)
│ │ │ │   ├─Conflict (Class)
│ │ │ │   ├─PossibilitySet (Class)
│ │ │ │   └─UnwindDetails (Class)
│ │ │ ├─ResolverError (Class)
│ │ │ ├─SpecificationProvider (Module)
│ │ │ ├─UI (Module)
│ │ │ ├─VERSION (String)
│ │ │ └─VersionConflict (Class)
│ │ ├─RequirementList (Class)
│ │ ├─Set (Class)
│ │ ├─SourceSet (Class)
│ │ ├─SpecSpecification (Class)
│ │ ├─Specification (Class)
│ │ ├─Stats (Class)
│ │ │ └─PATTERN (String)
│ │ ├─VendorSet (Class)
│ │ └─VendorSpecification (Class)
│ ├─RubyGemsVersion (String)
│ ├─RubyVersionMismatch (Class)
│ ├─RuntimeRequirementNotMetError (Class)
│ ├─Source (Class)
│ │ ├─FILES (Hash)
│ │ ├─Git (Class)
│ │ ├─Installed (Class)
│ │ ├─Local (Class)
│ │ ├─Lock (Class)
│ │ ├─SpecificFile (Class)
│ │ └─Vendor (Class)
│ ├─SourceFetchProblem (Class)
│ ├─SourceList (Class)
│ ├─SpecFetcher (Class)
│ ├─SpecificGemNotFoundException (Class)
│ ├─Specification (Class)
│ │ ├─CURRENT_SPECIFICATION_VERSION (Integer)
│ │ ├─DateLike (Object)
│ │ ├─DateTimeFormat (Regexp)
│ │ ├─INITIALIZE_CODE_FOR_DEFAULTS (Hash)
│ │ ├─LATEST_RUBY_WITHOUT_PATCH_VERSIONS (Gem::Version)
│ │ ├─MARSHAL_FIELDS (Hash)
│ │ ├─NONEXISTENT_SPECIFICATION_VERSION (Integer)
│ │ ├─NOT_FOUND (#<Class:0x00007fa4ce6f6060>)
│ │ ├─REMOVED_METHODS (Array)
│ │ ├─SPECIFICATION_VERSION_HISTORY (Hash)
│ │ ├─TODAY (Time)
│ │ └─VALID_NAME_PATTERN (Regexp)
│ ├─SpecificationPolicy (Class)
│ │ ├─HOMEPAGE_URI_PATTERN (Regexp)
│ │ ├─LAZY (String)
│ │ ├─LAZY_PATTERN (Regexp)
│ │ ├─METADATA_LINK_KEYS (Array)
│ │ ├─SPECIAL_CHARACTERS (Regexp)
│ │ ├─VALID_NAME_PATTERN (Regexp)
│ │ └─VALID_URI_PATTERN (Regexp)
│ ├─StubSpecification (Class)
│ │ ├─OPEN_MODE (String)
│ │ ├─PREFIX (String)
│ │ └─StubLine (Class)
│ │   ├─NO_EXTENSIONS (Array)
│ │   ├─REQUIRE_PATHS (Hash)
│ │   └─REQUIRE_PATH_LIST (Hash)
│ ├─SystemExitException (Class)
│ ├─UninstallError (Class)
│ ├─UnknownCommandError (Class)
│ ├─UnknownCommandSpellChecker (Class)
│ ├─UnsatisfiableDepedencyError (Class)
│ ├─UnsatisfiableDependencyError (Class)
│ ├─Util (Module)
│ ├─VERSION (String)
│ ├─VerificationError (Class)
│ ├─Version (Class)
│ │ ├─ANCHORED_VERSION_PATTERN (Regexp)
│ │ ├─Requirement (Class)
│ │ │ ├─BadRequirementError (Class)
│ │ │ ├─DefaultPrereleaseRequirement (Array)
│ │ │ ├─DefaultRequirement (Array)
│ │ │ ├─OPS (Hash)
│ │ │ ├─PATTERN (Regexp)
│ │ │ ├─PATTERN_RAW (String)
│ │ │ └─SOURCE_SET_REQUIREMENT (#<Class:0x00007fa4ce6f7a00>)
│ │ └─VERSION_PATTERN (String)
│ ├─WIN_PATTERNS (Array)
│ └─WebauthnVerificationError (Class)
├─Hash (Class)
├─IO (Class)
│ ├─Buffer (Class)
│ │ ├─AccessError (Class)
│ │ ├─AllocationError (Class)
│ │ ├─BIG_ENDIAN (Integer)
│ │ ├─DEFAULT_SIZE (Integer)
│ │ ├─EXTERNAL (Integer)
│ │ ├─HOST_ENDIAN (Integer)
│ │ ├─INTERNAL (Integer)
│ │ ├─InvalidatedError (Class)
│ │ ├─LITTLE_ENDIAN (Integer)
│ │ ├─LOCKED (Integer)
│ │ ├─LockedError (Class)
│ │ ├─MAPPED (Integer)
│ │ ├─MaskError (Class)
│ │ ├─NETWORK_ENDIAN (Integer)
│ │ ├─PAGE_SIZE (Integer)
│ │ ├─PRIVATE (Integer)
│ │ ├─READONLY (Integer)
│ │ └─SHARED (Integer)
│ ├─EAGAINWaitReadable (Class)
│ ├─EAGAINWaitWritable (Class)
│ ├─EINPROGRESSWaitReadable (Class)
│ ├─EINPROGRESSWaitWritable (Class)
│ ├─EWOULDBLOCKWaitReadable (Class)
│ ├─EWOULDBLOCKWaitWritable (Class)
│ ├─PRIORITY (Integer)
│ ├─READABLE (Integer)
│ ├─SEEK_CUR (Integer)
│ ├─SEEK_DATA (Integer)
│ ├─SEEK_END (Integer)
│ ├─SEEK_HOLE (Integer)
│ ├─SEEK_SET (Integer)
│ ├─TimeoutError (Class)
│ ├─WRITABLE (Integer)
│ ├─WaitReadable (Module)
│ └─WaitWritable (Module)
├─IOError (Class)
├─IndexError (Class)
├─Integer (Class)
│ └─GMP_VERSION (String)
├─Interrupt (Class)
├─Kernel (Module)
│ └─RUBYGEMS_ACTIVATION_MONITOR (Monitor)
├─KeyError (Class)
├─LoadError (Class)
├─LocalJumpError (Class)
├─Marshal (Module)
│ ├─MAJOR_VERSION (Integer)
│ └─MINOR_VERSION (Integer)
├─MatchData (Class)
├─Math (Module)
│ ├─DomainError (Class)
│ ├─E (Float)
│ └─PI (Float)
├─Method (Class)
├─Module (Class)
├─Monitor (Class)
├─MonitorMixin (Module)
│ └─ConditionVariable (Class)
├─Mutex (Class)
├─NameError (Class)
├─NilClass (Class)
├─NoMatchingPatternError (Class)
├─NoMatchingPatternKeyError (Class)
├─NoMemoryError (Class)
├─NoMethodError (Class)
├─NotImplementedError (Class)
├─Numeric (Class)
├─Object → Object
├─ObjectSpace (Module)
│ ├─WeakKeyMap (Class)
│ └─WeakMap (Class)
├─Proc (Class)
├─Process (Module)
│ ├─CLOCK_BOOTTIME (Integer)
│ ├─CLOCK_BOOTTIME_ALARM (Integer)
│ ├─CLOCK_MONOTONIC (Integer)
│ ├─CLOCK_MONOTONIC_COARSE (Integer)
│ ├─CLOCK_MONOTONIC_RAW (Integer)
│ ├─CLOCK_PROCESS_CPUTIME_ID (Integer)
│ ├─CLOCK_REALTIME (Integer)
│ ├─CLOCK_REALTIME_ALARM (Integer)
│ ├─CLOCK_REALTIME_COARSE (Integer)
│ ├─CLOCK_TAI (Integer)
│ ├─CLOCK_THREAD_CPUTIME_ID (Integer)
│ ├─GID (Module)
│ ├─PRIO_PGRP (Integer)
│ ├─PRIO_PROCESS (Integer)
│ ├─PRIO_USER (Integer)
│ ├─RLIMIT_AS (Integer)
│ ├─RLIMIT_CORE (Integer)
│ ├─RLIMIT_CPU (Integer)
│ ├─RLIMIT_DATA (Integer)
│ ├─RLIMIT_FSIZE (Integer)
│ ├─RLIMIT_MEMLOCK (Integer)
│ ├─RLIMIT_MSGQUEUE (Integer)
│ ├─RLIMIT_NICE (Integer)
│ ├─RLIMIT_NOFILE (Integer)
│ ├─RLIMIT_NPROC (Integer)
│ ├─RLIMIT_RSS (Integer)
│ ├─RLIMIT_RTPRIO (Integer)
│ ├─RLIMIT_RTTIME (Integer)
│ ├─RLIMIT_SIGPENDING (Integer)
│ ├─RLIMIT_STACK (Integer)
│ ├─RLIM_INFINITY (Integer)
│ ├─RLIM_SAVED_CUR (Integer)
│ ├─RLIM_SAVED_MAX (Integer)
│ ├─Status (Class)
│ ├─Sys (Module)
│ ├─Tms (Class)
│ ├─UID (Module)
│ ├─WNOHANG (Integer)
│ ├─WUNTRACED (Integer)
│ └─Waiter (Class)
├─Queue (Class)
├─RUBY_COPYRIGHT (String)
├─RUBY_DESCRIPTION (String)
├─RUBY_ENGINE (String)
├─RUBY_ENGINE_VERSION (String)
├─RUBY_PATCHLEVEL (Integer)
├─RUBY_PLATFORM (String)
├─RUBY_RELEASE_DATE (String)
├─RUBY_REVISION (String)
├─RUBY_VERSION (String)
├─Ractor (Class)
│ ├─ClosedError (Class)
│ ├─Error (Class)
│ ├─IsolationError (Class)
│ ├─MovedError (Class)
│ ├─MovedObject (Class)
│ ├─RemoteError (Class)
│ └─UnsafeError (Class)
├─Random (Class)
│ ├─Base (Class)
│ └─Formatter (Module)
│   └─ALPHANUMERIC (Array)
├─Range (Class)
├─RangeError (Class)
├─Rational (Class)
├─RbConfig (Module)
│ ├─CONFIG (Hash)
│ ├─DESTDIR (String)
│ ├─MAKEFILE_CONFIG (Hash)
│ └─TOPDIR (String)
├─Refinement (Class)
├─Regexp (Class)
│ ├─EXTENDED (Integer)
│ ├─FIXEDENCODING (Integer)
│ ├─IGNORECASE (Integer)
│ ├─MULTILINE (Integer)
│ ├─NOENCODING (Integer)
│ └─TimeoutError (Class)
├─RegexpError (Class)
├─RubyVM (Class)
│ ├─AbstractSyntaxTree (Module)
│ │ └─Node (Class)
│ ├─DEFAULT_PARAMS (Hash)
│ ├─INSTRUCTION_NAMES (Array)
│ ├─InstructionSequence (Class)
│ ├─OPTS (Array)
│ └─RJIT (Module)
├─RuntimeError (Class)
├─STDERR (IO)
├─STDIN (IO)
├─STDOUT (IO)
├─ScriptError (Class)
├─SecurityError (Class)
├─Set (Class)
│ ├─InspectKey (Symbol)
│ └─VERSION (String)
├─Signal (Module)
├─SignalException (Class)
├─SizedQueue (Class)
├─StandardError (Class)
├─StopIteration (Class)
├─String (Class)
├─Struct (Class)
├─Symbol (Class)
├─SyntaxError (Class)
├─SyntaxSuggest (Module)
│ └─MiniStringIO (Class)
├─SystemCallError (Class)
├─SystemExit (Class)
├─SystemStackError (Class)
├─TOPLEVEL_BINDING (Binding)
├─Thread (Class)
│ ├─Backtrace (Class)
│ │ └─Location (Class)
│ ├─ConditionVariable (Class)
│ ├─Mutex (Class)
│ ├─Queue (Class)
│ └─SizedQueue (Class)
├─ThreadError (Class)
├─ThreadGroup (Class)
│ └─Default (ThreadGroup)
├─Time (Class)
├─TracePoint (Class)
├─TrueClass (Class)
├─TypeError (Class)
├─UnboundMethod (Class)
├─UncaughtThrowError (Class)
├─UnicodeNormalize (Module)
├─Warning (Module)
└─ZeroDivisionError (Class)
Constant Tree Printer
def print_constants(nested_constants = [Object], nested_last_status = [], seen_constants = [])
  current_constant = nested_constants[-1]
  seen_constants << current_constant
  constants = current_constant.constants(false).select{|c| c.to_s =~ /^[A-Z]/ }.sort
  length = constants.length
  constants.each.with_index{ |constant_name, index|
    is_last = (index + 1) == length
    constant = current_constant.const_get(constant_name)
    print nested_last_status.map{ |is_hidden| is_hidden ? "  " : "│ " }.join
    print is_last ? "└─" : "├─"
    if seen_constants.include?(constant)
      puts '%{name} → %{alias}' % { name: constant_name, alias: constant.name }
    else
      puts '%{name} (%{class})' % { name: constant_name, class: constant.class }
      print_constants(nested_constants + [constant], nested_last_status + [is_last]) if constant.is_a? Module
    end
  }
end

puts "Object (Class)"
print_constants
Also See
https://idiosyncratic-ruby.com/53-the-constant-tree.html
Constant Visibility
Show full content

It is less common, but similar to methods, constants have a visibility attached to them. You have the choice between private and public, and you can also mark a constant deprecated!

Like with methods, the default visibility of a constant is public. Unlike methods, which have a lot of associated methods for metaprogramming, working with constants is easier:

Module.methods.grep /const/
=> [:const_get, :constants, :const_defined?, :const_set, :private_constant,
:public_constant, :deprecate_constant, :const_missing]

Module.private_methods.grep /const/
=> [:remove_const]

Besides some minor idiosyncrasies (like the visibility modifiers, which where introduced at a later time, refer to constants with constant, while the others just use const), their usage is straight forward.

Effects of Visibility Modifications

You must create a constant before you can modify its visibility. When a constant exists, you can use the class method private_constant or deprecate_constant to alter its behaviour. You can change private visibility back to the original state using the public_constant method. You cannot "undeprecate" constants.

Public

This is the default behavior, the constant can be referenced from anywhere and shows up in the constants list:

module Namespace
  module Public
  end
end

Namespace::Public # => Namespace::Public

Namespace.const_defined?(:Public) # => true
Namespace.constants.include?(:Public) # => true
Private

The constant cannot referenced via the :: operator and does not show up in the constants list. They can still be accessed from within the namespace and via const_get:

module Namespace
  module Private
  end

  private_constant :Private
end

Namespace::Private # NameError: private constant Namespace::Private referenced

module Namespace
  Private # => Namespace::Private
end

Namespace.const_defined?(:Private) # => true
Namespace.constants.include?(:Private) # => false

Namespace.const_get(:Private) # => Namespace::Private
Deprecated

This is an additional property, which is also stored in a constant's visibility flag. Whenever you reference it, it will output a ($VERBOSE level independent) warning:

module Namespace
  module Deprecated
  end

  deprecate_constant :Deprecated
end

Namespace::Deprecated # => Namespace::Deprecated
# warning: constant Namespace::Deprecated is deprecated

Namespace.const_defined? :Deprecated # => true
Namespace.constants.include? :Deprecated # => true
More about Constants
https://idiosyncratic-ruby.com/52-constant-visibility.html
½ Kilo of SHA256
Show full content

How many bytes (= ASCII characters) of Ruby code does it take to generate a SHA 256 hash sum of STDIN?

500 Bytes¹
q,z=[3,2].map{|t|i=l=1;(2..330).select{i-1<(l*=i)%i+=1}.map{|e|(e**t**-1*X=2**32).to_i&X-=1}}
s=proc{|n,*m|a=0
m.map{|e|a^=n>>e|n<<32-e}
a}
i=$<.read.b<<128
(i+"\0"*(56.-(w=i.size)%64)+[~-w*8].pack('Q>')).gsub(/.{64}/m){w=$&.unpack'N*'
y=z
64.times{|i|i>15&&w[i]=w[i-16]+(s[v=w[i-15],7,18]^v>>3)+w[i-7]+(s[w[i-2],17,19]^w[i-2]>>10)&X
f=y[7]+s[u=y[4],6,11,25]+(u&y[5]^~u&y[6])+q[i]+w[i]
y=[f+s[y[0],2,13,22]+(y[0]&y[1]^y[0]&y[2]^y[1]&y[2])&X]+y
y[4]=y[4]+f&X}
z=z.zip(y).map{|a,b|a+b&X}}
$><<'%.8x'*8%z

This is based on a submission to a (now defunct) code golf contest and there were "better" submissions, so it is possible to get the code smaller. Looking for pull requests!

¹ The code above actually contains 501 bytes, but you can replace "\0" with a real null byte

Test Script

Save the above code as sha256.rb and create the following test script in the same directory:

# encoding: utf-8

require "digest/sha2"
require "open3"

TEST_SCRIPT = "ruby sha256.rb"
TEST_CASES  = [
  "Idiosyncrätic Ruby",
  "\n",
  "",
  "a"*6000,
  "a"*57
]

TEST_CASES.each{ |test_case|
  expected = Digest::SHA256.hexdigest(test_case)
  actual = nil
  Open3.popen3(TEST_SCRIPT){ |in_, out,|
    in_ << test_case
    in_.close
    actual = out.read
  }
  if expected == actual
    print "."
  else
    $stderr.puts "Fail:
- Expected: #{expected.inspect}
- Actual:   #{actual.inspect}
"
  end
}
Also See
https://idiosyncratic-ruby.com/51-half-kilo-of-sha256.html
Naming Too Good
Show full content

Some words should not be chosen as identifiers for variables, parameters and methods in Ruby, because they clash with core methods or keywords.

As long as you do not define a method with the name of a keyword, Ruby will not complain. Still, it is often better to avoid naming things like existing methods. It carries potential for future bugs and also confuses newcomers. You might change the name in the future, but miss some occurrences, which will then do something completely different. It also makes debugging harder.

A simple workaround is to append an _ to critical identifiers. Some variables names that I find myself wanting to choose sometimes, but which should not (or cannot) be used:

class

class is a keyword so this is invalid code:

class = Thread

When referencing classes in your code the most common convention is to use klass instead.

in

An example where this rarely used keyword (which is part of the for loop syntax) prevents good naming is working with streams:

require 'open3'
Open3.popen3(cmd){ |in, out, err|
  # ...
}
method

A common pattern:

def send_somewhere(method, something)
  # ...
  public_send(method)
  # ...
end

Conflicts with: Object#method

hash

Calculating a hash:

require "digest/sha2"
hash = Digest::SHA256.hexdigest "ö"

Conflicts with: Object#hash

format

"format" is a typical name for a keyword argument:

def something(format: "json")
  # ...
end

I still do it sometimes, but it conflicts with: Kernel#format

display

Object#display should also be avoided!

https://idiosyncratic-ruby.com/50-naming-too-good.html
What the Format?
Show full content

%a %A %b %B %c %d %e %E %f %g %G %i %o %p %s %u %x %X %% 0 $ # + - * space

Ruby comes with a structured alternative to classic string interpolation: This episode will explore format strings, also known as the sprintf syntax.

Recall the normal way of interpolating variables into a string:

v = 42
"--> #{v} <--"
# => "--> 42 <--"

Format strings are different in that they use a string template and bind it to data via the % method:¹

v = 42
"--> %s <--" % v
# => "--> 42 <--"

This might look familiar to you, because dozens of other programming languages also support some flavor of this syntax.

¹ Some people prefer the functional-style Kernel#sprintf or Kernel#format methods, which let you access the same functionality

Four Kinds of References

Format strings separate the string's format (= template) from the actual data. The template contains references in the format of %X (unnamed) or %<name>X (named). The X consists of the formatting type, optionally preceded by other formatting options (see next section). The most basic formatting type is %s, which stands for string. You cannot mix between the two referencing styles; either go with named or unnamed:

# Named format strings take a hash parameter:
"--> %<forty_two>s -- %<forty_three>s <--" % {forty_two: 42, forty_three: 43}
# => --> 42 -- 43 <--

# Named format strings, fancy style (note the dot before `%`):
"--> %<forty_two>s -- %<forty_three>s <--".% forty_two: 42, forty_three: 43
# => --> 42 -- 43 <--

# Shorter, simple/unnamed format strings, take an array as parameter:
"--> %s -- %s <--" % [42, 43]
# => --> 42 -- 43 <--

# If you only need to interpolate a single value, you can shorten this to:
"--> %s <--" % 42
# => --> 42 <--

# Attempt to mix:
"--> %s -- %<second>s <--" % [1, second: 2]
# ArgumentError: named<second> after unnumbered(1)

Conceptionally, this is very similar to how regular expressions handle references. For simple interpolations use simple references, for more complex interpolations named references might be a better fit. Named references serve as inline documentation.

Referencing: Template Style

Besides the two main styles, there exists a shorthand syntax for using format strings with named references:

"--> %{first} -- %{second} <--".% first: 1, second: 2
# => --> 1 -- 2 <--

Though you will lose the ability to apply a formatting type (see below), it is concise and looks good. At its core, it is templating built into the language!

Referencing: Absolute Positioning

The fourth way of referencing the values is the most unreadable one and I would not recommend it. It is a modification of the unnamed reference style: Instead of using the variables in the order you passed them in, you denote the position of the value in the template string using n$:

"--> %2$s -- %1$s <--" % [:first, :second]
# => "--> second -- first <--"

Again, mixing with other types of referencing will lead to errors like this one:

"--> %2$s -- %s <--" % [:first, :second]
# ArgumentError: unnumbered(1) mixed with numbered
Flags, Widths, and Formatting Type

In the previous examples, only basic string substitution was used. But format strings can do more: They can convert a value to another representation using a different formatting type. The formatting type is specified by the last letter of the reference. Besides %s, another common used formatting type is %d, which will put the value through Interger():

"%d" % 1
# => 1

"%d" % "1"
# => 1

"%d" % "string without integer value"
# ArgumentError: invalid value for Integer(): "string without integer value"

There are three different kinds of formatting types: Format as String, format as Integer, and format as Float. See further below for a detailed description. Often, the formatting can be enhanced with special flags or widths. Special options appear between the % sign and the formatting type². For example:

"%.2f" % 1.23456 # => 1.23

This is a float conversion, and the special option "precision of 2" was used. Different formatting types support different kinds of flags and options. The complete syntax of a reference is:

%<name>AB.CX

Syntax Notes Required/Optional % -³ Required <name> Named reference Optional A Flags Optional B Width Optional . C Precision Optional X Formatting type Required

² As fnordfish noted, the syntax can sometimes be quite confusing, such as in:
"Such %<num> cookies" % { num: 100 }
³ Since the % character denotes a reference, you have to use %% to get a single "%"

What follows is a description of all formatting options and types.

Formatting Flags and Options: String Padding

When the format string parser finds a number (which is not a preceded by . or $), it will treat the value as a padding width. The padding width defines the minimum string length, the remaining space will be filled with ASCII spaces. This is a similar functionality like provided by String#ljust:

"%20s" % "Idiosyncratic"
# => "       Idiosyncratic"

It also works with template-style references:

"%20{ruby}".% ruby: "Idiosyncratic"
#=> "       Idiosyncratic"
- | Minus

You can use "negative widths" to right-pad a string:

"%-20s" % "Idiosyncratic"
# => "Idiosyncratic       "
* | Star

A dynamic padding width can be achieved with *. This will require two arguments and does not work with named references:

w = 20
"%*s" % [w, "Idiosyncratic"] # => "       Idiosyncratic"

Note: Alternatively, you can just inline-interpolate the format string:

w = 20
"%#{w}s" % "Idiosyncratic" # => "       Idiosyncratic"

Can be combined with absolute positioned references (e.g. "%1$*2$s").

0 | Zero

The 0 as flag allows you to pad numerical values with zeros instead of spaces:

"%020i" % 1
# => #=> "00000000000000000001"

Will not work for %s, %p, or %c. Can also not be combined with the - flag (right-pad).

Formatting Flags and Options: Algebraic Sign + | Plus

The + flag forces a "+" sign for positive numbers:

"%+d" % 1
# => "+1"

"%+d" % -1
# => "-1"

Will not work for %s, %p, or %c.

⍽ | Space

In a similar manner, the flag, forces positive numbers to leave a space (for a potential "-" sign):

"% d" % 1
# => " 1"

"% d" % -1
# => "-1"

Will not work for %s, %p, or %c.

Other Formatting Flags and Options # | Hash

Modifies the way a numerical value gets converted. What it exactly does varies, so see the description at respective formatting type!

Formatting Types: String %s | String

Does nothing but putting the string argument at the right position.

"%s Ruby" % "Idiosyncratic"
# => "Idiosyncratic Ruby"

Will call to_s on the object passed in.

"%s Ruby" % :Idiosyncratic
# => "Idiosyncratic Ruby"

A padding example:

"%4s" % "A"
# => "   A"

Using the precision syntax, you can pass a hard length limit:

"%.4s" % "Idiosyncratic"
# => "Idio"

Padding + Limit:

"%4.8s" % "12"
# => "  12"

"%4.8s" % "1234567890"
# => "12345678"
%p | Inspect

Calls inspect on the value:

"%p" % "Idiosyncratic"
# => "\"Idiosyncratic\""

Supports the same flags and arguments like %s.

%c | Character

Interpretes a numerical value as a codepoint of the current encoding and converts it to the respective character (the reverse of String#ord, similar to what Array#pack("U") does for UTF-8 strings):

"%c" % 11835
# => "⸻"

Can also be used with a single letter string, which will just be inserted (as if was used with %s):

"%c" % "A"
# => "A"
Formatting Types: Integer

A padding width has the same effect it has for strings. When Integer formatting is used together with a precision it will act as the minimum number of digits to display (which is different from the effect it has in Float formatting):

"%6.4d" % 20
# => "  0020"

The all integer formatting type will run the value through Integer():

"%d" % 42.9
# => "42"

"%d" % "23"
# => "23"

"%d" % "0xff"
# => "255"

"%d" % nil
# TypeError: can't convert nil into Integer
%d, %i, %u | Integer (Decimal Number)

%d, %i and %u all convert the value to an integer (see explanation above):

"%d" % "123"
# => 123
%b, %B | Binary Number

Converts the number to a binary number string:

"%b" % 42
# => "101010"

Note: Another way of achieving the same would be to use Numeric#to_s(2):

42.to_s(2)
# => "101010"

Negative numbers will be convert to two's complement, preceded by "..1" representing an infinite string of leading "1"s:

"%b" % -42
# => "..1010110"

This is not the case when the + or flag are in use:

"%+b" % -42
# => "-101010"

Alternative conversion format (# flag) will prepend "0b" (except for 0):

"%#b" % 42
# => "0b101010"

The %B type has exactly the same behavior as %b, except that it will use an uppercase "B" in alternative conversion format:

"%#B" % 42
# => "0B101010"
%o | Octal Number

Converts the number to an octal number string:

"%o" % 42
# => "52"

Note: Another way of achieving the same would be to use Numeric#to_s(8):

42.to_s(8)
# => "52"

Negative numbers will be convert to two's complement, preceded by "..7" representing an infinite string of leading "7"s:

"%o" % -42
# => "..726"

This is not the case when the + or flag are in use:

"%+o" % -42
# => "-52"

Alternative conversion format (# flag) will prepend "0" (except for 0):

"%#o" % 42
# => "052"
%x, %X | Hexadecimal Number

Converts the number to a hexadecimal number string:

"%x" % 42
# => "2a"

The %X type has the same behavior, except that it will used uppercased letters:

"%X" % 42
# => "2A"

Note: Another way of achieving the same would be to use Numeric#to_s(16):

42.to_s(16)
# => "2a"

Negative numbers will be convert to two's complement, preceded by "..f" representing an infinite string of leading "f"s:

"%x" % -42
# => "..fd6"

This is not the case when the + or flag are in use:

"%+x" % -42
# => "-2a"

Alternative conversion format (# flag) will prepend "0x" (except for 0):

"%#x" % 42
# => "0x2a"

Or "0X" when using big %X:

"%#X" % 42
# => "0X2A"
Formatting Types: Float %f | Float

This will convert the argument to a floating point number:

"%f" % 42
# => "42.000000"

The precision syntax defines the actual precision here:

"%.2f" % 42
# => "42.00"

"%.3f" % 42
# => "42.000"
%e, %E | Float in Exponential Notation

Converts the value to a float in exponential notation (with 6 digits before the exponent):

"%e" % 42
# => "4.200000e+01"

"%e" % 0.00000023
# => "2.300000e-07"

"%e" % -1_000_000_000
# => "-1.000000e+09"

The precision syntax defines the number of digits before the exponent:

"%.2e" % 42
#=> "4.20e+01"

"%.4e" % 42
# => "4.2000e+01"

Using big %E will uppercase the "E" in the result:

"%E" % 1
# => "1.000000E+00"
%g, %G | Float in Normal or Exponential Notation

Converts a float either to normal representation 1.23 or exponential notation (see %e above). Which one is chosen, depends on the number: If the exponent is more than 5 or less than -4, exponential format is used:

>> "%g" % 100000
# => "100000"

>> "%g" % 1000000
# => "1e+06"

>> "%g" % 0.0001
# => "0.0001"

>> "%g" % 0.00001
# => "1e-05"

Will use a given (positive) precision as the point to decide between both notation forms:

"%.2g" % 10
# => "10"

"%.2g" % 100
# => "1e+02"

Using big %G will uppercase the "E" in the result:

"%G" % 1234567890
# => "1.23457E+09"
%a, %A | Analyze Float

Converts a float into a format revealing its underlying representation, which is divided into significant (mantissa) and exponent. The result is a string of the following format:

- (if negative) + 0x + significant (hexadecimal) + p + exponent sign + exponent (decimal)

Examples:

"%a" % 1
# => "0x1p+0"

"%a" % 1.2
# => "0x1.3333333333333p+0"

"%a" % 1.23
# => "0x1.3ae147ae147aep+0"

"%a" % 0.1
# => "0x1.999999999999ap-4"

"%a" % 10000000000
# => "0x1.2a05f2p+33"

"%a" % 0.000000001
# => "0x1.12e0be826d695p-30"

Using big %A will uppercase all letters:

"%A" % -12.34
# => "-0X1.8AE147AE147AEP+3"
Classic Interpolation vs. Format Strings Advantages of Format Strings
  • Values sit side by side, instead of being all around the place
  • Simple access to string padding functionality
  • Advanced (and explicit) numerical conversions
  • Can be used as built-in mini templating engine
Advantages of Classical Interpolation
  • Interpolation happens on syntax level, no method calling involved
  • Inline interpolation quicker to write/more convenient for simple interpolations
  • Not possible to mismatch values and format string references
Resources Also See
https://idiosyncratic-ruby.com/49-what-the-format.html
Ruby TRICKS of 2015
Show full content

Ruby was initially designed to be a successor of the Perl programming language, which also means that it inherited a lot of Perl's expressiveness. To celebrate this, the TRIC¹ contest was invented:

  • Write the most Transcendental, Imbroglio Ruby program!
  • Illustrate some of the subtleties (and design issues) of Ruby!
  • Show the robustness and portability of Ruby interpreters!
  • Stabilize the spec of Ruby by the presence of valuable but unmaintainable code!

The best submissions were awarded at the Japanese Ruby Kaigi conference and also included in the Ruby source, for educational purpose. The winning submissions² of 2015 were:

¹ Transcendental Ruby Imbroglio Contest
² All code is MIT licensed, Copyright (c) 2015, TRICK Winners and Judges

1st Place: "Best piphilology"

By kinaba (remarks)

big, temp = Array 100000000**0x04e2
srand big
alias $curTerm $initTerm

Numeric
Interrupt

big += big
printout _pi_ finish if $never
init ||= big
$counter ||= 02

private
@mainloop
while 0x00012345 >= $counter

  Rational aprx = 3.141592r
  numbase = 0o0000

  @justonce
  def increment
    $initTerm ||= Integer srand * 0x00000002
    srand $counter += 0x00000001

    $noaction
    Integer rand
    $noaction
    rand
    rand
    alias $line_cnt $.
  end

  @lets_just
  @assume
  diameter = 100000

  @you
  @then_have
  permtr |= +3_14159

  return if $nomeaning

  @onlyuse
  increment

  beautiful computer action if $nothing
  $sigmaTerm ||= init
  $curTerm /= srand and init
  pi, = Integer $sigmaTerm unless $nomean

  iterator?
  $counter += 1
  atan real_one multiplied by__four unless
  srand +big && $counter >> 0b1

  Enumerable
  Fixnum
  Bignum
  Math
  Complex
  Comparable
  TrueClass
  Dir
  Encoding
  Data
  Hash
  Method
  Enumerator
  Exception
  Fiber
  Errno
  FalseClass
  Mutex
  NilClass
  IO
  GC

  num = numbase |= srand

  ENV
  Float
  MatchData
  Proc
  TracePoint
  KeyError
    p   or
  FileTest
  File
  EOFError
    p
    p
    p
  Binding
  Time
  Class

  $sigmaTerm += $curTerm
  puts a HelloWorld if $nomean
  SystemExit

  !LoadError
  31i
  3.1415e0
  Array 14 + 3
  IndexError
  Range
  false
  55555
  NameError

  Object
  @ori
    @ent
  RubyVM

  pi += 3_3_1_3_8

  @use
  @lots_of
  @keywords
  begin
    self
    $noaction
    not $important
    nil
    __FILE__.object_id
  rescue
    next
    redo if __LINE__
    defined? +$nomeaning
    $noaction
    $nomean
    break $never
  ensure
    class PiCompute
    end
  end

  This code cannot _ be executed with typical style unless true
  $curTerm *= num
end

@ll_set
@re_U_ok

$Enjoy
$Superb
$TRICK15 and a number

print pi

All valid syntax! Run it and it will output the first 1000 digits of Pi:

31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275900994657640789512694683983525957098258226205224894077267194782684826014769909026401363944374553050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382686838689427741559918559252459539594310499725246808459872736446958486538367362226260991246080512438843904512441365497627807977156914359977001296160894416948685558484063534220722258284886481584560285060168427394522674676788952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288797108931456691368672287489405601015033086179286809208747609178249385890097149096759852613655497818931297848216829989487226588048575640142704775551323796414515237462343645428584447952658678210511413547357395231134271661021359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435064302184531910484810053706146806749192781911979399520614196634287544406437451237181921799983910159195618146751426912397489409071864942319615679452080951465502252316038819301420937621378559566389377870830390697920773467221825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539057962685610055081066587969981635747363840525714591028970641401109712062804390397595156771577004203378699360072305587631763594218731251471205329281918261861258673215791984148488291644706095752706957220917567116722910981690915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398315019701651511685171437657618351556508849099898599823873455283316355076479185358932261854896321329330898570642046752590709154814165498594616371802709819943099244889575712828905923233260972997120844335732654893823911932597463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100449293215160842444859637669838952286847831235526582131449576857262433441893039686426243410773226978028073189154411010446823252716201052652272111660396665573092547110557853763466820653109896526918620564769312570586356620185581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318586769751456614068007002378776591344017127494704205622305389945613140711270004078547332699390814546646458807972708266830634328587856983052358089330657574067954571637752542021149557615814002501262285941302164715509792592309907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111790429782856475032031986915140287080859904801094121472213179476477726224142548545403321571853061422881375850430633217518297986622371721591607716692547487389866549494501146540628433663937900397692656721463853067360965712091807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862947265473642523081770367515906735023507283540567040386743513622224771589150495309844489333096340878076932599397805419341447377441842631298608099888687413260472156951623965864573021631598193195167353812974167729478672422924654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001593776471651228935786015881617557829735233446042815126272037343146531977774160319906655418763979293344195215413418994854447345673831624993419131814809277771038638773431772075456545322077709212019051660962804909263601975988281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267945612753181340783303362542327839449753824372058353114771199260638133467768796959703098339130771098704085913374641442822772634659470474587847787201927715280731767907707157213444730605700733492436931138350493163128404251219256517980694113528013147013047816437885185290928545201165839341965621349143415956258658655705526904965209858033850722426482939728584783163057777560688876446248246857926039535277348030480290058760758251047470916439613626760449256274204208320856611906254543372131535958450687724602901618766795240616342522577195429162991930645537799140373404328752628889639958794757291746426357455254079091451357111369410911939325191076020825202618798531887705842972591677813149699009019211697173727847684726860849003377024242916513005005168323364350389517029893922334517220138128069650117844087451960121228599371623130171144484640903890644954440061986907548516026327505298349187407866808818338510228334508504860825039302133219715518430635455007668282949304137765527939751754613953984683393638304746119966538581538420568533862186725233402830871123282789212507712629463229563989898935821167456270102183564622013496715188190973038119800497340723961036854066431939509790190699639552453005450580685501956730229219139339185680344903982059551002263535361920419947455385938102343955449597783779023742161727111723643435439478221818528624085140066604433258885698670543154706965747458550332323342107301545940516553790686627333799585115625784322988273723198987571415957811196358330059408730681216028764962867446047746491599505497374256269010490377819868359381465741268049256487985561453723478673303904688383436346553794986419270563872931748723320837601123029911367938627089438799362016295154133714248928307220126901475466847653576164773794675200490757155527819653621323926406160136358155907422020203187277605277219005561484255518792530343513984425322341576233610642506390497500865627109535919465897514131034822769306247435363256916078154781811528436679570611086153315044521274739245449454236828860613408414863776700961207151249140430272538607648236341433462351897576645216413767969031495019108575984423919862916421939949072362346468441173940326591840443780513338945257423995082965912285085558215725031071257012668302402929525220118726767562204154205161841634847565169998116141010029960783869092916030288400269104140792886215078424516709087000699282120660418371806535567252532567532861291042487761825829765157959847035622262934860034158722980534989650226291748788202734209222245339856264766914905562842503912757710284027998066365825488926488025456610172967026640765590429099456815065265305371829412703369313785178609040708667114965583434347693385781711386455873678123014587687126603489139095620099393610310291616152881384379099042317473363948045759314931405297634757481193567091101377517210080315590248530906692037671922033229094334676851422144773793937517034436619910403375111735471918550464490263655128162288244625759163330391072253837421821408835086573917715096828874782656995995744906617583441375223970968340800535598491754173818839994469748676265516582765848358845314277568790029095170283529716344562129640435231176006651012412006597558512761785838292041974844236080071930457618932349229279650198751872127267507981255470958904556357921221033346697499235630254947802490114195212382815309114079073860251522742995818072471625916685451333123948049470791191532673430282441860414263639548000448002670496248201792896476697583183271314251702969234889627668440323260927524960357996469256504936818360900323809293459588970695365349406034021665443755890045632882250545255640564482465151875471196218443965825337543885690941130315095261793780029741207665147939425902989695946995565761218656196733786236256125216320862869222103274889218654364802296780705765615144632046927906821207388377814233562823608963208068222468012248261177185896381409183903673672220888321513755600372798394004152970028783076670944474560134556417254370906979396122571429894671543578468788614445812314593571984922528471605049221242470141214780573455105008019086996033027634787081081754501193071412233908663938339529425786905076431006383519834389341596131854347546495569781038293097164651438407007073604112373599843452251610507027056235266012764848308407611830130527932054274628654036036745328651057065874882256981579367897669742205750596834408697350201410206723585020072452256326513410559240190274216248439140359989535394590944070469120914093870012645600162374288021092764579310657922955249887275846101264836999892256959688159205600101655256375678

But that is not all, Pi is encoded a second time! The program is a Piphilology: Each token's length represents the next digit (and 0 is represented by a token length of 10)! Save the program as entry.rb and run the following one-liner to verify:

$ ruby -r ripper -e \
  'puts Ripper.tokenize(STDIN).grep(/\S/).map{|t|t.size%10}.join' < entry.rb

Output:

31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652
2nd Place: "Most unreadable ALU"

By Keisuke Nakano (remarks)

If the number is even, divide it by two, otherwise, multiply it by three and add one. …and eventually the number becomes 1. This is known as the Collatz conjecture. The following one-liner calculates this series, without using any conditionals or arithmetic operations:

%%%while eval '_=%%r%%(.)...\1=%%=~[%%%%,,,,,%%%s  ?=]*%%%%%%#"]*%%%%3x+1?%%'.% %%",%*p(_||=eval($**%%%))

To try it out, save the code to entry.rb and called it with a number! Example of $ ruby entry.rb 42:

42
21
64
32
16
8
4
2
1
3rd Place: "Doubling amphisbaena award"

By monae (remarks)

          ;;  ;;          ;;  ;;
           ;;  ;;          ;;  ;;
        ;;eval$s        =%q[i=1#
         eval(%q[        xxxxxxxx
        xx  xxxx  xx    xx  xxxx  xx
         xx  xxxx  xx    xx  xxxx  xx
            xxxxxxxx        xxxxxxxx
             xxxxxxxx        xxxxxxxx
  xx  xx  xxxxxxxxxx  xx  xxxxxxxx
   j,  t,  p=0,[?;],"  ev  al$s=%qx
[#$s]".split*"";i,j,t=i-j,i+j,(x
 [b=?\s]*j.abs+t).map{|s|r=t.shix
ft  ||b;r.gsub!(?;){p.slice!0}if  $x
 f|  |=p>p=p.center(i*i+j*j,?;);r  ,x
    s=[s,r]if(i*j<0);(b*i.abs+s).ljx
     ust(r.size).gsub(b){r[$`.size]|x
  |b}}unti  l$  f;puts(t)#  xx  xx
   xxxxxxxx  xx  xxxxxxxxxx  xx  xx
xxxxxxxx        xxxxxxxx
 xxxxxxxx        xxxxxxxx
xx  xxxx  xx    xx  xxxx  xx
 xx  xxxx  xx    xx  xxxx  xx
    xxxxxxxx        x].gsub\
     /x.*|\s/        ,"")#];;
    ;;  ;;          ;;  ;;
     ;;  ;;          ;;  ;;

Save this program as entry.rb and run it with:

$ ruby entry.rb | ruby | ruby | ruby # ...

Then watch it duplicating!

4th Place: "Least general solver"

By Benoit Daloze (remarks)

What is your visual impression when looking at the following code?

class String;def[]*a;$*<<a;b;end;end;
_=0;z="C=Fiber;s=$*;a=*0..8;l=C.new{e
xit},*a.product(a).select{|r,c|s[r][c
]==0}."[1,9,_, _,_,8, _,_,5]+"map{|r,
 c|C.ne"[_,_,2, _,5,_, _,8,9]+"w{o=s[r
][c];l"[8,_,6, 7,4,_, _,_,_]+"oop{(1.
.9).map{|n|C.yield(s[r][c]=n)if a.non
e?{|k|"[_,_,_, _,_,4, _,9,2]+"s[r][k]
==n||s"[_,2,3, _,7,_, 8,1,_]+"[k][c]=
=n||s["[5,6,_, 8,_,_, _,_,_]+"r-r%3+k
%3][c-c%3+k/3]==n}};s[r][c]=o;C.yield
}}},C."[_,_,_, _,2,7, 9,_,3]+"new{loo
p{puts"[9,3,_, _,8,_, 1,_,_]+" s.map{
|r|r*'"[2,_,_, 5,_,_, _,4,8]+" '}<<''
;C.yield}};c=l[i=1];loop{c=l[i+=c.res
ume ? 1:-1]}";eval z.tr ?\n,''

There is a Sudoku embedded! Run the code to solve it!

5th Place: "Most general solver"

By Keisuke Nakano (remarks)

This handy one-liner is a SAT solver based on Ruby's regex engine:

_='s %sSATISFIABLE';puts eval$<.read.gsub(/.*p.*?(\d+).*?$|\d+/m){$1?%w[?-* +'=-'=~/#{'(-?)'* }-*=(?=]*$1:$&>?0?"\\#$&$|":'$)(?='}+')/x?[_%p%i=0,[*$~].map{|x|x>?-?:v:eval(x+?1)*i-=1}*" "]:_%:UN'

See the description for more info! Sample files to pipe in:

Other Awarded Submissions Also See
https://idiosyncratic-ruby.com/48-ruby-tricks-of-2015.html
Ruby TRICKS of 2013
Show full content

Ruby was initially designed to be a successor of the Perl programming language, which also means that it inherited a lot of Perl's expressiveness. To celebrate this, the TRIC¹ contest was invented:

  • Write the most Transcendental, Imbroglio Ruby program!
  • Illustrate some of the subtleties (and design issues) of Ruby!
  • Show the robustness and portability of Ruby interpreters!
  • Stabilize the spec of Ruby by the presence of valuable but unmaintainable code!

The best submissions were awarded at the Japanese Ruby Kaigi conference and also included in the Ruby source, for educational purpose. The winning submissions² of 2013 were:

¹ Transcendental Ruby Imbroglio Contest
² All code is MIT licensed, Copyright (c) 2013, TRICK Winners and Judges

1st Place: "Best pangram"

By kinaba (remarks)

The program prints each ASCII character from 0x20 ' ' to 0x7e '~' exactly once:

!@THEqQUICKbBROWNfFXjJMPSvVLAZYDGgkyz&[%r{\"}mosx,4>6]|?'while(putc 3_0-~$.+=9/2^5;)<18*7and:`#

While this would not be such a complicated thing to accomplish, reconsider the program after reading the second constraint!

The program contains each ASCII character from 0x20 ' ' to 0x7e '~' exactly once.

This is what it outputs:

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~%
2nd Place: "Most Readable"

By Shinichiro Hamaji (remarks)

begin with an easy program.
you should be able to write
a program unless for you,
program in ruby language is
too difficult. At the end
of your journey towards the
ultimate program; you must
be a part of a programming
language. You will end if
you != program

This program does exactly nothing, but nevertheless, it is all valid syntax!

3rd Place: "Most classic"

By Yusuke Endoh (remarks)

Guess what this one does:

          eval$C=%q(at_exit{
          open("/dev/dsp","wb"){|g|h=[0]*80
          $><<"\s"*18+"eval$C=%q(#$C);S=%:"
          (S<<m=58).lines{|l|s=[128]*n=20E2
          t=0;           h.map!{|v|d=?!==l[
          t]?1                         :(l[
          t]==                         ?#)?
          0*v=                         6:03
          (v<1                         ?[]:
          0..n                         -1).
          each                         {|z|
          s[z]                         +=2*
  M.sin(($*[0]                         ||1)
.to_f*M.sin(y=                 40*(z+m)*2**
(t/12E0)/463)+               y)*(v-z*d/n)};
t+=1;v-d};m+=                n;g.flush<<(s.
  pack"C*");                 puts(l)}}};M=
                               Math);S=%:

         Jesu, Joy of Man's Desiring
            Johann Sebastian Bach

  #
  |                       #
  |                         #
              #      #    #   #
              |      |    |      #
              |      |   #     #
           #           #  #    #
           |           |  |        #
           |           |    #    #
      #                   #   #  #
      |                   |   |       #
      |                   | #        #
           #           #      #       #
           |           |      |  #
           |           |  #   #
           #      #    #  #
           |      |    |    #
           |      |  #        #
    #           #      #       #
    |           |      |         #
    |           |        #         #
      #              #    #      #
      |              |    |    #
      |              |        #
       #           #   #    #
       |           |   |      #
       |          #|      #
         #      #  |     #
         |      |  |      #
         |         | #      #
             #  #    #      #
             |  |        #  |
             |  |         # #
         #               #  #  #
         |               |  | #
         |               |  #
              #      #    #   #
              |      |    #   |
              |          #  # |
           #  #           #   #
           |  |           |      #
           |  |          #     #
       #               #  #    #
       |               |  |        #
       |               |    #    #
      #                   #   #  #
      |                   |   |       #
      |                   | #        #
           #           #      #       #
           |           |      |  #
           |           |  #   #
         #        #    #  #
         |        |    |    #
         |        |       #   #
       #           #   #    #
       |           |        |    #
       |           |     #     #
        #              #  #   #
        |              |  | #
        |              #  #
         #      #    #
         |      |    |    #
         |         # |   #
  #               #  #    #
  |               |  |    |
  |               |  |    |
  |               |  |    |
  |               |  |    |
  |               |  |    |
  |               |  |    |
  |               |  |    |
  |               |  |    |
  |               |  |    |
  |               |  |    |
  |               |  |    :

Right! It will play some lovely classical music! Run it with:³

$ padsp ruby entry.rb

³ See Limitations for how to play it on Mac OS

Also See Other Awarded Submissions
https://idiosyncratic-ruby.com/47-ruby-tricks-of-2013.html
The Art of Arguments
Show full content

There is nothing easier than parsing the command-line arguments given to your Ruby program: It is an array found in the special variable $*:

$ ruby -e 'p $*' -- some command line --arguments
["some", "command", "line", "--arguments"]
That is Too Easy!

The trouble begins with supporting common arguments conventions, like GNU's, and combining it with Ruby DSLs. This has lead to hundreds of Ruby libraries parsing command line options, even the standard library includes two ways: OptParse and GetoptLong.

Which One is the Best?

Despite all the options above, I found myself using $* directly very often, because it is simple and does not require remembering the API of an option parser. Unfortunately, this also means loosing the ability to understand the mentioned conventions for command-line options.

This changed the day I came across the minimist option parser for NodeJS! It evolved out of the Optimist option parser, which has the following slogan:

With Optimist, the options are just a hash! No optstrings attached.

— node-optimist readme
We Need This in Ruby!

Why not?¹ It features a superior API:

$ ruby example/parse.rb -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
{ _: [ 'foo', 'bar', 'baz' ],
  x: 3,
  y: 4,
  n: 5,
  a: true,
  b: true,
  c: true,
  beep: 'boop' }

The contents of parse.rb

require 'rationalist'
p Rationalist.parse(ARGV)
  • You always get back a Ruby hash
  • Options get their own key
  • Untreated arguments go to :_
  • The default usage is simple, yet advanced processing is easily configurable

¹ By the way: On its syntactical surface, JavaScript and Ruby have more in common than you would usually expect. Take arrays [] and hashes {}: They just look very similar!
² To continue the tradition of Perl-style two-letter variables, we should probably do:
$★ = Rationalist.parse(ARGV)

https://idiosyncratic-ruby.com/46-the-art-of-arguments.html
Constant Shuffle
Show full content

Today, another snippet from the category don't try at home, might have unforeseeable consequences!

Constant assignment¹ is not permanent in Ruby, so it is perfectly valid to do this:

module A
end

class B
  def initialize
    p 42
  end
end

A, B = B, A
# warning: already initialized constant A
# warning: previous definition of A was here
# warning: already initialized constant B
# warning: previous definition of B was here
A.new  #=> #<B:0x00000002744008>
# 42

¹ As a side note: There is also Module#remove_const, which will delete the constant, but not the module! Quoting the documentation: "If that constant referred to a module, this will not change that module's name and can lead to confusion"

o = Object.send(:remove_const, :Object)
Object.constants # NameError: uninitialized constant Object
o # => Object
The Ruby Shuffle

Developing the swapping idea further, for maximal confusion:

require 'stringio'
def shuffle_ruby(n=rand(50))
  mod, os, e, sio = Module, ObjectSpace, Exception, StringIO
  stderr, $stderr = $stderr, sio.new
  n.times{
    begin
      m1 = os.each_object(mod).to_a.sample
      m2 = os.each_object(mod).to_a.sample
      puts "Swap #{m1} and #{m2}"
      eval "#{m1}, #{m2} = #{m2}, #{m1}"
    rescue e
    end
  }
  $stderr = stderr
  puts "Ruby shuffled (#{n} swaps)"
end
https://idiosyncratic-ruby.com/45-constant-shuffle.html
Top Level Binding
Show full content

In case you have wondered, what this top-level constant TOPLEVEL_BINDING is all about:

It is, as its name suggest, the Binding of your script's main scope:

a = 42
p binding.local_variable_defined?(:a) # => true
p TOPLEVEL_BINDING.local_variable_defined?(:a) # => true

def example_method
  p binding.local_variable_defined?(:a) # => false
  p TOPLEVEL_BINDING.local_variable_defined?(:a) # => true
end

example_method
What is a practical use of it?

Besides being a general default binding for your application (which is used in IRB), it can act also as the missing Binding.new:

clean_binding = TOPLEVEL_BINDING.dup

Assuming a more complex/structured application (instead of a single-file script), the top-level binding is mostly empty or consists of just a few important variables.

In fact, this is how it is utilized in stdlib's ERB implementation.

https://idiosyncratic-ruby.com/44-top-level-binding.html
New Ruby Startup
Show full content

What happens when you invoke the Ruby interpreter, even before it executes your first line of code? Actually a lot! A few observations:

Initial Load Path

These are all locations you can Kernel#require from:

$ ruby --disable-all -e 'puts $LOAD_PATH.map{ |path| "- #{path}" }'
  • …/ruby-3.2.0/lib/ruby/site_ruby/3.2.0
  • …/ruby-3.2.0/lib/ruby/site_ruby/3.2.0/x86_64-linux
  • …/ruby-3.2.0/lib/ruby/site_ruby
  • …/ruby-3.2.0/lib/ruby/vendor_ruby/3.2.0
  • …/ruby-3.2.0/lib/ruby/vendor_ruby/3.2.0/x86_64-linux
  • …/ruby-3.2.0/lib/ruby/vendor_ruby
  • …/ruby-3.2.0/lib/ruby/3.2.0
  • …/ruby-3.2.0/lib/ruby/3.2.0/x86_64-linux
Initial Loaded Features

These are core libraries that will always get loaded by Ruby:

$ ruby --disable-all -e 'puts $LOADED_FEATURES.map{ |lib| "- #{lib} "}'
  • enumerator.so ¹
  • thread.rb ¹
  • fiber.so ¹
  • rational.so ¹
  • complex.so ¹
  • ruby2_keywords.rb ¹
  • …/ruby-3.2.0/lib/ruby/3.2.0/x86_64-linux/enc/encdb.so
  • …/ruby-3.2.0/lib/ruby/3.2.0/x86_64-linux/enc/trans/transdb.so

¹ Not actual files. They show up here for backward compatibility because they were moved from the standard library (thus had to be loaded first) to the core.

Initial Memory Consumption

Measured with Ruby 3.2.2 on an ubuntu machine:

$ ruby --disable-all -e'puts"%.2f MB".%`ps -o rss -p#$$$$`.strip.split.last.to_f/1024'

20.14 MB

Initial Ruby Objects

Via: ObjectSpace.each_object

$ ruby --disable-all -e 'puts \
" Ruby Object                   | Count\n" +
"-------------------------------|------\n" +
ObjectSpace.each_object.group_by(&:class).map{|k,v| [k, v.size]}.
sort_by(&:last).reverse.map{|k,v| "#{k.to_s.rjust(30)} | #{v}" }.
join("\n")'
Ruby Object Count String 3327 Array 1087 Class 288 Encoding 103 Module 23 Hash 5 Float 4 IO 3 Object 3 Symbol 3 fatal 2 ARGF.class 1 SystemStackError 1 NoMemoryError 1 Ractor 1 RubyVM 1 Thread 1 Binding 1 IOError 1 ThreadGroup 1 Integer 1 Complex 1 File 1 Enumerator 1

Not listed in this table are "immediate" objects that are directly embedded in Ruby's underlying object system, for example, small integers.

Initial Numbers

Some interesting magic numbers:

$ ruby --disable-all -e 'puts ObjectSpace.each_object(Numeric).
map{ |n| "- #{n} (#{n.class})" }'
  • 0+1i (Complex)
  • 18446744073709551615 (Integer)
  • NaN (Float)
  • Infinity (Float)
  • 1.7976931348623157e+308 (Float)
  • 2.2250738585072014e-308 (Float)
Initial Internal Objects

Via: ObjectSpace.count_objects

$ ruby --disable-all -e 'puts \
" Object    | Count\n" +
"-----------|------\n" +
ObjectSpace.count_objects.to_a.sort_by(&:last).
reverse.map{|k,v| "#{k.to_s.rjust(10)} | #{v}" }.
join("\n")'
Object Count TOTAL 11460 T_IMEMO 3514 T_STRING 3328 FREE 2696 T_ARRAY 1113 T_CLASS 548 T_DATA 181 T_ICLASS 27 T_MODULE 23 T_HASH 10 T_OBJECT 7 T_FILE 4 T_FLOAT 4 T_SYMBOL 3 T_COMPLEX 1 T_BIGNUM 1 Initial Symbols

Via: Symbol.all_symbols

Related: Grammar rules for symbols

$ puts Symbol.all_symbols.sort.
map{ |s| s.inspect.sub("`", "\\`").gsub(/'/,"\\'") }.join(" ")

All symbols:

:"" :! :!= :!~ :"\"" :"#" :"$" :$! :$" :$$ :$& :$ :$* :$+ :$, :$-0 :$-F :$-I :$-W :$-a :$-d :$-i :$-l :$-p :$-v :$-w :$. :$/ :$0 :$: :$; :$< :$= :$> :$? :$@ :$DEBUG :$FILENAME :$LOADED_FEATURES :$LOAD_PATH :$PROGRAM_NAME :$VERBOSE :$\ :$_ :$:$ :$stderr :$stdin :$stdout :$~ :% :& :"&&" :"&." :""" :"(" :")" :* :** :+ :+@ :"," :- :-@ :"." :".." :"..." :/ :":" :"::" :";" :< :<< :<= :<=> :"<CFUNC>" :"<IFUNC>" :"=" :== :=== :=~ :> :>= :>> :"?" :"@" :@CALL_DATA :@IC :@IVC :@RB_BUILTIN :@VALUE :@attr_index_t :@compile_branch :@compile_status :@denominator :@gem_prelude_index :@image :@inlined_call_context :@iseq_inline_constant_cache :@iseq_inline_constant_cache_entry :@iseq_inline_iv_cache_entry :@iseq_inline_storage_entry :@mjit_options :@numerator :@path :@ractor :@rb_builtin_function :@rb_call_data :@rb_callable_method_entry_struct :@rb_callcache :@rb_callinfo :@rb_control_frame_t :@rb_cref_t :@rb_execution_context_struct :@rb_execution_context_t :@rb_iseq_constant_body :@rb_iseq_location_t :@rb_iseq_struct :@rb_iseq_t :@rb_method_definition_struct :@rb_method_iseq_t :@rb_method_type_t :@rb_mjit_compile_info :@rb_mjit_unit :@rb_serial_t :@rb_shape :@rb_shape_t :@real :@shape_id_t :AFTER_OUTPUT :ALT_SEPARATOR :ANSI_X3_4_1968 :APPEND :ARGF :ARGV :ASCII :ASCII_8BIT :AbstractSyntaxTree :AccessError :AllocationError :ArgumentError :ArithmeticSequence :Array :BASE_SLOT_SIZE :BIG5 :BIG5_HKSCS :BIG5_HKSCS_2008 :BIG5_UAO :BIG_ENDIAN :BINARY :Backtrace :Base :BasicObject :Big5 :Big5_HKSCS :Big5_HKSCS_2008 :Big5_UAO :Binding :BitField :Bool :Buffer :C :CALL_DATA :CESU_8 :CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID :CLOCK_BOOTTIME :CLOCK_BOOTTIME_ALARM :CLOCK_MONOTONIC :CLOCK_MONOTONIC_COARSE :CLOCK_MONOTONIC_RAW :CLOCK_PROCESS_CPUTIME_ID :CLOCK_REALTIME :CLOCK_REALTIME_ALARM :CLOCK_REALTIME_COARSE :CLOCK_TAI :CLOCK_THREAD_CPUTIME_ID :CP1250 :CP1251 :CP1252 :CP1253 :CP1254 :CP1255 :CP1256 :CP1257 :CP1258 :CP437 :CP50220 :CP50221 :CP51932 :CP65000 :CP65001 :CP720 :CP737 :CP775 :CP850 :CP852 :CP855 :CP857 :CP860 :CP861 :CP862 :CP863 :CP864 :CP865 :CP866 :CP869 :CP874 :CP878 :CP932 :CP936 :CP949 :CP950 :CP951 :CREAT :CRLF_NEWLINE_DECORATOR :CR_NEWLINE_DECORATOR :CSWINDOWS31J :CType :CUR :Chain :Class :ClosedError :ClosedQueueError :Comparable :CompatibilityError :Complex :ConditionVariable :Constants :Converter :ConverterNotFoundError :CsWindows31J :DATA :DEBUG :DEFAULT_PARAMS :DEFAULT_SIZE :DIG :DIRECT :DSYNC :Data :Default :DidYouMean :Dir :DomainError :E :E2BIG :EACCES :EADDRINUSE :EADDRNOTAVAIL :EADV :EAFNOSUPPORT :EAGAIN :EAGAINWaitReadable :EAGAINWaitWritable :EALREADY :EAUTH :EBADARCH :EBADE :EBADEXEC :EBADF :EBADFD :EBADMACHO :EBADMSG :EBADR :EBADRPC :EBADRQC :EBADSLT :EBCDIC_CP_US :EBFONT :EBUSY :ECANCELED :ECAPMODE :ECHILD :ECHRNG :ECOMM :ECONNABORTED :ECONNREFUSED :ECONNRESET :EDEADLK :EDEADLOCK :EDESTADDRREQ :EDEVERR :EDOM :EDOOFUS :EDOTDOT :EDQUOT :EEXIST :EFAULT :EFBIG :EFTYPE :EHOSTDOWN :EHOSTUNREACH :EHWPOISON :EIDRM :EILSEQ :EINPROGRESS :EINPROGRESSWaitReadable :EINPROGRESSWaitWritable :EINTR :EINVAL :EIO :EIPSEC :EISCONN :EISDIR :EISNAM :EKEYEXPIRED :EKEYREJECTED :EKEYREVOKED :EL2HLT :EL2NSYNC :EL3HLT :EL3RST :ELAST :ELIBACC :ELIBBAD :ELIBEXEC :ELIBMAX :ELIBSCN :ELNRNG :ELOOP :EMACS_MULE :EMEDIUMTYPE :EMFILE :EMLINK :EMSGSIZE :EMULTIHOP :ENAMETOOLONG :ENAVAIL :END :ENEEDAUTH :ENETDOWN :ENETRESET :ENETUNREACH :ENFILE :ENOANO :ENOATTR :ENOBUFS :ENOCSI :ENODATA :ENODEV :ENOENT :ENOEXEC :ENOKEY :ENOLCK :ENOLINK :ENOMEDIUM :ENOMEM :ENOMSG :ENONET :ENOPKG :ENOPOLICY :ENOPROTOOPT :ENOSPC :ENOSR :ENOSTR :ENOSYS :ENOTBLK :ENOTCAPABLE :ENOTCONN :ENOTDIR :ENOTEMPTY :ENOTNAM :ENOTRECOVERABLE :ENOTSOCK :ENOTSUP :ENOTTY :ENOTUNIQ :ENV :ENXIO :EOFError :EOPNOTSUPP :EOVERFLOW :EOWNERDEAD :EPERM :EPFNOSUPPORT :EPIPE :EPROCLIM :EPROCUNAVAIL :EPROGMISMATCH :EPROGUNAVAIL :EPROTO :EPROTONOSUPPORT :EPROTOTYPE :EPSILON :EPWROFF :EQFULL :ERANGE :EREMCHG :EREMOTE :EREMOTEIO :ERESTART :ERFKILL :EROFS :ERPCMISMATCH :ESHLIBVERS :ESHUTDOWN :ESOCKTNOSUPPORT :ESPIPE :ESRCH :ESRMNT :ESTALE :ESTRPIPE :ETIME :ETIMEDOUT :ETOOMANYREFS :ETXTBSY :EUCCN :EUCJP :EUCJP_MS :EUCKR :EUCLEAN :EUCTW :EUC_CN :EUC_JISX0213 :EUC_JIS_2004 :EUC_JP :EUC_JP_MS :EUC_KR :EUC_TW :EUNATCH :EUSERS :EWOULDBLOCK :EWOULDBLOCKWaitReadable :EWOULDBLOCKWaitWritable :EXCL :EXDEV :EXFULL :EXTENDED :EXTERNAL :Emacs_Mule :Encoding :EncodingError :Enumerable :Enumerator :Errno :Error :ErrorHighlight :EucCN :EucJP :EucJP_ms :EucKR :EucTW :Exception :F32 :F64 :FIXEDENCODING :FNM_CASEFOLD :FNM_DOTMATCH :FNM_EXTGLOB :FNM_NOESCAPE :FNM_PATHNAME :FNM_SHORTNAME :FNM_SYSCASE :FalseClass :Fiber :FiberError :File :FileTest :Float :FloatDomainError :Formatter :FrozenError :GB12345 :GB18030 :GB1988 :GB2312 :GBK :GC :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID :GETTIMEOFDAY_BASED_CLOCK_REALTIME :GID :GMP_VERSION :Gem :Generator :HEAP_PAGE_BITMAP_SIZE :HEAP_PAGE_OBJ_LIMIT :HEAP_PAGE_SIZE :HOLE :HOST_ENDIAN :Hash :I :IBM037 :IBM437 :IBM720 :IBM737 :IBM775 :IBM850 :IBM852 :IBM855 :IBM857 :IBM860 :IBM861 :IBM862 :IBM863 :IBM864 :IBM865 :IBM866 :IBM869 :IC :ID :IGNORECASE :INFINITY :INSTRUCTION_NAMES :INTERNAL :INTERNAL_CONSTANTS :INVALID_MASK :INVALID_REPLACE :INVALID_SHAPE_ID :IO :IOError :ISO2022_JP :ISO2022_JP2 :ISO8859_1 :ISO8859_10 :ISO8859_11 :ISO8859_13 :ISO8859_14 :ISO8859_15 :ISO8859_16 :ISO8859_2 :ISO8859_3 :ISO8859_4 :ISO8859_5 :ISO8859_6 :ISO8859_7 :ISO8859_8 :ISO8859_9 :ISO_2022_JP :ISO_2022_JP_2 :ISO_2022_JP_KDDI :ISO_8859_1 :ISO_8859_10 :ISO_8859_11 :ISO_8859_13 :ISO_8859_14 :ISO_8859_15 :ISO_8859_16 :ISO_8859_2 :ISO_8859_3 :ISO_8859_4 :ISO_8859_5 :ISO_8859_6 :ISO_8859_7 :ISO_8859_8 :ISO_8859_9 :IVC :Immediate :IndexError :InstructionSequence :Integer :Interrupt :InvalidByteSequenceError :InvalidatedError :IsolationError :K :KOI8_R :KOI8_U :Kernel :KeyError :LF_NEWLINE_DECORATOR :LITTLE_ENDIAN :LOCKED :LOCK_EX :LOCK_NB :LOCK_SH :LOCK_UN :Lazy :LoadError :LocalJumpError :Location :LockedError :MACCENTEURO :MACCROATIAN :MACCYRILLIC :MACGREEK :MACICELAND :MACJAPAN :MACJAPANESE :MACROMAN :MACROMANIA :MACTHAI :MACTURKISH :MACUKRAINE :MAJOR_VERSION :MANT_DIG :MAPPED :MAX :MAX_10_EXP :MAX_EXP :MIN :MINOR_VERSION :MIN_10_EXP :MIN_EXP :MJIT :MULTILINE :MacCentEuro :MacCroatian :MacCyrillic :MacGreek :MacIceland :MacJapan :MacJapanese :MacRoman :MacRomania :MacThai :MacTurkish :MacUkraine :Marshal :MaskError :MatchData :Math :Method :Module :MovedError :MovedObject :Mutex :NAN :NETWORK_ENDIAN :NOATIME :NOCTTY :NOENCODING :NOERROR :NOFOLLOW :NONBLOCK :NOT_COMPILED_STACK_SIZE :NULL :NameError :NilClass :NoMatchingPatternError :NoMatchingPatternKeyError :NoMemoryError :NoMethodError :Node :NotImplementedError :Numeric :OPTS :Object :ObjectSpace :PAGE_SIZE :PARTIAL_INPUT :PATH_SEPARATOR :PCK :PI :PRIORITY :PRIO_PGRP :PRIO_PROCESS :PRIO_USER :PRIVATE :Pointer :Proc :Process :Producer :Product :Profiler :Queue :RADIX :RB_BUILTIN :RDONLY :RDWR :READABLE :READONLY :RLIMIT_AS :RLIMIT_CORE :RLIMIT_CPU :RLIMIT_DATA :RLIMIT_FSIZE :RLIMIT_MEMLOCK :RLIMIT_MSGQUEUE :RLIMIT_NICE :RLIMIT_NOFILE :RLIMIT_NPROC :RLIMIT_RSS :RLIMIT_RTPRIO :RLIMIT_RTTIME :RLIMIT_SIGPENDING :RLIMIT_STACK :RLIM_INFINITY :RLIM_SAVED_CUR :RLIM_SAVED_MAX :RSYNC :RUBY_COPYRIGHT :RUBY_DESCRIPTION :RUBY_ENGINE :RUBY_ENGINE_VERSION :RUBY_EVENT_CLASS :RUBY_PATCHLEVEL :RUBY_PLATFORM :RUBY_RELEASE_DATE :RUBY_REVISION :RUBY_VERSION :RVALUE_OVERHEAD :RVALUE_SIZE :RVARGC_MAX_ALLOCATE_SIZE :Ractor :Random :Range :RangeError :Rational :Refinement :Regexp :RegexpError :RemoteError :RubyVM :RuntimeError :S16 :S32 :S64 :S8 :SCRIPT_LINES__ :SEEK_CUR :SEEK_DATA :SEEK_END :SEEK_HOLE :SEEK_SET :SEPARATOR :SET :SHAPE_CAPACITY_CHANGE :SHAPE_FLAG_SHIFT :SHAPE_FROZEN :SHAPE_ID_NUM_BITS :SHAPE_INITIAL_CAPACITY :SHAPE_IVAR :SHAPE_MASK :SHAPE_ROOT :SHARED :SHARE_DELETE :SHIFT_JIS :SIZE_POOL_COUNT :SJIS :SJIS_DOCOMO :SJIS_DoCoMo :SJIS_KDDI :SJIS_SOFTBANK :SJIS_SoftBank :STATELESS_ISO_2022_JP :STATELESS_ISO_2022_JP_KDDI :STDERR :STDIN :STDOUT :SYNC :ScriptError :SecurityError :Separator :Set :Shift_JIS :Signal :SignalException :SizedQueue :StandardError :Stat :Stateless_ISO_2022_JP :Stateless_ISO_2022_JP_KDDI :Status :StopIteration :String :Struct :Stub :Symbol :SyntaxError :SyntaxSuggest :Sys :SystemCallError :SystemExit :SystemStackError :TIMES_BASED_CLOCK_MONOTONIC :TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID :TIME_BASED_CLOCK_REALTIME :TIS_620 :TMPFILE :TMP_RUBY_PREFIX :TOPLEVEL_BINDING :TRUNC :Thread :ThreadError :ThreadGroup :Time :TimeoutError :Tms :TracePoint :TrueClass :TypeError :U16 :U32 :U64 :U8 :UCS_2BE :UCS_4BE :UCS_4LE :UID :UNDEF_HEX_CHARREF :UNDEF_MASK :UNDEF_REPLACE :UNIVERSAL_NEWLINE_DECORATOR :USE_LAZY_LOAD :US_ASCII :UTF8_DOCOMO :UTF8_DoCoMo :UTF8_KDDI :UTF8_MAC :UTF8_SOFTBANK :UTF8_SoftBank :UTF_16 :UTF_16BE :UTF_16LE :UTF_32 :UTF_32BE :UTF_32LE :UTF_7 :UTF_8 :UTF_8_HFS :UTF_8_MAC :UnboundMethod :UncaughtThrowError :UndefinedConversionError :UnicodeNormalize :Union :UnsafeError :VALUE :VM_CALL_KW_SPLAT :VM_CALL_KW_SPLAT_bit :VM_CALL_TAILCALL :VM_CALL_TAILCALL_bit :VM_METHOD_TYPE_CFUNC :VM_METHOD_TYPE_ISEQ :WINDOWS_1250 :WINDOWS_1251 :WINDOWS_1252 :WINDOWS_1253 :WINDOWS_1254 :WINDOWS_1255 :WINDOWS_1256 :WINDOWS_1257 :WINDOWS_1258 :WINDOWS_31J :WINDOWS_874 :WNOHANG :WRITABLE :WRONLY :WUNTRACED :WaitReadable :WaitWritable :Waiter :Warning :WeakMap :Windows_1250 :Windows_1251 :Windows_1252 :Windows_1253 :Windows_1254 :Windows_1255 :Windows_1256 :Windows_1257 :Windows_1258 :Windows_31J :Windows_874 :XML_ATTR_CONTENT_DECORATOR :XML_ATTR_QUOTE_DECORATOR :XML_TEXT_DECORATOR :Yielder :ZeroDivisionError :"[" :[] :[]= :"\\" :"]" :^ :_ :_1 :_2 :_3 :_4 :_5 :_6 :_7 :_8 :_9 :_Bool :__attached__ :__autoload__ :__bp__ :__callee__ :__classpath__ :__dir__ :__id__ :__keyword_init__ :__members__ :__members_back__ :__memory_view__ :__method__ :__recursive_key__ :__refined_class__ :__send__ :__tmp_classpath__ :_alloc :_alone :_bf_addr :_captured_body_addr :_cc_addr :_ci_addr :_compiled_body_addr :_dump :_dump_data :_enumerable_collect :_enumerable_collect_concat :_enumerable_drop :_enumerable_drop_while :_enumerable_filter :_enumerable_filter_map :_enumerable_find_all :_enumerable_flat_map :_enumerable_grep :_enumerable_grep_v :_enumerable_map :_enumerable_reject :_enumerable_select :_enumerable_take :_enumerable_take_while :_enumerable_uniq :_enumerable_with_index :_enumerable_zip :_flags :_fork :_id2ref :_iseq_addr :_load :_load_data :_operands_addr :_opes_addr :_separator :_shape_id :_unused1 :_unused2 :: :a :abort :abort_on_exception :abort_on_exception= :abs :abs2 :absolute_path :absolute_path? :accepts_no_kwarg :acos :acosh :add :add_trace_func :addr :address_resolve :advise :after_output :alias :alias_count :alias_method :aliases :alive? :all? :all_symbols :all_tokens :allbits? :allocate :allow_reentry :ambiguous_param0 :ancestors :and :and! :angle :any? :anybits? :append :append_features :arg :argc :args :arguments :argv :argv0 :arity :ary :ascii :ascii_compatible? :ascii_only? :asciicompat_encoding :asctime :asin :asinh :assoc :at :at_exit :atan :atan2 :atanh :atime :attached_object :attr :attr_accessor :attr_index_t :attr_reader :attr_writer :auto_compact :auto_compact= :autoclose :autoclose= :autoclose? :autoload :autoload? :aux :aux_ :b :backtrace :backtrace_location :backtrace_locations :base :base_label :basename :begin :between? :bf_ptr :bin :bind :bind_call :binding :binmode :binmode? :binread :binwrite :birthtime :bit_length :blksize :block :block_code :block_given? :block_start :blockdev? :blocking :blocking? :blocks :bmethod :body :bottom :broadcast :bsearch :bsearch_index :bt :bt_locations :buf :buffer :builtin_compiler :builtin_inline_p :by :byteindex :byteoffset :byterindex :bytes :bytesize :byteslice :bytesplice :call :call_ :call_data :call_threshold :called_id :callee_id :caller :caller_locations :capacity :capitalize :capitalize! :captured_body :captures :casecmp :casecmp? :casefold? :catch :catch_except_p :catch_table :category :cause :cbrt :cc :cc_entries :cc_entries_index :cc_entries_size :cc_ptr :ccan_list_node :cdhash_addr :ceil :ceildiv :center :cfp :cfunc :chain :change_privilege :chardev? :chars :chdir :child :children :chmod :chomp :chomp! :chop :chop! :chown :chr :chroot :chunk :chunk_categorize :chunk_enumerable :chunk_while :ci :ci_ptr :ci_size :clamp :class :class_eval :class_exec :class_variable_defined? :class_variable_get :class_variable_set :class_variables :clear :clock_getres :clock_gettime :clone :close :close_incoming :close_on_exec= :close_on_exec? :close_others :close_outgoing :close_read :close_write :closed? :cme_ :code_location :codepoints :coerce :collect :collect! :collect_concat :combination :compact :compact! :compare_by_identity :compare_by_identity? :compatible :compatible? :compile :compile_branch :compile_data :compile_file :compile_info :compile_option :compile_option= :compile_status :compiled_body :compiled_id :compiled_iseq :compiler :complemented_count :concat :conj :conjugate :const_added :const_defined? :const_get :const_missing :const_set :const_source_location :constants :convert :convpath :copy :copy_stream :"core#define_method" :"core#define_singleton_method" :"core#hash_merge_kwd" :"core#hash_merge_ptr" :"core#raise" :"core#set_method_alias" :"core#set_postexe" :"core#set_variable_alias" :"core#sprintf" :"core#undef_method" :coredump? :cos :cosh :count :count_objects :cover? :coverage :coverage_enabled :cr :cr_newline :cref :crlf :crlf_newline :crypt :cstime :cstime= :ctime :current :current_scheduler :curry :custom :cutime :cutime= :cycle :daemon :day :debug :debug_flags :debug_frozen_string_literal :debug_level :deconstruct :deconstruct_keys :dedup :def :default :default= :default_external :default_external= :default_internal :default_internal= :default_proc :default_proc= :define :define_finalizer :define_method :define_singleton_method :defined_class :delete :delete! :delete_at :delete_if :delete_prefix :delete_prefix! :delete_suffix :delete_suffix! :denominator :deprecate_constant :deprecated :deq :destination_buffer_full :destination_encoding :destination_encoding_name :detach :detailed_message :detect :dev :dev_major :dev_minor :difference :dig :digits :dir :directory? :dirname :disable :disable_const_cache :disable_exivar_cache :disable_inlining :disable_ivar_cache :disable_send_cache :disasm :disassemble :display :div :divmod :dontneed :double_heap :downcase :downcase! :downto :drop :drop_while :dst :dst? :dummy? :dump :dup :e :each :each_byte :each_caller_location :each_char :each_child :each_codepoint :each_cons :each_entry :each_grapheme_cluster :each_index :each_key :each_line :each_object :each_pair :each_slice :each_value :each_with_index :each_with_object :eager :edge_name :edges :egid :egid= :eid :eid= :empty :empty? :enable :enabled? :enclose :enclosed? :encode :encode! :encoded :encoding :end :end_with? :enq :ensure_list :ensure_shareable :entries :entry :enum_for :eof :eof? :ep :eql? :equal? :erf :erfc :err :errinfo :errno :error_bytes :error_char :error_tolerant :escape :euid :euid= :eval :eval_script :even? :event :events :except :exception :excl :exclude_end :exclude_end? :exec :executable? :executable_real? :exist? :exit :exit! :exit_value :exited? :exitstatus :exp :expand_heap :expand_path :experimental :extend :extend_object :extended :external? :external_encoding :extname :f32 :f64 :fail :fallback :fastpath_applied_iseq_p :fatal :fcntl :fdatasync :fdiv :feed :fetch :fetch_values :fiber :fiber_machine_stack_size :fiber_ptr :fiber_vm_stack_size :file :file? :filename :fileno :fill :filter :filter! :filter_map :find :find_all :find_index :find_timezone :finish :finish_p :finished :finite? :first :first_column :first_lineno :fixed_encoding? :flag :flags :flat_map :flatten :flatten! :flip_count :float_microsecond :float_millisecond :float_second :flock :floor :flush :fmt :fnmatch :fnmatch? :fold :for :for_fd :force :force_encoding :foreach :fork :format :free :freeze :frexp :friday? :from_name :from_time :frozen? :frozen_string_literal :fsync :ftype :full_mark :full_message :func_ptr :gamma :garbage_collect :gcd :gcdlcm :get_string :get_value :get_values :getbyte :getc :getegid :geteuid :getgid :getgm :getlocal :getpgid :getpgrp :getpriority :getrlimit :gets :getsid :getuid :getutc :getwd :gid :gid= :glob :global_trace_events :global_variables :gm :gmt? :gmt_offset :gmtime :gmtoff :grant_privilege :grapheme_clusters :grep :grep_v :group :group_by :groups :groups= :grpowned? :gsub :gsub! :handle :handle_interrupt :has_block :has_cache_for_send :has_key? :has_kw :has_kwrest :has_lead :has_opt :has_post :has_rest :has_value? :hash :hash_or_key :heap_name :hertz :hex :hexdump :highlight :home :hour :hypot :i :ic_cache :ic_cref :ic_size :icvarc_size :id :id2name :identical? :ignore_deadlock :ignore_deadlock= :imag :imaginary :immediate :immediate_mark :immediate_sweep :import_methods :in :include :include? :included :included_modules :incomplete_input :incomplete_input? :index :infinite? :inherited :initgroups :initialize :initialize_clone :initialize_copy :initialize_dup :inject :inline_const_cache :inline_context :inlined_call_context :inlined_iseqs :ino :inplace_mode :inplace_mode= :insert :insert_output :insn :insn_may_depend_on_sp_or_pc :insns_info :inspect :instance_eval :instance_exec :instance_method :instance_methods :instance_of? :instance_variable_defined? :instance_variable_get :instance_variable_set :instance_variables :instruction_sequence :instructions_unification :integer? :intern :internal? :internal_encoding :interrupt_flag :interrupt_mask :intersect? :intersection :invalid :invalid_byte_sequence :invert :io_close :io_pread :io_pwrite :io_read :io_select :io_wait :io_write :ioctl :irb :is_a? :is_entries :isatty :isdst :ise_size :iseq :iseq_addr :iseq_bits_t :iseq_catch_table :iseq_compile_data :iseq_encoded :iseq_inline_constant_cache :iseq_inline_constant_cache_entry :iseq_inline_iv_cache_entry :iseq_inline_storage_entry :iseq_insn_info :iseq_overload :iseq_ptr :iseq_size :iseqptr :iseqw :issetugid :iterator? :itself :iv_cache :iv_set_name :ivc_size :jit_func :jit_return :join :keep_if :keep_script_lines :keep_script_lines= :keep_tokens :kernel_sleep :key :key? :keys :keyword :keyword_init? :kill :kind_of? :klass :klass_or_self :kwarg :label :lambda :lambda? :last :last_column :last_error :last_lineno :last_match :last_status :latest_compact_info :latest_gc_info :lazy :lchmod :lchown :lcm :ldexp :lead_num :left :len :length :lf :lf_newline :lgamma :limit :linear_time? :lineno :lineno= :lines :link :list :lithuanian :ljust :load :load_from_binary :load_from_binary_extra_data :load_iseq :loader :loc :local :local_hooks :local_iseq :local_size :local_stack_p :local_storage :local_storage_recursive_hash :local_storage_recursive_hash_for_trace :local_table :local_table_size :local_to_utc :local_variable_defined? :local_variable_get :local_variable_set :local_variables :locale_charmap :locals :localtime :location :lock :locked :locked? :log :log10 :log2 :loop :lstat :lstrip :lstrip! :lutime :machine :magnitude :main :make_shareable :make_shareable_copy :mandatory_only_iseq :map :map! :mapped? :mark_bits :marshal_dump :marshal_load :match :match? :match_length :matchee :max :max= :max_by :max_cache_size :maxgroups :maxgroups= :mday :me :measure_total_time :measure_total_time= :member? :members :memo :merge :merge! :mesg :message :method :method_added :method_defined? :method_id :method_missing :method_missing_reason :method_removed :method_serial :method_undefined :methods :microsecond :mid :millisecond :min :min_by :minmax :minmax_by :mjit_call_attribute_sp_inc :mjit_cancel_all :mjit_capture_cc_entries :mjit_options :mjit_opts :mjit_unit :mkdir :mkfifo :mktime :mode :module_eval :module_exec :module_function :modulo :mon :monday? :month :move :msgs :mtime :n :name :name= :name_list :named_captures :names :nan? :nano_den :nano_num :nanosecond :native_thread_id :negative? :nesting :never :new :new_seed :newline :next :next! :next_float :next_iv_index :next_values :nil :nil? :nlink :no_redef_warning :nobits? :node_id :node_id_for_backtrace_location :non_block :none? :nonzero? :noreuse :normal :normalize :normalized? :not :not! :now :nsec :null? :num_waiting :numerator :obj :object :object_id :objs :oct :odd? :of :offset :on :on_blocking :once :one? :open :open_args :operands :operands_unification :opes :opt_num :opt_table :optimized :options :or :or! :ord :orig_argc :original_id :original_iseq :original_name :other :out :outer_variables :owned? :owner :p :pack :param :param_size :parameters :parent_id :parent_iseq :parse :parse_file :partial_input :partition :pass :passed_block_handler :path :pathname :pathobj :pattern :pause :pc :pc2branchindex :peek :peek_values :peephole_optimization :pending_interrupt? :perm :permutation :pgroup :phase :pid :pipe :pipe? :polar :pool :pop :popen :pos :pos= :positive? :post_match :post_num :post_start :pow :pp :ppid :pre_match :pread :precision :pred :prepend :prepend_features :prepended :prev_float :primitive_convert :primitive_errinfo :print :printf :priority :priority= :private :private_call? :private_class_method :private_const_reference :private_constant :private_instance_methods :private_method_defined? :private_methods :proc :process_wait :produce :product :protected :protected_instance_methods :protected_method_defined? :protected_methods :public :public_class_method :public_constant :public_instance_method :public_instance_methods :public_method :public_method_defined? :public_methods :public_send :push :putback :putc :puts :pwd :pwrite :quo :quote :ractor :ractors :raise :raised_exception :raised_flag :rand :random :random_number :rassoc :rationalize :raw_data :rb_atomic_t :rb_builtin_function :rb_cFalseClass :rb_cFloat :rb_cInteger :rb_cNilClass :rb_cSymbol :rb_cTrueClass :rb_call_data :rb_callable_method_entry_struct :rb_callcache :rb_callinfo :rb_callinfo_kwarg :rb_code_location_t :rb_control_frame_t :rb_cref_struct :rb_cref_t :rb_ensure_list_t :rb_event_flag_t :rb_execution_context_struct :rb_execution_context_t :rb_fiber_t :rb_hash_values :rb_hook_list_struct :rb_id_table :rb_iseq_check :rb_iseq_constant_body :rb_iseq_first_lineno :rb_iseq_location_t :rb_iseq_param_keyword :rb_iseq_path :rb_iseq_struct :rb_iseq_t :rb_iseq_type :rb_iseqw_to_iseq :rb_method_alias_t :rb_method_attr_t :rb_method_bmethod_t :rb_method_cfunc_t :rb_method_definition_struct :rb_method_iseq_t :rb_method_optimized_t :rb_method_refined_t :rb_method_type_t :rb_mjit_compile_info :rb_mjit_unit :rb_mjit_unit_list :rb_mjit_unit_type :rb_scope_visibility_t :rb_serial_t :rb_shape :rb_shape_get_shape_by_id :rb_shape_t :rb_snum_t :rb_splat_or_kwargs_p :rb_thread_struct :rb_trace_arg_struct :rb_vm_insn_decode :rb_vm_insn_encode :rb_vm_tag :rdev :rdev_major :rdev_minor :re_exchange :re_exchangeable? :read :read_nonblock :readable? :readable_real? :readagain_bytes :readbyte :readchar :readline :readlines :readlink :readonly? :readpartial :real :real? :realdirpath :realpath :reason :receive :receive_if :receiver :rect :rectangular :recv :reduce :refine :refined :refined_class :refinements :regexp :rehash :reject :reject! :remainder :remove_class_variable :remove_const :remove_instance_variable :remove_method :rename :reopen :repeated_combination :repeated_permutation :replace :replacement :replacement= :replicate :report :report_on_exception :report_on_exception= :require :require_relative :resize :resolve_feature_path :respond_to? :respond_to_missing? :rest_start :restore :result :resume :return_value :reverse :reverse! :reverse_each :rewind :rid :rindex :rjust :rmdir :root_lep :root_svar :rotate :rotate! :round :rpartition :rstrip :rstrip! :ruby2_keywords :ruby2_keywords_hash :ruby2_keywords_hash? :run :running_thread :s :s16 :s32 :s64 :sample :saturday? :save_temps :scan :schedule :scheduler :scheduler_close :scope_visi :script_lines :scrub :scrub! :search_convpath :sec :second :seed :seek :segments :select :select! :self :send :sequential :set_backtrace :set_encoding :set_encoding_by_bom :set_scheduler :set_string :set_trace_func :set_value :set_values :setbyte :setegid :seteuid :setgid :setgid? :setpgid :setpgrp :setpriority :setproctitle :setregid :setresgid :setresuid :setreuid :setrgid :setrlimit :setruid :setsid :setuid :setuid? :shape_addr :shape_id :shape_id_t :shareable? :shared? :shift :shuffle :shuffle! :sid_available? :signal :signaled? :signame :signm :signo :sin :single :singleton_class :singleton_class? :singleton_method :singleton_method_added :singleton_method_removed :singleton_method_undefined :singleton_methods :singletonclass :sinh :size :size? :size_of :size_pool_index :skip :sleep :slice :slice! :slice_after :slice_before :slice_when :sliceafter_enum :sliceafter_pat :sliceafter_pred :slicebefore_enumerable :slicebefore_sep_pat :slicebefore_sep_pred :slicewhen_enum :slicewhen_inverted :slicewhen_pred :socket? :sort :sort! :sort_by :sort_by! :source :source_buffer_empty :source_encoding :source_encoding_name :source_location :sp :spawn :specialized_instruction :split :sprintf :sqrt :squeeze :squeeze! :srand :stack_caching :stack_end :stack_max :stack_maxsize :stack_size :stack_size_for_pos :stack_start :start :start_with? :stat :stat_heap :state :status :step :sticky? :stime :stime= :stop :stop? :stopped? :stopsig :storage :storage= :store :str :stress :stress= :strftime :string :strip :strip! :sub :sub! :subclasses :submicro :subsec :succ :succ! :success :success? :sum :sunday? :super_method :superclass :swapcase :swapcase! :switch :sym :symlink :symlink? :sync :sync= :synchronize :syscall :sysopen :sysread :sysseek :system :syswrite :tag :tailcall_optimization :take :take_while :tally :tan :tanh :tap :target :target_line :target_thread :tell :terminate :termsig :test :text :textmode :then :thread_machine_stack_size :thread_ptr :thread_variable? :thread_variable_get :thread_variable_set :thread_variables :thread_vm_stack_size :throw :thursday? :time :timeout :timeout= :timeout_after :times :tm :to :to_a :to_ary :to_binary :to_c :to_enum :to_f :to_h :to_hash :to_i :to_int :to_io :to_path :to_proc :to_r :to_ruby :to_s :to_set :to_str :to_sym :to_time :to_tty? :to_write_io :token :tokens :top :total_calls :total_time :toward :tr :tr! :tr_s :tr_s! :trace :trace_arg :trace_points :trace_var :transfer :transform_keys :transform_keys! :transform_values :transform_values! :translate :transpose :trap :truncate :try_convert :try_lock :tty? :tuesday? :turkic :tv_nsec :tv_sec :tv_usec :type :u16 :u32 :u64 :uid :uid= :umask :unbind :unblock :undef :undef_method :undefine_finalizer :undefined_conversion :undefined_instance_methods :undump :ungetbyte :ungetc :unicode_normalize :unicode_normalize! :unicode_normalized? :union :uniq :uniq! :unit :units :universal :universal_newline :unlink :unlock :unode :unpack :unpack1 :unsetenv_others :unshift :untrace_var :upcase :upcase! :update :uplevel :upto :urandom :usec :used_code_p :used_modules :used_refinements :using :using_rvargc? :utc :utc? :utc_offset :utc_to_local :utime :utime= :v :val :valid? :valid_encoding? :value :value? :values :values_at :variable :verbose :verify_compaction_references :verify_internal_consistency :verify_transient_heap_internal_consistency :vm_call_handler :vm_ci_argc :vm_ci_flag :vm_stack :vm_stack_size :wait :wait2 :wait_priority :wait_readable :wait_writable :waitall :waitpid :waitpid2 :wakeup :warn :warnings :wday :wednesday? :willneed :with :with_index :with_object :world_readable? :world_writable? :wrapper :writable? :writable_real? :write :write_nonblock :xml :xor! :yday :year :yield :yield_self :yield_unspecified :yield_value :zero? :zip :zone :"{" :| :"||" :"}" :~
Initial Global/Special Variables

More info

$ ruby --disable-all -e 'puts global_variables.sort.
map{ |g| "`#{g.to_s.sub("`", "\\`")}`" }.join(", ")'

$!, $", $$, $&, $', $*, $+, $,, $-0, $-F, $-I, $-W, $-a, $-d, $-i, $-l, $-p, $-v, $-w, $., $/, $0, $:, $;, $<, $=, $>, $?, $@, $DEBUG, $FILENAME, $LOADED_FEATURES, $LOAD_PATH, $PROGRAM_NAME, $VERBOSE, $\, $_, $$, $stderr, $stdin, $stdout, $~

Also See
https://idiosyncratic-ruby.com/43-new-ruby-startup.html
R(u)b(y)Config(uration)
Show full content

At some point when working with Ruby, you come across this mysterious RbConfig constant. A typical scenario is that you want to check which operating system your current program is executed on. You can do this with RbConfig::CONFIG['host_os'] or RbConfig::CONFIG['arch'], see the RubyGems source for an advanced example!

The Ruby Configuration is a collection of low-level information about your operating system, which gets created by mkconfig.rb when Ruby is compiled. It mostly contains compiler flags generated by Ruby's compile scripts. Its exact contents depend on your system, and also on your Ruby implementation and version. All major Ruby implementations have a RbConfig.

The majority of its data can be found in a hash called RbConfig::CONFIG and you will need to require "rbconfig" before using it. There is additional data in other constants, such as in RbConfig::SIZEOF, which was added with Ruby 2.3. What follows is an overview of what can be found in RbConfig:

RbConfig.ruby

Returns the absolute pathname of the ruby command, constructed from bindir, ruby_install_name, and EXEEXT (see table below):

require "rbconfig"
RbConfig.ruby #=> "/home/jan/.rvm/rubies/ruby-2.3.0/bin/ruby"
RbConfig.expand(val)

The RbConfig object has an internal method to substitute placeholders in values with other values from RbConfig. For example, the LIBRUBY_SO value could be converted from "lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR).$(TEENY)" to "libruby.so.2.3.0".

RbConfig::TOPDIR

Returns the directory where the Ruby interpreter is located:

require "rbconfig"
RbConfig::TOPDIR #=> "/home/jan/.rvm/rubies/ruby-2.3.0"
RbConfig::DESTDIR

If you set the ::DESTDIR constant before loading "rbconfig", it will have an impact on some other values (see the table below).

RbConfig::MAKEFILE_CONFIG

A copy of RbConfig::CONFIG without expanded values (see table in next section).

RbConfig::CONFIG

The following table contains the example output on an ubuntu machine using Ruby 2.3.0, installed via RVM:

Config Key Value Construction (Non-Expanded) Final Value (Expanded) DESTDIR DESTDIR "" MAJOR "2" "2" MINOR "3" "3" TEENY "0" "0" PATCHLEVEL "0" "0" INSTALL '/usr/bin/install -c' "/usr/bin/install -c" EXEEXT "" "" prefix (TOPDIR || DESTDIR + "/home/jan/.rvm/rubies/ruby-2.3.0") "/home/jan/.rvm/rubies/ruby-2.3.0" ruby_install_name "$(RUBY_BASE_NAME)" "ruby" RUBY_INSTALL_NAME "$(RUBY_BASE_NAME)" "ruby" RUBY_SO_NAME "$(RUBY_BASE_NAME)" "ruby" exec "exec" "exec" ruby_pc "ruby-2.3.pc" "ruby-2.3.pc" PACKAGE "ruby" "ruby" BUILTIN_TRANSSRCS " enc/trans/newline.c" " enc/trans/newline.c" USE_RUBYGEMS "YES" "YES" MANTYPE "doc" "doc" NROFF "/usr/bin/nroff" "/usr/bin/nroff" vendorarchhdrdir "$(vendorhdrdir)/$(sitearch)" "/home/jan/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/vendor_ruby/x86_64-linux" sitearchhdrdir "$(sitehdrdir)/$(sitearch)" "/home/jan/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/site_ruby/x86_64-linux" rubyarchhdrdir "$(rubyhdrdir)/$(arch)" "/home/jan/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/x86_64-linux" vendorhdrdir "$(rubyhdrdir)/vendor_ruby" "/home/jan/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/vendor_ruby" sitehdrdir "$(rubyhdrdir)/site_ruby" "/home/jan/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0/site_ruby" rubyhdrdir "$(includedir)/$(RUBY_VERSION_NAME)" "/home/jan/.rvm/rubies/ruby-2.3.0/include/ruby-2.3.0" RUBY_SEARCH_PATH "" "" UNIVERSAL_INTS "" "" UNIVERSAL_ARCHNAMES "" "" configure_args " '--prefix=/home/jan/.rvm/rubies/ruby-2.3.0' '--disable-install-doc' '--enable-shared'" " '--prefix=/home/jan/.rvm/rubies/ruby-2.3.0' '--disable-install-doc' '--enable-shared'" CONFIGURE "configure" "configure" vendorarchdir "$(vendorlibdir)/$(sitearch)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/vendor_ruby/2.3.0/x86_64-linux" vendorlibdir "$(vendordir)/$(ruby_version)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/vendor_ruby/2.3.0" vendordir "$(rubylibprefix)/vendor_ruby" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/vendor_ruby" sitearchdir "$(sitelibdir)/$(sitearch)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/site_ruby/2.3.0/x86_64-linux" sitelibdir "$(sitedir)/$(ruby_version)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/site_ruby/2.3.0" sitedir "$(rubylibprefix)/site_ruby" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/site_ruby" rubyarchdir "$(rubylibdir)/$(arch)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/x86_64-linux" rubylibdir "$(rubylibprefix)/$(ruby_version)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0" ruby_version "2.3.0" "2.3.0" sitearch "$(arch)" "x86_64-linux" arch "x86_64-linux" "x86_64-linux" sitearchincludedir "$(includedir)/$(sitearch)" "/home/jan/.rvm/rubies/ruby-2.3.0/include/x86_64-linux" archincludedir "$(includedir)/$(arch)" "/home/jan/.rvm/rubies/ruby-2.3.0/include/x86_64-linux" sitearchlibdir "$(libdir)/$(sitearch)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/x86_64-linux" archlibdir "$(libdir)/$(arch)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/x86_64-linux" libdirname "libdir" "libdir" RUBY_EXEC_PREFIX "/home/jan/.rvm/rubies/ruby-2.3.0" "/home/jan/.rvm/rubies/ruby-2.3.0" RUBY_LIB_VERSION "" "" RUBY_LIB_VERSION_STYLE "3\t/* full */" "3\t/* full */" RI_BASE_NAME "ri" "ri" ridir "$(datarootdir)/$(RI_BASE_NAME)" "/home/jan/.rvm/rubies/ruby-2.3.0/share/ri" rubysitearchprefix "$(rubylibprefix)/$(sitearch)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/x86_64-linux" rubyarchprefix "$(rubylibprefix)/$(arch)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/x86_64-linux" MAKEFILES "Makefile GNUmakefile" "Makefile GNUmakefile" PLATFORM_DIR "" "" THREAD_MODEL "pthread" "pthread" SYMBOL_PREFIX "" "" EXPORT_PREFIX "" "" COMMON_HEADERS "" "" COMMON_MACROS "" "" COMMON_LIBS "" "" MAINLIBS "" "" ENABLE_SHARED "yes" "yes" DLDLIBS " -lc" " -lc" SOLIBS "$(LIBS)" "-lpthread -lgmp -ldl -lcrypt -lm " LIBRUBYARG_SHARED "-Wl,-R$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)" "-Wl,-R/home/dan/.rvm/rubies/ruby-2.3.0/lib -L/home/dan/.rvm/rubies/ruby-2.3.0/lib -lruby" LIBRUBYARG_STATIC "-Wl,-R$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)-static" "-Wl,-R/home/dan/.rvm/rubies/ruby-2.3.0/lib -L/home/dan/.rvm/rubies/ruby-2.3.0/lib -lruby-static" LIBRUBYARG "$(LIBRUBYARG_SHARED)" "-Wl,-R/home/dan/.rvm/rubies/ruby-2.3.0/lib -L/home/dan/.rvm/rubies/ruby-2.3.0/lib -lruby" LIBRUBY "$(LIBRUBY_SO)" "libruby.so.2.3.0" LIBRUBY_ALIASES "lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR) lib$(RUBY_SO_NAME).so" "libruby.so.2.3 libruby.so" LIBRUBY_SO "lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR).$(TEENY)" "libruby.so.2.3.0" LIBRUBY_A "lib$(RUBY_SO_NAME)-static.a" "libruby-static.a" RUBYW_INSTALL_NAME "" "" rubyw_install_name "" "" EXTDLDFLAGS "" "" EXTLDFLAGS "" "" strict_warnflags "-std=iso9899:1999" "-std=iso9899:1999" warnflags "-Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wno-packed-bitfield-compat -Wno-maybe-uninitialized" "-Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wno-packed-bitfield-compat -Wno-maybe-uninitialized" debugflags "-ggdb3" "-ggdb3" optflags "-O3 -fno-fast-math" "-O3 -fno-fast-math" NULLCMD ":" ":" DLNOBJ "dln.o" "dln.o" EXECUTABLE_EXTS "" "" ARCHFILE "" "" LIBRUBY_RELATIVE "no" "no" EXTOUT ".ext" ".ext" PREP "miniruby$(EXEEXT)" "miniruby" CROSS_COMPILING "no" "no" TEST_RUNNABLE "yes" "yes" rubylibprefix "$(libdir)/$(RUBY_BASE_NAME)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby" setup "Setup" "Setup" ENCSTATIC "" "" EXTSTATIC "" "" STRIP "strip -S -x" "strip -S -x" TRY_LINK "" "" PRELOADENV "LD_PRELOAD" "LD_PRELOAD" LIBPATHENV "LD_LIBRARY_PATH" "LD_LIBRARY_PATH" RPATHFLAG " -Wl,-R%1$-s" " -Wl,-R%1$-s" LIBPATHFLAG " -L%1$-s" " -L%1$-s" LINK_SO "" "" ASMEXT "S" "S" LIBEXT "a" "a" DLEXT2 "" "" DLEXT "so" "so" LDSHAREDXX "$(CXX) -shared" "g++ -shared" LDSHARED "$(CC) -shared" "gcc -shared" CCDLFLAGS "-fPIC" "-fPIC" STATIC "" "" ARCH_FLAG "" "" DLDFLAGS "" "" ALLOCA "" "" codesign "" "" POSTLINK ":" ":" WERRORFLAG "-Werror" "-Werror" CHDIR "cd -P" "cd -P" RMALL "rm -fr" "rm -fr" RMDIRS "rmdir --ignore-fail-on-non-empty -p" "rmdir --ignore-fail-on-non-empty -p" RMDIR "rmdir --ignore-fail-on-non-empty" "rmdir --ignore-fail-on-non-empty" CP "cp" "cp" RM "rm -f" "rm -f" PKG_CONFIG "pkg-config" "pkg-config" PYTHON "" "" DOXYGEN "" "" DOT "dot" "dot" MAKEDIRS "/bin/mkdir -p" "/bin/mkdir -p" MKDIR_P "/bin/mkdir -p" "/bin/mkdir -p" INSTALL_DATA "$(INSTALL) -m 644" "/usr/bin/install -c -m 644" INSTALL_SCRIPT "$(INSTALL)" "/usr/bin/install -c" INSTALL_PROGRAM "$(INSTALL)" "/usr/bin/install -c" SET_MAKE "" "" LN_S "ln -s" "ln -s" NM "nm" "nm" DLLWRAP "" "" WINDRES "" "" OBJCOPY ":" ":" OBJDUMP "objdump" "objdump" ASFLAGS "" "" AS "as" "as" AR "ar" "ar" RANLIB "ranlib" "ranlib" try_header "" "" CC_VERSION "$(CC) -v" "gcc -v" COUTFLAG "-o " "-o " OUTFLAG "-o " "-o " CPPOUTFILE "-o conftest.i" "-o conftest.i" GNU_LD "yes" "yes" LD "ld" "ld" GCC "yes" "yes" EGREP "/bin/grep -E" "/bin/grep -E" GREP "/bin/grep" "/bin/grep" CPP "$(CC) -E" "gcc -E" CXXFLAGS "$(cxxflags)" " -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wno-packed-bitfield-compat -Wno-maybe-uninitialized" OBJEXT "o" "o" CPPFLAGS " $(DEFS) $(cppflags)" " " LDFLAGS "-L. -fstack-protector -rdynamic -Wl,-export-dynamic" "-L. -fstack-protector -rdynamic -Wl,-export-dynamic" CFLAGS "$(cflags) -fPIC" " -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wno-packed-bitfield-compat -Wno-maybe-uninitialized -fPIC" CXX "g++" "g++" CC "gcc" "gcc" NACL_LIB_PATH "" "" NACL_SDK_VARIANT "" "" NACL_SDK_ROOT "" "" NACL_TOOLCHAIN "" "" target_os "linux" "linux" target_vendor "pc" "pc" target_cpu "x86_64" "x86_64" target "x86_64-pc-linux-gnu" "x86_64-pc-linux-gnu" host_os "linux-gnu" "linux-gnu" host_vendor "pc" "pc" host_cpu "x86_64" "x86_64" host "x86_64-pc-linux-gnu" "x86_64-pc-linux-gnu" RUBY_VERSION_NAME "$(RUBY_BASE_NAME)-$(ruby_version)" "ruby-2.3.0" RUBYW_BASE_NAME "rubyw" "rubyw" RUBY_BASE_NAME "ruby" "ruby" build_os "linux-gnu" "linux-gnu" build_vendor "pc" "pc" build_cpu "x86_64" "x86_64" build "x86_64-pc-linux-gnu" "x86_64-pc-linux-gnu" RUBY_PROGRAM_VERSION "2.3.0" "2.3.0" cxxflags " $(optflags) $(debugflags) $(warnflags)" " -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wno-packed-bitfield-compat -Wno-maybe-uninitialized" cppflags "" "" cflags " $(optflags) $(debugflags) $(warnflags)" " -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -Wdeprecated-declarations -Wno-packed-bitfield-compat -Wno-maybe-uninitialized" target_alias "" "" host_alias "" "" build_alias "" "" LIBS "-lpthread -lgmp -ldl -lcrypt -lm " "-lpthread -lgmp -ldl -lcrypt -lm " ECHO_T "" "" ECHO_N "-n" "-n" ECHO_C "" "" DEFS "" "" mandir "$(datarootdir)/man" "/home/jan/.rvm/rubies/ruby-2.3.0/share/man" localedir "$(datarootdir)/locale" "/home/jan/.rvm/rubies/ruby-2.3.0/share/locale" libdir "$(exec_prefix)/lib" "/home/jan/.rvm/rubies/ruby-2.3.0/lib" psdir "$(docdir)" "/home/jan/.rvm/rubies/ruby-2.3.0/share/doc/ruby" pdfdir "$(docdir)" "/home/jan/.rvm/rubies/ruby-2.3.0/share/doc/ruby" dvidir "$(docdir)" "/home/jan/.rvm/rubies/ruby-2.3.0/share/doc/ruby" htmldir "$(docdir)" "/home/jan/.rvm/rubies/ruby-2.3.0/share/doc/ruby" infodir "$(datarootdir)/info" "/home/jan/.rvm/rubies/ruby-2.3.0/share/info" docdir "$(datarootdir)/doc/$(PACKAGE)" "/home/jan/.rvm/rubies/ruby-2.3.0/share/doc/ruby" oldincludedir "/usr/include" "/usr/include" includedir "$(prefix)/include" "/home/jan/.rvm/rubies/ruby-2.3.0/include" localstatedir "$(prefix)/var" "/home/jan/.rvm/rubies/ruby-2.3.0/var" sharedstatedir "$(prefix)/com" "/home/jan/.rvm/rubies/ruby-2.3.0/com" sysconfdir "$(prefix)/etc" "/home/jan/.rvm/rubies/ruby-2.3.0/etc" datadir "$(datarootdir)" "/home/jan/.rvm/rubies/ruby-2.3.0/share" datarootdir "$(prefix)/share" "/home/jan/.rvm/rubies/ruby-2.3.0/share" libexecdir "$(exec_prefix)/libexec" "/home/jan/.rvm/rubies/ruby-2.3.0/libexec" sbindir "$(exec_prefix)/sbin" "/home/jan/.rvm/rubies/ruby-2.3.0/sbin" bindir "$(exec_prefix)/bin" "/home/jan/.rvm/rubies/ruby-2.3.0/bin" exec_prefix "$(prefix)" "/home/jan/.rvm/rubies/ruby-2.3.0" PACKAGE_URL "" "" PACKAGE_BUGREPORT "" "" PACKAGE_STRING "" "" PACKAGE_VERSION "" "" PACKAGE_TARNAME "" "" PACKAGE_NAME "" "" PATH_SEPARATOR ":" ":" SHELL "/bin/bash" "/bin/bash" archdir "$(rubyarchdir)" "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/x86_64-linux" topdir File.dirname(__FILE__) "/home/jan/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/x86_64-linux" RbConfig::SIZEOF

This hash contains the byte sizes of low-level data structures of your system. This is useful when interacting with external libraries via FFI/Fiddle. I needs to be explicitly required:

require "rbconfig/sizeof"
RbConfig::SIZEOF # => {"int"=>4, "short"=>2, "long"=>8, "long long"=>8, ...

The following table contains example values from an ubuntu machine using Ruby 2.3.0:

Type Size int 4 short 2 long 8 long long 8 off_t 8 void* 8 float 4 double 8 time_t 8 clock_t 8 size_t 8 ptrdiff_t 8 int8_t 1 uint8_t 1 int16_t 2 uint16_t 2 int32_t 4 uint32_t 4 int64_t 8 uint64_t 8 intptr_t 8 uintptr_t 8 ssize_t 8 int_least8_t 1 int_least16_t 2 int_least32_t 4 int_least64_t 8 int_fast8_t 1 int_fast16_t 8 int_fast32_t 8 int_fast64_t 8 intmax_t 8 sig_atomic_t 4 wchar_t 4 wint_t 4 wctrans_t 8 wctype_t 8 _Bool 1 long double 16 float _Complex 8 double _Complex 16 long double _Complex 32 __int128 16 __float128 16 _Decimal32 4 _Decimal64 8 _Decimal128 16 __float80 16
https://idiosyncratic-ruby.com/42-ruby-config.html
Proper Unicoding
Show full content

Ruby's Regexp engine has a powerful feature built in: It can match for Unicode character properties. But what exactly are properties you can match for?

The Unicode consortium not only assigns all codepoints, it also publishes additional data about their assigned characters. When searching through a string, Ruby allows you to utilize some of this extra knowledge.

Property Regexp Syntax

Within a regular expression, use the \p directive:

  • /\p{ PROPERTY NAME }/

To invert the property (matching characters that do not fit), you can either use a big \P:

  • /\P{ PROPERTY NAME }/

Or add the ^ sign:

  • /\p{ ^PROPERTY NAME }/

Ruby will strip all spaces, dashes, underscores from the given property and convert it to a lowercased string. So the following examples are all valid syntax:

  • /\p{AGE = 6.3}/
  • /\p{^In Supplementary Private Use Area-B}/
  • /\p{In_Egyptian_Hieroglyphs}/
  • /\P{inemoticons}/
  • /\P{inno block}/
  • /\p{^zzzz}/
  • /\p{ z___ y-y-y }/
Supported Unicode Versions

See table at Episode 73: Unicode Version Mapping

List of Properties as of Ruby 3.0 / Unicode 12.1 General Category

Each code point has a General Category, one of the most basic categorizations. Codepoints without an explicit general category will implicitly get Cn (Unassigned):

"Find decimal numbers (like 2 or 3)".scan(/\p{Nd}+/) # => ["2", "3"]

See the Unicode::Categories micro gem for a way find all general categories a string belongs to and a list of possible categories.

Major Category

The Major category is basically the first letter of the general category:

  • L: Letter
  • M: Mark
  • N: Number
  • P: Punctuation
  • S: Symbol
  • Z: Separator
  • C: Other

Example:

"Find punctuation characters (like : or ;)".scan(/\p{P}+/) # => ["(", ":", ";)"]
Block

Unicode codepoints are also structured as contiguous blocks: Each codepoint is part of one or has the special value No_Block. To make the block name a Unicode property, you have to prefix it with "in":

"Do not look directly into the ☼".scan /\p{In Miscellaneous Symbols}/ # => ["☼"]

See the Unicode::Blocks micro gem for a way to retrieve the blocks of a string and a list of all valid block names.

Script

The script of a character can also be matched:

"ᴦ".scan/\p{Greek}/ # => "ᴦ"

See the Unicode::Scripts micro gem for a way to find all scripts a string contains and a list of valid script names. A great way to explore the different scripts is codepoints.net.

Age

The age property lets you find out the required Unicode version to display a string:

"Train: 🛲 " =~ /\A\p{age=3.1}*\z/ # => nil
"Train: 🛲 " =~ /\A\p{age=7.0}*\z/ # => 0
Combined/POSIX like Properties

All properties of the POSIX brackets syntax are available with the \p syntax: For example, [[:print:]] simply becomes \p{print}. You can find the full list of properties in Episode 30: Regex with Class.

Generic Properties
  • Any
  • Assigned

While \p{Any} will just match any representable codepoint, \p{Assigned} will ignore Reserved codepoints and Non-Characters

Derived Core Properties

These can be found in DerivedCoreProperties.txt (explanation), along with a comment how the property gets constructed. Possible values are (short form in parenthesis):

  • Math
  • Alphabetic (Alpha)
  • Lowercase (Lower)
  • Uppercase (Upper)
  • Cased
  • Case Ignorable
  • Changes When Lowercased (CWL)
  • Changes When Uppercased (CWU)
  • Changes When Titlecased (CWT)
  • Changes When Casefolded (CWCF)
  • Changes When Casemapped (CWCF)
  • ID Start (IDS)
  • ID Continue (IDC)
  • XID Start (XIDS)
  • XID Continue (XIDC)
  • Default Ignorable Code Point (DI)
  • Grapheme Extend (Gr Ext)
  • Grapheme Base (Gr Base)
  • Grapheme Link (Gr Link)
Grapheme Related

Ruby's regex engine supports matching for grapheme clusters using \X. But it can also match for very specific grapheme related properties:

  • Grapheme Cluster Break = Prepend
  • Grapheme Cluster Break = CR
  • Grapheme Cluster Break = LF
  • Grapheme Cluster Break = Control
  • Grapheme Cluster Break = Extend
  • Grapheme Cluster Break = Regional Indicator
  • Grapheme Cluster Break = SpacingMark
  • Grapheme Cluster Break = L
  • Grapheme Cluster Break = V
  • Grapheme Cluster Break = T
  • Grapheme Cluster Break = LV
  • Grapheme Cluster Break = LVT
  • Grapheme Cluster Break = ZWJ
Binary Properties

Other matchable character properties are:

  • White Space (W Space)
  • Bidi Control (Bidi C)
  • Join Control (Join C)
  • Dash
  • Hyphen
  • Quotation Mark (Q Mark)
  • Terminal Punctuation (Term)
  • Other Math (O Math)
  • Hex Digit (Hex)
  • ASCII Hex Digit (A Hex)
  • Other Alphabetic (O Alpha)
  • Ideographic (Ideo)
  • Diacritic (Dia)
  • Extender (Ext)
  • Other Lowercase (O Lower)
  • Other Uppercase (O Upper)
  • Noncharacter Code Point (N Char)
  • Other Grapheme Extend (O Gr Ext)
  • IDS Binary Operator (IDSB)
  • IDS Trinary Operator (IDST)
  • Radical
  • Unified Ideograph (U Ideo)
  • Other Default Ignorable Code Point (ODI)
  • Deprecated (Dep)
  • Soft Dotted (SD)
  • Logical Order Exception (LOE)
  • Other ID Start (OIDS)
  • Other ID Continue (OIDC)
  • Sentence Terminal (S Term)
  • Variation Selector (VS)
  • Pattern White Space (Pat WS)
  • Pattern Syntax (Pat Syn)
  • Prepended Concatenation Mark (PCM)
  • Regional Indicator (RI)
Emoji Properties

Also see: unicode-emoji

  • Emoji
  • Emoji Presentation
  • Emoji Modifier
  • Emoji Modifier_Base
  • Emoji Component
  • Extended Pictographic
Resources
https://idiosyncratic-ruby.com/41-proper-unicoding.html
Symbolic Validations
Show full content

When exactly don't you have to :"escape" a Ruby symbol?

Because this question is somehow related to the Ruby interpreter's internal usage of symbols, the rules are not the most obvious ones:

  • : + Identifier¹, optionally appended by !, ?, or = (→ methods)
  • :@ + Identifier¹ (→ instance variables)
  • :@@ + Identifier¹ (→ class variables)
  • :$ + Identifier¹ (→ global variables)
  • :$ + Single identifier¹ character or 0-9 (→ Perl-style special variables)
  • :$- + Single identifier¹ character or 0-9 (→ Ruby interpreter CLI options)
  • :!, :!=, :!~, :%, :&, :*, :+, :-, :/, :<, :>, :^, :`, :|, :~, :$!, :$", :$$, :$&, :$', :$*, :$+, :$,, :$., :$/, :$:, :$;, :$<, :$=, :$>, :$?, :$@, :$\, :$`, :$~, :**, :+@, :-@, :<<, :<=², :<=>², :==, :===, :=~, :>=, :>>, :[], :[]=

¹ Valid for identifiers: A-Z, a-z, 0-9, _, non-ASCII characters. Not allowed to start with 0-9.
² Example of a syntactical edge case that is not 100% clear

https://idiosyncratic-ruby.com/40-symbolic-validations.html
Fixed Numbers
Show full content

A quick reminder that number literals in Ruby can be pretty fancy!

Example Evaluates To Class Purpose 0x10 16 Integer Integers in hexadecimal (0-16) format 0o10¹ 8 Integer Integers in octal (0-8) format 0b10 2 Integer Integers in binary (0-1) format 1e1000 Float::INFINITY Float Floats in exponential notation 1i (0+1i)² Complex Shorthand for creating complex numbers 3/6r (1/2)² Rational Shorthand for creating rational numbers 0_0 0 any Visually separate digits

¹ Also: 010
² While the representation of a complex number (e.g. (0+1i)) is a valid way to create the same number again, this is not true for (1/2) which will just evaluate to 0³. Also note that the r only makes the 6 a rational, which in turn "rationalizes" the result. An equivalent way of expressing the same fraction would be 3r/6
³ Except when you require "mathn"

https://idiosyncratic-ruby.com/39-fixed-numbers.html
Sad Methods
Show full content

In general, Ruby's reflection capabilities are pretty powerful, although not always logical. However, when reflecting on a method's (or proc's) usage, you are sometimes stuck with sad methods.

Sad methods only work for code, that is written in Ruby itself. And Ruby itself (official MRI) is written in C, which limits such methods' usefulness quite a lot. This is an implementation specific problem, and it naturally does not occur in implementations like Rubinius. The following three methods are affected:

Arity

The arity of a method (or proc) will return:

  • A positive number if the method has a fixed number of arguments
  • A negative number if the method has a variable number of arguments, the value denoting the number of required arguments

For example:

method(:require).arity # => 1

However: For methods written in C, returns -1 if the call takes a variable number of arguments

method(:puts).arity # => -1
Source Location

The source_location of a method (or proc) returns a two-element array containing the path to the source file and the line number, where it is defined:

method(:require).source_location
# => ["/home/jan/.rvm/rubies/ruby-2.3.0/lib/.../core_ext/kernel_require.rb", 39]

However: Returns […] nil if this method was not defined in Ruby (i.e. native)

method(:puts).source_location # => nil
Parameters

The Method#parameters method lets inspect what kind of parameters a method (or proc) takes:

FileUtils.method(:cd).parameters
# => [[:req, :dir], [:opt, :options], [:block, :block]]

However: Like arity, it will treat all C methods with multiple arguments as "variable number of arguments", instead of providing exact information:

Module.instance_method(:define_method).parameters
#=> [[:rest]]
Also See
https://idiosyncratic-ruby.com/38-sad-methods.html
Static Monkeys vs. Strong Ducks
Show full content

Programming languages have been, and will always be categorized by their typing system. Naturally, large parts of the Ruby community (including myself) have some kind of aversion against static typing. But while Ruby goes down the route of being dynamically typed that does not mean that you are not allowed to use some form of types!

2020 update: Ruby 3.0 introduced types

Put differently, nothing is wrong with ensuring a specific behavior of arguments given to, or received from a method. You sometimes do it anyways, for example:

  • When you raise an error, because the argument given is not a Numeric
  • When you raise an error, because an argument does not respond to :to_i
  • When you check that something has a trueish value

The second example is checking if an object has a specific method, you could call it duck type checking.

The third example might not look logical at first glance, but: As soon as you check if an object is not "falsy", you are doing some kind of type checking. The type is "trueish" and it is very implicit (every object that is not nil or false) . Such type checks are normal, not necessarily a bad thing, and it also does not mean static typing is much better, and we all should use Haskell. It is more about how to think about types and how to have conversations about types.

Almighty Staticness?

Static type systems often use compile time type checking, which lets you catch a specific type of bugs earlier. It also opens the room for a much better performance. There are some very Ruby-like languages that use static types and achieve a much better performance, namely Mirah and Crystal.

However, having to annotate everything is a very strict requirement. It is not Don't Repeat Yourself. It is harder to work with and less flexible. It is not backwards-compatible with existing Ruby code. Unless you put an unrealistically huge effort into it, it will not proof your software is correct. It will not free you from the responsibility to ensure your program is working properly (for instance, by writing tests).

Yet, it will check types for you.

Manual Type Checking at Runtime

There are some options out there that can assist you with explicitly and optionally checking the type of method arguments and return values, for example Rubype, or my very similar sig library:

# On main object
sig [:to_i, :to_i], Integer,
def sum(a, b)
  a.to_i + b.to_i
end

sum(42, false)
# Sig::ArgumentTypeError:
# - Expected false to respond to :to_i

# In modules
class A
  sig [Numeric, Numeric], Numeric,
  def mul(a, b)
    a * b
  end
end

A.new.mul(4,"3")
# Sig::ArgumentTypeError:
# - Expected "3" to be a Numeric, but is a String


# Explicitely define signature for singleton_class
class B
  sig_self [:reverse],
  def self.rev(object)
    object.reverse
  end
end

B.rev 42
# Sig::ArgumentTypeError:
# - Expected 42 to respond to :reverse

There is also some academic work that explores advanced runtime checking (like "gradual" typing) and resulted in the Ruby Type Checker.

Future

But isn't the point of Ruby being a dynamic language and not having to care about types?

…which is true and false at the same time. We are still dealing with types, since we do type checks all the time. Type checking is not a binary question. As a matter of fact, some form of static typing will perhaps be introduced in Ruby 3.0!

Conclusion

Types are not evil, they are all around us. Ruby 3.0 may include a new typing system. That is great news! In order to be as rubyistic as possible, it should:

  • Be optional
  • Support duck types
  • Have an intuitive syntax
  • Perhaps use gradual typing
  • Help us all writing better programs

2020 update: Ruby 3.0 introduced types

Further Reading
https://idiosyncratic-ruby.com/37-static-monkeys-vs-strong-ducks.html
ERB Render Standard
Show full content

ERB stands for <%# Embedded Ruby %> and is the templating engine included in the Ruby Standard Library. While there are more recent gems that provide a better templating experience (see tilt for an abstraction, and erubis/erbse for an updated ERB), it is also convenient to have basic support directly in the standard library.

However, it does not directly support rendering data from a Hash, but only from a Binding object:¹

¹ Update: It is now possible with Ruby 2.5 – click here to see the best best practice

How to Render an ERB Template² (Pre 2.1)
require "erb"
require "ostruct"

def render_erb(template, data = nil)
  ERB.new(template, nil, "%<>").result(
    OpenStruct.new(data).instance_eval { binding }
  )
end

example_data = {
  idiosyncratic: "Ruby"
}

example_template = <<TEMPLATE
<%= idiosyncratic %> 3.0
TEMPLATE

render_erb(example_template, example_data) # => "Ruby 3.0\n"

² Actually, this also supports a (quite useful) additional syntax of ERB templates, "percent-lines":

example_template2 =<<TEMPLATE
% calculation = 2 + 1
Result is: <%= calculation %>
TEMPLATE

render_erb(example_template2) # => "Result is: 3\n"
How to Render an ERB Template (Post 2.1)

Ruby 2.1 came with Binding#local_variable_set, so we can remove OpenStruct from the equation:

require "erb"

def render_erb(template, data = {})
  render_binding = binding
  data.each{ |key, value| render_binding.local_variable_set(key.to_sym, value) }
  ERB.new(template, nil, "%<>").result(render_binding)
end

example_data = {
  idiosyncratic: "Ruby"
}

example_template = <<TEMPLATE
<%= idiosyncratic %> 3.0
TEMPLATE

render_erb(example_template, example_data) # => "Ruby 3.0\n"

Note: Both versions' bindings also contain the method arguments of render_erb, so you can access template and data from within the template. If you don't like this, you can can use TOPLEVEL_BINDING.dup to work around the local parameters.

How to Render an ERB Template (Post 2.5)

Ruby 2.5 finally introduces a way to render hashes:

require "erb"

def render_erb(template, data = {})
  ERB.new(template, nil, "%<>").result_with_hash(data)
end

example_data = {
  idiosyncratic: "Ruby"
}

example_template = <<TEMPLATE
<%= idiosyncratic %> 3.0
TEMPLATE

render_erb(example_template, example_data) # => "Ruby 3.0\n"
Also See
https://idiosyncratic-ruby.com/36-erb-render-standard.html
Identification
Show full content

Is it a hash? Or is it a hash?

hash = {"Idiosyncratic" => "Ruby"}
hash["Idiosyncratic"] # => "Ruby"

hash.compare_by_identity
idiosyncratic_in_variable = "Idiosyncratic"
hash[idiosyncratic_in_variable] # => nil
hash["Idiosyncratic"] # => "Ruby"

Hash#compare_by_identity changes the semantics of what is equal in a hash and what not. Only if exact the same object is passed in, the value will be retrieved.

Please note: The above example works for the key of"Idiosyncratic", because every string literal returns the same object. This behaviour has been introduced with Ruby 2.2, so running it in 2.1 or lower will return nil for the last line.

Hash Surprise

Identity hashes can feel very unnatural as the following snippet illustrates:

hash = {}.compare_by_identity

a="Idiosyncratic"
b="Idiosyncratic"
c="Idiosyncratic"

hash[a] = "Ruby1"
hash[b] = "Ruby2"
hash[c] = "Ruby3"

hash #=> {"Idiosyncratic"=>"Ruby1",
     #    "Idiosyncratic"=>"Ruby2",
     #    "Idiosyncratic"=>"Ruby3"}

# Quiz: What is the result of: hash["Idiosyncratic"]
Explicit Identity Hashes

What can be done to improve readability and reduce surprise? A starting point can be using an extra class:

class IdentityHash < Hash
  def initialize(*)
    super.compare_by_identity
  end

  def inspect
    "#<IdentityHash: #{super}>"
  end
end

For this class to be really useful it would need some more Hash-like features, like ActiveSupport does with HashWithIndifferentAccess. Still, it is already less confusable than some hash that looks like a normal hash and that you haven't checked compare_by_identity? for.

https://idiosyncratic-ruby.com/35-identification.html
Utility Gems
Show full content

RubyGems is bundled with core Ruby since 1.9, which was first released in 2007. As long as you do not run Ruby with the $ ruby --disable-gems flag, it is available to you without having to install anything. This also means that you can use some of RubyGems' support utilities for free!

1) Current Platform Info
Gem::Platform.local.os # => "linux"
Gem::Platform.local.cpu # => "x86_64"

The value is derived from RbConfig. Also see the OS gem, which provides similar functionality.

2) Gem::Util.gzip and Gem::Util.gunzip

Super simple access to text compression functionality:

require "rubygems/util"
s = "Ruby"*99
s.size #=> 396
c = Gem::Util.gzip(s)
c.size #=> 29
Gem::Util.gunzip(c) == s #=> true
3) Console Use Interface

If you don't feel like reinventing the wheel today, use RubyGems' neat user_interaction helpers:

require "rubygems/user_interaction"
ui = Gem::ConsoleUI.new

# Get Yes or No from the user
ui.ask_yes_no "Install, this script?", false
# ->
# Install, this script? [yN]

# Password Prompt
password = ui.ask_for_password "Master password:"
# ->
# Master password:

# Select Option
selected = ui.choose_from_list "How to move on?", [
"Go",
"Elixir",
"EcmaScript 2016",
"Real World Haskell"
]
# ->
# How to move on?
#  1. Go
#  2. Elixir
#  3. EcmaScript 2016
#  4. Real World Haskell
4) A List of Licenses

RubyGems includes some common license identifiers:

Gem::Licenses::LICENSE_IDENTIFIERS # =>
["0BSD", "AAL", "ADSL", "AFL-1.1", "AFL-1.2", "AFL-2.0", "AFL-2.1", "AFL-3.0", "AGPL-1.0", "AGPL-3.0", "AGPL-3.0-only", "AGPL-3.0-or-later", "AMDPLPA", "AML", "AMPAS", "ANTLR-PD", "APAFML", "APL-1.0", "APSL-1.0", "APSL-1.1", "APSL-1.2", "APSL-2.0", "Abstyles", "Adobe-2006", "Adobe-Glyph", "Afmparse", "Aladdin", "Apache-1.0", "Apache-1.1", "Apache-2.0", "Artistic-1.0", "Artistic-1.0-Perl", "Artistic-1.0-cl8", "Artistic-2.0", "BSD-1-Clause", "BSD-2-Clause", "BSD-2-Clause-FreeBSD", "BSD-2-Clause-NetBSD", "BSD-2-Clause-Patent", "BSD-3-Clause", "BSD-3-Clause-Attribution", "BSD-3-Clause-Clear", "BSD-3-Clause-LBNL", "BSD-3-Clause-No-Nuclear-License", "BSD-3-Clause-No-Nuclear-License-2014", "BSD-3-Clause-No-Nuclear-Warranty", "BSD-4-Clause", "BSD-4-Clause-UC", "BSD-Protection", "BSD-Source-Code", "BSL-1.0", "Bahyph", "Barr", "Beerware", "BitTorrent-1.0", "BitTorrent-1.1", "Borceux", "CATOSL-1.1", "CC-BY-1.0", "CC-BY-2.0", "CC-BY-2.5", "CC-BY-3.0", "CC-BY-4.0", "CC-BY-NC-1.0", "CC-BY-NC-2.0", "CC-BY-NC-2.5", "CC-BY-NC-3.0", "CC-BY-NC-4.0", "CC-BY-NC-ND-1.0", "CC-BY-NC-ND-2.0", "CC-BY-NC-ND-2.5", "CC-BY-NC-ND-3.0", "CC-BY-NC-ND-4.0", "CC-BY-NC-SA-1.0", "CC-BY-NC-SA-2.0", "CC-BY-NC-SA-2.5", "CC-BY-NC-SA-3.0", "CC-BY-NC-SA-4.0", "CC-BY-ND-1.0", "CC-BY-ND-2.0", "CC-BY-ND-2.5", "CC-BY-ND-3.0", "CC-BY-ND-4.0", "CC-BY-SA-1.0", "CC-BY-SA-2.0", "CC-BY-SA-2.5", "CC-BY-SA-3.0", "CC-BY-SA-4.0", "CC0-1.0", "CDDL-1.0", "CDDL-1.1", "CDLA-Permissive-1.0", "CDLA-Sharing-1.0", "CECILL-1.0", "CECILL-1.1", "CECILL-2.0", "CECILL-2.1", "CECILL-B", "CECILL-C", "CNRI-Jython", "CNRI-Python", "CNRI-Python-GPL-Compatible", "CPAL-1.0", "CPL-1.0", "CPOL-1.02", "CUA-OPL-1.0", "Caldera", "ClArtistic", "Condor-1.1", "Crossword", "CrystalStacker", "Cube", "D-FSL-1.0", "DOC", "DSDP", "Dotseqn", "ECL-1.0", "ECL-2.0", "EFL-1.0", "EFL-2.0", "EPL-1.0", "EPL-2.0", "EUDatagrid", "EUPL-1.0", "EUPL-1.1", "EUPL-1.2", "Entessa", "ErlPL-1.1", "Eurosym", "FSFAP", "FSFUL", "FSFULLR", "FTL", "Fair", "Frameworx-1.0", "FreeImage", "GFDL-1.1", "GFDL-1.1-only", "GFDL-1.1-or-later", "GFDL-1.2", "GFDL-1.2-only", "GFDL-1.2-or-later", "GFDL-1.3", "GFDL-1.3-only", "GFDL-1.3-or-later", "GL2PS", "GPL-1.0", "GPL-1.0+", "GPL-1.0-only", "GPL-1.0-or-later", "GPL-2.0", "GPL-2.0+", "GPL-2.0-only", "GPL-2.0-or-later", "GPL-2.0-with-GCC-exception", "GPL-2.0-with-autoconf-exception", "GPL-2.0-with-bison-exception", "GPL-2.0-with-classpath-exception", "GPL-2.0-with-font-exception", "GPL-3.0", "GPL-3.0+", "GPL-3.0-only", "GPL-3.0-or-later", "GPL-3.0-with-GCC-exception", "GPL-3.0-with-autoconf-exception", "Giftware", "Glide", "Glulxe", "HPND", "HaskellReport", "IBM-pibs", "ICU", "IJG", "IPA", "IPL-1.0", "ISC", "ImageMagick", "Imlib2", "Info-ZIP", "Intel", "Intel-ACPI", "Interbase-1.0", "JSON", "JasPer-2.0", "LAL-1.2", "LAL-1.3", "LGPL-2.0", "LGPL-2.0+", "LGPL-2.0-only", "LGPL-2.0-or-later", "LGPL-2.1", "LGPL-2.1+", "LGPL-2.1-only", "LGPL-2.1-or-later", "LGPL-3.0", "LGPL-3.0+", "LGPL-3.0-only", "LGPL-3.0-or-later", "LGPLLR", "LPL-1.0", "LPL-1.02", "LPPL-1.0", "LPPL-1.1", "LPPL-1.2", "LPPL-1.3a", "LPPL-1.3c", "Latex2e", "Leptonica", "LiLiQ-P-1.1", "LiLiQ-R-1.1", "LiLiQ-Rplus-1.1", "Libpng", "MIT", "MIT-CMU", "MIT-advertising", "MIT-enna", "MIT-feh", "MITNFA", "MPL-1.0", "MPL-1.1", "MPL-2.0", "MPL-2.0-no-copyleft-exception", "MS-PL", "MS-RL", "MTLL", "MakeIndex", "MirOS", "Motosoto", "Multics", "Mup", "NASA-1.3", "NBPL-1.0", "NCSA", "NGPL", "NLOD-1.0", "NLPL", "NOSL", "NPL-1.0", "NPL-1.1", "NPOSL-3.0", "NRL", "NTP", "Naumen", "Net-SNMP", "NetCDF", "Newsletr", "Nokia", "Noweb", "Nunit", "OCCT-PL", "OCLC-2.0", "ODbL-1.0", "OFL-1.0", "OFL-1.1", "OGTSL", "OLDAP-1.1", "OLDAP-1.2", "OLDAP-1.3", "OLDAP-1.4", "OLDAP-2.0", "OLDAP-2.0.1", "OLDAP-2.1", "OLDAP-2.2", "OLDAP-2.2.1", "OLDAP-2.2.2", "OLDAP-2.3", "OLDAP-2.4", "OLDAP-2.5", "OLDAP-2.6", "OLDAP-2.7", "OLDAP-2.8", "OML", "OPL-1.0", "OSET-PL-2.1", "OSL-1.0", "OSL-1.1", "OSL-2.0", "OSL-2.1", "OSL-3.0", "OpenSSL", "PDDL-1.0", "PHP-3.0", "PHP-3.01", "Plexus", "PostgreSQL", "Python-2.0", "QPL-1.0", "Qhull", "RHeCos-1.1", "RPL-1.1", "RPL-1.5", "RPSL-1.0", "RSA-MD", "RSCPL", "Rdisc", "Ruby", "SAX-PD", "SCEA", "SGI-B-1.0", "SGI-B-1.1", "SGI-B-2.0", "SISSL", "SISSL-1.2", "SMLNJ", "SMPPL", "SNIA", "SPL-1.0", "SWL", "Saxpath", "Sendmail", "SimPL-2.0", "Sleepycat", "Spencer-86", "Spencer-94", "Spencer-99", "StandardML-NJ", "SugarCRM-1.1.3", "TCL", "TCP-wrappers", "TMate", "TORQUE-1.1", "TOSL", "UPL-1.0", "Unicode-DFS-2015", "Unicode-DFS-2016", "Unicode-TOU", "Unlicense", "VOSTROM", "VSL-1.0", "Vim", "W3C", "W3C-19980720", "W3C-20150513", "WTFPL", "Watcom-1.0", "Wsuipa", "X11", "XFree86-1.1", "XSkat", "Xerox", "Xnet", "YPL-1.0", "YPL-1.1", "ZPL-1.1", "ZPL-2.0", "ZPL-2.1", "Zed", "Zend-2.0", "Zimbra-1.3", "Zimbra-1.4", "Zlib", "bzip2-1.0.5", "bzip2-1.0.6", "curl", "diffmark", "dvipdfm", "eCos-2.0", "eGenix", "gSOAP-1.3b", "gnuplot", "iMatix", "libtiff", "mpich2", "psfrag", "psutils", "wxWindows", "xinetd", "xpp", "zlib-acknowledgement"]

The data is also accessible via a special regex:

!!Gem::Licenses::REGEXP.match?("MIT") # => true
Gem::Licenses.match? "Ruby" # => true
Gem::Licenses.match? "Crossword" # => true
Gem::Licenses.match? "Idiosyncratic" # => false

Finally, it can also assist you with finding the right license:

Gem::Licenses.suggestions "ABC" #=> ["AAL", "AML", "DOC", "ISC", "W3C"]
5) Gem::Util.silent_system

Like Kernel#system, but without printing to STDOUT/STDERR. It will temporary replace STDOUT and STDERR with a null device:

require 'rubygems/util'
# create file 123, but output nothing
Gem::Util.silent_system "touch 123"

Note: If you don't want to print anything, but you are still interested in the commands output, you can use backticks!

6) Gem::Util.traverse_parents

Get a list of parent directories of a specific directory:

require 'rubygems/util'
puts Gem::Util.traverse_parents('.').to_a

# example

/home/jan/dev/idiosyncratic/source/posts
/home/jan/dev/idiosyncratic/source
/home/jan/dev/idiosyncratic
/home/jan/dev
/home/jan
/home
/
7) Deprecation Helper

RubyGems also provides a deprecate method:

$VERBOSE = true # activate interpreter warnings

module Kernel
  extend Gem::Deprecate
  deprecate :puts, :none, 2020, 12
  deprecate :format, :sprintf, 2016, 5
end

puts "test"
# NOTE: Object#puts is deprecated with no replacement. It will be removed on or after 2020-12-01.
# Object#puts called from (irb):9.

format "%.2f", 1
# NOTE: Object#format is deprecated; use sprintf instead. It will be removed on or after 2015-05-01.
# Object#format called from (irb):13.
https://idiosyncratic-ruby.com/34-utility-gems.html
Too Expressive & * _ ?
Show full content

Ruby's syntax is so expressive — it utilizes every printable, non-alphanumeric ASCII character as much as it cans. Sometimes, this can be confusing for beginners.

The next sections show 4+ different meanings of every portrayed single character (not counting different meaning as custom string delimiter or meaning within a regex):

Question Mark (4 Syntactical Meanings)

The question mark is a sure way to confuse your syntax highlighter!

Valid ending of a method name
[].empty? # => true
?: Part of the Ternary Operator
nil ? true : false # => false
? char literals
?? # => "?"
Part of Special Variable $?
system "ls"
$? #=> #<Process::Status: pid 5223 exit 0>
Underscore (5 Syntactical Meanings)

Underscores serve as a good example of having multiple uses: No purpose interferes with another.

Valid Part of an Identifier (and $_)
variable_name = 42
Part of Special Keywords (__END__, __FILE__, __caller__)
File.dirname(__FILE__)
Allowed to Visually Separate Numbers
1_000_000 # => 1000000
Ignored Parameter
# other names would raise a SyntaxError (duplicated argument name)
def method_name(_,_)
  p _
end

method_name(42, 23)
# -> 42
2.7: Numbered Parameter
def method_name(param)
  p _1
end

method_name(42)
# -> 42
Ampersand (6 Syntactical Meanings) && Method/Operator
p true && false
# => false
& Method/Operator for Numbers, Arrays, Booleans
# set operation "and"
[1, 2] & [2] # => 2

# bit operation "and"
2 & 3 # => 2
Explicit Block Param
def method_name(&block)
  p block.call(1)
  p block.call(2)
end

method_name{ |x| x.odd? }
# -> true
# -> false
to_proc Shortcut
class Class
  def to_proc
    lambda{ |*args| self.new(*args) }
  end
end

[[1,2],[3,5,6,7,3]].map(&Set) # => [Set[1,2], Set[5,6,7,3]]
Part of Special Variable $&
/sync/ =~ "Idiosyncratic"
$& # => "sync"
2.3: &. Safe Navigation Operator
nil&.blank? # => nil
Star (7 Syntactical Meanings)

The record holder!

.* Method/Operator for Numbers, Strings, Arrays
4 * 4 # => 16
["4", "2"] * "." # => "4.2"
.** Method/Operator for Numbers
4 ** 4 # => 256
* Rest Arguments
def method_name(*arguments)
  p arguments
end

method_name(42, 23)
# -> [42, 23]
* Splat Arguments
[1, *2..4] # => [1, 2, 3, 4]
** Keyword Rest Arguments
def method_name(**arguments)
  p arguments
end

method_name(a: 42, b: 23)
# -> { a: 42, b: 23 }
** Keyword Splat Arguments
hash1 = { a: 1, b: 2 }
hash2 = { c: 3, **hash1 } # => { a: 1, b: 2, c: 3 }
Part of Special Variable $*
$ ruby -e "p $*" -- 42 23
["42", "23"]
Also See
https://idiosyncratic-ruby.com/33-too-expressive.html
No More Errors
Show full content

If you don't like errors in your code, you will have to fix them. This handy list of Ruby's errors will hopefully help you do so! (And welcome back for the second season of Idiosyncratic Ruby!)

Built-in Exceptions Exception Thrown by core Ruby when Remarks NoMemoryError The Ruby interpreter could not allocate the required memory "Idiosyncratic" * 100_000_000_000 ScriptError - Not thrown directly ScriptError → LoadError A source file could not be loaded, required, or required relatively It is meant for source code the current program is running and therefore should not be used for other kinds of files ScriptError → NotImplementedError A feature of Ruby does not work on this platform/OS, for example, fork Although it is often used as "I have not implemented it (yet)", its original purpose is low-level platform support errors ScriptError → SyntaxError Invalid Ruby syntax was found Do not raise when parsing some other file format fails. It is meant for source code that the current program is running. SecurityError Mostly raised when attempting a forbidden $SAFE level 1 operation Use as base class for critical security issues, which should intentionally not be rescued by default SignalException A signal is received The common way to catch a signal is the trap method SignalException → Interrupt An interrupt signal (SIGINT) is received The common way to catch a signal is the trap method StandardError - Base class for normal exceptions. See next table. SystemExit Thrown by Kernel#exit Not thrown by Kernel#exit! SystemStackError Raised for stack overflows, for example, in case of infinite recursion Cannot always be caught by the interpreter fatal When a deadlock is discovered or this special vm exception is triggered Never rescuable. You can use this hack to get a reference to the error object: ObjectSpace.each_object(Class){|c| break c if c.ancestors.include?(Exception) && c.name == 'fatal' } StandardError

These will be caught by the rescue statement without defining an explicit error class.

Exception Thrown by core Ruby when Remarks ArgumentError Raised when a method is not given the proper arguments, for example, a wrong argument count Best class to inherit from for custom errors describing that the method usage was wrong ArgumentError → UncaughtThrowError When throw is used without the proper catch around - EncodingError Sometimes raised directly in unicode edge cases or when symbols are broken - EncodingError → Encoding:: CompatibilityError Raised when trying to combine strings of two incompatible encodings Example: "Idiosyn" +"crätic".encode("UTF-16LE") under UTF-8 leads to Encoding::CompatibilityError: incompatible character encodings: UTF-8 and UTF-16LE EncodingError → Encoding:: ConverterNotFoundError Raised when no encoding converter is available Example: "Idiosyncrätic".encode("ABC") under UTF-8 leads to Encoding::ConverterNotFoundError: code converter not found (UTF-8 to ABC) EncodingError → Encoding:: InvalidByteSequenceError String contains byte sequences not valid in the current encoding Example: "Idiosyncr\u{D800}tic".encode("ASCII") under UTF-8 leads to Encoding::InvalidByteSequenceError: "\xED" followed by "\xA0" on UTF-8 EncodingError → Encoding:: UndefinedConversionError Raised when an encoding converter is available, but it cannot convert a specific codepoint Example: "\u{00A0}".encode("EUC-JP") under UTF-8 leads to Encoding::UndefinedConversionError: U+00A0 from UTF-8 to EUC-JP FiberError Raised when an invalid operation is attempted on a Fiber Such as: Attempting to call/resume a dead Fiber, yield from the root fiber, calling a Fiber across threads IOError Raised when an IO operation fails, like opening a file Pay attention that there are some failures will raise a SystemCallError, which is not a sub-class of IOError! IOError → EOFError Raised by many IO operations when reaching the end of file - IndexError Raised when an element or deducted value cannot be retrieved, for example, when using Array#fetch Thrown by many core classes like Array, Regex, String, Struct or some standard libraries like strscan IndexError → KeyError Raised when an element cannot be retrieved (by a key), for example, when using Hash#fetch Mainly used by hashes IndexError → StopIteration Raised when an external iterator has reached its end You can use the Kernel#loop method to automatically catch StopIteration IndexError → StopIteration → ClosedQueueError Raised when trying to modify a closed Queue - LocalJumpError Thrown when an invalid control flow operation is attempted, like calling yield from a method that was not passed a block to LocalJumpErrors contains a reason and an exit_value property from the last valid context Math::DomainError An invalid mathematical operation was attempted, for example, trying to calculate the arctan of a value greater than 1 - NameError Raised when referencing things that do not exist, like unknown constants - NameError → NoMethodError Raised if trying to call a method that does not exist, and no method_missing is defined Trying to call non-existent private methods of self (like Kernel#puts) will result in NameError instead of NoMethodError, because it could also have been a local variable RangeError A numerical number is off, most often it is too small or big For example, [].pack("C100000000000000000000") does not work, because pack requires the number to fit into long RangeError → FloatDomainError Raised when trying to convert a special Float value (NaN, Float::INFINITY) to another number format that does not support special values - RegexpError Raised when trying to dynamically create an invalid regex - RuntimeError Unspecific occurrences Default error class that will be used when raising a string: raise "something" RuntimeError → FrozenError Raised when trying to modify a frozen object Introduced with Ruby 2.5 SystemCallError - Lower level system call errors. See next table. ThreadError Raised for invalid Thread operations - TypeError Violations against Ruby's type system For example, "" + nil will lead to "TypeError: no implicit conversion of nil into String" ZeroDivisionError An integer, complex, or rational number was tried to divide by another integer, complex, or rational number Floats and BigDecimal return Infinity, negative Infinity, or NaN SystemCallError

These errors are thrown by the operating system under certain circumstances. The exact list depends on your platform and can be found in a file called errno.h. You get such errors when working with processes, sockets, files, and other functionality that relies on low level system operations.

What follows is the list of errors that are known by Ruby. The error numbers and messages were generated on a recent ubuntu Linux machine. All system call errors are namespaced under Errno:: and can be dynamically created using SystemCallError.new(number).

Exception No Message Example One-Liner¹ Errno::E2BIG 7 Argument list too long - Errno::EACCES 13 Permission denied As non-root: File.read('/root') Errno::EADDRINUSE 98 Address already in use require "socket"; 2.times{ TCPServer.new("", 3003) } Errno::EADDRNOTAVAIL 99 Cannot assign requested address - Errno::EADV 68 Advertise error - Errno::EAFNOSUPPORT 97 Address family not supported by protocol - Errno::EAGAIN 11 Resource temporarily unavailable - Errno::EAGAIN → IO::EAGAINWaitReadable² - - STDIN.read_nonblock(1) (if blocking) Errno::EAGAIN → IO::EAGAINWaitWritable² - - - Errno::EALREADY 114 Operation already in progress - Errno::EBADE 52 Invalid exchange - Errno::EBADF 9 Bad file descriptor IO.new(-1) Errno::EBADFD 77 File descriptor in bad state - Errno::EBADMSG 74 Bad message - Errno::EBADR 53 Invalid request descriptor - Errno::EBADRQC 56 Invalid request code - Errno::EBADSLT 57 Invalid slot - Errno::EBFONT 59 Bad font file format - Errno::EBUSY 16 Device or resource busy - Errno::ECANCELED 125 Operation canceled - Errno::ECHILD 10 No child processes Process.wait (with no child processes) Errno::ECHRNG 44 Channel number out of range - Errno::ECOMM 70 Communication error on send - Errno::ECONNABORTED 103 Software caused connection abort - Errno::ECONNREFUSED 111 Connection refused require "socket"; TCPSocket.new("", rand(987654321)) Errno::ECONNRESET 104 Connection reset by peer - Errno::EDEADLK 35 Resource deadlock avoided - Errno::EDEADLOCK 35 Resource deadlock avoided - Errno::EDESTADDRREQ 89 Destination address required - Errno::EDOM 33 Numerical argument out of domain - Errno::EDOTDOT 73 RFS specific error - Errno::EDQUOT 122 Disk quota exceeded - Errno::EEXIST 17 File exists Dir.mkdir("/") Errno::EFAULT 14 Bad address - Errno::EFBIG 27 File too large - Errno::EHOSTDOWN 112 Host is down - Errno::EHOSTUNREACH 113 No route to host - Errno::EHWPOISON 133 Memory page has hardware error - Errno::EIDRM 43 Identifier removed - Errno::EILSEQ 84 Invalid or incomplete multibyte or wide character - Errno::EINPROGRESS 115 Operation now in progress - Errno::EINPROGRESS → IO::EINPROGRESSWaitReadable² - - - Errno::EINPROGRESS → IO::EINPROGRESSWaitWritable² - - - Errno::EINTR 4 Interrupted system call - Errno::EINVAL 22 Invalid argument Process.clock_gettime(42) Errno::EIO 5 Input/output error - Errno::EISCONN 106 Transport endpoint is already connected - Errno::EISDIR 21 Is a directory File.read("/") Errno::EISNAM 120 Is a named type file - Errno::EKEYEXPIRED 127 Key has expired - Errno::EKEYREJECTED 129 Key was rejected by service - Errno::EKEYREVOKED 128 Key has been revoked - Errno::EL2HLT 51 Level 2 halted - Errno::EL2NSYNC 45 Level 2 not synchronized - Errno::EL3HLT 46 Level 3 halted - Errno::EL3RST 47 Level 3 reset - Errno::ELIBACC 79 Can not access a needed shared library - Errno::ELIBBAD 80 Accessing a corrupted shared library - Errno::ELIBEXEC 83 Cannot exec a shared library directly - Errno::ELIBMAX 82 Attempting to link in too many shared libraries - Errno::ELIBSCN 81 .lib section in a.out corrupted - Errno::ELNRNG 48 Link number out of range - Errno::ELOOP 40 Too many levels of symbolic links - Errno::EMEDIUMTYPE 124 Wrong medium type - Errno::EMFILE 24 Too many open files - Errno::EMLINK 31 Too many links - Errno::EMSGSIZE 90 Message too long - Errno::EMULTIHOP 72 Multihop attempted - Errno::ENAMETOOLONG 36 File name too long File.read("Ruby"*1000) Errno::ENAVAIL 119 No XENIX semaphores available - Errno::ENETDOWN 100 Network is down - Errno::ENETRESET 102 Network dropped connection on reset - Errno::ENETUNREACH 101 Network is unreachable - Errno::ENFILE 23 Too many open files in system - Errno::ENOANO 55 No anode - Errno::ENOBUFS 105 No buffer space available - Errno::ENOCSI 50 No CSI structure available - Errno::ENODATA 61 No data available - Errno::ENODEV 19 No such device - Errno::ENOENT 2 No such file or directory File.read("does not exist") Errno::ENOEXEC 8 Exec format error - Errno::ENOKEY 126 Required key not available - Errno::ENOLCK 37 No locks available - Errno::ENOLINK 67 Link has been severed - Errno::ENOMEDIUM 123 No medium found - Errno::ENOMEM 12 Cannot allocate memory - Errno::ENOMSG 42 No message of desired type - Errno::ENONET 64 Machine is not on the network - Errno::ENOPKG 65 Package not installed - Errno::ENOPROTOOPT 92 Protocol not available - Errno::ENOSPC 28 No space left on device - Errno::ENOSR 63 Out of streams resources - Errno::ENOSTR 60 Device not a stream - Errno::ENOSYS 38 Function not implemented - Errno::ENOTBLK 15 Block device required - Errno::ENOTCONN 107 Transport endpoint is not connected - Errno::ENOTDIR 20 Not a directory - Errno::ENOTEMPTY 39 Directory not empty - Errno::ENOTNAM 118 Not a XENIX named type file - Errno::ENOTRECOVERABLE 131 State not recoverable - Errno::ENOTSOCK 88 Socket operation on non-socket - Errno::ENOTSUP 95 Operation not supported - Errno::ENOTTY 25 Inappropriate ioctl for device - Errno::ENOTUNIQ 76 Name not unique on network - Errno::ENXIO 6 No such device or address - Errno::EOPNOTSUPP 95 Operation not supported - Errno::EOVERFLOW 75 Value too large for defined data type - Errno::EOWNERDEAD 130 Owner died - Errno::EPERM 1 Operation not permitted - Errno::EPFNOSUPPORT 96 Protocol family not supported - Errno::EPIPE 32 Broken pipe - Errno::EPROTO 71 Protocol error - Errno::EPROTONOSUPPORT 93 Protocol not supported - Errno::EPROTOTYPE 91 Protocol wrong type for socket - Errno::ERANGE 34 Numerical result out of range - Errno::EREMCHG 78 Remote address changed - Errno::EREMOTE 66 Object is remote - Errno::EREMOTEIO 121 Remote I/O error - Errno::ERESTART 85 Interrupted system call should be restarted - Errno::ERFKILL 132 Operation not possible due to RF-kill - Errno::EROFS 30 Read-only file system - Errno::ESHUTDOWN 108 Cannot send after transport endpoint shutdown - Errno::ESOCKTNOSUPPORT 94 Socket type not supported - Errno::ESPIPE 29 Illegal seek - Errno::ESRCH 3 No such process Process.kill(:KILL, 987654321) Errno::ESRMNT 69 Surmount error - Errno::ESTALE 116 Stale file handle - Errno::ESTRPIPE 86 Streams pipe error - Errno::ETIME 62 Timer expired - Errno::ETIMEDOUT 110 Connection timed out - Errno::ETOOMANYREFS 109 Too many references: cannot splice - Errno::ETXTBSY 26 Text file busy - Errno::EUCLEAN 117 Structure needs cleaning - Errno::EUNATCH 49 Protocol driver not attached - Errno::EUSERS 87 Too many users - Errno::EWOULDBLOCK³ 11 Resource temporarily unavailable - Errno::EXDEV 18 Invalid cross-device link - Errno::EXFULL 54 Exchange full - Errno::NOERROR 0 Success -

¹ Feel free to suggest more one-liners
² These include IO::WaitReadable/IO::WaitWritable. See IO#read_nonblock.
³ EAGAIN == EWOULDBLOCK on most systems

Resources
https://idiosyncratic-ruby.com/32-no-more-errors.html
Roots of Rubyism
Show full content

This is a summary of reasons why you should still use Ruby:

It is a language with a terrific community (welcoming and always questioning itself) and ecosystem (a lot of problems already solved), which is beautiful (focus on productivity), a little conservative (in the sense that it is easy to work with), and general purpose (a good choice in most cases).

For a deeper understanding of Ruby's principles, reading matz is highly recommended:

The Philosophy Behind Ruby
https://idiosyncratic-ruby.com/31-roots-of-rubyism.html
Regex with Class
Show full content

Ruby's regex engine defines a lot of shortcut character classes. Besides the common meta characters (\w, etc.), there is also the POSIX style expressions and the unicode property syntax. This is an overview of all character classes:

Meta Chars Char Negation ASCII Unicode . - ¹ Any ¹ Any \X - Any Grapheme clusters (\P{M}\p{M}*) \d \D [0-9] ² ASCII plus Decimal_Number (Nd) \h \H [0-9a-fA-F] Like ASCII \w \W [0-9a-zA-Z_] ² ASCII plus Letter (LC / Ll / Lm / Lo / Lt / Lu), Mark (Mc / Me / Mn), Number (Nd / Nl / No), Connector_Punctuation (Pc) \s \S [ \t\r\v\n\f] ² ASCII plus Separator (Zl / Zp / Zs) \R - [\n\v\f\r],\r\n ASCII plus , Line_Separator (Zl), Paragraph_Separator (Zp)

¹ Will only match linebreaks with /m flag
² You'll need to manually turn on unicode matching for these to work

POSIX and Unicode Property Style POSIX Negation Property Negation³ ASCII Unicode [:alnum:] [:^alnum:] \p{Alnum} \p{^Alnum} [0-9a-zA-Z] Letter (LC / Ll / Lm / Lo / Lt / Lu), Mark (Mc / Me / Mn), Decimal_Number (Nd) [:alpha:] [:^alpha:] \p{Alpha} \p{^Alpha} [a-zA-Z] Letter (LC / Ll / Lm / Lo / Lt / Lu), Mark (Mc / Me / Mn) [:ascii:] [:^ascii:] \p{ASCII} \p{^ASCII} [\x00-\x7F] Like ASCII [:blank:] [:^blank:] \p{Blank} \p{^Blank} [ \t] \t, Space_Separator (Zs) [:cntrl] [:^cntrl:] \p{Cntrl} \p{^Cntrl} [\x00-\x1F], \x7F Other (Cc / Cf / Cn / Co / Cs) [:digit:] [:^digit:] \p{Digit} \p{^Digit} [0-9] ASCII plus Decimal_Number (Nd) [:graph:] [:^graph:] \p{Graph} \p{^Graph} [\x21-\x7E] ALL, EXCEPT: Separator (Zl / Zp / Zs), Control (Cc), Unassigned (Cn), Surrogate (Cs) [:lower:] [:^lower:] \p{Lower} \p{^Lower} [a-z] Lowercase_Letter (Ll) [:print:] [:^print:] \p{Print} \p{^Print} [\x20-\x7E] ALL, EXCEPT: Line_Separator (Zl), Paragraph_Separator (Zp) , Control (Cc), Unassigned (Cn), Surrogate (Cs) [:punct:] [:^punct:] \p{Punct} \p{^Punct} [!-/:-@\[-`{-~] Punctuation (Pc / Pd / Pe / Pf / Pi / Po / Ps) [:space:] [:^space:] \p{Space} \p{^Space} [ \t\r\v\n\f] ASCII plus Separator (Zl / Zp / Zs) [:upper:] [:^upper:] \p{Upper} \p{^Upper} [A-Z] Uppercase_Letter (Lu) [:xdigit:] [:^xdigit:] \p{XDigit} \p{^XDigit} [0-9a-fA-F] Like ASCII [:word:] [:^word:] \p{Word} \p{^Word} [0-9a-zA-Z_] ASCII plus Letter (LC / Ll / Lm / Lo / Lt / Lu), Mark (Mc / Me / Mn), Number (Nd / Nl / No), Connector_Punctuation (Pc)

³ An alternative way of negating unicode properties is \P{Property}

More Properties

The above groups are only the tip of the iceberg. Using the \p{} syntax, you can match for a lot more unicode properties, see Episode 41: Proper Unicoding for details!

Further Reading
https://idiosyncratic-ruby.com/30-regex-with-class.html
Limitations of Language
Show full content

If you take a closer look, you'll notice that Ruby's grammar has quite a few edge-case where its syntax is inconsistent or ambiguous:

Binary Minus vs Minus taken as Unary Method Argument
>> [1,3,4,5].size - 1
# => 3

>> [1,3,4,5].size -1
# wrong number of arguments(1 for 0)
No Simple Rule, if a Symbol can be Displayed Without the Explicit :"" Syntax
>> {:< => 0}
# => {:<=>0}

>> {:<=>0}
# syntax error, unexpected tINTEGER,
# expecting tASSOC
Ambiguous if to Parse ~ Unary or as Part of Binary Match Operator
>> $_="Eurucamp X"
>> ~/X/ # => 9

>> a=~/X/ # undefined local variable or method `a'
>> a= ~/X/ # => 9
Global Variables can "Break" String and Regex Syntax
>> a = "Eurucamp #\n"
>> a.gsub /#$/, ''
# => ?

>> a = "Eurucamp #\n"
>> a.gsub /#$/, ''
# unterminated regexp meets end of file

>> a = "Eurucamp #\n"
>> a.gsub /#$//, ''
# => "Eurucamp #"
Unary or Binary Plus, Part 2
>> p +21
# => 21

>> p = 21
>> p +21
# => 42
String Creation vs Format Method
>> puts%[1]
# undefined method `%' for nil:NilClass

>> puts %[1]
# => 1
Hash vs Block

Ruby uses curly braces for both, blocks as well as hashes. Sometimes, this leads to confusing cases:

>> def identity(a) a end

>> identity(1)
#=> 1
>> identity 1
#=> 1
>> identity({})
#=> {}
>> identity {}
#=> wrong number of arguments (0 for 1) (ArgumentError)
Regex vs Division
>> puts /4/i
# => (?i-mx:4)

>> puts, i = 42, 2
>> puts /4/i
# => 5
Further Reading
https://idiosyncratic-ruby.com/29-limitations-of-language.html
Operating Nothing
Show full content

There is an operator in Ruby, that does nothing: The unary plus operator. It is part of the language for keeping symmetry with the unary minus operator!

This is awesome, an operator for free! How can we utilize it?

Update: In Ruby 2.3, the plus operator got its first purpose: Create an unfrozen copy of a string

string = "frozen string".freeze
string.object_id # => 19066860
string.frozen? # => true

copy = +string
copy.object_id # => 19012140
copy.frozen? # => false
1 | Logging
require 'logger'

# Definition
$logger = Logger.new(STDOUT)

class Object
  def +@
    $logger.warn(self.inspect)
  end
end

# Usage
+/Ruby/
# => W, [2015-05-28T10:52:51.115334 #16630]  WARN -- : /Ruby/

We could use it for logging. But this is more of the category nice, but feels like there is no real reason for the syntactic sugar.

2 | Null Objects

A more useful case would be to simplify often done object conversions, for example, converting null objects to actual nil for comparisons:

# Definition
class Object
  def +@
    null? ? nil : self
  end

  def null?
    false
  end
end

class NilClass
  def null?
    true
  end
end

# Usage
class CustomNullObject
  def null?
    true
  end
end

null = CustomNullObject.new

+nil #=> nil
+null #=> nil
+"Ruby" #=> "Ruby"

See null_question and null_plus for a gemified version of the code above.

3 | Symbol Conversion

Another conversion related use of +@ is the following snippet, which also defines -@. It will convert String and Symbol into each other's representation. It can be used as some kind of alternative to libraries that provide HashWithIndifferentAccess-kind functionality, by always explicitly converting the key:

# Definition
class String
  def +@
    self
  end

  def -@
    to_sym
  end
end

class Symbol
  def +@
    to_s
  end

  def -@
    self
  end
end

# Usage
hash   = { key: "value" }
symbol = :key
string = "key"

hash[-symbol] # => "value"
hash[-string] # => "value"

By the way, this would not be needed, if we make symbols frozen strings!

4 | Test Rocket!

Thinking further: How to get most of out operators? How about a testing framework:

require 'testrocket'

# BASIC USAGE
# +-> { block that should succeed }
# --> { block that should fail }

+-> { Die.new(2) }
--> { raise }
+-> { 2 + 2 == 4 }

# These two tests will deliberately fail
+-> { raise }
--> { true }

# A 'pending' test
~-> { "this is a pending test" }

# A description
!-> { "use this for descriptive output and to separate your test parts" }

See peterc/testrocket for further info!

5 | Superators!

There was a library that carried operator magic to the extremes: It let you define superators, which are new binary operators that use a chain of unary operators as their name! This is what it looked like:

# Definition
class Array
  superator "<---" do |operand|
    if operand.kind_of? Array
      self + operand.map { |x| x.inspect }
    else
      operand.inspect
    end
  end
end

# Usage
[1,2,3] <--- [4,5,6]

The library is not maintained, anymore, but it is the craziest leveraging of Ruby's capabilities I've ever seen! The repo is at jicksta/superators.

https://idiosyncratic-ruby.com/28-operating-nothing.html
Golfing Basics
Show full content

Code Golf is the art of writing the shortest program possible. The less bytes the better. And the competition is just ridiculously strong! Head over to Anarchy Golf if you want to see more!

A good beginner's problem is printing out Pascal's Triangle: Spend a few days to get to 45 bytes. Spend a few months to get to 43 bytes!

Attention: A new golf course has opened at code.golf. Why not give it a try 😉?

10 Ruby Tricks You'll Learn by Playing Code Golf

While code golfing does not necessarily make you a better programmer, you can learn a lot about the programming language you are using. Here are some things that were new to me:

Dirty Interpolation

String interpolation (#{}) is sometimes possible without using curlies:

"You can directly interpolate #@instance variables, " \
"#@@class variables, and #$global variables!"

I must admit, this can confuse newcomers, but it looks fantastic!

Constant Assignment in Modifiers

It is perfectly legit to use assignments in conditions:

if a = 42
  p a
end
# => 42

However, this won't work with the shorter modifier syntax:

p b if b = 42
# NameError: undefined local variable or method `b'...

Unless… you use constants:

p C if C = 42
# => 42
Shebang require

What could possibly be shorter than:

require'json'; require 'yaml'
p JSON,YAML

It's inlined command-line options:

#!ruby -rjson -ryaml
p JSON,YAML
Iterating Input Lines

Finding the shortest way to read user input is a common problem for golfers and solutions vary, depending on how to process the input. My favorite one is to iterate over the input's lines:

$<.each{|e|p e}
Appending Output

puts and p are already good candidates to output content. However, sometimes, using << on STDOUT is a tiny bit (or byte) more efficient:

?a.upto(?z){|o|$><<o}
Regex Always Wins

This is one of the golden rules of golfing. Especially, combining the block syntax of gsub with the perlish regex variables can be very expressive!

"some_string".gsub(/(^|_)(\w)/){$2.upcase}
String#tr

However, it's not true - regexes do not always win. If you need to perform some simple character substitutions, tr is an extremely short (and also clean) way to do so:

# ROT13 Cipher
"Vqvbflapengvp Ehol".tr'a-zA-Z','n-za-mN-ZA-M'
# => "Idiosyncratic Ruby"
One More or Less

In some instances, you cannot use i+1 or i-1 without wrapping them in parenthesis. No problem, unary complement to the rescue:

-~42 # => 43
~-42 # => 41
Flexible Precedence

This is one of my favorites: Explicitly call (.) operators for alternative precedence semantics:

3*(2+1) #=> 9
3.*2+1 #=> 9
Quick Quit

What's a shorter way to quit a Ruby script than the 4 bytes long exit method?

1/0

Although this is longer than z (calling an undefined method), it's often easier to trigger programmatically.

https://idiosyncratic-ruby.com/27-golfing-basics.html
File Encoding Magic
Show full content

Ruby has three default encodings. One of them is the default source encoding, which can be set using a magic comment in the file's first line, or in the second line if the first line is taken by a shebang.

Default source encoding (UTF-8):

p "".encoding #=> #<Encoding:UTF-8>

With encoding comment (file_with_magic_comment.rb):

# coding: cp1252
p "".encoding #=> #<Encoding:Windows-1252>

See Magic Instructions for more information about magic comments in general.

Respecting the Encoding Comment when Reading a File

REMOVED IN RUBY 3.3!

You might come across a situation, where you want to read in a source file using Ruby's File class, but also want to set the proper encoding from the magic comment. Fortunately, Ruby's standard library supports this. Unfortunately, it is not a stand-alone module, but a part of IRB:

>> require 'irb/magic-file'
# => false
>> IRB::MagicFile
# => #<Object:0x00000001a6bb10>
>> File.open('file_with_magic_comment.rb').read.encoding
# => #<Encoding:UTF-8>
>> IRB::MagicFile.open('file_with_magic_comment.rb').read.encoding
# => #<Encoding:Windows-1252>
Also See
https://idiosyncratic-ruby.com/26-file-encoding-magic.html
Meta Methodology
Show full content

Ruby clutters its objects a lot with methods for metaprogramming other methods:

Class.instance_methods.grep /method/
=> [:instance_methods, :public_instance_methods,
:protected_instance_methods, :private_instance_methods,
:method_defined?, :public_method_defined?,
:private_method_defined?, :protected_method_defined?,
:public_class_method, :private_class_method, :instance_method,
:public_instance_method, :methods, :singleton_methods,
:protected_methods, :private_methods, :public_methods,
:method, :public_method, :singleton_method,
:define_singleton_method]

Class.private_instance_methods.grep /method/
=> [:method_added, :method_removed, :method_undefined,
:remove_method, :undef_method, :alias_method, :define_method,
:instance_methods_for, :__method__, :singleton_method_added,
:singleton_method_removed, :singleton_method_undefined,
:method_missing]

It's so many methods, because working with methods is a multi-dimensional problem:

  • Where are the modules, in the current instance or if a class/module, in its instances?
  • Or in its singleton class?
  • What about the method visibility?
  • Should the inheritance chain be considered?

Let's put everything in some order:

Method Lists

Methods returning method lists always take a boolean argument, which will prevent inheritance if set to false¹

Method From Target Visibility Object#singleton_methods any singleton public + protected Object#methods any self + singleton public + protected Object#public_methods any self + singleton public Object#protected_methods any self + singleton protected Object#private_methods any self + singleton private Module#instance_methods class instances public + protected Module#public_instance_methods class instances public Module#protected_instance_methods class instances protected Module#private_instance_methods class instances private
  • There is no API for getting a list of private singleton methods
  • ¹ A special case is the methods method: If false is given as argument, it will switch target to singleton only
Method Defined? Checks

Instead of listing all methods and checking if the resulting array contains a specific method, you can also directly check if a method is defined.

Since Ruby 2.6, you can also pass in a boolean as second argument which will ignore the inheritance chain (similar like it is with the method listings above).

Method From Target Visibility Module#method_defined? class instances all Module#public_method_defined? class instances public Module#protected_method_defined? class instances protected Module#private_method_defined? class instances private
  • This is also the best way to get the visibility of a method
  • There is no direct way to check for singleton methods
Method Getters

These methods will return method objects for further metaprogramming action:

Method From Target Visibility Returns Object#singleton_method any singleton all Method Object#method any self + singleton all Method Object#public_method any self + singleton public Method Module#instance_method class instances all UnboundMethod Module#public_instance_method class instances public UnboundMethod
  • There are no methods to explicitly get private methods
Method Manipulation

These methods will actually modify your objects:

Method From Target Visibility Object#define_singleton_method any singleton public Module#define_method (private) class instances public (see notes) Module#remove_method (private) class instances - Module#undef_method (private) class instances - Module#alias_method (private) class instances same
  • No direct way to define a non-public method, but define_method respects visibility modifiers
  • No direct way to define a non-public singleton method
  • remove_method only deletes the method from the current module, while undef_method also deletes it from all ancestors
Method Hooks

Hook methods can be defined and will be called by the Ruby interpreter when the respective event happens:

Method From Target BasicObject#singleton_method_added any singleton BasicObject#singleton_method_undefined any singleton BasicObject#singleton_method_removed any singleton Module#method_added class instances Module#method_undefined class instances Module#method_removed class instances BasicObject#method_missing class instances
  • As long as you haven't defined a hook, Ruby considers it as an empty private method
Method Visibility Modifiers

Besides public, protected, and private, there are two additional methods with the sole purpose of changing a method's visibility:

Method From Target Description Module#public_class_method class singleton Makes a class's singleton method public Module#private_class_method class singleton Makes a class's singleton method private Current Method Name

There are two underscore-wrapped methods that return the current method's name:

Method From Returns Kernel#__method__ (private) any Original method name Kernel#__callee__ (private) any Aliased method name A Better API for Metaprogramming Methods?

Metaprogramming in Ruby has evolved over time, but it might be a good idea to clean it up a little - A good example of how to clean up one of Ruby's other metaprogramming APIs is the instance gem. It gives you a neat API for working with an object's state, like setting instance variables. Someone feels like building a similar gem for Ruby's Method APIs? 2019 Update: I gave it a try! You can see the results here: object_shadow

https://idiosyncratic-ruby.com/25-meta-methodology.html
Goto Fail
Show full content

If you change one line in Ruby's source, it will support goto statements!

You can install a patched version via RVM's patch feature:

$ rvm install 2.2.2 -n goto --patch http://git.io/vfxF2
$ rvm use 2.2.2-goto

What to do to play around with this new feature? Let's reimplement this famous bug in Ruby:

# prepare some dummy data
hashCtx = hashOut = clientRandom = serverRandom = signedRandom = Object.new
SSLHashSHA1 = Class.new do def update(*) end; alias final update end.new

# how the goto fail bug would look like if it was implemented in ruby
__goto__(:fail) if ((err = SSLHashSHA1.update(hashCtx, clientRandom)) != 0);
__goto__(:fail) if ((err = SSLHashSHA1.update(hashCtx, serverRandom)) != 0);
__goto__(:fail) if ((err = SSLHashSHA1.update(hashCtx, signedParams)) != 0);
__goto__(:fail);
__goto__(:fail) if ((err = SSLHashSHA1.final(hashCtx, hashOut)) != 0);

puts "Verified" # never reached
# ...

__label__(:fail);
puts "Failed";

Executing this with gotoruby:

$ rvm use 2.2.2-goto
$ ruby gotofail.rb
Failed
Further Reading
https://idiosyncratic-ruby.com/24-goto-fail.html
Ruby Lookalikes
Show full content

Tired of good old, but slow Ruby? Try one of Ruby's successors:

Name Compiles To Description Crystal Machine Fast Ruby Mirah JVM Fast Ruby in Java Opal JS Ruby for JavaScript CoffeeScript JS JavaScript for Rubyists Elixir BEAM Ruby for Erlang Scala JVM Multi-Paradigm Ruby Rooby Machine Simple Ruby Rubex Machine Ruby Extensions Ruby Goby Machine Go meets Ruby

All of them are better than Ruby, in some way!

https://idiosyncratic-ruby.com/23-ruby-lookalikes.html
Literate Ruby
Show full content

Ruby has a built-in feature that is much like Literate CoffeeScript. In contrast to it, this Ruby option will not ignore literature, but garbage:

-x[directory]
Tells Ruby that the script is embedded in a message.
Leading garbage will be discarded until the  first line
that starts with “#!” and contains the string, “ruby”.
Any meaningful switches on that line will be applied.
The end of the script must be specified with either EOF,
^D (control-D), ^Z (control-Z), or the reserved word
__END__.  If the directory name is specified, Ruby will
switch to that directory before executing script.

Awesome!

#! Let's see this in action, using this blog post about ruby
puts "Idiosyncratic Ruby"
__END__

Paste the whole content of this article into a file and execute it with:

$ ruby -x FILENAME
Further Reading
  • man ruby
https://idiosyncratic-ruby.com/22-literate-ruby.html
Uniform Resource Matching
Show full content

Ruby's URI standard library contains a very sophisticated regex for matching URLs:

"At https://idiosyncratic-ruby.com you can learn about the " \
"obscure parts of Ruby"[URI.regexp]
# => "https://idiosyncratic-ruby.com"

This regex is built in uri/rfc2396_parser.rb and looks like this:

$ ruby -v
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
$ ruby -r uri -e 'p URI.regexp'
/
        ([a-zA-Z][\-+.a-zA-Z\d]*):                           (?# 1: scheme)
        (?:
           ((?:[\-_.!~*'()a-zA-Z\d;?:@&=+$,]|%[a-fA-F\d]{2})(?:[\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]|%[a-fA-F\d]{2})*)                    (?# 2: opaque)
        |
           (?:(?:
             \/\/(?:
                 (?:(?:((?:[\-_.!~*'()a-zA-Z\d;:&=+$,]|%[a-fA-F\d]{2})*)@)?        (?# 3: userinfo)
                   (?:((?:(?:[a-zA-Z0-9\-.]|%\h\h)+|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[(?:(?:[a-fA-F\d]{1,4}:)*(?:[a-fA-F\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|(?:(?:[a-fA-F\d]{1,4}:)*[a-fA-F\d]{1,4})?::(?:(?:[a-fA-F\d]{1,4}:)*(?:[a-fA-F\d]{1,4}|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}))?)\]))(?::(\d*))?))? (?# 4: host, 5: port)
               |
                 ((?:[\-_.!~*'()a-zA-Z\d$,;:@&=+]|%[a-fA-F\d]{2})+)                 (?# 6: registry)
               )
             |
             (?!\/\/))                           (?# XXX: '\/\/' is the mark for hostport)
             (\/(?:[\-_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*(?:;(?:[\-_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*)*(?:\/(?:[\-_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*(?:;(?:[\-_.!~*'()a-zA-Z\d:@&=+$,]|%[a-fA-F\d]{2})*)*)*)?                    (?# 7: path)
           )(?:\?((?:[\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]|%[a-fA-F\d]{2})*))?                 (?# 8: query)
        )
        (?:\#((?:[\-_.!~*'()a-zA-Z\d;\/?:@&=+$,\[\]]|%[a-fA-F\d]{2})*))?                  (?# 9: fragment)
      /x
Further Reading
https://idiosyncratic-ruby.com/21-uniform-resource-matching.html
Better Standards
Show full content

A guide to Ruby's stdlib and available alternatives.

Please note: The standard library was turned into gems, see stdgems.org for up-to-date information on all standard gems!

Standard Library Overview

Library Sources Description Alternatives abbrev mri Small library that finds the shortest abbreviation to identify one string amongst many - base64 mri Encodes and decodes strings to a Base64 representation. Implemented as a small wrapper around String#unpack - continuation mri Deprecated library that adds the goto-like Kernel#callcc Concurrent Ruby, Fiber coverage c mri Measures code coverage - debug mri Command-line debugger byebug digest c mri Provides common hash functions like MD5, SHA1, SHA2, or RIPEMD-160 OpenSSL::Digest drb mri Distributed object system for Ruby - English mri Readable aliases for special global variables - erb mri Templating engine for Ruby erubis, erbse, erubi expect mri Adds IO#expect, which can be used to wait for a specific pattern to be read - fiber c mri Adds Fiber#transfer and Fiber#alive? - find mri Finds all files in a given directory and its sub-directories `find .`.split($/) io/nonblock c mri Allows to work with IO streams in a non-blocking way - io/wait c mri Adds methods to wait until an IO stream becomes readable or writable - mkmf mri Generates Makefiles for native C extensions - monitor mri Monitors for multi-threaded code - net/ftp mri Support for FTP (File Transfer Protocol) - net/http mri Support for HTTP (Hypertext Transfer Protocol) http.rb, em-http-request, excon, httpclient net/imap mri Support for IMAP (Internet Message Access Protocol) em-imap nkf c mri Kanji encoding converter - objspace c mri Adds more statistics methods to ObjectSpace - open-uri mri Monkeypatches Kernel#open to support remote endpoints via net/http and net/ftp - optparse mri Command-line option parser slop, optimist, clap, rationalist pathname c mri Wraps File, FileTest, Dir, and FileUtils to ease working with file system paths path prettyprint mri Better object formatting and inspection. Comes with the pp print debugging helper via require 'pp' wirb, hirb, awesome_print profiler mri Measures which methods are called and how long each method takes to complete. Auto-start via require 'profile' ruby-prof, perftools.rb, method_profiler pty c mri Manages pseudo terminals - racc c mri
gem A YACC-like LALR(1) parser generator parslet, citrus, treetop rbconfig - RbConfig is a Ruby constant that contains compile time information - resolv mri Thread-aware DNS resolver. Will replace Socket's DNS via require 'resolve-replace' rubydns, net-dns, em-resolve-replace rinda mri Support fot the Linda distributed computing paradigm in drb - ripper c mri Ruby parser that creates a symbolic expression tree ruby_parser, parser securerandom mri Provides crpytographical randomness from openssl or the OS - set mri Data structure for unordered collections without duplicates. Implemented on top of Hash. Also comes with SortedSet for ordered collections. - shellwords mri Escape and manipulate commands to be run in the shell - socket c mri Support for unix- and network sockets - syslog c mri Interface to the low-level syslog logger syslogger, log4r, lumberjack_syslog_device, yell-adapters-syslog tempfile mri Simplifies OS independent creation of temporary files - time mri Adds more methods to Time - tmpdir mri Adds a Dir.mktmpdir method for creating temporary directories OS independently - tsort mri Typological sorting using Tarjan’s algorithm, which finds strongly connected components in graphs - un mri Utilities to replace common UNIX commands - unicode_normalize
(auto-require) mri Adds a String#unicode_normalize method which normalizes unicode strings unf, unicode weakref mri Explicitly allow objects to be garbage collected ref Win32API c mri Let's you use Windows APIs, like calling functions in DLLs win32-api, ffi win32ole c mri Windows OLE automation interface - Default Gems

These libraries come as default Ruby gems, so that they can be updated independently from Ruby. See stdgems.org for more info.

Gem Sources Description Alternatives benchmark mri
gem Benchmarking library benchmark-ips, benchmark-driver bigdecimal c mri
gem Support for arbitrary-precision floating point decimal arithmetic - bundler mri
gem Bundler is the local package manager for Ruby applications - cgi mri
gem Support for CGI (Common Gateway Interface) rack csv mri
gem Support for CSV (Comma-separated Values) smarter_csv date c mri
gem The Date and DateTime classes - dbm c mri
gem Support for DBM databases - delegate mri
gem Provides three ways to delegate method calls forwardable did_you_mean
(auto-require) mri
gem Patches error messages to suggest correct spelling of methods/classes/variables - etc c mri
gem Access UNIX info from /etc - fcntl c mri
gem Loads values from the OS' fcntl.h to be used for low-level file descriptor manipulation system calls with IO#fcntl and IO.sysopen - fiddle c mri
gem Support for FFI (Foreign Function Interface) ffi fileutils mri
gem Utilities for working with the file system - forwardable mri
gem Provides a way to delegate method calls. Also see this overview of delegation in Ruby, which contains an example - gdbm c mri
gem Support for GNU dbm databases - getoptlong mri
gem GNU getopt_long() style command-line option parsing OptParse, slop, optimist, clap, rationalist io/console c mri
gem Patches IO for simple and portable access to the console - ipaddr mri
gem IP address manipulation ipaddress, ruby-ip irb mri Interactive Ruby Console (REPL) ripl, pry, rib json c mri
gem Support for JSON (JavaScript Object Notation) oj, yajl-ruby logger mri
gem Logging utility log4r, lumberjack, yell, logging, micrologger matrix mri
gem Support for matrices nmatrix mutex_m mri
gem A mixin that makes any object behave like a mutex - observer mri
gem Implementation of the observer pattern, a way to let interested other objects know o an object's updates microevent, signal_lamp net/pop mri
gem Support for POP3 (Post Office Protocol) - net/smtp mri
gem Support for SMTP (Simple Mail Transfer Protocol) - open3 mri
gem Simple spawning of child processes open4 openssl c mri
gem Wraps OpenSSL for cryptographic functionality - ostruct mri
gem Wrapper around Hash that lets you read and set attributes with a method API Hash, ostruct2 prime mri
gem Access to prime numbers and prime factorization - pstore mri
gem Transactional file storage for Ruby objects - psych c mri
gem Support for YAML (YAML Ain't Markup Language) - rdoc mri
gem Ruby documentation generator yard readline mri
gem If available, readline-ext will be loaded, or (Ruby-only) reline will be used - readline-ext mri
gem Interface to GNU Readline and NetBSD Editline rb-readline, reline reline mri
gem Ruby-only implementation of GNU Readline / NetBSD Editline rb-readline rexml mri
gem Support for XML (Extensible Markup Language) nokogiri, oga rss mri
gem Support for RSS (Rich Site Summary) and Atom - rubygems
(auto-require) mri
gem Manages Ruby libraries. - sdbm c mri
gem Support for SDBM databases - singleton mri
gem Mixin for Ruby classes that should only have one instance - stringio c mri
gem Makes strings behave like IO objects - strscan c mri
gem Lexical string scanning - timeout mri
gem Auto-terminates code blocks after the time limit is reached - tracer mri
gem Outputs the code execution trace via Kernel#set_trace_func TracePoint uri mri
gem URI/URL manipulation addressable,ruby-uriparser webrick mri
gem HTTP server thin, unicorn, puma yaml mri
gem Loads the psych yaml parser and sets YAML = Psych - zlib c mri
gem Interface to the zlib compression library - Bundled Gems

Gems that will be installed together with Ruby. See stdgems.org for more info.

Gem Description Alternatives minitest Test/spec framework, comes with mocking and benchmark capabilities rspec net-telnet Support for Telnet - power_assert Debug tool that displays intermediate results of a method chain - rake A Ruby task runner, inspired by make thor, boson test-unit A xUnit family unit testing framework minitest, rspec xmlrpc Remote Procedure Calls via XML and HTTP -

Something's wrong or missing? You can edit this list on GitHub!

Resources
https://idiosyncratic-ruby.com/20-better-standards.html
Symbolic Reservations
Show full content

This episode takes a look at the unusual use of symbols in one of Ruby's core APIs:

Enumerable#chunk

The chunk method splits the receiver object into multiple enumerators, using the rule defined in the block. It keeps together the parts that match in series. It then passes the result of this rule and an enumerator of the successive elements to the given block:

(1..42).chunk{ |n| n % 11 == 0 }.each{ |result, elements|
  puts "#{result}: #{elements * ' - '}"
}
# false: 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10
# true: 11
# false: 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21
# true: 22
# false: 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 31 - 32
# true: 33
# false: 34 - 35 - 36 - 37 - 38 - 39 - 40 - 41 - 42

You can use this to order numbers in quotient rings:

a = (0..4).map{ [] }
(1..42).chunk{ |n| n % 5 }.each{ |remainder, elements|
  a[remainder] += elements
}
puts a.map(&:inspect)
# [5, 10, 15, 20, 25, 30, 35, 40],    # every number where n % 5 == 0
# [1, 6, 11, 16, 21, 26, 31, 36, 41], # every number where n % 5 == 1
# [2, 7, 12, 17, 22, 27, 32, 37, 42], # every number where n % 5 == 2
# [3, 8, 13, 18, 23, 28, 33, 38],     # every number where n % 5 == 3
# [4, 9, 14, 19, 24, 29, 34, 39]      # every number where n % 5 == 4

The reason I am bringing it up as idiosyncratic is: You can use special symbols to influence the behavior of the chunk method, when used as the block return value. Anyone has seen something like this anywhere else in Ruby?

Let's revisit a shortened version of the example at the top:

(1..42).chunk{ |n| n % 11 == 0 }.to_a
# => [
#   [false, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]], [true, [11]],
#   [false, [12, 13, 14, 15, 16, 17, 18, 19, 20, 21]], [true, [22]],
#   [false, [23, 24, 25, 26, 27, 28, 29, 30, 31, 32]], [true, [33]],
#   [false, [34, 35, 36, 37, 38, 39, 40, 41, 42]]
# ]

It does nothing, when you pass in an arbitrary symbol as filter rule:

(1..42).chunk{ :symbol }.to_a
# => [
#   [:symbol, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
#   18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
#   36, 37, 38, 39, 40, 41, 42]]
# ]

However, when passing the special symbol :_alone, every element will be separated:

(1..42).chunk{ :_alone }.to_a
# => [
#   [:_alone, [1]], [:_alone, [2]], [:_alone, [3]], [:_alone, [4]], [:_alone, [5]],
#   [:_alone, [6]], [:_alone, [7]], [:_alone, [8]], [:_alone, [9]], [:_alone, [10]],
#   [:_alone, [11]], [:_alone, [12]], [:_alone, [13]], [:_alone, [14]],
#   [:_alone, [15]], [:_alone, [16]], [:_alone, [17]], [:_alone, [18]],
#   [:_alone, [19]], [:_alone, [20]], [:_alone, [21]], [:_alone, [22]],
#   [:_alone, [23]], [:_alone, [24]], [:_alone, [25]], [:_alone, [26]],
#   [:_alone, [27]], [:_alone, [28]], [:_alone, [29]], [:_alone, [30]],
#   [:_alone, [31]], [:_alone, [32]], [:_alone, [33]], [:_alone, [34]],
#   [:_alone, [35]], [:_alone, [36]], [:_alone, [37]], [:_alone, [38]],
#   [:_alone, [39]], [:_alone, [40]], [:_alone, [41]], [:_alone, [42]]
# ]

There is also the special symbol :_separator, which drops every element:

(1..42).chunk{ :_separator }.to_a
# => []

Normally you don't want to return :_alone or :_separator for every element, but in specific instances of your filter rule, which is legit. The question remains, is this a good API for the future of Ruby?

One more thing: Unknown special symbols (those that start with _) will raise a RuntimeError:

(1..42).chunk{ :_future }.to_a
# RuntimeError: symbols beginning with an underscore are reserved
Resources
https://idiosyncratic-ruby.com/19-semantic-symbols.html
Con-Struct Attributes
Show full content

Ruby's Struct class is a convenient way to create Ruby classes, which already have some attributes defined. If you are not familiar with structs, you should watch Avdi Grimm's introduction to structs!

But in many cases there is something better than structs:

Gems that Define Attributes for "Plain Old Ruby Objects"

Instead of using a specialized struct-class (which has different semantics), you could also go with normal Ruby classes. What follows is a collection of gems you could use for this purpose.

At the bottom, there are also some tips, when to use structs and what to bear in mind regarding structs.

Virtus

virtus: Attributes on Steroids for Plain Old Ruby Objects

require 'virtus'

class Person
  include Virtus.model

  attribute :name
  attribute :age
end

Person.new(name: "Jan", age: 26)
# => #<Person:0x00000001ad85a8 @name="Jan", @age=26>
Active Attr

active_attr: What ActiveModel left out

require 'active_attr'

class Person
  include ActiveAttr::MassAssignment
  attr_accessor :name, :age
end

Person.new(name: "Jan", age: 26)
# => #<Person:0x00000002464f18 @name="Jan", @age=26>
Fast Attributes

fast_attributes: FastAttributes adds attributes with their types to the class

require 'fast_attributes'

class Person
  extend FastAttributes

  define_attributes initialize: true do
    attribute :name, Object
    attribute :age, Object
  end
end

Person.new(name: "Jan", age: 26)
# => #<Person @name="Jan", @age=26>
Attrio

attrio: Attributes for plain old Ruby objects. No dependencies, only simplicity and clearness.

require 'attrio'

class Person
  include Attrio

  define_attributes do
    attr :name
    attr :age
  end

  def initialize(attributes = {})
    self.attributes = attributes
  end


  def attributes=(attributes = {})
    attributes.each do |attr,value|
      self.send("#{attr}=", value) if self.respond_to?("#{attr}=")
    end
  end
end

Person.new(name: "Jan", age: 26)
# => <Person name: "Jan", age: 26>
attr_extras

attr_extras: Takes some boilerplate out of Ruby with methods like attr_initialize.

require 'attr_extras'

class Person
  attr_initialize :name, :age
  attr_reader :name, :age
end

Person.new("Jan", 26)
# => #<Person:0x0000000216ed40 @name="Jan", @age=26>
Concord

concord: Mixin to ease compositions under ruby

require 'concord'

class Person
  include Concord.new(:name, :age)
end

Person.new("Jan", 26)
# => #<Person name="Jan" age=26>
Fatter Attr

fattr: fattr.rb is a "fatter attr" for ruby and borrows heavily from the metakoans.rb ruby quiz

require 'fattr'

class Person
  fattrs :name, :age
end

person = Person.new
person.name = "Jan"
person.age  = 26
person
# => #<Person:0x0000000147d7a8 @name="Jan", @age=26>
Anima

anima: Object initializer from attributes hash

require 'anima'

class Person
  include Anima.new(:name, :age)
end

Person.new(name: "Jan", age: 26)
# => #<Person name="Jan" age=26>
KWAttr

kwattr: attr_reader + initialize with keyword arguments

require 'kwattr'

class Person
  kwattr :name, :age
end

Person.new(name: "Jan", age: 26)
# => #<Person:0x00000002602988 @name="Jan", @age=26>
dry-struct

dry-struct: dry-struct is a gem built on top of dry-types which provides virtus-like DSL for defining typed struct classes.

require "dry-struct"

module Types
  include Dry::Types()
end

class Person < Dry::Struct
  attribute :name, Types::Strict::String.optional
  attribute :age, Types::Coercible::Integer
end

Person.new(name: "Jan", age: 26)
# => #<Person name="Jan" age=26>
Structs are Still Useful… as Value Objects

Structs are different from normal Ruby classes, but they are still very useful for creating value objects. Value objects should be immutable and the following gems assist you in creating read-only objects with a Struct-like API:

Values

values: Simple immutable value objects for ruby (the readme is longer than the code)

require 'values'

Person = Value.new(:name, :age)
Person.new("Jan", 26) # => <Person name="Jan", age=26>
Immutable Struct

immutable_struct: An immutable version of Ruby's Struct class

require 'immutable_struct'

Person = ImmutableStruct.new(:name, :age)
Person.new("Jan", 26) # => #<struct Person name="Jan", age=26>
Value Struct

value_struct: Read-only structs in Ruby

require 'value_struct'

Person = ValueStruct.new(:name, :age)
Person.new("Jan", 26) # => #<ValueStruct Person name="Jan", age=26>
Why Not Structs Everywhere?
  • You cannot access its instance variables directly
  • Structs have their own methods (like [], a getter for variables), which might not always be useful
  • Pitfalls when creating structs with custom behavior (see below)

The different ways to initialize a Struct:

Inherit

One way to add custom methods to a struct is to directly sub-class it:

class Person < Struct.new(:name, :age)
  def name_and_age
    "#{name}, #{age}"
  end
end

The bad thing about this is that it will add an additional entry to your ancestor chain:

Person.ancestors # => [Person, #<Class:0x00000001612140>, Struct, ...]
Block

This can be avoided by passing a block to the initializer:

Person = Struct.new(:name, :age) do
  def name_and_age
    "#{name}, #{age}"
  end
end

However, you got a new problem with this approach: You are not in the define a class scope. This can be confusing when working with constants:

Person = Struct.new(:name, :age) do
  MAXIMUM_AGE = 120
end

This will create a top-level constant MAXIMUM_AGE instead of a namespaced Person::MAXIMUM_AGE one.

Reopen

The approach that avoids both problems, is a little bit more verbose, but well readable:

Person = Struct.new(:name, :age)

class Person
  def name_and_age
    "#{name}, #{age}"
  end
end

It also seems to perform slightly better than the other options.

Further Reading
https://idiosyncratic-ruby.com/18-con-struct-attributes.html
Stream Editing
Show full content

One of Ruby's goals was to replace popular unix stream editors like awk or sed, which both have the concept of manipulating files in a line-based manner. Ruby has the -n option for this:

Causes Ruby to assume the following loop around your script, which makes it
iterate over file name arguments somewhat like sed -n or awk.

      while gets
        ...
      end

And its sibling -p:

Acts mostly same as -n switch, but print the value of variable $_ at the each
end of the loop.
For example:

      % echo matz | ruby -p -e '$_.tr! "a-z", "A-Z"'
      MATZ

What you need to know is that the special global variable $_ contains the last read input. When using -n or -p, this usually means the current line. Another thing to keep in mind: gets reads from ARGF, not from STDIN, so you can pass arguments that will be interpreted as filenames of the files that should be processed. Equipped with this knowledge, you can build a very basic example, which just prints out the given file:

$ ruby -ne 'print $_' filename

Since print without arguments implicitly prints out $_, this can be shortened to:

$ ruby -ne 'print' filename

If one uses -p, instead of -n, no code is required, because -p will call print implicitly:

$ ruby -pe '' filename

Now let's modify each line:

$ ruby -pe '$_.reverse!' filename

This will print out the file with all its lines reversed.

Here is another example, which will print every line in a random ANSI color:

$ ruby -ne 'print "\e[3#{rand(8)}m#$_"' filename

There is more to assist you in writing these short line manipulation scripts:

The Ruby One-Liner Toolbox
  • CLI Options: -n -p -0 -F -a -i -l
  • Global Variables: $_ $/ $\ $; $F $.
  • Methods that operate on $_, implicitly: print ~
  • The special BEGIN{} and END{} blocks
Running Code Before or After Processing the Input

You can run code before the loop starts with BEGIN and after the loop with END. For example, this will count characters:

$ ruby -ne 'BEGIN{ count = 0 }; count += $_.size; END{ print count }' filename
Using Line Numbers

$. contains the current line number. A use-case would be counting the lines of a file:

$ ruby -ne 'END{p$.}' filename
String Matching

Now let's do some conditional processing: Only print a line if it contains a digit:

$ ruby -ne 'print if ~/\d/' filename

The message to take away: The ~ method implicitly matches the regex against $_.

But it gets even better:

$ ruby -ne 'print if /\d/' filename

You thought conditions with a truthy value will always execute the if-branch of a conditions? They will not, if the truthy value is a non-matching regex literal!

This also works when using the ternary operator for conditions:

$ ruby -ne 'puts "#$.: #{ /\d/ ? "first digit: #$&" : "no digit" }"' filename
Inplace-Editing files

Using the -i option, you can modify files directly (just like sed's -i mode). For example, removing all trailing spaces:

$ ruby -ne 'puts $_.rstrip!' -i filename

Like in sed, you can provide a file extension to the -i option which will be used to create a backup file before processing:

$ ruby -pe '$_.upcase!' -i.original filename
Auto-splitting Lines

The -a option will run $F = $_.split for every line:

$ ruby -nae 'puts $F.reverse.join(" ")' filename
Specify Line Format

You might not always want to use \n as the character that separates lines. Fortunately, Ruby has record separators, and you can set some of them via command-line options:

Option Variable Description -0 $/ Sets the input record separator, which is used by Kernel#gets. Character to use must be given as octal number. If no number is given (-0), it will use null bytes as separator. Using -0777 will read in the whole file at once. Another special value is -00, which will set $_ to "\n\n" (paragraph mode). -F $; Sets the input field separator, which is used by String#split. Useful in combination with the -a option. -l $\ Sets the output record separator to the value of the input record separator ($/). Also runs String#chop! on every line! Further Reading
https://idiosyncratic-ruby.com/17-stream-editing.html
Changing the Rules
Show full content

Ruby allows you to change key functionality of the language. This means, it is also possible to break key functionality! Six examples of Ruby code you should never use:

Undefining Core Methods

The simplest way to change Ruby's global behavior is monkey patching: Nothing stops you from altering important core methods:

class Module; undef append_features; end

This line will break the ability to mix-in modules:

Math.sin 42 # => -0.9165215479156338
include Math
# NoMethodError: undefined method `append_features' for Math:Module
Everything nil

No more NoMethodError: undefined method or NameError: uninitialized constant:

class BasicObject
  def self.const_missing(*)
  end

  def method_missing(*)
  end
end

Nothing will fail, anymore. Not a good idea. Also see: Hopeless Egocentricity

IDio.synCRATIC # => nil
Alternative Hash Access Semantics

You can redefine hash semantics, to raise an error, if a key was not found:

class Hash
  alias [] fetch
end

Now you will always get KeyError instead of nil:

{ "Idiosyncratic": "Ruby" }["Sane"]
# `fetch': key not found: "Sane" (KeyError)

You could argue that this is much cleaner than the normal semantics, but you won't be compatible with the rest of the world.

Manipulate Global Randomness

Don't use Kernel#rand, Array#shuffle or Array#sample. Always use SecureRandom!

srand 84 # => (something)
rand 100 # => 42
Change a Global Default Separator

Four of Ruby's special two-letter globals are called record separators and they affect the behaviour of various methods in Ruby:

Variable Name Default Examples for Methods Affected $; (Input) Field Separator nil String#split $, Output Field Separator nil Array#join $/ Input Record Separator "\n" Kernel#gets, IO#readlines $\ Output Record Separator nil Kernel#print, IO#write

Not only your own code is affected, but also core functionality. For example, changing the default output separators also changes Ruby's error messages:

>> $, = "YIKES"
>> 123abc
SyntaxErrorYIKES: YIKES(irb):2: syntax error, unexpected tIDENTIFIER, \
expecting end-of-inputYIKES
  from /home/user/.rvm/rubies/ruby-2.2.2/bin/irb:11:in `<main>'YIKES
Disabling Garbage Collection

Be careful! This might cause your machine to freeze or even worse!

GC.disable
100_000_000.times.each{ |i| "#{i}" }
https://idiosyncratic-ruby.com/16-changing-the-rules.html
210 Ways to Rome
Show full content

All Ruby syntaxes¹ that represent the R string literal:

(1) Double Quoted Literal

"R"

(1) Single Quoted Literal

'R'

(1) Single Char Literals

?R

(9) Heredocs
<<"STRING"
R
STRING
<<'STRING'
R
STRING
<<STRING
R
STRING
<<-"STRING"
R
STRING
<<-'STRING'
R
STRING
<<-STRING
R
STRING
<<~"STRING"
R
STRING
<<~'STRING'
R
STRING
<<~STRING
R
STRING
(66) Percent Syntax / Q

%Q\0R\0 %Q\x01R\x01 %Q\x02R\x02 %Q\x03R\x03 %Q\x04R\x04 %Q\x05R\x05 %Q\x06R\x06 %Q\aR\a %Q\bR\b %Q\tR\t %Q\nR\n %Q\vR\v %Q\fR\f %Q\rR\r %Q\x0ER\x0E %Q\x0FR\x0F %Q\x10R\x10 %Q\x11R\x11 %Q\x12R\x12 %Q\x13R\x13 %Q\x14R\x14 %Q\x15R\x15 %Q\x16R\x16 %Q\x17R\x17 %Q\x18R\x18 %Q\x19R\x19 %Q\x1AR\x1A %Q\eR\e %Q\x1CR\x1C %Q\x1DR\x1D %Q\x1ER\x1E %Q\x1FR\x1F %Q R  %Q!R! %Q"R" %Q#R# %Q$R$ %Q%R% %Q&R& %Q'R' %Q(R) %Q)R) %Q*R* %Q+R+ %Q,R, %Q-R- %Q.R. %Q/R/ %Q:R: %Q;R; %Q<R> %Q=R= %Q>R> %Q?R? %Q@R@ %Q[R] %Q\\R\\ %Q]R] %Q^R^ %Q_R_ %Q`R` %Q{R} %Q|R| %Q}R} %Q~R~ %Q\x7FR\x7F

(66) Percent Syntax / q

%q\0R\0 %q\x01R\x01 %q\x02R\x02 %q\x03R\x03 %q\x04R\x04 %q\x05R\x05 %q\x06R\x06 %q\aR\a %q\bR\b %q\tR\t %q\nR\n %q\vR\v %q\fR\f %q\rR\r %q\x0ER\x0E %q\x0FR\x0F %q\x10R\x10 %q\x11R\x11 %q\x12R\x12 %q\x13R\x13 %q\x14R\x14 %q\x15R\x15 %q\x16R\x16 %q\x17R\x17 %q\x18R\x18 %q\x19R\x19 %q\x1AR\x1A %q\eR\e %q\x1CR\x1C %q\x1DR\x1D %q\x1ER\x1E %q\x1FR\x1F %q R  %q!R! %q"R" %q#R# %q$R$ %q%R% %q&R& %q'R' %q(R) %q)R) %q*R* %q+R+ %q,R, %q-R- %q.R. %q/R/ %q:R: %q;R; %q<R> %q=R= %q>R> %q?R? %q@R@ %q[R] %q\\R\\ %q]R] %q^R^ %q_R_ %q`R` %q{R} %q|R| %q}R} %q~R~ %q\x7FR\x7F

(66) Percent Syntax / None

%\0R\0 %\x01R\x01 %\x02R\x02 %\x03R\x03 %\x04R\x04 %\x05R\x05 %\x06R\x06 %\aR\a %\bR\b %\tR\t %\nR\n %\vR\v %\fR\f %\rR\r %\x0ER\x0E %\x0FR\x0F %\x10R\x10 %\x11R\x11 %\x12R\x12 %\x13R\x13 %\x14R\x14 %\x15R\x15 %\x16R\x16 %\x17R\x17 %\x18R\x18 %\x19R\x19 %\x1AR\x1A %\eR\e %\x1CR\x1C %\x1DR\x1D %\x1ER\x1E %\x1FR\x1F % R  %!R! %"R" %#R# %$R$ %%R% %&R& %'R' %(R) %)R) %*R* %+R+ %,R, %-R- %.R. %/R/ %:R: %;R; %<R> %=R= %>R> %?R? %@R@ %[R] %\\R\\ %]R] %^R^ %_R_ %`R` %{R} %|R| %}R} %~R~ %\x7FR\x7F


¹ You might need a hex editor, or eval, to be able to use non-printable string delimiters.

Resources
https://idiosyncratic-ruby.com/15-207-ways-to-rome.html
Meeting some Locals
Show full content

There are two very different ways to create local variables in Ruby. You are probably familiar with the classical way:

a, b = "$", "€"
a # => "$"
b # => "€"

It is simple to understand and looks good. But Ruby would not be Ruby, if there weren't for more obscure ways to assign variables: You could rewrite the previous example to create local variables in a more subtle way:

%r<(?'a'.)(?'b'.)>=~"$" "€"
a # => "$"
b # => "€"
Implicit Local Variables Through Regex Matching

Without the fancy obfuscations, the example above would look like this:

/(?<a>.)(?<b>.)/ =~ "$€"
a # => "$"
b # => "€"

The regex matching operator =~ will create new local variables, when used together with named captures. However, this is not recommended, because obviously, it violates PrOWCoFoHuNoMa (Principle of writing code for humans, not machines).

By the way, this will not work, if you swap operands:

"$€" =~ /(?<a>.)(?<b>.)/
a # NameError: ...
One More Option (Almost!)

In actuality, there is also a third way to set local variables: binding's local_variable_set, but it does not really count, since you cannot introduce new variables this way:

a = nil
binding.local_variable_set :a, "$"
binding.local_variable_set :b, "€"
a # => "$"
b # NameError: ...
Ruby 3.0 Update: Right Hand Assignment

Whoa!

%w[$ €] => [a, b]
a # => "$"
b # => "€"

Read more in Episode 68: Assignments In-Style

Resources
https://idiosyncratic-ruby.com/14-meeting-some-locals.html
Slicing Rubies
Show full content

Ruby puts a lot of effort into its Enumerable module, offering a lot of different ways of iterating through collections. It is one of the reasons for Ruby's success, but you can also call it idiosyncratic, sometimes. This episode portraits enumerables' three handy slice_* methods.

Slicing Enumerables

Slicing lets you divide a collection into sub-collections. Take this array:

a = %w[Ruby in the back-end, React in the front-end]

Let's say you want to divide it into smaller arrays. The simplest option would be passing a regex to slice_before describing where to slice:

a.slice_before(/,/).to_a
# => [["Ruby", "in", "the"], ["back-end,", "React", "in", "the", "front-end"]]

A variation of this is method is slice_after, which puts the separating element into the earlier sub-collection, which makes more sense in this case:

a.slice_after(/,/).to_a
# => [["Ruby", "in", "the", "back-end,"], ["React", "in", "the", "front-end"]]

Slicing uses === to compare each element with the given separator, so you can pass in a class as well:

["A", "B", 1, "C", "D", 2].slice_after(Integer).to_a
# => [["A", "B", 1], ["C", "D", 2]]

For more complex, and more real-world problems, you will need to pass in a block, like for separating ascending numerical sequences:

previous = Float::NAN
[0, 2, 3, 4, 6, 7, 9].slice_before{ |current|
  previous, slice = current, current != previous + 1
  slice # is false if previous + 1 is not current -> start new slice
}.to_a
# => [0], [2, 3, 4], [6, 7], [9]

Keeping around additional variables is a little annoying, but fortunately, we can rewrite the previous example using the newer slice_when method:

[0, 2, 3, 4, 6, 7, 9].slice_when{ |previous, current|
  current != previous + 1
}.to_a
# => [0], [2, 3, 4], [6, 7], [9]
Resources
https://idiosyncratic-ruby.com/13-slicing-rubies.html
More Inspections
Show full content

Some of IRB's command-line options can be called idiosyncratic as well. Take math mode¹ as an example: It will require the infamous mathn library on start up:

$ irb -m
>> Math #=> CMath
>> 3/2 #=> (3/2)
>> !!defined?(Vector) #=> true

¹ Math mode actually has been removed in Ruby version 2.5

And another one surprised me: You can pass custom inspectors to IRB, for example, yaml:

$ irb -f --inspect yaml
>> [1,2,3]
=> ---
- 1
- 2
- 3

Or marshal:

$ irb -f --inspect marshal
>> 42
=> i/

But you can also define your own inspectors on the fly:

$ irb -f --inspect "{ |r| r.to_s.reverse }"
>> [1,2,3]
=> ]3 ,2 ,1[

It will be eval'd (!) as the block part of a new proc.

Resources
https://idiosyncratic-ruby.com/12-more-inspections.html
Regular Extremism
Show full content

You are here for a collection of 10 advanced features of regular expressions in Ruby!

Regex Conditionals

Regular expressions can have embedded conditionals (if-then-else) with (?ref)then|else. "ref" stands for a group reference (number or name of a capture group):

# will match everything if string contains "ä", or only match first two chars
regex = /(.*ä)?(?(1).*|..)/

"Ruby"[regex] #=> "Ru"
"Idiosyncrätic"[regex] #=> "Idiosyncrätic"
Keep Expressions

The possible ways to look around within a regex are:

Syntax Description Example (?=X) Positive lookahead "Ruby"[/.(?=b)/] #=> "u" (?!X) Negative lookahead "Ruby"[/.(?!u)/] #=> "u" (?<=X) Positive lookbehind "Ruby"[/(?<=u)./] #=> "b" (?<!X) Negative lookbehind "Ruby"[/(?<!R|^)./] #=> "b"

But Ruby also has "Keep Expressions", an additional shortcut syntax to do positive lookbehinds using \K:

"Ruby"[/Ru\Kby/] #=> "by"
"Ruby"[/ru\Kby/] #=> nil
Character Class Intersections

You can nest character classes and AND-connect them with &&. Matching all non-vowels here:

"Idiosyncratic".scan /[[a-z]&&[^aeiou]]+/
# => ["d", "syncr", "t", "c"]
Regex Sub-Expressions

You can recursively apply regex groups again with \g<ref>. "ref" stands for a group reference (number or name of a capture group). This is different from back-references (\1 .. \9), which will re-match the already matched string, instead of executing the regex again:

# match any number of sequences of 3 identical chars
regex = /((.)\2{2})\g<1>*/
"aaa"[regex] #=> "aaa"
"abc"[regex] #=> nil
"aaab"[regex] #=> "aaa"
"aaabbb"[regex] #=> "aaabbb"
"aaabbbc"[regex] #=> "aaabbb"
"aaabbbccc"[regex] #=> "aaabbbccc"
Match Characters that Belong Together

\X treats combined characters as a single character. See grapheme clusters for more information.

string = "R\u{030A}uby"
string[/./] #=> "R"
string[/.../] #=> "R̊u"
string[/\X\X/] #=> "R̊u"
Relative Back-References

Back-refs can be relatively referenced from the current position via \k<-n>:

"Ruby by"[/(R)(u)(by) \k<-1>/] #=> "Ruby by"
Deactivate Backtracking

Atomic groups, defined via (?>X), will always try to match the first of all alternatives:

"Rüby"[/R(u*|ü)by/]   #=> "Rüby"
"Rüby"[/R(?>u*|ü)by/] #=> nil
Turn On Unicode-Matching for \w, \d, \s, and \b
"Rüby"[/\w*/] #=> "R"
"Rüby"[/(?u)\w*/] #=> "Rüby"
Continue Matching at Last Match Position

When using a method that matches a regex multiple times against a string (like String#gsub or String#scan), you can reference the position of the last match via \G:

"abc1abc22abc333".scan /\Gabc./ # => ["abc1", "abc2"]
String#split with Capture Groups

The normal way of using String#split is this:

"0-0".split(/-/) #=> ["0", "0"]

But if you want to make your code as hard to read as possible, remember that captured groups will be added to the resulting array:

"0-0".split(/(-)/) #=> ["0", "-", "0"]
"0-0".split(/-(?=(.))/) #=> ["0", "0", "0"]
"0-0".split(/(((-)))/) #=> ["0", "-", "-", "-", "0"]
Resources
https://idiosyncratic-ruby.com/11-regular-extremism.html
Know your Environment
Show full content

Ruby's ENV object gives you access to environment variables. It looks like normal Ruby hash:

ENV["TERM"] #=> "xterm"
ENV["SOMETHING"] = "NEW" #=> "NEW"

But this is only the surface. Turns out ENV is a special object:

ENV.class #=> Object

It is hash-like, but lacks some functionality:

ENV.flatten # NoMethodError
ENV.default = "MyNullObject" # NoMethodError

Besides this, it behaves like an ordinary hash:

ENV["my_value"] = "something"
ENV[42] = "oops" # not quite: TypeError

Another thing that is missing: Merging the ENV hash with another hash:

ENV.merge(Idiosyncratic: "YES") # NoMethodError
Resources
https://idiosyncratic-ruby.com/10-know-your-environment.html
Globalization
Show full content

This is an overview of all the special, two-letter (and other) global variables in Ruby, which Ruby inherited from Perl.

For the purpose of improving code readability, Ruby comes with English.rb in its standard library (or Deutsch.rb as gem), which provides non-cryptic aliases and some documentation.

Ruby also defines some three-letter global variables that mirror CLI options ($-…)

Types of Special Global Variables

Idiosyncratically, not all special global variables are global:

Type Scope global Real global variable thread Thread-global variable: Can have different values in different threads pseudo Looks like a global variable, but is a local variable defunct Not working, anymore (removed from Ruby) read-only Variable cannot be set to a new value (read-only) Variable cannot be set to a new value, but is an array that is mutable List of All Special Global Variables

The first table contains all two-letter variables and their aliases:

Perlish Type English Short Info $! thread $ERROR_INFO - RDoc $@ thread $ERROR_POSITION - RDoc $; global $FIELD_SEPARATOR $FS, $-F¹ RDoc $, global $OUTPUT_FIELD_SEPARATOR $OFS RDoc $/ global $INPUT_RECORD_SEPARATOR $RS, $-0¹ RDoc $\ global $OUTPUT_RECORD_SEPARATOR $ORS RDoc $. global $INPUT_LINE_NUMBER $NR RDoc $_ pseudo $LAST_READ_LINE - RDoc $> global $DEFAULT_OUTPUT $stdout¹ IO in Ruby $< global $DEFAULT_INPUT - (ARGF) RDoc $$ read-only $PROCESS_ID $PID Unix Processes $? thread / read-only $CHILD_STATUS - RDoc $~ pseudo $LAST_MATCH_INFO - RDoc $= defunct $IGNORECASE - - $* (read-only) $ARGV - Explanation $& pseudo / read-only $MATCH - RDoc $` pseudo / read-only $PREMATCH - RDoc $' pseudo / read-only $POSTMATCH - RDoc $+ pseudo / read-only $LAST_PAREN_MATCH² - RDoc $: (read-only) $LOAD_PATH¹ $-I¹ RHG: Loading $" (read-only) $LOADED_FEATURES¹ - RHG: Loading $0 global $PROGRAM_NAME¹ - RDoc $1 - $9³ pseudo - - RDoc $F⁴ global - - Auto-Splitting Lines

¹ Available without requiring English.rb
² No T, because it stands for PARENTHESES, not PARENT
³ Starting with Ruby 2.4, $1 - $9 only get defined when they are currently set
⁴ With command-line option -a

Other Special Global Variables Name Type Info $stdin global IO in Ruby $stderr global IO in Ruby $FILENAME read-only The current file being read via ARGF. Same as ARGF.filename. $DEBUG, $-d global Global Debug States $VERBOSE, $-v, $-w global Global Debug States $-W global Global Debug States $-p read-only Stream Editing $-l read-only Specify Line Format $-a read-only Auto-Splitting Lines $-i global Inplace-Editing Files
https://idiosyncratic-ruby.com/9-globalization.html
Self Improvement
Show full content

One of the never-ending style battles in Ruby land is module_function vs extend self.

Both enable you to define module methods, which can be called not only from instance level, but also from class level. This enables you to make modules that can optionally be include'd into your current scope, which makes sense if the module contains non-state changing methods ("functions"). Not having to prepend the module name every time you use the functions saves time and looks good:

# class level
Mathematics.calc # => 42

# instance level
include Mathematics
calc # => 42
module_function

You can achieve this kind of functionality using:

module Mathematics
  module_function

  def calc
    42
  end
end

Which is very similar to writing this:

module Mathematics
  def self.calc
    42
  end

  private

  def calc
    42
  end
end
Reflection Observations
Mathematics.instance_method(:calc).owner #=> Mathematics
Mathematics.public_method_defined?(:calc) #=> false
Mathematics.private_method_defined?(:calc) #=> true

Mathematics.method(:calc).owner #=> #<Class:Mathematics>
Mathematics.method(:calc).owner.singleton_class? #=> true

Two things to take away from this:

  • The method will be copied to the class' singleton class
  • The instance method's visibility will become private
extend self

There is another way to get something very similar:

module Mathematics
  extend self

  def calc
    42
  end
end

Using extend, the module will add its instance methods to the module's very own inheritance chain.

Reflection Observations
Mathematics.instance_method(:calc).owner #=> Mathematics
Mathematics.public_method_defined?(:calc) #=> true
Mathematics.private_method_defined?(:calc) #=> false

Mathematics.method(:calc).owner #=> Mathematics
Mathematics.method(:calc).owner.singleton_class? #=> false

The differences to module_function are:

  • No method copying involved
  • No changes to method visibility
Which One to Use? Advantages of extend self
  • No method copying: If you want to modify a method's behavior via meta-programming, you only need to do this in one place
  • No side effects, like changing the method's visibility
  • It is not an extra language feature
Advantages of module_function
  • The method name "module_function" describes what it does, so it might be more readable
  • Making included methods private might be desired
https://idiosyncratic-ruby.com/8-self-improvement.html
Easier Switching
Show full content

There is a command-line switch to enable command-line switches:

-s
Enables some switch parsing for switches after script name but before
any file name arguments (or before a --).  Any switches found there
are removed from ARGV and set the corresponding variable in the script.

In this context "corresponding variable" means global variable. Let's see this in action (the -e option is for executing the Ruby code that follows in a string):

$ ruby -se 'p $option'
# nil

$ ruby -se 'p $option' -- -option
# true
Switching Files

You can add command-line options to the Ruby shebang line, which makes using the switch feature from the command-line more readable. Create a Ruby file (switch.rb) and add:

#!ruby -s
p $option

No you can call it like this:

$ ruby switch.rb -option
# true
Caveats!

You should be careful, not to trigger the wrong switches:

$ ruby switch.rb -LOAD_PATH
switch.rb: $LOAD_PATH is a read-only variable (NameError)

$ ruby switch.rb -0
switch.rb: no implicit conversion of true into String (TypeError)

$ ruby switch.rb -stdout
switch.rb: $stdout must have write method, TrueClass given (TypeError)

$ ruby switch.rb -SAFE
switch.rb: no implicit conversion of true into Integer (TypeError)
Resources
  • man ruby
https://idiosyncratic-ruby.com/7-easier-switching.html
Run Ruby, Run!
Show full content

There is a one-liner on the internet that will start a local web server, for serving all the static files in your current directory:

$ python -m SimpleHTTPServer 8080

Or with Python 3:

$ python3 -m http.server

Rubyists generally do not want to rely on Python, so there is a Ruby equivalent:

$ ruby -run -e httpd . -p 8080

This will fire up a very simple server, written in Ruby, using WEBrick under the hood!

It also takes some more options, see at bottom of this post for a listing of available ones.

Please note: WEBrick was removed from Ruby in version 3.0

How does this work and what does it do exactly? First of all, what does ruby -run mean? The answer might be surprising: It could be rewritten as:

$ ruby -require "un" -e "httpd" . -p 8080

The -e option directly executes the ruby code given, and -r is the short version of --require. So it requires "un", which happens to be included in Ruby's standard library¹. It was written by Hirofumi WATANABE (eban), a long-time Ruby contributor and code golf star. un.rbs goal is to provide:

# Utilities to replace common UNIX commands in Makefiles etc

¹ The same is possible for requiring rubygems

Let's see, what else is included:

#   ruby -run -e cp             -- [OPTION] SOURCE DEST
#   ruby -run -e ln             -- [OPTION] TARGET LINK_NAME
#   ruby -run -e mv             -- [OPTION] SOURCE DEST
#   ruby -run -e rm             -- [OPTION] FILE
#   ruby -run -e mkdir          -- [OPTION] DIRS
#   ruby -run -e rmdir          -- [OPTION] DIRS
#   ruby -run -e install        -- [OPTION] SOURCE DEST
#   ruby -run -e chmod          -- [OPTION] OCTAL-MODE FILE
#   ruby -run -e touch          -- [OPTION] FILE
#   ruby -run -e wait_writable  -- [OPTION] FILE
#   ruby -run -e mkmf           -- [OPTION] EXTNAME [OPTION]
#   ruby -run -e httpd          -- [OPTION] DocumentRoot
#   ruby -run -e help [COMMAND]

Besides httpd, you mostly get FileUtils based implementations of common unix tools,: cp, ln, mv, rm, mkdir, rmdir, install, chmod, and touch.

There are two more commands included, which don't fit into this unix category: mkmf, which you can use to create the Makefile for a Ruby C extension and wait_writable, which allows you to continuously try to open a file in writable mode.

-run Reference

What follows is a reference of all un commands. Also checkout the integrated help with:

$ ruby -run -e help COMMAND
Copy Files
$ ruby -run -e cp SOURCE DEST [OPTIONS]
Argument Description SOURCE File to copy DEST Where to copy the file Option Description -p Preserve file attributes if possible -r Copy directories recursively -v Verbose mode (print executed shell command) Create Symlink
$ ruby -run -e ln TARGET LINK_NAME [OPTIONS]
Argument Description TARGET File to create symlink from LINK_NAME Where to create the symlink Option Description -s Make symbolic links instead of hard links -f Overwrite files, which already exists at destination -v Verbose mode (print executed shell command) Move File
$ ruby -run -e mv SOURCE DEST [OPTIONS]
Argument Description SOURCE File to move DEST Where to move the file Option Description -v Verbose mode (print executed shell command) Remove File
$ ruby -run -e rm FILE [OPTIONS]
Argument Description FILE File(s) to remove Option Description -f Do nothing if file does not exist -r Remove the contents of directories recursively -v Verbose mode (print executed shell command) Create Directory
$ ruby -run -e mkdir DIRS [OPTIONS]
Argument Description DIRS Director(y/ies) to create Option Description -p Don't fail if directory already exists
Create all directories necessary -v Verbose mode (print executed shell command) Remove Directory
$ ruby -run -e rmdir DIRS [OPTIONS]
Argument Description DIRS Director(y/ies) to remove Option Description -p Also remove directory's ancestors -v Verbose mode (print executed shell command) Copy Files and Set Attributes
$ ruby -run -e install SOURCE DEST [OPTIONS]
Argument Description SOURCE File to copy DEST Where to copy the file Option Description -p Apply access/modification times of SOURCE files to   corresponding destination files -m Set permission mode (as in chmod), instead of 0755 -v Verbose mode (print executed shell command) Change File Mode
$ ruby -run -e chmod OCTAL-MODE FILE [OPTIONS]
Argument Description OCTAL-MODE File mode to set as octal number FILE File(s) to operate on Option Description -v Verbose mode (print executed shell command) Update File Timestamp or Create Empty File
$ ruby -run -e touch FILE [OPTIONS]
Argument Description FILE File(s) to touch Option Description -v Verbose mode (print executed shell command) Wait until File gets Writable
$ ruby -run -e wait_writable FILE [OPTIONS]
Argument Description FILE File(s) to wait for Option Description -n RETRY Count how often to retry -w SEC Time to wait between retries (in seconds) -v Verbose mode (print access errors) Make Makefile
$ ruby -run -e mkmf EXTNAME [OPTIONS]
Argument Description EXTNAME Extension name Option Description -d ARGS Run dir_config -h ARGS Run have_header -l ARGS Run have_library -f ARGS Run have_func -v ARGS Run have_var -t ARGS Run have_type -m ARGS Run have_macro -c ARGS Run have_const –vendor Install to vendor_ruby Serve Static Files via HTTP
$ ruby -run -e httpd DOCUMENT_ROOT [OPTIONS]
Argument Description DOCUMENT_ROOT Directory to serve Option Short Description Example –bind-address=ADDR -b IP address to bind to -b 127.0.0.1 –port=NUM -p Port number to listen on -p 8080 –max-clients=MAX -m Max number of simultaneous clients -m 2 –temp-dir=DIR -t Temporary directory to use -t /tmp –do-not-reverse-lookup -d Disable reverse lookup -d –request-timeout=SECOND -r Request timeout (in seconds) -r 2 –http-version=VERSION   HTTP version --http-version=1.0   -v Start WEBrick in verbose mode -v Further Reading
https://idiosyncratic-ruby.com/6-run-ruby-run.html
Constant Shadows
Show full content

The script lines feature is probably the most famous example for idiosyncratic naming in Ruby!

Ruby can save all source files you load or require as strings. This is useful for debugging utilities, for example, standard library's debug and tracer both use these capabilities.

This is possible with the script lines object: It is a Ruby hash that stores all script filenames as keys and the whole file contents as values. It is not activated by default, you have to globally opt-in for it, which is done by initializing it with an empty hash!

Quiz: How to Access this Magical Script Lines Hash?

A) script_lines
B) SCRIPT_LINES
C) __SCRIPT_LINES
D) __script_lines__
E) SCRIPT_LINES__
F) Ruby::DebugInfo::SCRIPT_LINES
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
The answer is E: SCRIPT_LINES__

WEIRD. What gives with the trailing underscores? It’s such a big constant that it leaves a two-character shadow!!

— why
Usage Example

It is a best practice to check if it already is defined, because someone else might have already activated it:

SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
require 'abbrev'
SCRIPT_LINES__.size
# => 1
SCRIPT_LINES__.keys.first
# => "/home/user/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/abbrev.rb"
SCRIPT_LINES__.values.first.is_a? Array
# => true
SCRIPT_LINES__.values.first.size
# => 131

Running puts SCRIPT_LINES__.values.first will output every line of the file:

#--
# Copyright (c) 2001,2003 Akinori MUSHA <knu@iDaemons.org>
#
# All rights reserved.  You can redistribute and/or modify it under
# the same terms as Ruby.
#
# $Idaemons: /home/cvs/rb/abbrev.rb,v 1.2 2001/05/30 09:37:45 knu Exp $
# $RoughId: abbrev.rb,v 1.4 2003/10/14 19:45:42 knu Exp $
# $Id: abbrev.rb 46784 2014-07-11 08:16:05Z hsbt $
#++

##
# Calculates the set of unambiguous abbreviations for a given set of strings.
#
#   require 'abbrev'
#   require 'pp'
#
#   pp Abbrev.abbrev(['ruby'])
#   #=>  {"ruby"=>"ruby", "rub"=>"ruby", "ru"=>"ruby", "r"=>"ruby"}
#
#   pp Abbrev.abbrev(%w{ ruby rules })
#
# _Generates:_
#   { "ruby"  =>  "ruby",
#     "rub"   =>  "ruby",
#     "rules" =>  "rules",
#     "rule"  =>  "rules",
#     "rul"   =>  "rules" }
#
# It also provides an array core extension, Array#abbrev.
#
#   pp %w{ summer winter }.abbrev
#
# _Generates:_
#   { "summer"  => "summer",
#     "summe"   => "summer",
#     "summ"    => "summer",
#     "sum"     => "summer",
#     "su"      => "summer",
#     "s"       => "summer",
#     "winter"  => "winter",
#     "winte"   => "winter",
#     "wint"    => "winter",
#     "win"     => "winter",
#     "wi"      => "winter",
#     "w"       => "winter" }

module Abbrev

  # Given a set of strings, calculate the set of unambiguous abbreviations for
  # those strings, and return a hash where the keys are all the possible
  # abbreviations and the values are the full strings.
  #
  # Thus, given +words+ is "car" and "cone", the keys pointing to "car" would
  # be "ca" and "car", while those pointing to "cone" would be "co", "con", and
  # "cone".
  #
  #   require 'abbrev'
  #
  #   Abbrev.abbrev(%w{ car cone })
  #   #=> {"ca"=>"car", "con"=>"cone", "co"=>"cone", "car"=>"car", "cone"=>"cone"}
  #
  # The optional +pattern+ parameter is a pattern or a string. Only input
  # strings that match the pattern or start with the string are included in the
  # output hash.
  #
  #   Abbrev.abbrev(%w{car box cone crab}, /b/)
  #   #=> {"box"=>"box", "bo"=>"box", "b"=>"box", "crab" => "crab"}
  #
  #   Abbrev.abbrev(%w{car box cone}, 'ca')
  #   #=> {"car"=>"car", "ca"=>"car"}
  def abbrev(words, pattern = nil)
    table = {}
    seen = Hash.new(0)

    if pattern.is_a?(String)
      pattern = /\A#{Regexp.quote(pattern)}/  # regard as a prefix
    end

    words.each do |word|
      next if word.empty?
      word.size.downto(1) { |len|
        abbrev = word[0...len]

        next if pattern && pattern !~ abbrev

        case seen[abbrev] += 1
        when 1
          table[abbrev] = word
        when 2
          table.delete(abbrev)
        else
          break
        end
      }
    end

    words.each do |word|
      next if pattern && pattern !~ word

      table[word] = word
    end

    table
  end

  module_function :abbrev
end

class Array
  # Calculates the set of unambiguous abbreviations for the strings in +self+.
  #
  #   require 'abbrev'
  #   %w{ car cone }.abbrev
  #   #=> {"car"=>"car", "ca"=>"car", "cone"=>"cone", "con"=>"cone", "co"=>"cone"}
  #
  # The optional +pattern+ parameter is a pattern or a string. Only input
  # strings that match the pattern or start with the string are included in the
  # output hash.
  #
  #   %w{ fast boat day }.abbrev(/^.a/)
  #   #=> {"fast"=>"fast", "fas"=>"fast", "fa"=>"fast", "day"=>"day", "da"=>"day"}
  #
  #   Abbrev.abbrev(%w{car box cone}, "ca")
  #   #=> {"car"=>"car", "ca"=>"car"}
  #
  # See also Abbrev.abbrev
  def abbrev(pattern = nil)
    Abbrev::abbrev(self, pattern)
  end
end
Memory Impact

Only use this for debugging purpose, since a lot of strings get loaded into your memory. This is a comparison loading ActiveSupport with and without script lines:

require 'active_support/all'
puts "#{`ps -o rss -p #{Process.pid}`.strip.split.last.to_i / 1024.0} MB"

Result: 16.421875 MB

SCRIPT_LINES__ = {}
require 'active_support/all'
puts "#{`ps -o rss -p #{Process.pid}`.strip.split.last.to_i / 1024.0} MB"

Result: 19.85546875 MB

Resources
https://idiosyncratic-ruby.com/5-constant-shadows.html
What the Pack?
Show full content

a A b B c C d D e E F g G h H l L m m0 M n N p P q Q s S u U v V w x X Z @ ! * < > _

Ruby comes equipped with a powerful option for low level string manipulation: String#unpack and its counter part Array#pack. Today's episode takes a closer look.

The general way how String#unpack is used is this:

"a string".unpack("pack template with directives")
# => [...]

The string contains some data in a specific format, which you "unpack" using a format specification. The format specification is defined in the pack template. The result is an array that contains the same data (or parts of it), but in a different representation. Take a look at this very simple example, which converts a four-letter ASCII string into its integer based byte representation:

"Ruby".unpack("C C C C")
# => [82, 117, 98, 121]

Array#pack works the other way around, so if you have the integer byte representation, it will convert it to real bytes in a string:

[82, 117, 98, 121].pack("C C C C")
# => "Ruby"
Pack Template Format

The format of the pack template ("C C C C" in the example above) might be unfamiliar, but it is not too complicated. It is a series of letters that describe how to interpret the next bytes in the string you are operating on. A letter is called "directive". Each directive has a different meaning, see below for a complete list of available directives. C essentially means: One integer byte value.

A directive can be followed by a number, how often it should be applied. So you could rewrite the above code to:

"Ruby".unpack("C4")
# => [82, 117, 98, 121]

You don't need to read the complete string:

"Ruby".unpack("C2")
# => [82, 117]

Instead of using a number, it is possible to use *, which denotes that the directive should be applied as often as possible:

"Ruby".unpack("C*")
# => [82, 117, 98, 121]

Every character that is not a directive, a digit or * will be ignored. This is useful to make a pack template more readable, by separating directives with spaces.

What follows is a list of all directives and how to use them.

Integer Directives

These will all unpack the bytes of a string to an array of integers. One of these integers represents one or more bytes. You have different modes that differ in the number of bytes each integer represents:

Directive Size C char I! or I_ int S! or S_ short L! or L_ long Q! or Q_ long long J! or J_ pointer width

Except for char (which is always one byte), it depends on your operating system, how many bytes each of this modes actually reads. So if your operating system defines short as 2 bytes, you will get an array that represents every group of two bytes as an integer value:

"\x01\x00\x02\x00".unpack("S!*") #=> [1, 2]

Or the other way around:

[1, 2].pack("S!*") # => "\x01\x00\x02\x00"

If you do not want to depend on what byte sizes you operating system defines, you can omit the ! and it will use a fixed byte size (the exceptions being int and pointer width, which will always use their native size).

C | An Unsigned Integer per Byte

Range: 0 to 255

"Idiosyncrätic".unpack("C*")
# => [73, 100, 105, 111, 115, 121, 110, 99, 114, 195, 164, 116, 105, 99]

[73, 100, 105, 111, 115, 121, 110, 99, 114, 195, 164, 116, 105, 99].pack("C*")
# => "Idiosyncr\xC3\xA4tic"

Note that Array#pack will not set the string's encoding for you, because it has no way to know.

c | A Signed Integer per Byte

Range: -128 to 127

"Idiosyncrätic".unpack("c*")
# => [73, 100, 105, 111, 115, 121, 110, 99, 114, -61, -92, 116, 105, 99]

[73, 100, 105, 111, 115, 121, 110, 99, 114, -61, -92, 116, 105, 99].pack('c*')
# => "Idiosyncr\xC3\xA4tic"
S | An Unsigned Integer per 2 Bytes

Range: 0 to 65535

"Idiosyncrätic".unpack("S*")
# => [25673, 28521, 31091, 25454, 50034, 29860, 25449]

[25673, 28521, 31091, 25454, 50034, 29860, 25449].pack("S*")
# => "Idiosyncr\xC3\xA4tic"
s | A Signed Integer per 2 Bytes

Range: -32768 to 32767

"Idiosyncrätic".unpack("s*")
# => [25673, 28521, 31091, 25454, -15502, 29860, 25449]

[25673, 28521, 31091, 25454, -15502, 29860, 25449].pack("s*")
# => "Idiosyncr\xC3\xA4tic"
L | An Unsigned Integer per 4 Bytes

Range: 0 to 4294967296

"Idiosyncrätic".unpack("L*")
# => [1869177929, 1668184435, 1956954994]

[1869177929, 1668184435, 1956954994].pack("L*")
# => "Idiosyncr\xC3\xA4t"

Note: The byte size in this example is 14, which is not dividable by 4, so it will ignore the last 2 bytes. If you need them, you could use a different template like: "L* C*"

l | A Signed Integer per 4 Bytes

Range: -2147483648 to 2147483647

"Idiosyncrätic".unpack("l*")
# => [1869177929, 1668184435, 1956954994]

[1869177929, 1668184435, 1956954994].pack("l*")
# => "Idiosyncr\xC3\xA4t"
Q | An Unsigned Integer per 8 Bytes

Range: 0 to 18446744073709551616

"Idiosyncrätic".unpack("Q*")
# => [7164797593890415689]

[7164797593890415689].pack("Q*")
# => "Idiosync"
q | A Signed Integer per 8 Bytes

Range: -9223372036854775808 to 9223372036854775807

"Idiosyncrätic".unpack("q*")
# => [7164797593890415689]

[7164797593890415689].pack("q*")
# => "Idiosync"
A Note on Byte Order (Big-Endian vs. Little-Endian)

All the previous examples used the native byte order, which means, that the operating system defines, if the more significant bytes come first (little-endian) or last (big-endian). You will find more information about "endianness" on wikipedia.

If you don't want to rely on your operating system to define byte order, you can add > for big-endianness or < for little-endianness to your template's directives:

"\x01\x00\x02\x00".unpack("S<*") #=> [1, 2]
"\x01\x00\x02\x00".unpack("S>*") #=> [256, 512]
Integer Shortcut Directives n | An Unsigned Integer per 2 Bytes, Big-Endian (Similar to S>)

Range: 0 to 65535

"Idiosyncrätic".unpack("n*")
# => [18788, 26991, 29561, 28259, 29379, 42100, 26979]

[18788, 26991, 29561, 28259, 29379, 42100, 26979].pack("n*")
# => "Idiosyncr\xC3\xA4tic"
N | An Unsigned Integer per 4 Bytes, Big-Endian (Similar to L>)

Range: 0 to 4294967296

"Idiosyncrätic".unpack("N*")
# => [1231317359, 1937337955, 1925424244]

[1231317359, 1937337955, 1925424244].pack("N*")
# => "Idiosyncr\xC3\xA4t"
v | An Unsigned Integer per 2 Bytes, Little-Endian (Similar to S<)

Range: 0 to 65535

"Idiosyncrätic".unpack("v*")
# => [25673, 28521, 31091, 25454, 50034, 29860, 25449]

[25673, 28521, 31091, 25454, 50034, 29860, 25449].pack("v*")
# => "Idiosyncr\xC3\xA4tic"
V | An Unsigned Integer per 4 Bytes, Little-Endian (Similar to L<)

Range: 0 to 4294967296

"Idiosyncrätic".unpack("V*")
# => [1869177929, 1668184435, 1956954994]

[1869177929, 1668184435, 1956954994].pack("V*")
# => "Idiosyncr\xC3\xA4t"
Integer Encoding Directives U | UTF-8 Characters

This will convert the string to unicode code points.. Note that while it throws ArgumentError for invalid encodings, it will happily decode surrogates and too large codepoint values.

"ɔıʇɐɹɔuʎsoıpı".unpack("U*")
# => [596, 305, 647, 592, 633, 596, 117, 654, 115, 111, 305, 112, 305]

[596, 305, 647, 592, 633, 596, 117, 654, 115, 111, 305, 112, 305].pack("U*")
# => "ɔıʇɐɹɔuʎsoıpı"
w | BER Compression

See wikipedia on X.690 for an explanation.

"Idiosyncrätic".unpack("w*")
# => [73, 100, 105, 111, 115, 121, 110, 99, 114, 1102452, 105, 99]

[73, 100, 105, 111, 115, 121, 110, 99, 114, 1102452, 105, 99].pack("w*")
# => "Idiosyncr\xC3\xA4tic"
Float Directives

The following directives will interpret bytes as Floats.

D, d | A Float (Double Precision, Native-Endian)
[1.2, 3.4].pack("D*")
# => "333333\xF3?333333\v@"

"333333\xF3?333333\v@".unpack("D*")
#=> [1.2, 3.4]
F | A Float (Single Precision, Native-Endian)
[1.2, 3.4].pack("F*")
# => "\x9A\x99\x99?\x9A\x99Y@"

"\x9A\x99\x99?\x9A\x99Y@".unpack("F*")
# => [1.2000000476837158, 3.4000000953674316]
E | A Float (Double Precision, Little-Endian)
[1.2, 3.4].pack("E*")
# => "333333\xF3?333333\v@"

"333333\xF3?333333\v@".unpack("E*")
#=> [1.2, 3.4]
e | A Float (Single Precision, Little-Endian)
[1.2, 3.4].pack("e*")
# => "\x9A\x99\x99?\x9A\x99Y@"

"\x9A\x99\x99?\x9A\x99Y@".unpack("e*")
# => [1.2000000476837158, 3.4000000953674316]
G | A Float (Double Precision, Big-Endian)
[1.2, 3.4].pack("G*")
# => "?\xF3333333@\v333333"

"?\xF3333333@\v333333".unpack("G*")
#=> [1.2, 3.4]
g | A Float (Single Precision, Big-Endian)
[1.2, 3.4].pack("g*")
# => "?\x99\x99\x9A@Y\x99\x9A"

"\x9A\x99\x99?\x9A\x99Y@".unpack("g*")
# => [1.2000000476837158, 3.4000000953674316]
String Directives

String directives are more confusing in the regard that input and output of a pack or unpack operation are both strings, one of them being wrapped as a single argument in an array. The rule to remember here is that the string representation is something encoded (which might be saved or sent over the wire), while the string-in-an-array format represents the data in a readable format.

a | Arbitrary String
"Idiosyncrätic".unpack("a20")
# => ["Idiosyncr\xC3\xA4tic"]

Fills with null bytes when packing:

["Idiosyncrätic"].pack("a20")
# => "Idiosyncr\xC3\xA4tic\x00\x00\x00\x00\x00\x00"
A | Arbitrary String (Clean Null Bytes)

Like a, but removes trailing spaces and null bytes when unpacking:

"Idiosyncrätic    \0 ".unpack("A20")
# => ["Idiosyncr\xC3\xA4tic"]

Like a, but replaces null bytes with spaces when packing:

["Idiosyncrätic"].pack("A20")
# => "Idiosyncr\xC3\xA4tic      "
Z | Null-Terminated String

Like a, but unpacking will not read further than null bytes:

"Idiosyncrätic\0R".unpack("Z20")
# => ["Idiosyncr\xC3\xA4tic"]

Like a, but packing will add a null byte to the end, if used with *:

["Idiosyncrätic"].pack("Z*")
# => "Idiosyncr\xC3\xA4tic\x00"
String Base Conversion Directives B | Bit String (Big-Endian)
"abc".unpack("B*")
# => ["011000010110001001100011"]

["011000010110001001100011"].pack("B*")
# => "abc"
b | Bit String (Little-Endian)
"abc".unpack("b*")
# => ["100001100100011011000110"]

["100001100100011011000110"].pack("b*")
# => "abc"
H | Hex String (Big-Endian)
"xyz".unpack("H*")
# => ["78797a"]

["78797a"].pack("H*")
# => "xyz"
h | Hex String (Little-Endian)
"xyz".unpack("h*")
# => ["8797a7"]

["8797a7"].pack("h*")
# => "xyz"
String Encoding Directives

Pack supports a few encoding conversion directives. Note that they are idiosyncratic, since they don't take a count option.

u | UU-Encoding

Unix-to-Unix Encoding.

["Idiosyncrätic"].pack("u")
# => ".261I;W-Y;F-RPZ1T:6,`\n"

".261I;W-Y;F-RPZ1T:6,`\n".unpack("u")
# => ["Idiosyncr\xC3\xA4tic"]
M | Quoted-Printable / MIME Encoding (RFC2045)

Quoted-Printable.

["Idiosyncrätic"].pack("M")
# => "Idiosyncr=C3=A4tic=\n"

"Idiosyncr=C3=A4tic=\n".unpack("M")
# => ["Idiosyncr\xC3\xA4tic"]
m | Base64 Encoding (RFC 2045)

Base64. Ruby's standard library also contains a Base64 wrapper.

["Idiosyncrätic"].pack("m")
# => "SWRpb3N5bmNyw6R0aWM=\n"

"SWRpb3N5bmNyw6R0aWM=\n".unpack("m")
# => ["Idiosyncr\xC3\xA4tic"]
m0 | Base64 Encoding (RFC 4648)

Base64. This will not add a new-line at the end.

["Idiosyncrätic"].pack("m0")
# => "SWRpb3N5bmNyw6R0aWM="

"SWRpb3N5bmNyw6R0aWM=".unpack("m0")
# => ["Idiosyncr\xC3\xA4tic"]
Pointer Directives

Pointer inspection. If you want to understand how to use these, you should read pack's source.

P | Pointer to Fixed-Length String
["Idiosyncrätic"].pack('P*')
# => "\xC0\xDA\x04,.\x7F\x00\x00"

["Idiosyncrätic"].pack('P*').unpack("P*")
# => ["Idiosync"]
p | Pointer to Null-Terminated String
["Idiosyncrätic"].pack('p*')
# => "\xB8\xF8\x03\x1C.\x7F\x00\x00"

["Idiosyncrätic"].pack('p*').unpack("p*")
# => ["Idiosyncrätic"]
Positional Directives

You can jump around the current byte position while processing the data. This enables you to read data twice or ignore some data in the middle.

@ | Go to Position
"abc".unpack("H* @0B*")
#=> ["616263", "011000010110001001100011"]

["ffffff", "011000010110001001100011"].pack("H* @0B*")
# => "abc"

Note: There was a security issue with this feature where attackers would pass too large numbers to @. See the CVE-2018-8778 announcement for more info.

X | Move a Byte Back
"Idiosyncrä".unpack("C* X c*")
# => [73, 100, 105, 111, 115, 121, 110, 99, 114, 195, 164, -92]

[73, 100, 105, 111, 115, 121, 110, 99, 114, 195, 164, -92].pack("C* X c*")
# => "Idiosyncr\xC3\xA4"
x | Skip Byte (Fill with Null Byte when Packing)
"abc".unpack("C x C")
# => [97, 99]

[97, 99].pack("C x C")
# => "a\x00c"
New Features in Ruby 2.4 String#unpack1

When you unpack something, the resulting object will always be an array. Often, this array consists of only single element, which you are interested in (for example, this is the case for all String Encoding Directives). This is why the unpack1 has been introduced - It will return the first element directly:

"ℜ".unpack1("U")
# => 8476
buffer: Option for Array#pack

This keyword argument for Array#pack lets you use an existing (already allocated) string object as the result object¹²³:

require "fiddle"

# Initialize a string we will use later
a = "Idiosyncrätic Ruby"
Fiddle::Pointer[a]
# => #<Fiddle::Pointer:0x00000001e79af0 ptr=0x00000001c3b270
#      size=18 free=0x00000000000000>

# Pack something, the normal way
b = [1,2,3,4].pack("C*")
# => "\x01\x02\x03\x04"
Fiddle::Pointer[b]
# => #<Fiddle::Pointer:0x00000001ef51a0 ptr=0x00000001fc7980
#      size=4 free=0x00000000000000>

# Pack something, using an existing buffer
# It appends the result to the existing string object (same memory address)
c = [1,2,3,4].pack("C*", buffer: a)
# => "Idiosyncratic Ruby\u0001\u0002\u0003\u0004"
Fiddle::Pointer[c]
# => #<Fiddle::Pointer:0x00000001c314d0 ptr=0x00000001c3b270
#      size=22 free=0x00000000000000>

a == c
# => true

¹ Only if the string's capacity is enough to fit the result
² You can manually create string buffers of a specific size with another new keyword option:
String.new(..., capacity: ...)
³ See the RDoc for more info how the buffer argument is handled exactly

New Features in Ruby 3.2 offset: Option for String#unpack / String#unpack1

"Idiosyncrätic".unpack1("C*", offset: 1) #=> 100 ("d")

Resources Also See
https://idiosyncratic-ruby.com/4-what-the-pack.html
Ruby, Can You Speak Louder?
Show full content

Ruby has some ways to turn on debug mode, which library authors can use to print out extra information for interested users. But unfortunately, there are multiple debug modes in Ruby. When to use which one?

Consider you have this code:

def production_method
  puts "I am doing the right thing part 1"
  # @a is really intereting here
  puts "I am doing the right thing part 2"
end

We could query the global $DEBUG variable, which can be toggled when starting the Ruby interpreter:

def production_method
  puts "I am doing the right thing part 1"
  $stderr.puts "@a is now: #{@a}" if $DEBUG
  puts "I am doing the right thing part 2"
end

But is this the best way? It also could have been:

$stderr.puts "@a is now: #{@a}" if $VERBOSE

Or:

$stderr.puts "@a is now: #{@a}" if Library.debug_mode?

And what about:

warn "@a is now: #{@a}"

Ruby is a little idiosyncratic here. There is no standard way to signalize "I want to have more information". Ruby has two global debug modes: debug mode and verbosity mode and both behave differently. Within Ruby, the current debug mode state can be queried from two global variables:

Global Debug State

This table shows the different modes both of them can have:

Variable Value CLI-Variable Mirrors¹ Meaning $DEBUG true $-d == true Debug mode active $DEBUG false² $-d == false Debug mode inactive $VERBOSE true $-v == true
$-w == true
$-W == 2 Verbosity mode active $VERBOSE false² $-v == false
$-w == false
$-W == 1 Medium verbosity mode $VERBOSE nil $-v == nil
$-w == nil
$-W == 0 Silent verbosity mode

¹ Will be set automatically
² Default

Note that the Verbosity mode is different for $VERBOSE == false and $VERBOSE == nil.

Another side note: While it is possible to change $DEBUG to an arbitrary value, this is not true for $VERBOSE - If you assign it a trueish value, it will just be set to true.

What follows is a list of command line options that have an effects on the debug modes:

Command Line Options for Debug Modes Option Alias Effects -W2 -W, -w Sets $VERBOSE to true -W1   Nothing ($VERBOSE remains false) -W0   Sets $VERBOSE to nil --verbose   Sets $VERBOSE to true
Also quits Ruby if no arguments given -v   Sets $VERBOSE to true
Also Prints Ruby version
Also quits Ruby if no arguments given --debug -d Sets $DEBUG to true
Sets $VERBOSE to true

A funny thing to note is that -v is a shortcut for --version as well as it is one for --verbose.

Effect of Debug Modes on Interpreter Verbosity $VERBOSE Effect true or false (but not nil) Kernel#warn will output to STDERR true Interpreter level 1 warnings will be printed, for example, duplicated hash keys true Interpreter level 2 warnings will be printed, for example, method redefinition Debug Mode $DEBUG Effect true Extended exception reporting will be turned on. See this blog post for an example. It will also turn on Thread.abort_on_exception Best Practice

Use neither $VERBOSE, nor $DEBUG, but use custom logging, for example standard library's logger or some other logging gem. It is easier to understand than relying on the global debug modes.

Use $VERBOSE = true if you are interested in level 2 interpreter warnings.

Use $DEBUG = true if you want to turn on extended exception reporting or enable Thread.abort_on_exception.

Further Reading
https://idiosyncratic-ruby.com/3-ruby-can-you-speak-louder.html
Ruby String Magic
Show full content

Ruby strings are powerful. You could say Ruby is built around manipulating strings. There are tons of ways how to work with strings and as of Ruby 2.7.1 String offers 130 instance methods. Knowing them well can save you a lot of time.

What follows is a list of 10 lesser known things about strings: Some of them useful, some of them idiosyncratic, some both.

Named Format Strings

Btw, Ruby's format strings can be used with hashes:
"%<language>s: %<author>s" % { language: "Ruby", author: "matz" } #=> "Ruby: matz"

— Ruby String Magic (@RubyStrings) October 28, 2014
String Concatenation

There is a lesser-known syntax for concatenating string literals: "just" "put" "them" "directly""after" "each" "other"

— Ruby String Magic (@RubyStrings) September 11, 2014
Strings + Empty Ranges

Ruby is strange. How can an *empty* range have an effect when applied to a string?
r = 0..-3
r.to_a.empty? #=> true
"Ruby"[r] #=> "Ru"

— Ruby String Magic (@RubyStrings) October 6, 2014
Whitespace Matching

Unicode is full of whitespaces. This is how you match them:
a="     " #=> "     "
a.scan(/\s/).size #=> 1
a.scan(/[[:space:]]/).size #=> 5

— Ruby String Magic (@RubyStrings) December 1, 2014
String#succ

Ruby's weird calculation of string successors:
"9z".succ #=> "10a"
"z9".succ #=> "aa0"

— Ruby String Magic (@RubyStrings) October 9, 2014
Stdlib String Compression

Simple stdlib string compression:
require 'zlib'
s = "Ruby"*99
s.size #=> 396
c = Zlib.deflate(s)
c.size #=> 17
Zlib.inflate(c) == s #=>true

— Ruby String Magic (@RubyStrings) September 16, 2014
Using Regex Groups in String#[]

You can use regex incl. captured groups when accessing substrings via the [] method: "#42"[/.(\d+)/, 1] #=> "42"

— Ruby String Magic (@RubyStrings) September 7, 2014
Rexep.union

If you have an array of strings, you can automatically generate a regex that matches any the strings: regex = Regexp.union(array_of_strings)

— Ruby String Magic (@RubyStrings) September 12, 2014
Convert a String from snake_case to CamelCase

You can camelize a string (some_string => SomeString) with:
"some_string".gsub(/(?:^|_)([a-z])/) do $1.upcase end

— Ruby String Magic (@RubyStrings) September 9, 2014
Convert a String from CamelCase to snake_case

You can snakify a string (SomeString => some_string) with:
"SomeString".gsub(/(?<!^)[A-Z]/) do "_#$&" end.downcase

— Ruby String Magic (@RubyStrings) September 8, 2014
Resources
https://idiosyncratic-ruby.com/2-ruby-string-magic.html
Test Highlights
Show full content

Compared to other languages, Ruby does not have very good tool support for development. This might not be a problem for many of us: In the end, humans create the code, and not the tools.

Nevertheless, it would be great to have better tools. Or at least valid syntax highlighting!

The following table shows popular options for code highlighting, but none of them can manage to properly highlight more advanced Ruby features. Here is the:

Syntax Highlighter Comparison Editor or Syntax Highlighter Version Highlights Ruby Correctly?¹ coderay 1.1.0 no. score: 4/5 ruby mine 7.1 RM-141.664 no. score: 4/5 rouge 1.8.0 no. score: 3/5 emacs 24.3.1 no. score: 2/5 pygments 1.6 no. score: 2/5 gedit 3.10.4 no. score: 1/5 prism.js 0.0.1 no. score: 1/5 rainbow.js 1.1.9 no. score: 1/5 src-highlight 3.1.6 (library: 4:0:0) no. score: 1/5 syntaxhighlighter.js 3.0.83 no. score: 1/5 vim 7.4.52 no. score: 1/5 atom 0.192.0 no. score: 0/5 highlight.js 8.5 no. score: 0/5 sublime text 3 Build 3083 no. score: 0/5

¹ Obviously, passing the test does not necessarily mean that a tool highlights Ruby correctly - but it is an indication.

The Idiosyncratic Ruby Syntax Highlight Test
# # #
# For Reference
42
"String with #{ :interpolation }"
/regex$/
$/

# # #
# TEST CASE 1: Question Marks
# SHOULD BE HIGHLIGHTED AS: Array of Strings - Operator - String - Operator - String

[?', ?(] ?'a':'b'

# # #
# TEST CASE 2: Percent Format
# SHOULD BE HIGHLIGHTED AS: String - Operator - Array of Numbers

"%d %d %d"%[1,2,3]

# # #
# TEST CASE 3: Space-delimited String
# SHOULD BE HIGHLIGHTED AS: String Delimiter - String

% 5 #

# # #
# TEST CASE 4: Multi-line Regex with Global Variable Interpolation
# SHOULD BE HIGHLIGHTED AS: Regex Delimiter - Regex -
#                           Interpolation Character (Optional) -
#                           Global Variable -
#                           Regex Delimiter - Regex Options

/
$$#$/
/omix

# # #
# TEST CASE 5: Nested Heredoc
# SHOULD BE HIGHLIGHTED AS: Method - String Delimiter - Operator -
#                           String Delimiter - String - String Delimiter
#                           String - String Delimiter

puts <<HERE<<<<THERE
foo 42
HERE
bla 43
THERE
https://idiosyncratic-ruby.com/1-test-highlights.html