Вызов методов динамически (Crystal-lang)

Я понимаю, что это может быть дубликат метода Любого эквивалента метода public_send в Ruby? . Я хотел бы объяснить, что делаю, и, возможно, кто-нибудь сможет посоветовать.

Я портировал приложение Ruby в течение последних нескольких дней, чтобы изучить Crystal. Мне пришлось вырезать много функций из-за отсутствия send, но сегодня я затронул главную артерию в своей программе.

У меня есть хеш, который содержит нажатие клавиши как ключ и метод как значение. В зависимости от того, какая клавиша нажата, вызывается соответствующий метод. Очевидно, что для реализации того же самого используется send.

Из связанного вопроса я понимаю, что Crystal скомпилирован, поэтому вызовы динамических методов не разрешены. Однако, если вы посмотрите на редактор Vim, пользователь также может сопоставить ключи с методами. А vi (m) написано на C.

Интересно, не упустил ли я что-нибудь.

Я знаю, что, вероятно, мог бы жестко закодировать оператор switch с каждой клавишей и вызвать соответствующий метод, но это все еще не позволяет пользователю назначать клавишу методу. Есть ли альтернатива этому методу очень большого выключателя?

(Я предполагаю, что вместо того, чтобы проверять ключ в части when, я бы проверил привязку и вызвал метод.

 binding = @bindings[key]
 case binding
 when :up
    up
 when :down
    down
 when .....
 else
 end

Есть ли лучшее решение?


person rahul    schedule 30.04.2019    source источник
comment
Уточнение вашего примера с Vim - я бы предположил, что Vimscript - это то, что обрабатывает привязки клавиш, это динамический язык. Если бы он проходил через C, они могли бы иметь сопоставление ключа с функцией и искать метод из этого.   -  person Will Richardson    schedule 01.05.2019


Ответы (1)


Не уверен, что это самый простой и удобный способ (возможно, более опытные разработчики меня поправят ниже), но я бы использовал Proc:

def method1
  puts "i'm  method1"
end

def method2
  puts "i'm method2"
end

def method3
  puts "i'm  method3"
end

hash = { 
  "ctrl":  -> { method1 },
  "shift": -> { method2 },
  "alt":   -> { method3 }
}

binding = ["ctrl", "shift", "alt"].sample
hash[binding].call #=> i'm method2

См. рабочий пример

person Sergey Fedorov    schedule 30.04.2019
comment
Большое спасибо. Это работает. Я отмечу это как правильный ответ, если ничего лучше не придет. Я бы хотел, чтобы кто-то упомянул об этом в связанном вопросе. - person rahul; 30.04.2019
comment
Я просто сделаю небольшую записку. Crystal, в отличие от Ruby, не может изменять свой код во время выполнения, поскольку код процесса компиляции представляет собой просто инструкции низкого уровня. При запуске Ruby send может найти в иерархии классов требуемый метод и вызвать его. Кристаллический код не имеет классов, методов или других знакомых нам объектов, вызывать просто нечего. - person Sergey Fedorov; 30.04.2019
comment
Но в Crystal есть замечательные макросы, которые позволяют эмулировать многие привычные нам вещи в интерпретируемых языках. Например, Crystal может находить переменные экземпляра и делать с ними что угодно. Эта статья помогла мне понять концепцию: github.com/crystal-lang/crystal / wiki / Справка по метапрограммированию - person Sergey Fedorov; 30.04.2019
comment
Примечание относительно конкретного варианта использования: распространенной идиомой для реализации настраиваемого пользовательского ввода, такого как привязки клавиш, является использование сопоставления ключа с внутренним идентификатором (например, "ctrl+c" => "clipboard.copy"). Эти внутренние идентификаторы могут быть жестко закодированы в программе (например, использоваться в switch), в то время как их сопоставления могут быть изменены. - person Johannes Müller; 01.05.2019
comment
Предложение @ JohannesMüller звучит как жестко запрограммированный пример, который я вставил в свой вопрос. Верно, Йоханнес? - person rahul; 01.05.2019