Ruby object oriented inheritance - ruby

I am writing a banking program. Already defined Bank class.
class Checking
def initialize(initial_deposit)
#number = Bank.size + 1
#principal = initial_deposit.to_f
##intest_rate = 0.003
end
def balance
principal = principal * (1 + interest_rate / 365 ) ** 365
end
end
class Savings
def initialize(initial_deposit)
#number = Bank.size + 1
#principal = initial_deposit.to_f
##interest_rate = 0.025
end
def balance
principal = principal * (1 + interest_rate / 4) ** 4
end
end
But keep getting error message.I'm pretty sure the issue is within Saving and Checking; when I press s or c, errors arise. Maybe someone could help find my error. Any help or advice would be appreciated.

Can you post the Bank class code here. I think the issue could be in the Bank class, not sure why are you pressing 's' and 'c'. The above code doesn't take any input.
And I assume that the Bank class asks the user to select the account type he need to create and in response to the key he presses, the Bank class might call the Saving and Checking class and create the account.

Related

Ruby using Elapsed Time to increase Obj stats

I'm still new to Ruby and I'm having some issues working with time. Essentially the goal of this project is to make a virtual pet. I have class Pet set up at that when initialized randomly generates stats for the pets hunger, energy, fun, affection, and then will determine the pets mood.
In my class Game, the user is displayed the pets current stats and then asked for input to interact with the pet. The user input takes the string (e.g. 'Feed') and then will decrease #pet.hunger by 1.
What I want to do is create some way of storing the time elapsed since the user last interacted with a stat. If the stat has not been interacted with within 2 minutes it will be increased or decreased accordingly and the time will restart. Here is the module I attempted to use
module FeedTime
def feed_time
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
#user_input == 'Feed'
end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
time_elapsed = end_time - start_time
#pet.hunger += 1 unless time_elapsed < 120
end
end
This is how it was used within the Game class
require_relative 'time'
class StartGame
include Reaction
include FeedTime
attr_reader :dragon
def initialize
#dragon = Dragon.new
end
def game
feed_time
loop do
welcome
user_input
break if #user_input == 'Quit'
end
end
I've tried a few variations of this code with no luck. All of my code runs without error but Hunger will never increase.

Turning a single file into MVC without Rails

I need to take the single file code below and separate it into a Model, View, Controller (MVC) ruby program that can run by the ruby command in the command line without using Rails (for instructions on how to run this program from irb, check out the README.md on my RubyBank Github Repo).
require_relative 'view'
class BankAccount
attr_accessor :name, :balance
def initialize(name, balance=0)
#name = name
#balance = balance
end
def show_balance(pin_access)
if pin_access == pin || pin_access == bank_manager
puts "\nYour current balance is: $#{#balance}"
else
puts pin_error_message
end
end
def withdraw(pin_access, amount)
if pin_access == pin
#balance -= amount
puts "'\nYou just withdrew $#{amount} from your account. \n\nYour remaining balance is: $#{#balance}\n\n"
else
puts pin_error_message
end
if #balance < 0
#balance += amount
return overdraft_protection
end
end
def deposit(pin_access, amount)
if pin_access == pin
#balance += amount
puts "\nYou just deposited $#{amount} into your account. \n\nYour remaining balance is: $#{#balance}"
else
puts pin_error_message
end
end
private
def pin
#pin = 1234
end
def bank_manager
#bank_manager = 4321
end
def pin_error_message
puts "Invalid PIN number. Try again."
end
def overdraft_protection
puts "\nYou have overdrafted your account. We cannot complete your withdrawl. Please deposit money before trying again. \n\nYour corrected balance is $#{#balance}"
end
end
I am looking for a good place to start or a general approach towards taking on such a task.
A simple approach would be to create three classes:
BankAccount minus text output is your Model.
All the text I/O goes into your View. Prompt the user for an action or registration. Get the model (for displaying data) from your controller or use the model directly.
Your Controller is responsible for a) reacting to user input, b) modifying the model and c) for holding state not directly related to the BankAccount (this point is discussable) like being logged in or what actions are possible from your current state. Your Controller receives all actions with user supplied data from your view.
Clean separation between View and Controller may be a bit hard in a console application. Also, there are about a million possible ways to implement this in a MVC style. Most important point: no UI-Code (puts/gets) in your model.

