Используйте Ruby для разбора Tcl DSL

Я хотел бы иметь возможность анализировать некоторый код Tcl, где аргументы не окружены строками.

Рассмотрим этот код tcl:

proc foo {name} {
  puts "Foo --> $name"
}    

foo bar

Для тех, кто не знаком с Tcl, foo — это имя метода, а bar — аргумент (в Tcl кавычки необязательны).

Предыдущий код выведет:

Foo --> bar

Можно ли проанализировать точно тот же ввод с помощью ruby ​​(bar остается без кавычек)?

Эквивалентный рубиновый код:

def foo(name)
  puts "Foo --> #{name}"
end

tcl = <<-TCL.gsub(/^\s+/, "").chop
  foo bar
TCL
instance_eval(tcl)

Конечно, это не удается, когда он достигает bar, поскольку ожидается, что он будет заключен в кавычки.

Я пробовал возиться с method_missing

def method_missing(meth, *args)
    puts meth.to_s + " --> args.to_s
end

но он анализирует в обратном порядке:

to_hash --> []
bar --> []
foo --> [nil]

У кого-нибудь есть чистое решение этой проблемы. Я хотел бы избежать токенизации строк, поскольку чтение данных путем вызова метода требует минимальной работы по сравнению с лексическим анализом. Но если я пытаюсь сделать что-то невозможное, я хотел бы знать. Спасибо.


person elmt    schedule 20.04.2011    source источник


Ответы (2)


Это не работает для вас, потому что метод .puts возвращает nil вместо строки:

irb(main):003:0> puts "42"
42
=> nil

Я действительно не знаю, почему to_hash появляется в этом method_missing, но это работает:

def foo(name)
  puts "Foo --> #{name}"
end

def method_missing(meth, *args)
     meth.to_s unless meth.to_s  == "to_hash"
end

tcl = <<-TCL.gsub(/^\s+/, "").chop
  foo bar
TCL

instance_eval(tcl)

=> Foo --> bar
person Vasiliy Ermolovich    schedule 20.04.2011
comment
Дэнг, я был так близок к тому, чтобы понять это. Спасибо за отзыв. Кто-нибудь может подсказать, откуда to_hash? - person elmt; 21.04.2011
comment
Tcl не использует ничего подобного nil; концепция разделена между пустой строкой (результатом puts Tcl) и отсутствием переменных. - person Donal Fellows; 21.04.2011

Это реализация, которая пытается сделать синтаксис близким к синтаксису TCL.

class TCL
  class << self
    alias run instance_eval
    def proc(n, &b)
      self.class.__send__(:define_method, n, &b)
    end
    def method_missing(n, *a, &b)
      n.to_s
    end
  end
end

TCL.run do

  proc(:foo) { |name|
    puts "Foo --> #{name}"
  }

  foo bar

end

# prints Foo --> bar
person Guilherme Bernal    schedule 20.04.2011
comment
Мне пришлось изменить ваши фигурные скобки в блоке, чтобы сделать/завершить из-за приоритета. А потом у меня все еще была ошибка с define_method, которую я не мог понять. Хотите уточнить немного больше? - person elmt; 21.04.2011
comment
@elmt, я внес изменения и теперь тестирую. Много чего было не так. Теперь это работает. - person Guilherme Bernal; 21.04.2011