Super-operatory w Rubym
5 komentarzy | Kategorie: Ruby, Techblog, Tips & tricks | trackbackTagi: hacks ruby superators tips&tricks
Ostatnim razem pisałem o zabawie z unicode w Rubym. Podkreślam słowo "zabawie" bo raczej nie jest to praktyczne. Chciałem jeszcze pokazać jeden dosyć ciekawy trick, który można uznać także za niezbyt praktyczny, choć niekoniecznie (o tym za chwilę).
Być może nieraz brakowało Wam operatorów w języku programowania? Może chcieliście wprowadzić swój, unikalny operator? A co byś powiedział na coś takiego:
puts "Tangy" ++ "Erlangy" #=> TANGYERLANGY
puts "Super" -~+~- "ators" #=> Superators
p ["jay"] <--- "spillihp" #=> ["jay", "phillips"]
rocket = Rocket.new
fuel = Fuele.new
rocket <=- fuel #=> rocket is full!
puts 1 /~ 2 #=> 0.5
p ["a", "b"] <~ ["c"] #=> ["a", "b", "c"]
Nie potrzebujesz do tego nowego parsera Rubiego, aktualny poradzi sobie z tym jak najbardziej. A wszystko dzięki temu jak Ruby interpretuje takie wiązanki. Otóż taki kod
foo ++- bar
jest równoważny temu
foo.+(bar.-@().+@())
Czyli są to wywołania zwykłych metod, które można odpowiednio przesłonić. Ten fakt wykorzystał jeden z hackerów Rubiego (co opisał na swoim blogu), zapakował ładnie do gema i nazwał go dumnie "superators".
Instalacja jest standardowa: gem install superators. Poniżej prezentuję uzupełniony kod o definicję superatorów
require 'rubygems'
require 'superators'
class Array
superator "<---" do |operand|
self << operand.reverse
end
superator "<~" do |operand|
self.concat(operand)
sort!
end
end
class String
superator "++" do |operand|
upcase + operand.upcase
end
superator "-~+~-" do |operand|
self + operand
end
end
class Rocket
superator "<=-" do |operand|
puts "rocket is full!"
end
end
class Fuel
end
puts "Tangy" ++ "Erlangy" #=> TANGYERLANGY
puts "Super" -~+~- "ators" #=> Superators
p ["jay"] <--- "spillihp" #=> ["jay", "phillips"]
rocket = Rocket.new
fuel = Fuel.new
rocket <=- fuel #=> rocket is full!
p ["b", "z", "y"] <~ ["c", "a"] #=> ["a", "b", "c", "y", "z"]
Sposób tworzenia operatorów nie jest dowolny i podlega pewnej zasadzie. Prawidłowy superator to:
-na pierwszym miejscu jeden z binarnych operatorów: ** * / % + – << >> & | ^ <=> >= <= < > === == =~
-potem dowolna ilość operatorów unarnych: – ~ +
A co z wykorzystaniem tego w praktyce? Otóż może to się przydać przy tworzeniu jakiegoś DSL-a, w czym Ruby jest po prostu genialny. Można też pokusić się o wykorzystanie tej metody w jakimś naszym osobistym, superwypaśnym skrypcie :). Albo żeby wkurzyć innego programistę...
Jakby nie wystarczyło Perla używać ;-)
A poważnie: DSLe są zajebiste. http://www.generative-programming.org/
Heh, super sprawa, Ruby chyba nigdy nie przestanie mnie zadziwiac.
@Khorne, czy aby na pewno mówimy o tym samym znaczeniu DSL?:)
@wijet, otóż to! Od samego początku Ruby mnie zadziwia i wciąż to robi :).
@Radarek, owszem. Czarnecki i Eisenecker pociągneli to po prostu dalej.
Na marginesie chodzi Ci nie tyle o DSL co o DSEL (embedded). Ładnym przykładem jest C++owy http://spirit.sourceforge.net/
@Khorne, rzeczywiście, ja raczej myślę kategoriami embedded DSL. W sumie na dzień dzisiejszy tylko one mnie iteresują, bo: – są embedded, więc nie muszę się martwić o zewn. środowisko, parsowanie itp – mogę je tworzyć w Rubym – więcej do szczęścia mi nie trzeba ;)