Cool Ruby Features

Flip Flop Operator
in ruby since the dawn of time
Example
(1..15).each do |x|
  if (x == 5) .. (x == 10)
    puts "true: #{x}"
  else
    puts "false: #{x}"
  end
end
# false: 1
# false: 2
# false: 3
# false: 4
(1..15).each do |x|
  if (x == 5) .. (x == 10)
    puts "true: #{x}"
  else
    puts "false: #{x}"
  end
end
# false: 1
# false: 2
# false: 3
# false: 4
# true: 5
# true: 6
# true: 7
# true: 8
# true: 9
# true: 10
(1..15).each do |x|
  if (x == 5) .. (x == 10)
    puts "true: #{x}"
  else
    puts "false: #{x}"
  end
end
# false: 1
# false: 2
# false: 3
# false: 4
# true: 5
# true: 6
# true: 7
# true: 8
# true: 9
# true: 10
# false: 11
# false: 12
# false: 13
# false: 14
# false: 15Method Arguments
2.0+
Optional arguments
def some_method(a, b, *p, q)
end
some_method(25, 35, 45, 55)
#=> a=25, b=35, p=[45], q=55
some_method(25, 35, 45)
#=> a=25, b=35, p=[], q=45
some_method(25, 35, 45, 55, 65, 75)
#=> a=25, b=35, p=[45,55,65], q=75
def some_method(a, b, c=5, *p, q)
end
some_method(25, 35, 45) 
#=> a=25, b=35, c=5, p=[], q=45
some_method(25, 35, 45, 55)
#=>a=25, b=35, c=45, p=[], q=55
some_method(25, 35, 45, 55, 65)
#=> a=25, b=35, c=45, p=[55], q=65
some_method(25, 35, 45, 55, 65, 75)
#=> a=25, b=35, c=45, p=[55,65], q=75Keyrest Argument
def create_party(place,time,**options)
  puts "place: #{place}, time: #{time}, options: #{options}"
end
def create_party(place,time,**options)
  puts "place: #{place}, time: #{time}, options: #{options}"
end
create_party("Club","Evening",{vodka: 'lots'})
# place: Club, time: Evening, options: {:vodka=>"lots"}
def create_party(place,time,**options)
  puts "place: #{place}, time: #{time}, options: #{options}"
end
create_party("Club","Evening",{vodka: 'lots'})
# place: Club, time: Evening, options: {:vodka=>"lots"}
create_party("Club","Evening",{music: 'loud', party: 'hard'})
# place: Club, time: Evening, options: {:music=>"loud", :party=>"hard"}
def create_party(place,time,**options)
  puts "place: #{place}, time: #{time}, options: #{options}"
end
create_party("Club","Evening",{vodka: 'lots'})
# place: Club, time: Evening, options: {:vodka=>"lots"}
create_party("Club","Evening",{music: 'loud', party: 'hard'})
# place: Club, time: Evening, options: {:music=>"loud", :party=>"hard"}
create_party("Church","Morning")
# place: Church, time: Morning, options: {}
def create_party(place,time,**options)
  puts "place: #{place}, time: #{time}, options: #{options}"
end
create_party("Club","Evening",{vodka: 'lots'})
# place: Club, time: Evening, options: {:vodka=>"lots"}
create_party("Club","Evening",{music: 'loud', party: 'hard'})
# place: Club, time: Evening, options: {:music=>"loud", :party=>"hard"}
create_party("Church","Morning")
# place: Church, time: Morning, options: {}
create_party("Home", "Tomorrow", "Crasher")
# ArgumentError: wrong number of arguments (3 for 2)
# from (irb):4:in `create_party'
# from (irb):10
# from /Users/bartek/.rvm/rubies/ruby-2.0.0-p576/bin/irb:12:in `<main>'
Keyword Arguments
def m(foo: 1, bar: 2)
  [foo, bar]
end
def m(foo: 1, bar: 2)
  [foo, bar]
end
m 
# => [1, 2]
def m(foo: 1, bar: 2)
  [foo, bar]
end
m 
# => [1, 2]
m(1, 2)
# => ArgumentError
def m(foo: 1, bar: 2)
  [foo, bar]
end
m 
# => [1, 2]
m(1, 2)
# => ArgumentError
m(foo: 2) 
# => [2, 2]
m(bar: 1) 
# => [1, 1]
m(foo: 3, bar: 3) 
# => [3, 3]
Keyword Arguments
def m(foo: 1, **opts)
  [foo, opts]
end
def m(foo: 1, **opts)
  [foo, opts]
end
m(foo: 1, bar: 2) 
# => [1, {:bar=>2}]
m(bar: 2) 
# => [1, {:bar=>2}]
def m(foo: 1, **opts)
  [foo, opts]
end
m(foo: 1, bar: 2) 
# => [1, {:bar=>2}]
m(bar: 2) 
# => [1, {:bar=>2}]
def m(foo: 1)
  foo
end
m(bar: 2) 
# => ArgumentError
def m(foo: 1, **opts)
  [foo, opts]
end
m(foo: 1, bar: 2) 
# => [1, {:bar=>2}]
m(bar: 2) 
# => [1, {:bar=>2}]
def m(foo: 1)
  foo
end
m(bar: 2) 
# => ArgumentError
def m(foo, *bar, baz, qux: 1, **opts)
  [foo, bar, baz, qux, opts]
