Creating A Caesar Cipher in Ruby, getting an error - ruby

I am attempting to create a Caesar Cipher in Ruby for my computer science class. My friend was able to create part of the code:
def cipher(word, n)
new_word = ""
word.each_char do |i|
n.times do
if(i == "z")
i = "a"
next
elsif(i == "Z")
i = "A"
next
end
i.next!
i == "%" ? i = " " : ""
end
new_word += i
end
puts new_word
end
cipher("phrase", 5)
Where the last line is where you would put the phrase you want to scramble, and the number is how much you want to scramble it by. One of the requirements is that we use gets.chomp to specify a phrase and amount to scramble by without editing the .rb file itself. So I came up with this:
puts "What would you like to scramble?"
word = gets.chomp
puts "How much would you like to scramble that?"
n = gets.chomp
def cipher(word, n)
new_word = ""
word.each_char do |i|
n.times do
if(i == "z")
i = "a"
next
elsif(i == "Z")
i = "A"
next
end
i.next!
i == "%" ? i = " " : ""
end
new_word += i
end
puts new_word
end
cipher(word, n)
And I get the following error outputed when run in Terminal:
some.rb:10:in `block in cipher': undefined method `times' for "5":String (NoMethodError)
from some.rb:9:in `each_char'
from some.rb:9:in `cipher'
from some.rb:26:in `<main>'
If someone could help me figure out what I'm doing wrong, that would help me out a lot.

gets.chomp returns a string
word = gets.chomp
So word is a string, as expected, but then you call gets.chomp again, this time to get number of scrabbles that should be applied to the string. So n is a string as well.
n = gets.chomp
When you call the times method on n it's not defined, because it only makes sense on integers. The solution is to convert n to an integer. This should work:
n = gets.chomp.to_i
Update
Documentation on the to_i method on String instances: http://ruby-doc.org/core-2.0.0/String.html#method-i-to_i

Call .to_i on n.
You need to convert that string you got from the user's input into a number before you can run .times on it. .to_i does this for you.
Example:
http://progzoo.net/wiki/Ruby:Convert_a_String_to_a_Number

Did this a while ago, the requirements were only lowercase ASCII alphabet letters, hope you get the general idea to do it your way:
def encrypt(msg, key)
msg.downcase.split("").each_with_index do |char, i|
next if msg[i] == " "
msg[i] = (msg[i].ord + key) > 122 ? (((msg[i].ord + key) % 123) + 97).chr : (msg[i].ord + key).chr
end
msg
end
def decrypt(msg, key)
msg.downcase.split("").each_with_index do |char, i|
next if msg[i] == " "
msg[i] = (msg[i].ord - key) < 97 ? (123 - (97 - (msg[i].ord - key))).chr : (msg[i].ord - key).chr
end
msg
end

gets.chomp return a string, you must convert it to a number in order to call .times method. Change this line n = gets.chomp by n = gets.chomp.to_i

Related

How to preserve case of characters when using Caesar Cipher

I have a Caesar Cipher script in Ruby that is working but it returns the string as all upper-case letters instead of preserving the cases of the original string.
I could use capitalize to make it look good enough but I would like a more concrete way of preserving the cases.
Here is the script:
BASE_ORD = 'A'.ord
def caesar_cipher(phrase, key)
cipher = phrase.gsub(/[a-z]/i) do |c|
orig_pos = c.upcase.ord - BASE_ORD
new_pos = (orig_pos + key) % 26
(new_pos + BASE_ORD).chr
end
puts cipher
end
caesar_cipher("What a string!", 5)
Any help or insight would be appreciated.
The simplest solution, given your existing code, is to check whether the character is uppercase or lowercase and set base_ord accordingly. Since the lowercase letters come after the uppercase letters in UTF-8 (as in ASCII), we can just test letter >= 'a', e.g.:
base_ord = (letter >= 'a' ? 'a' : 'A').ord
Here's the whole method with this change (you no longer need the BASE_ORD constant):
def caesar_cipher(phrase, key)
phrase.gsub(/[a-z]/i) do |letter|
base_ord = (letter >= 'a' ? 'a' : 'A').ord
orig_pos = letter.ord - base_ord
new_pos = (orig_pos + key) % 26
(new_pos + base_ord).chr
end
end
puts caesar_cipher("What a string!", 5) # => Bmfy f xywnsl!
Edit
Amadan makes a good point about using String#tr. Here's a somewhat more concise implementation:
ALPHABET = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
# Or if you want to be fancy: ALPHABET = (?a..?z).flat_map {|c| [ c, c.upcase ] }.join
def caesar_cipher(phrase, key)
to_alphabet = ALPHABET.dup
to_alphabet << to_alphabet.slice!(0, key * 2)
phrase.tr(ALPHABET, to_alphabet)
end
puts caesar_cipher("What a string!", 5) # => Bmfy f xywnsl!
As said in comments, tr is easier to use for Caesar Cypher (once you prepare the two alphabets), and should also be much faster:
class CaesarCypher
def initialize(key, alphabet=nil)
#from_alphabet = alphabet || (?a..?z).to_a.join
#to_alphabet = #from_alphabet[key..-1] + #from_alphabet[0...key]
#from_alphabet += #from_alphabet.upcase
#to_alphabet += #to_alphabet.upcase
end
def encode(str)
str.tr(#from_alphabet, #to_alphabet)
end
def encode!(str)
str.tr!(#from_alphabet, #to_alphabet)
end
def decode(str)
str.tr(#to_alphabet, #from_alphabet)
end
def decode(str)
str.tr!(#to_alphabet, #from_alphabet)
end
end
cc = CaesarCypher.new(1)
puts cc.encode("Caesar, huh?")
puts cc.decode("Dbftbs, ivi?")

puts statement is printing on two lines

I have a class called PolynomialElements and inside that class I have a method called printElement that has a puts statement that print two variables. The puts statement is printing the variables on different lines. How do I get puts to print the two variables on one line. My code is below, it is line #5 where the puts statement is.
class PolynomialElements
attr_accessor :element, :size
def printElement
puts "#{element}x^#{size}"
end
end
askAgain = true
polyArray = Array.new
while askAgain
puts "How many numbers do you want to enter? "
numString = gets
num = numString.to_i
while num > 0
puts "Enter a value for the Polynomial "
value = gets
polyArray.push(value)
num -= 1
end
sizeOfArray = polyArray.length
polyArray.each do |x|
var = PolynomialElements.new
var.element = x
sizeOfArray -= 1
var.size = sizeOfArray
var.printElement
end
puts "Enter y to enter new number or anything else to quit"
cont = gets
if cont.chomp != "y"
askAgain = false
else
polyArray.clear
end
end
In the while loop change:
value = gets
to:
value = gets.chomp
You will then get:
Enter a value for the Polynomial
3
1x^2
2x^1
3x^0

Programming a basic calculator in Ruby

This is my first foray into computer programming. I have chosen to learn Ruby, and I am enjoying it quite a bit. However, I am a little confused as to why the answer will not output properly in this bit of code.
def addition_function
puts "Which numbers would you like to add?"
#n1 = gets.chomp
#n2 = gets.chomp
#n1 + #n2 == #answer
puts "The sum is... #{#answer}"
end
def subtraction_function
puts "Which numbers would you like to subtract?"
#n1 = gets.chomp.to_i
#n2 = gets.chomp.to_i
#n1 - #n2 == #answer
puts "The answer is... #{#answer}"
end
def multiplication_function
puts "Which numbers would you like to multiply?"
#n1 = gets.chomp
#n2 = gets.chomp
#n1 * #n2 == #answer
puts "The answer is... #{#answer}"
end
puts "Would you like to [add], [multiply], or [subtract]?"
response = gets.chomp
if response == "add" then
addition_function
end
if response == "subtract" then
subtraction_function
end
if response == "multiply" then
multiplication_function
end
I know this is probably horrible code... but could someone help steer me in the right direction?
Consider this code:
def get_int_values
[gets, gets].map{ |s| s.chomp.to_i }
end
puts "Would you like to [add], [multiply], or [subtract]?"
response = gets.chomp
case response.downcase
when 'add'
puts "Which numbers would you like to add?"
operator = :+
when 'subtract'
puts "Which numbers would you like to subtract?"
operator = :-
when 'multiply'
puts "Which numbers would you like to multiply?"
operator = :*
end
answer = get_int_values.inject(operator)
puts "The answer is... #{ answer }"
The idea is to follow the "DRY" principle: "DRY" means "Don't Repeat Yourself", which the vast majority of the time, is a really good thing.
To help avoid typing mistakes I'd recommend doing something like:
puts "Would you like to [a]dd, [m]ultiply, or [s]ubtract?"
response = gets.chomp
case response[0].downcase
then change the when clauses to match the first letter of the desired operation.
Which will work unless response is empty. You can figure out how to handle that.
another way to obtain answer, once operator is determined, is answer = gets.to_i.send(operator, gets.to_i)
That's true, but here's why I refactored the code the way I did: If, for some reason, there was a need to operate on more than two values, only one thing has to be changed:
[gets, gets].map{ |s| s.chomp.to_i }
could become:
[gets, gets, gets].map{ |s| s.chomp.to_i }
Or, better, could be transformed to something like:
def get_int_values(n)
n.times.map { gets.chomp.to_i }
end
Nothing else will have to change except to find out how many values are needed.
Now, to do it all right would require different text to alert the user that multiple values are expected, but that's easily done by letting letting the user say how many they want to enter, and then prompting for each gets:
def get_int_values(n)
n.times.map.with_index { |n|
print "Enter value ##{ 1 + n }: "
gets.chomp.to_i
}
end
puts "Would you like to [add], [multiply], or [subtract]?"
response = gets.chomp
puts "How many values?"
num_of_values = gets.to_i
case response.downcase
when 'add'
puts "Which numbers would you like to add?"
operator = :+
when 'subtract'
puts "Which numbers would you like to subtract?"
operator = :-
when 'multiply'
puts "Which numbers would you like to multiply?"
operator = :*
end
answer = get_int_values(num_of_values).inject(operator)
puts "The answer is... #{ answer }"
inject can scale up easily because it doesn't presuppose knowledge about the number of values being operated on.
I think with_index in n.times.map.with_index is an artifact you forgot to delete.
It was deliberate but I like this better:
def get_int_values(n)
1.upto(n).map { |n|
print "Enter value ##{ n }: "
gets.chomp.to_i
}
end
Your assignments are on the wrong side of the statement. You should have answer = n1 * n2,
which is not the same as answer == n1 * n2 (this is a check for equality, using ==). The expression always goes on the right, and the variable the result is assigned to goes on the left -- this is pretty much universal, but not necessarily intuitive coming from algebra.
Also: using an # prior to a variable name differentiates it as an instance variable, or member, of a class. From what you've shown here you don't need to include those, just normally scoped variables are required for this use.
Check out this question for more on that part.
The "#" sigil is used to indicate a class instance variable, you have no class so don't use it.
#n1 + #n2 == #answer
Is a boolean expression evaluating whether #n1 + #n2 is equal to #answer.
It will evaluate to true or false.... but you don't make use of the answer.
What you want is ...
answer = n1 + n2
I strongly recommend you always run Ruby with the -w option. It will save you much much heartache.
Please indent your "end"'s to match your "def" (or "if").
You repeat n1 = gets.chomp.to_i all over the place, do it once and pass the answers as a parameter...
response = gets.chomp
n1 = gets.chomp.to_i
n2 = gets.chomp.to_i
if response == "add" then
addition_function( n1, n2)
elsif...
A few suggestions not mentioned by others:
Shorten your method (not "function") names and use verbs (e.g., add instead of addition_method).
As well as using local variables rather than instance variables (mentioned by others), eliminate them where you can. For example, you could simplify
.
def add
puts "Which numbers would you like to add?"
n1 = gets.to_i
n2 = gets.to_i
answer = n1 + n2
puts "The sum is... #{answer}"
end
to
def add
puts "Which numbers would you like to add?"
puts "The sum is... #{gets.to_i + gets.to_i}"
end
Notice I've used the Ruby convention of indenting two spaces.
You don't need chomp here (though it does no harm), because "123followed by \n or any other non-digits".to_i => 123.
A case statement would work well at the end (and let's loop until the user chooses to quit):
.
loop do
puts "Would you like to [add], [multiply], [subtract] or [quit]?"
case gets.chomp
when "add"
add
when "subtract"
subtract
when "multiply"
multiply
when "quit"
break
end
or just
def quit() break end
loop do
puts "Would you like to [add], [multiply], [subtract] or [quit]?"
send(gets.chomp)
end
Here we do need chomp. You could replace loop do with while true do or use other equivalent constructs.
class Calculator
def Calc
puts"==well come to mobiloitte calculator=="
puts "enter the first operand:"
#op1 = gets.chomp
return if #op1=="q"
#o1=#op1.to_i
puts "entre the second operand:"
#op2 = gets.chomp
return if #op2=="q"
#o2=#op2.to_i
strong text puts "enter any one operator of your choice (add,sub,mul,div,mod)"
operator = gets.chomp
case operator
when 'add' then #s=#o1+#o2 ; puts "\n ##o1 + ##o2 =##s"
when 'sub' then #t=#o1-#o2 ; puts "\n ##o1 - ##o2 =##t"
when 'mul' then #l=#o1*#o2 ; puts "\n ##o1 * ##o2 =##l"
when 'div' then #r=#o1/#o2 ; puts "\n ##o1 \ ##o2 =##r"
when 'md' then #d=#o1%#o2 ; puts "\n ##o1 % ##o2 =##d"
else
puts"invalide input"
end
end
end
obj= Calculator.new
$f=obj.Calc
You are using #n1 + #n2 == #answer to try and set the answer. What you want to do is #answer = #n1 + #n2.
= is assignment, == is a comparison operator.
Also, you will need to #n1 = gets.chomp.to_i. This will convert your input to an integer from a string. Do that with #n2 as well.
You also do not need to use the # before each of your variables. That should only be used when you are dealing with classes, which you do not appear to be doing.
print "enter number 1 : "
n1 = gets.chomp.to_f
print "enter number 2 : "
n2 = gets.chomp.to_f
print "enter operator: "
op = gets.chomp
if op == '+'
puts "#{n1} + #{n2} = #{n1 + n2}"
elsif op == '-'
puts "#{n1} - #{n2} = #{n1 - n2}"
elsif op == '*'
puts "#{n1} * #{n2} = #{n1 * n2}"
elsif op == '/'
puts "#{n1} / #{n2} = #{n1 / n2}"
end
puts "Would you like to
0 ---- [exit],
1 ---- [add],
2 ---- [subtract],
3 ---- [multiply],
4 ---- [divide]"
response = gets.chomp
case response.downcase
when '1'
def addition_function
puts "Which numbers would you like to add?"
n1 = gets.to_i
n2 = gets.to_i
answer = n1 + n2
puts "The sum is... #{n1} + #{n2} = #{answer}"
end
addition_function()
#Subtract
when '2'
def subtraction_function
puts "Which numbers would you like to subtact?"
n1 = gets.to_i
n2 = gets.to_i
answer = n1 - n2
puts "The subtraction is... #{n1} - #{n2} = #{answer}"
end
subtraction_function()
#Multiply
when '3'
def multiplication_function
puts "Which numbers would you like to multiply?"
n1 = gets.to_i
n2 = gets.to_i
answer = n1 * n2
puts "The multiplication is... #{n1} * #{n2} = #{answer}"
end
multiplication_function()
#Division
when '4'
def division_function
puts "Which numbers would you like to divide?"
n1 = gets.to_i
n2 = gets.to_i
answer = n1 / n2
puts "The division is... #{n1} / #{n2} = #{answer}"
end
division_function()
else '0'
puts "Exit! Thank You for using us!"
end
#ruby script to do the calculator
puts " enter the number1"
in1=gets.to_i
puts " enter the number2"
in2=gets.to_i
puts "enter the operator"
op=gets.chomp
case op
when '+'
plus=in1+in2
puts "#{in1+in2}"
#puts "#{plus}"
when '-'
min=in1-in2
puts "#{min}"
when '*'
mul= in1*in2
puts "#{mul}"
when '/'
div=in1/in2
puts "#{div}"
else
puts "invalid operator"
end
begin
puts 'First number:'
a = $stdin.gets.chomp.to_i
puts 'Second number:'
b = $stdin.gets.chomp.to_i
operation = nil
unless ['+', '-', '*', '/', '**'].include?(operation)
puts 'Choose operation: (+ - * /):'
operation = $stdin.gets.chomp
end
result = nil
success = false
case operation
when '+'
result = (a + b).to_s
when '-'
result = (a - b).to_s
when '*'
result = (a * b).to_s
when '/'
result = (a / b).to_s
when '**'
result = (a**b).to_s
else
puts 'There is not such kind of operation'
end
success = true
puts "Результат: #{result}"
rescue ZeroDivisionError => e
puts "You tried to devide number by zero! Error: #{e.message}"
end
if success
puts "\nSuccess!"
else
puts "\nSomething goes wrong :("
end
puts ("plz enter a number :")
num1 = gets.chomp.to_f
puts ("plz enter a another number")
num2 = gets.chomp.to_f
puts ("plz enter the operation + , - , x , / ")
opp = gets.chomp
if opp == "+"
puts (num1 + num2)
elsif opp == "-"
puts (num1 - num2)
elsif opp == "x"
puts (num1 * num2)
elsif opp == "/"
puts (num1 / num2)
else puts ("try again :|")
end

Ruby Pig Latin Multiple Arguments

Hi I'm trying to write code for to convert strings to pig latin
def translate(str)
alpha = ('a'..'z').to_a
vowels = %w[a e i o u]
consonants = alpha - vowels
if vowels.include?(str[0])
str + 'ay'
elsif str[0..1] == 'qu'
str[2..-1]+'quay'
elsif consonants.include?(str[0]) && str[1..2]=='qu'
str[3..-1]+str[0..2]+'ay'
elsif consonants.include?(str[0]) && consonants.include?(str[1]) && consonants.include?(str[2])
str[3..-1] + str[0..2] + 'ay'
elsif consonants.include?(str[0]) && consonants.include?(str[1])
str[2..-1] + str[0..1] + 'ay'
elsif consonants.include?(str[0])
str[1..-1] + str[0] + 'ay'
elsif str[0..1] == 'qu'
str[2..-1]+'quay'
else
return str
end
end
This code works perfect for converting one word strings, for example: translate("monkey").
What i'm trying to do is make it possible for this code to accept multiple words as well (within the same string)...following the above criteria for converting into pig latin, example:
translate("please help") => "easeplay elphay"
thanks much!
Since you already know how to translate a single word why not just split up the task into two methods:
def translate(str)
str.split.map { |word| translate_word(word) }.join
end
def translate_word(str)
# Your old translate code here
end
What I would do for this is:
use the #split method to make your str variable into an array of words (or 1 word if its only 1 word).
afterwards you can use the array#each method to iterate through each array index.
i.e.
str = "hello"
str = str.split(" ") # str now equals ["hello"]
for multiple variables:
str = "hello world"
str- str.split(" ") #now equals ["hello", "world"]
then you can use the .each method:
str.each do |<variable name you want to use>|
<how you want to manipulate the array>
end
for the pig latin program you could do:
str.each do|element|
if vowels.include?(element)
<do whatever you want here>
elsif
<do whatever>
else
<do whatver>
end
end
this will iterate through each element in the array and translate it (if there is only one element it will still work)

How to generate xml_builder ruby code from an XML file

I've got an xml file. How could I generate xml_builder ruby code out of that file?
Notice - I'm sort of going backwards here (instead of generating xml, I'm generating ruby code).
Pretty formatting isn't a big deal - I can always run it through a formatter later.
It's sort of impossible, not unlike if you asked "how to generate Ruby script that outputs number 3", for the answer could be:
puts 3
or
puts 2+1
or
puts [1,2,3].count
etc.
So, one answer to your question would be:
xml = File.read('your.xml')
puts "puts <<EOF\n#{xml}\nEOF"
Anyway, if you would just want to generate Builder based script which just generates your XML node-for-node, I guess it would be easiest using XSLT. That's a language constructed exactly for such purposes - transforming XMLs.
Here's what I eventually came up with:
#!/usr/bin/env ruby
require "rexml/document"
filename = ARGV[0]
if filename
f = File.read(filename)
else
raise "Couldn't read file: `#{filename}'"
end
doc = REXML::Document.new(f)
def self.output_hash(attributes={})
count = attributes.size
str = ""
index = 0
attributes.each do |key, value|
if index == 0
str << " "
end
str << "#{key.inspect} => "
str << "#{value.inspect}"
if index + 1 < count
str << ", "
end
index += 1
end
str
end
def self.make_xml_builder(doc, str = "")
doc.each do |element|
if element.respond_to?(:name)
str << "xml.#{element.name}"
str << "#{output_hash(element.attributes)}"
if element.length > 0
str << " do \n"
make_xml_builder(element, str)
str << "end\n"
else
str << "\n"
end
elsif element.class == REXML::Text
string = element.to_s
string.gsub!("\n", "")
string.gsub!("\t", "")
if !string.empty?
str << "xml.text!(#{string.inspect})\n"
end
end
end
str
end
puts make_xml_builder(doc)
After generating that, I then formatted it in Emacs.

Resources