Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Weird Ruby (RubyDay 2024, Verona)

Weird Ruby (RubyDay 2024, Verona)

A weird talk. :-)

Bozhidar Batsov

May 31, 2024
Tweet

More Decks by Bozhidar Batsov

Other Decks in Programming

Transcript

  1. #68

  2. 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
  3. class String def shout self.upcase + "!!!" end end puts

    "hello".shout # Outputs: HELLO!!! 1. Monkey Patching
  4. 2. Open classes class Integer def is_even? self % 2

    == 0 end end puts 2.is_even? # Outputs: true
  5. 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)
  6. 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
  7. 9. Self context changes class SelfExample def show_self puts self

    end end SelfExample.new.show_self # Outputs: #<SelfExample:0x0000560c7c8b3a00>
  8. 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
  9. 1.

  10. WAT

  11. 2.

  12. 3.

  13. class SomeClass =begin This is a top comment. Or is

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

    it? =end def some_method end end
  15. 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
  16. 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"
  17. # 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
  18. ENV

  19. 012

  20. ++x

  21. X

  22. # Don't do this at home! class Integer def !

    (1..self).reduce(:*) end end 5.! # => 120 !5 # => 120
  23. # 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"]
  24. # Examples in Bulgarian with Cyrilic letters below # Looking

    good! '1999б'.succ # => "1999в" # WAT!!! '1999я'.succ # => "1999ѐ"
  25. # frozen_string_literal: true foo = "string" foo.upcase! # => FrozenError

    - can't modify frozen String (+foo).upcase! # => "STRING"
  26. 1. fi nite? => true 1.in fi nite? => nil

    Float::INFINITY. fi nite? => false Float::INFINITY.in fi nite? => 1
  27. 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
  28. # => "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"
  29. 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
  30. # => "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"
  31. 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
  32. 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.
  33. 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)
  34. 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)
  35. Explicit is better than implicit. Errors should never pass silently.

    In the face of ambiguity, refuse the temptation to guess.