Ruby method not being seen - ruby

I have a method known_args being called from the main class of my script, it is included in the module, Validations, but for some reason I'm getting:
undefined method `known_args' for PasswordGenerator:Class (NoMethodError)
Strange thing is, even when I place it back in the main class, I get the same error.
password_generator.rb
require 'securerandom'
require_relative 'validations'
class PasswordGenerator
include Validations
class Array
# If +number+ is greater than the size of the array, the method
# will simply return the array itself sorted randomly
def randomly_pick(number)
sort_by{ rand }.slice(0...number)
end
end
def password_generator length, charsets
#Set allowed characters
valid_characters = charsets
#Intitialise empty string
password = ""
length.times do
#we cannot do "randomly_pick(length)" because we want repeating characters
password << valid_characters.randomly_pick(1).first
end
#Return password
password
end
def username_generator
SecureRandom.urlsafe_base64(calc_usename_length)
end
def calc_usename_length
length = (12..32).to_a
length.sample
end
############### Input, checks and validations
def charsets
special_chars = [ '#', '£', "#", "%", "?", "€", "-", "+", "=", "*", "_", "~", "^", "|", ".", "[","]", "{", "}" ]
other = ('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a
combined = use_special? ? insert_special(special_chars, other) : no_special(other)
combined
end
def use_special?
return true if #use_special_argument == 's' || #use_special_argument == 'S'
return false if #use_special_argument == 'b' || #use_special_argument == 'B'
end
def insert_special(special_chars, other)
other + special_chars
end
def no_special(other)
other
end
def argument_check length
is_integer(length) && check_length(length) ? pass(length) : fail
end
def pass length
password_generator(length, charsets)
end
length = ARGV[0].to_i
#use_special_argument = ARGV[1]
unless known_args.include? #use_special_argument
puts
puts "Specify whether or not to use special characters."
puts "Use special characters: 's' || 'S'"
puts "No special characters: 'b' || 'B'"
puts
puts "Unknown argument: '#{#use_special_argument}'. Aborting"
exit_script
end
puts
puts "Username: " + username_generator
puts "Password: " + argument_check(length)
puts
puts "Complete. Exiting"
exit_script
end
validations.rb
module Validations
def is_integer length
length.is_a? Integer
end
def check_length length
length > 0
end
def fail
'Argument must be integer and greater than 0. Recommend max length available by application. 64 if unknown'
end
def known_args
known_args_array = ['s', 'S', 'b', 'B' ]
known_args_array
end
def exit_script
Kernel.exit(false)
end
end

Look closely at the error message:
undefined method `known_args' for PasswordGenerator:Class (NoMethodError)
That message is saying that Ruby can't find a known_args method in PasswordGenerator, not in an instance of PasswordGenerator.
Saying include Validations adds known_args from Validations as an instance method but you're trying to call it as a class method.
You can either set up a Validations.included method to add known_args the includer when include Validations happens or, better IMO, move all your code into an instance method:
class PasswordGenerator
#...
def perform
length = ARGV[0].to_i
#use_special_argument = ARGV[1]
unless known_args.include? #use_special_argument
puts
puts "Specify whether or not to use special characters."
puts "Use special characters: 's' || 'S'"
puts "No special characters: 'b' || 'B'"
puts
puts "Unknown argument: '#{#use_special_argument}'. Aborting"
exit_script
end
puts
puts "Username: " + username_generator
puts "Password: " + argument_check(length)
puts
puts "Complete. Exiting"
exit_script
end
end
and then say:
PasswordGenerator.new.perform
to crank things up.

Related

Ruby Word Guessing Game

