Creating an object from a class which is inherited ruby - ruby

Im struggling on understanding (after googling) on how to implement this: I have a class:
class Student
# constructor method
def initialize(name,age)
#name, #age = name, age
end
# accessor methods
def getName
#name
end
def getAge
#age
end
# setter methods
def setName=(value)
#name = value
end
def setAge=(value)
#age = value
end
end
And lets say I have another class which inherits from Student
class Grade < Student
#constructor method
def initialize(grade)
super
#grade = grade
end
# accessor methods
def getGrade
#grade
end
# setter methods
def setGrade=(value)
#grade = value
end
end
I understand how to build an abject:
student = Student.new(name, age)
How can I build this Student (that I have just created) a Grade object associated with the student and how would I call the inherited object, for example i wanted to:
puts 'student name and associated grade'
I know I can place the grade variable within the Student class, but for the purpose of learning im doing it this way.

This code would do what you wanted:
class Grade
attr_accessor :value
def initialize value
#value = value
end
end
class Student
attr_accessor :name, :age, :grade
def initialize name, age, grade
#name, #age, #grade = name, age, Grade.new(grade)
end
end
st = Student.new 'John', 18, 5
puts "student #{st.name} and associated grade #{st.grade.value}"

First off, no need to define accessors in Ruby like that, it's far from idiomatic. Let's clean that up first:
class Student
attr_accessor :name, :age
def initialize(name, age)
#name =name
#age = age
end
end
class Grade
attr_accessor :value
def initialize(grade)
#value = grade
end
end
Secondly it doesn't seem like Grade should inherit from Student at all, just adjust the latter to also store a Grade instance variable:
class Student
attr_accessor :name, :age, :grade
def initialize(name, age, grade = nil)
#name =name
#age = age
#grade = grade
end
end
You can then instantiate a student like this:
student = Student.new("Test", 18, Grade.new(1))
Or because of the default value you leave off the grade and assign it later:
student = Student.new("Test", 18)
# later
student.grade = Grade.new(1)

Related

Converting a class into a hash in Ruby

