Ruby: TDD Plus Coding - ruby

gem 'minitest', '~> 5.2'
# TDD
require 'minitest/autorun'
require 'minitest/pride'
require_relative 'kid'
class KidTest < Minitest::Test
def test_kid_has_not_eaten_sugar
kid = Kid.new
assert_equal 0, kid.grams_of_sugar_eaten
end
def test_kid_gets_5_grams_from_eating_candy
kid = Kid.new
kid.eat_candy
assert_equal 5, kid.grams_of_sugar_eaten
5.times { kid.eat_candy }
assert_equal 30, kid.grams_of_sugar_eaten
end
def test_kid_is_not_hyperactive
kid = Kid.new
refute kid.hyperactive?
end
def test_kid_is_hyperactive_after_60_grams_of_sugar
kid = Kid.new
11.times { kid.eat_candy }
refute kid.hyperactive?, "Not hyperactive yet..."
kid.eat_candy
assert kid.hyperactive?, "OK, now the kid is hyperactive."
end
end
# CODE
class Kid
attr_reader :grams_of_sugar_eaten
def initialize
#grams_of_sugar_eaten = 0
end
def eat_candy(grams = 5)
#grams_of_sugar_eaten += grams
end
def hyperactive?
false
end
end
Can anyone help direct me in the thinking that I should have as far as how to go about getting the 2nd test to pass and so on?
I'm not sure what to do make the test pass after the kid eats 5 grams of sugar and then after 5.times to have it pass after he eats 30 grams of sugar.
Appreciate any help

You've added eat_candy as an attr_reader, not a method. The initialize function here sets eat_candy to itself.
A possible fix:
class Kid
attr_reader :grams_of_sugar_eaten
def initialize
#grams_of_sugar_eaten = 0
end
def eat_candy(grams = 5)
#grams_of_sugar_eaten += grams
end
end

Related

Uninitialized constant Van (NameError)

I am trying to write some functionality which allows me to take a broken bike to a garage to have it fixed, whilst implementing this i have come across this issue. i understand that this usually is because it cannot find the file but have ran out of ideas on how to fix it. If you need any of the other code let me know but i thought this would be all the code needed.
dockingstation.rb:
require_relative 'Bike'
require_relative 'van'
require_relative 'garage'
class DockingStation
attr_reader :dock, :max_dock, :DEFAULT_CAPACITY
DEFAULT_CAPACITY = 20
def initialize(capacity = DEFAULT_CAPACITY)
#max_dock = capacity
#dock = []
end
def release_bike
if !empty?
#dock.each_with_index do |bike, index|
if bike.working?
#dock.delete_at(index)
return bike
else
raise "Bike is broken"
end
end
else
raise "No bikes to release"
end
end
def dock_bike(bike, working = true)
if !full?
#dock << bike
else
raise "Too many bikes"
end
end
def show_dock
#dock.each do |el|
return el
end
end
def van_takes_broken_bikes(van)
puts #dock
#dock.each_with_index do |bike, index|
if bike.working? == true
van.storage.append(bike)
else
van.storage.append(bike)
end
end
end
private def full?
#dock.length == #max_dock
end
private def empty?
#dock.length == 0
end
end
dock = DockingStation.new
bike = Bike.new
van = Van.new
bike.report_broken
dock.dock_bike(bike)
dock.van_takes_broken_bikes(van)
van.rb:
require_relative 'dockingstation'
require_relative 'garage'
class Van
attr_reader :storage
def initialize
#storage = []
end
def take_broken_bikes_to_garage(bikes)
end
end

How to make this test pass, I'm a bit confused

