Подтвердить что ты не робот

Действительно интересные функции в Ruby 1.9

С выпуском Ruby 1.9.2 на горизонте настало время привлечь разработчиков к Ruby 1.9. Какие интересные вещи вы можете сделать в Ruby 1.9, которые вы не можете сделать в Ruby 1.8?

4b9b3361

Ответ 1

Я не могу поверить, что об этом еще не упоминалось: самая большая особенность Ruby 1.9.2+ заключается в том, что впервые за 17 лет Ruby будет иметь спецификацию.

Возможно, вы слышали, что все расписания релизов для Ruby 1.9.2 (который должен был быть выпущен в Spring 2010 года) был отменен, и вот почему: во-первых, полная версия Ruby 1.9.2 будет разработана в проекте RubySpec, тогда будет выпущен Ruby 1.9.2 (язык программирования), и только тогда YARV 1.9.2 освобождается после прохождения теста RubySpec.

Это точно в обратном направлении от того, как он работал до: первая MRI была выпущена, затем все другие разработчики читали (не очень хорошо спроектированный и, как правило, плохо документированный) исходный код C MRI, чтобы попытаться выяснить, что это за черт что новая функция должна была делать, тогда они попытались написать исполняемые спецификации, и только тогда у них даже была отдаленная вероятность реальной совместимости. Но к тому времени, как правило, новая версия YARV уже была выпущена, и цикл начался заново... Не говоря уже о том, что разработчики MRI и YARV даже не запускали RubySpecs.

Это имеет огромные последствия. Например, несмотря на то, что в настоящее время более 10 различных реализаций Ruby находятся в активной разработке, и за годы своего существования было более 30 различных реализаций языка программирования Ruby, этот факт не был подтвержден сопровождающими языка программирования Ruby. Для них Ruby и MRI (или совсем недавно Ruby и YARV) всегда были одним и тем же: MRI был и языком, и механизмом выполнения, Ruby был и механизмом исполнения, и языком. "Спецификация" языка программирования Ruby была исходным кодом C MRI.

Как и пять недель назад, это изменилось: теперь официальная спецификация языка программирования Ruby (по крайней мере, версия 1.9.2 и новее) является исполняемым testuite проекта RubySpec. И YARV - это еще одна реализация Ruby, полностью равная MacRuby, IronRuby, JRuby, Cardinal, tinyrb, SmallRuby, BlueRuby, MagLev и остальным.

Это означает, что так называемые "альтернативные" реализации (которые на данный момент больше не называются "альтернативными", потому что YARV потерял свой особый статус) теперь имеют шанс фактически догнать новейшие языковые функции, реализованные в YARV. Фактически, поскольку большинство других реализаций на самом деле оба гораздо лучше разработаны и реализованы на гораздо лучших языках, чем YARV (что в основном представляет собой огромный спагетти-код C), плюс наличие большей рабочей силы, вполне вероятно, что другие реализации на самом деле будут Ruby 1.9.2 соответствует YARV.

Ответ 2

Мне лично нравится новый синтаксис хэша: {:a => 1} становится {a:1}

Ответ 3

Перечислители.

["a", "b", "c"].map {|elem, i| "#{elem} - #{i}" }
# => ["a - ", "b - ", "c - "]
["a", "b", "c"].each_with_index.map {|elem, i| "#{elem} - #{i}" }
# => ["a - 1", "b - 2", "c - 3"]

Enumerable возвращает экземпляр Enumerator, когда ему не передается блок. В этом случае он использовал аргумент map an index, взятый из each_with_index.

Это также было передано в 1.8.7.

Ответ 4

Ruby 1.9 имеет разные блок поведения:

  • Параметры блока всегда локальны для их блока, а вызовы блока никогда не присваивают значения существующим переменным:

  • Синтаксис блока расширен, что позволяет объявлять локально-локальные переменные, которые гарантированно являются локальными, даже если переменная с тем же именем уже существует в охватывающей области.

Темы также отличаются:

  • Ruby 1.8 использует только один собственный поток и запускает все потоки Ruby внутри одного собственного потока. Это означает, что потоки очень легкие, но они никогда не работают параллельно.

  • Ruby 1.9 отличается, он выделяет собственный поток для каждого потока Ruby. Но поскольку некоторые библиотеки C не сами по себе не являются потокобезопасными, Ruby очень консервативен и никогда не позволяет запускать одновременно один из своих собственных потоков (это ограничение может быть смягчено в последующих выпусках)

Другим незначительным изменением является включение RubyGems в путь загрузки, больше не нужно require "rubygems".

Ответ 5

Мне очень нравится Enumerators - не только для существующих типов, но и для написания моих собственных коллекций как классов Enumerator. Начиная с перехода на 1.9, я дважды должен был создавать API-адаптеры для внешних веб-сервисов, которые вытягивают большие массивы результатов JSON или XML. Иногда я мог бы ограничить количество записей, которые мог получить сразу, а это значит, что мне нужно будет выполнить несколько запросов. (Получите первые 500, затем получите записи от 501 до 1000 и т.д.).

"Старый" способ, с помощью которого я бы обработал это, состоял в том, чтобы захватить первую партию, перебрать ее все с помощью .each или .collect и создать массив равных размеров объектов Ruby. Если бы я не смог получить все записи в одном запросе, я бы также запрограммировал запросы API, добавляя к массиву каждый раз. Это означает, что все время загружено спереди, воспринимается как медленное извлечение, и я пережевываю много из памяти: для исходных данных, для равного количества объектов Ruby, а иногда и для операции промежуточного массива. Это бесполезно, когда я, вероятно, работаю только по одному объекту за раз.

