Tk DSL теряет доступ к методам и переменным экземпляра?

Я знаю, что это не относится к tk, а скорее к более общей проблеме с ruby ​​DSL и instance_eval, но вот мой вопрос: если я хочу использовать DSL для tk, я не могу понять, как заставить некоторые вещи работать. Например, если я хочу вызвать метод экземпляра нажатием кнопки, это не сработает, потому что он думает, что я пытаюсь вызвать метод с тем же именем в родительском классе Tk (т.е. Tk::Button), как и в ниже код:

require 'tk'
class MyApp
  def initialize
    @root = TkRoot.new
    TkFrame.new {|f|
      TkButton.new(f) {
        text "Press Me"
        command proc {do_something()}
        pack
      }
      pack
    }
  end
  def do_something
    puts "Hello!"
  end
  def run
    Tk.mainloop
  end
end

MyApp.new.run

Если я перепишу его без использования DSL, я смогу избежать этой проблемы, но я предпочитаю DSL по разным причинам:

class MyApp
  def initialize
    @root = TkRoot.new
    f = TkFrame.new
    TkButton.new(f, text: "Press Me", command: proc {do_something()}).pack
    f.pack
  end
  def do_something
    puts "Hello!"
  end
  def run
    Tk.mainloop
  end
end

MyApp.new.run

То же самое верно и для переменных экземпляра класса MyApp. Есть ли способ обойти это?


person Eric Seifert    schedule 16.04.2012    source источник


Ответы (1)


proc { do_something }, вероятно, оценивается в контексте экземпляра TkButton. Вероятно, именно так вы можете вызывать text, command и pack, находясь внутри блока.

Фактически это означает, что self больше не является экземпляром MyApp; он был изменен на экземпляр TkButton.

Попробуй это:

def initialize
  my_app = self  # self is the MyApp instance here
  @root = TkRoot.new
  TkFrame.new do |f|
    TkButton.new f do
      text "Press Me"
      command proc { my_app.do_something }
      pack
    end
    pack
  end
end

Поскольку блоки являются замыканиями, для блока будет доступна локальная переменная my_app.

person Matheus Moreira    schedule 16.04.2012