Статьи

Новые методы в Ruby 2.2

Векторная иллюстрация темно-красного щита с ruby ​​программирования Lan

Большая часть фанфар вокруг Ruby 2.2 была посвящена обновлениям сборки мусора (GC). GC теперь будет очищать символы и имеет новый инкрементный алгоритм, который сокращает время паузы. Эти изменения очень интересны, но были добавлены и новые методы. Посмотрим, какие еще новые игрушки поставлены 2.2.

Связывание # local_variables

Если вы когда-нибудь хотели узнать локальные переменные, определенные в области видимости, у меня есть метод для вас. Вставьте это куда угодно и узнайте, какие переменные используются:

def addition(x, y) puts binding.local_variables.inspect z = x + y puts binding.local_variables.inspect z end > addition(2, 3) [😡, :y, :z] [😡, :y, :z] 5 

Binding # приемник

Может быть, вы не заботитесь о местных переменах. Вы хотите знать, какой объект получает вызов метода?

 class Cat def self.type binding.receiver end end > Cat.type Cat class Tiger < Cat end > Tiger.type Tiger 

Большинство из нас напрямую не имеют дело с привязками, но если вы занимаетесь жизнью, вам стало немного легче.

Dir # fileno

Получение дескриптора файла для объекта IO не является чем-то новым. Теперь вы можете получить его и для каталога. Файловые дескрипторы — это способ ссылки на определенный открытый файл, каталог и т. Д. Вы, вероятно, использовали их раньше, даже не осознавая этого. В системах POSIX 0, 1 и 2 зарезервированы для стандартного входа, стандартного выхода и стандартной ошибки соответственно.
Вы когда-нибудь использовали что-то вроде 2>&1 в командной строке? Вы ссылались на дескрипторы файлов.

 > $stdout.fileno 1 > Dir.new('.').fileno 8 

Имейте в виду, этот новый метод доступен только в системах POSIX. Если вы попытаетесь вызвать его в Windows, он NotImplementedError .

Перечислимых # slice_after

Этот метод является дополнением к существующему методу slice_before . Я не сталкивался с slice_before в дикой природе, поэтому мне пришлось посмотреть, как это работает.

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

 > [1, 'a', 2, 'b', 'c', 3, 'd', 'e', 'f'].slice_before { |e| e.is_a?(Integer) }.to_a [[1, "a"], [2, "b", "c"], [3, "d", "e", "f"]] 

В этом случае он делал сокращения перед целыми числами 1 , 2 и 3 .

Аргумент может быть передан вместо блока. Когда это происходит, аргумент проверяется с помощью === (т. Е. Равенство регистра). Мы можем получить тот же результат, что и выше, передав Integer :

 > [1, 'a', 2, 'b', 'c', 3, 'd', 'e', 'f'].slice_before(Integer).to_a [[1, "a"], [2, "b", "c"], [3, "d", "e", "f"]] 

Хотите угадать, что делает slice_after ? Вместо нарезки перед матчем, он нарезает после:

 > [1, 'a', 2, 'b', 'c', 3, 'd', 'e', 'f'].slice_after(Integer).to_a [[1], ["a", 2], ["b", "c", 3], ["d", "e", "f"]] 

Перечислимых # slice_when

Особенно забавным дополнением является slice_when . В отличие от slice_after , этот метод принимает только блок. Он перебирает перечисляемые пары элементов в блок. Когда блок возвращает true , перечислимое разделяется между парой элементов:

 > [1, 3, 4, 5, 7, 8, 9, 10, 12].slice_when { |a, b| a + 1 != b }.to_a [[1], [3, 4, 5], [7, 8, 9, 10], [12]] 

Здесь мы нашли серии последовательных чисел, разрезая их, когда второе число не является первым числом плюс один.

Учитывая массив чисел, вы можете легко узнать, сколько у вас каждого:

 > Array.new(10) { rand(3) + 1 }.sort.slice_when(&:!=).map { |x| [x.first, x.size] } [[1, 4], [2, 4], [3, 2]] 

В этом заезде мы получили 1 четыре раза, 2 четыре раза и 3 раза.

Float # next_float, Float # prev_float

Эти функции возвращают следующее или предыдущее представимое число с плавающей точкой. Обратите внимание на слово « представимое » в этом предложении, не все числа могут быть представлены.

 > 1.0.next_float 1.0000000000000002 

Обратите внимание, как пропустили 1.0000000000000001 ? Он не может быть представлен с помощью Float :

 > 1.0000000000000001 1.0 

