Reputation: 1139
I am trying to write a Person
class in Ruby which has some methods and properties. The below is how I have implemented it now.
class Person
attr_accessor :name, :gender, :mother
def initialize(name, gender, mother)
@name = name
@gender = gender
@mother = mother
@spouse = nil
end
def add_spouse(spouse)
if spouse
@spouse = spouse
spouse.spouse = self
end
end
def father(self)
return [self.mother.spouse]
end
end
I want to access the methods like this:
m = Person.new('mom', 'Female')
d = Person.new('dad', 'Male')
d.add_spouse(m)
p = Person.new('Jack', 'Male', m)
If I want to get the father
of p
, then I want to get it like this: p.father
.
So is the above implementation correct?
I am getting the below error if I run the code:
person.rb:18: syntax error, unexpected `self', expecting ')'
def father(self)
person.rb:21: syntax error, unexpected `end', expecting end-of-input
If I remove self
from def father(self)
, then I am getting this error:
person.rb:14:in `add_spouse': undefined method `spouse=' for #<Person:0x00005570928382d8> (NoMethodError)
My error was here: attr_accessor :spouse
. I had to add this and to access it I had to do puts(p.father[0].name)
Is there a better way to implement the above class with similar other properties like father
, children
, brothers
etc?
Upvotes: 2
Views: 1762
Reputation: 1959
In Ruby, everything is an object, well almost everything excluding blocks, etc. Ruby uses classes
as definitions for Objects
and they establish attributes
and methods
.
Your code sets the attributes for name
, gender
and mother
and has methods for add_spouse
and father
. So there's an obvious mix for father being interpreted as both attribute and method. From a naming convention perspective we could rename that method collect_father_relation
or something similar, which will process the logic to present the Object.
You also do not need to explicitly write return
as you have in the father
method, Ruby does that for you.
I would reconfigure the father
method to the below:
def collect_father_relation
@mother&.spouse
end
You call the @mother
instance_variable, defined the instance, and only call spouse
if @mother
is present (as it can be nil
) with the &.
operator.
You should also prepare the initialize
function for a nil
mother being passed:
def initialize(name, gender, mother = nil)
This will accept a mother parameter, but also not raise an ArgumentError
if one is not passed.
Finally, you will have to add an attr_accessor
for :spouse
as you will want to explicitly reference spouse
for the spouse Person object as you are setting the relation in spouse.spouse = self
Other comments:
Let's make a guard clause for the add_spouse
method (as we have above) to explicitly explain what we are doing, rather than the ambiguous if statement.
def add_spouse(spouse)
return if spouse.nil?
@spouse = spouse
spouse.spouse = self
end
Upvotes: 1
Reputation: 719
Have a look -
class Person
attr_accessor :name, :gender, :mother, :spouse
def initialize(name, gender, mother)
@name = name
@gender = gender
@mother = mother
@spouse = nil
end
def add_spouse(spouse)
if spouse
@spouse = spouse
@spouse.spouse = self
end
end
def father()
return [self.mother.spouse]
end
end
output -
m = Person.new('mom', 'Female', nil)
d = Person.new('dad', 'Male', nil)
d.add_spouse(m)
p = Person.new('Jack', 'Male', m)
As written in a comment, it's more a question for https://codereview.stackexchange.com/
Upvotes: 1