私はRubyプロジェクトに「クラスレスDSL」を作成する方法を理解しようとしています。ステップ定義がCucumberのステップ定義ファイルで定義されている方法やSinatraアプリケーションで定義されている方法と似ています。私はそれがある方法の束を持つグローバル(Kernel
)名前空間を汚染する悪い習慣だと仮定しRubyでクラスレスDSLを作成するには?
#sample.rb
when_string_matches /hello (.+)/ do |name|
call_another_method(name)
end
:
は例えば、私はすべての私のDSL機能が呼び出されているファイルを持つようにしたいです私のプロジェクトに特有のものですしたがって、方法when_string_matches
とcall_another_method
は私のライブラリに定義され、sample.rb
ファイルは何とか私のDSLメソッドのコンテキストで評価されます。
更新:ここではこれらのDSL方式は、現在定義されている方法の例を示します。
メソッドがサブクラス化されているクラスで定義されているDSLは(私が間にこれらのメソッドを再利用する方法を見つけるしたいと思いますシンプルなDSLやクラスのインスタンス):
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
そして、いくつかの点で、私のプログラムの初期化中に、私はsample.rb
ファイルを解析し、後で実行されるこれらのアクション格納したい:
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
私がこれまで持っているものとの問題(と私は上記言及しなかったことを試みた様々なもの)ブロックは、ファイルに定義されている場合、インスタンスメソッドが利用可能ではありません(私がいることを知っています今は別のクラスにあります)。しかし、私がしたいのは、Parser
クラスで評価するのではなく、そのコンテキストでインスタンスを作成して評価することです。しかし、私はこれを行う方法を知らない。
私はそれが理にかなっていると思います。どんな助け、経験、アドバイスも感謝します。
def when_string_matches(regex)
# do whatever is required to produce `my_string` and `name`
yield(name) if my_string =~ regex
end
:
それは私の頭の上に少しあるので、そこに消化するための多くがありますが、それはまだ有用です。ありがとう! – Andrew