Custom class instantiates its superclass objects - ruby

I'm working on a Grid class that inherits from Matrix:
class Grid < Matrix
def self.[](x,y=x)
if x.is_a? String
ary = x.lines.map { |l| l.strip.split('|') }.map.with_index do |col,x|
col.map.with_index { |cell,y| ::Cell.new x: x, y: y, alive: !!(cell =~ /O/i) }
end
super *ary
else
super *Array.new(y) { [::Cell.new(x: x, y: y, alive: [true,false].sample)] * x }
end
end
end
I can't seem to be able to overwrite ::initialize since it's private. The above works but yields instances of Matrix class instead of my custom class, so I'm stuck. Realized my class wasn't instantiating when calling to_s and receiving "Matrix[[X,O],[O,O]]" stuff. What I am missing?

There is no ::new method in ruby, you define it via #initialize
When you call super it's calling Matrix::[] with the arguments provided.
Look at the source code:
def Matrix.[](*rows)
Matrix.rows(rows, false)
end
You can try defining Grid::rows with your logic instead. Or just override #initialize
Incidentally this is poorly written, they should have done rows(rows,false) (without the Matrix) to prevent this very issue.

Related

Have a different public constructor than a private one

I read that it is not possible to have several constructors for a class. So the following code won't work:
class C
def initialize x
initialize x,0
end
# Some methods using the private constructor…
def foo
# …
bar = C.new 3,4
# …
end
private
def initialize x,y
#x = x
#y = y
end
end
I have thought about replacing the public constructor by a static method, but that would prevent other classes to extend C. I also have thought about making a private post-initializing method:
class C
def initialize x
post_init x,0
end
# Some methods using the private constructor…
def foo
# …
bar = C.new baz
bar.post_init 3,4
# …
end
private
def post_init x,y
#x = x
#y = y
end
end
But here, the post_init is called twice, which is not a good thing.
Is there a way to give a public constructor, while having in private a more complete way to make a new instance? If not, what is the best way to do something similar?
I guess this would do what you expect.
class C
def initialize(x, y = 0)
#x = x
#y = y
end
def self.with_position
new(3, 4)
end
end
c1 = C.new(5)
c2 = C.with_position
If you want to prohibit setting y by anyone from outside the class, you can use some private method behind the scenes (as you suggested) and konstructor gem
class C
def initialize(x)
set_coords(x, 0)
end
konstructor
def with_position
set_coords(3, 4)
end
private
def set_coords(x, y)
#x = x
#y = y
end
end
c1 = C.new(5)
c2 = C.with_position
A simple way is to accept options for initialize, you can have an if statement in there that covers the private or public cases.
Ruby doesn't really have this concept of 'private class' in a simple way such as saying 'private'.
You can see How to I make private class constants in Ruby for a way to make a private constant (since classes are constants). You'd make a class method that returns an anonymous class (Class.new do ... end). Then mark that class method private with private_class_method.
A better solution would be to make two classes with different initializes. Common functionality could be in a separate class or module. If it's a class, then the way to include them in the 'public/private' classes would be inheritance. If it's a module, then you'd include/extend.

Equivalent ruby code to following without attr_accessor?

This is a Java Code :
public class test{
public static void main(String args[]){
number A = new number();
System.out.println(A.b);
}
}
class number{
int b = 100;
}
Is there a equivalent of above code in ruby without attr_accessor ?
Why can't we access member variables using '.' like in java ? or is there a way i am unaware of in ruby ... ?
Instance variables are hidden by default. You can get around this by using instance_variable_get and instance_variable_set, but these are private (you can get around this too if you must) because it's unidiomatic to do such things.
In Ruby, when you say foo.bar, you are invoking the bar method on your foo object (with no arguments). When you say foo.bar = 5, you are invoking the bar= method with argument 5.
All attr_accessor does is provide implementations of bar and bar= for you, but this:
class MyClass
attr_accessor :bar
end
is equivalent to
class MyClass
def bar
#bar
end
def bar=(new_bar)
#bar = new_bar
end
end
This lets you later replace the implementation with something else if you wish. Instance variables are supposed to be private to that object, so I wouldn't recommend trying to work around this unless you're doing heavy-duty metaprogramming.
If you just want to pass around structured data, then you can use the Ruby Struct class, which will work more like you'd expect from your example:
Number = Struct.new(:value)
n = Number.new
n.value = 123
n.value # => 123
The equivalent is using Ruby's attr_accessor. Why do you want to avoid it?
class number
attr_accessor :b
end
Then you can call
a = number.new
a.b = 1

Ruby and modifying self for a Float instance

