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

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

Related

Cannot get a method instance to function; How to use an Each Do method in ruby?

I have an specific method that I would like to call so that I can see the balances for 'accounts'. The method is;
def report_balances(accounts)
accounts.each do |account|
puts account.balance
end
end
I am not sure but I have either built the above method incorrectly or I am calling it incorrectly or maybe I have placed the method correctly in my code.
class BankAccount
attr_reader :balance
def initialize(balance)
#balance = balance
end
def deposit(amount)
#balance += amount if amount >= 0
end
def withdraw(amount)
#balance -= amount if #balance >= amount
end
end
class SavingsAccount < BankAccount
attr_reader :number_of_withdrawals
APY = 0.0017
def initialize(balance)
super(balance) # calls the parent method
#number_of_withdrawals = 0 # then continues here
end
def end_of_month_closeout
if #balance > 0
interest_gained = (#balance * APY) / 12
#balance += interest_gained
end
#number_of_withdrawals = 0
end
def report_balances(accounts)
accounts.each do |account|
puts account.balance
end
end
end
I would like to see the balances of the objects:
my_account = SavingsAccount.new(100)
and
account = BankAccount.new(2500)
by calling
'report_balances(accounts)'
How would this be accomplished?
Think of my_account = SavingsAccount.new(100) as creating a new account, but what you're asking is I want to see all the balances of a list of accounts. Since each account has a balance, you can do:
[my_account, other_account].each do |account|
puts account.balance
end
I'd recommend moving your report_balances method to a class method or out of that class all together but that's a topic for a different discussion.

attr_accessor - Accessing an objects attributes from another class

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

Ruby classes, subclasses and factory methods

I'm working on a TestFirst exercise (temperature_object) and have come to a standstill when it comes to integrating a subclass. So far I've got:
class Temperature
def initialize(opts = {})
#options = opts
#c = #options[:c]
#f = #options[:f]
end
def self.from_celsius(num)
self.new(:c => num)
end
def self.from_fahrenheit(num)
self.new(:f => num)
end
def in_celsius
if #options.has_key?(:c)
#c
elsif #options.has_key?(:f)
ctof(#f)
end
end
def in_fahrenheit
if #options.has_key?(:f)
#f
elsif #options.has_key?(:c)
ftoc(#c)
end
end
def ftoc(num)
(((num * 9) / 5.000) + 32)
end
def ctof(num)
(((num - 32) * 5) / 9.0000)
end
end
class Celsius < Temperature
def initialize(num)
#c = num
end
end
class Fahrenheit < Temperature
def initialize(num)
#f = num
end
end
All of the tests pass until I get to the following:
require "temperature_object"
describe Temperature do
# Here's another way to solve the problem!
describe "Temperature subclasses" do
describe "Celsius subclass" do
it "is constructed in degrees celsius" do
Celsius.new(50).in_celsius.should == 50
Celsius.new(50).in_fahrenheit.should == 122
end
it "is a Temperature subclass" do
Celsius.new(0).should be_a(Temperature)
end
end
describe "Fahrenheit subclass" do
it "is constructed in degrees fahrenheit" do
Fahrenheit.new(50).in_fahrenheit.should == 50
Fahrenheit.new(50).in_celsius.should == 10
end
it "is a Temperature subclass" do
Fahrenheit.new(0).should be_a(Temperature)
end
end
end
end
So, I'm thinking the problem is that I'm trying to go from Temperature.new, which takes a hash, to Celsius.new, which only takes a value. I'm getting an undefined method "has_key?" for nil:NilClass error message. Do I need to set num as a hash value and assign it a key? If so, how do I do that? If not, any suggestions?
Your problem is that you refer to #options, but you don't assign it when creating an instance of Celsius. You should call the super constructor in your inherited classes:
class Celsius < Temperature
def initialize(num)
super(c: num)
end
end
class Fahrenheit < Temperature
def initialize(num)
super(f: num)
end
end
Now, when you call Celsius.new(50) the initialize(opts) will be called as if you called Temperature.new(c: 50), and all members will be properly assigned.

Ruby Check Class Owner From Other Inheritance With Default Library

I wondering of how to check the owner of certain method/class from other class.
For example:
class Value
attr_accessor :money
def initialize
#money = 0.0
end
def get_money
return self.money
end
def transfer_money(target, amount)
self.money -= amount
target.money += amount
end
end
class Nation
attr_accessor :value
def initialize
#value = Value.new
end
end
class Nation_A < Nation
def initialize
super
end
def pay_tribute_to_decendant_country
value.transfer_money(Nation_B.value, 500)
end
end
class Nation_B < Nation
def initialize
super
end
def pay_tribute_to_decendant_country
value.transfer_money(Nation_C.value, 200)
end
end
class Nation_C < Nation
def initialize
super
end
def pay_tribute_to_decendant_country
value.transfer_money(Nation_A.value, 300)
end
end
Yea, makes no sense how the decendant goes in a circle, but I'd like to implement the idea that different subclass has different argument.
The list is pretty long (I've installed at least 40 of these already with much more complex desendant branches and much more methods that call transfer_money from Value class). Then I have some idea to implement to the structure. I'd like to add currency, but to override all transfer_money method call would be a tremendous task for me to apply. Therefore I create a hash table that generate the call for me.
class Nation
def self.get_descendants
ObjectSpace.each_object(Class).select { |klass| klass < self }
end
end
module Additional_Value
currency_table = {}
min = 50
max = 100
def self.range (min, max)
rand * (max-min) + min
end
Nation.get_descendants.each do |derived_classes|
currency_table[derived_classes] == self.range min, max
end
end
class Value
attr_accessor :currency
def initialize
#money = 0
#currency = Additional_Value::currency_table
end
def transfer_money(target, amount)
self.money -= amount
amount = amount * #currency[self.class.owner] / #currency[target.class.owner]
target.money += amount
end
end
and I need to figure out how to define owner class. I tried using the caller, but it returns me string / array of string instead of object, method or calle work only for the same method, the 'sender' gem gives me an idea, but it's written in C, and I need to use the default library due to my circumstances.
Greatly appreciated.
Edit:
I'll rewrite the problem in a shorter way:
class Slave
def who_is_the_owner_of_me
return self.class.owner unless self.class.owner.nil?
end
end
class Test
attr_accessor :testing
def initialize
#testing = Slave.new
end
end
class Test2 < Test1
end
a = Test.new
b = Test2.new
c = Slave.new
a.testing.who_is_the_owner_of_me #=> Test
b.testing.who_is_the_owner_of_me #=> Test2
c.who_is_the_owner_of_me #=> main

Ruby Factory Method rpsec temperature converter

not quite understanding factory method here...
here is the respec line:
Temperature.from_celsius(50).in_celsius.should == 50
Here is what I have now:
getting errors...not quite sure how to satisfy this. thanks
class Temperature
attr_accessor :f
attr_accessor :c
def initialize(args)
#f = args[:f]
#c = args[:c]
end
def in_fahrenheit
#f or
(#c*9.0/5.0)+32
end
def in_celsius
#c or
(#f-32)*(5.0/9.0)
end
def self.from_celsius(c)
new c
end
end
This should help
class Temperature
def initialize c
#c = c
end
def in_celsius
#c
end
def in_fahrenheit
#c *9.0 /5.0 +32
end
# factory pattern typically instantiates a new object
def self.from_celsius(c)
new c
end
end
puts Temperature.from_celsius(50).in_celsius #=> 50
puts Temperature.from_celsius(100).in_fahrenheit #=> 212
I would recommend against attr_accessor :c unless you want users to have public access to temp.c. Without it, users will be forced to use temp.in_celsius or temp.in_fahrenheit
You need to assign to :c in the initialize method. Then you need self.from_celsius to return a new instance of Temperature. You probably want something like this:
class Temperature
attr_accessor :c
def initialize c
#c = c
end
def in_celsius
#c
end
def in_fahrenheit
9/5 * #c + 32
end
def self.from_celsius(num)
Temperature.new(num)
end
def self.from_fahrenheit(num)
Temperature.new((num-32)*5/9)
end
end
Now rspec shows true
1.9.1p378 :047 > Temperature.from_celsius(50).in_celsius.should == 50
=> true
1.9.1p378 :131 > Temperature.from_fahrenheit(32).in_celsius.should == 0
=> true
The reason you're getting "error: Can't covert symbol to integer –" is because you're in your Temperature.from_celsius(50) you're passing it an integer when you're supposed to pass it a key & symbol for the options hash.
initialized
class Temperature
def initialize(opts = {})
#options = opts
end
class factory method
def self.from_celsius(x)
Temperature.new(:c => x)
end
instance method
def in_celsius
if #options[:c] == nil
return (#options[:f]-32) * (5/9.to_f)
else
return #options[:c]
end
end

Resources