I am trying to override the == operation as shown here. I created == as so:
class Point
def ==(g)
p'Never reaches here'
if #x==g.grid
true
else
false
end
end
end
I am calling the method as so:
def home? (gridPoint,point)
if point==gridPoint
do something
end
When I run an application, "Never reaches here" is never printed, and the application skips the rest of the code and exits.
If I print gridPoint and Point right before the ==, I can see they are both points. Why does the program seem to have never entered the == method?
I tried point.==(gridPoint). This does not work either, and also defies the purpose of trying to clean the code.
Can anyone help me?
I think I have some suggestions why your exact code doesn't work
Class names should always be constants. This means you must capitalize the first letter!
You need to declare your == method as a class method not an instance method.
Along with #2 you need to call it using the class name not from the objects instance
class Point
attr_accessor :x
def initialize(string)
#x == string
end
def self.== (g)
p'Never reaches here'
#x==(g) ? true : false
end
def home? (gridpoint, point)
Point == (gridpoint)
end
end
n = Point.new("Schylar")
puts n.home?("Schylar","Schylar")
Related
I've two loops in two different methods which look very similar. I wanted to abstract most of their logic in a Proc.new
This works
def matches_base?
proc_exec = Proc.new do |subclass, breakpoint|
# next and return are meant to act inside the loop and quit it if needed
response = process_match(subclass)
next if response == :continue
return true if response == false
return response
end
subclasses(BASE_NAMESPACE).each do |subclass|
proc_exec.call(subclass)
end
false
end
The obvious issue here is the proc_exec is defined inside the method itself, but I want to use it in another method
def matches_breakpoints?
breakpoints.fetch.each do |breakpoint|
# I want to include the proc_exec here too
end
false
end
So I just tried to extract it at the class level like so
This does not work
def proc_exec
Proc.new do |subclass, breakpoint|
response = process_match(subclass)
next if response == :continue
return true if response == false
return response
end
end
def matches_base?
subclasses(BASE_NAMESPACE).each do |subclass|
proc_exec.call(subclass)
end
false
end
Then I could have called it like proc_exec.call from within both instance methods. Currently it throws
LocalJumpError:
unexpected return
I tried many tricks such as instance_eval or instance_exec without success. I'm out of solution right now.
Easily executable, simplified example of what I want below.
class MyLoops
def proc_exec
Proc.new do |num|
next if num == 1
# we want this `return` to act in the method context
# as it would do if I defined it inside a method directly
return if num == 4
puts "Current number : #{num}"
end
end
def method_a
[0,1,2].each do |num|
proc_exec.call(num)
end
false
end
def method_b
[3,4,5].each do |num|
proc_exec.call(num)
end
end
# this `false` below should never be reached ; that's the trick
false
end
loops = MyLoops.new
loops.method_a
loops.method_b
You can't have your cake and eat it too. If you want return from the proc to abort the method, it must be in the method's lexical scope* (which is another way to say "it must be defined within the same method").
An alternative is to have proc/lambda return a "stop" value, which caller will use to abort its execution.
(Your experiments with instance_eval/instance_exec were misdirected, sadly. Those methods only change current self. This problem has nothing to do with current self, but rather current lexical scope, in which return is executed.)
* The error you're getting, it is caused by return trying to return from a method that is no longer running (proc_exec).
Ok so I just started learning ruby and I'm making a Yhatzee game, now this is where I'm currently at:
class Yhatzee
def dices
#dices.to_a= [
dice1=rand(1..6),
dice2=rand(1..6),
dice3=rand(1..6),
dice4=rand(1..6),
dice5=rand(1..6)
]
end
def roll_dice
#dices.to_a.each do |dice|
puts dice
end
end
end
x = Yhatzee.new
puts x.roll_dice
Now the reason i typed .to_a after the array is i kept getting a "uninitialized variable #dices" error, and that seemed to fix it, i have no idea why.
anyways on to my question, i currently don't get any errors but my program still won't print anything to the screen. I expected it to print out the value of each dice in the array... any idea what I'm doing wrong? It seems to work when i do it in a procedural style without using classes or methods so i assumed it might work if i made the 'dices' method public. But no luck.
There are a few issues here. Firstly #dices is nil because it is not set anywhere. Thus when you call #dices.to_a you will get []. Also the dices method will not work either because nil does not have a to_a= method and the local variables you are assigning in the array will be ignored.
It seems a little reading is in order but I would do something like the following: (Not the whole game just refactor of your code)
class Yhatzee
def dice
#dice = Array.new(5){rand(1..6)}
end
def roll_dice
puts dice
end
end
x = Yhatzee.new
puts x.roll_dice
There are alot of additional considerations that need to be made here but this should at least get you started. Small Example of how I would recommend expanding your logic: (I did not handle many scenarios here so don't copy paste. Just wanted to give you a more in depth look)
require 'forwardable'
module Yahtzee
module Display
def show_with_index(arr)
print arr.each_index.to_a
print "\n"
print arr
end
end
class Roll
include Display
extend Forwardable
def_delegator :#dice, :values_at
attr_reader :dice
def initialize(dice=5)
#dice = Array.new(dice){rand(1..6)}
end
def show
show_with_index(#dice)
end
end
class Turn
class << self
def start
t = Turn.new
t.show
t
end
end
attr_reader :rolls
include Display
def initialize
#roll = Roll.new
#rolls = 1
#kept = []
end
def show
#roll.show
end
def roll_again
if available_rolls_and_dice
#rolls += 1
#roll = Roll.new(5-#kept.count)
puts "Hand => #{#kept.inspect}"
show
else
puts "No Rolls left" if #rolls == 3
puts "Remove a Die to keep rolling" if #kept.count == 5
show_hand
end
end
def keep(*indices)
#kept += #roll.values_at(*indices)
end
def show_hand
show_with_index(#kept)
end
def remove(*indices)
indices.each do |idx|
#kept.delete_at(idx)
end
show_hand
end
private
def available_rolls_and_dice
#rolls < 3 && #kept.count < 5
end
end
end
The main problem with this code is that you are trying to use the #dices instance variable inside of the roll_dice method, however you are not defining the instance variable anywhere (anywhere that is being used). You have created the dices method but you are not actually instantiating it anywhere. I have outlined a fix below:
class Yhatzee
def initialize
create_dices
end
def roll_dice
#dices.each do |dice|
puts dice
end
end
private
def create_dices
#dices = Array.new(5){rand(1..6)}
end
end
x = Yhatzee.new
x.roll_dice
I have done some simple refactoring:
Created an initialize method, which creates the #dice instance variable on the class initialization.
Made the 'dices' method more descriptive and changed the method visibility to private so only the class itself is able to create the #dice.
Cleaned up the creation of the dices inside of the #dice instance variable
I have omitted the .to_a from the roll_dice method, now that we create the variable from within the class and we know that it is an array and it will be unless we explicitly redefine it.
UPDATE
Although I cleaned up the implementation of the class, it was kindly pointed out by #engineersmnky that I oversaw that the roll would return the same results each time I called the roll_dice function, I have therefore written two functions which will achieve this, one that defines an instance variable for later use and one that literally just returns the results.
class Yhatzee
def roll_dice
#dice = Array.new(5){rand(1..6)} # You will have access to this in other methods defined on the class
#dice.each {|dice| puts dice }
end
def roll_dice_two
Array.new(5){rand(1..6)}.each {|dice| puts dice } # This will return the results but will not be stored for later use
end
end
x = Yhatzee.new
x.roll_dice
x.roll_dice # Will now return a new result
I am having trouble incrementing a variable. This seems very trivial and easy but for some reason I can't get it to work.
I have a program moving a robot about a grid and it's fully working. I would now just like to count how many moves he makes.
Here is my code:
Class Robot
#counter = 0
def move
#counter +=1
end
def print
puts "Hurray the Markov chain has worked in #{#counter}"
end
I get an error saying undefined method '+' operator. I have also tried
#counter = #counter + 1
What am I doing wrong?
your #counter variable is nil because it is not getting set on line 3.
As tomsoft pointed out, the variable is actually defined, but it is defined on the class, and not an instance of the class (an individual Robot).
To define the variable on an instance of the class, you need to initialize the #counter variable in an initializer method.
class Robot
def initialize
#counter = 0
end
def move
#counter +=1
end
def print
puts "Hurray the Markov chain has worked in #{#counter}"
end
end
TL;DR
Classes are executable code. Setting instance variables must generally be done within an instance method. Initialization is invoked by the #new method, which is created when you define "initialize" within your class.
Initializing Instance Variables for Robot#new
For example:
class Robot
def initialize
#counter = 0
end
def move
#counter += 1
end
def print
puts "Hurray the Markov chain has worked in #{#counter}"
end
end
robot = Robot.new
robot.move
robot.print
will print what you expect:
Hurray the Markov chain has worked in 1
Coding Robot Without an Explicit Initializer
Coding is often a matter of style, and how you code something depends not only on what you're trying to do, but also on what you're trying to communicate. In this case, you could rewrite your class without an explicit initializer by ensuring that #counter is set to zero before you attempt to increment it. For example:
def move
#counter.to_i.succ
end
This will ensure that if #counter is nil, it will be converted to an integer (in this case, zero) and then incremented. This might seem a bit "magical" to some folks, so you might also see people being more explicit with nil guards:
def move
#counter ||= 0
#counter += 1
end
If #counter is nil or false, it is assigned the value of zero. This ensures that you'll be able to invoke numeric methods on its value.
The way you define it is that #counter become a class variable, and not an instance variable.
class Robot
#counter=0 # you are in class definition, not instance
def self.print_counter
puts #counter
end
end
Robot.print_counter
returns
0
The only option is to define it in the initializer method
class Robot
def initialize
#counter=0
end
end
I just started working with Ruby classes and am writing a binary tree class. However, when I go to print the value of a particular node, it prints the hexadecimal memory address as opposed to the actual value. I looked around on the web quite a bit but all I see is puts and print, which are what I am trying. How do you print the actual value and not the address?
class Node
attr_accessor :value,:left,:right
def initialize(newValue)
#value = newValue
#left = nil
#right = nil
end
# In my binary tree class after a value has been inserted into the tree....
current_node = #root
puts current_node.value
When I run the output I get BinaryTree::NumericTreeItem:0x007fa101125eb8
Thank you for your time and I apologize for the trivial question. I'm sure it's a simple fix. Haven't been able to find anything else online.
You can override the to_s method in a class to control what gets printed out in situations like this. I'll borrow the example from the previous answer:
class NumericTreeItem
attr_accessor :numericValue
def initialize(newValue)
#numericValue = newValue
end
def to_s
"NumericTreeItem with value of #{#numericValue}"
end
end
Now when you do this line:
puts current_node.value
you would see something like:
NumericTreeItem with value of 5
be displayed.
The value instance variable in your Node contains an instance of a class called NumericTreeItem. You don't show what that class is in your question, but let's pretend for a moment that is is defined like so:
class NumericTreeItem
attr_accessor :numericValue
def initialize(newValue)
#numericValue = newValue
end
end
Then to print the value in the node:
puts current_node.value.numericValue
Some code
class Parent
def print
p "Hi I'm the parent"
end
end
class Child < Parent
def initialize(num)
#num = num
end
def print
child_print
end
def child_print
if #num == 1
#call parent.print
else
p "I'm the child"
end
end
end
c1 = Child.new(1)
c2 = Child.new(2)
c1.print
c2.print
Child is an instance of Parent. Print is the method exposed in the interface, and both classes define them. Child decides to do other things in a (possibly really complex) method, but will invoke its parent's method under some condition.
I could just write
def print
if #num == 1
super
else
p "I'm the child"
end
end
And that works, but what if it's not just a simple one-liner comparison but instead is doing lots of complicated things that deserve to be separated into another method? It may have to do some calculations before deciding that the parent's method should be called.
Or perhaps there is a different, better way to design it.
Parent.instance_method(:print).bind(self).call
This is already pretty readable, but here's an explanation.
Get the #print method of the Parent class
Bind it to your current object
Call it
PS: You can even give arguments to #call and they will be relayed to the called method.
PPS: That said, such code almost always hints at an issue in your class design. You should try to avoid it whenever possible.