title: Migrating to Ruby 1.9 h1. Migrating to Ruby 1.9 Bruce Williams @ Scotland on Rails, Edinburgh, April 2008 Adapted S6/S9[1] Version from "Original Slide Deck":http://codefluency.com/articles/2008/04/14/migrating-to-ruby-1-9
fn1. ("Source":http://slideshow.rubyforge.org/svn/samples/ruby19mig.textile) *Slide Show Keyboard Controls (Help)* | Action | Key | | Go to next slide | Space Bar, Right Arrow, Down Arrow, Page Down | | Go to previous slide | Left Arrow, Up Arrow, Page Up | | Toggle between slideshow and outline view (Ø) | T | | Show/hide slide controls (Ø « ») | C, Move mouse to bottom right corner | h1. About 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 "@codefluency.com@":http://codefluency.com h1. Ruby 1.8 / Ruby 1.9 h3. 1.8 * Stable. * The syntax and language features you know and probably love. * The performance profile you know and might hate a little. h3. 1.9 * Unstable, transitional. * Many new syntax and language features. * Better performance, especially for computationally intensive operations. h1. Installing Ruby 1.9 * Get it from "ruby-lang.org":http://ruby-lang.org; by release or subversion * Use @./configure --prefix=/somewhere/nice@ to put it where you want it * Probably use @--program-suffix=1.9@, too h1. Ruby's Releases - From Toybox to Toolshed Born in Japan (1995) -> Beyond Japan (2001) -> .. on Rails (2004) -> Expansion (2008) | (development 1.5) | | | | 1.6.0 | '00 | | | 1.6.1 | '01 | | | 1.6.2 | '01 | | | 1.6.3 | '01 | | | 1.6.4 | '02 | | | 1.6.5 | '02 | | | 1.6.7 | '02 | | | 1.6.8 | '03 | (development 1.7 ongoing) | | 1.8.0 | '04 | | | 1.8.1 | '04 | | | 1.8.2 | '05 | | | 1.8.3 | '05 | | | 1.8.4 | '06 | | | 1.8.5 | '06 | | | 1.8.6 | '07 | (development 1.9 ongoing) | h1. Standard Library * *rubygems* added (+ prelude & @ruby --disable-gems@) * *rake* added * *json* (pure, ext) added * FasterCSV replaced the previous *csv* * Also added: *ripper*, *probeprofiler*, *securerandom*, HMAC digests (some others moved) * Removed: *soap*, *wsdl*, *base64* (use @[@@str].pack/unpack 'm*'@), and some rarely used, old libraries h1. Parser/Syntax Changes New Hash Literal {{{ {a: "foo"} # => {:a=>"foo"} {a: "bar", :b => "baz"} # => {:a=>"bar", :b=>"baz"} }}} New Proc Literal, Invocation {{{ multiply_by_2 = ->(x) { x * 2 } # => # multiply_by_2.(4) # => 8 }}} h1. Parser/Syntax Changes Continued Splat arguments before {{{ names = %w(joe john bill) [*names, 'jack'] # => ["joe", "john", "bill", "jack"] }}} Method Parameter ordering {{{ def say(language=:english, text) puts Translator[language].translate(text) end say "hello" # hello say :spanish, "hello" # hola }}} h1. Migrating Risk Factors * Text processing * "Clever" assignment with blocks * Some Hash enumerations * Metaprogramming, code generation h1. 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 (December 2007) Follow-up Posting: "Getting Code Ready for Ruby 1.9":http://blog.grayproductions.net/articles/getting_code_ready_for_ruby_19 h1. Block Local Variables - Arguments Are Always Local {{{ item = 1 2.upto(4) do |item| p item end }}} Outputs In 1.8 {{{ # 2 # 3 # 4 item # => 4 }}} Outputs In 1.9 {{{ # 2 # 3 # 4 item # => 1 }}} h1. Shadowing Variables - You'll Get a Warning {{{ i = 1 lambda { |i| p i }.call(3) }}} Outputs In 1.8 {{{ # 3 i # => 3 }}} Outputs In 1.9 {{{ # 3 i # => 1 }}} warning line 2: shadowing outer local variable - @i@ h1. Shadowing Variables - Locals, But Warned No Local, Reassigns {{{ d = 2 -> { d = 1 }.() d # => 1 }}} Local, shadowed {{{ d = 2 ->(;d) { d = 1 }.() d # => 2 }}} warning line 2: shadowing outer local variable - @d@ h1. @Hash#select@ - Changes to Yielded Arguments Ruby 1.8 {{{ conferences.select do |data| p data end # [:euruko, "Prague"] # [:scotland_on_rails, "Edinburgh"] # [:railsconf_europe, "Berlin"] }}} warning: multiple values for a block parameter (2 for 1) Ruby 1.9 {{{ conferences.select do |data| p data end # :euruko # :scotland_on_rails # :railsconf_europe }}} {{{ conferences.select do |name, city| p [name, city] end # [:euruko, "Prague"] # [:scotland_on_rails, "Edinburgh"] # [:railsconf_europe, "Berlin"] }}} h1. @Hash#select@ - Returns a Hash {{{ conferences.select do |name, _| name == :scotland_on_rails end }}} Ruby 1.8 {{{ # => [[:scotland_on_rails, "Edinburgh"]] }}} Ruby 1.9 {{{ # => {:scotland_on_rails=>"Edinburgh"} }}} h1. 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@) h1. Multilingualization (m17n) Continued h3. Encodings :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 h1. Multilingualization (m17n) Continued Read a file with @File.read@ {{{ File.read("input.txt").encoding # => # File.read("input.txt", encoding: 'ascii-8bit').encoding # => # }}} Read a file with @File.open@ {{{ result = File.open("input.txt", "r:euc-jp") do |f| f.read end result.encoding # => # result.valid_encoding? # => true }}} h1. Regular Expressions - Oniguruma Engine * Same basic API * Much Better performance * Support for encodings * Extended Syntax ** Look-ahead @(?=)@, @(?!)@, look-behind @(?<)@, @(?)@, backreferences, etc Named Groups {{{ "His name is Joe".match(/name is (?\S+)/)[:name] # => "Joe" }}} h1. 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"] }}} h1. Enumerable - @Reduce@ (@inject@) {{{ [1,2,3,4].reduce(:+) # => 10 }}} h1. Enumerable Continued New Enumerable methods @take@, @group_by@, @drop@, @min_by@, @max_by@, @count@, and others. @Enumerable#inject@/@reduce@ can take a single argument. @take@ {{{ array = [1, 2, 3, 4, 5] array.take(3) # => [1, 2, 3] array # => [1, 2, 3, 4, 5] }}} @drop@ {{{ array = [1, 2, 3, 4, 5] array.drop(3) # => [4, 5] array # => [1, 2, 3, 4, 5] }}} h1. 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" }}} h1. Object - Added @tap@ {{{ thing = Thing.new.tap do |thing| thing.something = 1 thing.something_else = 2 end }}} h1. Lambda Changes - Obfuscation, Ahoy! * New literal syntax more flexible * Not possible in @{ | | ... }@ style literals Passing Blocks {{{ m = ->(x, &b) { b.(x * 2) if b } m.(3) do |result| puts result end # Output # 6 }}} Default Arguments {{{ ->(a, b=2) { a * b }.(3) # => 6 }}} h1. 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 a Symbol {{{ :foo[1] # => "o" }}} Comparing with a String {{{ :this === "this" # => true }}} h1. 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: * "Pipelines Using Fibers in Ruby 1.9":http://pragdave.blogs.pragprog.com/pragdave/2007/12/pipelines-using.html (and follow-up) * "Fibonacci numbers with Ruby 1.9 Fibers; Coroutines (via fibers) in Ruby 1.9":http://www.davidflanagan.com/blog/2007_08.html (older) * Revactor project (Actors in 1.9 using Fibers + Threads) * InfoQ, others... h1. Thanks! This was really just an introduction. Bruce Williams // @bruce AT codefluency.com@ // twitter: wbruce