Ruby 2.0 Rundown
@benjaminoakes
Ruby 2.0 was released on its birthday, Feb 24th
From a developer's perspective:
Things I like:
__dir__%i / %I
to_hNot ready for prodution use, yet.
Object are now privateThese problems will shake out over time.
Some breakage is to be expected.
Many thanks to Mat Sadler for his writeup.
=> __dir__
%i / %I
to_h__dir__If you've ever hated writing File.dirname(__FILE__) over and over, you'll love this
p __dir__
# => "/vagrant"
__dir__=> %i / %I
to_h%iLike %w(), but for symbols.
p %i(panda bamboo)
# => [:panda, :bamboo]
Seems roughly the same as:
p %w(panda bamboo).map { |s| s.intern }
# => [:panda, :bamboo]
Like normal, be careful when making symbols from user input.
__dir__%i / %I
=> to_h
to_hHash representation of an object.to_s, to_a, and to_sym for the other core types, why not to_h?serializable_hash in Rails.to_h (cont'd)Searching ruby-doc.org core gave:
ENV.to_hHash#to_hNilClass#to_hStruct#to_h...and a handful of aliases called to_hash (from 1.9)
to_h (cont'd)p ENV.to_h # => {"TERM"=>"xterm", "SHELL"=>"/bin/bash", ...}
p {}.to_h # => {}
p nil.to_h # => {}
s = Struct.new(:panda, :bamboo).new
p s.to_h # => {:panda=>nil, :bamboo=>nil}
to_h (cont'd)Searching ruby-doc.org std-lib gave:
OpenStruct#to_hJSON::Ext::Generator::StateXMLRPC::FaultExceptionOpenSSL::X509::Extensionto_h (cont'd)require 'ostruct'
os = OpenStruct.new(panda: 'bamboo')
p os # => #<OpenStruct panda="bamboo">
p os.to_h # => {:panda=>"bamboo"}
to_h (cont'd)to_h (cont'd)This doesn't work:
%w(panda bamboo).to_h
# => NoMethodError: undefined method `to_h'
I might have expected behavior like this:
p Hash['panda', 'bamboo']
# => {"panda"=>"bamboo"}
to_h (cont'd)I screwed that up the first time (nested array Hash[['panda', 'bamboo']]), and got a bunch of new warnings:
# (irb):5: warning: wrong element type String
# at 0 (expected array)
# (irb):5: warning: ignoring wrong elements is
# deprecated, remove them explicitly
# (irb):5: warning: this causes ArgumentError
# in the next release
# [...]
In Ruby 1.9.3, it would print no warnings and return {}.
to_h (cont'd)I also was hoping JSON would take advantage (More info)
require 'json'
p JSON.generate(ENV)
# => /usr/local/lib/ruby/2.0.0/json/common.rb:
# 223:in `generate': only generation of
# JSON objects or arrays allowed
# (JSON::GeneratorError)
# from /usr/local/lib/ruby/2.0.0/json/common.rb:223:
# in `generate'
# from tmp/talk_code.rb:3:in `<main>'
to_h (cont'd)Can do:
require 'json'
p ENV.to_h.to_json
# => "{\"TERM\":\"xterm\",\"SHELL\": ...
to_h (cont'd)Hash[] too, if you've ever done that.to_h (cont'd)Duck typing example:
def eat(diet)
diet.to_h[:eats]
end
panda_diet = { eats: 'bamboo' }
p eat(panda_diet)
# => "bamboo"
to_h (cont'd)Duck typing example:
def eat(diet)
diet.to_h[:eats]
end
panda_diet = Struct.new(:eats).new('bamboo')
p eat(panda_diet)
# => "bamboo"
to_h (cont'd)Duck typing with "coercion" example:
def eat(diet)
# New in 2.0: `Hash(obj)`
#
# Like `Array(obj)` or `String(obj)`
#
# Similar in 1.9: `Hash[diet]`
Hash(diet)[:eats]
end
panda_diet = { eats: 'bamboo' }
p eat(panda_diet)
# => "bamboo"
__dir__%i / %I
to_h=> Keyword argumentsFinally, a built in way to handle what we already do all the time:
some_method(positional_arg, panda: 'bamboo')
# Ruby < 2.0 idiom
def some_method(positional_arg, opts)
panda = opts[:panda] || 'bamboo'
# ...
end
# Ruby 2.0
def some_method(positional_arg, panda: 'bamboo')
# ...
end
2 ways of defining
# As keywords
def keywords(positional, panda: 'bamboo', place: 'Earth')
p positional
p panda
p place
end
keywords('foo', panda: 'kung fu')
# =>
# "foo"
# "kung fu"
# "Earth"
# As keywords
def keywords(positional, panda: 'bamboo', place: 'Earth')
p positional
p panda
p place
end
# 1.8 style hashes accepted
keywords('eats', :panda => 'shoots and leaves')
# =>
# "eats"
# "shoots and leaves"
# "Earth"
# As keywords
def keywords(positional, panda: 'bamboo', place: 'Earth')
p positional
p panda
p place
end
# Position doesn't matter
keywords('greeting', place: 'China', panda: 'nom nom nom')
# =>
# "greeting"
# "nom nom nom"
# "China"
# As a capture ("double splat")
#
# Kind of like Python, but better.
#
# Because it's Ruby.
def capture(**kwargs)
p kwargs
end
capture(anything: 'that', I: 'want')
# =>
# {:anything=>"that", :I=>"want"}
__dir__%i / %I
to_h=> Lazy evaluationEnumerator (Enumerator::Lazy)Panda.where(...) doesn't retreive a result until needed)From the docs:
# See Kernel#to_enum for the definition of repeat
require_relative './repeat'
r = 1..Float::INFINITY
r.repeat(2).first(5) # => [1, 1, 2, 2, 3]
r.repeat(2).class # => Enumerator
# r.repeat(2).map { |n| n ** 2 }.first(5) # => endless loop!
# works naturally on lazy enumerator:
r.lazy.repeat(2).class # => Enumerator::Lazy
r.lazy.repeat(2).map { |n| n ** 2 }.first(5) # => [1, 1, 4, 4, 9]
There's a lot of changes, but those are some that I like.
Kernel#require performance improvementsFloat operation performance improvementsModule#prepend./configure && make && sudo make install)rvm or rbenv
rvm pkg install openssl firstThese were very useful when preparing this.
Module#prependReplacement for alias_method_chain hackery.
Module#include examplemodule Diet
def eats; 'bamboo'; end
end
class Panda
include Diet
def eats; 'shoots and leaves'; end
end
p Panda.new.eats # => 'shoots and leaves'
Module#prepend examplemodule Diet
def eats; 'bamboo'; end
end
class Panda
prepend Diet # <-------
def eats; 'shoots and leaves'; end
end
p Panda.new.eats # => 'bamboo'