Capitalize a final first and last name in my program [closed] - ruby

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I am trying to ask the user for a name so we can create a fake name.
Fake name will:
Swap the first and last name
Change all the vowels (a,e,i,o,u) to next vowel, So 'a' would become 'e','u' would become 'a'
Change all the consonants to (besides the vowels) to the next consonant in the alphabet, So 'd' would become 'f', 'n' would become 'p'
I am unable to get the first and last name capitalized at the end of the program. Any advice on how to do this?
I am also trying to Use a data structure to store the fake names as they are entered. When the user exits the program, iterate through the data structure and print all of the data the user entered. A sentence like "Vussit Gimodoe is actually Felicia Torres" or "Felicia Torres is also known as Vussit Gimodoe
# ---- Swap First and Last Name ----
def name_swap(name)
name.split.reverse.join(' ')
end
# ---- Change all the vowels ----
def vowel_change(name)
vowels = ['a', 'e', 'i', 'o', 'u']
name = name.downcase.split('')
new_name = name.map do |vow|
if vowels.include?(vow)
vowels.rotate(1)[vowels.index(vow)]
elsif vowels == 'u'
vowels.replace('a')
else
vow
end
end
new_name.join
end
# ---- Change the constant ----
def constant_change(name)
constants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z']
name = name.downcase.split('')
new_name = name.map do |letter|
if constants.include?(letter)
constants.rotate(1)[constants.index(letter)]
elsif constants == 'z'
constants.replace('b')
else
letter
end
end
new_name.join.capitalize!
end
# ---- User Interface and Data Storage----
valid_input = false
agents ={}
user_input = ""
secret_name = ""
until valid_input
puts "Hello Secret Agent, to begin please enter the name you would like to change. When you are finished, type 'quit' !"
user_input = gets.chomp.downcase
if user_input == "quit"
puts "Thank You!"
valid_input = true
else
secret_name = name_swap(vowel_change(constant_change(user_input)))
puts "Your secret name is #{secret_name} "
end
agents[user_input] = secret_name
end
agents.each do |name, scramble|
puts"#{name} is also known #{scramble}"
end
The problem is when I return the final agent name the name is lower case and I need both the first name and last name capitalized. It is also taking quit to exit the until loop as a name.

Have a look at this: https://ruby-doc.org/core-2.2.0/String.html#method-i-capitalize-21
You could do this before you print the secret name:
output = output.split.each { |name| name.capitalize! }.join(' ')
and the same for the original name:
original_name = original_name.split.each { |name| name.capitalize! }.join(' ')
Examples from Ruby docs:
a = "hello"
a.capitalize! #=> "Hello"
a #=> "Hello"
a.capitalize! #=> nil
Or use Rails' titleize method if you are using Rails.
http://apidock.com/rails/String/titleize

In rails, you have a method called titleize
that said, give this a try
output = name_swap(vowel_change(constant_change(original_name))).titleize
original_name = original_name.titleize
Reference Answer: https://stackoverflow.com/a/15005638/2398387

Related

How to call a method from an another method with ruby?