I am trying to convert any class into a hash using ruby. The initial implementation I have done:
class Object
def to_hash
instance_variables.map{ |v|
Hash[v.to_s.delete("#").to_sym, instance_variable_get(v)] }.inject(:merge)
end
end
Everything seemed to work ok. But when I tried the following code:
class Person
attr_accessor :name, :pet
def initialize(name, pet)
#name = name
#pet = pet
end
end
class Pet
attr_accessor :name, :age
def initialize(name, age)
#name = name
#age = age
end
end
tom = Person.new("Tom", Pet.new("Tobby", 5))
puts tom.to_hash
I have got the following output
{:name=>"Tom", :pet=>#<Pet:0x0055ff94072378 #name="Tobby", #age=5>}
I am unable to hash the attribute pet of type Pet (or any other custom class)
Any ideas?
Edit
That's what I would expect to be returned:
{:name=>"Tom", :pet=>{ :name=>"Tobby", :age=>5}}
When you want to have associated objects to be returned as a hash too hen you have to call to_hash recursively:
class Object
def to_hash
return self if instance_variables.empty?
instance_variables
.map { |v| [v.to_s.delete("#").to_sym, instance_variable_get(v).to_hash] }
.to_h
end
end
tom = Person.new("Tom", Pet.new("Tobby", 5))
puts tom.to_hash
#=> { :name=>"Tom", :pet => { :name=>"Tobby", :age=>5 } }

Passing an object from one class to another

Here's code that works but I'm looking to make it as clean as possible, to get the output without having to build a hash.
class Person
attr_accessor :name, :age
def initialize(name, age)
#name = name
#age = age
end
def create
Report.create({name: #name, age: #age})
end
end
class Report < Person
def self.create(attributes)
puts "Hello, this is my report. I am #{attributes[:name]} and my age is #{attributes[:age]}."
end
end
me = Person.new("Andy", 34)
me.create # Hello, this is my report. I am Andy and my age is 34.
Here are my changes that didn't work, but is there a method that would?
def create
Report.create
end
and
def self.create(attributes)
puts "Hello, this is my report. I am #{:name} and my age is #{:age}."
end
but the output was "I am name and my age is age."
You could just pass the person, something like this:
class Person
attr_accessor :name, :age
def initialize(name, age)
#name = name
#age = age
end
def report
Report.new(self)
end
end
class Report
attr_accessor :person
def initialize(person)
#person = person
end
def to_s
"Hello, this is my report. I am #{person.name} and my age is #{person.age}."
end
end
me = Person.new("Andy", 34)
puts me.report
# Hello, this is my report. I am Andy and my age is 34.
Note that I've changed some details:
Report doesn't inherit from Person
Report instances are created via new
Person#create is now Person#report
Report uses to_s for the output (which is called by puts)

Ruby wrong number of arguments

I'm trying to to create my getters and setters using attr_accessor. I want to assign a value to my variables.
Here is my code:
class Person
def initialize(name)
attr_accessor :name
end
def initialize(age)
attr_accessor :age
end
end
person1 = Person.new
person1.name = "Andre"
person1.age = 22
I get some trouble though. My error is:
q5.rb:6:in `initialize': wrong number of arguments (given 0, expected 1) (ArgumentError)
This is what you're trying to do:
class Person
attr_accessor :name, :age
end
person1 = Person.new
person1.name = "Andre"
person1.age = 22
An alternative approach, for example, could be:
class Person
attr_accessor :name, :age
def initialize(name, age)
#name = name
#age = age
end
end
person1 = Person.new("Andre", 22)
The error you're seeing is because you defined (and then re-defined) an initialize method that is expecting one parameter:
def initialize(name)
and then tried to create an object without supplying a parameter:
person1 = Person.new

Access variables in methods that are in a class, outside of that class

I have the following code that creates a viking game character and gives them random stats such as health, age and strength.
class Viking
def initialize(name, health, age, strength)
#name = name
#health = health
#age = age
#strength = strength
end
def self.create_warrior(name)
age = rand * 20 + 15
health = [age * 5, 120].min
strength = [age/2, 10].min
Viking.new(name, health, age, strength)
end
end
brad = Viking.create_warrior("Brad")
puts "New Warrior Created!"
The create_warrior function returns all those values, but how do I access them so I could see the stats.
For example this doesn't work but I would like to see the age or health of the new Viking brad (i.e brad.age even though that wouldn't work because it's not a method).
So how do I access those variables (without making them global).
Use attr_accessor :name, :health, :age, :strength if you would like the variables to be both readable and writable or attr_reader :name, :health, :age, :strength if you would like them to be read only.
After this you can access with brad.varname e.g. brad.name etc...
[Documentation]
Use attr_reader :age, so you can simply use brad.age, same goes for the other variables
If you really don't want them global, try instance_variable_get method http://apidock.com/ruby/Object/instance_variable_get
puts brad.instance_variable_get(:#age)
Use the attr_reader method, it creates a attribute method to point to the variable in the initialize method which is private. Its read-only
You can use attr_writer to write only
And attr_accessor to both read and write
class Viking
attr_reader :age, :name, :health, :strength
def initialize(name, health, age, strength)
#name = name
#health = health
#age = age
#strength = strength
end
def self.create_warrior(name)
age = rand * 20 + 15
health = [age * 5, 120].min
strength = [age/2, 10].min
Viking.new(name, health, age, strength)
end
end
brad = Viking.create_warrior("Brad")
puts "New Warrior Created!"

Ruby class set/get

What is wrong with this set/get?
class Pupil
def name
#name
end
def name=(name)
#name = name
end
def age
#age
end
def age=(age)
#age
end
end
Further on the same, if there was a child class with 3 arguments, name, age, sex, would the set get method in the child for sex only. Can you please show the set/get method and initialize in the child class.
def age=(age)
#age
end
should be
def age=(age)
#age = age
end
You can also make your code beautiful by replacing get/set with attr_accessor which itself provides a getter/setter
class Pupil
attr_accessor :age,:name
end
You forgot to set #age = age.

Resources