Ruby имеет синтаксически облегченную поддержку буквальных анонимных процедур (в Ruby они называются blocks ).Поэтому для этого не требуется новая языковая функция.
(В общем, это плохой знак, если вам нужно добавить языковые функции. Вы должны иметь возможность реализовать все в библиотеке, иначеэто признак плохого языкового дизайна.)
Итак, вы обычно пишете метод, который принимает блок кода, выделяет ресурс, выполняет блок кода в контексте этого ресурса.и затем закрывает ресурс.
Примерно так:
def with(klass, *args)
yield r = klass.open(*args)
ensure
r.close
end
Вы можете использовать его следующим образом:
with File, 'temp.txt', 'w' do |f|
f.write 'hi'
raise 'spitespite'
end
Однако это очень процедурный способсделай это.Ruby является объектно-ориентированным языком, что означает, что ответственность за правильное выполнение блока кода в контексте File
должна принадлежать классу File
:
File.open 'temp.txt', 'w' do |f|
f.write 'hi'
raise 'spitespite'
end
Это может быть реализованопримерно так:
def File.open(*args)
f = new(*args)
return f unless block_given?
yield f
ensure
f.close if block_given?
end
Это общий шаблон, который реализуется множеством классов в базовой библиотеке Ruby, стандартных библиотеках и сторонних библиотеках.
ЕщеТочное соответствие с общим протоколом диспетчера контекста Python:
def with(ctx)
yield ctx.setup
ensure
ctx.teardown
end
class File
def setup; self end
alias_method :teardown, :close
end
with File.open('temp.txt', 'w') do |f|
f.write 'hi'
raise 'spitespite'
end
Обратите внимание, что это практически неотличимо от примера Python, но не требует добавления нового синтаксиса к языку.