Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Ciao!

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Third time is the charm!

Slide 14

Slide 14 text

The best is yet to come…

Slide 15

Slide 15 text

Bozhidar (Божидар)

Slide 16

Slide 16 text

a.k.a. Bug (Бъг) / Bozho (Божо)

Slide 17

Slide 17 text

@bbatsov

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

✅ Older

Slide 21

Slide 21 text

❌ Wiser

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Su + giu = sugiu

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Seiko 6105 (a.k.a. Captain Willard)

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

Casio

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

Open-Source Projects

Slide 42

Slide 42 text

bbatsov

Slide 43

Slide 43 text

Ruby & Rails style guides

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

RuboCop supports Prism now! (In other words - RuboCop is faster)

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

RuboCop turned 12 on April 21!

Slide 48

Slide 48 text

Total Downloads: 424,020,934

Slide 49

Slide 49 text

13 million downloads between Balkan Ruby & RubyDay! (1 month)

Slide 50

Slide 50 text

#68

Slide 51

Slide 51 text

RuboCop 1.64.1 is out today to celebrate RubyDay!

Slide 52

Slide 52 text

Weird Ruby

Slide 53

Slide 53 text

Dictionary de fi nitions

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

A dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write. — ruby-lang.org

Slide 57

Slide 57 text

Weird != Bad

Slide 58

Slide 58 text

Weird is Subjective

Slide 59

Slide 59 text

ChatGPT, what are the 10 most weird features of the Ruby programming language?

Slide 60

Slide 60 text

class String def shout self.upcase + "!!!" end end puts "hello".shout # Outputs: HELLO!!! 1. Monkey Patching

Slide 61

Slide 61 text

2. Open classes class Integer def is_even? self % 2 == 0 end end puts 2.is_even? # Outputs: true

Slide 62

Slide 62 text

3. Symbols puts :symbol.object_id == :symbol.object_id

Slide 63

Slide 63 text

4. Block, procs and lambdas def execute_block(&block) block.call end execute_block { puts "Hello from a block!" }

Slide 64

Slide 64 text

5. Method missing class DynamicMethods def method_missing(name, *args) puts "Called #{name} with #{args}" end end dm = DynamicMethods.new dm.some_method(1, 2, 3)

Slide 65

Slide 65 text

6. Metaprogramming class MetaClass def self.create_method(name) define_method(name) { puts "#{name} method called" } end end MetaClass.create_method(:dynamic) obj = MetaClass.new obj.dynamic # Outputs: dynamic method called

Slide 66

Slide 66 text

7. Flexible syntax puts 'single quoted' puts "double quoted" puts %q{percent q} puts %Q{percent Q}

Slide 67

Slide 67 text

8. Implicit returns def add(a, b) a + b end

Slide 68

Slide 68 text

9. Self context changes class SelfExample def show_self puts self end end SelfExample.new.show_self # Outputs: #

Slide 69

Slide 69 text

10. Keyword arguments with default values def greet(name:, greeting: "Hello") puts "#{greeting}, #{name}" end greet(name: "Alice") # Outputs: Hello, Alice greet(name: "Bob", greeting: "Hi") # Outputs: Hi, Bob

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

Grazie! twitter: @bbatsov github: @bbatsov https://metaredux.com https://batsov.com RubyDay 2024 Verona, Italy 31.05.2024

Slide 72

Slide 72 text

Ruby is 31 years old!

Slide 73

Slide 73 text

Whatever doesn’t kill you simply makes you weirder. — The Joker

Slide 74

Slide 74 text

Ground rules

Slide 75

Slide 75 text

3 Levels of weirdness

Slide 76

Slide 76 text

1.

Slide 77

Slide 77 text

WAT

Slide 78

Slide 78 text

Mamma mia!

Slide 79

Slide 79 text

Ma sei serio!

Slide 80

Slide 80 text

2.

Slide 81

Slide 81 text

F**k This Sh*t

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

Ma dai!

Slide 84

Slide 84 text

Cosa c*zzo cosa!

Slide 85

Slide 85 text

Che c*zzo e!

Slide 86

Slide 86 text

Cosa c*zzo e!

Slide 87

Slide 87 text

3.

Slide 88

Slide 88 text

Holy sh*t!

Slide 89

Slide 89 text

Madonna!

Slide 90

Slide 90 text

The Contenders

Slide 91

Slide 91 text

The (un)Usual Suspects…

Slide 92

Slide 92 text

END { puts 'Bye!' } puts 'Processing...' BEGIN { puts 'Starting...' }

Slide 93

Slide 93 text

DATA.each_line do |line| print(line) if (line =~ /begin/)..(line =~ /end/) end

Slide 94

Slide 94 text

=begin comment line another comment line =end

Slide 95

Slide 95 text

Must be placed at the very beginning of a line

Slide 96

Slide 96 text

