Sto cercando di capire come creare una sorta di "DSL senza classi" per il mio progetto Ruby, in modo simile a come le definizioni dei passi sono definite in un file di definizioni passo Cucumber o le rotte sono definite in un'applicazione Sinatra.Come creare un DSL senza classi in Ruby?
Per esempio, io voglio avere un file in cui tutte le mie funzioni DSL sono chiamati:
#sample.rb
when_string_matches /hello (.+)/ do |name|
call_another_method(name)
end
Penso che sia una cattiva pratica di inquinare la (Kernel
) namespace globale con un gruppo di metodi che sono specifico per il mio progetto. Quindi i metodi when_string_matches
e call_another_method
verrebbero definiti nella mia libreria e il file sample.rb
verrebbe in qualche modo valutato nel contesto dei miei metodi DSL.
Aggiornamento: Ecco un esempio di come questi metodi DSL sono attualmente definiti:
Il DSL metodi sono definiti in una classe che si sta sottoclassi (mi piacerebbe trovare un modo per riutilizzare questi metodi tra la semplice DSL e le istanze di classe):
module MyMod
class Action
def call_another_method(value)
puts value
end
def handle(text)
# a subclass would be expected to define
# this method (as an alternative to the
# simple DSL approach)
end
end
end
Poi ad un certo punto, durante l'inizializzazione del mio programma, voglio analizzare il file sample.rb
e memorizzare queste azioni da eseguire in seguito:
module MyMod
class Parser
# parse the file, saving the blocks and regular expressions to call later
def parse_it
file_contents = File.read('sample.rb')
instance_eval file_contents
end
# doesnt seem like this belongs here, but it won't work if it's not
def self.when_string_matches(regex, &block)
MyMod.blocks_for_executing_later << { regex: regex, block: block }
end
end
end
# Later...
module MyMod
class Runner
def run
string = 'hello Andrew'
MyMod.blocks_for_executing_later.each do |action|
if string =~ action[:regex]
args = action[:regex].match(string).captures
action[:block].call(args)
end
end
end
end
end
Il problema con quello che ho finora (e le varie cose che ho provato che non ho menzionato sopra) è quando un blocco è definito nel file, il metodo di istanza non è disponibile (lo so che è in una classe diversa in questo momento). Ma quello che voglio fare è più come creare un'istanza e valutare in quel contesto piuttosto che evalutare nella classe Parser
. Ma non so come farlo.
Spero che abbia senso. Qualsiasi aiuto, esperienza o consiglio sarebbe apprezzato.
C'è molto per me da digerire perché alcuni sono un po 'sopra la mia testa, ma è comunque utile. Grazie! – Andrew