I am new to Ruby and working with this hangman style word guessing game. I have 2 main issues. Here is what I am working with now:
class Word_game
def initialize(word)
#word = word.downcase
#display_word = "_ " * word.length
end
def guess_the_word(word_guess)
word_guess.downcase
#word.split("").each_with_index do |word_letter, index|
if word_guess == word_letter
#display_word[index] = word_guess
p #display_word
puts "You're getting somewhere! Keep trying!"
end
end
if !#word.include? (word_guess)
puts "Nope, guess again..."
end
def win?
if #word == #display_word
puts "Congratulations you won!!! You are the word master!!!"
true
else
false
end
end
def lose?
if #attempts == 0
puts "You lose!!"
true
end
end
puts "Welcome to the Word Guessing Game! Let's see if YOU have what it TAKES!!!"
puts "This is a 2 player game. "
puts "Player 1... please enter a word for Player 2 to guess!"
puts ">>"
game_word = gets.chomp
game = Word_game.new(game_word)
attempts = 0
guessed_letters = []
until #attempts == game_word.length
puts "Ok Player 2, Guess a letter! GO!!!"
letter_guess = gets.chomp
if guessed_letters.include? letter_guess
puts "You already guessed that letter! Enter a new one."
letter_guess = gets.chomp
end
guessed_letters << letter_guess
game.guess_the_word(letter_guess)
if game.win?
attempts += 1
else game.lose?
end
end
end
First, the word progress should look like this if the word is hello:
h _ e _ _ o
Instead of this, the spaces are not in the right places and looks like this (an actual outcome of running my code):
.
Ok Player 2, Guess a letter! GO!!!
h
"h _ _ _ _ "
You're getting somewhere! Keep trying!
Ok Player 2, Guess a letter! GO!!!
o
"h _ o _ _ "
You're getting somewhere! Keep trying!
Ok Player 2, Guess a letter! GO!!!
e
"he_ o _ _ "
You're getting somewhere! Keep trying!
Ok Player 2, Guess a letter! GO!!!
l
"hel o _ _ "
You're getting somewhere! Keep trying!
"hello _ _ "
When the user guesses the word, it does not put my "congrats" statement and end the game.
I am also stuck on my 'lose' method. I am not sure how to fix the method so that the game ends when the user runs out of attempts and prints the "lose" statement.
Thanks for your help!
I think you're making the output too complicated. I would track the word and the guesses in an array. Instead of a display_word variable, I'd make it a method, possibly "to_s"
By the way, Ruby convention is to use CamelCase class names.
class WordGame
def initialize(word)
#word = word.downcase.chars
#guesses = ["_"] * #word.size
end
def to_s
#guesses.join " "
end
This should fix your spacing problem. This will also simplify guesses.
Also, the checking to see if you've already used the letter should probably be handled by the WordGame class.
For your first problem, your #display_word starts as follows:
[0] = '_' # For h
[1] = ' '
[2] = '_' # For e
[3] = ' '
...
When you guess 'e', for instance, you do:
#display_word[index] = word_guess
Where index equals 1, the second character in "hello", so as you can see it doesn't write to the 'e' index in #display_word.
For your second problem, there are a number of ways to fix it. For instance, I would do something like using #attempts_remaining starting from a value of 10 or so, then using the existing code:
if !#word.include? (word_guess)
#attempts_remaining -= 1 # Count failure to guess
puts "Nope, guess again..."
end
Then:
def win?
# If you've guessed all the letters, there's no '_' left in the display word
if !#display_word.include? ('_')
puts "Congratulations you won!!! You are the word master!!!"
true
else
false
end
end
def lose?
if #attempts_remaining == 0
puts "You lose!!"
true
end
end
Finally, tweak the until loop termination condition:
until game.win? or game.lose?
The existing calls to win? and lose? can be deleted.
(WORD MISSING GAME)
puts " "
puts "Total Round"
puts " "
puts "=> [Round-One ,Round-two,Round -three Round-four]"
puts " "
puts "=> [TOTAL 5 Tries]"
puts " "
one=""
two=""
three=""
four=""
puts " "
puts " --ROUND One press-- => (1)"
one=gets.to_i
puts '==================='
puts "Question:=> ( K ? N G )"
puts ""
c=5
5.times do
string1 = 'i'
stringone ="I"
puts "Answer:=> Try NO:#{c}"
string2 = gets.chomp
if (string1==string2)
puts "Good Work correct spaling"
break
elsif (stringone == string2 )
puts "Good Work correct spaling"
break
else
puts "-Worng spaling-"
end
c -=1
end
puts " Round Over "
if c<1
puts " Tries Over Game End "
exit
end
puts '==================='
puts "--ROUND Two press-- => (2)"
two=gets.to_i
puts '==================='
puts "Question:=> (P L ? Y )"
5.times do
string1 = 'a'
stringone = "A"
puts "Answer:=> Try NO:#{c}"
string2 = gets.chomp
if (string1==string2)
puts "Good Work correct spaling"
break
elsif (stringone==string2)
puts "Good Work correct spaling"
break
else
puts "-Worng spaling-"
end
c -=1
if c<1
puts " Tries Over Game End "
exit
end
end
puts " Round Over "
puts '==================='
puts "--ROUND Three press-- => (3)"
three=gets.to_i
puts '==================='
puts "Question:=> ( S P ? T )"
5.times do
string1 = 'o'
stringone= 'O'
puts "Answer:=> Try NO:#{c}*"
string2 = gets.chomp
if (string1==string2)
puts "_Good Work correct spaling_"
break
elsif (stringone == string2)
puts "_Good Work correct spaling_"
break
else
puts "-Worng spaling-"
end
c -=1
if c<1
puts " *Tries Over Game End* "
exit
end
end
puts " *Round Over* "
puts '==================='
puts "--ROUND Four press-- => (4)"
four=gets.to_i
puts '==================='
puts "Question:=> ( G ? M E )"
5.times do
string1 = 'a'
stringone = "A"
puts "Answer:=> Try NO:#{c}*"
string2 = gets.chomp
if (string1==string2)
puts "_Good Work correct spaling_"
break
elsif (stringone == string2)
puts "_Good Work correct spaling_"
break
else
puts "-Worng spaling-"
end
c -=1
if c<1
puts " *Tries Over Game End* "
exit
end
end
puts "**Yahoo Congragualtion complete All Round**"

