Ruby 2.0, что нас ждет?

25/10/2012

2 ноября вышла первая версия Ruby 2.0. По плану, 24 февряля 2013 года выйдет 2.0.0-p0, что значит — релиз, но пока не для продакшна.

Даты выхода

  • Начало декабря: 2.0.0-preview2
  • После нового года: 2.0.0-rc1
  • Начало февраля: 2.0.0-rc2
  • 24 февраля: 2.0.0-p0

Новое в 2.0.0

Refinements

Давайте рассмотрим следующий кусок кода:

module NumberQuery
  refine String do
    def number?
      match(/^[1-9][0-9]+$/) ? true : false
    end
  end
end

И попробуем вызвать его:

begin
  "123".number?
rescue => e
  p e  #=> #<NoMethodError: undefined method `number?' for "123":String>
end

Этот метод недоступен в глобальном пространстве, но его можно использовать внутри модуля NumberQuery:

module NumberQuery
  p "123".number?  # => true
end

Так-же этот метод можно добавить в другой модуль:

module MyApp
  using NumberQuery

  p "123".number?  # => true
  p "foo".number?  # => false
end

Keyword arguments

Новая фича простая, но очень удобная, это как новые хеши в 1.9, к которым я до сих пор не могу привыкнуть и использую старый вид :)

def wrap(string, before: "<", after: ">")
  "#{before}#{string}#{after}" # в теле как переменная,
                               # в параметрах как хеш
end

# опциональное использование
p wrap("foo")                                  # => "<foo>"
# один или другой
p wrap("foo", before: "#<")                    # => "#<foo>"
p wrap("foo", after: "]")                      # => "<foo]"
# порядок не важен
p wrap("foo", after: "]", before: "[")         # => "[foo]"

# две звезды для захвата всех аргументов
# или использование аргументов в виде хеша
def capture(**opts)
  opts
end
p capture(foo: "bar")                          # => {:foo=>"bar"}

# ключи можно использовать как символы
opts = {:before => "(", :after => ")"}
p wrap("foo", **opts)                          # => "(foo)"

# можно использовать старый вид хешей
p wrap("foo", :before => "{", :after => "}")   # => "{foo}"

Module#prepend

Тоже очень полезное нововведение, комментарии и объяснения излишне.

module A
  def foo
    "A"
  end
end
class B
  include A

  def foo
    "B"
  end
end

p B.new.foo   # => "B"
class C
  prepend A

  def foo
    "B"
  end
end

p C.new.foo   # => "A"

Converting convention to Hash: #to_h

def foo(opts)
  raise ArgumentError, "opts must be a Hash" unless opts.is_a?(Hash)
  # do stuff with opts
end

Теперь можно добавить универсальности:

def foo(options)
  if options.respond_to?(:to_h)
    opts = options.to_h
  else
    raise TypeError, "can't convert #{options.inspect} into Hash"
  end
  # do stuff with opts
end

%i: a literal for symbol array

p %i{hurray huzzah whoop}   # => [:hurray, :huzzah, :whoop]

Установка и тестирование новой версии (ruby-2.0.0-preview1)

Этот кусок статьи не мой, его я нагло позаимствовал у Александрова Игоря :)

Железо:

  • OS: OSX 10.8.2
  • CPU: 2.2GHz i7
  • RAM: 8Gb 1333 MHz DDR3
  • HHD: Seagate Momentus XT, 2.5”, SATA 3Gb/s, 7200 rpm, hybrid

Набор тестов.

Установка:

$ export CC=clang # http://bugs.ruby-lang.org/issues/7264
$ rvm install ruby-2.0.0-preview1

Результаты тестирования:

chart