Function calls in hash come up empty in Ruby - ruby

I've been sifting through the prior questions and answers on stackoverflow, and I have gotten most of my question figured out. I figured out that I can't place a function call within a hash, without placing it within a proc, or a similar container.
What I'm ultimately trying to do is have a menu displayed, grab user input, and then iterate through the hash, and run the specified function:
def Main()
menu_titles = {"Answer1" => Proc.new{Choice1()}}
Menu(menu_titles)
end
def Choice1()
puts "Response answer"
end
def Menu(menu_titles)
menu_titles.each_with_index do |(key, value),index|
puts "#{index+1}. #{key}"
end
user_input = 0
menu_titles.each_with_index do |(key, value), index|
if index.eql?(user_input)
menu_titles[value]
break
end
end
end
Main()
The issue I'm having right now is that I'm not entering the functions that my hash calls for. Whether I use a return or a "puts", I either get a blank line or nothing at all. If anyone has other recommendations about my code, I'm all ears also. To be honest, I don't like using procs, but that's mostly because I don't entirely know how they work and where to use them.
Right now for my menus I have:
user_input = 1
if user_input == 1
Choice1()
...
end

Here's how I would refactor this:
class Menu
attr_reader :titles
# initialize sets up a hard-coded titles instance variable,
# but it could easily take an argument.
def initialize
#titles = {
"Answer1" => Proc.new{ puts "choice 1" },
"Answer2" => Proc.new{ puts "choice 2" }
}
end
# This is the only public instance method in your class,
# which should give some idea about what the class is for
# to whoever reads your code
def choose
proc_for_index(display_for_choice)
end
private
# returns the index of the proc.
def display_for_choice
titles.each_with_index { |(key,value), index| puts "#{index + 1}. #{key}" }
gets.chomp.to_i - 1 # gets will return the string value of user input (try it in IRB)
end
# first finds the key for the selected index, then
# performs the hash lookup.
def proc_for_index(index)
titles[titles.keys[index]]
end
end
If you're serious about Ruby (or object-oriented programming in general), I would highly recommend learning about the advantages of packaging your code into behavior-specific classes. This example allows you to do this:
menu = Menu.new
proc = menu.choose
#=> 1. Answer1
#=> 2. Answer2
2 #(user input)
proc.call
#=> choice 2
And you could actually run it on one line:
Menu.new.choose.call

Related

List in Ruby gem cli

I am making a ruby cli that outputs a list of game deals scraped from a site.
The list prints out promptly using
def games_sales
Deal.all.each_with_index do |deal, index|
puts "#{index + 1}. #{deal.title}"
end
puts "What game do you want to see?"
input = gets.strip
game_selection(input.to_i)
end
My problem comes when asking the user to select an item from the list.
def game_selection(input)
deal = Deal.find_by_index(input)
#binding.pry
deal.each do |deal|
puts "#{deal.index}"
puts " Name: #{deal.title}"
puts " Price: #{deal.price}"
puts " Store: #{deal.store}"
puts " Expiration: #{deal.expiration}"
end
deal
end
It returns the int input but only the first item on the list every time.
I forgot my find_by_index method:
def self.find_by_index(input)
all.select do |deal|
end
end
which is incomplete
Not 100% sure if I got your question right and if you're using Rails, but Deals.all let me think of this.
I had to replace Deals.all with DEALS for testing as I haven't got a rails app running. So I used an Array of OpenStructs to fake your Model result.
# this fakes Deals.all
require 'ostruct'
DEALS = [
# add any more properties the same way as title, separated by comma
OpenStruct.new(title: 123),
OpenStruct.new(title: 456)
]
def games_sales
DEALS.each_with_index do |deal, index|
puts "#{index + 1}. #{deal.title}"
end
puts "What game do you want to see?"
input = gets.strip
game_selection(input.to_i)
end
def game_selection(input)
deal = DEALS.at(input-1)
p deal[:title]
end
def self.find_by_index(input)
all.select do |deal|
deal.index == input
end
end
games_sales
Result when choosing 1 is 123, choosing 2 you'll get 456, due to p deal[:title] above in the code.
I think your find_by_index need to get the right index and in my example I had to use at(index) as at(input-1) in order to get the right result.
I really hope this helps somehow and I suggest that you add the expected result to your question, in case my answer does not help you.

Passing Ruby Hash into Classes

