Why is Ruby printing object.method before string? - ruby

class Bike
attr_accessor :color, :gear_numbers, :style
def spin
puts " spins! Woosh!"
end
end
gw = Bike.new
gw.color = "white"
gw.gear_numbers = 11
gw.style = "compact"
puts "This bike is #{gw.color} and it has #{gw.gear_numbers} gears. Oh, and it has a #{gw.style} design. Did I mention that my bike #{gw.spin}?"
Using IRB, this is what I get:
**spins! Woosh!
This bike is white and it has 11 gears. Oh, and it
has a compact design. Did I mention that my bike ?**
Why is "spins! Woosh!" coming BEFORE the string and why isn't it IN the string?

Because you're not returning the string from your method, you're printing it directly.
To do what you want to do, simply remove the puts from your spin method and you're good to go.
class Bike
attr_accessor :color, :gear_numbers, :style
def spin
"spins! Woosh!"
end
end

Because to interpolate the string Ruby needs to call spin. Then Ruby includes the return value of the spin method (which is nil, because puts returns nil) into the string and prints the generated string.

The issue here is that string interpolation needs to be fully complete before the string is passed through to the main puts you have there. As part of figuring out what's in there it must execute each of the methods referenced in the order which they appear.
Your spin method causes an immediate puts and it doesn't return anything, as that's how puts works. If you want to supply a string to go in there, simply leave it:
def spin
" spins! Woosh!"
end
Think of this string interpolation:
"a #{b} c #{d} e"
This is roughly equivalent to:
"a " + b.to_s + " c " + d.to_s + " e"
Where those .to_s calls are to force it into a string. You'd expect b and d to be exercised before the whole string is returned.
When anticipating what code will do, trace execution to the bottom first, then work back up. Simple programs work in very predictable ways.

Related

Calling functions inside functions when the inner function's arguments will always be the same as the outer's

The inner_method is only ever called within outer_method, and its argument will always be identical to outer_method's.
This works:
def outer_method(word)
inner_method(word)
puts word + " are like candy."
end
def inner_method(same_word)
puts "I really love " + same_word + "!"
end
outer_method("onions")
but this doesn't:
def outer_method(word)
inner_method
puts word + "tastes like candy."
end
def inner_method
puts "I really love " + word + "!"
end
outer_method("onions")
It seems that inner_method's reference to word is not being registered by outer_method. Is there a better way to do this?
(I realize there's no reason to have a separate inner_method in the above example; this is simplified for clarity's sake)
I honestly think your first technique is the best way to go and perfectly idiomatic. Still, here's another option:
def outer_method(word)
inner_lambda = lambda do
puts "I really love " + word + "!"
end
inner_lambda.call
puts word + " tastes like candy."
end
outer_method("onions")
lambda creates a lexical closure, which means it captures the surrounding environment, including the reference to word.
There are two concerns with your question. The shallow one is your learning Ruby syntax. The deeper one is learning proper coding patterns. In your case, word object begs to exist:
class MyWord < String
def singular?; #singular end
def initialize **setup
singular, plural = setup[:singular], setup[:plural]
if singular then #singular = true
super singular
elsif plural then #singular = false
super plural
else fail ArgumentError, "Bad MyWord constructor arguments!" end
end
def interjection_1
"I really love #{self}!"
end
def interjection_2
"#{capitalize} #{singular? ? 'is' : 'are'} like cand#{singular? ? 'y' : 'ies'}!"
end
def hysteria
puts interjection_1
puts interjection_2
end
end
And then:
MyWord.new( plural: "onions" ).hysteria

method undefined?

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)

what does #{ do in Ruby? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Meaning of #{ } in Ruby?
I know it is used for meta-programming, and I'm having a hard time trying to wrap my mind about what this operator is doing in the following example:
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s # make sure it's a string
attr_reader attr_name
attr_reader attr_name+"_history"
class_eval %Q"
def #{attr_name}=(value)
if !defined? ##{attr_name}_history
##{attr_name}_history = [##{attr_name}]
end
##{attr_name} = value
##{attr_name}_history << value
end
"
end
end
class Foo
attr_accessor_with_history :bar
end
In general terms, #{...} evaluates whatever's inside of it and returns that, converted to a string with to_s. This makes it a lot easier to combine several things in a single string.
A typical example:
"There are #{n} car#{n == 1 ? '' : 's'} in the #{s}"
This is equivalent to:
"There are " + n.to_s + " car" + (n == 1 ? '' : 's').to_s + " in the " + s.to+_s
It's important to remember that the contents of the #{...} interpolation is actually a block of Ruby code and the result of it will be converted to a string before being combined.
That example of meta programming is awfully lazy as instance_variable_get and instance_variable_set could've been used and eval could've been avoided. Most of the time you'll see string interpolation used to create strings, not methods or classes.
There's a more robust formatter with the String#% method:
"There are %d car%s in the %s" % [ n, (n == 1 ? '' : 's'), s ]
This can be used to add a precise number of decimal places, pad strings with spaces, and other useful things.
#{var} does variable substitution in Ruby. For example:
var = "Hello, my name is #{name}"
The code you've posted is generating a string with the code for an accessor method for the attr_name you've passed in.
It's not doing much really :D. All the red text is basically just a string. The "bla #{var} bla" part is just a nicer way of writing "bla " + var + " bla". Try it yourself in irb:
a = 10
puts "The Joker stole #{a} pies."
what it does is called variable interpolation.
name = "Bond"
p "The name is #{name}. James #{name}."
will output,
> "The name is Bond. James Bond."

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

Adding conversion method to Numeric causes SystemStackError

I'm attempting to add conversion methods to the Numeric class but when I run the following lines of code I get a SystemStackError
puts 5.dollars.in(:euros) # => 6.5
puts 1.dollar.in(:yen)
Here is my Numeric class
class Numeric
##conversion_hash = {:dollar => {:yen => 0.013, :euros => 1.292, :rupees => 0.019}}
def method_missing(method_id)
name = method_id.to_s
if name =~ /^dollar|yen|euros|rupee|$/
self.send(name + 's')
else
super # pass the buck to superclass
end
end
def dollars()
puts "Called Dollars method"
#current_currency = :dollar
return self
end
def in(key)
if ##conversion_hash.has_key?(#current_currency)
puts "Current currency: #{#current_currency}"
conversion_rate = ##conversion_hash[#current_currency]
puts "Current conversion rate: #{conversion_rate}"
if conversion_rate.has_key?(key)
puts "we have that key"
puts"What am I? #{self}"
rate = conversion_rate[key]
puts "Rate to multiply by #{rate}"
return self.to_int * conversion_rate[key]
end
end
end
end
Any help is greatly appreciated.
You're getting infinite recursion in your method_missing because your regex isn't quite right. Try changing the line:
if name =~ /^dollar|yen|euros|rupee|$/
to:
if name =~ /^dollar|yen|euros|rupee$/
That extra | is causing anything to match the regex, so any other method is recursing with a continually extending suffix of s.
In this case it looks like puts seems to be trying to call to_ary when it's trying to determine the type its argument. I'm not exactly sure why it's not just using respond_to? though - it's deep in the C internals so I don't really know what's happening.
Your solution overcomplicated.
- You don't need to modify method_missing. Armando version works fine.
- You should simple dollar definition to hash plus
- find the way to call method_missing again from method in(this is your homework).
Working solution have only 1 line of code + 2 lines def surronding.

Resources