work in progress article
Classes
Ruby is a OOP (Object-Oriented Programming Language) and everything is an object, even nil
, false
and true
.
But what about functional programming?
- You can use the functional paradigm with any language.
- Don't mix with Functional Programming Languages (Haskell, Erlang, Clojure...)
- Some of the main differences between OOP and FP: Immutable data and Pure functions
| So, knowing that Ruby is a OOP, what happens when you call a method? Basically, Ruby will try to find the method in the current class, then will move up trying to find it.
class Animal
def name
'animal'
end
end
class Dog < Animal
end
puts Animal.new.name # => 'animal'
puts Dog.new.name # => 'animal'
To check the parents classes of an object, there's the 'ancestors' method.
1.ancestors # => [Integer, Numeric, Comparable, Object, Kernel, BasicObject]
If even after traversing the whole stack up to BasicObject and does not find it you'll receive an Exception
:
10.hey # => NoMethodError (undefined method `hey' for 10:Integer)
In this case, the hey
method was searched in the Integer, then Numeric and so on.
Ok, but how do I know and find where a method was defined?
p Dog.new.method(:name).source_location # => ["file.rb", 2]
The method name
was defined into the file.rb
at line 2.
__
Modules
It's a way to componentize your methods. Let's say you have a Log
module that creates some
methods. You can just include this module inside other classes and these classes will be
able to use the module methods.
Extend, Include and Prepend
You can load a module with this three forms.
- include: instance methods
- extend: class methods
- prepend: upfront instance methods
module A
def a
'A'
end
end
module B
def b
'B'
end
end
module C
def c
'C'
end
end
class Person
include A
extend B
prepend C
def c
'called c at person class '
end
end
puts Person.new.a # => 'A'
puts Person.b # => 'B'
puts Person.new.c # => 'C'
Monkey Patching and Refinements
=> Monkey Patching is the way to change and add methods inside classes.
class Integer
def hey
'hooyaa'
end
end
10.hey # => "hooyaa"
It's a good practice? Well, I think so. Rails with ActiveSupport uses it quite a lot to add new methods in Ruby Core Classes, you can also use it to extend or change the behavior of a external gem.
class Float
def round
'no'
end
end
1.2.round # => "no"
What about Refinements?
=> As Monkey Patch scope is global, meaning it can break a lot of things if you're changing the default behavior of a method, Refinement is a way to limit the monkey patch.
module Rounded
refine Float do
def round
'no'
end
end
end
class A
def rounded
1.5.round
end
using Rounded
def refined_rounded
1.5.round
end
end
puts A.new.rounded # => 2
puts A.new.refined_rounded # => no