end
m(1, 2, 3, 4, 5, quux: 6) 
# => [1, [2, 3, 4], 5, 1, {:quux=>6}]
def m(foo: 1, **opts)
  [foo, opts]
end
m(foo: 1, bar: 2) 
# => [1, {:bar=>2}]
m(bar: 2) 
# => [1, {:bar=>2}]
def m(foo: 1)
  foo
end
m(bar: 2) 
# => ArgumentError
def m(foo, *bar, baz, qux: 1, **opts)
  [foo, bar, baz, qux, opts]
end
m(1, 2, 3, 4, 5, quux: 6) 
# => [1, [2, 3, 4], 5, 1, {:quux=>6}]
m(1, 2, 3, 4, 5, 6) 
# => [1, [2, 3, 4, 5], 6, 1, {}]
def m(foo: 1, **opts)
  [foo, opts]
end
m(foo: 1, bar: 2) 
# => [1, {:bar=>2}]
m(bar: 2) 
# => [1, {:bar=>2}]
def m(foo: 1)
  foo
end
m(bar: 2) 
# => ArgumentError
def m(foo, *bar, baz, qux: 1, **opts)
  [foo, bar, baz, qux, opts]
end
m(1, 2, 3, 4, 5, quux: 6) 
# => [1, [2, 3, 4], 5, 1, {:quux=>6}]
m(1, 2, 3, 4, 5, 6) 
# => [1, [2, 3, 4, 5], 6, 1, {}]
m(1, 2, qux: 3) 
# => [1, [], 2, 3, {}]
Keyword Arguments
# Block parameters can use keyword arguments:
def m
  yield bar: 3
end
m do |foo: 1, bar: 2|
  [foo, bar]
end # => [1, 3]
# Block parameters can use keyword arguments:
def m
  yield bar: 3
end
m do |foo: 1, bar: 2|
  [foo, bar]
end # => [1, 3]
# Putting it all together:
define_method(:m) do |foo, *bar, baz, qux: 1, **opts, &blk; a, b|
  [foo, bar, baz, qux, opts, blk]
end
method(:m).parameters # => [[:req, :foo], [:rest, :bar], [:req, :baz], [:key, :qux], [:keyrest, :opts], [:block, :blk]]
m(1, 2, 3, qux: 4, quux: 5) { } # => [1, [2], 3, 4, {:quux=>5}, #<Proc:0x83bbfc@kwargs.rb:67>]
Symbol Literal Syntax
2.0+
%w(kiedy swieca zgasnie)
#=> ['kiedy','swieca','zgasnie']
%i(to jest ciemno)
#=> [:to, :jest, :ciemno]%i like %w and others
Improved Numbers
2.1+
Complex Numbers
# 2.0
Complex(2, 3)
#=> (2+3i)
(2+3i)
#=> SyntaxError
# 2.1
(2+3i)
#=> (2+3i)
(2+3i) + Complex(5, 4i)
#=> (3+3i)Rational Shorthand
# ruby 2.0
2/3.0 + 5/4.0
# => 1.9166666666666665
# ruby 2.1
2/3r + 5/4r
# => (23/12)Method Definitions
2.1+
def's return value
# ruby 2.0
def foo; end
# => nil
# ruby 2.1
def foo; end
# => :fooUseful with private methods
class Foo
  # ruby 2.0
  def public
  end
  def private_1
  end
  private :private_1
  private
  def private_2
  end
end
class Foo
  # ruby 2.1
  def public
  end
  private def private_1
  end
end
Refinements
2.1+
Good bye monkey patching
# party.rb
module Party
  refine String do
    def bartek_other
      "bartek other"
    end
  end
end
# refinements.rb
require './party'
module Party
  refine String do
    def bartek
      "bartek"
    end
  end
end
class Test
  using Party
  def initialize
    puts "test".bartek
    puts "test".bartek_other
  end
end
# file_scope.rb
require './refinements.rb'
class Test
  def string_party
    "string".bartek
  end
end
test = Test.new
# => 'bartek'
# => 'bartek_other'
puts test.string_party
# => `string_party': undefined method `bartek' for "string":String (NoMethodError)
Works only within current class:
# refinements_parent.rb
require './party'
class BaseTest
  using Party
end
# refinements_inheritance.rb
require './refinements_parent'
class Test < BaseTest
  def initialize
    puts "test".bartek_other
  end
end
Test.new
# => undefined method `bartek_other' for "test":String (NoMethodError)No nesting - clarity first
# refinements_nesting.rb
require './bigger_party'
class Test
  using BiggerParty
  def initialize
    puts "test".bigger_bartek
    puts "test".bartek_other
  end
end
Test.new
# => faaaaaat
# => `initialize': undefined method `bartek_other' for "test":String (NoMethodError)# bigger_party.rb
require './party'
module BiggerParty
  using Party
  refine String do
    def bigger_bartek
      'faaaaaat'
    end
  end
end
Static Typing
3.0 proposal
Soft Typing
a = 1 # the type of a is now Integer
a = 1 # the type of a is now Integer
def foo(x)
  x.to_int  # now all x must have .to_int
end
foo(1)   # OK
foo('a') # no good! doesn't have to_int!Questions?
Cool Ruby Features
By Bartek Kruszczyński
Cool Ruby Features
- 1,136
 
   
   
  