I have this phonebook program that looks up all the contacts, deletes a contact, and adds a contact. I created a hash global variable called contactList. However, the program fails to recognize this. What did I do wrong?
class PhoneBook
contactList = hash.new
def Add(newContact = {})
flag = false
if newContact.length < 1
return flag
else
flag = true
newContact.collect do |name, number|
contactList[name] = number
end
return flag
end
end
def delete (targetName)
if !contactList.has_key?(targetName)
return false
else
contactList.delete(targetName)
return true
end
end
def displayContact (targetName)
number = -1
if contactList.has_key?(targetName)
number = contactList(targetName)
puts "Contact name : #{targetName}, Contact Number, #{number}"
else
puts "#{targetName} doesn't exist in the phonebook"
end
end
def displayAllContacts
if !contactList.empty?
contactList.each {|name, number| puts "Contact name: #{name}, contact number #{number}" }
else
puts "You don't have any contact details your phonebook"
end
end
end
Because you have defined class local variable contactList, whereas you wanted to have an instance variable.
Remove this line
contactList = hash.new
and add the following method:
def contactList
#contactList ||= {}
end
P.S. there is no such thing as hash.new, you most likely meant Hash.new.
P.P.S. By Ruby naming conventions your variables/methods names should be snake-cased, not camel cased.
So it should be contact_list.
Related
I need to randomly pick a name from an array in Ruby and then check if it uppercase. So far I have:
def namegenerator
return #name.sample
end
def namechecker
if name.upcase then
check = TRUE
else
check = FALSE
end
end
It needs to be as two separate methods like this.
Something like this:
def sample_word(words)
words.sample
end
def upcase?(word)
word == word.upcase
end
And then something like:
words = %w[APPLE banana CherRy GRAPE]
word = sample_word(words)
puts word # e.g. BANANA
puts upcase?(word) # will print true
If you just want to check just the first letter:
names = %w(Kirk mccoy scott Spock)
names.sample.then { |name| [name, name[0] == name[0].upcase] }
#=> ["mccoy", false]
Maybe something like this:
class NameGenerator
def initialize(size, items)
#name = ""
#size = size
#items = items
end
def namegenerator
#name = #items.sample(#size).to_s
end
def namechecker?
#name == #name.upcase
end
def name
#name
end
end
ng = NameGenerator.new 1, ["name", "Name", "NAME"]
ng.namegenerator
puts ng.name, ng.namechecker?
Update
I've posted code without much thinking about abstraction and i think it would be much better to encapsulate name and upper case check to separate class and make it immutable, then make generator class that selects one entity from collection.
class NameGenerator
def initialize(items)
#items = items
end
def next
#items.sample
end
end
class Name
attr_reader :name
def initialize(name)
#name = name
end
def is_uppercase?
#name.match(/\p{Lower}/) == nil
end
end
ng = NameGenerator.new [
Name.new("name"),
Name.new("Name"),
Name.new("NAME"),
Name.new("na-me")
]
name = ng.next
puts name.name, name.is_uppercase?
How do I write a rspec test for the following.
the value that gets passed in is this...
90A14F 1.4
def classname
def init
#input_colors = Array.new
end
def speak
puts "enter your line of color values"
result = STDIN.gets.chomp
new_result = result.gsub!(/([\s])+/,':')
#input_colors << new_result
end
end
How do I write an rspec 3.1 test for this speak method that test if gets.chomp is...90A14F 1.4
They will get an instance var #input_colors == ["90A14F:1.4"]
There are some issues in your example. I would change and fix it to something like this:
class ColorReader # with `class` and an upcase class name
def initialize # not `init`
#colors = [] # the use of `Array.new` is uncommon
end
def read
puts "enter your line of color values"
result = STDIN.gets.chomp
new_result = result.gsub!(/([\s])+/,':')
#colors << new_result
end
end
Then a test could look like this:
describe ColorReader do
describe '#read' do
let(:input) { "90A14F 1.4\n" }
subject(:color_reader) { ColorReader.new }
before do
allow(color_reader).to receive(:puts).and_return(nil)
allow(STDIN).to receive(:gets).and_return(input)
end
it 'writes to the console' do
color_reader.read
expect(color_reader).to have_received(:puts).
with("enter your line of color values").once
end
it 'reads from STDIN' do
color_reader.read
expect(STDIN).to have_received(:gets).once
end
it 'returns the sanitized input' do
expect(color_reader.read).to eq(['90A14F:1.4'])
end
end
end
Btw. I would prefer to explicitly test the new value of the #colors array (perhaps with attr_reader :colors) and not the implizit return value of the read method. If you have a reader for the #colors then the last spec can be changed to:
it 'adds the sanitized input to `colors`' do
expect {
color_reader.read
}.to change { color_reader.colors }.from([]).to(['90A14F:1.4'])
end
I'm trying to build a relatively simple app in ruby. However I am unable to get my object to return anything other than 0 when puts obj.to_s is called on it. I understand the quality of the code may be poor (and wouldn't mind any hints).
Help please!
class Docpart
def Docpart.new(inputAsString,typeAsInteger)
#value = inputAsString
#type = typeAsInteger.to_i # 0 = title, 1 = text, 2 = equation (can't be done yet), 3 = table
end
def Docpart.to_s
return "Type is #{#type}, value is #{#value}"
end
end
module Tests
def Tests.test1()
filetree = Array.new(0)
filetree.push( Docpart.new("Title",0))
filetree.each{|obj| puts obj.to_s}
return filetree[0]
end
end
puts Tests.test1.to_s
gets.chomp
Because you defined class method to_s not instance one. Also writing constructor in Ruby is a little different. You need to write this that way:
class Docpart
def initialize(inputAsString,typeAsInteger)
#value = inputAsString
#type = typeAsInteger.to_i # 0 = title, 1 = text, 2 = equation (can't be done yet), 3 = table
end
def to_s
"Type is #{#type}, value is #{#value}"
end
end
module Tests
def self.test1
filetree = []
filetree << Docpart.new("Title",0)
filetree.each{ |obj| puts obj.to_s }
filetree[0]
end
end
puts Tests.test1.to_s
gets.chomp
PS Read any book about Ruby and any styleguide like Githubbers or bbatsov one.
I have a strange need that I can't find a good solution to.
I've got a method that I will pass either an object, hash, or array to. And I want to be able to get the name of that object, hash, or array that i'm passing.
Here is an example:
#user = User.find(5)
log_info(#user)
def log_info(obj)
Rails.logger.debug(obj.to_s)
Rails.logger.debug(obj.inspect)
end
That would log something like:
#user
{"active"=>true, "address1"=>"something", "address2"=>"", "city"=>"somewhere"}
This would just prevent me from having to do this:
#user = User.find(5)
log_info("#user", #user)
def log_info(heading, obj)
Rails.logger.debug(heading)
Rails.logger.debug(obj.inspect)
end
Any ideas on how to accomplish this?
You can do that with a little hackery - i'll just leave this here:
class Reference
def initialize(var_name, vars)
#var_name = var_name
#getter = eval "lambda { #{var_name} }", vars
end
def name
#var_name
end
def value
#getter.call
end
end
def log_info(ref)
Rails.logger.debug(ref.name.to_s)
Rails.logger.debug(ref.value.inspect)
end
def ref(&block)
Reference.new(block.call, block.binding)
end
#user = "something";
log_info(ref{:#user}) # -> #user - "something"
If your case only requires to work with instance variables, you could do something like this:
def log_info(obj)
heading = instance_variables.detect {|name| instance_variable_get(name).equal?(obj) }
Rails.logger.debug(heading)
Rails.logger.debug(obj.inspect)
end
class DobbsyKretts
def initialize
#Receive idea
puts "Enter an idea, a secret or anything else you want to secretize; hit enter to stop typing and save the file"
(#idea = gets).reverse.upcase
#Filename and saving - to encrypt the file
puts "Enter the file name you'd like to have this saved as; Type PLAN at the beginning for plans and REM for reminders"
(#file_name = gets.chomp.upcase)
File::open("DobbsyKrett-"+ #file_name + ".txt", "w") do |f|
f << #idea
end
end
def unzip
puts "Do you want to withdraw PLAN or REM"
response = gets.chomp.upcase!
puts "Invalid" if !["PLAN","REM"].include?(response)
file_contents = nil
Dir['DobbsyKrett-'+response+"*.txt"].each do |file_nom|
file_contents = File.read(file_nom)
end
puts file_contents
end
end
somethingsomething1 = DobbsyKretts.new
somethingsomething1.unzip
def unzip
puts "Do you want to withdraw PLAN or REM"
#response = gets.strip
if #response.downcase != "plan" and #response.downcase != "rem"
puts "Invalid" end
Dir["DobbsyKrett-"+#response+".txt"].each do |file_nom|
#value = file.read(file_nom)
end
puts #value
end
end
The function gets will return a string with the line-ending character at the end which is not what you expected. To remove it, use the chomp function:
#response = gets.chomp
It is okay for a method (e.g. unzip) to create new instance variables (e.g. #valueholder). In general it's always better for your variables to have the smallest possible scope, so unless you need to read valueholder later, you should just use a local variable (remove the # from the name):
Dir["DobbsyKrett-"+#response+".txt"].each do |file_nom|
valueholder = File.read(file_nom)
end
puts valueholder
Also, valueholder is a terrible name for a variable but if you made it a local variable that could be excused.
Also, your block startings/endings are mismatched. Here's a fixed version of your function that shouldn't result in syntax errors:
def unzip
puts "Do you want to withdraw PLAN or REM"
response = gets.chomp.downcase
if !["plan","rem"].include? response
puts "Invalid"
else
Dir["DobbsyKrett-#{response}.txt"].each do |file_nom|
valueholder = file.read(file_nom)
end
puts valueholder
end
end
Edit: You should capitalize File to correctly call File.read.