新米パパの育児留学

新米パパの育児留学

未経験からエンジニアへの転職体験談など "リアル" な情報を発信

30代未経験からIT・Webエンジニアに転職した私のロードマップ
30代未経験からIT / Webエンジニアへのリアルな転職体験談1 ”エンジニアを目指し求人応募へ”
クロスバイク  LIG(リグ) MOVE 700Cの組み立て手順まとめ
本当に使えるものだけ!出産準備品・ベビー用品で実際に買ってよかったおすすめ10選
Ruby初心者におすすめの学習方法「プロを目指す人のためのRuby入門」
Ruby on Rails チュートリアル 完全攻略 概要と演習解答総まとめ

Ruby2.4の主な変更点まとめ

先日Rails5.0(Ruby2.3,Ruby2.4)の新機能勉強会を開催したのでその際の資料をアップします。

本記事は、Ruby2.4 の主な新機能についてです。

GEEKLYのIT・WEB・ソーシャルゲーム業界への転職支援サービス

発表スライド

Ruby 2.4の主な新機能

1. 【重要!】FixnumクラスとBignumクラスがIntegerクラスに統合された

  • Ruby2.3までは整数は基本的にFixnumクラスで、極端に大きいまたは小さい数になるとBignumクラスに自動的に変わっていた
  • Ruby 2.4では両者の親クラスであるIntegerクラスにまとめられた
  • Fixnum, Bignum はdeprecated
#ruby 2.3
irb(main):003:0> 1.class
#=> Fixnum
irb(main):004:0> -1.class
#=> Fixnum
irb(main):001:0> 10000000000000000000000000000.class
#=> Bignum
irb(main):002:0> -10000000000000000000000000000.class
#=> Bignum
#ruby 2.4
irb(main):086:0> 1.class
#=> Integer
irb(main):087:0> -1.class
#=> Integer
irb(main):088:0> 10000000000000000000000000000.class
#=> Integer
irb(main):089:0> -10000000000000000000000000000.class
#=> Integer

2. 指定された範囲内の値を返すようにするComparable#clamp

下限値と上限値を引数で指定し、レシーバの値(下記)に従い値を返す

  • その範囲内であればレシーバを返す
  • 下限を超えていれば下限値を返す
  • 上限を超えていれば上限値を返す
> 2.clamp(1,3)
#=> 2
> 0.clamp(1,3)
#=> 1
> 4.clamp(1,3)
#=> 3

3. 切り上げ、切り下げ、切り捨てで小数点の位置を指定できるようになった

  • ceilfloortruncateの各メソッドに引数を渡して、切り上げ、切り下げ、切り捨てを行う小数点の位置を指定
  • デフォルトは一の位に対して実行
 # 切り上げ
> 1.11.ceil(1)
#=> 1.2
> 1.11.ceil
#=> 2
> -1.11.ceil
#=> -1
> 1.11.ceil(1)
#=> 1.2
> -1.11.ceil(1)
#=> -1.1
> 11111.ceil(-1)
#=> 11120

# 切り下げ
> 1.99.floor
#=> 1
> -1.99.floor
#=> -2
> 1.99.floor(1)
#=> 1.9

# 切り捨て
> 1.99.truncate
#=> 1
> -1.99.truncate
#=> -1
> 1.99.truncate(1)
#=> 1.9

4. 正規表現に文字列がマッチしたかどうかだけを返すRegexp#match?、String#match?、Symbol#match?

  • 正規表現に文字列がマッチしたかどうかだけ(true/false)を返す
  • matchメソッドよりも高速
> /\d+-\d+-\d+/.match('2016-09-01')
#=> #<MatchData "2016-09-01">

> /\d+-\d+-\d+/.match?('2016-09-01')
#=> true

5. 名前付きキャプチャをハッシュとして返すMatchData#named_captures

  • ハッシュのキーはシンボルではなく文字列
> m = /(?<year>\d+)-(?<month>\d+)-(?<day>\d+)/.match('2018-05-01')
#=> #<MatchData "2018-05-01" year:"2018" month:"05" day:"01">

> m.named_captures
#=> {"year"=>"2018", "month"=>"05", "day"=>"01"}

6. MatchData#values_atで名前付きキャプチャの名前を指定できるようになった

  • Ruby 2.3までは指定できるのは、キャプチャした文字列のインデックスだけ
  • Ruby 2.4では名前付きキャプチャの名前を指定できるように
  • 名前は文字列、またはシンボルで指定
> m = /(?<year>\d+)-(?<month>\d+)-(?<day>\d+)/.match('2018-05-01')
#=> #<MatchData "2018-05-01" year:"2018" month:"05" day:"01">

> m.values_at(1, 3)
#=> ["2018", "01"]

> m.values_at('year', 'day')
#=> ["2018", "01"]

> m.values_at(:year, :day)
#=> ["2018", "01"]

7. 指定した条件で重複をなくすEnumerable#uniq

  • 配列だけでなく、ハッシュでもuniqが使えるように
  • 引数にvalueを指定することでvalueuniqできる
