Ruby'nin DSL'leri hiç DSL değil ve bunları kullanmaktan kesinlikle nefret ediyorum çünkü dokümantasyonları gerçekten nasıl yürüdüğü konusunda yatıyor. Örneğin ActiveRecord'u ele alalım. Modeller arasındaki ilişkileri "bildirmenizi" sağlar:
class Foo < ActiveRecord::Base
has_one :bar
has_one :baz
end
Ancak, bu "DSL" nin bildirimi (Ruby'nin class
sözdiziminin kendisinin bildirimi gibi ), Ruby "DSL" lerin gerçekte nasıl çalıştığını anlayan herkes tarafından açığa çıkabilen korkunç bir yalan:
class Foo < ActiveRecord::Base
[:bar,:baz,:qux,:quux].each do |table|
has_one table if i_feel_like_it?(table)
end
puts "Just for shits and giggles, and to show"
puts "just how fucked up Ruby really is, we're gonna ask you"
puts "which SQL table you want the Foo model to have an"
puts "association with.\n"
puts "Type the name of a table here: "
has_one gets.chomp.to_sym
end
(Sadece bir Lisp formunun bedeninde buna yakın bir şey yapmayı deneyin defclass
!)
Kod tabanınızda yukarıdaki gibi bir kodun olduğu anda, projedeki her geliştiricinin, Ruby DSL'lerin , kodun bakımını yapmadan önce gerçekte nasıl çalıştığını (sadece yarattıkları yanılsamaları değil) tam olarak anlamaları gerekir . Mevcut belgeler tamamen yararsız olacaktır, çünkü bunlar yalnızca bildirimsel yanılsamayı koruyan deyimsel kullanımı belgelemektedir .
RSpec, yukarıdakinden bile daha kötü, çünkü hata ayıklamak için kapsamlı ters mühendislik gerektiren tuhaf kenar durumları var. (Bütün günlerimi neden test vakalarımdan birinin atlandığını bulmaya çalışarak geçirdim. RSpec'in test olaylarından sonra bağlamda olan tüm sınav vakalarını, bağlamda göründükleri sıraya bakılmaksızın bağlamsız yürütdüğü ortaya çıktı. , çünkü context
yöntem blokunuzu normalde girdiğinden farklı bir veri yapısına yerleştirir.)
Lisp DSL'ler, küçük derleyiciler olan makrolar tarafından uygulanır. Bu şekilde oluşturabileceğiniz DSL'ler, Lisp'in mevcut sözdizimini kötüye kullanmaz. Tamamen kusursuz olacak şekilde yazılabilecek gerçek mini dillerdir, çünkü kendi gramerlerine sahip olabilirler. Örneğin, Lisp'in LOOP
makroları Ruby'nin each
yönteminden çok daha güçlü .
(Çoktan bir cevap kabul ettiğinizi biliyorum, ancak bunu okuyan herkes On Lisp'in tamamını okumak isteyecek .)