repl.it Ruby interpreter : error when defining multiple functions containing loops - ruby

I'm relatively new to programming and even newer to Ruby, and I've been using the repl.it Ruby interpreter to test code. However, I've run into the same problem multiple times now whenever I try to enter in multiple function definitions that contain loops -- I inevitably get an error message that looks like this:
(eval):350: (eval):350: compile error (SyntaxError)
(eval):344: syntax error, unexpected kDO_COND, expecting kEND
(eval):350: syntax error, unexpected kEND, expecting $end
Does anyone know what the problem is and how to avoid this? It doesn't look like a code error per se, since my code seems to run fine with codepad. But I've been told to use this specific interpreter to test code for a program I'm applying to.
Here's my code (I'm testing two different methods I wrote to reverse a string, one in place and the other using a new output list):
def reverse(s)
#start by breaking the string into words
words = s.split
#initialize an output list
reversed = []
# make a loop that executes until there are no more words to reverse
until words.empty?
reversed << words.pop.reverse
end
# return a string of the reversed words joined by spaces
return reversed = reversed.join(' ')
end
def reverse_string(s)
# create an array of words and get the length of that array
words = s.split
count = words.count #note - must be .length for codepad's older Ruby version
#For each word, pop it from the end and insert the reversed version at the beginning
count.times do
reverse_word = words.pop.reverse
words.unshift(reverse_word)
end
#flip the resulting word list and convert it to a string
return words.reverse.join(' ')
end
a = "This is an example string"
puts reverse(a)
puts reverse_string(a)

Your code is fine; their interpreter is old. If you change the block syntax that you use with times, e.g.
count.times {
reverse_word = words.pop.reverse
words.unshift(reverse_word)
}
...suddenly it works.

Related

bad value in range argument error - regarding range construction in ruby

I wrote the following snippet.
def add_me(num)
result = 0
(1..num).each { |i| result += i}
result
end
puts add_me(STDIN.gets)
I received an argument error list_sum.rb:6:in 'AddMe': bad value for range (ArgumentError) the line # corresponds to line # in my editor.
I also experimented with things like foo = (1..num).to_a. But still receive the same error. What is going on? Ruby version 2.3.3. What am I missing? I should be able to use variables in ranges, no?
gets returns a string. You need to do gets.to_i, in order to turn the input into a number for your numeric range. Right now you’re trying to make a range where the start is the number 1 and the end is some string, and that is raising an ArgumentError.
Also as an aside, ruby convention would tell you that your function should be named add_me. Ruby uses snake case, and anything that starts with a capital letter is typically assumed to be a class or constant (constant being all caps).

Metaprogramming Ruby 2 example from the book isn't working when I try it. Trouble shooting assistance

While reading through a chapter of Metaprogramming Ruby 2, I've come across an example in the book that does not seem to work when I execute the code.
array_explorer.rb
def explore_array(method)
code = "['a','b','c'].#{method}"
puts "Evaluating: #{code}"
eval code
end
loop { p explore_array(gets()) }
The code above is designed to illustrate the power of eval. In the next example the book teaches the major flaw of code injections and refactors the code like so to safeguard:
array_explorer.rb
def explore_array(method, *arguments)
['a','b','c'].send(method, *arguments)
end
loop { p explore_array(gets()) }
When I try to run the above code, the file always gives me this error no matter what array method I try to place in.
array_explorer.rb:2:in `explore_array': undefined method `:size (NoMethodError)
' for ["a", "b", "c"]:Array
I've tried taking out the *arguments portion to whittle it down. I tried using a string as input, a symbol as input, etc. This code doesn't work for some reason. Does anyone know why?
gets reads a line from STDIN; a "line" is defined as a string of characters ending with a newline (\n). Thus, you are trying to invoke the method "size\n", which does not exist. Use chomp to get rid of the newline:
loop { p explore_array(gets.chomp) }
It does not matter in the first example, since you are evaluating the code "['a', 'b', 'c'].size\n", which is still valid.

Push an array into another array with Ruby, and return square brackets

