Ruby Name Error - Uninitialized constant - ruby

I am doing exercises and am
getting NameError:Unitialized Constant MyUnitTests::Room when running test_ex47.rb.
test_ex47.rb:
require 'test/unit'
require_relative '../lib/ex47'
class MyUnitTests < Test::Unit::TestCase
def test_room()
gold = Room.new("Gold Room", """This room has gold in it you can grab. There's a doo to the north.""")
assert_equal(gold.name, "GoldRoom")
assert_equal(gold.paths, {})
end
def test_room_paths()
center = Room.new("Center", "Test room in the center.")
north = Room.new("North", "Test room in the north.")
south = Room.new("South", "Test room in the south.")
center.add_paths({:north => north, :south => south})
assert_equal(center.go(:north), north)
assert_equal(center.go(:south), south)
end
def test_map()
start = Room.new("Start", "You can go west and down a hole.")
west = Room.new("Trees", "There are trees here, you can go east.")
down = Room.new("Dungeon", "It's dark down here, you can go up.")
start.add_paths({:west => west, :down => down})
west.add_paths({:east => start})
down.add_paths({:up => start})
assert_equal(start.go(:west), west)
assert_equal(start.go(:west).go(:east), start)
assert_equal(start.go(down).go(up), start)
end
end
ex47.rb is located in the lib folder and looks like:
class Room
aatr_accessor :name, :description, :paths
def initialize(name, description)
#name = name
#description = description
#paths = {}
end
def go(direction)
#paths[direction]
end
def add_paths(paths)
#paths.update(paths)
end
end
Error:
Finished tests in 0.000872s, 3440.3670 tests/s, 0.0000 assertions/s.
1) Error:
test_map(MyUnitTests):
NameError: uninitialized constant MyUnitTests::Room
test_ex47.rb:22:in `test_map'
2) Error:
test_room(MyUnitTests):
NameError: uninitialized constant MyUnitTests::Room
test_ex47.rb:6:in `test_room'
3) Error:
test_room_paths(MyUnitTests):
NameError: uninitialized constant MyUnitTests::Room
test_ex47.rb:12:in `test_room_paths'
3 tests, 0 assertions, 0 failures, 3 errors, 0 skips]

The problem here is that you are creating a Room object inside the MyUnitTests class on line 3. Ruby thinks you want to use a class called MyUnitTest::Room, which doesn't exist. You need to use an absolute class reference, like so:
class MyUnitTests < Test::Unit::TestCase
def test_room()
gold = ::Room.new("Gold Room", """This room has gold in it you can grab. There's a doo to the north.""")
assert_equal(gold.name, "GoldRoom")
assert_equal(gold.paths, {})
end
Notice the :: before Room.new on line 3 there? That tells Ruby that you want to create a Room object from the top level name space :)
I hope that answers your question.
EDIT: You'll also need to change your other references to the Room class to ::Room. Sorry, I thought only the top one was a problem because of the indentation. A closer look reveals that the rest need the :: as well.

Related

I have a name error and not exactly sure where to define my argument

I'm making an guitar browsing CLI project. I have the name and url of different guitars like so:
def self.get_electric
doc = Nokogiri::HTML(open("https://reverb.com/c/electric-guitars"))
electrics = []
counter = 0
while counter < doc.css("h2:contains('Popular Electric Guitars')+div.overflowing-row__items ul.tiles.tiles--single-row.tiles--grow.tiles--three-wide li.tiles__tile").length
electric = {
name: doc.css("h2:contains('Popular Electric Guitars')+div.overflowing-row__items ul.tiles.tiles--single-row.tiles--grow.tiles--three-wide li.tiles__tile")[counter].text,
url: doc.css("h2:contains('Popular Electric Guitars')+div.overflowing-row__items ul.tiles.tiles--single-row.tiles--grow.tiles--three-wide li.tiles__tile a.marketing-callout__inner")[counter]["href"]
}
counter += 1
electrics << electric
end
electrics
HiStrung::Guitar.mass_create_electrics(electrics)
end
If user types in 'electric' or 'acoustic' they will get the name of the guitar and the url:
Enter here: electric
1. Fender Telecaster - https://reverb.com/marketplace/electric-guitars?query=telecaster
2. Gibson Les Paul - https://reverb.com/marketplace?query=les%20paul
3. Fender Stratocaster - https://reverb.com/marketplace/electric-guitars?query=stratocaster
4. Gibson SG - https://reverb.com/marketplace?query=sg
5. Fender Jazzmaster - https://reverb.com/marketplace?query=jazzmaster
Now what I want my program to do is when a user types in the number for whichever guitar they want to know more about, it will show the price and description of that guitar. The price and description are in another url.
I'm trying to make a method that grabs the url and get the html for the price and description:
def self.get_electric_info(electric)
url = electric.url
doc = Nokogiri::HTML(url)
end
but i'm getting this name error:
pry(main)> HiStrung::Scraper.get_electric_info(electric)
NameError: undefined local variable or method `electric' for main:Object
from (pry):1:in `__pry__'
Here is my initialize class:
class HiStrung::Guitar
attr_accessor :name, :url
##electrics = []
##acoustics = []
def self.electrics
##electrics
end
def self.acoustics
##acoustics
end
def self.mass_create_electrics(electric_hash)
electric_hash.each do |e_hash|
electric = HiStrung::Guitar.new(e_hash[:name], e_hash[:url])
##electrics << electric
end
end
def self.mass_create_acoustics(acoustic_hash)
acoustic_hash.each do |a_hash|
acoustic = HiStrung::Guitar.new(a_hash[:name], a_hash[:url])
##acoustics << acoustic
end
end
def initialize(name, url)
#name, #url = name, url
end
end
You don't provide the context at the point where you are calling that method, but if you look in your code you'll see you don't have an electric variable defined.
Assign electric to the Guitar object you want information for before you invoke your method.
Do something like this:
electric = HiStrung::Guitar.new("My name", "My url")
HiStrung::Scraper.get_electric_info(electric)
That should fix the problem.

Accessing instance variable array using IRB

I'm new to Ruby and am working on an exercise where a sports team (of up to 10 ppl) have to have at least 2 men and 2 women. I've created a Player class where the player's gender is determined and a Team class, where I add these players into an instance variable array of #team (which is created upon initialization of Team).
I have placed my full code towards the bottom of this request.
I'm hoping someone can please help me on the following:
(1) What do I type in IRB to be able to specifically recall/maniuplate the #team instance variable array (which stores all the players). I wish to later iterate over the array or extract the first item in the array (#team.first does not work)
(2) I'm having difficulty writing the code to determine if at least 2 male and female players are in the #team instance variable. The best code I came up in the Team class was the following - but it is reporting that #team is nilclass.
def gender_balance
#team.select{|player| player.male == true }
end
I have researched the internet and tried various combinations for an answer - with no success.
Directly below are the IRB commands that I have typed to create and add players to teams. Later below is my code for Team (which contains the method to assess whether it has the right gender mix) and Players.
irb(main):001:0> team = Team.new
=> #<Team:0x007fd8f21df858 #team=[]>
irb(main):002:0> p1 = Player.new
=> #<Player:0x007fd8f21d7b08 #male=true>
irb(main):003:0> p1.female_player
=> false
irb(main):004:0> p2 = Player.new
=> #<Player:0x007fd8f21bff58 #male=true>
irb(main):005:0> team.add_player(p1)
=> [#<Player:0x007fd8f21d7b08 #male=false>]
irb(main):006:0> team.add_player(p2)
=> [#<Player:0x007fd8f21d7b08 #male=false>, #<Player:0x007fd8f21bff58 #male=true>]
These two IRB lines are me trying unsucessfully to recall the contents of #team
irb(main):007:0> team
=> #<Team:0x007fd8f21df858 #team=[#<Player:0x007fd8f21d7b08 #male=false>, #<Player:0x007fd8f21bff58 #male=true>]>
irb(main):013:0> #team
=> nil
The code for both classes is below:
class Player
def initialize
#male = true
end
def female_player
#male = false
end
def male_player
#male
end
end
class Team
def initialize
#team = []
end
def add_player player
#team << player
end
def player_count
#team.count
end
def valid_team?
player_number_check
gender_balance
end
private
def player_number_check
player_count > 6 && player_count < 11
end
def gender_balance
#team.select{|player| player.male == true }
end
end
My github reference for this code is: https://github.com/elinnet/object-calisthenics-beach-volleyball-edition.git
Thank you.
Your Team class does not have an attribute for getting the #team instance variable.† So the only way you can extract its value is by using instance_variable_get:
irb(main):029:0> team = Team.new
=> #<Team:0x007fff4323fd58 #team=[]>
irb(main):030:0> team.instance_variable_get(:#team)
=> []
Please don't use instance_variable_get for actual production code though; it's a code smell. But for the purposes of inspecting instance variables in IRB, it's okay.
† You'd normally define one using either attr_accessor :team (read/write) or attr_reader :team (read-only) inside the class definition.

Get ruby dungeon to repeat back player name

I'm trying to expand upon Peter Cooper's dungeon game in Beginning Ruby and I want the game to address the player by name at each room and then ask them where they will go to make the game more interactive. I keep getting this error though:
dungeon.rb:82:in <main>': undefined methodname' for nil:NilClass (NoMethodError)
So the main parts I've added to try to make this work are Dungeon initialize (lines 4-13)
def initialize
player_name = ""
until !player_name.empty?
puts "Enter your name!"
player_name = gets.chomp
end
#player = Player.new(player_name)
#player.name = player_name
#rooms = []
end
The line in question that creates the error is this:
my_dungeon.add_room(:largecave, "Large Cave", "#{#player.name}, you find yourself in a large cavernous cave. To the west is a small aperture", {:west => :smallcave})
Full code is here:
Ruby Dungeon Code
What's going on here?
You probably wanted to use
my_dungeon.player.name
instead of
#player.name
in rooms addition method calls(since player has been defined for Dungeon instance).
So just use these lines instead of ones you currently have:
my_dungeon.add_room(:largecave, "Large Cave", "#{my_dungeon.player.name}, you find yourself in a large cavernous cave. To the west is a small aperture", {:west => :smallcave})
my_dungeon.add_room(:smallcave, "Small Cave", "#{my_dungeon.player.name}, you find yourself in a small, claustrophopic cave. To the east is a small aperture", {:east => :largecave}
By the way, you set name in initialize method, so there is no need for #player.name = player_name. And it is simpler to read while player_name.empty? instead of until !player_name.empty?, consider following refactoring:
def initialize
player_name = ""
while player_name.empty?
puts "Enter your name!"
player_name = gets.chomp
end
#player = Player.new(player_name)
#rooms = []
end

Struggling to write code and tests for my Tube System program, TDD using Rspec and Ruby

I am writing a small program for a train system.
I have a passenger, coach, train and station class (and thus, a spec test for each).
My test for my passenger class is as such:
let (:passenger) {Passenger.new}
it "should not be touched in to a station when initialized" do
expect(passenger.touchedin?).to be false
end
it "should be able to enter coach" do
coach = Coach.new
passenger.enter(coach)
expect{coach.to receive(:enter)}
end
it "should be able to alight coach" do
coach = Coach.new
passenger.alight(coach)
expect{coach.to receive(:alight)}
end
it "should be able to touch into station" do
station = Station.new
passenger.touchin(station)
expect{station.to receive(:touchin)}
end
it "should be able to touch out of station" do
station = Station.new
passenger.touchout(station)
expect{station.to receive(:touchout)}
end
end
And my passenger class is like this (at the moment :p):
class Passenger
def initialize
#touchedin = false
end
def enter(coach)
end
def touchedin?
#touchedin
end
def alight(coach)
end
def touchin(station)
end
def touchout(station)
end
end
I am unsure how to satisfy my tests, if my tests are even correct in the first place.
Any help is really appreciated!
You've not really said how you're modeling the relationship between coaches and passengers, but one way I could think of could be as follows. I'm just putting enough for the coach/passenger relationship (so nothing about touching in as this involves the station) - and I'm using minitest syntax, but I think you can get the idea of what's happening.
class Coach
def initialize
#passengers = []
end
...
end
class Passenger
def initialize
#touched_in = false
end
def alight(coach)
coach.passengers << self.uid # or self, if you want the whole passenger object available
end
...
end
coach = Coach.new
assert_empty coach.passengers
joe = Passenger.new
refute_includes coach.passengers, joe.uid # or joe
joe.alight(coach)
assert_includes coach.passengers, joe.uid # or joe

Assert_equal undefined local variable LRTHW ex52

Hi I made it to the lase exercise os Learn Ruby The Hard Way, and I come at the wall...
Here is the test code:
def test_gothon_map()
assert_equal(START.go('shoot!'), generic_death)
assert_equal(START.go('dodge!'), generic_death)
room = START.go("tell a joke")
assert_equal(room, laser_weapon_armory)
end
And here is the code of the file it should test:
class Room
attr_accessor :name, :description, :paths
def initialize(name, description)
#name = name
#description = description
#paths = {}
end
def ==(other)
self.name==other.name&&self.description==other.description&&self.paths==other.paths
end
def go(direction)
#paths[direction]
end
def add_paths(paths)
#paths.update(paths)
end
end
generic_death = Room.new("death", "You died.")
And when I try to launch the test file I get an error:
generic_death = Room.new("death", "You died.")
I tried to set the "generic_death = Room.new("death", "You died.")" in test_gothon_map method and it worked but the problem is that description of the next object is extremely long, so my questions are:
why assertion doesn't not respond to defined object?
can it be done different way then by putting whole object to testing method, since description of the next object is extremely long...
The nature of local variable is that they are, well, local. This means that they are not available outside the scope they were defined.
That's why ruby does not know what generic_death means in your test.
You can solve this in a couple of ways:
define rooms as constants in the Room class:
class Room
# ...
GENERIC_DEATH = Room.new("death", "You died.")
LASER_WEAPON_ARMORY = Room.new(...)
end
def test_gothon_map()
assert_equal(Room::START.go('shoot!'), Room::GENERIC_DEATH)
assert_equal(Room::START.go('dodge!'), Room::GENERIC_DEATH)
room = Room::START.go("tell a joke")
assert_equal(room, Room::LASER_WEAPON_ARMORY)
end
assert the room by its name, or some other identifier:
def test_gothon_map()
assert_equal(START.go('shoot!').name, "death")
assert_equal(START.go('dodge!').name, "death")
room = START.go("tell a joke")
assert_equal(room.name, "laser weapon armory")
end

Resources