This is my simple code. I've problems with this IF statement that is looking for a element for each item in the array.
Now my problem is that the code gets stuck in the first part of the IF-statements. The 2 items that I've inside train_tables have just one TrainPathNotAvailable. I should expect that if one the items doesnt have TrainPathNotAvailable it should print out 'second IN' BUT it doesnt
right?
thanks for yr time!
the url for the code: here
def self.opening_file
#train_at_path_locations
doc = Nokogiri::XML(File.open("test_with_path.xml"))
#train_tables = doc.css("TrainTimeTable")
puts #train_tables.count # I have just 2 items to make this test easy
#train_tables.each do |i|
#train_id = i.css('TrainIdent PathIdent')
#train_locations = i.css('TrainAtPathLocation')
if i.css('TrainPathNotAvailable') #here is the problem
puts 'first IN'
# #first_station_not_available = i.css('FromLocationIdent LocationSubsidiaryCode')
# puts #train_location_last = i.css('ToLocationIdent LocationSubsidiaryCode').text
break
else
puts 'second IN'
# #train_location_first = i.css('TrainAtPathLocation LocationIdent LocationSubsidiaryCode').first
#
# puts #train_location_last = i.css('TrainAtPathLocation LocationIdent LocationSubsidiaryCode').last
end
end
try at_css instead of css.
css will return an empty array, [], when it doesn't find anything and this is a truthy value causing your if statement to fire.
at_css will return nil if it finds nothing.
if you need an array returned, try css().any?
Related
My CLI project is working almost correctly, however, is only returning one value. I would like my program to return multiple values.
Here's the code:
def display_info
puts "You'll love the following spots!"
puts "********************************"
#objects.each.with_index(1) {|brewery, index| puts "#{index}. #{brewery.name}"}
puts "Please make a selection by index number for more information:"
puts "****************************************************"
puts "Type Quit to end. Type Menu to try another location."
input = gets.strip.downcase
if(input.to_i > 0)
#brewery = #objects[input.to_i - 1]
puts "name: #{#brewery.name}"
puts "street: #{#brewery.street}"
puts "city: #{#brewery.city}"
puts "phone: #{#brewery.phone}"
puts "website_url: #{#brewery.website_url}"
display_info
elsif (input == "quit")
quit
elsif (input == "menu")
start
else
puts "Ooops, please try again to get more info:"
display_info
end
end
Here's the input result if that helps.
Austin
You'll love the following spots!
********************************
1. Oasis Texas Brewing Company
Please make a selection by index number for more information:
****************************************************
Type Quit to end. Type Menu to try another location.
quit
Goodbye. Drink responsibly and enjoy.
What can I do to return more than one value?
Here's the source of this code. This is the content.
class Breweries::API
def self.get_breweries(input)
#breweries_hash = HTTParty.get("https://api.openbrewerydb.org/breweries?by_city=#{input}")
return if #breweries_hash.empty? #empty array handle
breweries_obj = {
name: #breweries_hash[1]["name"],
street: #breweries_hash[3]["street"],
city: #breweries_hash[4]["city"],
phone: #breweries_hash[10]["phone"],
website_url: #breweries_hash[11]["website_url"]
}
Breweries::HoppyCode.new(breweries_obj)
end
end
end
You need to split the string you capture using gets with a character. You should ask for it in your message, normally that would be a comma, possibly surrounded by spaces.
I extracted the problem in a simplified script so that you can test it separately, which is always a good idea when solving a problem.
Mind the use of regular expressions between the // delimiters, and followed by the i flag to indicate that the comparison should be case-insensitive.
# what you would receive when you type this in the console following your message
# and captured by the gets, in this case brewerie 1 and 3
input = "1, 3"
#split by a comma preceded or followed or not by a space
breweries = input.split(/ *, */)
breweries.each do |brewerie|
if(brewerie.to_i > 0)
# #brewery = #objects[input.to_i - 1]
puts "displaying info about #{brewerie}"
elsif brewerie[/quit/i]
# quit
elsif brewerie[/menu/i]
# start
else
puts "Ooops, please try again to get more info:"
# display_info
end
end
Which returns:
displaying info about 1
displaying info about 3
From what I understand, You are asking the user to pick a brewery from a list of breweries. When they pick one, you show its info to them. What you could do instead is display a list of cities and let them pick a city and select all elements of the #objects where the city matches
def display_info
arr_of_cities = []
#objects.each{|element| arr_of_cities.push(element.city)}
arr_of_cities.each.with_index(1) {|city, index| puts "#{index}.#{city}"}
puts "Please make a selection by index number for more information:"
puts "****************************************************"
puts "Type Quit to end. Type Menu to try another location."
input = gets.strip.downcase
arr_of_breweries = #objects.where(city:arr_of_cities[input.to_i- 1])
if(input.to_i > 0)
arr_of_breweries.each.with_index(1) do |brewery,index|
puts "#{index}"
puts "name: #{#brewery.name}"
puts "street: #{#brewery.street}"
puts "city: #{#brewery.city}"
puts "phone: #{#brewery.phone}"
puts "website_url: #{#brewery.website_url}"
end
display_info
elsif (input == "quit")
quit
elsif (input == "menu")
start
else
puts "Ooops, please try again to get more info:"
display_info
end
end
Hopefully that helps. I haven't used ruby in a while so my syntax might be off a bit.
I've got a validator in ActiveRecord model, in which I faced with some realy strange behavior.
Example:
if status_changed?
p status # output on line below
# <= "my_status_1"
p my_conditions_1 # output on line below
# <= false
if my_conditions_1
errors.add(:status, 'Error1')
status = status_was
end
p status # output on line below
# <= nil
# my_conditions_2 depends on "status variable"
if my_conditions_2
errors.add(:status, 'Error2')
status = 2
end
end
Second condition always failed, because status somehow was setted to nil. But when I changed status to self.status everything started working as expected.
UPDATED
I've got the rule, that in case of assigning attribute I have to use self, thanks everyone who explained it. But part of the code's behavior still doesn't obvious to me
More general example:
class Detector
def status
"Everything ok"
end
def check
p status
# <= "Everything ok"
if false
status = "Danger!"
end
p status
# <= nil
end
end
detector = Detector.new
detector.check
Can someone explain it? How not interpreted code can "redirect" message from method to a variable? Is it ok?
To access object's attribute it's fine to do it with attribute.
While updating this attribute one should be using self.attribute, because otherwise how should Rails know you mean to set its attribute, not define local variable?
Rule of thumb: use self for assigning attribute, don't use it for reading the attribute.
EDIT
Regarding your update:
As #Jörg W Mittag said (who would say better?):
Well, status is un-initialized, und un-initialized local variables
evaluate to nil, just like instance variables.
To make your code sample behave as you expect you would want to call status as a method. Look:
class Detector
def status
"Everything ok"
end
def check
p status
# <= "Everything ok"
status = "Danger!" if false
status() # or method(:status).call
# <= "Everything ok"
end
end
First p status works because Ruby looks for local variable status. When it does not find it, it looks for a method called status (by method lookup). So it prints it "Everything ok".
Then in parses the if statement and sees, that there's un-initialized local variable status. Thus, when you reference it, it is legitimately nil.
So in other words, make Ruby know exactly, what you mean.
If you are updating the attribute then you must use self
self.status = 'something'
otherwise rails will assume status as a local variable so
puts self.status
#=> "something"
status = 'abc'
puts self.status
#=> "something"
self.status = 'something else'
puts self.status
#=> "something else"
But you can access the attribute with just status.
why status was set to nil?
Maybe because of this line
status = status_was
before status_changed? maybe the self.status was nil
I am trying to create some simple programs as trying to learn Ruby and then move on to rails, I am just playing about to try and get used to the flow of how different types of code work variables, loops etc.
I am trying to create a simple book system were I already have 3 books in my hash and then I want to list the books already in the library in the console and then I want to be able to add new books and then also loop through and display the new list to the console.
require 'rubygems'
class GetDetailsFromUser
books = {
Eagle_Eye: 1,
Eage_Eye1: 2,
Eagle_Eye2: 3
}
books.each do |i|
puts i
end
while true
add = gets.chomp
break if add.empty?
books << add
end
puts 'New list is below'
books.each do |i|
puts i
end
end
Were am I going wrong? I manage to print out the hash to the console, however, I get an error message
undefined method '<<' for {:Eagle_Eye=>1,...
Why is the method undefined? books << add? This should add a new book to the book hash table?
Add your second number with it. Here is a working example I wrote for you
Live Demo - VISIT THIS LINK
books = {
Eagle_Eye: 1,
Eage_Eye1: 2,
Eagle_Eye2: 3
}
books.each do |i|
puts i
end
while true
puts "What book would you like to add?"
add = gets.chomp
if add.empty? == true
puts "Error - You did not enter a title for a book"
break
else
books.max_by do |book,id|
#list_number = id
end
books[add.to_sym]=#list_number
break
end
end
puts 'New list is below'
books.each do |i|
puts i
end
refactored version of #ExecutiveCloser
books = {
Eagle_Eye: 1,
Eage_Eye1: 2,
Eagle_Eye2: 3
}
books.each do |i|
puts i
end
add = ""
while add.empty? do
puts "What book would you like to add?"
add = gets.chomp
books[add.to_sym] = books.size + 1 unless add.empty?
end
puts 'New list is below'
books.each do |i|
puts i
end
https://repl.it/CDK2/3
Ruby has a documentation site. E. g. Hash documentation clearly states, that there is no method << defined on the hash instance.
<< method is defined on Array.
Why would you expect “books << add should add a new book to the book hash table”?
There is another glitch within your code: you execute everything on class definition level, which makes absolutely no sense in this case.
Since it is unclear what do you want to achieve, I am unable to provide a ready-to-go-with solution.
I'm writing a helper method to determine if current has any pending reviews to write. If there is a pending review, simply print a line in the view.
My helper is putting exactly the right stuff to the console, however I'm struggling with how to simply return it. In this scenario, current user has an id: 4.
My Code:
def review_pending
gallery = current_user.galleries.first
if gallery
if gallery.permissions.accepted
gallery.permissions.accepted.each do |p|
return true if p.user.reviews.find_by_reviewer_id(!current_user)
puts "already written review: #{p.user.reviews.find_by_reviewer_id(4)} - prints correctly"
end
end
end
end
My goal: if there is a user from the list that current user has not yet reviewed return true.
Thanks!!!
Thanks for all your pointers!
I had forgotten/learned 2 things to make it work:
First, if nil is returned, ruby returns the last returned value which in my case was true (if gallery.permissions.accepted).
Secondly, I placed the "!" before current_user, and should have placed it before the entire line.
Corrected Code:
def review_pending
gallery = current_user.galleries.first
if gallery
gallery.permissions.accepted.each do |p|
return !p.user.reviews.find_by_reviewer_id(current_user.id)
end
end
return false
end
I'm writing a function that reads in an answer key, creates a question, and then associates the right answer with that questions. Here's my function:
def self.save_images_in_dir(dir)
answer_key_file = Dir.glob(dir+"/*.{rtf,txt}").first
answer_key = Array.new
if answer_key_file
puts "found key"
File.open(answer_key_file, "r") do |infile|
while (line = infile.gets)
if line.match(/^\d+[.]\s+/)
num = line.match(/\d+/)
answer = line.gsub(/\d+[.]\s+/,"") # Take out the 1.
answer.chomp!
answer_key.push(answer.to_s)#answer_key[num.to_s]=answer.to_s
puts "number #{num} is #{answer.to_s}"
end
end
end
end
images = Dir.glob("#{dir}*.{png,jpeg,jpg,gif}").sort_by {|file| File.ctime(file) }
counter = 0
answer_key.each do |q|
puts "before entering: #{q}"
end
images.each do |img|
q = self.new
q.tags = get_tags(img)
q.correct_answer = answer_key[counter]
puts "---------Answer is:#{answer_key[counter]}--------\n"
q.photo = File.open(img)
if q.correct_answer.nil?
puts "answer is nil"
end
counter = counter + 1
end
end
and here's a snippet of the output right before it enters the images.each block.
before entering: D
before entering: A
before entering: A
before entering: C
before entering: A
found key
---------Answer is:--------
answer is nil
Does anyone know why answer_key would "reset", and, furthermore, why answer_key.count would return 0 when evaluated within the images block? I understand that blocks should inherit the local scope from where they are called...any reason why answer_key would not be passed?
The mistake must be somewhere else, this code should work.
Write a few unit tests and refactor this method, it's trying to do too many things.
Also, when you loop over the images, you can get rid of counter and use each_with_index instead.