class SomeClass =begin This is a top comment. Or is it? =end def some_method end end

Slide 97

Slide 97 text

class SomeClass =begin This is a top comment. Or is it? =end def some_method end end

Slide 98

Slide 98 text

pry(main)> ?a => "a"

Slide 99

Slide 99 text

irb> ?\C-\a => "\a" irb> ?\C-\M-\f => "\x8C"

Slide 100

Slide 100 text

Reassignable constants

Slide 101

Slide 101 text

pry(main)> A = 5 => 5 pry(main)> A = 6 (pry):39: warning: already initialized constant A (pry):38: warning: previous definition of A was here => 6 pry(main)> Class = 3 (pry):40: warning: already initialized constant Class => 3 pry(main)> Class => 3

Slide 102

Slide 102 text

No content

Slide 103

Slide 103 text

Class variables

Slide 104

Slide 104 text

class Parent @@class_var = 'parent' def self.print_class_var puts @@class_var end end class Child < Parent @@class_var = 'child' end Parent.print_class_var # => will print "child"

Slide 105

Slide 105 text

# Unintended usage: the variable is defined in the child, but then the parent changes it class Bad def self.corrupt_registry! @@registry = [] end end class BadChild < Bad @@registry = {} # This is some variable which meant to belong to THIS class def self.registry @@registry end end Bad.corrupt_registry! # Probably unexpected for BadChild's author, its ancestor have changed the variable BadChild.registry # On the next attempt to _access_ the variable the error will be raised # 2.7: => [] # 3.0: RuntimeError (class variable @@registry of BadChild is overtaken by Bad) Ruby 3.0 changes

Slide 106

Slide 106 text

Let’s get really weird!

Slide 107

Slide 107 text

true || true && false

Slide 108

Slide 108 text

true || (true && false)

Slide 109

Slide 109 text

=> true

Slide 110

Slide 110 text

true or true and false

Slide 111

Slide 111 text

(true or true) and false

Slide 112

Slide 112 text

=> false

Slide 113

Slide 113 text

ENV

Slide 114

Slide 114 text

{“COLORFGBG"=>"7;0", "COLORTERM"=>"truecolor", "COMMAND_MODE"=>"unix2003", "GEM_HOME"=>"/Users/bbatsov/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0", "HOME"=>"/Users/bbatsov", "HOMEBREW_CELLAR"=>"/opt/homebrew/Cellar", "HOMEBREW_PREFIX"=>"/opt/homebrew", “HOMEBREW_REPOSITORY"=>"/opt/homebrew"}

Slide 115

Slide 115 text

ENV.class

Slide 116

Slide 116 text

ENV.class => Object

Slide 117

Slide 117 text

012

Slide 118

Slide 118 text

012 => 10

Slide 119

Slide 119 text

No content

Slide 120

Slide 120 text

0o12 => 10

Slide 121

Slide 121 text

0b10 0o12 0xab

Slide 122

Slide 122 text

1if 2 Yep

Slide 123

Slide 123 text

def foo; 1return; end Nope

Slide 124

Slide 124 text

++x

Slide 125

Slide 125 text

+++-+++-+++x

Slide 126

Slide 126 text

+++x => (+(+(+x)))

Slide 127

Slide 127 text

X

Slide 128

Slide 128 text

Twitter -> X

Slide 129

Slide 129 text

twitter.com -> x.com

Slide 130

Slide 130 text

@batsov.net

Slide 131

Slide 131 text

@bbatsov.hachyderm.io

Slide 132

Slide 132 text

Object-Oriented Negation

Slide 133

Slide 133 text

something.foo.! # double negation something.bar.!.! (x == y).! (x == y).!.! 10.!

Slide 134

Slide 134 text

# Don't do this at home! class Integer def ! (1..self).reduce(:*) end end 5.! # => 120 !5 # => 120

Slide 135

Slide 135 text

Incrementing Strings

Slide 136

Slide 136 text

1.succ # => 2 (1..10).to_a # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Slide 137

Slide 137 text

No content

Slide 138

Slide 138 text

# looking good ('1.0'..'1.5').to_a # => ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5"] # oh, shit! ('1.0'..'1.10').to_a # => ["1.0", # "1.1", # "1.2", # "1.3", # "1.4", # "1.5", # "1.6", # "1.7", # "1.8", # "1.9", # "2.0", # "2.1", # ... # "99.9"]

Slide 139

Slide 139 text

# Examples in Bulgarian with Cyrilic letters below # Looking good! '1999б'.succ # => "1999в" # WAT!!! '1999я'.succ # => "1999ѐ"

Slide 140

Slide 140 text

Positive & Negative Strings

Slide 141

Slide 141 text

content = +"\n" content << "## #{title}\n" content << "\n" content

Slide 142

Slide 142 text

# frozen_string_literal: true foo = "string" foo.upcase! # => FrozenError - can't modify frozen String (+foo).upcase! # => "STRING"