I ran into a study drill problem, and I couldn't figure it out.
Here's the link to the exercise. https://learnrubythehardway.org/book/ex40.html
Below are my work. On Study Drill 2, I passed in variables and it worked.
However, at study drill 3, I broke my code. I realized I wasn't passing in variable, but a hash. And because my class takes in 2 arguments, I couldn't figure out how to pass a dictionary as 2 arguments.
class Song
def initialize(lyrics, singer)
#lyrics = lyrics
#singer = singer
end
def sing_along()
#lyrics.each {|line| puts line}
end
def singer_name()
puts "The song is composed by #{#singer}"
end
def line_reader(lineNum)
line = #lyrics[lineNum-1]
puts "The lyrics line #{lineNum} is \"#{line}\"."
end
end
# The lyrics are arrays, so they have [] brackets
practiceSing = Song.new(["This is line 1",
"This is line 2",
"This is line 3"],"PracticeBand")
practiceSing.sing_along()
practiceSing.singer_name()
practiceSing.line_reader(3)
puts "." * 20
puts "\n"
# Variable for passing. Working on dictionary to pass the singer value.
lovingThis = {["Don't know if I'm right",
"but let's see if this works",
"I hope it does"] => 'TestingBand'}
# Everything after this line is somewhat bugged
# Because I was using a variable as an argument
# I couldn't figure out how to use dictionary or function to work with
this
practiceVariable = Song.new(lovingThis,lovingThis)
practiceVariable.sing_along()
practiceVariable.singer_name()
practiceVariable.line_reader(3)
Here's the Output. What it should do is return the singer/band, and return requested lyrics line.
I'm new to coding, please advise how to pass hashes into classes?
How to pass lovingThis hash into Song.new() and read as 2 arguments?
you can pass hash to constructor of class in the same way as we pass any other variable, But for that you need to change your constructor definition to take variable number of arguments i.e def initialize(*args)
class Song
def initialize(*args)
if args[0].instance_of? Hash
#lyrics = args[0].keys.first
#singer = args[0].values.first
else
#lyrics = args[0]
#singer = args[1]
end
end
def sing_along()
#lyrics.each {|line| puts line}
end
def singer_name()
puts "The song is composed by #{#singer}"
end
def line_reader(lineNum)
line = #lyrics[lineNum-1]
puts "The lyrics line #{lineNum} is \"#{line}\"."
end
end
# The lyrics are arrays, so they have [] brackets
practiceSing = Song.new(["This is line 1",
"This is line 2",
"This is line 3"],"PracticeBand")
practiceSing.sing_along()
practiceSing.singer_name()
practiceSing.line_reader(3)
puts "." * 20
puts "\n"
# Variable for passing. Working on dictionary to pass the singer value.
lovingThis = {["Don't know if I'm right",
"but let's see if this works",
"I hope it does"] => 'TestingBand'}
practiceVariable = Song.new(lovingThis)
practiceVariable.sing_along()
practiceVariable.singer_name()
practiceVariable.line_reader(3)

Self enumerating function

