attr_accessor - Accessing an objects attributes from another class - ruby

I want to access the ogre's object's swings attribute from the Human's class. However, all I am getting is:
NameError: undefined local variable or method ogre for
**<Human:0x007fdb452fb4f8 #encounters=3, #saw_ogre=true>
Most likely a simple solution, and my brain is just not operating this morning. I am running tests with minitest. The test and classes are below:
ogre_test.rb
def test_it_swings_the_club_when_the_human_notices_it
ogre = Ogre.new('Brak')
human = Human.new
ogre.encounter(human)
assert_equal 0, ogre.swings
refute human.notices_ogre?
ogre.encounter(human)
ogre.encounter(human)
assert_equal 1, ogre.swings
assert human.notices_ogre?
end
ogre.rb
class Ogre
attr_accessor :swings
def initialize(name, home='Swamp')
#name = name
#home = home
#encounters = 0
#swings = 0
end
def name
#name
end
def home
#home
end
def encounter(human)
human.encounters
end
def encounter_counter
#encounters
end
def swing_at(human)
#swings += 1
end
def swings
#swings
end
end
class Human
def initialize(encounters=0)
#encounters = encounters
#saw_ogre = false
end
def name
"Jane"
end
def encounters
#encounters += 1
if #encounters % 3 == 0 and #encounters != 0
#saw_ogre = true
else
#saw_ogre = false
end
if #saw_ogre == true
ogre.swings += 1 # <----issue
end
end
def encounter_counter
#encounters
end
def notices_ogre?
#saw_ogre
end
end

The easy fix would be to pass the ogre object as an argument to encounters - assuming encounters isn't used anywhere else without the argument.
class Ogre
...
def encounter(human)
human.encounters(self)
end
...
end
class Human
...
def encounters(ogre)
#encounters += 1
if #encounters % 3 == 0 and #encounters != 0
#saw_ogre = true
else
#saw_ogre = false
end
if #saw_ogre == true
ogre.swings += 1 # <----issue
end
end
...
end

Related

Undefined function make_card Ruby

