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_h
Not 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
%i
Like %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_h
Hash
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_h
Hash#to_h
NilClass#to_h
Struct#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_h
JSON::Ext::Generator::State
XMLRPC::FaultException
OpenSSL::X509::Extension
to_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#prepend
Replacement 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'