Вопрос

Я хочу написать простой Ruby DSL для перевода некоторых операторов и выражений на другой язык.Основным примером может быть:

some_function {
    t + 2
}

Здесь t не является переменной ruby, и, следовательно, блок не может (и не должен!) быть оценен Ruby.Поэтому моим лучшим выбором было бы использовать выходные данные синтаксического анализа (или AST), чтобы выполнить перевод самостоятельно.Для этого я могу использовать ParseTree и ruby2ruby.Однако у меня есть другие конструкции, которые я хотел бы использовать, например:

1.upto(10) {|x|
    some_function {
        t + x
    }
}

Здесь у меня есть локальная переменная, и мне нужно получить ее значение, чтобы выполнить мой перевод.Однако в функции, которая выполняет вычисление блока, у меня нет доступа к локальным переменным вызывающего блока.Если бы это была глобальная переменная ($ x), я мог бы проверить, существует ли ее имя в массиве global_variables, и в худшем случае использовать eval , но как я мог бы сделать это для локальной переменной, если это вообще возможно?

Обновить:

Просто чтобы кое-что прояснить.Как я уже говорил изначально, я использую ruby2ruby (и, следовательно, ParseTree), чтобы получить AST (используя to_sexp), соответствующий блоку.Но при использовании локальной переменной внутри моего блока я сталкиваюсь со следующим:

[:dvar, :x]

И, таким образом, мне нужно было бы получить значение переменной из ее имени в виде строки / символа.И я не могу использовать method_missing или instance_eval , потому что я хочу перевести все выражение на другой язык или синтаксис (например, RPN).

Тем не менее, приветствовалось бы другое решение, не основанное на ParseTree, поскольку оно, по-видимому, не полностью поддерживается Ruby 1.9.

Это было полезно?

Решение

Чтобы получить значения переменных, используйте привязку процедуры:

def some_function(&block)
  b = block.binding
  p [b.eval("t"), b.eval("x")]
end

t = 1
1.upto(10) {|x|
  some_function {
    t + x
  }
}

Другие советы

Здесь t не является переменной ruby и таким образом, блок не может (и не должен!) быть оценен Ruby.

Есть какая-либо причина для ограничения "не оценено"?Это похоже на метод_миссинга элегантно справился бы с оценкой "недостающего" t переменной, но Ruby автоматически разыменовал бы x переменная.

Вы можете использовать instance_eval для объекта с t.

class Context
  attr_accessor :t

  def initialize(_t)
    @t = _t
  end
end

def some_function(&block)
  puts Context.new(1).instance_eval(&block)
end

1.upto(10) {|x|
  some_function {
    t + x
  }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top