Estoy tratando de descubrir cómo crear una especie de "DSL sin clase" para mi proyecto Ruby, similar a cómo se definen las etapas en un archivo de definición de paso de Cucumber o las rutas se definen en una aplicación Sinatra.¿Cómo crear un DSL sin clase en Ruby?
Por ejemplo, yo quiero tener un archivo donde están siendo llamados todos mis funciones DSL:
#sample.rb
when_string_matches /hello (.+)/ do |name|
call_another_method(name)
end
supongo que es una mala práctica de contaminar el (Kernel
) espacio de nombres global con un montón de métodos que sean específico para mi proyecto. Entonces los métodos when_string_matches
y call_another_method
se definirían en mi biblioteca y el archivo sample.rb
se evaluaría de alguna manera en el contexto de mis métodos DSL.
Actualización: Aquí está un ejemplo de cómo se definen actualmente estos métodos DSL:
El DSL métodos se definen en una clase que se está subclase (me gustaría encontrar una manera de volver a utilizar estos métodos entre la DSL simple y las instancias de clases):
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
a continuación, en algún momento, durante la inicialización de mi programa, quiero analizar el archivo sample.rb
y almacenar estas acciones a ejecutar más tarde:
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
El problema con lo que tengo hasta ahora (y las varias cosas que he intentado que no mencioné anteriormente) es cuando se define un bloque en el archivo, el método de instancia no está disponible (sé que está en una clase diferente ahora mismo). Pero lo que quiero hacer es más como crear una instancia y evaluar en ese contexto en lugar de evaluar en la clase Parser
. Pero no sé cómo hacer esto.
Espero que tenga sentido. Cualquier ayuda, experiencia o consejo sería apreciado.
Hay mucho para mí para digerir allí ya que algo de eso está un poco sobre mi cabeza, pero aún así es útil. ¡Gracias! – Andrew