Также стоит отметить, что расстояние между двумя шагами не всегда одинаково:

 > 2.0.prev_float 1.9999999999999998 > 2.0.next_float 2.0000000000000004 

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

File.birthtime, File # birthtime, File :: Stat # birthtime

У нас были atime , ctime и mtime чтобы проверить различные времена доступа и изменения, связанные с файлом. До 2.2 у нас не было времени рождения (т.е. времени создания) файла. Вы заметите, что он, как и другие, поставляется в классах и экземплярах:

 > File.new('test', 'w').birthtime 2015-01-06 19:24:44 -0600 > File.birthtime('test') 2015-01-06 19:24:44 -0600 

Также доступно в File::Stat :

 > File::Stat.new('test').birthtime 2015-01-06 19:24:44 -0600 

Само ядро ​​#

Руби вышла и получила метод идентификации. Для тех, кто не знаком, метод идентификации возвращает объект, к которому он обращался:

 > 1.itself 1 

В этот момент вам может быть интересно, где это полезно. Одним из наиболее распространенных примеров является группировка:

 > [2, 3, 3, 1, 2, 3, 3, 1, 1, 2].group_by(&:itself) {2=>[2, 2, 2], 3=>[3, 3, 3, 3], 1=>[1, 1, 1]} 

Он также может быть использован как способ не использовать метод, такой как map или select . В функциональном программировании это может быть хорошим способом избежать того, что в противном случае может быть неудобным условием.

Метод # Карри

Возможно, вы не поняли, что Ruby способен к карри и частичному применению. В прошлом вы могли вызывать curry только на Proc . Эта же сила теперь доступна вам на Method .

 def sum(*args) args.reduce(:+) end > inc = method(:sum).curry(2).(1) #<Proc:0x007ff68ac96728 (lambda)> > inc.(3) 4 

Метод # super_method

Ранее мы нашли объект, получающий метод с binding.receiver . Мы также можем узнать о родителе метода. Вызов super_method возвращает метод, который вы получили бы, если бы вы вызвали super . Если у метода нет родителя, он возвращает nil .

 class Cat def speak 'meow' end end class Tiger < Cat def speak 'roar' end end > Tiger.new.method('speak') #<Method: Tiger#speak> > Tiger.new.method('speak').super_method #<Method: Cat#speak> > Cat.new.method('speak').super_method nil 

String # unicode_normalize, String # unicode_normalize !, String # unicode_normalized?

Знаете ли вы, что в Unicode некоторые символы могут быть представлены несколькими способами? Взять, к примеру, «е» с острым акцентом. Вы можете представить его с помощью канонической композиции (NFC) формы нормализации, используя одну кодовую точку:

 > nfc = "\u{e9}" "é" 

Вы также можете представить его с помощью формы нормализации канонического разложения (NFD), комбинируя две кодовые точки:

 > nfd = "\u{65}\u{301}" "é" 

В этой форме обычное «е» в сочетании с «◌́» создает «é», которое вы видите выше. Хотя эти два могут давать похожий результат, они не одинаковы:

 > nfc == nfd false 

unicode_normalize выполняет преобразование строк из одной формы в другую. По умолчанию он конвертируется в NFC:

 > nfc == nfd.unicode_normalize true 

Вы также можете передать символ, указывающий форму для преобразования в:

 > nfc.unicode_normalize(:nfd) == nfd true 

Эти формы существуют, потому что они имеют ценность в разных ситуациях. Коды NFC короче, но если вы хотите убрать акценты из слова для, скажем, целей поиска, форму NFD будет легче обрабатывать. Хотя NFC и NFD являются наиболее распространенными, вы также можете передать :nfkc и :nfkd если необходимо.

Ударная версия этого делает то, что вы ожидаете, и изменяет строку, получающую сообщение.

Вызов unicode_normalized? проверяет, соответствует ли строка нужной форме. Он принимает тот же аргумент, что и unicode_normalize :

 > nfc.unicode_normalized? true > nfc.unicode_normalized?(:nfd) false 

Время уточнять

Многие из этих методов не каждый день инструменты. Это постепенные улучшения, которые поддерживают язык. За последние несколько лет в Ruby произошли большие изменения. Изменения между 1.8, 1.9 и 2.0 выпусками были монументальными. Теперь язык сфокусирован на уточнении некоторых грубых граней, созданных этим процессом. Фактически, 2.2 позволяет вам создавать ключи символов в кавычках в хешах с конечным двоеточием:

 { 'programming-language': :ruby } 

Больше не должно быть хэшей с символьными ключами с добавленной случайной ракетой из-за дефисного атрибута HTML. Я думаю, это то, что мы все можем отстать.