this is my money class
class Money
def initialize
#amount = 0
end
def amount
#amount
end
def earn(this_many)
#amount += this_many
end
def spend(this_many)
#amount -= this_many
end
end
my failing test
def test_cant_spend_money_that_you_dont_have
money = Money.new
money.earn(75)
money.spend(75)
assert_equal "You can't spend what you don't have", money.spend(12)
assert_equal 0, money.amount
end
I'm not sure how to modify the amount method to make the test pass... any help will be appreciated.
You should raise errors when the account doesn't have enough money to spend.
class Money
class InsufficientFunds < StandardError; end
attr_accessor :amount
def initialize
self.amount = 0
end
def earn(this_many)
self.amount += this_many
end
def spend(this_many)
raise InsufficientFunds, "You can't spend what you don't have" if amount < this_many
self.amount -= this_many
end
end
And your test case should be
def test_cant_spend_money_that_you_dont_have
money = Money.new
money.earn(75)
money.spend(75)
assert_raise Money::InsufficientFunds, "You can't spend what you don't have" do
money.spend(12)
end
assert_equal 0, money.amount
end
I think you need to change
assert_equal "You can't spend what you don't have", money.spend(12)
to
money.spend(12)
assert money.amount > 0, "You can't spend what you don't have"

Uninitialized constant Game::World when I try and initialize the World class in Ruby

