I have class Actor with some attributes.
class Actor
attr_accessor :name, :age, :sex, :birth_date, :birthplace, :filmography, :death_date
def alive?
death_date.nil?
end
end
When I iterate over an array actors of Actors and display the elements as follows:
display = actors.each do |i|
puts puts i.inspect
end
I get empty lines between the items:
#<Actor:0x007f7c04da41c0 #name="Paul Newman", #age=83, #sex="M", #filmography=["Cool Hand Luke", "Butch Cassidy and the Sundance Kid"]>
#<Actor:0x007f7c04da40d0 #name="Catherine Keener", #age=52, #sex="F", #filmography=["Being John Malkovich", "Capote"], #death_date="Jan 01 2011">
#<Actor:0x007f7c04ba3c40 #name="Kathy Pornstar", #age=24, #sex="F", #filmography=["Pono", "Capote"]>
With the following code, the output does not have empty lines in between the items:
living = actors.select{ |i| "\n"; i.death_date.nil?}
puts "#{living}"
Output:
[#<Actor:0x007f7c04da41c0 #name="Paul Newman", #age=83, #sex="M", #filmography=["Cool Hand Luke", "Butch Cassidy and the Sundance Kid"]>, #<Actor:0x007f7c04ba3c40 #name="Kathy Pornstar", #age=24, #sex="F", #filmography=["Pono", "Capote"]>]
How do I make it such that the output has an empty line in between the items? Any formatting/re-formatting will be appreciated.
I assume that by "space", you mean an empty line.
The reason display has empty lines in between is because you have two puts, used in a wrong way. It would be simplified to:
display = actors.each do |i|
puts i.inspect, nil
end
and for living, you can do:
living.each do |e|
puts e.inspect, nil
end
Assuming you want to print each actor in living on a separate line, you could do the following:
living.each do |actor|
puts actor
end
Does that answer your question?
Related
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.
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)
I have the following in a variable called store
#<InitializeStore:0x007f83a39b72a0
#inventory=[
#<CreateStoreInventory:0x007f83a39b7228 #item="apples", #value=150>,
#<CreateStoreInventory:0x007f83a39b71d8 #item="bananas", #value=350>,
#<CreateStoreInventory:0x007f83a39b7188 #item="tissue paper", #value=450>,
#<CreateStoreInventory:0x007f83a39b7138 #item="soap", #value=850>
]>
Now when I try and do: store.inventory I should get an array. Instead I get everything inside the array spit out 4 times. This is not what I want. I want to be able to do store.inventory and get the array of objects.
I thought of assigning store.inventory to an inventory array, but it's already an array ...
Ideas?
It depends on how your InitializeStore is implemented.
store.inventory is actually store.inventory(). It's not a field access, it is a method call.
Its result depends on that method (inventory) is implemented.
Your code works perfectly for me:
require 'pp'
class InitializeStore
attr_reader :inventory
def initialize(arr)
#inventory = arr
end
end
class CreateStoreInventory
def initialize(item, value)
#item = item
#value = value
end
end
store_inventories = [
CreateStoreInventory.new('apples', 150),
CreateStoreInventory.new('bananas', 350),
CreateStoreInventory.new('tissue paper', 450),
CreateStoreInventory.new('soap', 850),
]
my_store = InitializeStore.new(store_inventories)
pp my_store.inventory
--output:--
[#<CreateStoreInventory:0x000001008423e8 #item="apples", #value=150>,
#<CreateStoreInventory:0x00000100842398 #item="bananas", #value=350>,
#<CreateStoreInventory:0x00000100842348 #item="tissue paper", #value=450>,
#<CreateStoreInventory:0x00000100842258 #item="soap", #value=850>]
1) Oh, but you didn't post your code. It's sort of hard to debug imaginary code.
2) Your class names are all wrong. Class names should not have verbs in them, e.g. Initialize, Create. Class names are things, which are nouns, e.g.:
require 'pp'
class Store
attr_reader :inventory
def initialize(arr)
#inventory = arr
end
end
class Product
def initialize(name, price)
#name = name
#price = price
end
end
products = [
Product.new('apples', 150),
Product.new('bananas', 350),
Product.new('tissue paper', 450),
Product.new('soap', 850),
]
my_store = Store.new(products)
pp my_store.inventory
--output:--
[#<Product:0x00000100842438 #name="apples", #price=150>,
#<Product:0x000001008423e8 #name="bananas", #price=350>,
#<Product:0x00000100842398 #name="tissue paper", #price=450>,
#<Product:0x00000100842348 #name="soap", #price=850>]
3) puts <--> p <--> pp
puts arr: prints out a string representation of each element of the array--followed by a newline. If the element is a string, and it already ends in a newline, puts doesn't add another newline.
p arr: prints a string representation of the entire array, which just happens to look like an array you specify in your code, e.g. [1, 2, 3], with quotes around it.
pp arr: pretty print the array. Like p but adds some formatting to make the output easier to read.
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
Consider the following code:
I receive an object from datamapper which contains Values from my select:
user = User.first()
puts user.name
# John
puts user.surname
# Doe
puts user.age
# 42
In a user defined Array I have an Order for these Values to be displayed
dataordering = ["age", "surname", "name"]
So how do I get my values ordered as in my Array?
dataordering.each do |sequence|
puts user.sequence
# this, of course, fails
end
I don't want to use eval(). nope.
Maybe there's even a better way to store an ordering of values?
You can pick values from record this way:
user_attributes = user.attributes
dataordering.each do |attribute|
puts user_attributes[attribute.to_sym]
end
Or use send method:
dataordering.each do |attribute|
puts user.send attribute.to_sym
end
As an ordering solution, I can offer you this code:
dataordering.map { |attr| user.send attribute.to_sym }