В прошлой статье у нас был тур остановки блоков свистка. Как они определены, для каких целей они служат и чем отличаются различные версии Ruby. Все было очень академично. Но практически какую пользу мы действительно получаем от блоков. Что делает их таким мощным инструментом для разработчиков Ruby.
Процы и лямбды
Прежде чем мы перейдем к некоторым полезным примерам блоков, мы должны обсудить Proc
lambda
Эти два позволяют вам определить блок для последующего использования с помощью метода call
Эти «вызываемые объекты» предназначены для использования в процессе исполнения наших приложений. Чтобы понять суть дела, нам нужен пример. На ум приходит все, что связано с деньгами, курсами валют, тарифами для разных клиентов, скидками и так далее.
def discount( rate )
Proc.new { |n| n - ( n * rate ) }
end
ten_percent_off = discount(0.1)
twenty_percent_off = discount(0.2)
ten_percent_off.call(100) # => 90.0
twenty_percent_off.call(60) # => 48.0
В приведенном выше примере мы определяем метод discount
Proc
Код не выполняется (ну, ничего не возвращается), все что мы сделали, это настроили небольшое окружение, которое снимает процент). Мы устанавливаем две скидки и звоним им на значения 100 и 60 с помощью call
Теперь вы знаете, что метод discount
lambda
def discount( rate )
lambda { |n| n - ( n * rate ) }
end
Почему два способа определить процесс?
Proc
lambda
Из предыдущего примера мы видим, что блок принимает параметр n
lambda
ten_percent_off.call(10, "This should not be here")
# => ArgumentError: wrong number of arguments (2 for 1)
Proc
Точно так же lambda
Proc
nil
Похоже, Proc
Proc.new
lambda
Что ж, в 90% случаев мне нравится, когда выполняются условия оплаты (количество параметров), и возникает ужасная ошибка, если я что-то делаю не так. Если эта причина кажется слабой, то мы можем рассмотреть, как Proc
lambda
return
def hello_me
hiya = Proc.new { return "Hiya" }
hiya.call
puts "Woe is me, I will never fulfill my purpose"
end
hello_me
#=> Hiya
# Using a lambda
def hello_me
hiya = lambda { return "Hiya" }
hiya.call
puts "Finally I fell like I have contributed"
end
hello_me
Finally I fell like I have contributed
Как видно, Proc
lambda
Я не говорю «выбирай одно и никогда не используй другое», это далеко не так. Знание значения обоих просто позволяет нам использовать правильное определение, когда это уместно. Тем не менее я использую lambda
Практические блоки
Итак, теперь мы хотим посмотреть, как мы можем использовать эти блоки на практике, и это больше, чем просто итерация, к которой мы привыкли.
Упрощение интерфейсов
Первое, что приходит на ум, — это техника, которую я использую на заводских методах. Фабрика — это фрагмент кода, который возвращает объект на основе его входных данных. Хорошим примером будет создание текста для печати этикетки.
class AddressLabel
def initialize
@lines = []
end
def self.generate &block
label = AddressLabel.new
label.instance_eval(&block)
label.print
end
def print
@lines.each do |line|
puts line
end
end
def address(lines)
lines.each do |line|
@lines << line
end
end
end
AddressLabel.generate do
address ["Lets Be Avenue", "Glasgow"]
end
# Another way of creating the same label would be ...
label = AddressLabel.new
label.address ["Lets Be Avenue", "Glasgow"]
label.print
Здесь instance_eval
AddressLabel
Оба метода создания метки делают одно и то же, только с использованием блочного формата более сексуально и делает его более естественным для чтения. Без сомнения, вы уже видели этот тип интерфейса во многих доступных драгоценных камнях.
Настройка и снос
Другим распространенным использованием блоков является предварительная и последующая обработка. Наиболее распространенный пример в Интернете — это, вероятно, стандартная библиотека Ruby для File.open
File.open('testfile', 'w') do |f|
f.write 'Some text'
end
file = File.open('testfile2', 'w')
file.write 'More text'
file.close
Второй пример, вероятно, то, к чему вы привыкнете с PHP, но мы видим, что хорошая реализация блока заботится о том, чтобы закрыть файл позади нас. Вы можете применять этот вид реализации везде, где требуются разборочные действия. Я помню, как писал код php, который создавал PDF-файлы. Код был что-то вроде
try {
$pdf = new PDFlib();
if ($pdf->begin_document("file_name", "") == 0) {
die("Error: " . $pdf->get_errmsg());
}
$pdf->show(“hello world”);
$pdf->end_page_ext(“”);
$pdf->end_document(“”);
} catch (Exception $e) {
exit();
}
Это просто открывает новый файл, пишет некоторый текст и закрывает его снова, есть некоторая очень простая обработка исключений, чтобы выйти из сценария, если что-то пойдет не так. Он никогда не был самым элегантным фрагментом кода. Однако, поскольку у нас есть такие элегантные примеры интерфейсов в стандартной библиотеке Ruby, написание такого кода в Ruby будет выглядеть просто старым «грязным».
Это можно было бы прояснить в PHP (особенно в случае анонимных функций PHP), но инструменты, которые были в нашем распоряжении до PHP5.3, были просто не в состоянии извлечь всю эту работу по открытому / закрытому документу без обертывания PDFlib. библиотека.
Так что насчет настройки? Все, что мы только что обсудили, — это постобработка, поэтому какие преимущества дают блоки при настройке. При создании методов, которые начинают использовать много условной логики для определения результата, я смотрю на прохождение блоков.
def more_than_ten_rows? rows
if rows.length > 10
yield rows
end
end
more_than_ten_rows? (1..10).to_a do |row|
puts row
end
Так с этим простым куском кода more_than_ten_rows?
действует как ворота, позволяя блоку работать, когда у нас больше необходимого количества строк. Альтернативы могут состоять в том, чтобы переместить условную логику в представление или представление в логику, используя блок, в котором мы достигли некоторого базового разделения.
Завершение
Я думаю, будет справедливо сказать, что если вы не будете хорошо владеть блоками, изучая Ruby, вы никогда не сможете полностью реализовать свой потенциал. Обычно слышно, что «блоки повсюду», и это правда, так что вы будете скучать по вечеринке, если у вас не будет качественного времени с ними.
Они призваны помочь нам, разработчикам, выполнить код простым и лаконичным способом, используя их, и со временем они станут более естественными, и как только вы доберетесь до этой стадии, вы удивитесь, как вы обходились без них.
Это определенно стоит использовать эквивалент PHP, я никогда не использовал их (хотя у меня было 5.3 в производственной среде), пока я не пришел к написанию этой статьи, синтаксис более многословен, чем Ruby, но, эй, это довольно приличный компромисс и Я полностью верю, что понимание этого относительно нового дополнения в PHP поможет вам понять основные принципы Ruby.