SlideShare a Scribd company logo
Upgrading to Ruby 2.x 
Joe Rafaniello 
@jrafanie
2007
13
Agenda 
1. History 
2. Why upgrade? 
3. Ruby 2.1 
4. Ruby 2.0 
5. "Fall cleanup" of old code 
6. Slow tests 
7. Building 2.0 appliances 
8. Developer setup 
9. Links 
10. Questions?
History 
Tue Nov 1 2011: 
First ruby 1.8.7 -> 1.9.3 related commit on ManageIQ
History 
Tue Nov 1 2011: 
First ruby 1.8.7 -> 1.9.3 related commit on ManageIQ 
Tue Apr 23 2013: 
Ruby 1.9.3 finally...
History 
Tue Nov 1 2011: 
First ruby 1.8.7 -> 1.9.3 related commit on ManageIQ 
Tue Apr 23 2013: 
Ruby 1.9.3 finally... 
540 days???
History 
Tue Nov 1 2011: 
First ruby 1.8.7 -> 1.9.3 related commit on ManageIQ 
Tue Apr 23 2013: 
Ruby 1.9.3 finally... 
540 days??? 
Lesson learned: Don't wait to upgrade!
Why upgrade?
Why upgrade? 
We're behind!!! 
Ruby 1.9.3 is ending 
In maintenance until February 23, 2014 
Security only mode until February 23, 2015 
Ruby 2.0.0 is nearly 20 months old 
Ruby 2.1.0 is nearly 10 months old 
Ruby 2.2.0 is scheduled for a Christmas release
Why upgrade? ... Because ruby 2.1! 
Generational mark and sweep garbage collector 
http://tmm1.net/ruby21-rgengc/ 
String#freeze - reuse String objects 
Less objects == less memory == less GC time 
Object allocation tracing 
http://tmm1.net/ruby21-objspace/ 
https://github.com/srawlins/allocation_stats 
Required keyword arguments 
def returns method name 
Exception#cause - ActiveRecord::StatementInvalid#cause -> Real error 
More...
Why upgrade? ... Because ruby 2.1! 
Useless benchmark 
bundle exec rspec spec/models/ems_refresh/refreshers 
1.9.3-p545 
70.85s user 2.23s system 96% cpu 1:15.98 total 
71.21s user 2.22s system 96% cpu 1:16.27 total
Why upgrade? ... Because ruby 2.1! 
Useless benchmark 
bundle exec rspec spec/models/ems_refresh/refreshers 
1.9.3-p545 
70.85s user 2.23s system 96% cpu 1:15.98 total 
71.21s user 2.22s system 96% cpu 1:16.27 total 
2.0.0-p576 
54.02s user 2.03s system 95% cpu 58.980 total 
49.96s user 2.14s system 94% cpu 54.923 total
Why upgrade? ... Because ruby 2.1! 
Useless benchmark 
bundle exec rspec spec/models/ems_refresh/refreshers 
1.9.3-p545 
70.85s user 2.23s system 96% cpu 1:15.98 total 
71.21s user 2.22s system 96% cpu 1:16.27 total 
2.0.0-p576 
54.02s user 2.03s system 95% cpu 58.980 total 
49.96s user 2.14s system 94% cpu 54.923 total 
2.1.3 
36.52s user 2.79s system 91% cpu 42.930 total 
35.68s user 2.22s system 92% cpu 40.768 total
Why upgrade? ... Because ruby 2.1! 
Example allocation information: 
Line number 
Number of allocations by object type 
Such as: 
Running: ./spec/controllers/application_controller/buttons_spec.rb:91 
223730 Arrays @ .../activerecord/lib/active_record/result.rb:35 
203280 Strings @ .../activerecord/lib/active_record/relation.rb:27
Why upgrade? ... Because ruby 2.1! 
Example allocation information: 
Line number 
Number of allocations by object type 
Such as: 
Running: ./spec/controllers/application_controller/buttons_spec.rb:91 
223730 Arrays @ .../activerecord/lib/active_record/result.rb:35 
203280 Strings @ .../activerecord/lib/active_record/relation.rb:27 
See Issue 241 and 762
But that's 2.1, let's get to 2.0 first...
Ruby 2.0 features
Faster Rails startup 
Optimizations were made to speed up 'require'
Faster Rails startup 
Optimizations were made to speed up 'require' 
(master) (1.9.3-p545) + time bundle exec rake environment 
bundle exec rake environment 3.51s user 0.63s system 99% cpu 4.148 total 
(master) (2.0.0-p576) + time bundle exec rake environment 
bundle exec rake environment 2.60s user 0.53s system 99% cpu 3.132 total
Faster Rails startup 
Optimizations were made to speed up 'require' 
(master) (1.9.3-p545) + time bundle exec rake environment 
bundle exec rake environment 3.51s user 0.63s system 99% cpu 4.148 total 
(master) (2.0.0-p576) + time bundle exec rake environment 
bundle exec rake environment 2.60s user 0.53s system 99% cpu 3.132 total 
25% faster loading of rails environment!
Faster Rails startup 
Optimizations were made to speed up 'require' 
(master) (1.9.3-p545) + time bundle exec rake environment 
bundle exec rake environment 3.51s user 0.63s system 99% cpu 4.148 total 
(master) (2.0.0-p576) + time bundle exec rake environment 
bundle exec rake environment 2.60s user 0.53s system 99% cpu 3.132 total 
25% faster loading of rails environment! 
Most obvious when: 
Running tests 
Loading Rails console
Keyword arguments 
Simplifies conventions: 
Accessing option hash values 
Default hash values 
Optional / can't handle all cases
Keyword arguments 
Example: EmsVmware#vm_connect_all 
def vm_connect_all(vm, options={}) 
defaults = { :onStartup => false } 
options = defaults.merge(options) 
vm_connect_disconnect_all_connectable_devices( 
vm, 
true, 
options[:onStartup], 
options[:user_event] 
) 
end
Keyword arguments 
Example: EmsVmware#vm_connect_all 
def vm_connect_all(vm, options={}) 
defaults = { :onStartup => false } 
options = defaults.merge(options) 
vm_connect_disconnect_all_connectable_devices( 
vm, 
true, 
options[:onStartup], 
options[:user_event] 
) 
end 
With keyword arguments: 
def vm_connect_all(vm, user_event: nil, onStartup: false) 
vm_connect_disconnect_all_connectable_devices(vm, true, onStartup, user_event) 
end
Keyword arguments 
Invoking methods not changed 
Valid on 1.9.3 / 2.0.0: 
vm_connect_all(:vm_object1, :onStartup => true, :user_event => "event1") 
vm_connect_all(:vm_object2) 
vm_connect_all(:vm_object3, :user_event => "event3") 
vm_connect_all(:vm_object3, user_event: "event3")
Keyword arguments 
Shortcomings and gotchas: 
if - valid hash key / invalid keyword argument 
Required keyword arguments added in 2.1 
http://magazine.rubyist.net/?Ruby200SpecialEn-kwarg 
http://robots.thoughtbot.com/ruby-2-keyword-arguments 
http://chriszetter.com/blog/2012/11/02/keyword-arguments-in-ruby-2- 
dot-0/
Module#prepend 
Problem: We want to debug a slow method.
Module#prepend 
Problem: We want to debug a slow method. 
Wrap the method so can time it!
Module#prepend 
Using alias_method: 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
def run 
puts "Sub" 
super 
end 
def run_with 
puts "DebugIt" 
run_without 
end 
alias_method :run_without, :run 
alias_method :run, :run_with 
end
Module#prepend 
Using alias_method: 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
def run 
puts "Sub" 
super 
end 
def run_with 
puts "DebugIt" 
run_without 
end 
Sub is a class with the slow run method... 
alias_method :run_without, :run 
alias_method :run, :run_with 
end
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
def run 
puts "Sub" 
super 
end 
def run_with 
puts "DebugIt" 
run_without 
end 
Sub is a class with the slow run method... 
alias_method :run_without, :run 
alias_method :run, :run_with 
end 
irb(main):01:0> Sub.new.run 
DebugIt 
Sub 
Parent 
Module#prepend 
Using alias_method:
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
def run 
puts "Sub" 
super 
end 
def run_with 
puts "DebugIt" 
run_without 
end 
Sub is a class with the slow run method... 
alias_method :run_without, :run 
alias_method :run, :run_with 
end 
irb(main):01:0> Sub.new.run 
DebugIt 
Sub 
Parent 
YAY! But that's really dirty! 
(alias_method_chain) 
Module#prepend 
Using alias_method:
Module#prepend 
Using include: 
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
include DebugIt 
def run 
puts "Sub" 
super 
end 
end
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
include DebugIt 
def run 
puts "Sub" 
super 
end 
end 
Sub is a class with the slow run method... 
Module#prepend 
Using include:
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
include DebugIt 
def run 
puts "Sub" 
super 
end 
end 
Sub is a class with the slow run method... 
irb(main):002:0> Sub.ancestors 
=> [Sub, DebugIt, Parent, Object, Kernel, BasicObject] 
Module#prepend 
Using include:
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
include DebugIt 
def run 
puts "Sub" 
super 
end 
end 
Sub is a class with the slow run method... 
irb(main):002:0> Sub.ancestors 
=> [Sub, DebugIt, Parent, Object, Kernel, BasicObject] 
irb(main):01:0> Sub.new.run 
Sub 
DebugIt 
Parent 
Module#prepend 
Using include:
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
include DebugIt 
def run 
puts "Sub" 
super 
end 
end 
Sub is a class with the slow run method... 
irb(main):002:0> Sub.ancestors 
=> [Sub, DebugIt, Parent, Object, Kernel, BasicObject] 
irb(main):01:0> Sub.new.run 
Sub 
DebugIt 
Parent 
UGH, Sub's method comes first! 
Module#prepend 
Using include:
Module#prepend 
Using prepend: 
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
prepend DebugIt 
def run 
puts "Sub" 
super 
end 
end
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
prepend DebugIt 
def run 
puts "Sub" 
super 
end 
end 
irb(main):002:0> Sub.ancestors 
=> [DebugIt, Sub, Parent, Object, Kernel, BasicObject] 
Module#prepend 
Using prepend:
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
prepend DebugIt 
def run 
puts "Sub" 
super 
end 
end 
irb(main):002:0> Sub.ancestors 
=> [DebugIt, Sub, Parent, Object, Kernel, BasicObject] 
irb(main):01:0> Sub.new.run 
DebugIt 
Sub 
Parent 
Module#prepend 
Using prepend:
module DebugIt 
def run 
puts "DebugIt" 
super 
end 
end 
class Parent 
def run 
puts "Parent" 
end 
end 
class Sub < Parent 
prepend DebugIt 
def run 
puts "Sub" 
super 
end 
end 
irb(main):002:0> Sub.ancestors 
=> [DebugIt, Sub, Parent, Object, Kernel, BasicObject] 
irb(main):01:0> Sub.new.run 
DebugIt 
Sub 
Parent 
Ship it! 
... but don't forget to call super! 
Module#prepend 
Using prepend:
Array of symbols: %i and %I
Array of symbols: %i and %I 
irb(main):001:0> %i{vmware redhat microsoft} 
=> [:vmware, :redhat, :microsoft]
Array of symbols: %i and %I 
irb(main):001:0> %i{vmware redhat microsoft} 
=> [:vmware, :redhat, :microsoft] 
%I allows interpolation:
Array of symbols: %i and %I 
irb(main):001:0> %i{vmware redhat microsoft} 
=> [:vmware, :redhat, :microsoft] 
%I allows interpolation: 
irb(main):002:0> prefix = "vm_" 
=> "vm_" 
irb(main):003:0> %I{#{prefix}vmware #{prefix}redhat #{prefix}microsoft} 
=> [:vm_vmware, :vm_redhat, :vm_microsoft]
Refinements 
Goal: localize monkey patches 
I'm not going to explain them because: 
Ruby's open classes 
Many gotchas... 
See Charles Nutter (@headius/jruby guy) explanation: 
http://blog.headius.com/2012/11/refining-ruby.html
Enumerable#lazy 
Enumerable methods evaluate left to right 
With lazy, chains of enumerations are evaluated right to left
Enumerable#lazy 
Enumerable methods evaluate left to right 
With lazy, chains of enumerations are evaluated right to left 
Ruby may "cheat": 
May skip creating intermediate objects 
Large collection operations may be optimized
Enumerable#lazy 
Example benchmark 
(0...1000).select(&:odd?).take(5).to_a 
(0...1000).lazy.select(&:odd?).take(5).to_a 
What is this doing?
Enumerable#lazy 
Example benchmark 
(0...1000).select(&:odd?).take(5).to_a 
(0...1000).lazy.select(&:odd?).take(5).to_a 
What is this doing? 
First 5 odd numbers 
=> [1, 3, 5, 7, 9]
Enumerable#lazy 
require 'benchmark/ips' 
Benchmark.ips do |x| 
x.report("normal") { (0...1000).select(&:odd?).take(5).to_a } 
x.report("lazy") { (0...1000).lazy.select(&:odd?).take(5).to_a } 
end
Enumerable#lazy 
require 'benchmark/ips' 
Benchmark.ips do |x| 
x.report("normal") { (0...1000).select(&:odd?).take(5).to_a } 
x.report("lazy") { (0...1000).lazy.select(&:odd?).take(5).to_a } 
end 
Calculating ------------------------------------- 
normal 1539 i/100ms 
lazy 5778 i/100ms 
------------------------------------------------- 
normal 15123.2 (±2.5%) i/s - 76950 in 5.091373s 
lazy 59797.4 (±4.0%) i/s - 300456 in 5.033123s 
See http://patshaughnessy.net/2013/4/3/ruby-2-0-works-hard-so-you-can-be- 
lazy
__dir__ 
__dir__ path of the script without the filename 
# cat test.rb 
puts __dir__ 
# ruby test.rb 
/Users/joerafaniello/Code/test
__dir__ 
__dir__ path of the script without the filename 
# cat test.rb 
puts __dir__ 
# ruby test.rb 
/Users/joerafaniello/Code/test 
We have 984 instances of File.dirname(__FILE__)! 
WAT...Why?
Ruby 2.0 breaking changes and deprecations 
Note: We're green on travis, so we're getting close...
Objects don't respond_to? to protected methods 
Ruby 1.9.3: 
respond_to?(symbol) => public and protected methods 
respond_to?(symbol, true) => all methods
Objects don't respond_to? to protected methods 
Ruby 1.9.3: 
respond_to?(symbol) => public and protected methods 
respond_to?(symbol, true) => all methods 
Ruby 2.0.0 
respond_to?(symbol) => public methods only 
respond_to?(symbol, true) => all methods
Objects don't respond_to? to protected methods 
class Worker 
protected 
def run 
end 
end
Objects don't respond_to? to protected methods 
class Worker 
protected 
def run 
end 
end 
Worker.new.respond_to?(:run) 
1.9.3 => true 
2.0.0 => false
Objects don't respond_to? to protected methods 
class Worker 
protected 
def run 
end 
end 
Worker.new.respond_to?(:run) 
1.9.3 => true 
2.0.0 => false 
Pass true as second argument... 
Worker.new.respond_to?(:run, true) 
1.9.3 => true 
2.0.0 => true
Objects don't respond_to? to protected methods 
class Worker 
protected 
def run 
end 
end 
Worker.new.respond_to?(:run) 
1.9.3 => true 
2.0.0 => false 
Pass true as second argument... 
Worker.new.respond_to?(:run, true) 
1.9.3 => true 
2.0.0 => true 
See Pull #685 - default_value_for gem
UTF-8 is the default character encoding of ruby 
scripts 
# cat test.rb 
FOO = "222dL256"
UTF-8 is the default character encoding of ruby 
scripts 
# cat test.rb 
FOO = "222dL256" 
Ruby 1.9.3 
US-ASCII is the default encoding of ruby scripts
UTF-8 is the default character encoding of ruby 
scripts 
# cat test.rb 
FOO = "222dL256" 
Ruby 1.9.3 
US-ASCII is the default encoding of ruby scripts 
Binary string literals become ASCII-8BIT:
UTF-8 is the default character encoding of ruby 
scripts 
# cat test.rb 
FOO = "222dL256" 
Ruby 1.9.3 
US-ASCII is the default encoding of ruby scripts 
Binary string literals become ASCII-8BIT: 
irb(main):001:0> require './test' 
=> true 
irb(main):002:0> FOO.encoding 
=> #<Encoding:ASCII-8BIT>
UTF-8 is the default character encoding of ruby 
scripts 
# cat test.rb 
FOO = "222dL256"
UTF-8 is the default character encoding of ruby 
scripts 
# cat test.rb 
FOO = "222dL256" 
Ruby 2.0.0 
UTF-8 is the default encoding
UTF-8 is the default character encoding of ruby 
scripts 
# cat test.rb 
FOO = "222dL256" 
Ruby 2.0.0 
UTF-8 is the default encoding 
Binary string literals become UTF-8 even if invalid: 
irb(main):001:0> require './test' 
=> true 
irb(main):002:0> FOO.encoding 
=> #<Encoding:UTF-8> 
irb(main):003:0> FOO.valid_encoding? 
=> false
UTF-8 is the default character encoding of ruby 
scripts 
So, what's the problem? 
Binary strings are used in many places for vm "fleecing" 
Invalid UTF-8 encoded strings != raw binary:
UTF-8 is the default character encoding of ruby 
scripts 
So, what's the problem? 
Binary strings are used in many places for vm "fleecing" 
Invalid UTF-8 encoded strings != raw binary: 
irb(main):003:0> FOO.valid_encoding? 
=> false 
irb(main):004:0> FOO == "222dL256".force_encoding("ASCII-8BIT") 
=> false
UTF-8 is the default character encoding of ruby 
scripts 
Solutions: 
Force binary on individual Strings: 
1.9.3/2.0.0 compatible 
Painful on files with many binary string literals
UTF-8 is the default character encoding of ruby 
scripts 
Solutions: 
Force binary on individual Strings: 
1.9.3/2.0.0 compatible 
Painful on files with many binary string literals 
# cat test.rb 
FOO = "222dL256".force_encoding("ASCII-8BIT")
UTF-8 is the default character encoding of ruby 
scripts 
Solutions: 
Force binary on individual Strings: 
1.9.3/2.0.0 compatible 
Painful on files with many binary string literals 
# cat test.rb 
FOO = "222dL256".force_encoding("ASCII-8BIT") 
irb(main):001:0> require './test' 
=> true 
irb(main):002:0> FOO.encoding 
=> #<Encoding:ASCII-8BIT> 
irb(main):003:0> FOO.valid_encoding? 
=> true 
irb(main):004:0> FOO == "222dL256".force_encoding("ASCII-8BIT") 
=> true
UTF-8 is the default character encoding of ruby 
scripts 
Solutions: 
Use String#b on individual strings 
Not compatible with ruby 1.9.3 
Copies the String in ASCII-8BIT encoding 
Note: String#force_encoding("ASCII-8BIT") modifies the receiver
UTF-8 is the default character encoding of ruby 
scripts 
Solutions: 
Add #encoding magic comment at top 
1.9.3/2.0.0 compatible 
Good option when binary strings are expected
UTF-8 is the default character encoding of ruby 
scripts 
Solutions: 
Add #encoding magic comment at top 
1.9.3/2.0.0 compatible 
Good option when binary strings are expected 
# cat test.rb 
# encoding: US-ASCII 
FOO = "222dL256"
UTF-8 is the default character encoding of ruby 
scripts 
Solutions: 
Add #encoding magic comment at top 
1.9.3/2.0.0 compatible 
Good option when binary strings are expected 
# cat test.rb 
# encoding: US-ASCII 
FOO = "222dL256" 
irb(main):001:0> require './test' 
=> true 
irb(main):002:0> FOO.encoding 
=> #<Encoding:ASCII-8BIT>
Descriptors except 0, 1, 2 are closed in child 
processes 
Prevents file descriptor leakage 
See Pull #682, Issue #459, and https://bugs.ruby-lang.org/issues/5041
Descriptors except 0, 1, 2 are closed in child 
processes 
Prevents file descriptor leakage 
See Pull #682, Issue #459, and https://bugs.ruby-lang.org/issues/5041 
Example: shared pipe to communicate data between two processes
Descriptors except 0, 1, 2 are closed in child 
processes 
Prevents file descriptor leakage 
See Pull #682, Issue #459, and https://bugs.ruby-lang.org/issues/5041 
Example: shared pipe to communicate data between two processes 
Use IO#close_on_exec = false 
reader, writer = IO.pipe 
writerfd = writer.fileno 
my_env["WRITER_FD"] = writerfd.to_s 
+ 
+ writer.close_on_exec = false 
+ 
pid = Kernel.spawn(my_env, "ruby #{SERVER_PATH}VixDiskLibServer.rb", 
[:out, :err] => [LOG_FILE, "a"], 
:unsetenv_others => true,
String#lines returns an array 
Also String#chars, #bytes and #codepoints 
Previously, returned enumerators 
Above are deprecated for StringIO, IO and friends
String#lines returns an array 
Also String#chars, #bytes and #codepoints 
Previously, returned enumerators 
Above are deprecated for StringIO, IO and friends 
StringIO#lines deprecated, so use #each_line instead: 
@log_stream.rewind 
- lines = @log_stream.lines.to_a 
+ lines = @log_stream.each_line.to_a 
lines.length.should == 1 
line = lines.first.chomp
String#lines returns an array 
Also String#chars, #bytes and #codepoints 
Previously, returned enumerators 
Above are deprecated for StringIO, IO and friends 
StringIO#lines deprecated, so use #each_line instead: 
@log_stream.rewind 
- lines = @log_stream.lines.to_a 
+ lines = @log_stream.each_line.to_a 
lines.length.should == 1 
line = lines.first.chomp 
See Pull #714
Ok, great, but are we there yet???
"Fall cleanup" of old code 
"...Now I've only been an OpenBSD developer for 11 years, one year less than 
this header has existed, but in that brief time, I've learned a thing or two 
about deleting obsolete code. It doesn't delete itself. And worse, people 
will continue using it until you force them onto a better path." 
http://freshbsd.org/commit/openbsd/68dc781944a2c5b90f8b6e1069a4201750c67f94
"Fall cleanup" of old code 
"...Now I've only been an OpenBSD developer for 11 years, one year less than 
this header has existed, but in that brief time, I've learned a thing or two 
about deleting obsolete code. It doesn't delete itself. And worse, people 
will continue using it until you force them onto a better path." 
http://freshbsd.org/commit/openbsd/68dc781944a2c5b90f8b6e1069a4201750c67f94 
Git is our friend if we really want it back
"Fall cleanup" of old code 
Path to ruby 2.0...
"Fall cleanup" of old code 
Path to ruby 2.0... 
83 commits 
565 lines added 
5,553 lines deleted
"Fall cleanup" of old code 
Path to ruby 2.0... 
83 commits 
565 lines added 
5,553 lines deleted 
A good start?
"Fall cleanup" of old code 
More "opportunities" 
host directory 
soap4r/actionwebservice (fork) 
handsoap (fork) - note, useful but still forked :-( 
ruport (fork) 
ziya (fork) - patches rails! 
prototype 
old rails plugins 
old gems 
old monkey patches
Slow tests 
Tests take 30+ minutes on CI servers 
Separate tests 
Minimizing setup (database inserts) 
Remove invalid/not useful/duplicate tests 
Allocation tracing with ruby 2.1 
Cut support for 1.9.3 when 2.0 is stable
Building 2.0 appliances 
Verified Ruby 2.0 on CentOS appliance: 
Appliance startup 
SmartState Analysis "fleecing" using vddk 
vCenter inventory 
Basic reporting
Building 2.0 appliances 
Goal: automate building ruby 2.0 appliances 
We currently use ruby 1.9.3 through SCL rpms 
Not multi-platform 
Restricts updating of some gems 
Ruby 2.1 is not yet packaged as SCL rpms
Building 2.0 appliances 
Solution: 
rpms for base CentOS OS 
rpms needed to build ruby and compiled gems 
libxml2-devel, libxslt-devel, etc.
Building 2.0 appliances 
Solution: 
rpms for base CentOS OS 
rpms needed to build ruby and compiled gems 
libxml2-devel, libxslt-devel, etc. 
Use ruby-install or ruby-build for building ruby 
https://github.com/postmodern/ruby-install 
https://github.com/sstephenson/ruby-build
Building 2.0 appliances 
Solution: 
rpms for base CentOS OS 
rpms needed to build ruby and compiled gems 
libxml2-devel, libxslt-devel, etc. 
Use ruby-install or ruby-build for building ruby 
https://github.com/postmodern/ruby-install 
https://github.com/sstephenson/ruby-build 
Let bundler handle what it does well...
Developer setup 
2.0.0 is not much different from 1.9.3: 
Install using rvm, ruby-install, or ruby-build 
Manage with rvm, rbenv, or chruby 
Need guinea pigs to try it and document any issues 
Others tools, such as rubymine, may require some configuration
Links 
2.0 open issues: https://github.com/ManageIQ/manageiq/labels/ruby%202 
2.0 closed issues: https://github.com/ManageIQ/manageiq/issues? 
q=label%3A%22ruby+2%22+is%3Aclosed 
2.0 in depth: http://globaldev.co.uk/2013/03/ruby-2-0-0-in-detail/ 
2.1 in depth: http://globaldev.co.uk/2014/05/ruby-2-1-in-detail/ 
Slides available here: https://github.com/jrafanie/manageiq_summit_ruby20 
Slides written in markdown using remarkjs: http://remarkjs.com/#1
uestions?

More Related Content

PDF
Managing Puppet using MCollective
ODP
Mcollective introduction
KEY
Puppet for dummies - ZendCon 2011 Edition
PDF
Puppet Camp DC 2014: Managing Puppet with MCollective
PDF
Test Driven Development with Puppet - PuppetConf 2014
PDF
“warpdrive”, making Python web application deployment magically easy.
ODP
Introduction to Python Celery
PDF
Data processing with celery and rabbit mq
Managing Puppet using MCollective
Mcollective introduction
Puppet for dummies - ZendCon 2011 Edition
Puppet Camp DC 2014: Managing Puppet with MCollective
Test Driven Development with Puppet - PuppetConf 2014
“warpdrive”, making Python web application deployment magically easy.
Introduction to Python Celery
Data processing with celery and rabbit mq

What's hot (20)

PDF
Antons Kranga Building Agile Infrastructures
PDF
Advanced task management with Celery
PDF
Introduction to Marionette Collective
PDF
Celery with python
PDF
DevOps(3) : Ansible - (MOSG)
PDF
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
PDF
Scaling up task processing with Celery
PDF
Introduction to MCollective - SF PUG
PDF
Building and Testing from Scratch a Puppet Environment with Docker - PuppetCo...
PDF
Introduction to orchestration using Mcollective
PDF
The MetaCPAN VM for Dummies Part One (Installation)
KEY
PyCon US 2012 - Web Server Bottlenecks and Performance Tuning
PDF
Pro Puppet
PDF
Beaker: Automated, Cloud-Based Acceptance Testing - PuppetConf 2014
PDF
Performance Tuning Your Puppet Infrastructure - PuppetConf 2014
PDF
The Puppet Master on the JVM - PuppetConf 2014
PDF
Celery
KEY
PyCon US 2012 - State of WSGI 2
PDF
Scaling Django with gevent
PPTX
Django deployment best practices
Antons Kranga Building Agile Infrastructures
Advanced task management with Celery
Introduction to Marionette Collective
Celery with python
DevOps(3) : Ansible - (MOSG)
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Scaling up task processing with Celery
Introduction to MCollective - SF PUG
Building and Testing from Scratch a Puppet Environment with Docker - PuppetCo...
Introduction to orchestration using Mcollective
The MetaCPAN VM for Dummies Part One (Installation)
PyCon US 2012 - Web Server Bottlenecks and Performance Tuning
Pro Puppet
Beaker: Automated, Cloud-Based Acceptance Testing - PuppetConf 2014
Performance Tuning Your Puppet Infrastructure - PuppetConf 2014
The Puppet Master on the JVM - PuppetConf 2014
Celery
PyCon US 2012 - State of WSGI 2
Scaling Django with gevent
Django deployment best practices
Ad

Similar to Design Summit - Migrating to Ruby 2 - Joe Rafaniello (20)

KEY
Speedy TDD with Rails
PDF
How Puppet Enables the Use of Lightweight Virtualized Containers - PuppetConf...
PPTX
Puppet quick start guide
PDF
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
PDF
Strategies for Puppet code upgrade and refactoring
PDF
Lessons Learnt in 2009
PDF
Test Driven Development
PPTX
DevOps Hackathon: Session 3 - Test Driven Infrastructure
KEY
把鐵路開進視窗裡
PDF
Continuous Delivery with Maven, Puppet and Tomcat - ApacheCon NA 2013
KEY
Ruby and Rails Packaging to Production
PDF
Writing & Sharing Great Modules on the Puppet Forge
PDF
Testing Legacy Rails Apps
PDF
Moo at System::Image::Update
PDF
Infrastructureascode slideshare-160331143725
PPTX
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
PDF
Infrastructureascode slideshare-160331143725
PDF
Writing & Sharing Great Modules - Puppet Camp Boston
PDF
JS Lab2017_Андрей Кучеренко _Разработка мультипакетных приложения: причины, с...
PPTX
Puppet At Twitter - Puppet Camp Silicon Valley
Speedy TDD with Rails
How Puppet Enables the Use of Lightweight Virtualized Containers - PuppetConf...
Puppet quick start guide
Adopt DevOps philosophy on your Symfony projects (Symfony Live 2011)
Strategies for Puppet code upgrade and refactoring
Lessons Learnt in 2009
Test Driven Development
DevOps Hackathon: Session 3 - Test Driven Infrastructure
把鐵路開進視窗裡
Continuous Delivery with Maven, Puppet and Tomcat - ApacheCon NA 2013
Ruby and Rails Packaging to Production
Writing & Sharing Great Modules on the Puppet Forge
Testing Legacy Rails Apps
Moo at System::Image::Update
Infrastructureascode slideshare-160331143725
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructureascode slideshare-160331143725
Writing & Sharing Great Modules - Puppet Camp Boston
JS Lab2017_Андрей Кучеренко _Разработка мультипакетных приложения: причины, с...
Puppet At Twitter - Puppet Camp Silicon Valley
Ad

More from ManageIQ (20)

PPTX
ManageIQ - Sprint 268 Review - Slide Deck
PPTX
ManageIQ - Sprint 267 Review - Slide Deck
PPTX
ManageIQ - Sprint 266 Review - Slide Deck
PPTX
ManageIQ - Sprint 265 Review - Slide Deck
PPTX
ManageIQ - Sprint 264 Review - Slide Deck
PPTX
ManageIQ - Sprint 263 Review - Slide Deck
PPTX
ManageIQ - Sprint 262 Review - Slide Deck
PPTX
ManageIQ - Sprint 260 & 261 Review - Slide Deck
PPTX
ManageIQ - Sprint 259 Review - Slide Deck
PPTX
ManageIQ - Sprint 258 Review - Slide Deck
PPTX
ManageIQ - Sprint 257 Review - Slide Deck
PPTX
ManageIQ - Sprint 256 Review - Slide Deck
PPTX
ManageIQ - Sprint 255 Review - Slide Deck
PPTX
ManageIQ - Sprint 254 Review - Slide Deck
PPTX
ManageIQ - Sprint 247 Review - Slide Deck
PPTX
ManageIQ - Sprint 253 Review - Slide Deck
PPTX
ManageIQ - Sprint 252 Review - Slide Deck
PPTX
ManageIQ - Sprint 251 Review - Slide Deck
PPTX
ManageIQ - Sprint 250 Review - Slide Deck
PPTX
ManageIQ - Sprint 249 Review - Slide Deck
ManageIQ - Sprint 268 Review - Slide Deck
ManageIQ - Sprint 267 Review - Slide Deck
ManageIQ - Sprint 266 Review - Slide Deck
ManageIQ - Sprint 265 Review - Slide Deck
ManageIQ - Sprint 264 Review - Slide Deck
ManageIQ - Sprint 263 Review - Slide Deck
ManageIQ - Sprint 262 Review - Slide Deck
ManageIQ - Sprint 260 & 261 Review - Slide Deck
ManageIQ - Sprint 259 Review - Slide Deck
ManageIQ - Sprint 258 Review - Slide Deck
ManageIQ - Sprint 257 Review - Slide Deck
ManageIQ - Sprint 256 Review - Slide Deck
ManageIQ - Sprint 255 Review - Slide Deck
ManageIQ - Sprint 254 Review - Slide Deck
ManageIQ - Sprint 247 Review - Slide Deck
ManageIQ - Sprint 253 Review - Slide Deck
ManageIQ - Sprint 252 Review - Slide Deck
ManageIQ - Sprint 251 Review - Slide Deck
ManageIQ - Sprint 250 Review - Slide Deck
ManageIQ - Sprint 249 Review - Slide Deck

Recently uploaded (20)

PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Modernizing your data center with Dell and AMD
PDF
cuic standard and advanced reporting.pdf
PDF
Machine learning based COVID-19 study performance prediction
PPTX
Cloud computing and distributed systems.
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
Encapsulation theory and applications.pdf
Unlocking AI with Model Context Protocol (MCP)
Modernizing your data center with Dell and AMD
cuic standard and advanced reporting.pdf
Machine learning based COVID-19 study performance prediction
Cloud computing and distributed systems.
Understanding_Digital_Forensics_Presentation.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Dropbox Q2 2025 Financial Results & Investor Presentation
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
NewMind AI Weekly Chronicles - August'25 Week I
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Chapter 3 Spatial Domain Image Processing.pdf
20250228 LYD VKU AI Blended-Learning.pptx
Spectral efficient network and resource selection model in 5G networks
Network Security Unit 5.pdf for BCA BBA.
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Encapsulation theory and applications.pdf

Design Summit - Migrating to Ruby 2 - Joe Rafaniello

  • 1. Upgrading to Ruby 2.x Joe Rafaniello @jrafanie
  • 3. 13
  • 4. Agenda 1. History 2. Why upgrade? 3. Ruby 2.1 4. Ruby 2.0 5. "Fall cleanup" of old code 6. Slow tests 7. Building 2.0 appliances 8. Developer setup 9. Links 10. Questions?
  • 5. History Tue Nov 1 2011: First ruby 1.8.7 -> 1.9.3 related commit on ManageIQ
  • 6. History Tue Nov 1 2011: First ruby 1.8.7 -> 1.9.3 related commit on ManageIQ Tue Apr 23 2013: Ruby 1.9.3 finally...
  • 7. History Tue Nov 1 2011: First ruby 1.8.7 -> 1.9.3 related commit on ManageIQ Tue Apr 23 2013: Ruby 1.9.3 finally... 540 days???
  • 8. History Tue Nov 1 2011: First ruby 1.8.7 -> 1.9.3 related commit on ManageIQ Tue Apr 23 2013: Ruby 1.9.3 finally... 540 days??? Lesson learned: Don't wait to upgrade!
  • 10. Why upgrade? We're behind!!! Ruby 1.9.3 is ending In maintenance until February 23, 2014 Security only mode until February 23, 2015 Ruby 2.0.0 is nearly 20 months old Ruby 2.1.0 is nearly 10 months old Ruby 2.2.0 is scheduled for a Christmas release
  • 11. Why upgrade? ... Because ruby 2.1! Generational mark and sweep garbage collector http://tmm1.net/ruby21-rgengc/ String#freeze - reuse String objects Less objects == less memory == less GC time Object allocation tracing http://tmm1.net/ruby21-objspace/ https://github.com/srawlins/allocation_stats Required keyword arguments def returns method name Exception#cause - ActiveRecord::StatementInvalid#cause -> Real error More...
  • 12. Why upgrade? ... Because ruby 2.1! Useless benchmark bundle exec rspec spec/models/ems_refresh/refreshers 1.9.3-p545 70.85s user 2.23s system 96% cpu 1:15.98 total 71.21s user 2.22s system 96% cpu 1:16.27 total
  • 13. Why upgrade? ... Because ruby 2.1! Useless benchmark bundle exec rspec spec/models/ems_refresh/refreshers 1.9.3-p545 70.85s user 2.23s system 96% cpu 1:15.98 total 71.21s user 2.22s system 96% cpu 1:16.27 total 2.0.0-p576 54.02s user 2.03s system 95% cpu 58.980 total 49.96s user 2.14s system 94% cpu 54.923 total
  • 14. Why upgrade? ... Because ruby 2.1! Useless benchmark bundle exec rspec spec/models/ems_refresh/refreshers 1.9.3-p545 70.85s user 2.23s system 96% cpu 1:15.98 total 71.21s user 2.22s system 96% cpu 1:16.27 total 2.0.0-p576 54.02s user 2.03s system 95% cpu 58.980 total 49.96s user 2.14s system 94% cpu 54.923 total 2.1.3 36.52s user 2.79s system 91% cpu 42.930 total 35.68s user 2.22s system 92% cpu 40.768 total
  • 15. Why upgrade? ... Because ruby 2.1! Example allocation information: Line number Number of allocations by object type Such as: Running: ./spec/controllers/application_controller/buttons_spec.rb:91 223730 Arrays @ .../activerecord/lib/active_record/result.rb:35 203280 Strings @ .../activerecord/lib/active_record/relation.rb:27
  • 16. Why upgrade? ... Because ruby 2.1! Example allocation information: Line number Number of allocations by object type Such as: Running: ./spec/controllers/application_controller/buttons_spec.rb:91 223730 Arrays @ .../activerecord/lib/active_record/result.rb:35 203280 Strings @ .../activerecord/lib/active_record/relation.rb:27 See Issue 241 and 762
  • 17. But that's 2.1, let's get to 2.0 first...
  • 19. Faster Rails startup Optimizations were made to speed up 'require'
  • 20. Faster Rails startup Optimizations were made to speed up 'require' (master) (1.9.3-p545) + time bundle exec rake environment bundle exec rake environment 3.51s user 0.63s system 99% cpu 4.148 total (master) (2.0.0-p576) + time bundle exec rake environment bundle exec rake environment 2.60s user 0.53s system 99% cpu 3.132 total
  • 21. Faster Rails startup Optimizations were made to speed up 'require' (master) (1.9.3-p545) + time bundle exec rake environment bundle exec rake environment 3.51s user 0.63s system 99% cpu 4.148 total (master) (2.0.0-p576) + time bundle exec rake environment bundle exec rake environment 2.60s user 0.53s system 99% cpu 3.132 total 25% faster loading of rails environment!
  • 22. Faster Rails startup Optimizations were made to speed up 'require' (master) (1.9.3-p545) + time bundle exec rake environment bundle exec rake environment 3.51s user 0.63s system 99% cpu 4.148 total (master) (2.0.0-p576) + time bundle exec rake environment bundle exec rake environment 2.60s user 0.53s system 99% cpu 3.132 total 25% faster loading of rails environment! Most obvious when: Running tests Loading Rails console
  • 23. Keyword arguments Simplifies conventions: Accessing option hash values Default hash values Optional / can't handle all cases
  • 24. Keyword arguments Example: EmsVmware#vm_connect_all def vm_connect_all(vm, options={}) defaults = { :onStartup => false } options = defaults.merge(options) vm_connect_disconnect_all_connectable_devices( vm, true, options[:onStartup], options[:user_event] ) end
  • 25. Keyword arguments Example: EmsVmware#vm_connect_all def vm_connect_all(vm, options={}) defaults = { :onStartup => false } options = defaults.merge(options) vm_connect_disconnect_all_connectable_devices( vm, true, options[:onStartup], options[:user_event] ) end With keyword arguments: def vm_connect_all(vm, user_event: nil, onStartup: false) vm_connect_disconnect_all_connectable_devices(vm, true, onStartup, user_event) end
  • 26. Keyword arguments Invoking methods not changed Valid on 1.9.3 / 2.0.0: vm_connect_all(:vm_object1, :onStartup => true, :user_event => "event1") vm_connect_all(:vm_object2) vm_connect_all(:vm_object3, :user_event => "event3") vm_connect_all(:vm_object3, user_event: "event3")
  • 27. Keyword arguments Shortcomings and gotchas: if - valid hash key / invalid keyword argument Required keyword arguments added in 2.1 http://magazine.rubyist.net/?Ruby200SpecialEn-kwarg http://robots.thoughtbot.com/ruby-2-keyword-arguments http://chriszetter.com/blog/2012/11/02/keyword-arguments-in-ruby-2- dot-0/
  • 28. Module#prepend Problem: We want to debug a slow method.
  • 29. Module#prepend Problem: We want to debug a slow method. Wrap the method so can time it!
  • 30. Module#prepend Using alias_method: class Parent def run puts "Parent" end end class Sub < Parent def run puts "Sub" super end def run_with puts "DebugIt" run_without end alias_method :run_without, :run alias_method :run, :run_with end
  • 31. Module#prepend Using alias_method: class Parent def run puts "Parent" end end class Sub < Parent def run puts "Sub" super end def run_with puts "DebugIt" run_without end Sub is a class with the slow run method... alias_method :run_without, :run alias_method :run, :run_with end
  • 32. class Parent def run puts "Parent" end end class Sub < Parent def run puts "Sub" super end def run_with puts "DebugIt" run_without end Sub is a class with the slow run method... alias_method :run_without, :run alias_method :run, :run_with end irb(main):01:0> Sub.new.run DebugIt Sub Parent Module#prepend Using alias_method:
  • 33. class Parent def run puts "Parent" end end class Sub < Parent def run puts "Sub" super end def run_with puts "DebugIt" run_without end Sub is a class with the slow run method... alias_method :run_without, :run alias_method :run, :run_with end irb(main):01:0> Sub.new.run DebugIt Sub Parent YAY! But that's really dirty! (alias_method_chain) Module#prepend Using alias_method:
  • 34. Module#prepend Using include: module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent include DebugIt def run puts "Sub" super end end
  • 35. module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent include DebugIt def run puts "Sub" super end end Sub is a class with the slow run method... Module#prepend Using include:
  • 36. module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent include DebugIt def run puts "Sub" super end end Sub is a class with the slow run method... irb(main):002:0> Sub.ancestors => [Sub, DebugIt, Parent, Object, Kernel, BasicObject] Module#prepend Using include:
  • 37. module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent include DebugIt def run puts "Sub" super end end Sub is a class with the slow run method... irb(main):002:0> Sub.ancestors => [Sub, DebugIt, Parent, Object, Kernel, BasicObject] irb(main):01:0> Sub.new.run Sub DebugIt Parent Module#prepend Using include:
  • 38. module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent include DebugIt def run puts "Sub" super end end Sub is a class with the slow run method... irb(main):002:0> Sub.ancestors => [Sub, DebugIt, Parent, Object, Kernel, BasicObject] irb(main):01:0> Sub.new.run Sub DebugIt Parent UGH, Sub's method comes first! Module#prepend Using include:
  • 39. Module#prepend Using prepend: module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent prepend DebugIt def run puts "Sub" super end end
  • 40. module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent prepend DebugIt def run puts "Sub" super end end irb(main):002:0> Sub.ancestors => [DebugIt, Sub, Parent, Object, Kernel, BasicObject] Module#prepend Using prepend:
  • 41. module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent prepend DebugIt def run puts "Sub" super end end irb(main):002:0> Sub.ancestors => [DebugIt, Sub, Parent, Object, Kernel, BasicObject] irb(main):01:0> Sub.new.run DebugIt Sub Parent Module#prepend Using prepend:
  • 42. module DebugIt def run puts "DebugIt" super end end class Parent def run puts "Parent" end end class Sub < Parent prepend DebugIt def run puts "Sub" super end end irb(main):002:0> Sub.ancestors => [DebugIt, Sub, Parent, Object, Kernel, BasicObject] irb(main):01:0> Sub.new.run DebugIt Sub Parent Ship it! ... but don't forget to call super! Module#prepend Using prepend:
  • 43. Array of symbols: %i and %I
  • 44. Array of symbols: %i and %I irb(main):001:0> %i{vmware redhat microsoft} => [:vmware, :redhat, :microsoft]
  • 45. Array of symbols: %i and %I irb(main):001:0> %i{vmware redhat microsoft} => [:vmware, :redhat, :microsoft] %I allows interpolation:
  • 46. Array of symbols: %i and %I irb(main):001:0> %i{vmware redhat microsoft} => [:vmware, :redhat, :microsoft] %I allows interpolation: irb(main):002:0> prefix = "vm_" => "vm_" irb(main):003:0> %I{#{prefix}vmware #{prefix}redhat #{prefix}microsoft} => [:vm_vmware, :vm_redhat, :vm_microsoft]
  • 47. Refinements Goal: localize monkey patches I'm not going to explain them because: Ruby's open classes Many gotchas... See Charles Nutter (@headius/jruby guy) explanation: http://blog.headius.com/2012/11/refining-ruby.html
  • 48. Enumerable#lazy Enumerable methods evaluate left to right With lazy, chains of enumerations are evaluated right to left
  • 49. Enumerable#lazy Enumerable methods evaluate left to right With lazy, chains of enumerations are evaluated right to left Ruby may "cheat": May skip creating intermediate objects Large collection operations may be optimized
  • 50. Enumerable#lazy Example benchmark (0...1000).select(&:odd?).take(5).to_a (0...1000).lazy.select(&:odd?).take(5).to_a What is this doing?
  • 51. Enumerable#lazy Example benchmark (0...1000).select(&:odd?).take(5).to_a (0...1000).lazy.select(&:odd?).take(5).to_a What is this doing? First 5 odd numbers => [1, 3, 5, 7, 9]
  • 52. Enumerable#lazy require 'benchmark/ips' Benchmark.ips do |x| x.report("normal") { (0...1000).select(&:odd?).take(5).to_a } x.report("lazy") { (0...1000).lazy.select(&:odd?).take(5).to_a } end
  • 53. Enumerable#lazy require 'benchmark/ips' Benchmark.ips do |x| x.report("normal") { (0...1000).select(&:odd?).take(5).to_a } x.report("lazy") { (0...1000).lazy.select(&:odd?).take(5).to_a } end Calculating ------------------------------------- normal 1539 i/100ms lazy 5778 i/100ms ------------------------------------------------- normal 15123.2 (±2.5%) i/s - 76950 in 5.091373s lazy 59797.4 (±4.0%) i/s - 300456 in 5.033123s See http://patshaughnessy.net/2013/4/3/ruby-2-0-works-hard-so-you-can-be- lazy
  • 54. __dir__ __dir__ path of the script without the filename # cat test.rb puts __dir__ # ruby test.rb /Users/joerafaniello/Code/test
  • 55. __dir__ __dir__ path of the script without the filename # cat test.rb puts __dir__ # ruby test.rb /Users/joerafaniello/Code/test We have 984 instances of File.dirname(__FILE__)! WAT...Why?
  • 56. Ruby 2.0 breaking changes and deprecations Note: We're green on travis, so we're getting close...
  • 57. Objects don't respond_to? to protected methods Ruby 1.9.3: respond_to?(symbol) => public and protected methods respond_to?(symbol, true) => all methods
  • 58. Objects don't respond_to? to protected methods Ruby 1.9.3: respond_to?(symbol) => public and protected methods respond_to?(symbol, true) => all methods Ruby 2.0.0 respond_to?(symbol) => public methods only respond_to?(symbol, true) => all methods
  • 59. Objects don't respond_to? to protected methods class Worker protected def run end end
  • 60. Objects don't respond_to? to protected methods class Worker protected def run end end Worker.new.respond_to?(:run) 1.9.3 => true 2.0.0 => false
  • 61. Objects don't respond_to? to protected methods class Worker protected def run end end Worker.new.respond_to?(:run) 1.9.3 => true 2.0.0 => false Pass true as second argument... Worker.new.respond_to?(:run, true) 1.9.3 => true 2.0.0 => true
  • 62. Objects don't respond_to? to protected methods class Worker protected def run end end Worker.new.respond_to?(:run) 1.9.3 => true 2.0.0 => false Pass true as second argument... Worker.new.respond_to?(:run, true) 1.9.3 => true 2.0.0 => true See Pull #685 - default_value_for gem
  • 63. UTF-8 is the default character encoding of ruby scripts # cat test.rb FOO = "222dL256"
  • 64. UTF-8 is the default character encoding of ruby scripts # cat test.rb FOO = "222dL256" Ruby 1.9.3 US-ASCII is the default encoding of ruby scripts
  • 65. UTF-8 is the default character encoding of ruby scripts # cat test.rb FOO = "222dL256" Ruby 1.9.3 US-ASCII is the default encoding of ruby scripts Binary string literals become ASCII-8BIT:
  • 66. UTF-8 is the default character encoding of ruby scripts # cat test.rb FOO = "222dL256" Ruby 1.9.3 US-ASCII is the default encoding of ruby scripts Binary string literals become ASCII-8BIT: irb(main):001:0> require './test' => true irb(main):002:0> FOO.encoding => #<Encoding:ASCII-8BIT>
  • 67. UTF-8 is the default character encoding of ruby scripts # cat test.rb FOO = "222dL256"
  • 68. UTF-8 is the default character encoding of ruby scripts # cat test.rb FOO = "222dL256" Ruby 2.0.0 UTF-8 is the default encoding
  • 69. UTF-8 is the default character encoding of ruby scripts # cat test.rb FOO = "222dL256" Ruby 2.0.0 UTF-8 is the default encoding Binary string literals become UTF-8 even if invalid: irb(main):001:0> require './test' => true irb(main):002:0> FOO.encoding => #<Encoding:UTF-8> irb(main):003:0> FOO.valid_encoding? => false
  • 70. UTF-8 is the default character encoding of ruby scripts So, what's the problem? Binary strings are used in many places for vm "fleecing" Invalid UTF-8 encoded strings != raw binary:
  • 71. UTF-8 is the default character encoding of ruby scripts So, what's the problem? Binary strings are used in many places for vm "fleecing" Invalid UTF-8 encoded strings != raw binary: irb(main):003:0> FOO.valid_encoding? => false irb(main):004:0> FOO == "222dL256".force_encoding("ASCII-8BIT") => false
  • 72. UTF-8 is the default character encoding of ruby scripts Solutions: Force binary on individual Strings: 1.9.3/2.0.0 compatible Painful on files with many binary string literals
  • 73. UTF-8 is the default character encoding of ruby scripts Solutions: Force binary on individual Strings: 1.9.3/2.0.0 compatible Painful on files with many binary string literals # cat test.rb FOO = "222dL256".force_encoding("ASCII-8BIT")
  • 74. UTF-8 is the default character encoding of ruby scripts Solutions: Force binary on individual Strings: 1.9.3/2.0.0 compatible Painful on files with many binary string literals # cat test.rb FOO = "222dL256".force_encoding("ASCII-8BIT") irb(main):001:0> require './test' => true irb(main):002:0> FOO.encoding => #<Encoding:ASCII-8BIT> irb(main):003:0> FOO.valid_encoding? => true irb(main):004:0> FOO == "222dL256".force_encoding("ASCII-8BIT") => true
  • 75. UTF-8 is the default character encoding of ruby scripts Solutions: Use String#b on individual strings Not compatible with ruby 1.9.3 Copies the String in ASCII-8BIT encoding Note: String#force_encoding("ASCII-8BIT") modifies the receiver
  • 76. UTF-8 is the default character encoding of ruby scripts Solutions: Add #encoding magic comment at top 1.9.3/2.0.0 compatible Good option when binary strings are expected
  • 77. UTF-8 is the default character encoding of ruby scripts Solutions: Add #encoding magic comment at top 1.9.3/2.0.0 compatible Good option when binary strings are expected # cat test.rb # encoding: US-ASCII FOO = "222dL256"
  • 78. UTF-8 is the default character encoding of ruby scripts Solutions: Add #encoding magic comment at top 1.9.3/2.0.0 compatible Good option when binary strings are expected # cat test.rb # encoding: US-ASCII FOO = "222dL256" irb(main):001:0> require './test' => true irb(main):002:0> FOO.encoding => #<Encoding:ASCII-8BIT>
  • 79. Descriptors except 0, 1, 2 are closed in child processes Prevents file descriptor leakage See Pull #682, Issue #459, and https://bugs.ruby-lang.org/issues/5041
  • 80. Descriptors except 0, 1, 2 are closed in child processes Prevents file descriptor leakage See Pull #682, Issue #459, and https://bugs.ruby-lang.org/issues/5041 Example: shared pipe to communicate data between two processes
  • 81. Descriptors except 0, 1, 2 are closed in child processes Prevents file descriptor leakage See Pull #682, Issue #459, and https://bugs.ruby-lang.org/issues/5041 Example: shared pipe to communicate data between two processes Use IO#close_on_exec = false reader, writer = IO.pipe writerfd = writer.fileno my_env["WRITER_FD"] = writerfd.to_s + + writer.close_on_exec = false + pid = Kernel.spawn(my_env, "ruby #{SERVER_PATH}VixDiskLibServer.rb", [:out, :err] => [LOG_FILE, "a"], :unsetenv_others => true,
  • 82. String#lines returns an array Also String#chars, #bytes and #codepoints Previously, returned enumerators Above are deprecated for StringIO, IO and friends
  • 83. String#lines returns an array Also String#chars, #bytes and #codepoints Previously, returned enumerators Above are deprecated for StringIO, IO and friends StringIO#lines deprecated, so use #each_line instead: @log_stream.rewind - lines = @log_stream.lines.to_a + lines = @log_stream.each_line.to_a lines.length.should == 1 line = lines.first.chomp
  • 84. String#lines returns an array Also String#chars, #bytes and #codepoints Previously, returned enumerators Above are deprecated for StringIO, IO and friends StringIO#lines deprecated, so use #each_line instead: @log_stream.rewind - lines = @log_stream.lines.to_a + lines = @log_stream.each_line.to_a lines.length.should == 1 line = lines.first.chomp See Pull #714
  • 85. Ok, great, but are we there yet???
  • 86. "Fall cleanup" of old code "...Now I've only been an OpenBSD developer for 11 years, one year less than this header has existed, but in that brief time, I've learned a thing or two about deleting obsolete code. It doesn't delete itself. And worse, people will continue using it until you force them onto a better path." http://freshbsd.org/commit/openbsd/68dc781944a2c5b90f8b6e1069a4201750c67f94
  • 87. "Fall cleanup" of old code "...Now I've only been an OpenBSD developer for 11 years, one year less than this header has existed, but in that brief time, I've learned a thing or two about deleting obsolete code. It doesn't delete itself. And worse, people will continue using it until you force them onto a better path." http://freshbsd.org/commit/openbsd/68dc781944a2c5b90f8b6e1069a4201750c67f94 Git is our friend if we really want it back
  • 88. "Fall cleanup" of old code Path to ruby 2.0...
  • 89. "Fall cleanup" of old code Path to ruby 2.0... 83 commits 565 lines added 5,553 lines deleted
  • 90. "Fall cleanup" of old code Path to ruby 2.0... 83 commits 565 lines added 5,553 lines deleted A good start?
  • 91. "Fall cleanup" of old code More "opportunities" host directory soap4r/actionwebservice (fork) handsoap (fork) - note, useful but still forked :-( ruport (fork) ziya (fork) - patches rails! prototype old rails plugins old gems old monkey patches
  • 92. Slow tests Tests take 30+ minutes on CI servers Separate tests Minimizing setup (database inserts) Remove invalid/not useful/duplicate tests Allocation tracing with ruby 2.1 Cut support for 1.9.3 when 2.0 is stable
  • 93. Building 2.0 appliances Verified Ruby 2.0 on CentOS appliance: Appliance startup SmartState Analysis "fleecing" using vddk vCenter inventory Basic reporting
  • 94. Building 2.0 appliances Goal: automate building ruby 2.0 appliances We currently use ruby 1.9.3 through SCL rpms Not multi-platform Restricts updating of some gems Ruby 2.1 is not yet packaged as SCL rpms
  • 95. Building 2.0 appliances Solution: rpms for base CentOS OS rpms needed to build ruby and compiled gems libxml2-devel, libxslt-devel, etc.
  • 96. Building 2.0 appliances Solution: rpms for base CentOS OS rpms needed to build ruby and compiled gems libxml2-devel, libxslt-devel, etc. Use ruby-install or ruby-build for building ruby https://github.com/postmodern/ruby-install https://github.com/sstephenson/ruby-build
  • 97. Building 2.0 appliances Solution: rpms for base CentOS OS rpms needed to build ruby and compiled gems libxml2-devel, libxslt-devel, etc. Use ruby-install or ruby-build for building ruby https://github.com/postmodern/ruby-install https://github.com/sstephenson/ruby-build Let bundler handle what it does well...
  • 98. Developer setup 2.0.0 is not much different from 1.9.3: Install using rvm, ruby-install, or ruby-build Manage with rvm, rbenv, or chruby Need guinea pigs to try it and document any issues Others tools, such as rubymine, may require some configuration
  • 99. Links 2.0 open issues: https://github.com/ManageIQ/manageiq/labels/ruby%202 2.0 closed issues: https://github.com/ManageIQ/manageiq/issues? q=label%3A%22ruby+2%22+is%3Aclosed 2.0 in depth: http://globaldev.co.uk/2013/03/ruby-2-0-0-in-detail/ 2.1 in depth: http://globaldev.co.uk/2014/05/ruby-2-1-in-detail/ Slides available here: https://github.com/jrafanie/manageiq_summit_ruby20 Slides written in markdown using remarkjs: http://remarkjs.com/#1