In ruby, there are two fundamental concepts for organizing methods: classes and modules.
A class is a blueprint or template for building objects. Classes have properties or attributes that are unique to the class while methods determine actions that can be carried out on the class, especially via manipulating the properties.
For example, we can decide to model a human class. Humans normally have legs, hands, a name, and other properties and they can say their names. Let's quickly wire that up
class Human
def initialize(no_of_hands, no_of_legs, name)
@no_of_hands = no_of_hands
@no_of_legs = no_of_legs
@name = name
end
def name
"Hi there, my name is #{@name}"
end
def name=(new_name)
@name = new_name
end
end
lm = Human.new(2, 4, 'lege miami')
puts lm.name # Hi there, my name is lege miami
lm.name = 'bugs bunny'
puts lm.name # Hi there, my name is bugs bunny
From the above code block, we defined a class or blueprint as we mentioned earlier called Human
with three instance properties and two instance methods, one being a getter
and the other being a setter
. The class is further instantiated with the initialized properties and then an action is carried out on the next line which prints the instance name as "lege miami". We further set the instance name to a new name via the setter method and when we log it, we see that the new name changes to "bugs bunny"
Imagine that we had about six instance properties, we would have to create a getter and setter method(if we intend to change them) for each and that will be twelve methods altogether. Thankfully Ruby has a shortcut called attr_accessor
which essentially helps you have a getter and setter in one piece. See the refactored code below:
class Human
attr_accessor :no_of_hands, :no_of_legs, :name
def initialize(no_of_hands, no_of_legs, name)
@no_of_hands = no_of_hands
@no_of_legs = no_of_legs
@name = "Hi there, my name is #{name}"
end
end
lm = Human.new(2, 4, 'lege miami')
puts lm.name # Hi there, my name is lege miami
lm.name = 'bugs bunny'
puts "Hi there, my name #{lm.name}" # Hi there, my name is bugs bunny
Now we don't have to define a specific getter and setter method as attr_accessor has taken care of that. There are also attr_reader
which creates only the reader and attr_writer
which creates only the writer. Methods are public
by default but they can also be made private
or protected
depending on the use case.
Modules in Ruby provide a way to organize code that allows for more flexibility than through a standard class. Including a module in a class allows that class use of the code within the module. The effect of this is similar to a child-class inheriting code from a parent-class.
Modules serve two purposes. First, they act as a namespace, letting you define methods whose names won’t clash with those defined elsewhere. Second, they allow you to share functionality among classes. If a class mixes in a module, that module’s methods become available as if they’d been defined in the class. Multiple classes can mix in the same module, sharing the module’s functionality without using inheritance. You can also mix multiple modules into a single class.
Let's look at how to use a module:
module RandomHelper
def capitalize_words(string)
string.split(' ').map {|word| word.capitalize}.join(' ')
end
end
class Questioner
include RandomHelper
def capitalize(string)
RandomHelper::capitalize_words(string)
end
end
question = Questioner.new
puts question.capitalize_words('is software engineering rewarding?') # Is Software Engineering Rewarding?
Here we have defined a module RandomHelper
because we are lazy with naming(you should not be in real life) and put in it a method capitalize_words
which turns the first letter of every word in the sentence passed into it into a capital letter and then we include
it in a class so it can be used. This class Questioner
(because naming is hard) is then instantiated before the instance calls the method in the module.
These organizing structures are largely used in Ruby on Rails with different flavors.
For further reading and possibilities;
Top comments (0)