Статьи

Как справиться с блоками II

В прошлой статье у нас был тур остановки блоков свистка. Как они определены, для каких целей они служат и чем отличаются различные версии Ruby. Все было очень академично. Но практически какую пользу мы действительно получаем от блоков. Что делает их таким мощным инструментом для разработчиков Ruby.

Процы и лямбды

Прежде чем мы перейдем к некоторым полезным примерам блоков, мы должны обсудить Proclambda Эти два позволяют вам определить блок для последующего использования с помощью метода 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

В приведенном выше примере мы определяем метод discountProc Код не выполняется (ну, ничего не возвращается), все что мы сделали, это настроили небольшое окружение, которое снимает процент). Мы устанавливаем две скидки и звоним им на значения 100 и 60 с помощью call Теперь вы знаете, что метод discountlambda

 def discount( rate )
  lambda { |n| n - ( n * rate ) }
end

Почему два способа определить процесс?

Proclambda Из предыдущего примера мы видим, что блок принимает параметр nlambda

 ten_percent_off.call(10, "This should not be here")
# => ArgumentError: wrong number of arguments (2 for 1)

Proc Точно так же lambdaProcnil Похоже, ProcProc.newlambda Что ж, в 90% случаев мне нравится, когда выполняются условия оплаты (количество параметров), и возникает ужасная ошибка, если я что-то делаю не так. Если эта причина кажется слабой, то мы можем рассмотреть, как Proclambdareturn

 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

Как видно, Proclambda Я не говорю «выбирай одно и никогда не используй другое», это далеко не так. Знание значения обоих просто позволяет нам использовать правильное определение, когда это уместно. Тем не менее я использую 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_evalAddressLabel Оба метода создания метки делают одно и то же, только с использованием блочного формата более сексуально и делает его более естественным для чтения. Без сомнения, вы уже видели этот тип интерфейса во многих доступных драгоценных камнях.

Настройка и снос

Другим распространенным использованием блоков является предварительная и последующая обработка. Наиболее распространенный пример в Интернете — это, вероятно, стандартная библиотека 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.