You are on page 1of 35

Migrating to

Ruby 1.9

Bruce Williams
Bruce Williams
Perpetrator of much random Ruby hackery, language tourist

Rubyist since 2001 (Full-time since 2005)

Open source developer, contributer, technical editor, designer


Occasionally blogs at http://codefluency.com
Ruby 1.8 Ruby 1.9
Stable. Unstable, transitional.
The syntax and language Many new syntax and
features you know and language features.
probably love.
Better performance,
The performance profile especially for computationally
you know and might hate intensive operations.
a little.
1.9 is a hint.
1.9 is a hint.
Get ready for 2.0.
Ruby’s Releases
From Toybox to Toolshed
(dev)
(dev) 1.7 (dev)
1.5 1.6.1 1.6.3 1.6.5 1.8.1 1.8.4 1.9
1.6.0 1.6.2 1.6.4 1.6.7 1.6.8 1.8.0 1.8.2 1.8.3 1.8.5 1.8.6

‘00 ‘01 ‘02 ‘03 ‘04 ‘05 ‘06 ‘07 ‘08

Japan Beyond Japan “... on Rails” Expansion


Standard Library
rubygems (+ prelude & ruby --disable-gems), rake, json (pure,
+ ext), ripper, probeprofiler, securerandom, HMAC
digests
~ csv replaced by FasterCSV implementation

- soap, wsdl, base64, some rarely used, old libraries


Parser Changes
Flexibility and Obscurity (for the moment)
Parser Changes
New Hash Literal
{a: "foo"}
# => {:a=>"foo"}

{a: "bar", :b => "baz"}


# => {:a=>"bar", :b=>"baz"}
Parser Changes
New Proc Literal
multiply_by_2 = ->(x) { x * 2 }
# => #<Proc:0x3c5a50>

multiply_by_2.(4)
# => 8
Parser Changes
Splat more flexibly

names = %w(joe john bill)


[*names, 'jack']
# => ["joe", "john", "bill", "jack"]
Parser Changes
Method parameter ordering

def say(language=:english, text)


puts Translator[language].translate(text)
end
say "hello"
# hello
say :spanish, "hello"
# hola
Migration Risk Factors

Text processing
“Clever” assignment with blocks
Some Hash enumerations
Metaprogramming, code generation
Tests are Good
I was surprised at how much work my 11th hour integration of the
FasterCSV code was. It was a pure Ruby library that really didn't do
a lot of fancy tricks, but I had to track down about 20 little issues
to get it running under Ruby 1.9. Thank goodness it had terrific test
coverage to lead me to the problem areas.

- James Edward Gray II


Follow-up at http://blog.grayproductions.net/articles/getting_code_ready_for_ruby_19
Block Local Variables
Arguments are always local

Ruby 1.8 Ruby 1.9


item = 1 item = 1
2.upto(4) do |item| 2.upto(4) do |item|
p item p item
end end
# Outputs: # Outputs:
# 2 # 2
# 3 # 3
# 4 # 4
item item
# => 4 # => 1
Shadowing Variables
You’ll get a warning

Ruby 1.8 Ruby 1.9


i = 1 i = 1
lambda { |i| p i }.call(3) lambda { |i| p i }.call(3)
# Outputs # Outputs
# 3 # 3
i i
# => 3 # => 1

-e:2: warning: shadowing outer local variable - i


Shadowing Variables
Locals, but warned

No local, reassigns Local, shadowed


d = 2 d = 2
-> { d = 1 }.() ->(;d) { d = 1 }.()
d d
# => 1 # => 2
(Ruby 1.9) -e:2: warning: shadowing outer local variable - d
Hash#select (etc)
Changes to yielded arguments

Ruby 1.8 Ruby 1.9


conferences.select do |data| conferences.select do |data|
p data p data
end end
# [:euruko, "Prague"] # :euruko
# [:scotland_on_rails, "Edinburgh"] # :scotland_on_rails
# [:railsconf_europe, "Berlin"] # :railsconf_europe

