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.
Related
I'm trying to learn Ruby and I came across a problem online where I need to create something similar to this :
add(1) # => 1
add(1).(2) # => 3
add(1).(2).(3) # => 6
and so on.
I've read around and the closest I can get to having this work is with the following code :
def add(n)
Proc.new { |s| s + n }
end
Which works to an extent.
I can run the following :
add(1) # => #<Proc:0x007fb8aac309f0#(pry):2>
# or
add(1).(2) # => 3
But the moment I try doing this :
add(1).(2).(3)
I get the following error :
NoMethodError: undefined method call for 3:Integer
Why am I getting this error and how would I change this method so that it will accept as many new values as I give it to add itself without giving me an error?
For reference, this problem comes from CodeWars "A Chain Adding Function".
The easiest way to achieve this is to define Integer#call:
class Integer
def call(n)
self + n
end
end
def add(n)
n
end
puts add(1)
# 1
puts add(1).(2)
# 3
puts add(1).(2).(3)
# 6
The returned objects are plain Ruby Integers, not Proxy objects.
Note that it's probably not a good idea to modify such an important class. It's possible to use refinements in order to avoid breaking other Ruby parts:
module ChainAdding
refine Integer do
def call(n)
self + n
end
end
end
def add(n)
n
end
using ChainAdding
puts add(1)
# 1
puts add(1).(2)
# 3
puts add(1).(2).(3)
# 6
If you're learning Ruby, this kind of metaprogramming trick isn't what you should concentrate on first. It's cool to know that we can do this, it doesn't mean that we should, though.
You can't quite do what you are trying to do. The reason is that you have to return something and that something can't change based on whether you are going to continue the chain or not.
Note that some Rails objects give you the illusion that you can in the REPL (irb, pry), but they actually just redefine #inspect, which is called upon visualisation by said REPL.
Instead you can do something very similar, which has an even better interface IMO:
def add(starting_number)
sum = starting_number
accumulator = proc do |next_number|
if next_number
sum += next_number
accumulator
else
sum
end
end
end
add(1) # => #<Proc:0x007fb8ae20e860#(pry):4>
add(1).(2) # => #<Proc:0x007fb8ae4894f0#(pry):4>
add(1).() # => 1
add(1).(2).() # => 3
add(1).(2).(3).(4).() # => 10
I am learning methods in Ruby and thought that the best way to learn them was to create a method that already exists. However, there are two problems that I am running in to:
I do not know what the capitalize method looks like
My solution (it does more than the original method does) seems like it can be refactored into something more elegant.
This is what I have come up with:
# method that capitalizes a word
def new_capitalize(string)
if string[0].downcase == "m" && string[1].downcase == "c"
puts "#{string[0].upcase}#{string[1].downcase}#{string[2].upcase}#{string[3..-1].downcase}"
else
puts "#{string[0].upcase}#{string[1..-1].downcase}"
end
end
name1 = "ryan"
name2 = "jane"
new_capitalize(name1) # prints "Ryan"
new_capitalize(name2) # prints "Jane"
str = "mCnealy"
puts str.capitalize
# prints "Mcnealy"
new_capitalize(str)
# prints "McNealy"
It seems as if the first part of my if statement could be made much more efficient. It does not need to be even close to my solution as long as it prints the second capital if the name begins with "mc"
Also, if someone could point me to where the built in capitalize method's code could be found that would be great too!
Thank you in advance!
Alright, how about:
module NameRules
refine String do
def capitalize
if self[0..1].downcase == 'mc'
"Mc#{self[2..-1].capitalize}"
else
super
end
end
end
end
Then to use it:
class ThingWithNames
using NameRules
def self.test(string)
string.capitalize
end
end
ThingWithNames.test('mclemon') # => "McLemon"
ThingWithNames.test('lemon') # => "Lemon"
If we were starting from scratch and not using the C implemented code:
module NameRules
refine String do
def capitalize
if self[0..1].downcase == 'mc'
"Mc#{self[2..-1].capitalize}"
else
new_string = self.downcase
new_string[0] = new_string[0].upcase
new_string
end
end
end
end
Reference materials:
String#capitalize source
A really good presentation on refinements
First, in my opinion, doing anything other than capitalizing the first letter of the string should be a different method or an optional arg you pass. Second, if you are trying to mimic the core lib behavior than you could monkey-patch String.
class String
def capitalize
self[0].upcase << self[1..-1].downcase
end
end
The closest to an official ruby implementation is probably Rubinius
https://github.com/rubinius/rubinius/blob/377d5c958bc8239514fb98701b75859c6b51b9d4/core/string.rb#L332
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)
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
Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.