I have the following class in Ruby:
class TOMatrix < Matrix
def initialize
self = Matrix.build(8, 8){|r, c| 0}
end
But, this gives the error:
Cannot assign to a keyword
Does anyone know how to achive what a I need ?
It seems you need to write a wrapper instead of subclassing the Matrix (subclassing in your case might break Liskov's substitution principle):
require 'matrix'
class TOMatrix
def initialize
#matrix = Matrix.build(8, 8){|r, c| 0}
end
def method_missing(*args, &block)
#matrix.send(*args, &block)
end
def respond_to?(method)
super || #matrix.respond_to?(method)
end
end
m = TOMatrix.new
m.hermitian? #=> true
You cannot change the value of self directly. You probably want to do something like this:
class Matrix # I defined it so that people can test the code right away
def initialize
#rows = []
self
end
def build rows = 0, columns = 0 #Use your own version of build instead
# It should modify Matrix instead of returning a new one
#rows = Array.new(rows, Array.new(columns, 0))
end
end
class TOMatrix < Matrix
def initialize
super.build 8, 8 #Initializes Matrix and calls build on it
end
end
Related
If I include a module into a class, which has initialize defined, I can call it using super:
module M
def initialize(x)
#m = x
end
end
class MyClass
def initialize
super(3)
end
def val
#m
end
end
MyClass.new.val
# => 3
But how do I code this, if I have several modules, and maybe also a parent class?
class Parent
def initialize(x)
#p = x
end
end
module M
def initialize(x)
#m = x
end
end
module N
def initialize(x)
#n = x
end
end
class MyClass < Parent
include M
include N
def initialize
# ???? How to initialize here?
end
def val
[#m,#n,#p]
end
end
I guess that super(100) within MyClass::initialize would set the variable #n, because N is the "most recent" ancestor, but how do I call the initialize methods in M and Parent?
Take a look at this blog post (http://stdout.koraktor.de/blog/2010/10/13/ruby-calling-super-constructors-from-multiple-included-modules/). It explains how do you use the initialize from different included modules.
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
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!'
I'm trying to learn ruby more in depth before I move on to rails dev, but I'm having some issues learning classes. I can't seem to understand why the following doesn't work.
#point.rb
class Point
attr_accessor :x, :y
def initialize(p = [0,0])
#x = p[0]
#y = p[1]
end
end
#shape.rb
require_relative 'point.rb'
class Shape
attr_accessor :points
def initialize *the_points
for p in the_points
#points.append Point.new(p)
end
end
end
s = Shape.new([3,2])
puts s.points
When I call the function I get a no method error for NilClass, which I'm assuming is referring to #point.append.
First, try this:
def initialize *the_points
#points = []
for p in the_points
#points << Point.new(p)
end
end
You get NilClass error because #points instance variable is Nil, and NilClass, which does not have append() method.
Better than creating an array and populating it in a loop would be to initialize it like so:
class Shape
attr_accessor :points
def initialize *the_points
#points = the_points.map{ |p| Point.new(p) }
end
end
If you had warnings on (ruby -w or $VERBOSE = true), it'd warn you that #points didn't exist.
See some other debugging tips in How do I debug Ruby scripts?
You need to initialize #points to be a new array. It starts off as nil.
def initialize *the_points
#points = [];
for p in the_points
#points.append Point.new(p)
end
end
How would I create an attr_accessor to array?
for example
class MyClass
attr_accessor :my_attr_accessor
def initialize()
end
def add_new_value(new_array)
#my_attr_accessor += new_array
return #my_attr_accessor
end
end
my_class = MyClass.new
my_class.my_attr_accessor = 1
my_class.my_attr_accessor[1] = 2
my_class.my_attr_accessor.push = 3
my_class.add_new_value(5)
my_class.my_attr_accessor
=> [1, 2, 3, 5]
Just use an instance variable that points to an array and make an accessor from that instance variable.
Inside your class include something like this:
attr_accessor :my_attr_accessor
def initialize
#my_attr_accessor = []
end
Note that usingattr_accessor will allow you to change the value of the variable. If you want to ensure that the array stays, use attr_reader in place of attr_accessor. You will still be able to access and set array elements and perform operations on the array but you won't be able to replace it with a new value and using += for concatenation will not work.
If you are OK with the Array always existing, #david4dev's answer is good. If you only want the array to pop into existence on the first usage, and never want the user to be able to replace it with a new array (via assignment):
class MyClass
def my_attr_accessor
#my_attr_accessor ||= []
end
def add_new_value( value )
my_attr_accessor << value
end
def add_new_values( values_array )
my_attr_accessor.concat values_array
end
end
The user could still call my_class.my_attr_accessor.replace( [] ) to wipe it out.