I've got some code:
def my_each_with_index
return enum_for(:my_each_with_index) unless block_given?
i = 0
self.my_each do |x|
yield x, i
i += 1
end
self
end
It is my own code, but the line:
return enum_for(:my_each_with_index) unless block_given?
is found in solutions of other's. I can't get why they passed the function to enum_for as a parameter. When I invoke my function without a block, it won't return anything with or without enum_for. I could left sth like:
return unless block_given?
and it has the same result. Or am I wrong?
Being called without a block, it will return an enumerator:
▶ def my_each_with_index
▷ return enum_for(:my_each_with_index) unless block_given?
▷ end
#⇒ :my_each_with_index
▶ e = my_each_with_index
#⇒ #<Enumerator: main:my_each_with_index>
later on you might iterate on this enumerator:
▶ e.each { |elem| ... }
This behavior is specifically useful in some cases, like lazy iteration, passing block to this enumerator later etc.
Just returning nil cuts this ability off.
Think you for very precise answer. I recived also very good example to understand this issue for other new developers:
def iterator
yield 1
yield 2
yield 3
puts "koniec"
end
iterator { |v| puts v }
it = enum_for(:iterator)
puts it.next
puts it.next
puts it.next
puts it.next
Just run and analyze this code.
For any method that accepts a block, a good method implementation should have a well-defined behavior when the block is not given.
In the example shared by you, each_for_index is being re-implemented by author, may be to provide additional semantics or may be just for academic purpose given that its behavior is same as Ruby's Enumerable#each_with_index.
The documentation has following for Enumerable#each_with_index.
Calls block with two arguments, the item and its index, for each item
in enum. Given arguments are passed through to each().
If no block is given, an enumerator is returned instead.
In order to stay consistent with highlighted line indicating what should be the behavior if block is not given, one has to use something like
return enum_for(:my_each_with_index) unless block_given?
enum_for is interesting method
enum_for creates a new Enumerator which will enumerate by calling method on obj.
Below is an example reproduced from documentation:
str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122
So, if one does not pass block to my_each_with_index, they have a chance to pass it later - just like one would have done with each_with_index.
e = obj.my_each_with_index
...
e.each { |x, i| # do something } # `my_each_with_index` executed later
In summary, my_each_with_index tries to be consistent with each_with_index and tries to be a well-behaved API.

How to write a nested search the Ruby way?

I am trying to write fast and concise code. I'd appreciate your thoughts on which is the best way to write the following code and why:
Option #1
def get_title
title = check_in_place_one
if title.empty?
title = check_in_place_two
if title.empty?
title = check_in_place_three
end
end
return title
end
Option #2
def get_title
title = check_in_place_one
title = check_in_place_two unless !title.empty?
title = check_in_place_three unless !title.empty?
return title
end
I think Option #1 is better since if the title is found by check_in_place_one, we test title.empty? once and then skip the rest of the code in the method and return. But, it looks too long. Option #2 appears better, but processes title.empty? one extra time, and unnecessary time before returning. Also, am I missing a third option?
From performance, there is no difference between the two versions of your code (besides very minor difference that may come from parsing, which should be ignorable). The control structures are the same.
From readability, if you can get away with nesting, doing so is better. Your second option is better.
It is usually better to get rid of any case that does not need further processing. That is done by return.
def get_title
title = check_in_place_one
return title unless title.empty?
title = check_in_place_two
return title unless title.empty?
title = check_in_place_three
return title
end
The last title = and return in the code above are redundant, but I put them there for consistency, which improves readability.
You can further compact the code using tap like this:
def get_title
check_in_place_one.tap{|s| return s unless s.empty?}
check_in_place_two.tap{|s| return s unless s.empty?}
check_in_place_three
end
tap is a pretty much fast method, and unlike instance_eval, its performance penalty is usually ignorable.
The following approach could be used for any number of sequential tests. Moreover, it is completely general. The return condition could be changed, arguments could easily be assigned to the test methods, etc.
tests = %w[check_in_place_one check_in_place_two check_in_place_three]
def do_tests(tests)
title = nil # Define title outside block
tests.each do |t|
title = send(t)
break unless title.empty?
end
title
end
Let's try it:
def check_in_place_one
puts "check 1"
[]
end
def check_in_place_two
puts "check 2"
''
end
def check_in_place_three
puts "check 3"
[3]
end
do_tests(tests) #=> [3]
check 1
check 2
check 3
#=> [3]
Now change one of the tests:
def check_in_place_two
puts "check 2"
'cat'
end
do_tests(tests) #=> 'cat'
check 1
check 2
#=> "cat"
If there were more tests, it might be convenient to put them in a module which would be included into a class. Mixed-in methods behave the same as those that you define for the class. For example, they have access to instance variables. I will demonstrate that with the definition of the first test method. We probably want to make the test methods private. We could do it like this:
module TestMethods
private
def check_in_place_one
puts "#pet => #{#pet}"
puts "check 1"
[]
end
def check_in_place_two
puts "check 2"
''
end
def check_in_place_three
puts "check 3"
[3]
end
end
class MyClass
##tests = TestMethods.private_instance_methods(false)
puts "##tests = #{##tests}"
def initialize
#pet = 'dog'
end
def do_tests
title = nil # Define title outside block
##tests.each do |t|
title = send(t)
break unless title.empty?
end
title
end
include TestMethods
end
The following is displayed when the code is parsed:
##tests = [:check_in_place_one, :check_in_place_two, :check_in_place_three]
Now we perform the tests:
MyClass.new.do_tests #=> [3]
#pet => dog
check 1
check 2
check 3
Confirm the test methods are private:
MyClass.new.check_in_place_one
#=> private method 'check_in_place_one' called for...'
The advantage of using a module is that you can add, delete, rearrange and rename the test methods without making any changes to the class.
Well, here's a few other alternatives.
Option 1: Return first non-empty check.
def get_title
return check_in_place_one unless check_in_place_one.empty?
return check_in_place_two unless check_in_place_two.empty?
return check_in_place_three
end
Option 2: Helper method with short-circuit evaluation.
def get_title
check_place("one") || check_place("two") || check_place("three")
end
private
def check_place(place)
result = send("check_in_place_#{place}")
result.empty? ? nil : result
end
Option 3: Check all places then find the first that's non-empty.
def get_title
[
check_in_place_one,
check_in_place_two,
check_in_place_three,
].find{|x| !x.empty? }
end
Option 2 looks good although you did a 360 degree turn with the unless !title.empty?. You can shorten that to if title.empty? since unless is equivalent to an if ! so doing an unless ! takes you back to just if.
If you're only ever going to have 3 places to look in then option 2 is the best. It's short, concise, and easy to read (easier once you fix the aforementioned whoopsie). If you might add on to the places you look for a title in you can get a bit more dynamic:
def get_title(num_places = 4)
title, cur_place = nil, 0
title = check_in_place(cur_place += 1) while title.nil? && cur_place < num_places
end
def check_in_place(place_num)
# some code to check in the place # given by place_num
end
The tricky line is that one with the while in it. What's happening is that the while will check the expression title.nil? && cur_place < num_places and return true because the title is still nil and 0 is less than 4.
Then we'll call the check_in_place method and pass in a value of 1 because the cur_place += 1 expression will increment its value to 1 and then return it, giving it to the method (assuming we want to start checking in place 1, of course).
This will repeat until either check_in_place returns a non nil value, or we run out of places to check.
Now the get_title method is shorter and will automatically support checking in num_places places given that your check_in_place method can also look in more places.
One more thing, you might like to give https://codereview.stackexchange.com/ a look, this question seems like it'd be a good fit for it.
I don't think there's any reason to get too clever:
def get_title
check_in_place_one || check_in_place_two || check_in_place_three
end
Edit: if the check_in_place_X methods are indeed returning an empty string on failure it would be better (and more idiomatic) to have them instead return nil. Not only does it allow for truthy comparisons like the above code, return "" results in the construction of a new and unnecessary String object.

Use of yield and return in Ruby

Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.

Resources