I've spent a few hours searching for a way to push an array into another array or into a hash. Apologies in advance if the formatting of this question is bit messy. This is the first time I've asked a question on StackOverflow so I'm trying to get the hang of styling my questions properly.
I have to write some code to make the following test unit past:
class TestNAME < Test::Unit::TestCase
def test_directions()
assert_equal(Lexicon.scan("north"), [['direction', 'north']])
result = Lexicon.scan("north south east")
assert_equal(result, [['direction', 'north'],
['direction', 'south'],
['direction', 'east']])
end
end
The most simple thing I've come up with is below. The first part passes, but then the second part is not returning the expected result when I run rake test.
Instead or returning:
[["direction", "north"], ["direction", "south"], ["direction",
"east"]]
it's returning:
["north", "south", "east"]
Although, if I print the result of y as a string to the console, I get 3 separate arrays that are not contained within another array (as below). Why hasn't it printed the outermost square brackets of the array, y?
["direction", "north"]
["direction", "south"]
["direction", "east"]
Below is the code I've written in an attempt to pass the test unit above:
class Lexicon
def initialize(stuff)
#words = stuff.split
end
def self.scan(word)
if word.include?(' ')
broken_words = word.split
broken_words.each do |word|
x = ['direction']
x.push(word)
y = []
y.push(x)
end
else
return [['direction', word]]
end
end
end
Any feedback about this will be much appreciated. Thank you all so much in advance.
What you're seeing is the result of each, which returns the thing being iterated over, or in this case, broken_words. What you want is collect which returns the transformed values. Notice in your original, y is never used, it's just thrown out after being composed.
Here's a fixed up version:
class Lexicon
def initialize(stuff)
#words = stuff.split
end
def self.scan(word)
broken_words = word.split(/\s+/)
broken_words.collect do |word|
[ 'direction', word ]
end
end
end
It's worth noting a few things were changed here:
Splitting on an arbitrary number of spaces rather than one.
Simplifying to a single case instead of two.
Eliminating the redundant return statement.
One thing you might consider is using a data structure like { direction: word } instead. That makes referencing values a lot easier since you'd do entry[:direction] avoiding the ambiguous entry[1].
If you're not instantiating Lexicon objects, you can use a Module which may make it more clear that you're not instantiating objects.
Also, there is no need to use an extra variable (i.e. broken_words), and I prefer the { } block syntax over the do..end syntax for functional blocks vs. iterative blocks.
module Lexicon
def self.scan str
str.split.map {|word| [ 'direction', word ] }
end
end
UPDATE: based on Cary's comment (I assume he meant split when he said scan), I've removed the superfluous argument to split.

Ruby Spell Checker Not Working Properly

I am writing a small project in ruby that takes all of the words from a website and then sorts them short to long.
To verify that what gets sorted is actually valid english I am comparing an array of scraped words to the basic unix/osx words file.
The method to do this is the spell_check method. The problem is that when used on small arrays is works fine, but with larger ones it will let non-words through. Any ideas?
def spell_check (words_array)
dictionary = IO.read "./words.txt"
dictionary = dictionary.split
dictionary.map{|x| x.strip }
words_array.each do |word|
if !(dictionary.include? word)
words_array.delete word
end
end
return words_array
end
I simplified your code, maybe this will work?
def spell_check(words)
lines = IO.readlines('./words.txt').map { |line| line.strip }
words.reject { |word| !lines.include? word }
end
I noticed that you were trying to modify the words_array while you were simultaneously iterating over it with each:
words_array.each do |word|
if !(dictionary.include? word)
words_array.delete word # Delete the word from words_array while iterating!
end
end
I'm not sure if this is the case in Ruby, but in other programming languages like Java and C#, trying to modify a collection, while you're iterating over it at the same time, invalidates the iteration, and either produces unexpected behavior, or just throws an error. Maybe this was your problem with your original code?
Also, the return statement was unnecessary in your original code, because the last statement evaluated in a Ruby block is always returned (unless there's an explicit return that precedes the last statement). It's idiomatic Ruby to leave it out in such cases.

Performing same action for each value in array in Ruby

I have a text file of stock symbols, each symbol is on its own line. In Ruby, I have created an array from the text file like so:
symbols = []
File.read('symbols.txt').each_line do |line|
symbols << line.chop!
end
For each symbol in the array, I want to read from a json file (ex. MSFT.json) and perform a number of calculations (all of that is now working) and then do the same thing for the next symbol in the array.
When attempting to "call" and perform calculations on the first item in the array I did this:
json = File.read("#{symbols[0]}.json")
#...calculations come after this
This worked fine, and it did run through the whole program for the first symbol, but of course doesn't go on to perform the same steps for the remaining symbols (I know thats because I specified an index in the array].
Now that I know that the program works for a single symbol, I now want it to run on all the symbols in the array...so after the first block, I tried adding: symbols.each do, and removed the [0] from the File.read line (and added end at the end of the calculations). I was hoping it would loop through everything between the "do" and "end" for each symbol. That didn't work.
Then I tried adding this after the first block:
def page(symbols, i)
page[i]
end
And changing the File.read line to: json = File.read("#{page[i]}.json)
But that didn't work either.
Any help is appreciated. Thanks a lot
You can simply use .each instead of an iterator index:
symbols.each do |symbol|
json = File.read("#{symbol}.json")
# do some calculation for symbol
end
No need to iterate twice:
open('symbols.txt').lines.each do |line|
symbol = line.strip
json = File.read("#{symbol}.json")
# process json
end

Resources