List in Ruby gem cli - ruby

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.

Related

validation on user input ruby

I created a gem that looks for a recipe with user input. I have almost 1000 recipes available to search for. How can I validate the user input when it does not match the names of my recipes?
as an example when the user type nabucodonosor or vocka the method load_recipe_by_ingridients return empty and I wish I could fix that. I'm using Ruby vanilla.. no rails
def start
puts "Hey there! you hungry? lets find some recipes ideas for you."
list_recipe_by_ingredients
show_summary
while #input != "exit"
if #input == "back"
list_recipe_by_ingredients
elsif valid_input?
puts Recipe.find_by_number(#input).summary
else
puts "Ops! not a valid number. try again."
end
ask_for_choices
end
end
def load_recipe_by_ingredients
puts "Search for recipes with the main ingredient, example: milk, pizza, eggs flour, ect."
#input = gets.strip.downcase
puts " "
Recipe.search_for_recipes(#input).each.with_index(1) do |recipe, index|
puts "#{index}. #{recipe.title}"
end
end
A pretty simple solution is to loop until a recipe is found, and once one or more recipes are found you break out of the loop and then render them:
def load_recipe_by_ingredients
recipes = []
loop do
puts 'Search for recipes with the main ingredient, example: milk, pizza, eggs flour, etc.'
input = gets.strip.downcase
puts
recipes = Recipe.search_for_recipes(input)
break if recipes.any?
puts 'No recipes found, please try again'
end
recipes.each.with_index(1) do |recipe, index|
puts "#{index}. #{recipe.title}"
end
end

Comparing values in a card game

I want to make a card game program that compares the values of cards assigned to player_value and dealer_value. If player_value is greater than dealer_value, it should display "you win". Here is my code:
def get_card (card)
type = case ((card-1)/13)
when 0 then "of clubs"
when 1 then "of diamonds"
when 2 then "of hearts"
when 3 then "of spades"
end
card = case (card%13)
when 0 then "king #{type}"
when 1 then "ace #{type}"
when 11 then "jack #{type}"
when 12 then "queen #{type}"
else card%13
end
"#{card} #{type}"
end
def deal_cards
total_cards = (1..52).to_a.shuffle
player_value = [total_cards.pop, total_cards.pop]
dealer_value = [total_cards.pop, total_cards.pop]
puts "Your cards are #{get_card(player_value[0]).to_s} and #{get_card(player_value[1]).to_s}"
puts "The dealer shows #{get_card(dealer_value[0])}"
if(dealer_value > player_value)
puts "You lose"
else (player_value > dealer_value)
puts "You win"
end
end
deal_cards()
It is not clear to me why this is not working, and I would appreciate any help with this.
I don't really understand why you assign an array to player_value and dealer_value, but you can't compare an array using > or <.
You have to retrieve the element from the array that you want to compare, and then use it in the if-else clause.
Also an else clause does not take another condition. An else will be used if all previous conditions fail. In your case, you should use elsif.
e.g.:
if(dealer_value[0] > player_value[0])
puts "You lose"
elsif (player_value[0] > dealer_value[0])
puts "You win"
end
Let me offer this object oriented solution to the same problem, since this is where Ruby really shines, and seeing it used in a procedural way really irks me. Object orientation adds a few more lines for scaffolding, but adds so much more in terms of legibility, reusability, and conceptual clarity.
We can represent the domain using three basic building blocks.
First, we need a Card object, able to hold some data (a rank and a suit) about itself, as well as the ability to represent itself as a string:
class Card
SUITS = [:clubs, :diamonds, :spades, :hearts]
RANKS = [:ace, *2..10, :jack, :queen, :king]
attr_reader :suit, :rank
def initialize(n)
#suit = (n - 1) / 13
#rank = (n - 1) % 13
end
def to_s
"#{ RANKS[#rank] } of #{ SUITS[#suit] }"
end
end
Next, we need a Hand object. Basically a collection of cards that can compare its strength to other hands, and also represent itself as a string:
class Hand
attr_reader :cards
def initialize(cards)
#cards = cards
end
def <=>(other_hand)
#cards.strength <=> other_hand.strength
end
def to_s
#cards.map(&:to_s).join(", ")
end
private
def strength
#cards.map(&:rank).inject(:+)
end
end
It is not clear from the question, how hand strength is determined. In this primitive implementation, it is simply the sum of the ranks of the cards in the hand.
Lastly, we need a Deck object. Something from which we can draw cards. We'll go with a standard 52-card deck:
class Deck
def initialize
#cards = (1..52).map { |n| Card.new(n) }.shuffle
end
def draw(number_of_cards = 1)
[*#cards.pop(number_of_cards)]
end
end
Now that we have our basic building blocks set up, using them is trivial:
def deal_cards
deck = Deck.new
player_hand = Hand.new(deck.draw(2))
dealer_hand = Hand.new(deck.draw(2))
puts "Your have: #{ player_hand }"
puts "The dealer has: #{ dealer_hand }"
if(player_hand > dealer_hand)
puts "You win!"
elsif(dealer_hand < player_hand)
puts "Aw. You lose."
else
puts "Woah! It's a tie!"
end
end
Notably this solution lacks error handling, for cases like passing an unknown n to the Card constructor, or drawing from an empty deck, but can easily be added in.

Adding inside function

I have some code that won't add two numbers. What have I done wrong?
class Add
##starting_value = 5
def self.Adding
puts "How much do you want to add? "
user_choice = gets.to_i
user_choice + ##starting_value
puts "new value is"
puts ##starting_value
end
end
The problem is this line:
user_choice + ##starting_value
That adds the two values and then throws out the answer. You need to store the answer in a variable:
##starting_value = user_choice + ##starting_value
Ruby has a special shortcut for this
##starting_value += user_choice
I highly recommend reading the Pickaxe book. I assume you already have a Ruby implementation installed on your computer.
Create a file called, say, add.rb. I would try to keep things as simple as possible:
class Add
#amount = 5
def self.add
puts "How much do you want to add?"
puts "New value is #{#amount + gets.to_i}"
end
end
Add.add # add is a class method
Then run it with ruby app.rb. The output should be something like:
How much do you want to add?
100
New value is 105

how to set two instance variables to each other in Ruby

I'm working on Chris Pine's Ruby tutorial. I have to write a cheat method that allows me to set which side of the die I want to show: https://pine.fm/LearnToProgram/?Chapter=09
I have two instance variables: #numberShowing and #numberCheat. #numberCheat receives an input from the user and I want to set #numberShowing to take the value of #numberCheat. However, #numberShowing always outputs some random number. Any tips?
Here's my code so far:
class Die
def initialize
roll
end
def roll
#numberShowing = 1 + rand(6)
end
def showing
#numberShowing
end
def cheat
puts "cheat by selecting your die number between 1 and 6"
#numberCheat = gets.chomp
end
#numberShowing = #numberCheat
end
puts Die.new.cheat
puts Die.new.showing
Thanks!
Move #numberShowing = #numberCheat into the cheat method. But your test is not going to prove it worked. Try something like:
die = Die.new
puts "Currently showing #{die.showing}"
puts "Cheating to change showing number to #{die.cheat}"

Function calls in hash come up empty in 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

Resources