LINUX.ORG.RU

Ruby: опять макросы


0

3

Есть в программе некий if, типа

(print a; x+=1) if (aaa=1 and bbb=2 and ccc=3) or (sss=1 and fff=2)

Хочется передавать в программу через ком.строку одно понятное слово, чтобы внутри программы ему сопоставлялось определённое условие под этим if. В чём затык - условие это может содержать в себе самое разное количество переменных и их сочетаний. Может (a and b), может (z or x and t) как угодно. Сюда просятся макросы. Которых в Ruby нет. Придумывается писать лесенку case и по сути N экземпляров программы, но это маразм. Как такие вещи делают по уму?

★★★★★

Последнее исправление: yu-boot (всего исправлений: 1)

Не очень понял проблему, но почему не:

..abc
check = {
  firstCondition => lambda { a and b and c },
  second         => lam...
}
if check[ARGV].call bla bla
С ruby не на ты, поэтому синтакс косяки, но суть в этом.

anonymous
()
h = Hash.new
h["понятное слово 1"] = lambda { (aaa=1 and bbb=2 and ccc=3) or (sss=1 and fff=2) }
h["понятное слово 2"] = lambda { to(:be) or (not to(:be)) }
...
(print a; x += 1) if h[word].call

не?

korvin_ ★★★★★
()
Ответ на: комментарий от korvin_

Спасибо. Не знал, что так можно.

Несколько неудобно, что на момент объявления этой «лямбды» все задействованные переменные должны уже существовать, но и так хорошо.

yu-boot ★★★★★
() автор топика
Ответ на: комментарий от yu-boot

Можно же передавать параметры. Только с их числом не знаю как.

a = lamda {|a, b, c| a and b and c}
a.call true true false
В perl с этим попроще.
my $a = sub { "sup " + $_[0] };
$a->("/b/")

anonymous
()
Ответ на: комментарий от yu-boot

Несколько неудобно, что на момент объявления этой «лямбды» все задействованные переменные должны уже существовать

Не обязательно. Можно обойти эту проблему таким «костылём»:

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

class Proc
  def bind(context)
    p = self
    ->(*args) do
      Class.new do
        def initialize(context)
          @context = context
        end

        def method_missing(m)
          eval m.to_s, @context
        end

        def run(p, *args)
          instance_exec *args, &p
        end
      end.new(context).run p, *args
    end
  end
end

conditions = {}
conditions["hello"] = ->{ world }
conditions["answer"] = ->{ answer }

answer = 42

puts conditions["answer"].bind(binding).call

theNamelessOne ★★★★★
()
Ответ на: комментарий от yu-boot

все задействованные переменные должны уже существовать

Еще можно переменные экземпляра или методы:

l = lambda { @a==1 and b==2}
@a = 1
def b; 2; end
l.call

Но там неиницилизированные переменные экземпляра будут nil. Можно сделать метод, который возвращает хеш или структуру, откуда доставать значения.

dr_jumba
()
Ответ на: комментарий от anonymous

Можно передавать *args, если хочется переменное количество аргументов.

S-Mage ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.