Ruby one liner lazy string evaluation - ruby

I'd like to create ruby one liner that prints some information to stdout and gets data from stdin. I've got some code:
["This should be shown first", "This second: #{gets.chomp}"].each{|i| puts "#{i}"}
...but apparently, get.chomp is evaluated in the same time when whole array is evaluated, before iteration of each element.
In result, I'm first prompted for input, and then each element is printed.
Can I somehow evaluate it lazily, print array in order and still have whole thing in one line?

One way to achieve lazy evaluation is to use procs. Something like this (multiple lines for readability):
[
-> { puts "This should be shown first" },
-> { print "This second: "; puts gets.chomp },
].each(&:call)

I don't really see the advantage of making this a one-liner since it becomes pretty unreadable, but nevertheless:
[ ->{ "This should be shown first" },
->{ "This second: #{gets.chomp}" }
].each {|line| puts line.call }
P.S. Never do "#{foo}". Use string interpolation (#{...}) when you want to, well, interpolate strings, as on the second line above. If you want to turn a non-string into a string, do foo.to_s. If you know it's already a string (or don't care if it is) just use it directly: foo. But puts automatically calls to_s on its arguments, so just do puts foo.

If you dont mind the repetiton of puts:
['puts "This should be shown first"', 'puts "This second: #{gets.chomp}"'].each{|i| eval i}

This is just to show you could use a method rather than a proc.
def line2
"#{["cat","dog"].sample}"
end
["Line 1", :line2, "line 3"].each { |l| puts (l.is_a? Symbol) ? method(l).call : l }
#=> dog

Related

Ruby: String interpolation prints the function first when called second

Here is my short program
def def1()
x = 1
puts x
end
def def2()
y = 2
puts y
end
puts "some text #{def1}"
puts "some text #{def2}"
The outcome of this example...
1
some text
2
some text
I don't understand why this puts in this order and not "sometext" first.
Because the string is created first, which means calling def1, and then the whole string is passed into puts.
We can expand puts "some text #{def1}" out to understand.
string = "some text " + def1.to_s
puts string
As you can see, def1 is called to create the string. def1 prints out 1 itself, it does not return anything (it returns nil). Then the whole string is printed.
That's how all function calls work. The arguments are evaluated, the the function is called.
You'd need to call def1 after printing the prefix.
print "some text "
def1
This is a reason why it's often better to have a function return a value rather than print it itself.
In order to print the string, puts has to know what the string is. In order to know what the string is in this particular line:
puts "some text #{def1}"
Ruby has to call def1 first. def1, in turn, calls puts to print something.

Why is the method output printed first?

I wrote the following:
greeting="i am awesome"
puts("I was saying that #{greeting}")
# => I was saying that i am awesome
When I change it to this:
def showman
print("I am awesome ")
end
puts("I was saying that #{showman}")
# => I am awesome I was saying that
why is the method output printed first, and then the string? Why is it not printing like "I was saying that I am awesome"? What can I do to make the output be as such?
If I modify the showman function to:
def showman
return ("I am awesome ")
end
then it gives the desired output. Why is the use of return in this way making difference to the output?
In first output why method output is printed first and then the string.
In order to evaluate the string, showman is evaluated before the whole string is evaluated, which prints "I am awesome ".
Why its not printing like "I was saying that I am awesome"
Because print returns nil, and interpolating nil in a string evaluates to an empty string ("#{showman}" → "#{nil}" → ""). Without print, the showman method returns the string "I am awesome ".
Why is the use of return in this way making difference to the output?
It is not the use of return that is making the difference. It is the absence of print that is making the difference.

Taking a block of strings and storing them in an array

Is it possible to write a function that takes a block of strings, does something with the strings, and then returns an array with the strings?
def collect_string(&block)
# just toss them into an array and return it
return ...
end
a = collect_string {
"string 1"
"string 2"
"string 3"
}
When I print out what a is, I should get
["string 1", "string2", "string3"]
Now suppose I decided to change my mind and wanted to do something more with the strings first. Maybe I want to remove all of the vowels first, or just grab the first 3 characters.
This is really not what the blocks are for. You're going to make an array of strings anyway, so why not use an array to begin with?
def collect_string &block
v = block.call
# do something with v
end
# block returning array
a = collect_string {[
"string 1",
"string 2",
"string 3"
]}
If you use a block as in your example then it will return only "string 3", the last expression evaluated. Previous strings are lost.

Ruby- find strings that contain letters in an array

I've googled everywhere and can't seem to find an example of what I'm looking for. I'm trying to learn ruby and i'm writing a simple script. The user is prompted to enter letters which are loaded into an array. The script then goes through a file containing a bunch of words and pulls out the words that contain what is in the array. My problem is that it only pulls words out if they are in order of the array. For example...
characterArray = Array.new;
puts "Enter characters that the password contains";
characters = gets.chomp;
puts "Searching words containing #{characters}...";
characterArray = characters.scan(/./);
searchCharacters=characterArray[0..characterArray.size].join;
File.open("dictionary.txt").each { |line|
if line.include?(searchCharacters)
puts line;
end
}
If i was to use this code and enter "dog"
The script would return
dog
doggie
but i need the output to return words even if they're not in the same order. Like...
dog
doggie
rodge
Sorry for the sloppy code. Like i said still learning. Thanks for your help.
PS. I've also tried this...
File.open("dictionary.txt").each { |line|
if line =~ /[characterArray[0..characterArray.size]]/
puts line;
end
}
but this returns all words that contain ANY of the letters the user entered
First of all, you don't need to create characterArray yourself. When you assign result of function to a new variable, it will work without it.
In your code characters will be, for example, "asd". characterArray then will be ["a", "s", "d"]. And searchCharacters will be "asd" again. It seems you don't need this conversion.
characterArray[0..characterArray.size] is just equal to characterArray.
You can use each_char iterator to iterate through characters of string. I suggest this:
puts "Enter characters that the password contains";
characters = gets.chomp;
File.open("dictionary.txt").each { |line|
unless characters.each_char.map { |c| line.include?(c) }.include? false
puts line;
end
}
I've checked it works properly. In my code I make an array:
characters.each_char.map { |c| line.include?(c) }
Values of this array will indicate: true - character found in line, false - character not found. Length of this array equals to count of characters in characters. We will consider line good if there is no false values.

Why does ruby output values like this?

Fairly new to ruby, can someone explain why these 2 things respond differently?
a=["A","B","C"]
puts a
A
B
C
puts "#{a}"
ABC
a.to_s returns the same output as the templating output, but shouldn't the simple "puts a" do the same?
The specified behavior of puts is that it writes stuff out with a newline afterwards. If it's an array, it writes each element with a newline.
When you do puts a.to_s, it does the to_s first (resulting in a single string) and then outputs that single string with a newline afterward.
As discussed in this thread, and for no good reason, Arrays have magically inconsistent behavior when given to puts.
array.each {|e| puts e }
is the same as:
puts array

Resources