Ruby: выход из встроенного блока

Обновлять

Игнорируйте следующее. Оказалось, что это ошибка, ограниченная Macruby 0.10 и, вероятно, специфичная для моей установки. Я покину пост на случай, если кто-то еще столкнется с проблемой.


Кажется, я что-то неправильно понял о рубиновых блоках. Я хотел использовать find модуля Pathname или Find для поиска определенного файла в определенном дереве каталогов. Однако я не могу заставить блок, предоставленный find, возвращать какое-либо значение.

Поскольку это:

n= (1..10).each {|i| break i if i > 5} 
puts "n = #{n}" #=> n=6

... работает (и является общей конструкцией) Я ожидал, что либо:

starting_directory= #... a directory path
file_name_I_want_to_find= #... a file name e.g. my_file.txt
pd=Pathname.new(starting_directory)
path=pd.find{|p| break p if p.basename.to_s==file_name_I_want_to_find } 
puts "path = #{path}" #=> path = 

... or:

path=Find.find(starting_directory) {|p| break p if p.include?(file_name_I_want_to_find) } 
puts "path = #{path}" #=> path = 

... будет производить только один искомый путь, но ни один из них не дает никакого значения.

Я знаю, что мой тест работает, потому что оба из следующих:

pd.find{|p| puts p if p.basename.to_s==file_name_I_want_to_find } 
#=> /path/to/file_name_I_want_to_find

Find.find(starting_directory) {|p| puts p if p.include?(file_name_I_want_to_find) } 
#=> /path/to/file_name_I_want_to_find

... работают как положено.

Почему break с find не работает так, как в первом примере?

В более общем плане, использую ли я правильную рубиновую технику/идиому для этого обстоятельства?


person TechZen    schedule 25.05.2011    source источник
comment
у меня работает на ruby ​​1.8.7 и 1.9.2 на windows.   -  person Vasiliy Ermolovich    schedule 25.05.2011
comment
взлом работает и на ruby-1.8.7-p334 на OSX для меня.   -  person xinit    schedule 25.05.2011
comment
@xinit - Спасибо, я не подумал проверить наличие проблемы с рубиновой версией. Я запускал скрипт под macruby, и macruby, похоже, был причиной. Если вы откроете вопрос, я приму его.   -  person TechZen    schedule 26.05.2011
comment
вы можете закрыть свой вопрос, если хотите.   -  person edgerunner    schedule 26.05.2011
comment
@edgerunner -- мог бы, но я хотел, чтобы xinit получил заслуженную репутацию.   -  person TechZen    schedule 26.05.2011


Ответы (2)


Кажется, что использование break работает на ruby-1.8.7-p334 (MRI) на OSX, а также на JRuby-1.6.1.

person xinit    schedule 25.05.2011
comment
Оказывается, это ошибка только с Macruby 0.10, - person TechZen; 26.05.2011

Enumerable#find завершит свой собственный цикл, когда блок вернет «не ложь», поэтому:

pd.find { |p| p.basename.to_s == file_name_I_want_to_find }

Независимо от того, работает ли ваша конструкция на самом деле или нет (кажется), вы на самом деле не знаете, какой метод в конечном итоге передал управление блоку, поэтому я думаю, что может быть сложно использовать разрыв и продолжать принудительное поведение основных элементов API. Я подозреваю, что их использование в качестве выражений потока управления блоком предназначено в основном для реализации, а не для границ API.

Итак, "нет" - не лучшая идиома Ruby. Вы должны использовать API напрямую. Все, что вы пытаетесь сделать, имеет прямую реализацию основного API (и своего рода функционала) без создания собственной императивной реализации.

person DigitalRoss    schedule 25.05.2011