
goruby
Ruby not concise enough? In the source code, you’ll find a file called golf_prelude.rb. Include it in the compilation and you get goruby where each method has its own abbreviation, the String class behaves like an Array, … to be as concise as possible!
Small reference in the Ruby documentation for goruby: ruby-doc.org/3.3.6/extension…
squadracer.com/en/weeklytips…
casecmp
Case insensitive comparison
casecmp? compares 2 strings without taking case into account. When it comes to unicode characters, there are a few subtleties! With a non-compatible type, the method returns nil rather than an exception.
There’s also the casecmp method for comparing 2 strings without taking case into account, but it returns -1, 0 or 1 (or nil if incompatible) which can be used to sort, for example.
Links to Ruby documentation for casecmp? (ruby-doc.org/3.3.6/String.ht…) and casecmp (ruby-doc.org/3.3.6/String.ht…).
squadracer.com/en/weeklytips…
||= vs defined?
Cache false/nil
||= is the most common way of caching. Except that it doesn’t handle false and nil! defined? can be a solution by checking whether the variable is defined. ⚠️ Be sure to take into account when the parser defines the variable!
Links to Ruby documentation for
||= (ruby-doc.org/3.3.6/syntax/as…)
defined? (ruby-doc.org/3.3.6/syntax/mi…)
squadracer.com/en/weeklytips…
local variable, a detail on how they work
They are created when the parser encounters them, not dynamically at runtime! Furthermore, a if does not create a new scope, making variables accessible after the scope has ended. This is also the case for unless, while, until and for.
A more interesting example highlighting the parser step. In the 1st if, the parser sees and creates the a variable after the condition, which will therefore be false at runtime. In the 2nd case, it sees and creates b before! (A if inline is therefore not equivalent!)
Link to Ruby documentation for local variables: ruby-doc.org/3.3.6/syntax/as…
squadracer.com/en/weeklytips…
tap
For method chaining
The tap method, defined in Kernel, returns self which is passed as a block argument. To be distinguished from then, which returns the result of the block.
The main benefit is to be able to alter the object in the method chain. Another use case is to be able to inspect an intermediate state without having to rewrite everything.
Link to Ruby documentation for tap: ruby-doc.org/3.3.5/Kernel.ht…
squadracer.com/en/weeklytips…
**{double splat operator}
The double splat operator (or keyword splat) has been around since Ruby 2.0. It’s the equivalent of the splat operator but for Hash.
⚠️ There is a subtle difference with the splat operator. It doesn’t handle nil. Well, not yet, because after more than 10 years, it will in Ruby 3.4.0 (see Issue 20064: bugs.ruby-lang.org/issues/20…).
Link to Ruby documentation for double splat operator: ruby-doc.org/3.3.5/syntax/ca…
squadracer.com/en/weeklytips…
Need to speed up?
Benchmark allows you to measure the execution time of a block with measure. You’ll find user and system CPU times, as well as the sum of the two. In brackets, the actual time. The unit is seconds. In this example, it’s long but not CPU-intensive.
Comparing implementations is generally more interesting, and can be done with bm or bmbm. The bmbm is run twice to « warm up » the code for a more accurate result. For example, compare flat_map and map { ... }.flatten and check that flat_map is indeed faster.
![require 'benchmark'
result = Benchmark.bmbm do |bm|
list = (0..1_000).to_a
bm.report "flat_map" do
list.flat_map { |x| [x, x * x] }
end
bm.report "map.flatten" do
list.map { |x| [x, x * x] }.flatten
end
end
puts result
# Rehearsal -----------------------------------------------
# flat_map 0.000085 0.000000 0.000085 ( 0.000085)
# map.flatten 0.000230 0.000001 0.000231 ( 0.000231)
# -------------------------------------- total: 0.000316sec
#
# user system total real
# flat_map 0.000080 0.000000 0.000080 ( 0.000078)
# map.flatten 0.000215 0.000001 0.000216 ( 0.000214)](https://pbs.twimg.com/media/GYT_xcAWMAASumH.jpg?name=small&format=webp)
ALT require 'benchmark' result = Benchmark.bmbm do |bm| list = (0..1_000).to_a bm.report "flat_map" do list.flat_map { |x| [x, x * x] } end bm.report "map.flatten" do list.map { |x| [x, x * x] }.flatten end end puts result # Rehearsal ----------------------------------------------- # flat_map 0.000085 0.000000 0.000085 ( 0.000085) # map.flatten 0.000230 0.000001 0.000231 ( 0.000231) # -------------------------------------- total: 0.000316sec # # user system total real # flat_map 0.000080 0.000000 0.000080 ( 0.000078) # map.flatten 0.000215 0.000001 0.000216 ( 0.000214)
fast-ruby presents some interesting comparisons, like while vs loop, which do you think is faster? github.com/fastruby/fast-rub…
Link to Ruby documentation for Benchmark: ruby-doc.org/3.3.5/stdlibs/b…
squadracer.com/en/weeklytips…
rescue ... else
A case to handle if there are no exceptions?
Ruby allows default case handling only if there is no exception with else!
The else is only allowed if there are rescue and can therefore be used wherever rescue can be used: block, method and even class!
Link to Ruby documentation for exception handling: ruby-doc.org/3.3.5/syntax/ex…
squadracer.com/en/weeklytips…


!["a".casecmp "B" # => -1
"b".casecmp "B" # => 0
"c".casecmp "B" # => 1
%w[C E B d a f].sort(&:casecmp)
# => ["a", "B", "C", "d", "E", "f"]](https://pbs.twimg.com/media/Gc60jnhXcAAx9mM.jpg?name=small&format=webp)




![3.times.to_a.tap { _1[1] = 5 } # [0, 5, 2]
# vs
a = 3.times.to_a
a[1] = 5
a # [0, 5, 2]
3.times .tap { p _1 } # #<Enumerator: 3:times>
.map { _1 * 2 } .tap { p _1 } # [0, 2, 4]
.filter(&:positive?) # [2, 4]](https://pbs.twimg.com/media/GabJw57XsAASvOm.jpg?name=small&format=webp)

![[*nil] # []
{**nil} # TypeError (< 3.4.0)
{**nil} # {} (>= 3.4.0)](https://pbs.twimg.com/media/GZgpdUAXsAMCUK5.jpg?name=small&format=webp)


