Inheritance initialize parameters - ruby

I was wondering how to properly initialize the subclass "Computer." I want it to inherit the attributes in initialize in the Game class, except for #start, which is a method. I am also unsure of how to handle parameters in the initialize method in this case. Does anyone know an elegant way to rephrase it? Thanks.
class Game
attr_reader :input, :clues
def initialize
colors = %w(R O Y G I V)
code = []
all = ''
count = 0
start
end
def start
...
end
def ask_input
...
end
class Computer < Game
attr_reader :input, :clues
def initialize
colors = %w(R O Y G I V)
code = []
all = ''
count = 0
ask_input
computer_turn
end
.....
end

I want it to inherit the attributes in initialize in the Game class, except for #start, which is a method.
All attributes and methods will be inherited. You did this correctly with:
class Computer < Game
You don't need the attr_reader because it is inherited from Game.
I am also unsure of how to handle parameters in the initialize method in this case.
You can do something like the following. It takes an input as the parameter. Consider:
computer = Computer.new( :foo )
After the computer is initialized, it's input is equal to :foo.
class Computer < Game
def initialize input
#input = input
...
See:
computer.input
=> :foo

I am also unsure of how to handle parameters in the initialize method in this case
You just
Add super in the initializer of a sub-class to call the initializer of its super-class.
And for sure, all instance variables should have # char at beginning to make they usable though all instance menthods.
Also remove attr_reader from the Computer class, because it will be inherited from Game class
I want it to inherit the attributes in initialize in the Game class, except for #start, which is a method
Finally, to avoid call the method #start of Game class, I think that you just need to override it in Computer class
Result code
class Game
attr_reader :input, :clues
def initialize
#colors = %w(R O Y G I V)
#code = []
#all = ''
#count = 0
start
end
def ask_input
# sample value for #input
#input = 'sample input'
end
def start
puts "start"
end
end
class Computer < Game
#attr_reader :input, :clues
def initialize
super
ask_input
computer_turn
end
def start
# Do nothing
end
def computer_turn
puts "computer_turn"
p #colors
end
end
comp = Computer.new
# The string "start" is not puts here because Game#start is not called
=> computer_turn
=> ["R", "O", "Y", "G", "I", "V"]
comp.input
=> "sample input"

Since you don't want the method start, just eliminate it from your Game class so that it wouldn't appear on your subclasses. Something like :
class Game
attr_reader :input, :clues
def initialize
colors = %w(R O Y G I V)
code = []
all = ''
count = 0
(Insert what start does here)
end
def ask_input
...
end
Then, just override the initialize of your Computer subclass with:
def initialize
colors = %w(R O Y G I V)
code = []
all = ''
count = 0
(insert other functionalities)
end
You can also eliminate the redundant attr_reader since it has been inherited from Game

Related

How to access attribute

