{"id":9960,"date":"2017-10-24T10:40:35","date_gmt":"2017-10-24T10:40:35","guid":{"rendered":"https:\/\/blog.jetbrains.com\/ruby\/?p=7824"},"modified":"2017-12-25T13:48:13","modified_gmt":"2017-12-25T13:48:13","slug":"10-new-features-in-ruby-2-5","status":"publish","type":"ruby","link":"https:\/\/blog.jetbrains.com\/fr\/ruby\/2017\/10\/10-new-features-in-ruby-2-5","title":{"rendered":"10 new features in Ruby 2.5"},"content":{"rendered":"<p style=\"text-align: right;\"><em>This is a guest post by Junichi Ito (<a href=\"https:\/\/twitter.com\/jnchito\" target=\"_blank\" rel=\"noopener\">@jnchito<\/a>). Junichi is a Ruby programmer at <a href=\"https:\/\/www.sonicgarden.jp\/\" target=\"_blank\" rel=\"noopener\">SonicGarden.jp<\/a>, translator of Everyday Rails Testing with RSpec, and one of the most popular Ruby writers\/bloggers in Japan<\/em><\/p>\n<p><a href=\"https:\/\/www.ruby-lang.org\/en\/news\/2017\/10\/10\/ruby-2-5-0-preview1-released\/\" target=\"_blank\" rel=\"noopener\">Ruby 2.5.0-preview1<\/a> was released on October 10 2017. It introduces lots of new features and performance improvements. I have handpicked 10 new features to go over. I hope this article will help you understand some of the coming changes available in Ruby 2.5!<\/p>\n<h3>rescue\/else\/ensure are allowed inside do\/end blocks without begin\/end<\/h3>\n<p>You can write rescue\/else\/ensure clauses without begin\/end keyword within do\/end blocks:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">[1].each do |n|\r\n  n \/ 0\r\nrescue\r\n  # rescue\r\nelse\r\n  # else\r\nensure\r\n  # ensure\r\nend<\/pre>\n<p><!--more-->But you&#8217;ll get an error if you use {} blocks:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">[1].each { |n|\r\n  n \/ 0\r\nrescue\r\n  # rescue\r\nelse\r\n  # else\r\nensure\r\n  # ensure\r\n}\r\n#=&gt; SyntaxError: (irb):3: syntax error, unexpected keyword_rescue, expecting &#039;}&#039;\r\n#     rescue\r\n#     ^~~~~~<\/pre>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/12906\" target=\"_blank\" rel=\"noopener\">Feature #12906: do\/end blocks work with ensure\/rescue\/else<\/a><\/li>\n<\/ul>\n<h3>Top-level constant lookup is removed<\/h3>\n<p>In Ruby 2.4, the following code works with a warning:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">class Staff; end\r\nclass ItemsController; end\r\n\r\nStaff::ItemsController\r\n#=&gt; warning: toplevel constant ItemsController referenced by Staff::ItemsController\r\n#=&gt; ItemsController<\/pre>\n<p>This is because the top-level constants are defined under Object class, and Ruby tries to look up the superclass of Staff class, and eventually finds ItemsController under the Object class which is a superclass of Staff class. The details were discussed here:<\/p>\n<ul>\n<li><a href=\"https:\/\/blog.jetbrains.com\/ruby\/2017\/03\/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications\/\" target=\"_blank\" rel=\"noopener\">Why you Should not use a Class as a Namespace in Rails Applications | RubyMine Blog<\/a><\/li>\n<\/ul>\n<p>But in Ruby 2.5, Ruby won&#8217;t look up superclass. So the previous code fails with error:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">Staff::ItemsController\r\n#=&gt; NameError: uninitialized constant Staff::ItemsController\r\n#   Did you mean?  ItemsController<\/pre>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/11547\" target=\"_blank\" rel=\"noopener\">Feature #11547: remove top-level constant lookup<\/a><\/li>\n<\/ul>\n<h3><span style=\"text-decoration: line-through;\">Bundler gem is now bundled<\/span><\/h3>\n<p>This change is postponed due to a big issue. Please see also:<br \/>\n<a href=\"https:\/\/github.com\/ruby\/ruby\/commit\/7825e8363d4b2ccad8e2d3f5eeba9e26f6656911\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/ruby\/ruby\/commit\/7825e8363d4b2ccad8e2d3f5eeba9e26f6656911<\/a><\/p>\n<p><span style=\"text-decoration: line-through;\">Bundler is bundled as a standard library. So you can use it without `gem install bundler`!<\/span><\/p>\n<ul>\n<li><span style=\"text-decoration: line-through;\"><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/12733\" target=\"_blank\" rel=\"noopener\">Feature #12733: Bundle bundler to ruby core<\/a><\/span><\/li>\n<\/ul>\n<h3>Print backtrace and error message in reverse order (experimental)<\/h3>\n<p>In Ruby 2.5, backtrace and error message are printed in reverse order. For example, in Ruby 2.4:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">$ ruby .\/test\/error_example.rb\r\n.\/test\/error_example.rb:7:in `\/&#039;: divided by 0 (ZeroDivisionError)\r\n    from .\/test\/error_example.rb:7:in `method_2&#039;\r\n    from .\/test\/error_example.rb:2:in `method_1&#039;\r\n    from .\/test\/error_example.rb:10:in `&#039;<\/pre>\n<p>In Ruby 2.5:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">$ ruby .\/test\/error_example.rb\r\nTraceback (most recent call last):\r\n        3: from .\/test\/error_example.rb:10:in `&#039;\r\n        2: from .\/test\/error_example.rb:2:in `method_1&#039;\r\n        1: from .\/test\/error_example.rb:7:in `method_2&#039;\r\n.\/test\/error_example.rb:7:in `\/&#039;: divided by 0 (ZeroDivisionError)<\/pre>\n<p>As of preview1, this is an experimental feature and applied only when STDERR is unchanged and a tty.<\/p>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/8661\" target=\"_blank\" rel=\"noopener\">Feature #8661: Add option to print backstrace in reverse order(stack frames first &amp; error last)<\/a><\/li>\n<\/ul>\n<h3>Kernel#yield_self<\/h3>\n<p>Kernel#yield_self is introduced. This method takes a receiver as a block argument and returns a block value as it is:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">2.yield_self { |n| n * 10 } #=&gt; 20\r\n\r\nnames = [&#039;Alice&#039;, &#039;Bob&#039;]\r\nnames.join(&#039;, &#039;).yield_self { |s| &quot;(#{s})&quot; } #=&gt; &quot;(Alice, Bob)&quot;<\/pre>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/6721\" target=\"_blank\" rel=\"noopener\">Feature #6721: Object#yield_self<\/a><\/li>\n<\/ul>\n<h3>String#delete_prefix\/delete_suffix<\/h3>\n<p>String#delete_prefix\/delete_suffix can remove prefix and suffix from a string:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">&#039;invisible&#039;.delete_prefix(&#039;in&#039;) #=&gt; &quot;visible&quot;\r\n&#039;pink&#039;.delete_prefix(&#039;in&#039;) #=&gt; &quot;pink&quot;\r\n\r\n&#039;worked&#039;.delete_suffix(&#039;ed&#039;) #=&gt; &quot;work&quot;\r\n&#039;medical&#039;.delete_suffix(&#039;ed&#039;) #=&gt; &quot;medical&quot;<\/pre>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/12694\" target=\"_blank\" rel=\"noopener\">Feature #12694: Want a String method to remove heading substr<\/a><\/li>\n<\/ul>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/13665\" target=\"_blank\" rel=\"noopener\">Feature #13665: String#delete_suffix<\/a><\/li>\n<\/ul>\n<h3>Array#prepend\/append as aliases of unshift\/push<\/h3>\n<p>Array#prepend\/append are added as aliases of unshift\/push methods:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">array = [3, 4]\r\narray.prepend(1, 2) #=&gt; [1, 2, 3, 4]\r\narray               #=&gt; [1, 2, 3, 4]\r\n\r\narray = [1, 2]\r\narray.append(3, 4)  #=&gt; [1, 2, 3, 4]\r\narray               #=&gt; [1, 2, 3, 4]<\/pre>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/12746\" target=\"_blank\" rel=\"noopener\">Feature #12746: class Array: alias .prepend to .unshift ?<\/a><\/li>\n<\/ul>\n<h3>Hash#transform_keys\/transform_keys!<\/h3>\n<p>Hash#transform_keys can change keys according to the return value of a block:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">hash = { a: 1, b: 2 }\r\nhash.transform_keys { |k| k.to_s }\r\n#=&gt; { &#039;a&#039; =&gt; 1, &#039;b&#039; =&gt; 2 }<\/pre>\n<p>`transform_keys!` is a destructive version:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">hash = { a: 1, b: 2 }\r\nhash.transform_keys! { |k| k.to_s }\r\n#=&gt; { &#039;a&#039; =&gt; 1, &#039;b&#039; =&gt; 2 }\r\n\r\nhash\r\n#=&gt; { &#039;a&#039; =&gt; 1, &#039;b&#039; =&gt; 2 }<\/pre>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/13583\" target=\"_blank\" rel=\"noopener\">Feature #13583: Adding `Hash#transform_keys` method<\/a><\/li>\n<\/ul>\n<h3>Dir.children\/each_child<\/h3>\n<p>You might have used Dir.entries method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">Dir.entries(&#039;.\/test\/dir_a&#039;)\r\n#=&gt; [&quot;.&quot;, &quot;..&quot;, &quot;code_a.rb&quot;, &quot;text_a.txt&quot;]<\/pre>\n<p>If you want to remove &#8220;.&#8221; and &#8220;..&#8221; from the returned values, you can Dir.children instead:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">Dir.children(&#039;.\/test\/dir_a&#039;)\r\n#=&gt; [&#039;code_a.rb&#039;, &#039;text_a.txt&#039;]<\/pre>\n<p>Dir.each_child returns not an array but an Enumerator object:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">Dir.each_child(&#039;.\/test\/dir_a&#039;)\r\n#=&gt; #&lt;Enumerator: Dir:each_child(\\&quot;.\/test\/dir_a\\&quot;)&gt;&quot;\r\n\r\nDir.each_child(&#039;.\/test\/dir_a&#039;).to_a\r\n#=&gt; [&#039;code_a.rb&#039;, &#039;text_a.txt&#039;]<\/pre>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/11302\" target=\"_blank\" rel=\"noopener\">Feature #11302: Dir.entries and Dir.foreach without [&#8220;.&#8221;, &#8220;..&#8221;]<\/a><\/li>\n<\/ul>\n<h3>ERB#result_with_hash<\/h3>\n<p>The following code shows how to assign local variables to ERB template in Ruby 2.4:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">require &#039;erb&#039;\r\nrequire &#039;ostruct&#039;\r\n\r\nnamespace = OpenStruct.new(a: 2, b: 3)\r\ntemplate = &#039;Result: &lt;%= a * b %&gt;&#039;\r\nERB.new(template).result(namespace.instance_eval { binding }) #=&gt; &quot;Result: 6&quot;<\/pre>\n<p>But in Ruby 2.5, you can rewrite with ERB#result_with_hash like this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-title=\"\">require &#039;erb&#039;\r\n\r\ntemplate = &#039;Result: &lt;%= a * b %&gt;&#039;\r\nERB.new(template).result_with_hash(a: 2, b: 3) #=&gt; &quot;Result: 6&quot;<\/pre>\n<ul>\n<li><a href=\"https:\/\/bugs.ruby-lang.org\/issues\/8631\" target=\"_blank\" rel=\"noopener\">Feature #8631: Add a new method to ERB to allow assigning the local variables from a hash<\/a><\/li>\n<\/ul>\n<h3>Other changes<\/h3>\n<p>You can find other changes on the Ruby 2.5 NEWS page:\u00a0<a href=\"https:\/\/github.com\/ruby\/ruby\/blob\/v2_5_0_preview1\/NEWS\" target=\"_blank\" rel=\"noopener\">NEWS for Ruby 2.5.0<\/a><\/p>\n<p>Love Ruby 2.5!<\/p>\n","protected":false},"author":574,"featured_media":0,"comment_status":"open","ping_status":"open","template":"","categories":[942],"tags":[617],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/ruby\/9960"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/ruby"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/ruby"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/574"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=9960"}],"version-history":[{"count":0,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/ruby\/9960\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=9960"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=9960"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=9960"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=9960"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}