olimpics = {
  1896 => 'Athens',
  1900 => 'Paris',
  1904 => 'Chikago',
  1906 => 'Athens',
  1908 => 'Rome'
  }
#=> {1896=>"Athens", 1900=>"Paris", 1904=>"Chikago", 1906=>"Athens", 1908=>"Rome"}

olimpics.uniq { |k, v| v }
#=> [[1896, "Athens"], [1900, "Paris"], [1904, "Chikago"], [1908, "Rome"]]

8. concatメソッドが複数の配列を引数に取れるようになった

> [1, 2].concat([3, 4], [5, 6])
#=> [1, 2, 3, 4, 5, 6]

9. concatメソッドとprependメソッドが複数の文字列を受け取れるようになった

> 'a'.concat('b','c')
#=> "abc"
>'z'.prepend('x','y')
#=> "xyz"

10. 大文字小文字を無視して同一かどうかを返すcasecmp?メソッドが追加された

  • 大文字小文字を無視して同一かどうかをtrue/falseで返す
  • 文字列とシンボルで使える
> 'abc'.casecmp?('ABC')
#=> true
> 'abc'.casecmp?('DEF')
#=> false
> :abc.casecmp?(:ABC)
#=> true
> :abc.casecmp?(:DEF)
#=> false

11. ディレクトリやファイルが空かどうかを判定するDir.empty?、File.empty?

  • File.empty?は以前からrubyのメソッドとしてあったFile.zero?のエイリアスメソッド
> require 'tmpdir'
> Dir.mktmpdir { |dir| Dir.empty?(dir) }
#=> true
> IO.write("zero.txt", "")
> File.zero?("zero.txt")
#=> true

> IO.write("nonzero.txt", "1")
> File.zero?("nonzero.txt")
#=> false

> IO.write("zero.txt", "")
> File.empty?("zero.txt")
#=> true

> IO.write("nonzero.txt", "1")
> File.empty?("nonzero.txt")
#=> false

12. プログラムの実行中にirbが開けるbinding.irbメソッドの追加

  • 以前からPryを使っているとbinding.pryというコマンドをコードに埋め込むことで、プログラムの実行中にPryを開くことができたが、これのirbバージョン
  • デバッグの際などに使える
[binding_irb.rb]
# irbをrequireする
require 'irb'

s = 'hello'
puts s

# ここでirbを開く
binding.irb

puts s
puts 'bye'
$ ruby binding_irb.rb
hello

irb(main):001:0> s
#=> "hello"
irb(main):002:0> s = "modify"
#=> "modify"
irb(main):003:0> exit

modify
bye

勉強会では紹介しなかった新機能

13. Logger.newのキーワード引数追加

  • Logger.newのキーワード引数としてlevelprognameformatterdatetime_formatが追加

[railsでの実装:なかった]

> require 'logger'
> formatter = proc { |severity, timestamp, progname, msg| "#{severity}:#{msg}\n\n" }
> logger = Logger.new(
*     STDERR,
*     level: :info,
*     progname: :progname,
*     formatter: formatter,
*     datetime_format: "%d%b%Y@%H:%M:%S"
> )
=> #<Logger:0x00007f1053d7d470 @level=1, @progname=:progname, @default_formatter=#<Logger::Formatter:0x00007f1053d7d380 @datetime_format="%d%b%Y@%H:%M:%S">, @formatter=#<Proc:0x00007f1053d99c60@(irb):66>, @logdev=#<Logger::LogDevice:0x00007f1053d7d330 @shift_period_suffix=nil, @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<IO:<STDERR>>, @mon_owner=nil, @mon_count=0, @mon_mutex=#<Thread::Mutex:0x00007f1053d7d2e0>>>

> logger.level
#=> 1
> logger.level == Logger::INFO
#=> true
> logger.progname
#=> :progname
> logger.formatter
#=> #<Proc:0x00007f1053d99c60@(irb):66>
> logger.datetime_format
#=> "%d%b%Y@%H:%M:%S"

14. ログのローテーションファイルの拡張子書式を指定できるようになった

  • ログのローテーションファイルの拡張子書式は"%Y%m%d"固定になっていたが、shift_period_suffixオプションを使って書式を指定できるようになった("%Y-%m-%d"など)

[railsでの実装:なかった]

> require 'logger'
> logger = Logger.new('development.log', shift_period_suffix: '%Y-%m-%d')
#=> #<Logger:0x00007f1053d0e7a0 @level=0, @progname=nil, @default_formatter=#<Logger::Formatter:0x00007f1053c5ff20 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x00007f1053c5fed0 @shift_period_suffix="%Y-%m-%d", @shift_size=1048576, @shift_age=0, @filename="development.log", @dev=#<File:development.log>, @mon_owner=nil, @mon_count=0, @mon_mutex=#<Thread::Mutex:0x00007f1053c5fe80>>>