I want to put the name of the enemies (toto and titi). How can I do that ?
My simplified code :
class Gamer
attr_accessor :name, ...
def initialize(name)
#name = name
...
end
...
end
class Enemy < Gamer
...
end
class Map
attr_accessor :enemies
...
end
##############
map = Map.new
map.enemies = [
Enemy.new("toto"),
Enemy.new("titi")
]
puts "#{map.enemies}"
I'm a beginner in Ruby
return :
[#<Gamer:0x000002e29da0 #name="toto">, #<Gamer:0x000002e29d50 #name="titi">]
If I understand your question correctly then:
map.enemies.each do |enemy|
puts enemy.name
end
Return an array of names
puts map.enemies.map(&:name)
You can define the method to_s in Enemy. This method is used when you puts an object:
class Enemy
...
def to_s
#name
end
end
enemy = Enemy.new("foo")
puts enemy
#=> foo
To print the names of an Array of objects, you can then use join on the Array:
map = Map.new
map.enemies = [Enemy.new("foo"), Enemy.new("bar")]
puts map.enemies.join(", ")
#=> foo, bar
This has the benefit that the Enemy object now is responsible for knowing how it should be printed, rather than this behaviour being spread across the code that uses Enemy.

return attributes from all objects of a class in ruby

I'm pretty new to Ruby(and programming in general), but I thought there was a way to call the attributes of all of a classes objects?
class Player
attr_reader :number
def initialize(name, number)
#name = name
#number = number
end
def self.all_numbers
[] << Player.each {|person| person.number}
end
end
guy1 = Player.new('Bill', 23)
guy2 = Player.new('jeff', 18)
I would like to just access the numbers for all objects by calling the class..
Player.all_numbers
hoping to return..
[23, 18]
The problem you have right now is that Player is your custom class. It does not respond to a class method each. Another issue is that the Player class has no knowledge of the instances created outside of it.
There's many ways to go about this. The way I would do this is to implement another class called Team like this
class Team
def initialize(*players)
#players = players
end
def player_numbers
#players.map { |player| player.number }
end
end
class Player
attr_reader :number
def initialize(name, number)
#name = name
#number = number
end
end
guy1 = Player.new('Bill', 23)
guy2 = Player.new('jeff', 18)
team = Team.new(guy1, guy2)
team.player_numbers
#=> [23, 18]
Write as below with the help of ObjectSpace#each_object :
Calls the block once for each living, nonimmediate object in this Ruby process. If module is specified, calls the block for only those classes or modules that match (or are a subclass of) module. Returns the number of objects found. Immediate objects (Fixnums, Symbols true, false, and nil) are never returned.
If no block is given, an enumerator is returned instead.
class Player
attr_reader :number
def initialize(name, number)
#name = name
#number = number
end
def self.all_numbers
ObjectSpace.each_object(self).map(&:number)
end
end
guy1 = Player.new('Bill', 23)
guy2 = Player.new('jeff', 18)
Player.all_numbers
# => [18, 23]
Another approach
class Player
attr_reader :number
#class_obj = []
def initialize(name, number)
#name = name
#number = number
self.class.add_object(self)
end
def self.add_object(ob)
#class_obj << ob
end
def self.all_numbers
#class_obj.map(&:number)
end
end
guy1 = Player.new('Bill', 23)
guy2 = Player.new('jeff', 18)
Player.all_numbers
# => [23, 18]
Use a Class Variable
Using a Team to hold references to complete Player objects is probably more desirable from a design perspective, but you can do what you want with a simple class variable. For example:
class Player
attr_reader :number
##numbers = []
def initialize(name, number)
#name = name
#number = number
##numbers << #number
end
def self.all_numbers
##numbers
end
end
guy1 = Player.new 'Bill', 23
guy2 = Player.new 'jeff', 18
Player.all_numbers
#=> [23, 18]
For this simple use case, that's probably sufficient. However, if you find yourself trying to stuff entire Player objects into a Player class variable then you will definitely want to find a better noun (e.g. Team or Players) to hold your collection.
I would simply override new and save the instances in a class variable:
class Player
attr_reader :number
def initialize(name, number)
#name = name
#number = number
end
def self.new(*args)
(##players ||= []) << super
##players.last
end
def self.all_numbers
##players.reduce([]) {|arr, player| arr << player.number}
end
end
Player.new('Bill', 23)
Player.new('jeff', 18)
p Player.all_numbers # => [23, 18]
Carpk, I should explain a few things:
Normally, Player.new('Bill', 23) would send the method Class#new to class Player, together with the two arguments. By defining self.new here, I am overriding Class#new. self.new invokes super, which invokes Class#new with self.new's arguments (there is no need to explicitly pass the arguments, unless you only want to pass some or none). Class#new returns the new class instance to self.new, which returns it as well, but first saves it in the array ##player.
(##players ||= []) is a typical Ruby trick. This has the effect of setting ##players equal to an empty array if it has not yet been defined (is nil), and leaves it unchanged if it already an array (empty or not). This is because ##players ||= [] is the same as ##players = ##players || []. If ##players => nil, this becomes ##players = []; else, ##players remains unchanged ([] is never evaluated). Cute, eh?
##players.last returns the class instance that was just returned by Class#new and added to the end of ##players.
##players.reduce([]) {|arr, player| arr << player.number} creates and returns an array arr of class instances, which in turn self.all_numbers returns. reduce's argument is the initial value of the accumulator, here an empty array named arr within the block. Note reduce and inject are synonyms.
Carpk, don't read any further; it will just be confusing.
I lied. I actually wouldn't do it that way. I suggested using a class variable and class methods because Carpk is new to Ruby and probably not into metaprogramming in a big way. What I'd actually do is define a class instance variable #players and make new and all_numbers singleton methods of the class Player. That way, instances of the class Player would not have easy access to that variable or those two methods. To do this, simply replace the above definitions of self.new and self.all_numbers with the following:
class << self
def new(*args)
(#players ||= []) << super
#players.last
end
def all_numbers
#players.reduce([]) {|arr, player| arr << player.number}
end
end
Carpk, I warned you.

Abstracting/generecizing class hierarchy variables in Ruby

I have several classes and I want each one to maintain on the class level a hash of all the instances that have been created for future lookup. Something akin to:
class A
def initialize(id, otherstuff)
# object creation logic
##my_hash[id]=self
end
def self.find(id)
##my_hash[id]
end
end
so I can then A.find(id) and get the right instance back.
There are several of these classes (A, B, etc), all having ids, all of which I want to have this functionality.
Can I have them all inherit from a superclass which has a generic version of this which they can leverage so I don't have to reimplement many things for every class?
Yes, you can either inherit from the same superclass, or use modules and include:
module M
def initialize(id)
##all ||= {}
##all[id] = self
end
def print
p ##all
end
end
class C
include M
def initialize(id)
super
puts "C instantiated"
end
end
If you want to keep separate indexes for each subclass, you can do something like:
def initialize(id)
##all ||= {}
##all[self.class] ||= {}
##all[self.class][id] = self
end
Edit: After your comment, I see that you need to keep per-class indexes. So:
class A
def initialize(id)
self.class.index(id, self)
end
def self.index id, instance
#all ||= {}
#all[id] = instance
end
def self.find(id)
#all[id]
end
end
class B < A
end
class C < A
end
a = A.new(1)
b = B.new(2)
c = C.new(3)
p A.find(1)
#=> #<A:0x10016c190>
p B.find(2)
#=> #<B:0x10016c140>
p C.find(3)
#=> #<C:0x10016c118>
p A.find(2)
#=> nil

how to get (and set) variables inside a ruby class?

I update this question to better reflect what I have problems to grasp. The example below kind of work but how can I access the Sub class then I have defined it inside the Base class? Should it not be better to do the call outside the class? If so how do I do that? The second question I have in this example is how to grab values so I can use them in another class. Here I store the values in an array that I later need to unpack in another class. Should I not be able to use a proc for this?
Basically what I want to do is to sort the methods into two different classes depending on if they are nested or not.
class Sub
def initialize(base_class_method)
#base_class_method = base_class_method
#sub_methods = []
end
# omitted code here
def base_class_method
#base_class_method
end
def sub_actions(method)
#sub_methods << method
end
def return_sub_methods
#sub_methods
end
def method_missing(sub_method, &block)
if sub_method
sub_method
else
super
end
end
end
class Base
def initialize
#base_methods = []
end
# omitted code here
def base_actions(method)
#base_methods << method
end
def return_base_methods
#base_methods
end
def method_missing(method, &block)
if block_given?
Sub.new(method).instance_eval(&block)
elsif method
base_actions(method)
else
super
end
end
end
base = Base.new
base.instance_eval do
something1
something_with_a_block do
something_inside_block1_1
something_inside_block1_2
end
something2
something_with_a_block2_2 do
something_inside_block2_1
end
end
p base.return_base_methods #=> [:something1, :something2] works!
You can do something like this.
class Test
# reserved method to instantiate object
def initialize(a,b,c)
#a = a
#b = b
#c = c
end
# getters
def a
#a
end
def b
#b
end
def c
#c
end
def abc
[#a, #b, #c] # returns an array
end
# setters
def a=(var)
#a = var
end
def b=(var)
#b = var
end
def c=(var)
#c = var
end
# set values all at once
def update(a, b, c)
#a = a
#b = b
#c = c
end
end
z = Test.new('something','something','something')
z.update('something!','nothing!',"a thing!")
z.a
z.b
z.c
z.a = 'wow, new value!'

How do I write a writer method for a class variable in Ruby?

I'm studying Ruby and my brain just froze.
In the following code, how would I write the class writer method for 'self.total_people'? I'm trying to 'count' the number of instances of the class 'Person'.
class Person
attr_accessor :name, :age
##nationalities = ['French', 'American', 'Colombian', 'Japanese', 'Russian', 'Peruvian']
##current_people = []
##total_people = 0
def self.nationalities #reader
##nationalities
end
def self.nationalities=(array=[]) #writer
##nationalities = array
end
def self.current_people #reader
##current_people
end
def self.total_people #reader
##total_people
end
def self.total_people #writer
#-----?????
end
def self.create_with_attributes(name, age)
person = self.new(name)
person.age = age
person.name = name
return person
end
def initialize(name="Bob", age=0)
#name = name
#age = age
puts "A new person has been instantiated."
##total_people =+ 1
##current_people << self
end
You can define one by appending the equals sign to the end of the method name:
def self.total_people=(v)
##total_people = v
end
You're putting all instances in ##current_people you could define total_people more accurately:
def self.total_people
##current_people.length
end
And get rid of all the ##total_people related code.
I think this solves your problem:
class Person
class << self
attr_accessor :foobar
end
self.foobar = 'hello'
end
p Person.foobar # hello
Person.foobar = 1
p Person.foobar # 1
Be aware of the gotchas with Ruby's class variables with inheritance - Child classes cannot override the parent's value of the class var. A class instance variable may really be what you want here, and this solution goes in that direction.
One approach that didn't work was the following:
module PersonClassAttributes
attr_writer :nationalities
end
class Person
extend PersonClassAttributes
end
I suspect it's because attr_writer doesn't work with modules for some reason.
I'd like to know if there's some metaprogramming way to approach this. However, have you considered creating an object that contains a list of people?

Resources