Skip to content

Commit be37de5

Browse files
committed
Advent of Changelog: Day 11
1 parent 705bc6e commit be37de5

File tree

1 file changed

+80
-14
lines changed

1 file changed

+80
-14
lines changed

_src/3.3.md

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,13 @@ Two methods to accept an integer file descriptor as an argument: `for_fd` create
6363
# Same logic works for .fchdir
6464
Dir.fchdir(fileno) #=> 0
6565
Dir.pwd
66-
# "/home/zverok/projects/ruby/doc" -- the current path have changed successfully
66+
#=> "/home/zverok/projects/ruby/doc" -- the current path have changed successfully
67+
68+
# A block form of fchdir is available, like for a regular .chdir:
69+
Dir.fchdir(Dir.new('NEWS').fileno) do
70+
p Dir.pwd #=> "/home/zverok/projects/ruby/doc/NEWS"
71+
end
72+
Dir.pwd #=> "/home/zverok/projects/ruby/doc" -- back to the path before the block
6773
```
6874
* **Notes:**
6975
* The functionality is only supported on POSIX platforms;
@@ -81,8 +87,13 @@ An instance method version of [Dir.chdir](https://docs.ruby-lang.org/en/master/D
8187
dir = Dir.new('doc')
8288
dir.chdir #=> nil
8389
Dir.pwd #=> "/home/zverok/projects/ruby/doc"
90+
91+
# The block form works, too:
92+
Dir.new('NEWS').chdir do
93+
Dir.pwd #=> "/home/zverok/projects/ruby/doc/NEWS"
94+
end
95+
Dir.pwd #=> "/home/zverok/projects/ruby/doc"
8496
```
85-
* **Notes:** Unlike [Dir.chdir](https://docs.ruby-lang.org/en/master/Dir.html#method-c-chdir), the new method doesn't have a block form (the form that restores previous working directory after the block is finished).
8697

8798
### `MatchData#named_captures`: `symbolize_names:` argument
8899

@@ -301,37 +312,92 @@ Specialized `Range#reverse_each` method is implemented.
301312
```
302313
* **Notes:** Other than raising `TypeError` for endless ranges (which works with any type of range beginning), the specialized behavior is only implemented for `Integer`. A possibility of a generalization was [discussed](https://bugs.ruby-lang.org/issues/18515#note-4) by using object's `#pred` method (opposite to `#succ`, which the range uses to iterate forward), but the scope of this change would be bigger, as currently only `Integer` implements such method. It is possible that the adjustments would be made in the future versions.
303314

304-
### `Refinement#target` as an alternative of `Refinement#refined_class`
315+
### `Refinement#refined_class` is renamed to `Refinement#target`
316+
317+
Just a renaming of the unfortunately named new method that [emerged in Ruby 3.2](/rubychanges/3.2.html#refinementrefined_class).
305318

306-
* **Reason:**
307319
* **Discussion:** [Feature #19714]
308320
* **Documentation:** [Refinement#target](https://docs.ruby-lang.org/en/master/Refinement.html#method-i-target)
309-
* **Code:**
310-
* **Notes:**
311321

312322
### `String#bytesplice`: new arguments to select a portion of the replacement string
313323

314-
* **Reason:**
324+
The low-level string manipulation method now allows to provide a coordinates of the part of the replacement string to be used.
325+
326+
* **Reason:** The new "byte-oriented" methods [were introduced](https://rubyreferences.github.io/rubychanges/3.2.html#byte-oriented-methods) in Ruby 3.2 to support low-level programming like text editors or network protocol implementations. In those use cases, the necessity of copying of a small part of one string into the middle of another is frequent, and producing intermediate strings (by first slicing the necessary part) is costly.
315327
* **Discussion:** [Feature #19314]
316328
* **Documentation:** [String#bytesplice](https://docs.ruby-lang.org/en/master/String.html#method-i-bytesplice)
317329
* **Code:**
318-
* **Notes:**
330+
```ruby
331+
# Base usage
332+
'foo'.byteplice(1..2, 'bar', 0..1)
333+
# The receiver is modified
319334

320-
### `TracePoint` supports `rescue` event
335+
# Or, alternatively:
336+
'foo'.byteplice(1, 2, 'bar', 0, 1)
337+
338+
# Two forms can't be mixed:
339+
'foo'.byteplice(1..2, 'bar', 0, 1)
340+
# Semi-open ranges work:
341+
'foo'.byteplice(1..2, 'bar', 1..)
342+
'foo'.byteplice(1..2, 'bar', ..1)
343+
344+
```
345+
346+
### `TracePoint` supports `:rescue` event
347+
348+
Allows to trace when some exception was `rescue`'d in the code of interest.
321349

322-
* **Reason:**
323350
* **Discussion:** [Feature #19572]
324351
* **Documentation:** [TracePoint#Events](https://docs.ruby-lang.org/en/master/TracePoint.html#class-TracePoint-label-Events)
325352
* **Code:**
326-
* **Notes:**
353+
```ruby
354+
TracePoint.trace(:rescue) do |tp|
355+
puts "Exception rescued: #{tp.raised_exception.inspect} at #{tp.path}:#{tp.lineno}"
356+
end
327357

328-
### `Kernel#lambda` behavior change with non-lambda blocks
358+
begin
359+
raise "foo"
360+
rescue => e
361+
end
362+
# Prints: "Exception rescued: #<RuntimeError: foo> at example.rb:7
363+
```
364+
* **Notes:** The event-specific attribute for the event is the same as for `:raise`: [#raised_exception](https://docs.ruby-lang.org/en/master/TracePoint.html#method-i-raised_exception).
329365

330-
* **Reason:**
366+
### `Kernel#lambda` raises when passed `Proc` instance
367+
368+
* **Reason:** `lambda`'s goal is to create a lambda from provided literal block; in Ruby, it is impossible to change the "lambdiness" of the block once it is created. But `lambda(&proc_instance)` never notified users of that, which was confusing.
331369
* **Discussion:** [Feature #19777]
332-
* **Documentation:**
370+
* **Documentation:** [Kernel#lambda](https://docs.ruby-lang.org/en/master/Kernel.html#method-i-lambda) _(no specific details are provided, though)_
333371
* **Code:**
372+
```ruby
373+
# Intended usage:
374+
l = lambda { |a, b| a + b }
375+
l.lambda? #=> true
376+
l.parameters #=> [[:req, :a], [:req, :b]]
377+
378+
# Unintended usage:
379+
p = proc { |a, b| a + b }
380+
381+
# In Ruby 3.2 and below, it worked, but the produced value wasn't lambda:
382+
l = lambda(&p)
383+
l.parameters #=> [[:opt, :a], [:opt, :b]]
384+
l.lambda? #=> false
385+
l.object_id == p.object_id #=> true, it is just the same proc
386+
387+
# Ruby 3.3:
388+
l = lambda(&p)
389+
# in `lambda': the lambda method requires a literal block (ArgumentError)
390+
391+
# Despite the message about a "literal block," the method
392+
# works (though has no meaningful effect) with lambda-like Proc objects
393+
other_lambda = lambda { |a, b| a + b }
394+
lambda(&other_lambda) #=> works
395+
lambda(&:to_s) #=> works
396+
lambda(&method(:puts)) #=> works
397+
```
334398
* **Notes:**
399+
* The discussion was once [started](https://bugs.ruby-lang.org/issues/15973) from the proposal to make `lambda` change "lambiness" of a passed block, but it raises multiple issues (changing the block semantics mid-program is just one of them). In general, `lambda` as a _method_ is considered legacy, inferior to the `-> { }` lambda literal syntax, exactly due to problems like this: it looks like a regular method that receives a block, and therefore should be able accept _any_ block, but in fact it is "special" method. So in 3.0, there was a warning about `lambda(&proc_instance)`, and since 3.3, the warning finally turned into an error.
400+
* There is exactly one occurrence in Ruby where block semantics _changes_ mid-flight:
335401

336402
### Deprecate subprocess creation with method dedicated to files
337403

0 commit comments

Comments
 (0)