15. 非ASCII文字でも小文字化、大文字化されるようになった

  • 非ASCII文字(たとえばウムラウトが含まれるような文字)でも小文字化、大文字化される
  • Ruby 2.3と同じようにASCII文字だけを変換したい場合は:asciiオプションを付ける

[railsでの実装:なかった]

> 'Türkiye'.upcase
#=> "TÜRKIYE"
> 'Türkiye'.downcase
#=> "türkiye"
> 'Türkiye'.upcase(:ascii)
#=> "TüRKIYE"

16. optparseで起動時引数をハッシュに格納するintoオプション

  • optparseで起動時引数をパースする際、intoオプションを使ってパースした結果をハッシュに格納できる

[railsでの実装:なかった]

require 'optparse'
require 'optparse/date'
require 'optparse/uri'

cli =
  OptionParser.new do |options|
    options.define '--from=DATE',    Date
    options.define '--url=ENDPOINT', URI
    options.define '--names=LIST',   Array
  end

config = {}

args = %w[
  --from  2016-02-03
  --url   https://blog.blockscore.com/
  --names John,Daniel,Delmer
]

cli.parse(args, into: config)

config
#=> {:from=>#<Date: 2016-02-03 ((2457422j,0s,0n),+0s,2299161j)>, :url=>#<URI::HTTPS https://blog.blockscore.com/>, :names=>["John", "Daniel", "Delmer"]}
config.keys
#=> [:from, :url, :names]
config[:from]
#=> #<Date: 2016-02-03 ((2457422j,0s,0n),+0s,2299161j)>
config[:url]
#=> #<URI::HTTPS https://blog.blockscore.com/>
config[:names]
#=> ["John", "Daniel", "Delmer"]

17. テキストファイルを行単位で読み込む際に、chompするかどうかを指定できるようになった

  • IO#gets, IO#readline, IO#each_line, IO#readlines,IO#foreachchompオプションを指定できるように
  • 最初からchompした状態(つまり改行文字を削除した状態)で各行のテキストを取得できる

[railsでの実装:なかった]

> File.write("text", "abc\nxyz\r\n")

> IO.readlines("text")
#=> ["abc\n", "xyz\r\n"]
> IO.readlines("text", chomp: true)
#=> ["abc", "xyz"]

18. Enumerableモジュールにsumが追加された

  • 配列の中身の合計値を求められる

[railsでの実装:あった]

> [1,2,3,4].sum
#=> 10

19. ハッシュの値を特定のルールで変更するHash#transform_values

  • ハッシュの値を特定のルールで変更できる
  • 破壊的な変更を行うtransform_values!メソッドもある

[railsでの実装:あった]

> x = {a: 1, b: 2, c: 3}
#=> {:a=>1, :b=>2, :c=>3}

> y = x.transform_values {|v| v ** 2 }
#=> {:a=>1, :b=>4, :c=>9}
> x
#=> {:a=>1, :b=>2, :c=>3}

> y = x.transform_values! {|v| v ** 2 }
#=> {:a=>1, :b=>4, :c=>9}
> x
#=> {:a=>1, :b=>4, :c=>9}

20. ハッシュにcompact/compact!メソッドが追加された

[railsでの実装:あった]

> hash = { a: 1, b: nil, c: 2 }
#=> {:a=>1, :b=>nil, :c=>2}
> hash.compact
#=> {:a=>1, :c=>2}
> hash
#=> {:a=>1, :b=>nil, :c=>2}
> hash.compact!
#=> {:a=>1, :c=>2}
> hash
#=> {:a=>1, :c=>2}

21. 整数を1桁ずつ配列に入れて返すInteger#digits

  • 値は1桁目、2桁目・・・の順番で格納

[railsでの実装:なかった]

irb(main):048:0> 123.digits
#=> [3, 2, 1]

22. Stringのcapacityを指定できるようになった

  • 長い文字列を追加することが事前に分かっている場合は、このオプションを指定することでパフォーマンスを向上させることができる
  • 以下のサイトの計測結果によると、capacityを指定すると2.32倍速くなったらしい
  • 文字数制限は越えても問題ないが、パフォーマンス向上を考えて適正な値を設定すること

New Features in Ruby 2.4 - BlockScore Blog

[railsでの実装:なかった]

template  = String.new(capacity: 100)

参考情報

公式情報

参考ブログ

所感

"正規表現に文字列がマッチしたかどうかだけを返すmatch?"はmatchdataはいらないけど判定だけしたい時に使用すると早いのでパフォーマンス向上につながって便利。
"切り上げ、切り下げ、切り捨てで小数点の位置を指定できるようになった"、"複数の配列/文字列を受け取れるように"や"binding.irb"など地味だけどかゆいところに手が届くような改善が嬉しい。

GEEKLYのIT・WEB・ソーシャルゲーム業界への転職支援サービス

あわせて読みたい記事

mochikichi.hatenablog.com

mochikichi.hatenablog.com

mochikichi.hatenablog.com