Các DSL của Ruby hoàn toàn không phải là DSL và tôi hoàn toàn ghét sử dụng chúng vì tài liệu của chúng hoàn toàn nói dối về cách chúng thực sự hoạt động. Hãy lấy ActiveRecord làm ví dụ. Nó cho phép bạn "khai báo" các liên kết giữa các Mô hình:
class Foo < ActiveRecord::Base
has_one :bar
has_one :baz
end
Nhưng tính từ chối của "DSL" này (giống như tính khử của class
chính cú pháp của Ruby ) là một lời nói dối khủng khiếp có thể bị lộ bởi bất kỳ ai hiểu cách Ruby "DSL" thực sự hoạt động:
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
(Chỉ cần thử làm bất cứ điều gì gần với điều đó trong cơ thể của một defclass
hình thức Lisp !)
Ngay khi bạn có mã như trên trong cơ sở mã của mình, mọi nhà phát triển trong dự án phải hiểu đầy đủ cách Ruby DSL thực sự hoạt động (không chỉ là ảo ảnh mà họ tạo ra) trước khi họ có thể duy trì mã. Các tài liệu có sẵn sẽ hoàn toàn vô dụng, bởi vì chúng chỉ ghi lại cách sử dụng thành ngữ , giúp duy trì ảo giác khai báo.
RSpec thậm chí còn tồi tệ hơn so với ở trên, bởi vì nó có các trường hợp cạnh kỳ quái đòi hỏi kỹ thuật đảo ngược rộng rãi để gỡ lỗi. (Tôi đã dành cả ngày cố gắng tìm ra lý do tại sao một trong các trường hợp thử nghiệm của tôi đã bị bỏ qua. Hóa ra là RSpec thực hiện tất cả các trường hợp thử nghiệm có bối cảnh sau khi trường hợp thử nghiệm không có bối cảnh, không phụ thuộc vào thứ tự mà chúng xuất hiện trong nguồn , bởi vì context
phương thức đặt khối của bạn trong một cấu trúc dữ liệu khác với cách thông thường.)
Lisp DSL được triển khai bởi các macro, là các trình biên dịch nhỏ. Các DSL bạn có thể tạo theo cách này không chỉ là lạm dụng cú pháp hiện có của Lisp. Chúng là những ngôn ngữ nhỏ thực sự có thể được viết hoàn toàn liền mạch, bởi vì chúng có thể có ngữ pháp riêng. Ví dụ, LOOP
macro của Lisp mạnh hơn nhiều so với each
phương pháp của Ruby .
(Tôi biết bạn đã chấp nhận câu trả lời, nhưng không phải ai đọc nó cũng sẽ muốn đọc toàn bộ On Lisp .)