Проверьте, включает ли блок метод, не запуская его в Ruby - PullRequest
0 голосов
/ 19 июня 2011

Я пишу внутренний DSL на Ruby. В настоящее время базовой структурой этого мини-языка является блок, который должен включать метод during и, необязательно, некоторые другие методы. E.g.:

do
  something...
  during do ... end
  something else ...
end

Я бы хотел упростить язык, обрабатывая блоки по-разному, если они не включают , включая ключевое слово during. В этом случае я могу рассматривать их как любой другой блок Ruby.

Можно ли определить, включает ли блок определенный метод , не запуская его ? Можно предположить, что метод не вложен во внутреннюю область, как оператор if или while. Я предполагаю, что, если возможно, это потребует рефлексии, и это нормально.

Уточнение и объяснения

Я не пытаюсь решить проблему остановки или преодолеть любую хитрость, о которой может подумать хакер Ruby. Решение может применяться только в самом наивном случае.

На нескольких языках можно получить некоторое представление об исходном коде во время выполнения. В методе Python объекты имеют поля, такие как привязки и байт-код. В Java можно, хотя и не тривиально, читать байт-код метода и искать команды invokevirtual.

Я не очень знаком с Руби. Я не знаю, имеют ли объекты Ruby, которые представляют элементы управления, такие как процессы и блоки, похожие поля. Если мне не изменяет память, у Ruby есть некоторая структура для доступа к его AST во время выполнения. Тем не менее, я не знаю, если и как эта структура может получить доступ к конкретным блокам. Решение, основанное на анализе AST во время выполнения, которое работает только для простых случаев, вполне приемлемо.

Ответы [ 3 ]

2 голосов
/ 19 июня 2011

Спонтанно единственный способ, который приходит на ум, - это использовать метод to_source из гема sourcify, а затем сопоставлять его с полученной строкой:

https://github.com/ngty/sourcify

2 голосов
/ 18 июля 2011

Впрочем, немного поздно. В любом случае, Proc # to_source sourcify поддерживает передачу соответствия тела, чтобы помочь вам получить то, что вы хотите:

x = proc do
  something...
  during do ... end
  something else ...
end

x.to_source {|body| body =~ /\bduring\b\s*(\{|do)/m }

С этим вы можете избежать пересечения пола. Однако все, что возвращается Proc # to_sexp и Proc # to_source, было нормализовано для совместимости с ParseTree, что может или не может быть тем, что вы хотите. Если вы действительно хотите захватить источник (как он изначально написан, например, сохранив комментарий), вы можете попробовать:

x.to_raw_source {|body| body =~ /\bduring\b\s*(\{|do)/m }

Если у вас есть определенный код 1.9, sourcify может выйти из строя, как это скрыто, он использует RubyParser для некоторой проверки синтаксиса, а RubyParser пока не совместим на 100% с синтаксисом 1.9. Тем не менее, продолжается работа по устранению этой проблемы.

Надеюсь, что вышеупомянутое помогает:]

0 голосов
/ 19 июня 2011

IMO, лучший способ для вас - это делать это внутри самого метода и не пытаться делать что-либо чрезвычайно сложное без необходимости.Хотя это зависит от того, определяете ли вы метод или нет, но вы все равно можете найти способ переопределить его при необходимости.

...