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: 15
Method 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=75
Keyrest 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
# => :foo
Useful 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,016