So I'm trying to create a basic text adventure in ruby, and I'm roughly following a tutorial (https://jsrn.gitbooks.io/make-your-first-text-adventure-in-ruby/content/creating_the_framework.html)
But when I try and run my code I get this error:
GameBase.rb:10:in `initialize': uninitialized constant Game::World (NameError)
from GameBase.rb:55:in `new'
from GameBase.rb:55:in `<main>'
This is my code:
From GameBase.rb
Dir["GameDir/**.*"].each { |file| require_relative file }
class Game
Actions = [
:forward, :backward, :look, :attack, :loot, :inventory, :use, :cast
]
def initialize
#world = World.new
#player = Player.new
start_game
end
private
def start_game
while #player.alive?
#current_room = #world.get_room_of(#player)
print_player_status
action = take_player_input
next unless ACTIONS.include? action
take_action(action)
end
end
def take_player_input
print "What do you do?"
gets.chomp.to_sym
end
def take_action(action)
case action
when :forward
#world
when :backward
#world
when :look
#world
when :attack
#current_room.interact(#player)
when :loot
#current_room.interact(#player)
when :inventory
when :use
when :cast
end
end
end
Game.new
And from world.rb
class World
def initialize
#past_rooms = 0
#current_room = 0
end
def move_entity_forward(entity)
#current_room += 1
end
def move_entity_backward(entity)
#current_room -= 1
end
def get_room_of(entity)
if #current_room <= #past_rooms then #current_room
else
Room.new
#past_rooms += 1 end
end
end
class Room
attr_accessor :size, :content
def initialize
#content = get_content
#size = get_size
#adjetive = get_adjetive
end
def interact(player)
if #content
#content.interact(player)
#content = nil
else
puts "There isn't anything here..."
end
end
private
def get_content
[Monster, Item.sample.new]
end
def get_size
dimensions = [5, 10, 15, 20, 25, 30, 40, 50, 75, 100, 200]
"#{dimensions.sample}'x#{dimensions.sample}'"
end
def get_adjetive
["well-lit", "dim", "filthy", "suprisingly clean", "round", "muddy", "oppressive"]
end
end
Try adding this line to the top of GameBase.rb:
require_relative 'world'
This tells the Ruby interpreter to look for a file named world.rb in the same folder as GameBase.rb and run the code in that file, which would define the World class. Then the World class would be available when you try to use it.
So, I ran into the same problem because I didn't see instructions in the tutorial that the extra files (world.rb, player.rb, etc.) are expected to be in a subfolder. I had them all in the same folder, game.rb , which was causing this error.
The first line of code in game.rb is telling Ruby where to load all the related game files
Dir["GameDir/**.*"]
So, if your game.rb file is in a directory 'game' for example, then all the related files need to be in a directory game>GameDir since you are telling it to look in the GameDir folder.

Ruby Program is not printing on screen

Good day everyone. I am writing a simple ruby code but it doesn't print on the screen I am using ruby 2.2.2 and my IDE is Rubymine 7.Thanks in advance.Here is the code;
class Animal
attr_accessor :name, :colour
def initialize(name,colour)
#name = name
#colour = colour
end
def to_s
"Name#{#name} Colour #{#colour}"
end
end
class Cheetah < Animal
attr_reader :speed
def initialize(name,colour,speed)
#speed = speed
super (name,colour)
end
def to_s
return super + "Speed#{#speed}kph"
end
end
class Zoo < Animal
def initialize
#animals = []
end
def add_animals(animal)
#animals << animal
end
def my_animals
cage = ""
#animal.each do|call|
cage += call.to_s
end
end
end
5.times do|count|
Zoo.add_animals(MyAnimal.new("Cheetah#{count}","yello and black spots"))
end
puts "#{Zoo.my_animals}"
My_cheetah = Cheetah.new("Cheetah","yello and black spots",180)
puts "#{My_cheetah.to_s}"
class Animal
attr_accessor :name, :colour
def initialize(name,colour)
#name = name
#colour = colour
end
def to_s
"Name#{#name} Colour #{#colour}"
end
end
class Cheetah < Animal
attr_reader :speed
def initialize(name,colour,speed)
#speed = speed
super(name,colour)
end
def to_s
return super + "Speed#{#speed}kph"
end
end
class Zoo < Animal
def initialize
#animals = []
end
def add_animal(animal)
#animals << animal
end
def my_animals
cage = ""
#animals.each do |call|
cage += call.to_s
end
cage
end
end
zoo = Zoo.new
5.times do|count|
zoo.add_animal(Animal.new("Cheetah#{count}","yello and black spots"))
end
puts "#{zoo.my_animals}"
my_cheetah = Cheetah.new("Cheetah","yello and black spots",180)
puts "#{my_cheetah.to_s}"

Calling a method from a method in another class

It's a fairly well know one. Determining the rank of a poker hand. I created the following classes: Card:
class Card
attr_accessor :suite, :rank, :value
def initialize(suite, rank, value)
#suite = suite
#rank = rank
#value = value
end
def to_s
puts "#{#value}, #{#suite}, #{#rank}"
end
end
Deck:
class Deck
def initialize()
#cardsInDeck = 52
#deck = Array.new()
end
def add_card(card)
#deck.push(card)
end
def deck_size
#deck.length
end
def to_s
#deck.each do |card|
"#{card.rank}, #{card.suite}"
end
end
def shuffle_cards
#deck.shuffle!
end
def deal_cards
#Here I create a new hand object, and when popping cards from the deck
# stack I insert the card into the hand. However, when I want to print
# the cards added to the hand I get the following error:
# : undefined method `each' for #<Hand:0x007fa51c02fd50> (NoMethodError)from
# driver.rb:36:in `<main>'
#hand = Hand.new
for i in 0..51 do
card = #deck.pop
#cardsInDeck -= 1
puts "#{card.value}, #{card.rank}, #{card.suite}"
#hand.add_cards(card)
end
#hand.each do |index|
"#{index.value}, #{index.rank}, #{index.suite}"
end
puts "Cards In Deck: #{#cardsInDeck}"
end
end
Hand
require_relative 'deck'
require_relative 'card'
class Hand
def initialize()
#hand = Array.new()
end
def to_s
count = 0
#hand.each do |card|
"#{card.value}, #{card.rank}, #{card.suite}"
count += 1
end
end
def add_cards(card)
#hand.push(card)
end
def hand_size()
#hand.length
end
end
and Driver File:
require 'logger'
require_relative 'card'
require_relative 'deck'
require_relative 'hand'
suite = ["Hearts", "Diamonds", "Clubs", "Spades"]
rank = ["Ace", 2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King"]
deck = Deck.new()
suite.each do |i|
v = 1
rank.each do |j|
deck.add_card(Card.new(i, j, v))
v += 1
end
end
In the Deck class, the deal_card method, I do not understand why looping for an array causes a method error
#hand.each do |index|
"#{index.value}, #{index.rank}, #{index.suite}"
end
puts "Cards In Deck: #{#cardsInDeck}"
#hand is an instance of Hand, and there is no instance method each defined for Hand, so that is why #hand.each is generating an undefined method error.
My answer is not very direct on the error but could hopefully help you in this case.
You method deal_cards is where Dependency Injection can play its role. By the original design Deck has a hard dependency on Hand which is not good and harder to test. You need to change it like
def deal_cards(hand=nil)
#hand = hand || Hand.new
# Others
end
By this you can accept instance outside of Hand, say Foot as long as somebody can play cards by feet!
You can also unit testing this method without writing Hand class at all.
Better to unit test the class instead of manual checking, then you can inject any instance you like into this method during testing.

Resources