+= operator overloading in ruby - ruby

class Fracpri
attr_accessor:whole, :numer, :denom, :dec, :flofrac
def initialize()
puts "Hey! It's an empty constructor"
end
def getFraction(whole,numer,denom)
#whole=whole
#numer=numer
#denom=denom
end
def showFraction
puts "#{whole} #{numer}/#{denom}"
end
def +=(obj)
if(self.whole+(self.numer.to_f/self.denom.to_f) < obj.whole+(obj.numer.to_f/obj.denom.to_f))
puts "Yes"
else
puts "No"
end
end
end
puts "10 question"
r3=Fracpri.new()
r3.getFraction(1,2,3)
r2=Fracpri.new()
r2.getFraction(4,6,5)
r1=Fracpri.new()
r1.getFraction(2,6,5)
r1 += r2
this is the error message I'm getting:
syntax error, unexpected '=', expecting ';' or '\n'
def +=(obj)
^
syntax error, unexpected keyword_end, expecting end-of-input
suggest me how to rectify this error so that i can perform overloading,i need to add a constant using "+=" operator

It is not possible to override =, nor variants such as +=. These are built in keywords and not methods such as +.
If you change your patch from def +=(obj) to def +(obj), you can still call r1 += r2 and it will have the same effect as if you'd patched +=. This is because += is calling your patched + method under the hood.
By the way, your + method doesn't actually return a value so any time you call += it will always result in nil .... but it seems like this is still a WIP so hopefully you can sort that bit out.

Related

Unclear syntax error in Ruby : "syntax error, unexpected end" when using an invalid operator

