Hrátky s Unicode identifkátory v Ruby
Na Silvestra vydal Jakub Vrána nevážně míněný článek o
patchi, který umožňuje používat v PHP různé symboly z Unicode – třeba
operátor ≤
nebo funkci √
. Vzhled programu se tak
přibližuje matematickému zápisu.
Hned po přečtení textu jsem začal přemýšlet nad tím, jak něco podobného spáchat v Ruby. Ruby totiž povoluje Unicode znaky v identifikátorech, a není tak ani třeba upravovat interpret, jako bylo nutné v případě PHP.
Pro další čtení doporučuji nejdřív přečíst zmiňovaný Jakubův článek, abyste byli v obraze. Tento text z něj totiž svým uspořádáním vychází.
Konstanty
Definice hodnot s názvy jako ½
či ¼
není v Ruby
problém:
½ = 0.5
¼ = 0.25
⅜ = 0.375
π = Math::PI
puts ½ # => 0.5
puts ¼ # => 0.25
puts ⅜ # => 0.375
puts π # => 3.14159265358979
Občas by se mohla hodit i prázdná množina nebo nekonečno:
∅ = []
∞ = 1.0 / 0.0
puts ∞ # => Infinity
Bohužel na rozdíl od opatchovaného PHP si tyto hodnoty nemůžeme definovat jako konstanty, neboť konstanty musí v Ruby začínat velkým písmenem. Musí postačit obyčejné proměnné.
Operátory
Psát v Ruby výrazy jako 1 ≠ 2
by bylo hezké, bohužel to ale tak
úplně nejde, protože Ruby neumožňuje definovat vlastní operátory (z jazyků, co
aspoň trochu znám, tohle umí jen Haskell). Pokud ale přežijeme volání "přes
tečku", můžeme si vytvořit aliasy pro odpovídající metody na numerických třídách
a volat pak je:
class Fixnum
alias ≠ != # nefunguje v Ruby 1.8.x
alias ≤ <=
alias ≥ >=
alias × *
alias ÷ /
# ...
end
# Analogicky i pro třídy Bignum a Float...
puts 1.≠ 2 # => true
puts 3.× 4 # => 12
puts 6.÷ 2 # => 2
Další matematika
Je libo odmocňovat pomocí funkce √
? Stačí přidat alias do modulu
Math
:
module Math
alias √ sqrt
end
Po inkluzi modulu už odmocninu můžeme používat:
include Math
puts √ 9 # => 3
Sumu (∑
) nebo součin (∏
) už jako alias definovat
nemůžeme, protože Ruby nemá vhodné metody, na které by šly tyto názvy namapovat.
Budeme si je tedy muset napsat (a to hezky funkcionálně :-)
def ∑(array)
array.inject(0) { |sum, item| sum + item }
end
def ∏(array)
array.inject(1) { |product, item| product * item }
end
puts ∑ [1,2,3,4] # => 10
puts ∏ [1,2,3,4] # => 24
Čistější by samozřejmě bylo definovat metody ve třídě Array
,
nebo ještě lépe v modulu Enumerable
.
V Ruby 1.9.0 bychom díky vylepšené metodě Enumerable#inject
mohli
definice součtu a součinu ještě o trochu zkrátit:
def ∑(array)
array.inject(0, :+)
end
def ∏(array)
array.inject(1, :*)
end
Lambda
Pokud jste se nahlédli do seznamu novinek Ruby 1.9.0, možná jste si všimli nové syntaxe pro lambda funkce:
f = ->(a, b){ a + b }
puts f.call(1, 2) # => 3
Matzovi (tvůrci Ruby) znaky "->" údajně po menší rotaci a translaci připomínají písmenko "lambda". Jelikož mě ne, rozhodl jsem se lambdu nadefinovat po svém:
module Kernel
alias λ lambda
end
f = λ { |a, b| a + b }
puts f.call(1, 2) # => 3
Pozor, nebezpečí!
V Ruby je (po vzoru Lispu) zvykem označovat metody, které "nebezpečně" modifikují obsah objektu, pomocí vykřičníku na konci jejich názvu:
s = "ABCD"
s.downcase!
puts s # => "abcd"
Pokud se vám to ale zdá málo výrazné, není problém použít jiný znak:
class String
alias downcase☠ downcase!
undef downcase!
# Podobně s dalšími metodami...
end
s = "ABCD"
s.downcase☠
puts s # => "abcd"
Chcete si taky hrát?
Na případné hraní s Unicode doporučuji stáhnout čerstvé Ruby 1.9.0, které podporuje specifikaci kódování zdrojáku přímo v souboru – na první řádek stačí napsat například toto:
# encoding=utf-8
V Ruby 1.8.x Unicode identifikátory fungují taky, ale při spuštění programu, který je používá, je nutno použít volbu -Ku, která přepne Ruby do režimu UTF-8. Tato volba funguje i v Ruby 1.9.0.
Šup sem s Ruby 1.9.0
Ruby 1.9.0 je v tuto chvíli k dispozici jen jako balík se zdrojovým kódem, který je nutno rozbalit a zkompilovat.
Pokud to uděláte, tak při spouštění ./configure doporučuji použít volbu --prefix a specifikovat adresář, kam se Ruby 1.9.0 po zkompilování nainstaluje. Nehrozí tak, že by nově zkompilovaná verze přepsala verzi nainstalovanou v systému.
Na mém Ubuntu 7.10 proběhla kompilace Ruby 1.9.0 bez problémů a stačilo napsat variaci na obvyklou "svatou trojici" příkazů:
./configure --prefix=/home/dmajda/ruby19 make sudo make install
Ke stažení
Příklady uvedené výše si můžete stáhnout hezky pohromadě v jednom souboru: unicode-fun.rb.
A to je konec...
alias † exit
†
Použité zdroje
- Mail Davida Flanagana a navazující vlákno v mailing listu ruby-core
- Changes in Ruby 1.9