3

ルビー愛好家!私はルビーでDSLを書き込もうとしていますが、いくつかの魔法のメソッドを作成できるようにしたいと思っています(それが私が望むものの最も正確な用語であるかどうかはわかりません)。

次のようなことができるようになりたいです。

a = [1, 2, 3]
b = 2

(a contains b)

そして、それを真または偽に解決させます。

基本的に、関数 "contains"を定義して、配列aと変数bを受け取り、実行するa.contains?(b)ことができますが、関連するすべてのルビー固有の構文はありませんか?

4

3 に答える 3

2

あなたは虐待することができますmethod_missing。トリッキーなことは、ブロックのローカル変数に直接アクセスできないことです。ブロックの内部バインディングをどこかにキャプチャする必要があります(残念ながらblock.binding、ブロックの外部バインディングを返します)。

次のコードを実行できます。

DSL.new do
  a = [1, 2, 3]
  b = 2
  a contains b
end

次のように:

class DSL
  attr_reader :last_binding

  def initialize(&block)
    set_trace_func method(:trace).to_proc
    instance_eval(&block)
    set_trace_func nil
  end

  def trace(event, file, line, id, binding, klass)
    if event.to_s == "call" and klass == self.class and id.to_s == "method_missing"
      @last_binding ||= @current_binding
      set_trace_func nil
    else
      @current_binding = binding
    end
  end

  def lvars
    eval('local_variables', last_binding).map(&:to_s)
  end

  def method_missing(name, *args)
    name = name.to_s
    if lvars.include? name
      eval(name, last_binding).send(*args.flatten)
    else
      ["#{name}?", *args]
    end
  end
end

class Array
  alias contains? include?
end
于 2010-06-20T12:07:16.760 に答える
2

Ruby 構文を使用しない DSL が必要な場合は、少なくとも変換を実行するパーサーを作成する必要があります (raganwalds rewrite lib が出発点になる可能性があります。http://github.com/raganwald/rewrite ) 。

そうは言っても、あなたはこれをしたくありません。これはより多くのコードを維持する必要があり、Ruby は言語構文の記述を困難にする多くの困難な決定をすでに行っています。また、自然言語プログラミングは、フォーマットの正確さが難しい側面であるため、非プログラマーが使用するのはそれほど簡単ではありません (たとえば、applescript を参照してください)。

于 2010-06-20T01:51:39.090 に答える
0

私が考えることができる最も近いものは次のとおりです。

def contains var, useless_symbol, arr
  arr.include? var
end

次に、次のように呼び出すことができます。

contains b, :in, a


独自の関数で中置記法を使用できる方法はないと思います。

于 2010-06-20T01:18:42.843 に答える