I would like to change the self value of a float instance.
I have the following method :
class Float
def round_by(precision)
(self * 10 ** precision).round.to_f / 10 ** precision
end
end
And I would like to add the round_by! method which will modify the self value.
class Float
def round_by!(precision)
self = self.round_by(precision)
end
end
But I got an error saying I can't change the value of self.
Any idea ?
You can't change the value of self. It always points to the current object, you can't make it point to something else.
When you want to mutate the value of an object, you either do this by calling other mutating methods or setting or changing the values of instance variables, not by trying to reassign self. However in this case, that won't help you, because Float doesn't have any mutating methods, and setting instance variables won't buy you anything, because none of the default float operations are affected by any instance variables.
So the bottom line is: you can't write mutating methods on floats, at least not in the way you want.
You can also create a class and store the float in a instance variable:
class Variable
def initialize value = nil
#value = value
end
attr_accessor :value
def method_missing *args, &blk
#value.send(*args, &blk)
end
def to_s
#value.to_s
end
def round_by(precision)
(#value * 10 ** precision).round.to_f / 10 ** precision
end
def round_by!(precision)
#value = round_by precision
end
end
a = Variable.new 3.141592653
puts a #=> 3.141592653
a.round_by! 4
puts a #=> 3.1416
More about using "class Variable" here.
This is actually a really good question and I'm sorry to say that you can't - at least not with the Float class. It's immutable. My suggestion would be to create your own class the implements Float (aka inherits all the methods), like so in pseudo-code
class MyFloat < Float
static CURRENT_FLOAT
def do_something
CURRENT_FLOAT = (a new float with modifications)
end
end

How to evaluate methods of another class in current context?

I have 2 classes whose object should act as "partners". The first one is my Thing class, whose instances should act as Tree::TreeNodes of the gem RubyTree.
Basically, this delegation can be implemented using Forwardable:
class Thing < NoClassInheritancePlease
extend Forwardable
def initialize(title = "node")
#node = Tree::TreeNode.new title
# Collect node methods that should be delegated
node_methods = #node.public_methods(false)
node_methods += #node.protected_methods
node_methods -= (public_methods(false) + protected_methods(false) + private_methods) # own methods should not been delegated
# Set up delegation of specified node methods as singleton methods
for method in node_methods
Base.def_delegator :#node, method
end
end
end
Problem:
A number of TreeNode methods refer to self. For example:
def each(&block) # :yields: node
yield self
children { |child| child.each(&block) }
end
Thus, my_thing.each {...} yields self, i.e. the Tree::TreeNode object that belongs to my_thing but not the Thing object itself.
Another example:
siblings = []
parent.children {|my_sibling| siblings << my_sibling if my_sibling != self}
siblings
parent.children returns an Array of Things and therefore the condition never evaluates to false as my_sibling is a Thing (which is fine) but self is a Tree::TreeNode
Question: How to evaluate the instance methods of a class (e.g. Tree::TreeNode) in the context of another class (e.g. Thing)? ("overwrite self")
I tried with UnboundMethods, but you can only bind an instance of the original receiving class to an unbound method.
If you really want, you could use evil-ruby to solve this.
require 'evil'
class A; def m; self; end; end
class B; end
A.instance_method(:m).force_bind(B.new).call
You probably want to use instance_exec.
From the docs:
Executes the given block within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables. Arguments are passed as block parameters.
class KlassWithSecret
def initialize
#secret = 99
end
end
k = KlassWithSecret.new
k.instance_exec(5) {|x| #secret+x } #=> 104
http://ruby-doc.org/core-1.8.7/Object.html#method-i-instance_exec
In your case you can use instance_exec to yield self.
def each(&block)
instance_exec{ yield self }
children { |child| child.each(&block) }
end
I'm not sure if you can. Maybe with instance_eval {unboundmethod.to_proc} or something?

method with same name and different parameters(Method Overloading) in Ruby

I have this code:
def setVelocity (x, y, yaw)
setVelocity (Command2d.new(x,y,yaw))
end
def setVelocity (vel)
......
end
vel is a Command2D class that has 3 attributes, is Comparable and defines + , basically is a convenient class for me to manage those 3 attributes, so I want to use it internally in my library (dont want to make them private, either give them weird names).
But Ruby seems to keep only the last setVelocity even when the number of parameters is different. so when I call setVelocity with 3 parameters will say that I need to call that method with only one parameter.
Ruby doesn't really support overloading.
This page gives more details and a workaround. Basically you create a single method with a variable number of parameters, and deal with them appropriately.
(I'd personally recommend writing one method to recognise the two different "faked overloads" and then one method for each overload, with different names reflecting the different parameters.)
Alternatively, just provide different names to start with :)
Just for comparison, here's how I would solve it:
#!/usr/bin/env ruby
class Command2D
def initialize(x, y, yaw)
#command = [x, y, yaw]
end
end
class Vehicle
def velocity=(command_or_array)
case command_or_array
when Command2D
self.velocity_from_command = command_or_array
when Array
self.velocity_from_array = command_or_array
else
raise TypeError, 'Velocity can only be a Command2D or an Array of [x, y, yaw]'
end
end
private
def velocity_from_command=(command)
#velocity = command
end
def velocity_from_array=(ary)
raise TypeError, 'Velocity must be an Array of [x, y, yaw]' unless ary.length == 3
#velocity = Command2D.new(*ary)
end
end
v1 = Vehicle.new
v1.velocity = Command2D.new(1, 2, 3)
v2 = Vehicle.new
v2.velocity = [1, 2, 3]
p v1
p v2
Use attr_accessor to add attributes and you will get getters and setters automatically.
Alternatively use attr_reader or attr_writer to get read-only or write-only attributes.
class Foo
attr_accessor :velocity
end
You can now set and get the value of this attribute like this:
foo = Foo.new
foo.velocity = 100
puts foo.velocity # => 100
If you want to add methods to set the attribute based on some parameters, use a name reflecting what kind of input are expected:
def velocity_from_yaw(x, y, yaw)
velocity = Command2d.new(x, y, yaw)
end
You can probably find a much better name in this case, but I don't know what your x, y and yaw really mean in your context.

Resources