Slide 143

Slide 143 text

Zeroing in on Zero!

Slide 144

Slide 144 text

0.zero? # => true 0.nonzero? #=> nil 1.zero? #=> false 1.nonzero? #=> 1

Slide 145

Slide 145 text

To In fi nity and Beyond!

Slide 146

Slide 146 text

1. fi nite? => true 1.in fi nite? => nil Float::INFINITY. fi nite? => false Float::INFINITY.in fi nite? => 1

Slide 147

Slide 147 text

Single-quoted Heredocs

Slide 148

Slide 148 text

land = 'Mordor' verse = <<-TEXT One Ring to rule them all, One Ring to find them, One Ring to bring them all, and in the darkness bind them, In the Land of #{land} where the Shadows lie. TEXT

Slide 149

Slide 149 text

# => "One Ring to rule them all,\n" + # "One Ring to find them,\n" + # "One Ring to bring them all,\n" + # "and in the darkness bind them,\n" + # "In the Land of Mordor where the Shadows lie.\n"

Slide 150

Slide 150 text

land = 'Mordor' verse = <<-'TEXT' One Ring to rule them all, One Ring to find them, One Ring to bring them all, and in the darkness bind them, In the Land of #{land} where the Shadows lie. TEXT

Slide 151

Slide 151 text

# => "One Ring to rule them all,\n" + # "One Ring to find them,\n" + # "One Ring to bring them all,\n" + # "and in the darkness bind them,\n" + # "In the Land of \#{land} where the Shadows lie.\n"

Slide 152

Slide 152 text

<<'END HTML' ... END HTML <<'\n!"£$%^&*()-=_+[];#{}:@~,./<>?|`\' hello \n!"£$%^&*()-=_+[];#{}:@~,./<>?|`\

Slide 153

Slide 153 text

Nested Heredocs

Slide 154

Slide 154 text

outer = <<-OUTER This is the outer heredoc. It contains an inner heredoc: #{<<-INNER} This is the inner heredoc. It is nested within the outer heredoc. It can contain its own multi-line text. INNER The outer heredoc continues here. OUTER

Slide 155

Slide 155 text

This is the outer heredoc. It contains an inner heredoc: This is the inner heredoc. It is nested within the outer heredoc. It can contain its own multi-line text. The outer heredoc continues here.

Slide 156

Slide 156 text

No content

Slide 157

Slide 157 text

Invoking Lambdas

Slide 158

Slide 158 text

add_five = ->(x) { x + 5}

Slide 159

Slide 159 text

add_five.call(10) # => 15

Slide 160

Slide 160 text

add_five.(10) # => 15

Slide 161

Slide 161 text

add_five[10] # => 15

Slide 162

Slide 162 text

add_five.yield(10) # => 15

Slide 163

Slide 163 text

add_five === 10 # => 15

Slide 164

Slide 164 text

No content

Slide 165

Slide 165 text

The Record for Most Aliases

Slide 166

Slide 166 text

Hash#include?

Slide 167

Slide 167 text

Hash#member?

Slide 168

Slide 168 text

Hash#key?

Slide 169

Slide 169 text

Hash#has_key?

Slide 170

Slide 170 text

No content

Slide 171

Slide 171 text

Honorable mentions

Slide 172

Slide 172 text

Queue#pop Queue#deq Queue#shift Queue#push Queue#enq Queue#<< Enumerable#select Enumerable# fi lter Enumerable# fi nd_all

Slide 173

Slide 173 text

Mixing Code & Data

Slide 174

Slide 174 text

DATA.each_line do |line| puts line end __END__ I am Groot

Slide 175

Slide 175 text

I am Groot

Slide 176

Slide 176 text

Making something out of nothing!

Slide 177

Slide 177 text

irb(main):001:0> nil.to_h => {} irb(main):002:0> nil.to_a => [] irb(main):003:0> nil.to_s => "" irb(main):004:0> nil.to_f => 0.0 irb(main):005:0> nil.to_i => 0 irb(main):006:0> nil.to_c => (0+0i)

Slide 178

Slide 178 text

irb(main):001:0> Array(nil) => [] irb(main):002:0> Hash(nil) => {} irb(main):003:0> Integer(nil) # `Integer': can't convert nil into Integer (TypeError) irb(main):004:0> Float(nil) # `Float': can't convert nil into Float (TypeError)

Slide 179

Slide 179 text

Explicit is better than implicit. Errors should never pass silently. In the face of ambiguity, refuse the temptation to guess.

Slide 180

Slide 180 text

This is Ruuuuubyyyyy!!!

Slide 181

Slide 181 text

Keep Ruby Weird!

Slide 182

Slide 182 text

Grazie! twitter: @bbatsov github: @bbatsov https://metaredux.com https://batsov.com RubyDay 2024 Verona, Italy 31.05.2024