Vastavalt määratlusele on DSL (Domain Specific Language) arvutikeel, mis on spetsialiseerunud konkreetsele rakendusvaldkonnale. See tähendab, et see on välja töötatud konkreetsete vajaduste rahuldamiseks.
Seda artiklit lugedes saate teada, mis on DSL ja mis on sellel ühist Ruby'ga.
DSL, tere tulemast!
Vastavalt määratlusele on DSL (Domain Specific Language) arvutikeel, mis on spetsialiseerunud konkreetsele rakendusvaldkonnale. See tähendab, et see on välja töötatud konkreetsete vajaduste rahuldamiseks. DSL on kahte tüüpi:
-
An väline DSL, mis nõuab oma süntaksiparserit. Hea tuntud näide võib olla SQL-keel - see võimaldab suhelda andmebaasiga keeles, milles andmebaasi ei ole loodud.
-
An sisemine DSL, millel ei ole oma süntaks, vaid mis kasutab konkreetse programmeerimiskeele süntaksit.
Nagu te ilmselt võite arvata, keskendume me teisele DSL-tüübile.
Mida see teeb?
Põhimõtteliselt võimaldab see Ruby metaprogrammeerimist kasutades luua oma minikeele. Metaprogrammeerimine on programmeerimistehnika, mis võimaldab kirjutada kood dünaamiliselt töö ajal (jooksvalt). Te ei pruugi sellest teadlik olla, kuid tõenäoliselt kasutate iga päev palju erinevaid DSL-e. Selleks, et mõista, mida DSL võib teha, vaatame mõned näited allpool - neil kõigil on üks ühine element, aga kas te oskate seda näidata?
Rails marsruutimine
Rails.application.routes.draw do
root to: 'home#index'
resources :users do
get :search, on: :collection
end
end
```
Iga inimene, kes on kunagi kasutanud Rails teada config/routes.rb faili, kus me määratleme rakenduse marsruudid (HTTP-verbide ja URL-ide seostamine kontrolleri tegevustega). Aga kas olete kunagi mõelnud, kuidas see toimib? Tegelikult on see lihtsalt Ruby kood.
Factory Bot
FactoryBot.define do
factory :user do
ettevõte
sequence(:email) { |i| "user_#{i}@test.com" }
sequence(:first_name) { |i| "kasutaja #{i}" }
last_name 'Test'
roll 'manager'
end
end
Testide kirjutamine nõuab sageli objektide valmistamist. Seega oleks aja raiskamise vältimiseks tõesti hea mõte protsessi võimalikult palju lihtsustada. See ongi see, mida FactoryBot teeb - kergesti meeldejäävad märksõnad ja viis objekti kirjeldamiseks.
Sinatra
nõuda 'sinatra/base'
class WebApplication < Sinatra::Base
get '/' do
'Hello world'
end
end
```
Sinatra on raamistik, mis võimaldab teil luua veebirakendusi nullist. Kas taotluse meetodi, tee ja vastuse määratlemine võiks olla lihtsam?
Muud DSL-i näited võivad olla järgmised Rake, RSpec või Aktiivne rekord. Iga DSLi põhielement on plokkide kasutamine.
Ehitusaeg
Aeg on mõista, mis peitub kapoti all ja kuidas rakendamine võib välja näha.
Oletame, et meil on rakendus, mis salvestab andmeid erinevate toodete kohta. Me tahame seda laiendada, andes võimaluse importida andmeid kasutaja määratud failist. Samuti peaks fail võimaldama vajadusel dünaamiliselt arvutada väärtusi. Selle saavutamiseks otsustame luua DSLi.
Lihtne toode esitus võib omada järgmisi atribuute (product.rb):
class Product
attr_accessor :name, :description, :price
end
Selle asemel, et kasutada reaalset andmebaasi, simuleerime lihtsalt selle tööd (fake_products_database.rb):
class FakeProductsDatabase
def self.store(product)
puts [product.name, product.description, product.price].join(' - ')
end
end
Nüüd loome klassi, mis vastutab toodete andmeid sisaldava faili lugemise ja käitlemise eest (dsl/data_importer.rb):
moodul Dsl
klass DataImporter
moodul Süntaks
def add_product(&block)
FakeProductsDatabase.store product(&block)
end
private
def product(&block)
ProductBuilder.new.tap { |b| b.instance_eval(&block) }.product
end
end
include süntaks
def self.import_data(file_path)
new.instance_eval File.read(file_path)
end
end
end
```
Klassil on meetod nimega import_data mis ootab argumendina failipuude esitamist. Faili loetakse ja tulemus edastatakse failiühendusele instance_eval meetodit, mida kutsutakse klassi instantsile. Mida see teeb? Ta hindab stringi Ruby koodina instantsi kontekstis. See tähendab, et ise on instantsi DataImporter klass. Tänu sellele, et meil on võimalik määratleda soovitud süntaks/võtmesõnad (parema loetavuse huvides on süntaks määratletud moodulina). Kui add_product meetodit kutsutakse meetodi jaoks antud plokki, mida hindab ProductBuilder instantsi, mis ehitab Toode näiteks. ProductBuilder klass on kirjeldatud allpool (dsl/product_builder.rb):
moodul Dsl
klass ProductBuilder
ATTRIBUTES = %i[nimi kirjeldus hind].freeze
attr_reader :product
def initialize
@product = Product.new
end
ATTRIBUTES.each do |attribuut|
define_method(atribuut) do |arg = nil, &block|
value = block.is_a?(Proc) ? block.call : arg
product.public_send("#{attribuut}=", value)
end
end
end
end
```
Klass määratleb süntaksi, mis on lubatud add_product plokk. Mõningase metaprogrammeerimise abil lisatakse meetodid, mis omistavad toote atribuutidele väärtusi. Need meetodid toetavad ka ploki edastamist otsese väärtuse asemel, nii et väärtust saab arvutada töö ajal. Kasutades atribuutide lugejat, saame lõpus ehitatud toote.
Nüüd lisame impordiskripti (import_job.rb):
requirerelative 'dsl/dataimporter'
requirerelative 'dsl/productbuilder'
requirerelative 'fakeproductsdatabase'
requirerelative 'product'
Dsl::DataImporter.import_data(ARGV[0])
```
Ja lõpuks - kasutades meie DSL-i - fail toodete andmetega (dataset.rb):
```ruby
add_product do
name 'Charger'
description 'Life saving'
price 19.99
end
add_product do
name 'Autovrakk'
description { "Vrakk kell #{Time.now.strftime('%F %T')}" }
price 0.01
end
add_product do
nimi 'Lockpick'
description 'Uksed ei sulgu'
hind 7.50
end
```
Andmete importimiseks tuleb täita vaid üks käsk:
ruby import_job.rb dataset.rb
Ja tulemus on..
Laadija - elupäästja - 19.99
Autovrakk - purunes kell 2018-12-09 09:47:42 - 0.01
Lockpick - Uksed ei sulgu - 7.5
..edu!
Kokkuvõte
Kõiki eespool toodud näiteid vaadates ei ole raske märgata DSLi pakutavaid võimalusi. DSL võimaldab lihtsustada mõningaid rutiinseid toiminguid, peites kogu vajaliku loogika ja avaldades kasutajale ainult kõige olulisemad võtmesõnad. See võimaldab saavutada kõrgema abstraktsioonitaseme ja pakub paindlikke kasutusvõimalusi (mis on eriti väärtuslik taaskasutatavuse seisukohalt). Teisest küljest, DSL-i lisamine oma projekt tuleks alati hästi läbi mõelda - metaprogrammeerimist kasutavat rakendust on kindlasti palju raskem mõista ja hooldada. Lisaks nõuab see oma dünaamilisuse tõttu kindlat testide komplekti. DSL-i dokumenteerimine soodustab selle lihtsamat mõistmist, seega tasub seda kindlasti teha. Kuigi oma DSL-i rakendamine võib olla tasuv, on hea meeles pidada, et see peab end ära tasuma.
Kas saite huvi teema vastu? Kui jah, siis andke meile teada - me räägime teile DSList, mille oleme hiljuti loonud, et vastata nõuetele ühes meie projektis.