Skip to content

Ruby and Rails: The Bad Parts by Volodymyr Melnyk

| ruby |

References

These notes are compiled from https://speakerdeck.com/egoholic/ruby-and-rails-the-bad-parts.

Good Parts

  • It has high abilities in meta-programming
  • It’s good for DSL
  • It allows to write prototypes very fast
  • It has a huge ecosystem with tons of gems and development tools

Bad

Ruby isn’t Static- typed

Ruby has no typed signatures. This means that you need to do all type checks manually.

x=5
y = string"
lambda = ->{ x + y }

# you will not get an
# error until execution
# next code line:

lambda.call

Ruby has an unclear concept of Module

In Ruby a module is a class which can’t have instances and can be included into another class or another class can be extended with it.

module InstanceMethods; end
module ClassMethods; end
class C
  include InstanceMethods
  extend  ClassMethods
end
C.ancestors
#=> [C, InstanceMethods, Object, Kernel, BasicObject]
C.singleton_class.ancestors
#=> [
#   #<Class:C>, ClassMethods, #<Class:Object>,
# <Class:BasicObject>, Class, Module, Object, Kernel, # BasicObject
#]

Proc and Lambda

In Ruby we have a Proc class and two types of its instances (it’s strange), but actually we need only one of them (as for me, I prefer lambdas).

p1 = Proc.new { |a, b| a + b }
p2 = Proc.new { |a, b| return a + b }
l1 = ->(a, b) { a + b }
l2 = ->(a, b) { return a + b }
p1.class   # Proc
l1.class   # Proc
p1.lambda? # false
l1.lambda? # true
def mtd(pobj, a, b = nil)
  args = b ? [a, b] : [a]
  puts "method code 1"
  puts pobj.call *args
  puts "method code 2"
end

mtd p1, 1 
# method code 1 
# TypeError: nil can't be coerced into Fixnum
mtd p1, 1, 3 
# method code 1  # 4 
# method code 2
mtd p2, 1 
# method code 1 
# TypeError: nil can't be coerced into Fixnum
mtd p2, 1, 3 
# method code 1 
# LocalJumpError: unexpected return

mtd l1, 1 
# method code 1 
# ArgumentError: wrong number of arguments (1 for 2)
mtd l1, 1, 3 
# method code 1  # 4 
# method code 2
mtd l2, 1 
# method code 1 
# ArgumentError: wrong number of arguments (1 for 2)
mtd l2, 1, 3 
# method code 1  # 4 
# method code 2

Ruby Standard Library is a ghetto

Ruby Standard Library has a huge number of low-quality and useless libraries.

Abbrev

require 'abbrev'
%w{ car cone }.abbrev #=> {  “car” => "car", 
  "ca" => "car", 
  "cone" => "cone", 
  "con" => "cone", 
  "co" => "cone"  
}

Delegator

class SimpleDelegator < Delegator
  def initialize obj 
    super 
    @delegate_sd_obj = obj  
  end

  def __getobj__  
    @delegate_sd_obj 
  end

  def __setobj__ obj  
    @delegate_sd_obj = obj 
  end  
end

Alternate syntax

Ruby has a lot of alternate syntaxes for different things. Because of that Ruby code can look very differently.

  • {...} vs do ... end
  • ->() {...}, -> {}, lambda {|| }, lambda {}
  • def mtd(a, b), def mtd a, b
  • 0..10, 0...10
  • %w{}, %w[], %w(), %w//, %w"", %w||, %w[], %W[], %i[], %i[] //, %r//, %s[]
  • '', ""

&& versus and

n = 1 && n + 1
# NoMethodError: undefined
# method `+' for nil


n = 1 #=> 1
n = 2 && n + 1 #=> 2
n = 2 && n + 1 #=> 3
n = 2 && n + 1 #=> 4
n = 2 && n + 1 #=> 5
n #=> 5
n = 1 and n + 1 #=> 2

n = 1 #=> 1
n = 2 and n + 1 #=> 3
n = 2 and n + 1 #=> 3
n = 2 and n + 1 #=> 3
n = 2 and n + 1 #=> 3
n #=> 2

|| versus or

n = 1  n = 1 
n = nil || n + 2 #=> 3 


n = nil or n + 2 
# NoMethodError: undefined  
# method `+' for nil

Values against expressions You should know!

Boolean Algebra Fail

If && and || are boolean operators, why their in/out arguments aren’t booleans?

true && "string"
#=> "string"

1 || nil #=> 1

Ruby is not that strongly-typed language.

Add more cases

nil

nil is

  • more code
    • checks
    • special cases
    • error handling
  • more specs / tests
  • more errors