Действительно крутые возможности в Ruby 1.9 - PullRequest
23 голосов
/ 27 октября 2009

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

Ответы [ 16 ]

31 голосов
/ 29 октября 2009

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

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

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

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

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

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

16 голосов
/ 27 октября 2009

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

13 голосов
/ 27 октября 2009

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

["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 аргумента index, взятого из each_with_index.

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

11 голосов
/ 27 октября 2009

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

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

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

Темы также различны:

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

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

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

10 голосов
/ 27 октября 2009

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

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

С помощью перечислителей я могу захватить первый пакет, сохранить исходные данные как свою «авторитетную» коллекцию, обработать и выдать каждый объект Ruby , когда я войду в него . Когда я передаю последний элемент, если я знаю, что из источника нужно извлечь больше данных, я могу сделать следующий вызов API. (То есть, отложенная загрузка.) Это означает гораздо более быстрый возврат при вызове метода извлечения и намного лучшее использование памяти. Каждый объект 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 благодаря бэкпорту. Но 1.9 намного быстрее благодаря внутреннему использованию волокон. И если бы не было 1.9, не было бы 1.8.7, поэтому я решил, что он по-прежнему считается моей любимой 1.9 функцией.

9 голосов
/ 02 ноября 2009

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

9 голосов
/ 31 октября 2009

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

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

6 голосов
/ 28 октября 2009

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

5 голосов
/ 27 октября 2009

Мне нравится 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 гораздо лучше оптимизирована, чем библиотечный подход.

5 голосов
/ 27 октября 2009

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

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

...