Returning string with an attribute in it - ruby

I have this ruby code for my class player and my class game, I'm working in the tennis kata.
class Player
def score
if #player_one.points <3 and #player_two.points<3
"#{#player_one.score} #{#player_two.score}"
elsif #player_one.points == #player_two.points
"#{#player_one.score} iguales"
end
if #player_one.points == 3 and #player_two.points == 3
'deuce'
elsif (#player_one.points == #player_two.points + 1) and (#player_two.points >=3)
"Ventaja #{#player_one.name}"
elsif (#player_one.points >= 4) and (#player_one.points >= (#player_two.points + 2))
"Game #{#player_one.name}"
end
end
end
And this test can't pass, all the other tests that had already passed aren't here.
it 'return 30-iguales when both players have 2 points scored' do
player_one = Player.new
player_two = Player.new
game = TennisGame.new(player_one, player_two)
player_one.wins_point
player_one.wins_point
player_two.wins_point
player_two.wins_point
expect(game.score).to eq("30 iguales")
end
The error that I got is that "30 iguales" are expected but got nil.
All my other tests have passed, but in this one fails, and I cant solve the problem.

Ruby methods will return the last evaluated expression even without an explicit return statement, and I take it that’s what you’re going for here. The problem is that for the test data the method will evaluate "#{#player_one.score} iguales", but then continue on evaluating the second if statement, and falling all the way through it to return nil.
Your options to fix are:
Make the whole thing a single if statement instead of two. Or:
Explicitly return the value of each possible string.

Related

Case code in Ruby program not working with a passed value

Have written some test code for a program, trying to pass 2 values, a file and a number. The below doesn't work at all, but if I have something like puts "test" (outside the case) it works.
def read_album(music_file, number)
puts number #(this does something)
case number.to_i
when(number > 1)
puts "done"
when(number < 2)
puts "something"
when(number == 3)
puts "none of this inside case is working"
end
end
def main()
a_file = File.new("albums.txt", "r")
print("Choose album id: ")
choice_of_album = gets().to_i
read_album(a_file, choice_of_album)
end
main()
Your cases are not doing what you think. The expressions given to when are evaluated and the result will be compared to the case value using the case equality operator ===. An expression such as number > 1 will evaluate to either true or false. It makes no sense to compare this result to an integer in Ruby.
You should compare against the constants directly.
case number
when 1
# handle 1
when 2
# handle 2
when 3
# handle 3
else
# handle unknown case; error?
end
Note that other classes may override === to provide useful behavior. The Range and Regexp classes, for example, do this.
case number
when 1..3
# handle 1, 2 and 3
end
case string
when /pattern/
# handle pattern
end
Notably, the Proc class also does this!
def greater_than(n)
proc { |x| x > n }
end
case number
when greater_than(2)
# handle number > 2
end
You need to drop the number.to_i from the case statement.
Or do something like
case number.to_i
when 1..2
puts "foo"
when 3..100
puts "bar"
else
puts "foobar"
end
end
From the Ruby docs
Case statements consist of an optional condition, which is in the position of an argument to case, and zero or more when clauses. The first when clause to match the condition (or to evaluate to Boolean truth, if the condition is null) “wins”, and its code stanza is executed. The value of the case statement is the value of the successful when clause, or nil if there is no such clause.
Your version would evaluate to somehting like
if (number > 1) === number.to_i
and since you are comparing a number with a boolean expression this will not evaluate to true. If you had an else in the case statement this would have been called.

wrong number of arguments (1 for 0) ruby warrior intermediate error that doesn't make any sense

I'm doing level 2 of ruby warrior on intermediate and every time I run this I get this error even though it doesn't seem I should. I am very new to ruby so I'd appreciate it if someone could tell me why this is happening even though I'm passing warrior for glance and glance has 1 slot for a variable to
here's the error:
wrong number of arguments (1 for 0)
Player.rb:24:in `glance'
Player.rb:6:in `play_turn'
here's my code:
class Player
def play_turn(warrior)
#warrior = warrior
glance(warrior)
actions
end
def actions
#warrior = warrior
glance(warrior)
if rightempty
warrior.walk!(:right)
elsif forwardenemy && rightempty == false
warrior.fight!
else
warrior.walk!(warrior.direction_of_stairs)
end
end
def glance(warrior)
#wariror = warrior
forwardempty = warrior.feel.empty?(:forward)
leftempty = warrior.feel.empty?(:left)
rightempty = warrior.feel.empty?(:right)
backwardempty = warrior.feel.empty?(:backward)
forwardenemy = warrior.feel.enemy?(:forward)
leftenemy = warrior.feel.enemy?(:left)
rightenemy = warrior.feel.enemy?(:right)
backwardenemy = warrior.feel.enemy?(:backward)
forwardcaptive = warrior.feel.captive?(:forward)
leftcaptive = warrior.feel.captive?(:left)
rightcaptive = warrior.feel.captive?(:right)
backwardenemy = warrior.feel.captive?(:backward)
end
end
The issue is not with the number of arguments being passed to glance, it's what's happening within that method.
You're calling empty? with one argument e.g. :forward when it doesn't take any - hence the error "1 for 0"

Getting Nil Value in function that I am running an RSpec test on...?

Can someone please help a newb?
I am running the following two tests trying to get the same value in the end. However; when I run the test through the computer_turn method, it gives me a nil value, but when I run the test directly through the function of player_first_turn? it returns the value of :b2 I am looking for. Why isn't the former giving me :b2 as well?
THE RSPEC TESTS.
before(:all) do
#test_case = ComputerLogic.new
$user_sign = "X"
$computer_name = "Watson"
$computer_sign = "O"
end
context "pertaining to computer_turn" do
it "should: if player picks corner then computer picks center" do
possible_places = {a1: "X",a2: #a2,a3: #a3,b1: #b1,b2: #b2,b3: #b3,c1: #c1,c2: #c2,c3: #c3}
#test_case.computer_turn(possible_places).should == :b2
end
end
context "pertaining to player_first_turn? and computer_first_move" do
it "should: if player picks corner then computer picks center" do
possible_places = {a1: "X",a2: #a2,a3: #a3,b1: #b1,b2: #b2,b3: #b3,c1: #c1,c2: #c2,c3: #c3}
#test_case.player_first_turn?(possible_places).should == :b2
end
THE FUNCTIONS I AM RUNNING THE RSPEC TESTS ON.
def computer_turn(possible_places)
if player_first_turn?(possible_places)
elsif attack
elsif counter_attack
elsif fork_play?
else random_move
end
end
def player_first_turn?(possible_places)
#first_turn = possible_places.select { |key, value| value == $user_sign }
if #first_turn.length == 1
return computer_first_move
else
return false
end
end
def computer_first_move
check_center = #first_turn.keys.first
if check_center == :b2
move = { a1: #a1,a3: #a3, c1: #c1,c3: #c3 }.keys.sample
#return declare_computer_move(move)
else
move = :b2
#return declare_computer_move(move)
end
end
The problem is that computer_turn returns nil if player_first_turn?(possible_places) is truthy since there is no code between the if expression and the following elsif. In fact, computer_move will return nil in case any of the conditional expressions are truthy, otherwise it will return random_move.
The if statement never returns the value of the conditionals it is evaluating. It returns the value of the statement series or expression following the conditional expression or nil if none if that is empty.

simple if else statement unit conversion cm and in

For some reason this code always multiplies b (2.54) by unit_number, regardless of whether I put enter "cm" or "in":
puts "Welcome to my unit conversion calculator. This calculator can convert
between Centimeters and Inches. If you could like to convert Centimeters to Inches, write: in. If you would like to convert Inches to centimeters, write: cm."
unit = gets.to_s
puts " how many of your unit would you like to convert"
unit_number = gets.to_f
a = 0.39370079
b = 2.54
if unit == 'in'
puts "your conversion is: #{ (unit_number * a)}"
else unit == 'cm'
puts "your conversion is: #{ (unit_number * b)}"
end
gets will capture the stdin input including the trailing new line (enter), so unit won't be 'cm' and instead will be "cm\n". You will need to remove the trailing "\n" using chomp:
unit = gets.chomp
You don't need to call to_s to the return value of gets because it is already a String, and the else statement should be elsif unit == 'cm' or else if unit == 'cm'.
Your conditional invokes an else statement, when what you actually need is an elsif statement:
elsif unit == 'cm'
Basically, what you currently have is a situation where the first of your conditions (i.e., if unit == 'in') is not being met (see Pablo B's answer for reasons why). However, the second condition is met because it's an else statement. Since the first condition is always false, the else condition will always be true.
If, instead, you invoke an elsif statement, the conditional will first check whether unit == 'in'; if it's not, then it checks whether unit == 'cm'. If neither are true, then the condition will return nil.
I know exactly how do you feel. Debugging is a pain. #akhanubis already pointed you towards #chomp method needed to process your gets return value. While I assume that you wrote your code for didactic purposes, if you ever need to convert physical units for real, just install sy gem. After gem install sy, you can:
require 'sy/imperial'
7.5.inch.in :cm
#=> 19.05
42.cm.in :inch
#=> 16.5354

Ruby metaprogramming, how does RSpec's 'should' work?

I was reading up on RSpec and I was trying to figure out how RSpec's "should" was implemented.
Could someone give a hand on how the meta nature of this function works?
The code is located here:
http://github.com/dchelimsky/rspec/blob/master/lib/spec/expectations/extensions/kernel.rb
TIA,
-daniel
Clarification:
target.should == 5
How did target's value get passed along to "should", which in turn was "=="'d against 5?
Take a look at class OperatorMatcher.
It all boils down to Ruby allowing you to leave out periods and parenthesis. What you are really writing is:
target.should.send(:==, 5)
That is, send the message should to the object target, then send the message == to whatever should returns.
The method should is monkey patched into Kernel, so it can be received by any object. The Matcher returned by should holds the actual which in this case is target.
The Matcher implements the method == which does the comparison with the expected which, in this case, is the number 5. A cut down example that you can try yourself:
module Kernel
def should
Matcher.new(self)
end
end
class Matcher
def initialize(actual)
#actual = actual
end
def == expected
if #actual == expected
puts "Hurrah!"
else
puts "Booo!"
end
end
end
target = 4
target.should == 5
=> Booo!
target = 5
target.should == 5
=> Hurrah!

Resources