warning: multiple values for a block parameter (2 for 1) conferences.select do |name, city|
p [name, city]
end
# [:euruko, "Prague"]
# [:scotland_on_rails, "Edinburgh"]
# [:railsconf_europe, "Berlin"]
Hash#select (etc)
Returns a Hash

Ruby 1.8 Ruby 1.9


conferences.select do |name, _| conferences.select do |name, _|
name == :scotland_on_rails name == :scotland_on_rails
end end
# => [[:scotland_on_rails, "Edinburgh"]] # => {:scotland_on_rails=>"Edinburgh"}
Features
Lots of changes,
some big ones
Multilingualization
(m17n)

There is one type of string, and the encoding is mutable

Strings are no longer Enumerable (use #each_char, #each_line, etc)

The encoding is ‘lazy’ and can be set by probing with


String#ascii_only? and String#valid_encoding?. 

Various ways to set default encoding (commandline, magic


comments)

String#[] now returns a String, not a Fixnum (use ord)


[:ASCII_8BIT, :Big5, :BIG5, :CP949, :EUC_JP, :EUC_KR, :EUC_TW, :GB18030, :GBK, :ISO_885
9_1, :ISO_8859_2, :ISO_8859_3, :ISO_8859_4, :ISO_8859_5, :ISO_8859_6, :ISO_8859_7, :IS
O_8859_8, :ISO_8859_9, :ISO_8859_10, :ISO_8859_11, :ISO_8859_13, :ISO_8859_14, :ISO
_8859_15, :ISO_8859_16, :KOI8_R, :KOI8_U, :Shift_JIS, :SHIFT_JIS, :US_ASCII, :UTF_8, :UTF
_16BE, :UTF_16LE, :UTF_32BE, :UTF_32LE, :Windows_1251, :WINDOWS_1251, :BINARY, :I
BM437, :CP437, :IBM737, :CP737, :IBM775, :CP775, :CP850, :IBM850, :IBM852, :CP852, :IBM85
5, :CP855, :IBM857, :CP857, :IBM860, :CP860, :IBM861, :CP861, :IBM862, :CP862, :IBM863, :CP
863, :IBM864, :CP864, :IBM865, :CP865, :IBM866, :CP866, :IBM869, :CP869, :Windows_1258, :
WINDOWS_1258, :CP1258, :GB1988, :MacCentEuro, :MACCENTEURO, :MacCroatian, :MA
CCROATIAN, :MacCyrillic, :MACCYRILLIC, :MacGreek, :MACGREEK, :MacIceland, :MACICE
LAND, :MacRoman, :MACROMAN, :MacRomania, :MACROMANIA, :MacThai, :MACTHAI, :M
acTurkish, :MACTURKISH, :MacUkraine, :MACUKRAINE, :CP950, :EucJP, :EUCJP, :EucJP_ms, :E
UCJP_MS, :EUC_JP_MS, :CP51932, :EucKR, :EUCKR, :EucTW, :EUCTW, :EUC_CN, :EucCN, :
EUCCN, :GB12345, :CP936, :ISO_2022_JP, :ISO2022_JP, :ISO_2022_JP_2, :ISO2022_JP2, :ISO
8859_1, :Windows_1252, :WINDOWS_1252, :CP1252, :ISO8859_2, :Windows_1250, :WIN
DOWS_1250, :CP1250, :ISO8859_3, :ISO8859_4, :ISO8859_5, :ISO8859_6, :Windows_1256,
:WINDOWS_1256, :CP1256, :ISO8859_7, :Windows_1253, :WINDOWS_1253, :CP1253, :IS
O8859_8, :Windows_1255, :WINDOWS_1255, :CP1255, :ISO8859_9, :Windows_1254, :WI
NDOWS_1254, :CP1254, :ISO8859_10, :ISO8859_11, :TIS_620, :Windows_874, :WINDOW
S_874, :CP874, :ISO8859_13, :Windows_1257, :WINDOWS_1257, :CP1257, :ISO8859_14, :I
SO8859_15, :ISO8859_16, :CP878, :SJIS, :Windows_31J, :WINDOWS_31J, :CP932, :CsWindo
ws31J, :CSWINDOWS31J, :MacJapanese, :MACJAPANESE, :MacJapan, :MACJAPAN, :ASCII, :A
NSI_X3_4_1968, :UTF_7, :CP65000, :CP65001, :UCS_2BE, :UCS_4BE, :UCS_4LE, :CP1251]
Multilingualization
Read a file with File.read

File.read("input.txt").encoding
# => #<Encoding:UTF-8>

File.read("input.txt", encoding: 'ascii-8bit').encoding


# => #<Encoding:ASCII-8BIT>
Multilingualization
Read a file with File.open

result = File.open("input.txt", "r:euc-jp") do |f|


f.read
end
result.encoding
# => #<Encoding:EUC-JP>
result.valid_encoding?
# => true
Regular Expressions
Integrated “oniguruma” engine

Same basic API

Much better performance

Support for encodings

Extended Syntax
Look-ahead (?=), (?!), look-behind (?<), (?<!)

Named groups (?<>), backreferences, etc


Regular Expressions
Named Groups

"His name is Joe".match(/name is (?<name>\S+)/)[:name]


# => "Joe"
Enumerable
Enumerator built-in, returned from Enumerable methods (and
those in Array, Dir, Hash, IO, Range, String or Struct that serve the
same purposes). Added Enumerator#with_index

Map with index


%w(Joe John Jack).map.with_index do |name, offset|
"#{name} is #{offset + 1}"
end
# => ["Joe is #1", "John is #2", "Jack is #3"]
Enumerable
reduce (inject)

[1,2,3,4].reduce(:+)
# => 10
Enumerable
New Enumerable methods take, group_by, drop, min_by, max_by,
count, and others.

take drop

array = [1, 2, 3, 4, 5] array = [1, 2, 3, 4, 5]


array.take(3) array.drop(3)
# => [1, 2, 3] # => [4, 5]
array array
# => [1, 2, 3, 4, 5] # => [1, 2, 3, 4, 5]
Hash Changes
Insertion order preserved
conferences = {
euruko: 'Prague',
scotland_on_rails: 'Edinburgh'
}
conferences[:railsconf_europe] = 'Berlin'
conferences.each do |name, city|
p "#{name} is in #{city}"
end
# "euruko is in Prague"
# "scotland_on_rails is in Edinburgh"
# "railsconf_europe is in Berlin"
conferences.delete(:scotland_on_rails)
conferences[:scotland_on_rails] = 'Edinburgh'
conferences.each do |name, city|
p "#{name} is in #{city}"
end
# "euruko is in Prague"
# "railsconf_europe is in Berlin"
# "scotland_on_rails is in Edinburgh"
Object
Added tap

thing = Thing.new.tap do |thing|


thing.something = 1
thing.something_else = 2
end
Lambda Changes
Obfuscation, ahoy!
New literal syntax more flexible

Not possible in { | | ... } style literals

Passing blocks Default arguments


m = ->(x, &b) { b.(x * 2) if b } ->(a, b=2) { a * b }.(3)
m.(3) do |result|
# => 6
puts result
end
# Output
# 6
Symbol Changes
Less sibling rivalry

Added to_proc

Added =~, [] like String (to_s less needed), sortable

Object#methods, etc now return an array of symbols

Indexing into Comparing with a String


:foo[1] :this === "this"
# => "o" # => true
Fibers
“Semi-coroutines”

Similar to Python’s generators


Owe method naming lineage to Lua
Out of scope of the talk, but very cool
For some examples, see:
http://pragdave.blogs.pragprog.com/pragdave/2007/12/pipelines-using.html (and follow-up)

http://www.davidflanagan.com/blog/2007_08.html (older)

Revactor project (Actors in 1.9 using Fibers + Threads)

InfoQ, others...
This was really just an introduction.

Bruce Williams bruce@codefluency.com twitter: wbruce

You might also like