С помощью Enumerators я могу захватить первую партию, сохранить исходные данные в качестве моей "авторитетной" коллекции и обработать и предоставить каждый объект Ruby, когда я в него вхожу. Когда я передаю последний элемент, если я знаю, что больше данных вытащить из источника, я могу сделать следующий вызов API тогда. (1.e., lazy loading.) Это означает гораздо более быстрый возврат вызова метода поиска и намного лучшее использование памяти. Каждый объект Ruby имеет право на сбор мусора, как только я закончил с ним, и перешел к следующему.

Абстрактная реализация идеи выглядит следующим образом:

class ThingyCollection < Enumerator
  attr_reader :total

  # Returns a new collection of thingies.
  def initialize(options={})

    # Make the request for the first batch
    response = ThingyAPIClient.get_thingies(options)
    @total = response.total   # Number of ALL thingies, not just first batch
    records = response.data  # Some array of JSON/XML/etc. from the API 

    # Create a closure which serves as our enumerator code
    enum = Proc.new do |yielder|
      counter = 0              # Initialize our iterator
      while counter < @total

        # If we're at the end of this batch, get more records
        if counter == records.length  
          more = ThingyAPIClient.get_next_thingies(counter, options)
          records += more.data
        end

        # Return a Ruby object for the current record 
        yielder.yield Thingy.new(records[counter])   
        counter += 1
      end
    end

    # Pass that closure to the Enumerator class
    super(&enum)
  end
end

Как только вы это сделаете, вы можете пройти через них, как:

thingies = ThingyCollection.new(foo: bar) # Whatever search options are relevant
puts "Our first thingy is #{thingies.next}"
puts "Our second thingy is #{thingies.next}"
thingies.rewind
thingies.each do |thingy|
  do_stuff(thingy)
end

Что вы теряете? В основном, способность легко перейти к определенному элементу по ссылке. (Это означает, что вы также теряете "последние", сортировки и т.д.). Просто получение .next и несколько вариантов .each не так богаты, как функции массива, но для моих наиболее распространенных случаев использования все, что мне нужно.

Да, вы можете сделать это с помощью Ruby 1.8.7 благодаря backporting. Но 1,9 намного быстрее, благодаря внутреннему использованию волокон. И если бы это было не для 1,9, то не было бы 1,8,7, поэтому я решил, что он по-прежнему считается моей любимой функцией 1.9.

Ответ 6

Ruby 1.9.2 поддерживает получение информации о параметрах метода. Вы можете получить имя параметров и информацию о них, такую ​​как необязательный, обязательный или блокирующий.

Просмотрите параметр # параметра для примера.

Ответ 7

Хеши упорядочены в рубине 1.9. Это очень полезно при реализации некоторых алгоритмов. Вы должны зависеть от драгоценного камня или написать свой собственный заказный хэш в рубине 1.8.

Ответ 8

Полная встроенная поддержка многобайтовых кодировок символов, особенно Unicode.

Ответ 9

instance_exec и class_exec - отличные новые функции, но для меня это в основном небольшие изменения (которые уже были переданы в 1.8.7). Вещи, подобные владельцу метода #, велики - когда-либо задавались вопросом, где именно в цепочке наследования определен конкретный метод? my_object.method(: blah).owner скажет вам:)

Другими вещами, которые мне нравятся примерно 1.9, являются более согласованные правила охвата esp. в контекстах. Было глупое упущение (IMO), что константы и переменные класса не были просмотрены в instance_eval, 1.9 исправляет это:)

Ответ 10

Мне нравится Symbol#to_proc, что избавляет вас от необходимости писать лямбду каждый раз, когда вы используете функцию более высокого порядка. Поэтому, суммируя массив, который был arr.inject(0) {|memo, val| memo + val}, теперь вы можете просто написать arr.inject(&:+), а не houses.collect {|house| house.price}, вы можете написать houses.collect(&:price).

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

Ответ 11

О, и: это более чем в два раза быстрее. Быстрее, если вы создаете многопоточное приложение с большим количеством задержек ввода-вывода. Со всеми работами, которые по-прежнему пытаются повысить производительность 1,8 или исправить ее потоки и т.д., Меня удивляет, что люди больше не волнуются о скорости 1.9 или ее собственных потоках.

Ответ 12

YARV. Новая Ruby VM в версии 1.9 предлагает новую современную виртуальную машину, которая значительно быстрее.

Ответ 13

Улучшена поддержка регулярных выражений. Ruby 1.9 поддерживает названные группы regex - среди многих других улучшений, которые вы можете вспомнить позже в своем регулярном выражении. Дэйв Томас дает отличный пример.

Ответ 15

Лучшая поддержка Unicode и лучшая потоковая передача.


Поддержка Unicode в версии 1.8 осуществляется через дополнительные драгоценные камни и не вызвала у меня никакой боли - будет здорово получить полную языковую поддержку для этого. Некоторые люди жаловались на сложность реализации, но я думаю, что они никогда не использовали ICU в С++!

Кроме того, возможность сделать "Hello"[3] и получить символ будет приятным.


Улучшения производительности

Некоторые тесты показали значительные улучшения по сравнению с 1.8.6, с 1,9,1 - благодаря новой VM (YARV) в Matz Ruby


Много аккуратных функций...

Если у вас есть копия Dave Thomas "Programming Ruby" (AKA The Pick-ax book), раздел о встроенных классах и методах делает достойную работу по пометке изменений с 1,8 до 1,9

Как насчет:

(a) новый синтаксис хэша: {: hello = > "world" } можно сократить до {: hello: "world" }

(b) упорядоченные хеши!

Ответ 16

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

Например:

@results = Clients
  .from_category(current_category)
  .selected_by(current_user.id)
  .activated
  .order("created ASC")
  .limit(1000)
  .map{ |e| "#{e.id} - {e.fullname}" }