I am doing a practice problem black jack card game in ruby, references I am using are
https://medium.com/quick-code/using-ruby-classes-to-implement-a-game-of-blackjack-535a786c417
I am getting error that says undefined method "make_card"
Code for my Deck Class
class Deck
def initialize
#faces = [*(2..10),'Jack','Queen','King','Ace']
#suits = ['clubs','spades','hearts','diamonds']
#cards = []
#faces.each do |face|
if face.class == "Integer"
value = face
elsif face == 'Ace'
value = 11
else
value = 10
end
#suits.each do |suit|
#cards << Card.new(face,suit,value)
end
end
#cards.shuffle!
end
def make_card(participant)
fresh_card = Card.new(face,suit,value)
participant.turn << fresh_card
participant.total = participant.total + fresh_card.value
end
def deal(number,participant)
number.times{#cards.shift.make_card(participant)}
end
end
As both methods are in same class I am still getting that error
Solved it by placing method in Card class and accessing it via its instance variable
class Card
attr_accessor :face, :suit, :value
def initialize(face,suit,value)
#face = face
#suit = suit
#value = value
end
def make_card(participant)
fresh_card = Card.new(face,suit,value)
participant.turn << fresh_card
participant.total = participant.total + fresh_card.value
end
end
class Deck
def initialize
#faces = [*(2..10),'Jack','Queen','King','Ace']
#suits = ['clubs','spades','hearts','diamonds']
#cards = []
#faces.each do |face|
if face.class == Integer
value = face
elsif face == 'Ace'
value = 11
else
value = 10
end
#suits.each do |suit|
#cards << Card.new(face,suit,value)
end
end
#cards.shuffle!
end
def deal(number,participant)
number.times{#cards.shift.make_card(participant)}
end
end

/usr/local/lib/ruby/gems/2.2.0/gems/gosu-0.10.4/lib/gosu/patches.rb:37:in `initialize': Cannot open file ./media/image.jpg (RuntimeError) in gosu

I have this code which is not giving the desired output and shows the above error.
require 'gosu'
def media_path(file)
File.join(File.dirname(File.dirname(
__FILE__)),'media', file)
end
#def media_path(file); File.expand_path "media/#{file}", File.dirname(__FILE__)
# end
class Explosion
FRAME_DELAY = 10 # ms
SPRITE = media_path('space.png')
def self.load_animation(window)
Gosu::Image.load_tiles(
window, SPRITE, 128, 128, false)
end
def initialize(animation, x, y)
#animation = animation
#x, #y = x, y
#current_frame = 0
end
def update
#current_frame += 1 if frame_expired?
end
def draw
return if done?
image = current_frame
image.draw(
#x - image.width / 2.0,
#y - image.height / 2.0,
0)
end
def done?
#done ||= #current_frame == #animation.size
end
private
def current_frame
#animation[#current_frame % #animation.size]
end
def frame_expired?
now = Gosu.milliseconds
#last_frame ||= now
if (now - #last_frame) > FRAME_DELAY
#last_frame = now
end
end
end
class GameWindow < Gosu::Window
BACKGROUND = media_path('image.jpg')
def initialize(width=800, height=600, fullscreen=false)
super
self.caption = 'Hello Animation'
#background = Gosu::Image.new(
self, BACKGROUND, false)
#animation = Explosion.load_animation(self)
#explosions = []
end
def update
#explosions.reject!(&:done?)
#explosions.map(&:update)
end
def button_down(id)
close if id == Gosu::KbEscape
if id == Gosu::MsLeft
#explosions.push(
Explosion.new(
#animation, mouse_x, mouse_y))
end
end
def needs_cursor?
true
end
def needs_redraw?
!#scene_ready || #explosions.any?
end
def draw
#scene_ready ||= true
#background.draw(0, 0, 0)
#explosions.map(&:draw)
end
end
window = GameWindow.new
window.show
It can't find ./media/image.jpg are you sure it is there, and can be opened, and is the current directory "." what you think it is?

Difference between parameters "amount" and "amount=0", in this context?

What's the difference that the parameter "amount" being defined to 0 has on the overall instance creation in this context, since the code below the commented line does the same thing with out "amount=0"?
class Account
attr_accessor :balance
def initialize(amount=0)
self.balance = amount
end
def +(x)
self.balance += x
end
def -(x)
self.balance -= x
end
def to_s
balance.to_s
end
end
acc = Account.new(20)
acc -= 5
puts acc
class Account
attr_accessor :balance
def initialize(amount)
self.balance = amount
end
def +(x)
self.balance += x
end
def -(x)
self.balance -= x
end
def to_s
balance.to_s
end
end
acc = Account.new(20)
acc -= 5
puts acc
I'm a beginner. Thanks for any help!
Specifying amount = 0 in the parameter list make the amount parameter become optional (with 0 as its default value).
If you don't specify amount argument, it will be 0.
account = Account.new # without amount argument
account.balance # => 0
account = Account.new 10 # with amount argument
account.balance # => 10
The only difference is:
The first class sets the default value
class Account
attr_accessor :balance
def initialize(amount=0)
self.balance = amount
end
... class omitted
end
account = Account.new
account.balance # should be equal to 0
class Account
attr_accessor :balance
def initialize(amount)
self.balance = amount
end
... class omitted
end
account = Account.new nil
account.balance # should be equal to nil

Object that can be coerced to either String, Fixnum, or Float?

Is there a way to define an object that can be coerced to either a String or a Fixnum or a Float? This is for use in a system that collects values and evaluates a restricted set of simple expressions with them.
I tried:
class EmptyValue < Numeric
def to_s; ''; end
def to_str; ''; end
def to_i; 0; end
def to_int; 0; end
def to_f; 0.0; end
end
but this fails for
1 + e
TypeError: EmptyValue can't be coerced into Fixnum
A little more poking and this worked for all my use cases:
class EmptyValue < Numeric
def to_s; ''; end
def to_str; ''; end
def to_i; 0; end
def to_int; 0; end
def to_f; 0.0; end
def +(other)
case other
when String
to_s + other
when Fixnum
to_i + other
when Float
to_f + other
end
end
end
This is what I've done long time ago:
class NullObject
attr_reader :null_object_type, :recorded_messages
alias ρ recorded_messages
def initialize( type_of_null_object = nil )
#null_object_type = type_of_null_object
#recorded_messages = []
end
def null_object? null_type = nil
null_object_type == null_type
end
alias null? null_object?
def to_a; [] end
def to_s; "null #{null_object_type}".strip end
def to_f; 0.0 end
def to_i; 0 end
def present?; false end
def empty?; true end
def blank?; true end
def inspect
"NullObject #{null_object_type}".strip
end
def method_missing ß, *aj, &b # :nodoc:
#recorded_messages << [ ß, aj, b ]; self
end
def respond_to? ß, *aj, &b # :nodoc:
true
end
protected
def == other # :nodoc:
null_object_type == other.null_object_type
end
end # class NullObject
# Strong zero.
#
ZERO = NullObject.new
ZERO.instance_exec {
ɪ = self
singleton_class.class_exec do
define_method :zero do ɪ end
end
def * other; other.class.zero end
def / other
self unless other.zero?
raise ZeroDivisionError, "The divisor is zero! (#{other})"
end
def + other; other end
def - other; -other end
def coerce other
return other, other.class.zero
end
def zero?; true end
def to_s; "∅" end
def inspect; to_s end
def to_f; 0.0 end
def to_i; 0 end
def == other
z = begin
other.class.zero
rescue NoMethodError
return false
end
other == z
end
}
class << Numeric; def zero; 0.0 end end
class << Integer; def zero; 0 end end
class << Float; def zero; 0.0 end end
class << Rational; def zero; Rational 0, 1 end end
class << Complex; def zero; Complex 0, 0 end end
class << String; def zero; '' end end
class << Array; def zero; [] end end
class << Hash; def zero; {} end end
So, now you have 0 + ZERO #=> 0. I called this "strong zero". But it was a hack. I have a gut feeling, that this is not such a good practice.

Ruby: Using variables between classes

I am making a short, text-based game as an extra credit exercise based on the Ruby I have learned so far and I'm having trouble getting classes to read and write variables between each other. I have read extensively and searched for clarification on how to do this but I haven't had much luck. I have tried using # instance variables and attr_accessible but I can't figure it out. Here is my code so far:
class Game
attr_accessor :room_count
def initialize
#room_count = 0
end
def play
while true
puts "\n--------------------------------------------------"
if #room_count == 0
go_to = Entrance.new()
go_to.start
elsif #room_count == 1
go_to = FirstRoom.new()
go_to.start
elsif #room_count == 2
go_to = SecondRoom.new()
go_to.start
elsif #room_count == 3
go_to = ThirdRoom.new()
go_to.start
end
end
end
end
class Entrance
def start
puts "You are at the entrance."
#room_count += 1
end
end
class FirstRoom
def start
puts "You are at the first room."
#room_count += 1
end
end
class SecondRoom
def start
puts "You are at the second room."
#room_count += 1
end
end
class ThirdRoom
def start
puts "You are at the third room. You have reached the end of the game."
Process.exit()
end
end
game = Game.new()
game.play
I want to have the different Room classes change the #room_count variable so that Game class knows which room to go to next. I am also trying to do this without implementing class inheritance. Thanks!
class Room
def initialize(game)
#game = game
#game.room_count += 1
end
def close
#game.room_count -= 1
end
end
class Game
attr_accessor :room_count
def initialize
#room_count = 0
end
def new_room
Room.new self
end
end
game = Game.new
game.room_count # => 0
room = game.new_room
game.room_count # => 1
room.close
game.room_count # => 0

Resources