https://www.ruby-lang.org/en/news/2017/12/25/ruby-2-5-0-released/
- rescue/else/ensure in do..end blocks :
# https://bugs.ruby-lang.org/issues/12906
my_func = lamdbda do
begin
# do something
rescue SomeException
# do something else
end
end
# New syntax
my_func = lamdbda do
# do something
rescue SomeException
# do something else
end
- yield_self vs tap
# .tap
foo = 123
bar = {}
foo.tap { |n| bar[:a] = n } # => 123
bar # => {:a=>123}
# .yield_self
123.yield_self { |n| {a: n} } # => {:a=>123}
- hash slice and transform_keys
# feature backported from ActiveSupport
foo = {a: 1, b: 2, c: 3} # => {:a=>1, :b=>2, :c=>3}
foo.slice(:a, :c, :d) # => {:a=>1, :c=>3}
foo.transform_keys { |k| k.to_s.upcase } # => {"A"=>1, "B"=>2, "C"=>3}
- Enumerable accept blocks on several methods
(1...5).any? { |x| x < 4 }
(1...5).none? { |x| x > 4 }
(1...5).all? { |x| x > 0 }
(1...5).one? { |x| x == 1 }
https://www.ruby-lang.org/en/news/2018/12/25/ruby-2-6-0-released/
https://www.rubyguides.com/2018/11/ruby-2-6-new-features/
https://www.ghostcassette.com/function-composition-in-ruby/
- alias yield_self with then
123.then { |n| {a: n} } # => {:a=>123}
- endless range support
# ruby 2.5
(1.. Float::INFINITY).last # => Infinity
# New implementation
(1..).last # RangeError (cannot get the last element of endless range)
# Sample usage
["a", "b", "c"].zip(1..)
[1,2,3,4,5][1..]
(1..).step(5).take(100)
- Enumerable#chain
(1..3).chain(2..5) # => #<Enumerator::Chain: [1..3, 2..5]>
(1..3).chain(2..5).to_a # => [1, 2, 3, 2, 3, 4, 5]
[1,2,3].chain([2, 3]) # => #<Enumerator::Chain: [[1, 2, 3], [2, 3]]>
[1,2,3].chain([2, 3]).to_a # => [1, 2, 3, 2, 3]
- some conversion methods
Integer("a") # ArgumentError (invalid value for Integer(): "a")
Float('1.03') # => 1.03
Rational('1') # => (1/1)
Complex(1.02) # => (1.02+0i)
- function composition
a = ->(x) { x ** 2 }
b = ->(x) { x + 2 }
c = ->(x) { x - 2 }
(a >> b >> c).call(4)
(a << b << c).call(4)
Examples:
- Pricing rules
# https://drivy.engineering/ruby-lambda-composition/
# List of our individual pricing rules
TAX = ->(val) { val + val*0.05 }
FEE = ->(val) { val + 1 }
PREMIUM = ->(val) { val + 10 }
DISCOUNT = ->(val) { val * 0.90 }
ROUND_TO_CENT = ->(val) { val.round(2) }
# One presenter
PRESENT = ->(val) { val.to_f }
# Pre-define some rule sets for some pricing scenarios
REGULAR_SET = [FEE, TAX, ROUND_TO_CENT, PRESENT]
PREMIUM_SET = [FEE, PREMIUM, TAX, ROUND_TO_CENT, PRESENT]
DISCOUNTED_SET = [FEE, DISCOUNT, TAX, ROUND_TO_CENT, PRESENT]
def apply_rules(rules:, base_price:)
rules.inject(:>>).call(base_price)
end
amount = BigDecimal(100)
puts "regular: #{apply_rules(rules: REGULAR_SET, base_price: amount)}" # => 106.05
puts "premium: #{apply_rules(rules: PREMIUM_SET, base_price: amount)}" # => 116.55
puts "discounted: #{apply_rules(rules: DISCOUNTED_SET, base_price: amount)}" # => 95.45
- API Client
# https://blog.stanko.io/function-composition-ruby-8f91aea21e5f
require 'net/http'
require 'uri'
require 'json'
fetch =
self.method(:URI) \
>> Net::HTTP.method(:get) \
>> JSON.method(:parse) \
>> -> response { response.dig('bpi', 'EUR', 'rate') || '0' } \
>> -> value { value.gsub(',', '') } \
>> self.method(:Float)
fetch.call('https://api.coindesk.com/v1/bpi/currentprice.json') # => 7028.6713
What it is not: