Ruby 2.6
- Released at: Dec 25, 2018 (NEWS file)
- Status (as of Feb 07, 2023): EOL, latest is 2.6.10
- This document first published: Dec 29, 2018
- Last change to this document: Feb 07, 2023
Note: As already explained in Introduction, this site is dedicated to changes in the language, not the implementation, therefore the list below lacks mentions of lots of important optimization introduced in 2.6, including the whole JIT big thing. That’s not because they are not important, just because this site’s goals are different.
Highlights
- Endless range
#then“piping” method- Support for timezones in
Time Proccomposition- Enumerator chaining
RubyVM::AbstractSyntaxTree
Language
Endless range: (1..)
- Discussion: Feature #12912
- Reason/Usage: More convenient
Arrayslicing, and idiomatic open-endedcaseconditions - Documentation: Range: Endless ranges
- Code:
# Usage ary = %w[List of words] ary[2..] # => ["words"] case indicator when 1...8 then # ... when 8...15 then # ... when 15.. then # ... end years.grep(2017...) # Details of behavior: (1..).end # => nil (1..).to_a # RangeError (cannot convert endless range to an array) (1..).each { } # hangs forever (1..) == (1...) # => false (1..).size # => Infinity - Follow-up: “Beginless” range was introduced in 2.7.
Non-ASCII constant names
Constant names may start with a non-ASCII capital letter.
- Discussion: Feature #13770
- Reason: Why not?
else in exception-handling context
In exception-handling context, else without any rescue is now a syntax error
- Discussion: Feature #14606
- Code:
# In Ruby 2.6 it would be SyntaxError: else without rescue is useless [1,2,3].each do p :foo else p :bar endThe code above obviously contains some error (omitted
ifor something), but before Ruby 2.6 the interpreter would not complain, interpreting it as “begin → perform code that might raise → else (if nothing was raised) performing something”, due to lesser-used Ruby feature of allowingelsein an exception-handling construct.
Refinements: improved visibility
Refinements are now compatible with #public_send and #respond_to?, and implicit #to_proc.
- Reason: This is part of the effort to make great yet neglected feature of refinements behave more naturally;
- Discussions: Feature #14223, Feature #15326, Feature #15327
- Code:
module StringExt refine String do def surround(before, after = before) after + self + before end def to_proc proc { |val| self % val } end end end using StringExt 'foo'.respond_to?(:surround) # => true in 2.6, false in 2.5 'foo'.public_send(:surround, '|') # => "|foo|" in 2.6, NoMethodError in 2.5 (1..3).map(&'%02i') # => ["01", "02", "03"] in 2.6; wrong argument type String (expected Proc) in 2.5 - Follow-up: Ruby 2.7 also made refinements available in
#method
Misc
- Infamous esoteric flip-flop syntax is deprecated finally: Feature #5400.
- Follow-up: Deprecation is reverted in 2.7
Core classes and modules
Kernel
Notice that methods defined in Kernel are typically available on any object, that’s why these changes are important.
#then as an alias for #yield_self
- Reason: Since the introduction of
Kernel#yield_selfat Ruby 2.5, it was pointed out that the name chosen is too long for this basic method, and, unlike most of other core methods, says “how it is implemented” not the intention; after lots of discussion it was decided#thencorresponds best to the method’s goal. - Notice: There is a controversy in the community about this alias, pointing out the fact that
#thenis a typical method name for promises. - Discussion: Feature #14594
- Code:
[BASE_URL, path].join('/') .then { |url| open(url).read } .then { |body| JSON.parse(body, symbolyze_names: true) } .dig(:data, :items) .then { |items| File.write('response.yml', items.to_yaml) }
<Numeric>() methods have exception: argument
- Reason: As of Ruby 2.5,
Integer('x')will raiseArgumentError (invalid value for Integer(): x), but in a lot of cases a sane thing to desire is “convert it, if possible” - Discussion: Feature #12732
- Affected methods:
#Integer,#Float,#Rational,#Complexand#BigDecimal(stdlib; previously known asBigDecimal.new) - Documentation:
Kernel#Integer,Kernel#Float,Kernel#Rational,Kernel#Complex,Kernel#BigDecimal - Code:
Integer('x') # => ArgumentError (invalid value for Integer(): "x") Integer('x', exception: false) # => nil
#system has exception: argument
With exception: true, the method raises instead of returning false on non-0 exit code, or nil on command execution failure.
- Discussion: Feature #14386
- Documentation:
Kernel#system(unfortunately, seems documentation haven’t been updated with new feature) - Code:
system('cat nonexistent.txt') # => false system('ctat nonexistent.txt') # => nil system('cat nonexistent.txt', exception: true) # RuntimeError (Command failed with exit 1: cat) system('ctat nonexistent.txt', exception: true) # Errno::ENOENT (No such file or directory - ctat)
Module#method_defined?: inherit argument
Module#method_defined? and similar methods accept an optional second argument. If it is false, only module’s own methods would be returned.
- Reason: Other module introspection methods, like
#methods, already have similar arguments. It may be important for meta-programming; like “when this module is included, it will redefine some host’s methods, but only those that belong to host”, or “test that all descendants of some abstract class redefine required methods”. - Affected methods:
#method_defined?,#private_method_defined?,#protected_method_defined?,#public_method_defined?. - Discussion: Feature #14944
- Documentation:
Module#method_defined?,Module#private_method_defined?,Module#protected_method_defined?,Module#public_method_defined? - Code:
Array.method_defined?(:chunk) # => true Array.method_defined?(:chunk, false) # => false -- it is Enumerable's method Array.method_defined?(:to_h, false) # => true -- despite inheriting from Enumerable, Array redefines it for performance - Follow-up: In 2.7,
inheritargument was also added toautoload?
String#split with block
- Reason: When parsing a huge string, and each substring is used exactly once, it could be ineffective to first create the whole array of parts, and only then iterate through it; with block form, parts are just yielded one by one;
- Discussion: Feature #4780
- Documentation:
String#split - Code:
"several\nlong\nlines".split("\n") { |part| puts part if part.start_with?('l') } # prints: # long # lines # => "several\nlong\nlines"Note that in block form, the original string will be returned, not the result of processing parts with block. To work with split results in a method-chaining style, one can utilize
Object#to_enum:"several\nlong\nlines" .to_enum(:split, "\n") # => Makes a enumerator, yielding each entry from split("\n") .each_with_object(Hash.new(0)) { |ln, h| h[ln.length] += 1 } # => {7=>1, 4=>1, 5=>1}
Time: support for timezones
The concept of a “timezone object” is introduced for various Time methods. Ruby does not define any timezone classes by itself, but the API expected corresponds to that of TZInfo::Timezone:
A timezone argument must have
local_to_utcandutc_to_localmethods, and may havenameandabbrmethods.
- Methods affected:
.new(timezone may be passed as a last argument, which previously accepted only raw UTC offsets).at(new keywordin:argument)#getlocal(accepts timezone where previously only UTC offset was accepted)#+,#-,#succ(no new argument, but preserve timezone of the source)
- Discussion: Feature #14850
- Documentation: Time: Timezone argument
- Reason: Named timezones are more complicated than just “offset from UTC”. Going over DST date, or between different years in country history, time could have the same timezone, but different UTC offset.
- Code:
zone = TZInfo::Timezone.get('America/New_York') time = Time.new(2018, 6, 1, 0, 0, 0, zone) time.zone # => #<TZInfo::DataTimezone: America/New_York> time.strftime('%H:%M %Z') # => "00:00 EDT" time.utc_offset # => -14400 = -4 hours time += 180 * 24*60*60 # + 180 days, summery->winter transition time.utc_offset # => -18000, -5 hours -- daylight saving handled by timezone - Follow-up: In Ruby 3.1, the new ways for handier constructing time with timezones were introduced.
Proc composition
Proc and Method classes now have #>> and #<< methods for functional composition.
- Reason: This was a long-anticipated feature for moving Ruby towards more functional code.
- Discussion: Feature #6284
- Code:
plus = ->(x, y) { x + y } mul2 = ->(x) { x * 2 } stringify = :to_s.to_proc (plus >> mul2).call(5, 6) # => 22 (mul2 >> stringify).call(5) # (5 * 2).to_s # => "10" (mul2 << stringify).call(5) # 5.to_s * 2 # => "55" # Realistic examples: # 1. Providing chain of functions instead of chaining map's: URLS.map(&Faraday.method(:get) >> :body.to_proc >> JSON.method(:parse) >> ->(data) { data.dig('response', 'items')}) # 2. Storing chain of processings in constant: RESPONSE_PROCESSOR = Faraday.method(:get) >> :body.to_proc >> JSON.method(:parse) >> ->(data) { data.dig('response', 'items')} # ...later... URLS.map(&RESPONSE_PROCESSOR) # 3. Utilizing block-based DSLs (Sinatra-alike) get '/my_endpoint', &parse_params >> perform_business_action >> render_response - Important notice: Unlike any other places in Ruby (where objects are coerced into procs with
#to_procmethod), “what can be chained” is decided by existence of#callmethod; this means you CAN’T chain symbols (notice:body.to_procabove), but CAN chain some “command pattern” classes withMyClass.callAPI.
Array#union and Array#difference
Array#union is like |, but also accepts multiple arguments; Array#difference is like -, but accepts multiple arguments.
- Discussion: Feature #14097
- Reason: Multiple-argument methods are more effective, and better chainable than operator form
- Documentation:
Array#union,Array#difference - Code:
[1, 2, 3].union([3, 4], [4, 5]) # => [1, 2, 3, 4, 5] [1, 2, 3, 4].difference([3, 4], [1]) # => [2] - Notice: There are also plans (discussed in the same ticket above) to introduce mutating
union!form. - Follow-up: Ruby 2.7 added
#intersectionmethod.
Hash#merge with multiple arguments
- Discussion: Feature #15111
- Methods affected:
Hash#merge,Hash#merge!,Hash#update(alias for#merge!) - Documentation:
Hash#merge - Code:
{a: 1, b: 2}.merge({b: 3, c: 4}, {c: 5, b: 6}) # => {a: 1, b: 6, c: 5} {a: 1, b: 2}.merge({b: 3, c: 4}, {c: 5, b: 6}) { |key, oldval, newval| [oldval, newval] } # => {a: 1, b: [[2, 3], 6], c: [4, 5]}Note the last example: if the block is provided for conflict resolution, it is called repeatedly for each pair of values provided for the conflicting key (not
|key, *all_conflicting_values|as one may expect).
Enumerables
#filter/#filter!
#select is aliased as #filter (and #select! as #filter!, where applicable).
- Reason: It was argued for a long time that most of other languages name the concept “filter”, so the new alias was added to lessen the confusion for newcomers.
- Discussion: Feature #13784
- Classes and modules affected:
Enumerable,Enumerator,Enumerator::Lazy,Struct(only#filter),Array,Hash, andSetof standard library (#filterand#filter!).
#to_h with a block
- Reason: It was noted that
.map { |...| [some_key, some_value] }.to_his a very common pattern and should be made DRY; - Discussion: Feature #15143;
- Classes and modules affected:
Enumerableand everything that includes it; - Documentation:
Enumerable#to_h,Array#to_h,ENV.to_h,Hash#to_h,Struct#to_h - Code:
{a: 1, b: 2, c: 3}.to_h { |k, v| [k.to_s, -v] } # => {'a' => -1, 'b' => -2, 'c' => -3} File.readlines('test.txt').each_with_index.to_h { |l, i| [i, l] } # => {0 => 'first line', 1 => 'second line', 2 => 'third line'}
Enumerator::ArithmeticSequence
Range#step and Numeric#step are now returning not an instance of Enumerator, but Enumerator::ArithmeticSequence instead.
- Reason/Usage: This feature was added by request of scientific Ruby community; it is useful for reusing results of
(from..to).step(s)as a value object for idiomatic slicing of custom collections, see alsoRange#%. - Discussion: Feature #13904
- Documentation:
Enumerator::ArithmeticSequence,Range#step,Numeric#step - Code:
# Basic usage remains the same: (1..10).step(2).to_a # => [1, 3, 5, 7, 9] enum = (1..10).step(2) # => ((1..10).step(2)) enum.class # => Enumerator::ArithmeticSequence enum.class.ancestors # => [Enumerator::ArithmeticSequence, Enumerator, Enumerable ...] # So, it is just a specialized subclass of enumerator, adding this methods: enum.begin # => 1 enum.end # => 10 enum.step # => 2 - Follow-up: In 3.0,
Arrayslicing withArithmeticSequence(from 1st to 10th, each 2nd element) became possible.
Enumerator chaining
Several enumerators can now be chained into one with Enumerator#+(other) or Enumerable#chain(list, of, enumerators). The result of the operation is Enumerator::Chain (specialized subclass of Enumerator).
- Reason: Cleaner expression of chaining enumeration for several sequences, especially for lazy enumerators
- Discussion: Feature #15144
- Documentation:
Enumerator#+,Enumerable#chain,Enumerator::Chain - Code:
[1, 2, 3].chain # => #<Enumerator::Chain: [[1, 2, 3]]> [1, 2, 3].each + [4, 5, 6].each # => #<Enumerator::Chain: [#<Enumerator: [1, 2, 3]:each>, #<Enumerator: [4, 5, 6]:each>]> [1, 2, 3].chain([4, 5, 6]) # => #<Enumerator::Chain: [[1, 2, 3], [4, 5, 6]]> # Realistic use-case: # Take data from several sources, abstracted into enumerator, fetching it on demand sources = URLS.lazy.map { |url| open(url).read } .chain(LOCAL_FILES.lazy.map { |path| File.read(path) }) # ...then uniformely search several sources (lazy-loading them) for some value sources.detect { |body| body.include?('Ruby 2.6') }
Range
Range#=== uses #cover? instead of #include?
- Reason: Previously, case equality operator used
#include?, which underneath iterates through entire range (except for Numerics). With objects other than numbers it could be ineffective (creating thousands of objects), impossible (if there is no notion of “next object”, but exists notion of order) or imprecise. - Discussion: Feature #14575
- Code:
case DateTime.now when Date.today..Date.today + 1 # this would've not been reached before Ruby 2.6 end # this would raise "can't iterate from Gem::Version" before Ruby 2.6 case Gem::Version.new('2.4') when Gem::Version.new('1.8.7')..Gem::Version.new('2.5') end gem 'ruby-ip' require 'ip' # this would perform ~0.5 sec before Ruby 2.6, iterating over 65536-elt sequence case IP.new('192.168.10.4') when IP.new('192.168.0.0')..IP.new('192.168.255.255') end - Notice: For
Stringranges, behavior left unchanged, so example with versions above would NOT work with pure-Stringversions. - Follow-up:
Stringbehavior was fixed in Ruby 2.7, so in 2.7 this code prints “yes”:case '2.5' when '1.8.7'..'2.6' puts "yes" else puts "no" end
Range#cover? accepts range argument
- Discussion: Feature #14473
- Code:
(1..5).cover?(2..3) # => true
Range#% alias
- Reason/Usage: It was proposed to have short syntax of complex array slicing, usable for math algorithms; see also
Enumerable::ArithmeticSequence. - Discussion: Feature #14697
- Code:
(5..20) % 2 # => ((5..20).%(2)) -- an instance of Enumerable::ArithmeticSequencee some_fancy_collection[(5..20) % 2] # each second element in 5..20 rangeNote that
()around the range is mandatory here, because5..20 % 2will be parsed as(5)..(20 % 2) - Notice: Ruby’s
Arraydoesn’t support slicing withEnumerable::ArithmeticSequenceeas of 2.6. - Follow-up: In 3.0,
Arrayslicing withArithmeticSequencebecame possible.
Exceptions
New arguments: receiver: and key:
NameError, NoMethodError accept :receiver on creation; KeyError accepts :receiver and :key.
- Reason: Since Ruby 2.5, these exception classes were “introspectable”: when you catch them, you can fetch the object that caused the problem and (in case of
KeyError) problematic key; but there were no way to add that helpful data when raising an exception in your own code. - Discussion: Feature #14313
- Documentation:
NameError.new,NoMethodError.new(docs not updated),KeyError.new - Code:
class MyFancyCollection def [](key) # ... raise KeyError.new("don't have this: #{key}", receiver: self, key: key) # ... end end - Notice:
<Exception>.newsyntax is the only way to pass new arguments, this would not work:raise KeyError, "don't have this: #{key}", receiver: self, key: key - Follow-up: Ruby 2.7 adds
receiver:argument forFrozenError, too.
Exception#full_message options
Exception#full_message (which returns “exceptions how they are printed by Ruby”, including message, class and backtrace) takes :highlight and :order options. This means client code can fine-tune which result it wants to achieve.
- Reason: Since introduction of new way for printing exceptions to STDERR (backtrace in reverse order and message is highlighted in bold), there were some improvements proposed to handle different contexts of exception printing.
- Discussion: Bug #14324
- Documentation:
Exception#full_message - Code:
begin {a: 1}.fetch(:b) rescue => e # highlight: true/false, order: :top/:bottom p e.full_message(highlight: false, order: :top) # "t.rb:2:in `fetch': key not found: :b (KeyError)\n\tfrom t.rb:2:in `<main>'\n" p e.full_message(highlight: true, order: :bottom) # "\e[1mTraceback\e[m (most recent call last):\n\t1: from t.rb:2:in `<main>'\nt.rb:2:in `fetch': \e[1mkey not found: :b (\e[1;4mKeyError\e[m\e[1m)\e[m\n" p e.full_message # Output could be either of two above, depending on whether STDERR is terminal # or redirected with `ruby test.rb 2> err.log end - Follow-up: In Ruby 3.2, one more related method
#detailed_messagewas added.
Exception output tweaking
Exception#causeis now printed if STDERR is the terminal:begin {a: 1}.fetch(:b) rescue => e raise 'something went wrong' end # Traceback (most recent call last): # 1: from t.rb:2:in `<main>' # t.rb:2:in `fetch': key not found: :b (KeyError) # 1: from t.rb:1:in `<main>' # t.rb:4:in `rescue in <main>': something went wrong (RuntimeError)Notice the exception that led to
rescue/raiseblock (KeyError) is printed too.- Discussion: Feature #8257
- Exception backtrace and error message are printed in reverse order when the exception is not caught and STDOUT is unchanged and a tty. Feature #8661
- Follow-up: Reverted completely to pre-2.5 order in 3.0.
Filesystem and IO
Dir#each_child and Dir#children
- Discussion: Feature #13969
- Documentation:
Dir#each_child,Dir#children - Code:
Dir.new('.').children # => ["_layouts", ".gitignore", "README.md", "_data", "_src", "_site", "_config.yml", "2.6.md", "js", "404.html", ".git", "images", "Gemfile", "css", "Gemfile.lock"]
IO open mode: 'x'
When opening a new file for writing, 'wx' can be specified to request the file does not exist before opening.
- Discussion: Feature #11258
- Documentation: IO: Open mode
- Code:
f1 = File.open('temp.txt', 'wx') # => #<File:temp.txt> f2 = File.open('temp.txt', 'wx') # it is already created by previous statement # Errno::EEXIST (File exists @ rb_sysopen - temp.txt)
Minor changes
Object#=~is deprecated: Feature #15231 (butNilClass#=~is still allowed without deprecation notice).Random.bytes: Feature #4938 /Random.bytesRandom.bytes(5) # => "8\a\xB0\xD1V" # ...will probably return different value for you, though :)
Introspection
Binding#source_location
- Reason: Important usage for this new feature is proper reporting in block-based DSL usage: if something was inconsistent in the passed block, library code may use
block.binding.source_locationto report where exactly problematic code came from. - Discussion: Feature #14230
- Documentation:
Binding#source_location - Code:
binding.source_location # => ["(irb)", 114] def my_dsl(&block) puts "Evaluating block from #{block.binding.source_location.join(':')}" end my_dsl { ... } # Prints "Evaluating block from (irb):118"
RubyVM.resolve_feature_path
For string name, returns what path require(name) will load (without actually loading it).
- Reason: Static analysis of the program (finding the code it will use without really loading it); understanding where dependencies are coming from.
- Discussion: Feature #15230
- Documentation: —
- Code:
RubyVM.resolve_feature_path('net/http') # => [:rb, "<...>/ruby-2.6.0/lib/ruby/2.6.0/net/http.rb"] RubyVM.resolve_feature_path('syslog') # => [:so, "<...>/ruby-2.6.0/lib/ruby/2.6.0/x86_64-linux/syslog.so"] RubyVM.resolve_feature_path('garbage') # LoadError (cannot load such file -- garbage) require 'net/http' RubyVM.resolve_feature_path('net/http') # => [:rb, false] -- for already loaded libraries, the path would not be returned # For gems: RubyVM.resolve_feature_path('faraday') # LoadError (cannot load such file -- faraday) gem 'faraday' # without this, gems can not be deduced RubyVM.resolve_feature_path('faraday') # => [:rb, "<...>/gems/faraday-0.15.4/lib/faraday.rb"] - Follow-up: In Ruby 2.7,
resolve_feature_pathwas moved to a$LOAD_PATHsingleton method, and its behavior for already loaded pathes was fixed to return path nevertheless.
RubyVM::AbstractSyntaxTree
The new module provides an “official” Ruby parser, replacing stdlib Ripper (and third-party parsers). The module is considered experimental, and its API can change in the future versions.
- Documentation:
RubyVM::AbstractSyntaxTree - Code:
tree = RubyVM::AbstractSyntaxTree.parse('1+2') # => #<RubyVM::AbstractSyntaxTree::Node(SCOPE(0) 1:0, 1:3): > tree.type # => :SCOPE tree.children # => [[], nil, #<RubyVM::AbstractSyntaxTree::Node(OPCALL(36) 1:0, 1:3): >] tree.children[2].type # => :OPCALL tree.children[2].children # => [#<RubyVM::AbstractSyntaxTree::Node(LIT(59) 1:0, 1:1): >, :+, #<RubyVM::AbstractSyntaxTree::Node(ARRAY(42) 1:2, 1:3): >] tree.children[2].children[0].children # => [1] - Note: One may be excited about
RubyVM::AbstractSyntaxTree.of(proc), but it doesn’t mean the “real” extraction of code from liveProc, rather a simple hack with trying to find proc’s source file and parse it. - Follow-up: In Ruby 3.2, new options were added for
parse, allowing to:- Perform fault-tolerant parsing (parse syntactically wrong/incomplete code);
- Preserve tokens from source code alongside nodes;
TracePoint improvements
Ruby TracePoint API allows to observe any events that are happening during program evaluation. In 2.6, there were several improvements to allow better control on event handling and their introspection.
#parameters
On :b_call and :c_call (block and method call events), TracePoint now provides #parameters method to fetch call params definitions.
- Discussion: Feature #14694
- Documentation:
TracePoint#parameters - Code:
t = TracePoint.new(:b_call) { |tp| p [tp.event, tp.parameters] } t.enable [1, 2, 3].map { |x| x.to_s } # [:b_call, [[:opt, :x]]] # [:b_call, [[:opt, :x]]] # [:b_call, [[:opt, :x]]] - Notice: Format of return value is the same as for
Method#parameters
:script_compiled event
Event fired when a new piece of Ruby code is loaded (through eval, require or load). #instruction_sequence on this event will return compiled RubyVM::InstructionSequence object, and #eval_script will return the text of the script sent to eval.
- Discussion: Feature #15287
- Documentation: TracePoint: Events (though new event seems to be omitted),
TracePoint#instruction_sequence,TracePoint#eval_script - Code:
t = TracePoint.new(:script_compiled) { |tp| p [tp.event, tp.instruction_sequence, tp.eval_script] } t.enable eval('p 1') # [:script_compiled, <RubyVM::InstructionSequence:<main>@(eval):1>, "p 1"] require 'net/http' # [:script_compiled, <RubyVM::InstructionSequence:<top (required)>@.../ruby-2.6.0/lib/ruby/2.6.0/net/http.rb:0>, nil] # [:script_compiled, <RubyVM::InstructionSequence:<top (required)>@.../ruby-2.6.0/lib/ruby/2.6.0/net/protocol.rb:0>, nil] # [:script_compiled, <RubyVM::InstructionSequence:<top (required)>@.../ruby-2.6.0/lib/ruby/2.6.0/socket.rb:0>, nil] # .....
#enable: new params target: and target_line:
With new parameters provided, you can fine-tune for what methods or specific lines to catch events.
- Reason: Less trace garbage and performance footprint on tracing in complex codebase, allowing very specific tracepoints to be enabled even in production.
- Discussion: Feature #15289.
- Documentation:
TracePoint#enable(not much, though…) - Code:
t = TracePoint.new(:line) { |tp| p tp } def m1 p 1 end def m2 p 2 end t.enable(target: method(:m1)) m1 # prints #<TracePoint:line@test.rb:5 in `m1'> m2 # prints nothing - Notice: In absence of docs, we can at least point at commit message:
codeshould be consisted ofInstructionSequence(iseq) (RubyVM::InstructionSequence.of(code)should not return nil). If code is a tree of iseq,TracePointis enabled on all of iseqs in a tree. - Follow-ups:
- In 2.7, the docs have emerged, and a new parameter named
target_thread:was introduced. It was missing from the officialNEWS-file and therefore missing from this changelog (which is a thing to be fixed!) - In 3.2,
target_thread:began defaulting to the current thread with block form ofenable.
- In 2.7, the docs have emerged, and a new parameter named
Standard library
- Bundler is added to Standard Library: Feature #12733.
Kernel#BigDecimal()method now acceptsexception:argument (see above for explanations)URInow can openfile://URIs,URI::Fileclass added.- Documentation:
URI::File - Discussion: Feature #14035
- Documentation:
Net::HTTP:write_timeoutadded- Documentation:
Net::HTTP#write_timeout= - Discussion: Feature #13396
- Documentation:
Net::HTTPServerErrorrenamed toNet::HTTPClientException- Discussion: Bug #14688
FileUtils.cp_lradded- Documentation:
FileUtils.cp_lr - Discussion: Feature #4189
- Documentation:
Large updated libraries
- RubyGems 3.0.1: Changelog
- RDoc: Changelog is outdated.
- CSV 3.0.2: Changelog.
- REXML 3.1.9: Changelog.
- Matrix 1.0.0: Changelog.
- RSS: No Changelog available.
Libraries promoted to default gems
stdgems.org project has a nice explanations of default and bundled gems concepts, as well as a list of currently gemified libraries.
“For the rest of us” this means libraries development extracted into separate GitHub repositories, and they are just packaged with main Ruby before release. It means you can do issue/PR to any of them independently, without going through more tough development process of the core Ruby.
Libraries extracted in 2.6:
Follow-up:
- 16 more libraries gemified in 2.7, and 6 just dropped from the standard library;
- 34 (!) more libraries gemified in 3.0, and 3 more just dropped from the standard library (including webrick).