Please explain to me why this is happening:
def resizeImage(event_file, resize_width, resize_height, options = {})
puts options
aspect_ratio = options.fetch(:maintain_aspect_ratio, true)
puts aspect_ratio
"return value"
end
resizeImage('event_file', 'resize_width', 'resize_height', {maintain_aspect_ratio: false} )
{:maintain_aspect_ratio=>false}
false
=> "return value"
I want to set a variable to = the fetch from the hash to make my code more readable. But for some reason it is nil when I call it. It almost looks like the fetch is asynchronous, but this ain't ajax.
This is a pretty elementary problem I know, but so far as I can tell I am doing things just as they are described in more than one guide to using options in ruby methods.
-- Update --
so now I have it returning something else to try to separate the problem. I see that the puts statement for aspect_ratio doesn't actually return anything at all. What is happening?
-- Update2 --
Okay, I got confused. It is returning false. So there is something else wrong in my real method. Thank you for your time, I will accept the most detailed answer but I appreciate both.
Remove this line from your method:
puts aspect_ratio
Your Ruby method is returning to the value of the final statement, i.e. the value of puts.
When you remove that line, then your method will return aspect_ratio.
You actually have the correct structure down, however the final puts in your method is causing the return value to be nil. Ruby utilizes an implicit return, so unless specified, it will return the last value of a method. remove the puts aspect_ratio from the method, or ensure the last line is aspect_ratio and the method will properly return your value
def resizeImage(event_file, resize_width, resize_height, options = {})
puts options
aspect_ratio = options.fetch(:maintain_aspect_ratio, true)
puts aspect_ratio #remove this line
aspect_ratio
end
this can end up being shortened to
def resizeImage(event_file, resize_width, resize_height, options = {})
options.fetch(:maintain_aspect_ratio, true)
end
#joelparkerhendersons answer is correct
Im going to explain whats happening.
Everything in ruby returns something(apart from a tiny minority). It can be forced by using return but by default the last line of the method is returned.
Your method resizeImage returns what puts returns. puts returns nil
Therefore as #joelparkerhendersons suggested remove the puts
Related
I am making my first web server, but When i use the if statement to compare user input from html file with a string, they just skip it even if it is true.
require 'socket'
require 'pry'
class Parser
def parse(req, clients)
save = File.new("requests.txt", "w+")
save.write(req.chomp)
save.close
words = IO.readlines("requests.txt").last(1)
if words == "Username=test&Password=1234"
success(clients)
end
#binding.pry
puts words
end
end
def success(succ_client)
success_file = File.read("templates/success.html")
stuff = "HTTP/1.1 200\r\n" + success_file.force_encoding('UTF-8')
succ_client.puts(stuff)
end
def response(cli)
file = File.read("templates/passpage.html")
content = "HTTP/1.1 200\r\n" + file.force_encoding('UTF-8')
cli.puts(content)
end
serv_sock = TCPServer.new('10.0.2.15', 8080)
loop {
client = serv_sock.accept()
requests = Parser.new
requests.parse(client.readpartial(2043), client)
response(client)
client.close
puts "Connected"
}
I tried using #compact!, nil?, and using pry to decode to find whats the issue, but I just cant find the problem, when i puts the words variable it puts the correct value but its just not the right one I guess. I tried decoding the words but that still didn't work unless i did it wrong.
It has been 5 days on this problem and this is my first ruby program, and web-server, So ill appreciate any help I can get with this to move forward in life.
There are several issues with your code.
Primarily, your call to IO.readlines("requests.txt").last(1) returns an Array of zero or one strings. However, you are comparing it to a single string. Since the string is not equal to the array, the comparison fails.
Likely, you want to use IO.readlines("requests.txt").last instead. This returns the last element or the array or nil if the array returned by the readlines method is empty.
Please have a look at the documentation of the Array#last method to learn more about the returned types of this method.
In addition to that, even if your if statement eventually matches, your intended call to the success method fill fail, because you have defined it in the global main object, rather than your Parser class.
Also, when you eventually call success from your parse method, you will be returning two responses as you also call the response method later. You may want to rethink the way you select the correct responses...
I'm trying to get an if statement for users who put incorrect data.
Here's my code:
class Breweries::CLI
def start
puts "Hello!"
puts "---------------------------"
puts "Please enter your location:"
input = gets.strip.downcase
#data = Breweries::API.get_breweries(input)
#objects = Breweries::HoppyCode.all
if input.length < 1
puts "Sorry!!"
puts "```````"
start
else
display_info
end
end
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:"
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
end
end
def quit
puts "Goodbye. Drink responsibly and enjoy."
end
end
When I put something that would generate an error, it returns the following:
Please enter your location: nvifpejvf80ejvip
Traceback (most recent call last):
2: from bin/breweriesCLI:6:in `<main>'
1: from /home/munificent-format-5297/Development/breweries/lib/breweries/cli.rb:8:in `start' /home/munificent-format-5297/Development/breweries/lib/breweries/api.rb:6:in `get_breweries': undefined method `[]' for nil:NilClass (NoMethodError)
How can I solve the undefined method '[]' error? Here's the API code in case that's necessary.
class Breweries::API
def self.get_breweries(input)
#breweries_hash = HTTParty.get("https://api.openbrewerydb.org/breweries?by_city=#{input}")
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
When the input is invalid, the call to
#breweries_hash = HTTParty.get("...")
returns not the object you expect (I’d suggest it returns an empty hash.) That makes it impossible to get to details in the following lines. Depending on how are you to handle it, you might decide to e. g. early return from this function, or raise, or do something else.
To approach this, start with debugging the issue, like this:
#breweries_hash = HTTParty.get("...")
puts #breweries_hash.inspect
...
That way you’ll see what gets returned and get the ideas of how to handle it.
If I am right, and what is returned is an empty hash, you might want to early return from this function.
#breweries_hash = HTTParty.get("...")
return if #breweries_hash.empty?
...
Identifying the Problem
There are lots of ways to solve for the nil problem, but at a quick glance it seems like part of the problem here is that you're somehow expecting input to return a valid Hash object from your API call, but an empty String or an instance of FalseClass may not do that. Consider the following:
input = gets.strip.downcase # <RETURN> here gets an empty string
input #=> ""
input.to_i > 0 #=> false
Then consider that some downstream of Breweries::API.get_breweries is expecting to operate on a Hash object instead if an instance of NilClass. In this case, that looks like #breweries_hash[1]["name"] and other operations on #breweries_hash.
Some Options
Without knowing more about your code, I don't want to be prescriptive here. But in general, you can do one or more of the following:
Coerce arguments into the expected class in the method call, the method signature, or the method body. For example, for Array objects:
# coerce a String to an Array, raising an exception if it can't
input = ""
Array(input)
#=> [""]
# coerce some Array to a Hash
array = [:name, "foo", :street, "bar"]
Array(array.each_slice 2).to_h
#=> {:name=>"foo", :street=>"bar"}
Explicitly check that you have an Hash object:
fail "#breweries is not a Hash" unless #breweries.is_a? Hash
Raise an exception rather than return 0 if input isn't actually a valid Integer representation in the first place:
input = Integer(gets.strip.downcase)
Check if your Hash or Array object responds to the relevant method calls, and raise a more helpful exception message:
raise sprintf("#brewery: %s", #brewery.class) unless #brewery.respond_to? :[]
There are other things you might do as well. Broadly speaking, you need to adjust your code to check the return value of your call to ensure it's not nil, then branch/raise/rescue appropriately depending on whether or not you ever expect nils as a valid return value from Breweries::API.get_breweries.
A Note on Using Exceptions for Non-Exceptional Circumstances
As a rule of thumb, you should only raise exceptions for truly unexpected circumstances, or when the program should halt because some condition can't (or shouldn't) be handled within the program during runtime. Which is best in your particular use case is really a design decision, and outside the scope of the original question. However, you might want to read Avdi Grimm's Exceptional Ruby for a deeper explanation of when exceptions might better than branching or handlers (or vice versa), but the choice in your code is a little left of center of the problem you're actually dealing with right now.
So, pretend we have the following three methods that check a grid to determine if there is a winner, and will return true if there is.
def win_diagonal?
# Code here to check for diagonal win.
end
def win_horizontal?
# Code here to check for horizontal win.
end
def win_vertical?
# Code here to check for vertical win.
end
I would like to push the returned values of each method into an Array instead of literally using the method names. Is this possible?
def game_status
check_wins = [win_vertical?, win_diagonal?, win_horizontal?]
if check_wins.uniq.length != 1 # When we don't have only false returns from methods
return :game_over
end
end
What you are looking for will indeed work in ruby.
def hello_world?
"hello world!"
end
a = [hello_world?]
Prints out
=> ["hello world!"]
Hope that helps. IRB is your friend when you wonder if something is possible in Ruby :-)
Simpler way (and very readable) yet:
def game_status
win_vertical? || win_diagonal? || win_horizontal?
end
If, for example, win_vertical? returns true, the other algorithms won't even need to run. You return immediately.
Or, if you need to know in which way the user won, I mean, if you need to preserve the results of all methods after they ran, you can use a hash, like:
{:vertical => win_vertical?, :diagonal => win_diagonal?, :horizontal => win_horizontal?}
This solution, like the array one, is worse than the first one above for it runs all algorithms all the time. If they are complex, you may have a problem. =)
You can do something like this when you really want to store all return values in an array:
def game_status
check_wins = [win_vertical?, win_diagonal?, win_horizontal?]
return :game_over if check_wins.any?
end
For readability I would prefer:
def game_status
return :game_over if win_vertical? || win_diagonal? || win_horizontal?
end
I have the following code
# colours a random cell with a correct colour
def colour_random!
while true do
col, row = rand(columns), rand(rows)
cell = self[row,col]
if cell.empty? then
cell.should_be_filled? ? cell.colour!(1) : cell.colour!(0)
break
end
end
end
it's not that important what's doing, although it should pretty obvious. The point is that Rubocop gives me a warning
Never use 'do' with multi-line 'while
Why should I not do that? How should I do it then?
while is a keyword,so you don't need to pass a block. Without do..end it will work fine. The below is fine
def colour_random!
while true
col, row = rand(columns), rand(rows)
cell = self[row,col]
if cell.empty? then
cell.should_be_filled? ? cell.colour!(1) : cell.colour!(0)
break
end
end
end
while is a keyword, and if you pass a block to it, like do..end, it still works as you asked it to do, by not throwing any error, rather just a warning. But it could be dangerous if you try to pass a Proc or Method object to it, and dynamically try to convert it to a block using & keyword, as we do generally. That means
# below code will work as expected just throwing an warning.
x = 2
while x < 2 do
#code
end
But if you try to do by mistake like below
while &block # booom!! error
The reason is while is a keyword, which don't support any to_proc method to satisfy your need. So it can be dangerous.
Ruby style guide also suggested that Never use while/until condition do for multi-line while/until
I think the reason is as Nobuyoshi Nakada said in the mailing list
loop is a kernel method which takes a block. A block introduces new local variable scope.
loop do
a = 1
break
end
p a #=> causes NameError
while doesn't.
while 1
a = 1
break
end
p a #=> 1
Ruby actually has a shortcut for while true: the loop statement.
def colour_random!
loop do
col, row = rand(columns), rand(rows)
cell = self[row,col]
if cell.empty? then
cell.should_be_filled? ? cell.colour!(1) : cell.colour!(0)
break
end
end
end
I am new to ruby. I tried to do a simple method(with parameter) call.
class MeowEncoder
def method(c)
puts c
end
end
print "please enter the thing you want"
s = gets.chomp()
MeowEncoder.method(s)
It is only passing parameter and prints it out. But the terminal keep giving me errors like
:MeowEncoder.rb:9: undefined method `toBinary' for MeowEncoder:Class (NoMethodError)
what is going on here?
I made some enhancement.
class MeowEncoder
def encode(n)
toBianry(?n)
puts ""
end
def toBinary(n)
if n < 2
print n
else
toBinary(n / 2)
print n % 2
end
end
end
o = MeowEncoder.new
print "please enter the thing you want: "
s = gets.chomp()
s.each_char{|c| o.encode(c)} #this doesn't work
o.toBinary(212) # this works
I made some enhancement here. I try to convert a char to its ASCII value then to its binary form. I can made the single toBinary works. But the Encode method also gave me same error. What happened?
You defined an instance method, but you're trying to call it on a class object. Try this:
MeowEncoder.new.method(s)
Also, method is a bad name for a method. It will cause a name clash.
To expand on Sergio's answer, if you actually wanted the method defined on the class, there are several ways to accomplish that, but the most straightforward is to prepend the method definition with self like so:
def self.method(c)
puts c
end
That will allow you to invoke the method the way you are currently.
The reason this works is, in the context of defining the method, self is set to the MeowEncoder class. It's equivalent to saying:
def MeowEncoder.method(c)
puts c
end
This is actually another valid way to declare class methods, but using self is better practice, as refactoring becomes easier if you ever change the name of your class.
Instead of each_char use each_byte and no need of encode method.
s.each_byte{|c| o.toBinary(c)}
Book (title, author)
Author (pseudonym, first_name, last_name)
Book_catalog => collection of books
methods
add_book(book)
remove_book(book)
borrow_book(borrower, book) => voeg boek toe aan borrower.books_borrowed
return_book(borrower, book) => verwijder boek uit borrower.books_borrowed
book_available?(book)
search(title) => geeft gevonden book-object terug (anders nil)
Book_borrowing
book (read-only), date_of_borrowing (read-only), date_of_return (read-only)
borrow_book(book_to_borrow) : #date_of_borrowing = systeem-datum+uur
return_book(book_to_return) : #date_of_return = systeem-datum+uur
Borrower
member_nbr, first_name, last_name, books_borrowed = collection of Book_borrowing
has_book_by_title(title) => geeft true of false terug
has_book(book) => geeft true of false terug
Person(first_name, last_name)