Я бы хотел заменить реализацию метода для объекта блоком, который указывает пользователь.В JavaScript это легко сделать:
function Foo() {
this.bar = function(x) { console.log(x) }
}
foo = new Foo()
foo.bar("baz")
foo.bar = function(x) { console.error(x) }
foo.bar("baz")
В C # это также довольно просто
class Foo
{
public Action<string> Bar { get; set; }
public Foo()
{
Bar = x => Console.WriteLine(x);
}
}
var foo = Foo.new();
foo.Bar("baz");
foo.Bar = x => Console.Error.WriteLine(x);
foo.Bar("baz");
Но как я могу сделать то же самое в Ruby?У меня есть решение, которое хранит лямбду в переменной экземпляра, а метод вызывает лямбду, но мне не очень нравятся накладные расходы и синтаксис
class Foo
def initialize
@bar = lambda {|x| puts x}
end
def bar x
@bar.call x
end
def bar= blk
@bar = blk
end
end
foo = Foo.new
foo.bar "baz"
foo.bar= lambda {|x| puts "*" + x.to_s}
foo.bar "baz"
Мне бы хотелось иметь такой синтаксис:
foo.bar do |x|
puts "*" + x.to_s
end
foo.bar "baz"
Я придумал следующий код
class Foo
def bar x = nil, &blk
if (block_given?)
@bar = blk
elsif (@bar.nil?)
puts x
else
@bar.call x
end
end
end
Но это несколько уродливо для более чем одного параметра и все еще не кажется «правильным».Я также мог бы определить метод set_bar, но мне это тоже не нравится:).
class Foo
def bar x
if (@bar.nil?)
puts x
else
@bar.call x
end
end
def set_bar &blk
@bar = blk
end
end
Поэтому вопрос таков: есть ли лучший способ сделать это, и если нет, каким способом вы бы предпочли
Редактировать: подход @ welldan97 работает, но я теряю область видимости локальной переменной, т.е.
prefix = "*"
def foo.bar x
puts prefix + x.to_s
end
не работает.Я полагаю, я должен придерживаться лямбда, чтобы это работало?