I am trying to make sense of why Ruby reported the syntax error that it did , and why it could not be more clear. The following code snippet is giving me a "syntax error, unexpected end"
# #param {NestedInteger[]} nested_list
# #return {Integer}
def depth_sum(nested_list)
queue = Queue.new
nested_list.each { |element| queue.enq element }
result = 0
level = 1
until queue.empty?
size = queue.size
size.times do
element = queue.pop
if element.is_integer
result += level * element.get_Integer
else
element.each { |elem| queue.enq(elem) }
end
end
level++
end
end
I then figured out that Ruby does not have the ++ operator , so i replaced level++ with level+=1 and the code worked. But why was Ruby's syntax error message so cryptic about an unexpected end when in fact my error was not due to the "end" but because I was using a ++ operator which is not used in Ruby.
In Ruby, it is allowed to have whitespace between an operator and its operand(s). This includes newlines, and it includes unary prefix operators. So, the following is perfectly valid Ruby:
+
foo
It is the same as
+ foo
which is the same as
+foo
which is the same as
foo.+#()
The following is also perfectly valid Ruby:
foo++
bar
It is the same as
foo ++ bar
which is the same as
foo + + bar
which is the same as
foo + +bar
which is the same as
foo.+(bar.+#())
So, as you can see, the line
level++
on its own is not syntactically invalid. It is the end on the next line that makes this invalid. Which is exactly what the error message says: you are using the unary prefix + operator, so Ruby is expecting the operand, but instead finds an end it was not expecting.

.include? is not triggered when reading a txt file

I am under the impression that the following code should return either the search item word or the message no match - as indicated by the ternary operator. I can't diagnose where/why include? method doesn't work.
class Foo
def initialize(word)
#word=word
end
def file_open
IO.foreach('some_file.txt') do |line|
line.include?(#word) ? "#{#word}" : "no match"
end
end
end
print "search for: "
input = gets.chomp.downcase
x = Foo.new(input)
puts x.file_open
The input exists in some_file.txt. My ternary operator syntax is also correct. IO reads the text fine (I also tried File.open() and had the same problem). So I must be making a mistake with my include? method.
You need to control the returned value. file_open defined above will always return nil. The ternary will be executed properly, but nothing is done with its value. Instead you can do the following:
class Foo
def initialize(word)
#word=word
end
def file_open
IO.foreach('some_file.txt') do |line|
return line if line.include?(#word)
end
return "no match"
end
end

Ruby '{x}' block works, but 'do |x|' block does not?

I'm writing a method and for some reason it's throwing an error whenever I run an each block like this:
array.each do |i|
something_on_i
end
But, it's not throwing an error when I do the same thing like this:
array.each {|i| something_on_i}
Why? I thought the two were identical.
Here's the full code:
Working:
def factor(num)
i=2
factors=[1]
while i<=num
if (num % i == 0)
factors << i
end
i+=1
end
return factors
end
def Division(num1,num2)
facs1=factor(num1)
facs2=factor(num2)
common=[]
***facs2.each {|i| common << i if facs1.include?i}***
return common.max
end
# keep this function call here
# to see how to enter arguments in Ruby scroll down
Division(STDIN.gets)
Not working:
def factor(num)
i=2
factors=[1]
while i<=num
if (num % i == 0)
factors << i
end
i+=1
end
return factors
end
def Division(num1,num2)
facs1=factor(num1)
facs2=factor(num2)
common=[]
***facs2.each do |i|
if facs1.include?(i)
common << i
end
end***
return common.max
end
# keep this function call here
# to see how to enter arguments in Ruby scroll down
Division(STDIN.gets)
The error I get is:
(eval):334: (eval):334: compile error (SyntaxError)
(eval):323: syntax error, unexpected kDO_COND, expecting kEND
facs2.each do |i|
^
(eval):324: syntax error, unexpected tIDENTIFIER, expecting kDO or '{' or '('
(eval):334: syntax error, unexpected kEND, expecting $end
Thanks to the great help in the comments from everyone, it appears this is just an issue with Coderbyte and Repl.it, rather than an issue with the code itself. The code runs just fine in irb. #Darek Nedza pointed out that Coderbyte and Repl.it are only running Ruby 1.8.7, which is likely the problem.
Solution:
For strange errors on Repl.it or Coderbyte, just double check in irb

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.

Ruby StringScanner used for lexing : how to get the line number?

I am using StringScanner for lexical analysis like this :
def next
#scanner.skip(/\s+/)
value,kind=nil,nil
TOKEN_DEF.each{|tok,regex| (kind=tok;break) if #scanner.scan(regex)}
return Token.new(kind,value,#line,#scanner.pos)
end
At first approximation, this works well, except that I can't figure out how to now get the #line number.
I have read the doc, where begin_of_line? method seems appropriate, but I cannot figure how to use it.
Keep the text that you are scanning in a variable and use 'count'
I use the following in my code:
def current_line_number; #text[0..#scanner.pos].count("\n") + 1; end
This code doesn't seem ready to go and for sure somewhere else more elegant solution, it just should give you something to think about.
class Retry < StandardError
end
class TextScanner
def initialize(filename)
#lines = IO.readlines(filename)
#fiber = Fiber.new do
#lines.each_with_index do |line, index|
#scanner = StringScanner.new(line)
#scanner.skip(/\s+/)
value, kind = nil, nil
begin
got_token = false
TOKEN_DEF.each do |tok, regex|
if #scanner.scan(regex)
Fiber.yield Token.new(tok, value, index, #scanner.pos)
got_token = true
end
end
raise Retry if got_token
rescue Retry
retry
end
end
"fiber is finished"
end
end
def next
#fiber.resume
end
end
text_scanner = TextScanner('sometextfile')
puts text_scanner.next #=> first token
puts text_scanner.next #=> second token
puts text_scanner.next #=> third token
...
puts text_scanner.next #=> "fiber is finished"
I think I have a simple solution. Here it is :
def next
#line+=1 while #scanner.skip(/\n/)
#line+=1 if #scanner.bol?
#scanner.skip(/\s+/)
#line+=1 if #scanner.bol?
#scanner.skip(/\s+/)
return :eof if #scanner.eos?
TOKEN_DEF.each { |tok,syntax| (kind=tok;break) if #scanner.scan(syntax)}
return Token.new(kind,nil,#line,#scanner.pos)
end

Resources