I have this little password generating program, I want the method print_password to call the generate_password method, but it just doesn't work
require 'digest'
class Challenge
KEY = [
'4', '5', '6', '7',
'8', '9', 'A', 'B',
'C', 'D', 'E', 'F',
'0', '1', '2', '3'
]
def initialize(email)
#email = email # && raise
puts 'This object was initialized!'
end
def print_password
puts %(Password 1: {generate_password}) # Here I want to call generate_password method
end
private
def generate_password
#hash = Digest::SHA1.hexdigest(#email)
#id = #hash.scan(/\d+/).map(&:to_i).inject(:+)
#prng = Random.new(#id)
prepare_map
apply_map
end
def prepare_map
#map = []
id_string = #id.to_s
id_size = id_string.size
map_string = id_string * (KEY.size.to_f / id_size).ceil
0.upto(15) do |i|
#map[i] = map_string[i].to_i
end
#map
end
end
def apply_map
calculated_key = KEY.shuffle(random: #prng).map.with_index do |char, i|
(char.bytes[0] + #map[i]).chr
end
calculated_key.join
end
me = Challenge.new('me#gmail.com') # Initialize new object
me.print_password # Here I want to print the password
So here at the end, it initializes a new object and then where I use me.print_password it just prints out Password 1: {generate_password}
Don't know exactly what I am doing wrong here, thanks for your help in advance.
You need to use a hash character before your curly brackets (same notation as for double quotes):
puts %(Password: #{generate_password})
puts "Password: #{generate_password}"

Conditional statement not triggered

I wrote a piece of code that creates a random string based on an input. The user decides its length and whether it should contain numbers and special characters. I added a fail-safe routine because the end result is random:
def create
i = #number
while i != 0
# testing the script I have noticed that the if statement is (always) ignored.
if i == 2 && (#word_bank.include?(#special_chars) && #rand_ary.include?(#special_chars) == false)
#rand_ary << #special_chars[rand(0..#special_chars.size - 1)]
end
letter = rand(0..word_bank.size - 1)
#puts "#{i}, #{word_bank[letter]}"
#rand_ary << word_bank[letter]
word_bank.delete_at(letter)
i -= 1
end
#rand_string = #rand_ary.join()
puts #rand_string
#rand_string
end
If the user elects to include a special character, a counter runs from n - 0. When i = 2, and no character from a special character array is included, a random special character is manually included.
But this if-statement is never triggered. I can't figure out why.
If your variables have the kind of values I think they do, it's because include isn't the right method to use here.
If #word_bank and #rand_ary are arrays, include will check if any single element is equal to #special_chars. If #special_chars is itself an array, then it'll only return true if one of the elements in #word_bank/#rand_ary is an array.
['a', 'b', 'c', '!'].include?('!') # => true
['a', 'b', 'c', '!'].include?(['!']) # => false
['a', 'b', 'c', ['!']].include?(['!']) # => true
I think you're actually interested in whether there's any overlap between them. In that case, you can use the intersection (&) operator and check whether it's empty.
['a', 'b', 'c', '!'] & ['!'] # => ['!']
['a', 'b', 'c'] & ['!'] # => []

.start_with? method not recognizing substring 'a'

I want to translate a string into pig latin. The rules are as following:
Valid words are two or more letters long.
If a word begins with a consonant (a letter other than 'a', 'e', 'i', 'o', or 'u'), then that first letter is shifted to the end of the word.
Then add 'ay'.
I managed to come up with the method:
def translate(word)
if word.size <= 2
word
elsif
word.size > 2
!word.start_with?('a', 'e', 'i', 'o', 'u')
x = word.reverse.chop.reverse
x.insert(-1, word[0])
x << "ay"
else
word << "ay"
end
end
However, my test does not pass for certain strings,
Test Passed: Value == "c"
Test Passed: Value == "pklqfay"
Test Passed: Value == "yykay"
Test Passed: Value == "fqhzcbjay"
Test Passed: Value == "ndnrzzrhgtay"
Test Passed: Value == "dsvjray"
Test Passed: Value == "qnrgdfay"
Test Passed: Value == "npfay"
Test Passed: Value == "ldyuqpewypay"
Test Passed: Value == "arqokudmuxay"
Test Passed: Value == "spvhxay"
Test Passed: Value == "firvmanxay"
Expected: 'aeijezpbay' - Expected: "aeijezpbay", instead got: "eijezpbaay"
Expected: 'etafhuay' - Expected: "etafhuay", instead got: "tafhueay"
These tests passes:
Test.assert_equals(translate("billy"),"illybay","Expected: 'illybay'")
Test.assert_equals(translate("emily"),"emilyay","Expected: 'emilyay'")
I am not sure why.
If the length of word is greather or equal to 2 return word, if not then do the start_with step, but when would your else statement work?
Try modifying your length validation just to less than 2, then check if the word "start_with" a vowel, and return just the word plus ay, and if not the do the first character rotate step then adding the ay part, something like:
def translate(word)
if word.size < 2
word
elsif word.start_with?('a', 'e', 'i', 'o', 'u')
word << "ay"
else
x = word.reverse.chop.reverse
x.insert(-1, word[0])
x << "ay"
end
end
Your code fails because it doesn't really evaluates if the word begins with a constant, you are only checking it but doing nothing about it, its just an isolated line:
!word.start_with?('a', 'e', 'i', 'o', 'u')
Try including that line inside an if condition, like this:
def translate(word)
if word.size <= 2
word
else
if !word.start_with?('a', 'e', 'i', 'o', 'u')
x = word.reverse.chop.reverse
x.insert(-1, word[0])
x << "ay"
else
word << "ay"
end
end
end
Also notice that i removed the if word.size > 2, it is not necessary since you are already checking for word.size <= 2, so anything other than that is > 2.

Stop a loop if a certain character is passed to it Ruby

So I am working on a small assignment to transcribe DNA strands to RNA strands. My current code looks like this:
class Complement
def self.of_dna(str)
dna_rna = { 'G' => 'C', 'C' => 'G', 'T' => 'A', 'A' => 'U' }
rna = []
str.scan(/[GCTA]/).each do |x|
rna << dna_rna[x]
end
rna.join('')
end
end
It works perfectly, except for in one situation. If a DNA strand is passed that is partially correct, for example ACGTXXXCTTAA, my method will translate the DNA to RNA and just leave out the X's, giving me a result of UGCAGAAUU rather than just "". How can I make it so the loop will fail and exit when it receives a letter that isn't DNA related?
EDIT:
The test I am trying to get to pass looks like this:
def test_dna_correctly_handles_partially_invalid_input
# skip
assert_equal '', Complement.of_dna('ACGTXXXCTTAA')
end
I attempted #Holger Just's idea from below, and received this error:
1) Error:
ComplementTest#test_dna_correctly_handles_completely_invalid_input:
ArgumentError: ArgumentError
/Users/LukasBarry/exercism/ruby/rna-transcription/rna_transcription.rb:6:in `block in of_dna'
/Users/LukasBarry/exercism/ruby/rna-transcription/rna_transcription.rb:5:in `each'
/Users/LukasBarry/exercism/ruby/rna-transcription/rna_transcription.rb:5:in `of_dna'
rna_transcription_test.rb:43:in `test_dna_correctly_handles_completely_invalid_input'
The usual failure I've been getting from the above method is this:
1) Failure:
ComplementTest#test_dna_correctly_handles_partially_invalid_input [rna_transcription_test.rb:48]:
Expected: ""
Actual: "UGCAGAAUU"
Any help would be greatly appreciated.
Try this
class Complement
def self.of_dna(str)
return "" if str =~ /[^GCTA]/
...
end
end
Fun fact, you don't even need a loop to replace characters
str = 'GATTACA'
str.tr('ATCG', 'UAGC')
# => 'CUAAUGU'
Is all you need.
You can also match X in your regex and perform some erorr handling if it is found in the string. This could look something like this:
class Complement
def self.of_dna(str)
dna_rna = { 'G' => 'C', 'C' => 'G', 'T' => 'A', 'A' => 'U' }
rna = []
str.scan(/[GCTAX]/).each do |x|
return '' if x == 'X'
rna << dna_rna[x]
end
rna.join('')
end
end
I prefer using Hash#fetch for this because it'll raise a KeyError for you on mismatch, allowing you to write less code that validates inputs (i.e., less defensive programming), which I think is more valuable than cleverness (in which case I would recommend String#tr).
class DNA
TranslationMap = { 'G' => 'C', 'C' => 'G', 'T' => 'A', 'A' => 'U' }
attr_reader :dna
def initialize(dna)
#dna = dna
end
def to_rna
dna.each_char.map do |nucleotide|
TranslationMap.fetch(nucleotide)
end.join('')
rescue KeyError
return false
end
end
Feel free to adapt what happens when the error is rescued to fit your needs. I recommend raising a more specific exception (e.g. DNA::InvalidNucleotide) for the caller to handle.
In use:
dna = DNA.new 'GCTA'
# => #<DNA:0x007fc49e903818 #dna="GCTA">
dna.to_rna
# => "CGAU"
dna = DNA.new 'ACGTXXXCTTAA'
# => #<DNA:0x007fc49f064800 #dna="ACGTXXXCTTAA">
dna.to_rna
# => false

Advancing Vowel to the Next Vowel in Ruby

I'm working on beginner Ruby tutorials. I'm trying to write a method that will advance vowels to the next vowel. 'a' will become 'e', 'e' will become 'i', 'u' will become 'a', etc etc. I've been trying various ideas for quite a while, to no avail.
I think I'm on the right track in that I need to create an array of the vowels, and then use an index to advance them to the next array in the vowel. I just can't seem to create the right method to do so.
I know this isn't workable code, but my outline is along these lines. Where I run into issues is getting my code to recognize each vowel, and advance it to the next vowel:
def vowel_adv(str)
vowels = ["a", "e", "i", "o", "u"]
str = str.split('')
**str_new = str.map do |letter|
if str_new.include?(letter)
str_new = str_new[+1]
end**
# The ** section is what I know I need to find working code with, but keep hitting a wall.
str_new.join
end
Any help would be greatly appreciated.
Because we have only a few vowels, I would first define a hash containing vowel keys and vowel values:
vowels_hash = {
'a' => 'e',
'A' => 'E',
'e' => 'i',
'E' => 'I',
'i' => 'o',
'I' => 'O',
'o' => 'u',
'O' => 'U',
'u' => 'a',
'U' => 'A'
}
Then I would iterate over the alphabets present in each word / sentence like so:
word.split(//).map do |character|
vowels_hash[character] || character
end.join
Update:
BTW instead of splitting the word, you could also use gsub with regex + hash arguments like so:
word.gsub(/[aeiouAEIOU]/, vowels_hash)
Or like so if you want to be Mr. / Ms. Fancy Pants:
regex = /[#{vowels_hash.keys.join}]/
word.gsub(regex, vowels_hash)
Here's your code with the fewest corrections necessary to make it work:
def vowel_adv(str)
vowels = ["a", "e", "i", "o", "u"]
str = str.split('')
str_new = str.map do |char|
if vowels.include?(char)
vowels.rotate(1)[vowels.index(char)]
else
char
end
end
str_new.join
end
vowel_adv "aeiou"
=> "eioua"
Things that I changed include
addition of a block variable to the map block
returning the thing you're mapping to from the map block
include? is called on the Array, not on the possible element
finding the next vowel by looking in the array of vowels, not by incrementing the character, which is what I think you were trying to do.
Here's an improved version:
VOWELS = %w(a e i o u)
ROTATED_VOWELS = VOWELS.rotate 1
def vowel_adv(str)
str.
chars.
map do |char|
index = VOWELS.index char
if index
ROTATED_VOWELS[index]
else
char
end
end.
join
end
static Arrays in constants
nicer array-of-string syntax
String#chars instead of split
use the index to test for inclusion instead of include?
no assignment to parameters, which is a little confusing
no temporary variables, which some people like and some people don't but I've done here to show that it's possible
And, just because Ruby is fun, here's a different version which copies the string and modifies the copy:
VOWELS = %w(a e i o u)
ROTATED_VOWELS = VOWELS.rotate 1
def vowel_adv(str)
new_str = str.dup
new_str.each_char.with_index do |char, i|
index = VOWELS.index char
if index
new_str[i] = ROTATED_VOWELS[index]
end
end
new_str
end
The string class has a nice method for this. Demo:
p "Oh, just a test".tr("aeiouAEIOU", "uaeioUAEIO") # => "Ih, jost u tast"
To riff of of steenslag's answer a little.
VOWELS = %w{a e i o u A E I O U}
SHIFTED_VOWELS = VOWELS.rotate 1
def vowel_shifter input_string
input_string.tr!(VOWELS.join, SHIFTED_VOWELS.join)
end
and just for fun, consonants:
CONSONANTS = ('a'..'z').to_a + ('A'..'Z').to_a - VOWELS
SHIFTED_CONSONANTS = CONSONANTS.rotate 1
def consonant_shifter input_string
input_string.tr!(CONSONANTS.join, SHIFTED_CONSONANTS.join)
end

Resources