How to add underscores and remove them when the user inputs the correct letter?

I'm having difficulty in adding underscores in my program. Also what is troubling me is that I can't seem to figure out how to remove the underscores when the user inputs the correct letter.
class Game
attr_reader :guess_count, :is_over, :word_length
def initialize (secret_word)
#secret_word = secret_word
#guess_count = 0
#is_over = false
#word_length = secret_word.length
end
def check_word(guess)
#guess_count += 1
if #secret_word == guess
puts "Congratulations!"
#is_over = true
else
#is_over = false
puts "Sorry, try again!"
end
end
def subtract_guess_count
counter = #word_length - #guess_count
end
end
puts "User 1, What is your secret word?"
secret_word = gets.chomp
anything = Game.new(secret_word)
while !anything.is_over
puts "User 2, Guess the secret word"
guess = gets.chomp
anything.check_word(guess)
if anything.subtract_guess_count == 0
puts "You lose! the correct word was #{secret_word}"
exit!
end
if anything.is_over == false
puts "You have #{anything.subtract_guess_count} left!"
end
end
Major Edit
To create a string of underscores you can do this:
word = ""
1.upto(#secret_word.length) do
word << "_"
end
To replace a character with an underscore (and vice versa) in a ruby string you can use the syntax:
word[i] = "_"
To print a word with spaces between each letter you can use the following:
array = word.split(//)
array.join(" ")
For your code a check_letter function could be useful:
def check_letter (guess)
if (#secret_word[guess])
for i in 0..((#secret_word.length) -1 )
if #secret_word[i] == guess
#progress[i] = guess
end
end
end
show_progress
check_word(#progress)
end
Working code
#! /usr/bin/env ruby
#
class Game
attr_reader :guess_count, :is_over, :word_length, :progress
def initialize (secret_word)
#secret_word = secret_word
#guess_count = 0
#is_over = false
#word_length = secret_word.length
#progress = ""
1.upto(secret_word.length) do
#progress << "_"
end
end
def check_word(guess)
if #secret_word == guess
puts "Congratulations!"
#is_over = true
else
#is_over = false
puts "Sorry, try again!"
end
end
def check_letter (guess)
if (#secret_word[guess])
for i in 0..((#secret_word.length) -1 )
if #secret_word[i] == guess
#progress[i] = guess
end
end
end
show_progress
check_word(#progress)
end
def show_progress
array = #progress.split(//)
word = ""
array.each do |letter|
word << letter + " "
end
puts word
end
def one_less_guess
#guess_count += 1
end
def subtract_guess_count
counter = #word_length - #guess_count
end
end
puts "User 1, What is your secret word?"
secret_word = gets.chomp
anything = Game.new(secret_word)
while !anything.is_over
puts "User 2, Guess the secret word"
guess = gets.chomp
anything.one_less_guess
if guess.length == 1
anything.check_letter(guess)
else
anything.check_word(guess)
end
if anything.subtract_guess_count == 0
puts "You lose! the correct word was #{secret_word}"
exit!
end
if anything.is_over == false
puts "You have #{anything.subtract_guess_count} left!"
end
end

What distinguishes .new from .new(true)? "Indent" XML document in Test-First-Ruby

I'm working through these problems and am a little stuck on how to finish this out. This is the RSPEC and what's specifically troubling me is the last "it indents" test:
# # Topics
#
# * method_missing
# * blocks
# * strings
# * hashes
require "13_xml_document"
describe XmlDocument do
before do
#xml = XmlDocument.new
end
it "renders an empty tag" do
#xml.hello.should == "<hello/>"
end
it "renders a tag with attributes" do
#xml.hello(:name => 'dolly').should == "<hello name='dolly'/>"
end
it "renders a randomly named tag" do
tag_name = (1..8).map{|i| ('a'..'z').to_a[rand(26)]}.join
#xml.send(tag_name).should == "<#{tag_name}/>"
end
it "renders block with text inside" do
#xml.hello do
"dolly"
end.should == "<hello>dolly</hello>"
end
it "nests one level" do
#xml.hello do
#xml.goodbye
end.should == "<hello><goodbye/></hello>"
end
it "nests several levels" do
xml = XmlDocument.new
xml.hello do
xml.goodbye do
xml.come_back do
xml.ok_fine(:be => "that_way")
end
end
end.should == "<hello><goodbye><come_back><ok_fine be='that_way'/></come_back></goodbye></hello>"
end
it "indents" do
#xml = XmlDocument.new(true)
#xml.hello do
#xml.goodbye do
#xml.come_back do
#xml.ok_fine(:be => "that_way")
end
end
end.should ==
"<hello>\n" +
" <goodbye>\n" +
" <come_back>\n" +
" <ok_fine be='that_way'/>\n" +
" </come_back>\n" +
" </goodbye>\n" +
"</hello>\n"
end
end
I feel like I understand the problem and the solution would be something like
"<#{method}>\n" + " #{yield}" + "</#{method}>\n"
given my code:
class XmlDocument
#use method missing so that arbitrary methods
#can be called and converted to XML
def method_missing(method, hash=nil, &block)
if (hash == nil && block == nil)
"<#{method}/>"
elsif hash.is_a?(Hash)
#renders tag with attributes (from hash)
my_key = nil
my_val = nil
hash.each do |key, value|
my_key = key
my_val = value
end
"<#{method} #{my_key}='#{my_val}'/>"
else
#passes whatever to between tags including nested methods.
"<#{method}>#{yield}</#{method}>"
end
end
end
My problem is I don't know how to distinguish the "it nests several levels" test from the "it indents" test so I can fit it into my "if" statement. The only thing that seems to distinguish them is the the "it indents" test has
#xml = XmlDocument.new(true)
What does it mean to have "true" as an argument of #new? Is it relevant to my problem?
You can pass an argument to the object when it is initialized. In this case, you want the value to default to false. This way, the code for indents only runs when XmlDocument.new(true) is called.
class XmlDocument
def initialize(indent = false)
#indent = indent
end
def method_missing(method, args=nil, &block)
if #indent == true
#run with indents
else
#run without indents
end
end
end

When creating an inventory, how do I keep people from adding a negative number?

I am creating a very simple "Repository" as my first real ruby script. I have the sections created where people can create an item and starting value, but I cannot seem to nail down how to keep people from incrementing (or decrementing) by 0 or negative numbers.
My code to add is as follows:
class Item
attr_accessor :name, :count
def initialize (name,initCount )
#name=name.downcase
#count=initCount
end
def add(amount)
#count += amount
end
def sub(amount)
#count -= amount
end
end
def prompt()
puts #items.inspect
puts " (A)dd item\n (R)emove item\n (L)ist items\n (I)ncrease item\n (D)ecrease items\n (Q)uit "
select = [(print '?: '), gets.rstrip][1]
if (select.upcase=="A") then
puts "Add Item\nItem name"
name=[(print 'Name? : '), gets.rstrip][1]
puts "Initial Count"
count= [(print 'Count? : '), gets.rstrip][1]
#items.push(Item.new(name,count.to_i)) unless #items.index(#items.find { |l| l.name == name })
end
Any help is appreciated.
Consider organizing your code like this. I may have made a few errors, but you'll get the idea.
PROMPT_TEXT =
" (A)dd item
(R)emove item
(L)ist items
(I)ncrease items
(D)ecrease items
(Q)uit ?: "
ILLEGAL_PROMPT_RESPONSE_MSG =
"You can't enter that! What were you thinking??"
NEGATIVE_NUMBER_MSG =
"If I've told you once, I've told you a thousand times: NO NEGATIVE NUMBERS!"
NOT_NUMBER_MSG =
"If that's a number, it must be Roman, and they aren't allowed."
TRY_AGAIN_MSG = "Try again...
.
def prompt()
loop do
puts #items.inspect # What's this?
puts PROMPT_TEXT
gets.rstrip.upcase case
when "A"
break if add_item
when "R"
...
when "L"
...
...
when "Q" then return
else
puts ILLEGAL_PROMPT_RESPONSE_MSG
end
puts TRY_AGAIN_MSG
end
end
.
def add_item
puts "Add Item\nItem name"
print 'Name? : '
name = gets.rstrip
puts "Initial Count"
print 'Count? : '
count = gets.rstrip
unless count =~ /\d+/
if count =~ /-\s*\d+/
puts NEGATIVE_NUMBER_MSG
else
puts NOT_NUMBER_MSG
end
return false
end
#items.push...
true
end
Aside: the statement
name=[(print 'Name? : '), gets.rstrip][1]
brings to mind a word that begins with "abomin" and ends with "ation". :-)
class Item
attr_accessor :name, :count
def initialize (name,initCount )
raise if initCount<0
#name=name.downcase
#count=initCount
end
def add(amount)
raise if amount<0
#count += amount
end
def sub(amount)
raise if amount<0 || amount>#count
#count -= amount
end
end

Help! check_in': undefined method `push' for nil:NilClass (NoMethodError)

Hi Im getting an core error which is really standard I suppose in Ruby but dont know what to make of it. I have a program that I have written. Its purpose is to register guests at a camping. You have a menu with 5 different options. 1. Checkin. When i do this I get a undefined method generateParkingLot' for #<Camping:0x10030a768> (NoMethodError)
When I choose Checkout I get a undefined local variable or methoddeparture' for Menu:Class (NameError).
So please i someone has a clue to my problem it would be great. I will here paste all my code. The code is separated in different files and I have used require for the different files. Here though I will paste all the code in one trace. Thankful for all help.
-Sebastien
require 'guest'
require 'parking_lot'
class Camping
attr_accessor :current_guests, :parking_lots, :all_guests, :staticGuests
def initialize(current_guests, parking_lots, all_guests, staticGuests)
#current_guests = Array.new()
# initiera husvagnsplatserna
#parking_lots = Array.new(32)
32.times do |nr|
#parking_lots[nr] = Parking_Lot.new(nr)
#staticGuests = Array[
Guest.new("Logan Howlett", "Tokyo", "07484822",1, #parking_lots[0]),
Guest.new("Scott Summers", "Chicago", "8908332", 2, #parking_lots[1]),
Guest.new("Hank Moody", "Boston", "908490590", 3, #parking_lots[2]),
Guest.new("Jean Grey", "Detroit", "48058221", 4, #parking_lots[3]),
Guest.new("Charles Xavier","Washington DC", "019204822",5, #parking_lots[4])
]
end
#all_guests = []
#staticGuests.each do |guest|
#current_guests[guest.plot.nr] = guest
#all_guests.push(guest)
end
end
def to_s
# creates an empty string
list = " "
# loop from 1 to 32
(1..32).each do |n|
if (!#current_guests[n-1].nil?)
list += #current_guests[n-1].to_s
else
# else adds the text "Vacant"
list += n.to_s + ": Vacant!\n"
end
return list
end
def generateParkingLot
randomNr = 1+rand(32)
# exists a guest at the (0-based) position?
if (!#current_guests[randomNr-1].nil?)
# if so generate a new figure
generateEmpty(array)
else
# returns the generated number
return randomNr
end
end
end
end
class Guest
attr_accessor :firstname, :lastname, :address, :phone, :departure
attr_reader :arrived, :plot
def initialize (firstName, lastName, address, phone, plot)
#firstName = firstName
#lastName = lastName
#address = address
#phone = phone
#arrived = arrived
#plot = plot
end
def to_s
"Personal information:
(#{#firstName}, #{#lastName}, #{#address}, #{#phone}, #{#arrived}, #{#departure}, #{#plot})"
end
end
require 'ruby_camping'
require 'camping_guests'
class Main
if __FILE__ == $0
$camping = Camping.new(#current_guests, #all_guests, #parking_lots,#staticGuests)
puts "\n"
puts "Welcome to Ruby Camping!"
while (true)
Menu.menu
end
end
end
require 'date'
require 'camping_guests'
require 'guest'
class Menu
def initialize(guests = [])
#camping = Camping.new(guests)
end
def self.menu
puts "---------------------------"
puts " Menu"
puts " 1. Checkin"
puts " 2. Checkout"
puts " 3. List current guests"
puts " 4. List all guests"
puts " 5. Exit\n"
puts ""
puts " What do you want to do?"
puts "---------------------------"
print ": "
action = get_input
do_action(action)
end
# fetches menu choice and returns chosen alternativ
def self.get_input
input = gets.chomp.to_i
while (input > 5 || input < 1) do
puts "Ooups, please try again."
input = gets.chomp.to_i
end
return input
end
def self.do_action(action)
case action
when 1:
check_in
when 2:
check_out
when 3:
puts $camping.current_guests
when 4:
puts $camping.all_guests
when 5:
puts "You are now leaving the camping, welcome back!"
exit
end
end
def self.check_in
puts "Welcome to the checkin"
puts "Please state your first name: "
firstName = gets.chomp
puts "Please state your last name:"
lastName = gets.chomp
puts "Write your address: "
address = gets.chomp
puts "and your phone number: "
phone = gets.chomp
puts "finally, your arrival date!"
arrived = gets.chomp
newPLot = $camping.generateParkingLot
newGuest = Guest.new(firstName, lastName, address, phone,arrived,$camping.parking_lots[newPLot-1])
$camping.current_guests[newPLot-1] = newGuest
#all_guests.push(newGuest)
puts "The registration was a success!! You have received the " + newPLot.to_s + "."
end
def self.check_out
puts "Welcome to checkout!"
puts $camping.all_guests
puts "State plot of the person to checkout!"
plot = gets.chomp.to_i
puts "Ange utcheckningsdatum: "
departureDate = gets.chomp.to_i
guest = $camping.current_guests[plot-1]
#departure = departure
guest.departure = departureDate
guestStayedDays = departureDate - guest.arrived
guest.plot.increase(guestStayedDays)
puts guest
$camping.current_guests[plot-1] = nil
end
end
class Parking_Lot
attr_accessor :nr
attr_reader :electricity_meter
def initialize (nr)
#nr = nr
#electricity_meter = 4000-rand(2000)
end
def increase_meter(days)
generatedUse = (10+rand(70))*days
puts "Increases the meter with " + generatedUse.to_s + " kWh."
#electricity_meter += generatedUse
end
def to_s
"Plot #{#nr+1} Electricity meter: #{#electricity_meter} kWh"
end
end
It looks (although I haven't tried this out) like some of your your 'end's are wrong.
The one which is causing your first error (generateParkingLot undefined) is that generateParkingLot is actually defined inside to_s, so you need an extra 'end' at the end of your to_s method.
As for the second error (departure not recognised), the folowing line in self.check_out is at fault:
#departure = departure
because there is no 'departure' variable. (Perhaps you meant DepartureDate?). I suspect there may be a few other issues with this code, but I'm afraid I don't really have time to check now.
One I noticed was that when you have
32.times do |nr|
#parking_lots[nr] = Parking_Lot.new(nr)
I think you might want to end that, either with an 'end' or curly brackets, e.g.
32.times do |nr|
#parking_lots[nr] = Parking_Lot.new(nr)
end
Although that would make your other blocks not match.. In general, just try and make sure your blocks are all defined properly (e.g. everything has a matching end).

Resources