Basic Ruby questions

My understanding is that checking and savings are saved under account_a and account_b. Can someone explain what's happening in the last two lines?
class Account
attr_accessor :balance
def initialize(balance)
#balance = balance
end
end
class Transaction
def initialize(account_a,account_b)
#account_a = account_a
#account_b = account_b
end
private
def debit(account, amount)
account.balance -= amount
end
def credit(account,amount)
account.balance += amount
end
public
def transfer(amount)
debit(#account_a, amount)
credit(#account_b, amount)
end
end
savings = Account.new (100)
checking = Account.new (200)
trans = Transaction.new(checking, savings)
trans.transfer(50)
How do I print the value of trans?
In the second to last line, you are initializing a new Transaction from your checking account to your savings account. Then in the last line, you are transferring 50.
You cannot print the value of trans because there is no value associated with it. You can print out the balance of your initialized accounts though, by calling savings.balance and checking.balance
When you create trans using Transaction.new then references to checking and savings are stored inside the transaction object as #account_a and #account_b
The transfer method calls debit with #account_a and credit with #account_b so decreasing the balance of a by the amount and increasing the balance of b by the same amount, in effect transferring from checking to savings.

Learnstreet Ruby Lesson 11.5 Transfer state between objects

I've been stuck on this Learnstreet lesson for a day now. The exercise prompts:
Can you now implement a method called transfer! which takes two parameters, amount and other_account. The method should withdraw the specified amount from the current object and deposit it into other_account object.
The code in the editor goes as follows:
class BankAccount
attr_accessor :name, :balance, :address
def initialize(name, balance, address)
#name = name
#balance = balance
#address = address
end
def withdraw!(amount)
if #balance - amount > 0
#balance = #balance - amount
end
#balance
end
def deposit!(amount)
#balance += amount
end
# your code here
end
alices_account = BankAccount.new("Alice Cooper", 2500, "456 University Avenue")
bobs_account = BankAccount.new("Bob Ventura", 2100, "3500 Fox Street")
I know that you need to set up a method with def transfer!(amount, other_account). However I do not know what to put in the bottom after alices_account and bobs_account.
You'd call transfer! on one of the objects, passing in the other, e.g.,
bobs_account.transfer!(500, alices_account)
You're just calling a method on an instance, like "foo".size or [1, 2, 3].each etc. The only difference is that you've created the method you're calling.
I know that you need to set up a method with def transfer!(amount, other_account).
So basically you have to create BankAccount#transfer! that withdraw some money from the object that calls it and deposit the sum into the "other" BankAccount object.
The solution is pretty trivial since you have the BankAccount#withdraw! and BankAccount#deposit! already set up:
def transfer!(amount, other_account)
withdraw! amount
other_account.deposit! amount
end
However I do not know what to put in the bottom after alices_account and bobs_account.
The exercise doesn't require you to do anything with the latter. If you were supposed to do something you would need to know the amount of "money" to transfer from alices_account to bobs_account an viceversa and then go with:
# assuming x to be the amount to transfer
alices_account.transfer! x, bobs_account
or:
# assuming x to be the amount to transfer
bobs_account.transfer! x, alices_account
Ok now. I've spent an hour to complete all the 10 course before that one and this is what I discovered. At some point you get to write the last two lines of your code.
Then a weird thing happens. The code generated by the exercise contains a . To near the end which is obviously a syntax error. By removing that line and adding the method I provided above you get to pass the test.

Implementing accessor methods in Ruby

This is a follow up question to: ruby variable scoping across classes. The solution makes sense to me conceptually, but I can't get it to work. Thought maybe with more code someone could help me.
I have a class Login that declares a new IMAP class, authenticates, and picks a mailbox.
I then am trying to create a separate class that will "do stuff" in the mailbox. For example, calculate the number of emails received. The problem is that the #imap instance of Net::IMAP doesn't pass from the Login class to the Stat class -- I'm getting no method errors for imap.search in the new class. I don't want to re-log in and re-authenticate each time I need to "do some stuff" with the mailbox. I'm trying to implement the solution in the other thread, but can't seem to get it to work.
Here's the Login class:
class Login
def initialize(user, domain, pass)
#username = user
#domain = domain
#pass = pass
#check if gmail or other domain
gmail_test = #domain.include? "gmail.com"
if gmail_test == true
#imap = Net::IMAP.new('imap.gmail.com',993,true,nil,false)
#imap.login(#username + "#" + #domain, #pass)
else
#imap = Net::IMAP.new("mail." + #domain)
#imap.authenticate('LOGIN', #username + "#" + #domain, #pass)
end
return self
end
#enable mailbox select
def mailbox(box)
#mailbox = box
#mailbox_array = #imap.list('','*').collect{ |mailbox| mailbox.name } #create array of mailboxes
#matching_mailbox = #mailbox_array.grep(/#{#mailbox}/i) #search for mailbox along list
if #matching_mailbox.empty? == true #if no results open INBOX
#mailbox = "INBOX"
#imap.examine(#mailbox)
else
#imap.examine(#matching_mailbox.first.to_s) #if multiple results, select first and examine
#mailbox = #matching_mailbox.first.to_s
end
return self
end
end
I want to be able to say:
Login.new("user", "domain", "pass").mailbox("in")
and then something like:
class Stat
def received_today()
#emails received today
#today = Date.today
#received_today = #imap.search(["SINCE", #today.strftime("%d-%b-%Y")]).count.to_s
puts #domain + " " + #mailbox.to_s + ": " + #received_today + " -- Today\n\n" #(" + #today.strftime("%d-%b-%Y") + ")
end
end
And be able to call
Stat.new.received_today and have it not throw a "no method search" error. Again, the other question contains pseudo_code and a high level explanation of how to use an accessor method to do this, but I can't implement it regardless of how many hours I've tried (been up all night)...
All I can think is that I am doing this wrong at a high level, and the stat calculation needs to be a method for the Login class, not a separate class. I really wanted to make it a separate class, however, so I could more easily compartmentalize...
Thanks!
Another approach that works and doesn't require defining get_var methods:
b.instance_variable_get("#imap") # where b = class instance of login
OK --- After much head banging on the wall, I got this to work.
Added these three methods to class Login:
def get_imap
#imap
end
def get_domain
#domain
end
def get_mailbox
#mailbox
end
Changed class Stat to:
class Stat
def received_today(login)
#emails received today
#today = Date.today
#received_today = login.get_imap.search(["SINCE", #today.strftime("%d-%b-%Y")]).count.to_s
# puts #received_today
puts login.get_domain + " " + login.get_mailbox.to_s + ": " + #received_today + " -- Today\n\n"
end
end
Now this actually works, and doesn't say undefined method search or imap:
b = Login.new("user", "domain", "pass").mailbox("box")
c = Stat.new
c.received_today(b)
I'm pretty sure there is a way to use attr_accessor to do this as well, but couldn't figure out the syntax. Anyway, this works and enables me to use the #imap var from class Login in class Stat so I can write methods to "do_stuff" with it. Thanks for the help and please don't hesitate to tell me this is horrible Ruby or not best practices. I'd love to hear the Ruby way to accomplish this.
Edit for attr_accessor or attr_reader use:
Just add it to class Login and then can say login.imap.search#stuff in class Stat with no problem.

Resources