Download - Migrating to Ruby 1.9
Ruby 1.9Migrating to
Bruce Williams
Bruce WilliamsRubyist since 2001
Open source developer, contributer, technical editor, designerOccasionally blogs at http://codefluency.com
(Full-time since 2005)
Perpetrator of much random Ruby hackery, language tourist
Stable.
The syntax and language features you know and probably love.
The performance profile you know and might hate a little.
Unstable, transitional.
Many new syntax and language features.
Better performance, especially for computationally intensive operations.
Ruby 1.9Ruby 1.8
1.9 is a hint.
1.9 is a hint.Get ready for 2.0.
1.8.61.8.51.8.4
1.8.31.8.21.8.1
1.8.01.6.81.6.71.6.21.6.1
1.6.01.5
1.71.9
1.6.41.6.51.6.3
Japan Beyond Japan “... on Rails” Expansion
‘00 ‘01 ‘02 ‘03 ‘04 ‘05 ‘06 ‘07 ‘08
(dev)(dev)
Ruby’s ReleasesFrom Toybox to Toolshed
(dev)
Standard Library
+rubygems (+ prelude & ruby --disable-gems), rake, json (pure,
ext), ripper, probeprofiler, securerandom, HMAC digests
- soap, wsdl, base64, some rarely used, old libraries
~ csv replaced by FasterCSV implementation
Parser ChangesFlexibility and Obscurity (for the moment)
{a: "foo"}# => {:a=>"foo"}
{a: "bar", :b => "baz"}# => {:a=>"bar", :b=>"baz"}
Parser ChangesNew Hash Literal
Parser ChangesNew Proc Literal
multiply_by_2 = ->(x) { x * 2 }# => #<Proc:0x3c5a50>
multiply_by_2.(4)# => 8
Parser ChangesSplat more flexibly
names = %w(joe john bill)[*names, 'jack']# => ["joe", "john", "bill", "jack"]
Parser ChangesMethod parameter ordering
def say(language=:english, text) puts Translator[language].translate(text)endsay "hello"# hellosay :spanish, "hello"# hola
Text processing
“Clever” assignment with blocks
Some Hash enumerations
Metaprogramming, code generation
Migration Risk Factors
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
Tests are Good
Follow-up at http://blog.grayproductions.net/articles/getting_code_ready_for_ruby_19
Block Local VariablesArguments are always local
item = 12.upto(4) do |item| p itemend# Outputs:# 2# 3# 4item# => 4
item = 12.upto(4) do |item| p itemend# Outputs:# 2# 3# 4item# => 1
Ruby 1.9Ruby 1.8
Shadowing VariablesYou’ll get a warning
Ruby 1.9Ruby 1.8
i = 1lambda { |i| p i }.call(3)# Outputs# 3i# => 3
i = 1lambda { |i| p i }.call(3)# Outputs# 3i# => 1
-e:2: warning: shadowing outer local variable - i
Shadowing VariablesLocals, but warned
-e:2: warning: shadowing outer local variable - d
d = 2->(;d) { d = 1 }.()d# => 2
d = 2-> { d = 1 }.()d# => 1
(Ruby 1.9)
No local, reassigns Local, shadowed
Hash#select (etc)Changes to yielded arguments
Ruby 1.9Ruby 1.8conferences.select do |data| p dataend# [:euruko, "Prague"]# [:scotland_on_rails, "Edinburgh"]# [:railsconf_europe, "Berlin"]
conferences.select do |data| p dataend# :euruko# :scotland_on_rails# :railsconf_europe
conferences.select do |name, city| p [name, city]end# [:euruko, "Prague"]# [:scotland_on_rails, "Edinburgh"]# [:railsconf_europe, "Berlin"]
warning: multiple values for a block parameter (2 for 1)
Hash#select (etc)Returns a Hash
Ruby 1.9Ruby 1.8conferences.select do |name, _| name == :scotland_on_railsend# => [[:scotland_on_rails, "Edinburgh"]]
conferences.select do |name, _| name == :scotland_on_railsend# => {:scotland_on_rails=>"Edinburgh"}
FeaturesLots 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_8859_1, :ISO_8859_2, :ISO_8859_3, :ISO_8859_4, :ISO_8859_5, :ISO_8859_6, :ISO_8859_7, :ISO_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, :IBM437, :CP437, :IBM737, :CP737, :IBM775, :CP775, :CP850, :IBM850, :IBM852, :CP852, :IBM855, :CP855, :IBM857, :CP857, :IBM860, :CP860, :IBM861, :CP861, :IBM862, :CP862, :IBM863, :CP863, :IBM864, :CP864, :IBM865, :CP865, :IBM866, :CP866, :IBM869, :CP869, :Windows_1258, :WINDOWS_1258, :CP1258, :GB1988, :MacCentEuro, :MACCENTEURO, :MacCroatian, :MACCROATIAN, :MacCyrillic, :MACCYRILLIC, :MacGreek, :MACGREEK, :MacIceland, :MACICELAND, :MacRoman, :MACROMAN, :MacRomania, :MACROMANIA, :MacThai, :MACTHAI, :MacTurkish, :MACTURKISH, :MacUkraine, :MACUKRAINE, :CP950, :EucJP, :EUCJP, :EucJP_ms, :EUCJP_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, :ISO8859_1, :Windows_1252, :WINDOWS_1252, :CP1252, :ISO8859_2, :Windows_1250, :WINDOWS_1250, :CP1250, :ISO8859_3, :ISO8859_4, :ISO8859_5, :ISO8859_6, :Windows_1256, :WINDOWS_1256, :CP1256, :ISO8859_7, :Windows_1253, :WINDOWS_1253, :CP1253, :ISO8859_8, :Windows_1255, :WINDOWS_1255, :CP1255, :ISO8859_9, :Windows_1254, :WINDOWS_1254, :CP1254, :ISO8859_10, :ISO8859_11, :TIS_620, :Windows_874, :WINDOWS_874, :CP874, :ISO8859_13, :Windows_1257, :WINDOWS_1257, :CP1257, :ISO8859_14, :ISO8859_15, :ISO8859_16, :CP878, :SJIS, :Windows_31J, :WINDOWS_31J, :CP932, :CsWindows31J, :CSWINDOWS31J, :MacJapanese, :MACJAPANESE, :MacJapan, :MACJAPAN, :ASCII, :ANSI_X3_4_1968, :UTF_7, :CP65000, :CP65001, :UCS_2BE, :UCS_4BE, :UCS_4LE, :CP1251]
MultilingualizationRead a file with File.read
File.read("input.txt").encoding# => #<Encoding:UTF-8>
File.read("input.txt", encoding: 'ascii-8bit').encoding# => #<Encoding:ASCII-8BIT>
MultilingualizationRead a file with File.open
result = File.open("input.txt", "r:euc-jp") do |f| f.readendresult.encoding# => #<Encoding:EUC-JP>result.valid_encoding?# => true
Regular ExpressionsIntegrated “oniguruma” engine
Same basic API
Much better performance
Support for encodings
Extended Syntax
Look-ahead (?=), (?!), look-behind (?<), (?<!)
Named groups (?<>), backreferences, etc
Regular ExpressionsNamed Groups
"His name is Joe".match(/name is (?<name>\S+)/)[:name]# => "Joe"
EnumerableEnumerator 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
%w(Joe John Jack).map.with_index do |name, offset| "#{name} is #{offset + 1}"end# => ["Joe is #1", "John is #2", "Jack is #3"]
Map with index
Enumerablereduce (inject)
[1,2,3,4].reduce(:+)# => 10
Enumerable
take
New Enumerable methods take, group_by, drop, min_by, max_by, count, and others.
array = [1, 2, 3, 4, 5]array.take(3)# => [1, 2, 3]array# => [1, 2, 3, 4, 5]
array = [1, 2, 3, 4, 5]array.drop(3)# => [4, 5]array# => [1, 2, 3, 4, 5]
drop
Hash ChangesInsertion 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"
thing = Thing.new.tap do |thing| thing.something = 1 thing.something_else = 2end
ObjectAdded tap
Lambda ChangesObfuscation, ahoy!
New literal syntax more flexible
Not possible in { | | ... } style literals
m = ->(x, &b) { b.(x * 2) if b }m.(3) do |result| puts resultend# Output# 6
->(a, b=2) { a * b }.(3)# => 6
Passing blocks Default arguments
Symbol ChangesLess sibling rivalry
Indexing into Comparing with a String
Added to_proc
Added =~, [] like String (to_s less needed), sortable
Object#methods, etc now return an array of symbols
:foo[1]# => "o"
:this === "this"# => true
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...
Fibers“Semi-coroutines”
This was really just an introduction.
Bruce Williams [email protected] twitter: wbruce